Creating a new user and password with Ansible Creating a new user and password with Ansible shell shell

Creating a new user and password with Ansible


I may be too late to reply this but recently I figured out that jinja2 filters have the capability to handle the generation of encrypted passwords. In my main.yml I'm generating the encrypted password as:

- name: Creating user "{{ uusername }}" with admin access  user:     name: {{ uusername }}    password: {{ upassword | password_hash('sha512') }}    groups: admin append=yes  when:  assigned_role  == "yes"- name: Creating users "{{ uusername }}" without admin access  user:    name: {{ uusername }}    password: {{ upassword | password_hash('sha512') }}  when:  assigned_role == "no"- name: Expiring password for user "{{ uusername }}"  shell: chage -d 0 "{{ uusername }}"

"uusername " and "upassword " are passed as --extra-vars to the playbook and notice I have used jinja2 filter here to encrypt the passed password.

I have added below tutorial related to this to my blog


If you read Ansible's manual for user module, it'll direct you to the Ansible-examples github repo for details how to use password parameter.

There you'll see that your password must be hashed.

- hosts: all  user: root  vars:    # created with:    # python -c 'import crypt; print crypt.crypt("This is my Password", "$1$SomeSalt$")'    password: $1$SomeSalt$UqddPX3r4kH3UL5jq5/ZI.  tasks:    - user: name=tset password={{password}}

If your playbook or ansible command line has your password as-is in plain text, this means your password hash recorded in your shadow file is wrong. That means when you try to authenticate with your password its hash will never match.

Additionally, see Ansible FAQ regarding some nuances of password parameter and how to correctly use it.


I want to propose yet another solution:

- name: Create madhead user  user:    name: madhead    password: "{{ 'password' | password_hash('sha512') }}"    shell: /bin/zsh    update_password: on_create  register: madhead- name: Force madhead to change password  shell: chage -d 0 madhead  when: madhead.changed

Why it is better? Like already has been noted here, Ansible plays should be idempotent. You should think of them not as a sequence of actions in imperative style, but like a desired state, declarative style. As a result you should be able to run it multiple times and get the same result, the same server state.

This all sounds great, but there are some nuances. One of them is managing users. "Desired state" means that every time you run a play that creates a user he will be updated to match exactly that state. By "updated" I mean that his password will be changed too. But most probably it is not what you need. Usually, you need to create user, set and expire his password only once, further play runs shouldn't update his password.

Fortunately, Ansible has update_password attribute in user module that solves this issue. Mixing this with registered variables you can also expire his password only when the user is actually updated.

Note that if you change user's shell manually (suppose, you don't like the shell that evil admin forced in his play) the user will be updated, thus his password will be expired.

Also note how you can easily use plain text initial passwords in plays. No need to encode them somewhere else and paste hashes, you can use Jinja2 filter for that. However, this can be a security flaw if someone happens to login before you initially do.