# Set user password only once?

**URL:** <https://forum.ansible.com/t/set-user-password-only-once/40383>\
**Category:** Get Help\
**Created:** [February 20, 2025, 6:03am UTC](https://forum.ansible.com/t/set-user-password-only-once/40383 "2025-02-20T06:03:56Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![microlinux](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/microlinux/32/2968_2.png) [@microlinux](https://forum.ansible.com/u/microlinux)\
**Post date:** [February 20, 2025, 6:03am UTC](https://forum.ansible.com/t/set-user-password-only-once/40383/1 "2025-02-20T06:03:56Z")

</div>

Hi,

I have a `local.yml` playbook to setup a test environment with `ansible-pull`. In this playbook I have a `setup_firstuser` role that sets up the first non-`root` user.

Here’s what `setup_firstuser/tasks/main.yml` looks like:

```auto
- name: "Setup account and generate SSH key pair for initial user: \
         {{firstuser_login}}"
  ansible.builtin.user:
    name: "{{firstuser_login}}"
    comment: "{{firstuser_name}}"
    password: >-
      {{firstuser_passwd|
      password_hash('sha512', 65534|
      random(seed=inventory_hostname)|
      string)}}
    generate_ssh_key: true
    ssh_key_type: ed25519
    ssh_key_file: .ssh/id_ed25519

- name: "Define administrator rights for initial user: {{firstuser_login}}"
  ansible.builtin.user:
    name: "{{firstuser_login}}"
    groups: wheel,systemd-journal
  when: firstuser_admin

```

And here’s the corresponding `setup_firstuser/defaults/main.yml` :

```auto
firstuser_login: ema
firstuser_name: EMA
firstuser_passwd: # no default
firstuser_admin: true

```

In the beginning of the `local.yml` playbook I have a `vars_prompt` section that prompts the user for a password like this :

```auto
  vars_prompt:
      - name: firstuser_passwd
        prompt: Choose a password for user ema
        default: ema123
        private: true

```

This all works nicely so far, except every time the playbook runs, the password prompt appears. So the user either has to confirm the default password or retype his or her custom password.

Here’s what I’d like to do :

- Only prompt for the password if it hasn’t already been set.
- If there is already a password for the `ema` account then don’t show the prompt and leave the password as is.

Or maybe even better :

- Define a dead simple default password (like `ema123`) for the user in the playbook.
- Let the user change the password manually (using the `passwd` command).
- Once there is a password, the playbook doesn’t try to set it anymore.

Any idea on how I could achieve that ?

---

<div class="post-metadata">

**Author:** ![markuman](https://avatars.discourse-cdn.com/v4/letter/m/7bcc69/32.png) [@markuman](https://forum.ansible.com/u/markuman)\
**Post date:** [February 20, 2025, 6:33am UTC](https://forum.ansible.com/t/set-user-password-only-once/40383/2 "2025-02-20T06:33:08Z")

</div>

> [@microlinux](#):
>
> - Define a dead simple default password (like `ema123`) for the user in the playbook.
> - Let the user change the password manually (using the `passwd` command).

I won’t bet on that.  
One way to go is to expire the password, once the user is created. That would force the user to change their password, once it logins via default password.  
But afaik, if you setup expiration once, it lasts forevery (when you don’t deactivate it again). So one day, the user will be forced to update their password again.

Another possibility is to replace the `var_prompt` at the beginning with a

```yml
    - name: > 
         Check if user 'alf' exists
         yes, relaying just on the home directoy is not safety
      stat:
        path: /home/alf
        follow_symlink: no

    - name: register new password of user does not exists
      when: not ansible_stat.stat.exists
      pause:
        prompt: enter password for user alf
      register: prompt_password
      no_log: true

```

Also there is `update_password: on_create`, that won’t update the passwort if the user exists already.

In case of a remote enviroment - don’t relay on password authentification. Just fetch some public keys from github/gitlab/gitea

```yml
- name: fetch ssh public keys
  ansible.posix.authorized_key:
    user: "{{ ansible_user_id }}"
    state: present
    manage_dir: true
    exclusive: true
    key: https://github.com/markuman.keys

```

---

<div class="post-metadata">

**Author:** ![chris](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/chris/32/293_2.png) [@chris](https://forum.ansible.com/u/chris)\
**Post date:** [February 20, 2025, 11:57am UTC](https://forum.ansible.com/t/set-user-password-only-once/40383/3 "2025-02-20T11:57:26Z")

</div>

There are lots of ways to do this, as @markuman has said above the best option is to not set a password and install SSH public keys for the account, if a password is essential then I have an Ansible role to generate a random password and send a email to the users email address (depends on the machine having working outgoing email) with the password in it and also to write a file to the server with the date and time the email was sent and if this file exists the role skips the tasks, so to reset the password you can delete the file and re-run the role.

---

<div class="post-metadata">

**Author:** ![sivel](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/sivel/32/1198_2.png) [@sivel](https://forum.ansible.com/u/sivel)\
**Post date:** [February 20, 2025, 3:20pm UTC](https://forum.ansible.com/t/set-user-password-only-once/40383/4 "2025-02-20T15:20:58Z")

</div>

Use the `update_password` parameter and set it to `on_create`. This is designed for exactly what you want. It only sets the password if it is creating the user, otherwise it never updates it.

---

<div class="post-metadata">

**Author:** ![microlinux](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/microlinux/32/2968_2.png) [@microlinux](https://forum.ansible.com/u/microlinux)\
**Post date:** [February 20, 2025, 3:46pm UTC](https://forum.ansible.com/t/set-user-password-only-once/40383/5 "2025-02-20T15:46:47Z")

</div>

Worked like a charm with `on_create`.

Thanks everybody !
