Create a new user and password using Ansible

I have one task that creates a new user on ubuntu 12.04;

- name: Add deployment user action: user name=deployer password=mypassword 

it completes as expected, but when I log in as this user and try to use the password that I set, it always says that it is incorrect. What am I doing wrong?

+78
bash shell ubuntu ansible
Oct 10 '13 at 10:07 on
source share
20 answers

If you read the Ansible manual for the user module , it will guide you to the Ansible github repo examples to learn how to use password .

There you will see that your password should 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 player or text string has its password as it is, this means that your hash password recorded in the shadow file is incorrect. This means that when you try to authenticate with a password, its hash will never match.

Also, see the Ansible FAQ for some nuances of the password parameter and how to use it correctly.

+81
Oct 11 '13 at
source share

I may be too late to answer this, but I recently found out that jinja2 filters are capable of handling encrypted password generation. In my main.yml I generate an encrypted password like:

 - 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 note that I used the jinja2 filter here to encrypt the passed password.

I have added below a tutorial related to this in my blog

+118
Apr 28 '15 at 4:23
source share

I want to offer 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 is it better? As already noted here, Ansible plays must be idempotent. You should not think of them as a sequence of actions in an imperative style, but as a desired state, a declarative style. As a result, you can run it several times and get the same result, the same server state.

All this sounds great, but there are some nuances. One of them is user management. “Desired state” means that every time you launch a game that creates a user, it will be updated to exactly match that state. By "update" I mean that his password will also be changed. But, most likely, this is not what you need. Usually you need to create a user, set and end his password only once, further playback runs should not update his password.

Fortunately, Ansible has the update_password attribute in the user module, which solves this problem. By mixing this with registered variables , you can also finish your password only when the user is actually updated.

Please note that if you change the user’s shell manually (suppose you don’t like the shell that the villainous administrator made to play), the user will be updated, so his password will expire.

Also pay attention to how you can easily use the initial plaintext passwords in games. There is no need to encode them somewhere else and insert hashes; you can use the Jinja2 filter . However, this can be a security flaw if someone accidentally logs in before you do this.

+36
Apr 24 '16 at 15:05
source share

The Ansible 'user' module manages users in idempotent . In the game book, state = present is declared for the user below the first task. Note that “ register: newuser ” in the first step helps the second step determine if the user is new (newuser.changed == True) or existing ( newuser.changed==False ) to only generate a password once.

The Ansible download contains:

 tasks: - name: create deployment user user: name: deployer createhome: yes state: present register: newuser - name: generate random password for user only on creation shell: /usr/bin/openssl rand -base64 32 | passwd --stdin deployer when: newuser.changed 
+10
Jun 26 '14 at 11:33
source share

try it

 vars_prompt: - name: "user_password" prompt: "Enter a password for the user" private: yes encrypt: "md5_crypt" #need to have python-passlib installed in local machine before we can use it confirm: yes salt_size: 7 - name: "add new user" user: name="{{user_name}}" comment="{{description_user}}" password="{{user_password}}" home="{{home_dir}}" shell="/bin/bash" 
+9
Apr 09 '14 at 15:10
source share

The purpose of the role in this answer is to generate a random password for new_user_name and expire the password immediately. The name new_user_name is required to change the password at the first login.

create_user.yml:

 --- # create_user playbook - hosts: your_host_group become: True user: ansible roles: - create_user 

roles / create_user / tasks / main.yml:

 --- # Generate random password for new_user_name and the new_user_name # is required to change his/her password on first logon. - name: Generate password for new user shell: makepasswd --chars=20 register: user_password - name: Generate encrypted password shell: mkpasswd --method=SHA-512 {{ user_password.stdout }} register: encrypted_user_password - name: Create user account user: name={{ new_user_name }} password={{ encrypted_user_password.stdout }} state=present append=yes shell="/bin/bash" update_password=always when: new_user_name is defined and new_user_name in uids register: user_created - name: Force user to change password shell: chage -d 0 {{ new_user_name }} when: user_created.changed - name: User created debug: msg="Password for {{ new_user_name }} is {{ user_password.stdout }}" when: user_created.changed 

If you want to create a new user:

 ansible-playbook -i hosts.ini create_user.yml --extra-vars "new_user_name=kelvin" 
+5
Jun 21 '16 at 2:35
source share

Here's how it worked for me

 - hosts: main vars: # created with: # python -c "from passlib.hash import sha512_crypt; print sha512_crypt.encrypt('<password>')" # above command requires the PassLib library: sudo pip install passlib - password: '$6$rounds=100000$H/83rErWaObIruDw$DEX.DgAuZuuF.wOyCjGHnVqIetVt3qRDnTUvLJHBFKdYr29uVYbfXJeHg.IacaEQ08WaHo9xCsJQgfgZjqGZI0' tasks: - user: name=spree password={{password}} groups=sudo,www-data shell=/bin/bash append=yes sudo: yes 
+3
Aug 12 '14 at 17:50
source share

This is an easy way:

 --- - name: Create user user: name=user shell=/bin/bash home=/srv/user groups=admin,sudo generate_ssh_key=yes ssh_key_bits=2048 - name: Set password to user shell: echo user:plain_text_password | sudo chpasswd no_log: True 
+3
Jan 03 '15 at 23:59
source share

The task definition for the user module should be different in the latest version of Ansible.

 tasks: - user: name=test password={{ password }} state=present 
+2
Jan 23 '14 at 13:49
source share

By combining several solutions from above, I created a tutorial that automatically generates the correct password hashes based on plaintext passwords stored in an encrypted local file of irreplaceable storage:

 --- - hosts: [your hosts] tasks: - include_vars: [path to your encrypted vault file] - local_action: "command openssl passwd -salt '{{password_salt}}' -1 '{{password}}'" register: password_hash - user: > name=[your username] state=present password="{{password_hash.stdout}}" 

Run this command using the "-ask-vault-pass" option to decrypt your vault file (see the section "Persistent vault" for information on how to manage encrypted vault).

+2
Dec 03 '14 at 17:52
source share

Just for completeness, I will send the ad-hoc command using ansible, as there is a trick.

First, try creating an encrypted password using the mkpasswd utility, which is available on most Linux systems:

 mkpasswd --method=SHA-512 

Then try the ansible ad-hock command:

 ansible all -m user -a 'name=testuser shell=/bin/bash \ comment="Test User" password=$6$XXXX' -k -u admin --sudo 

But make sure that:

  • The command is in single quotes, NOT double, otherwise your password will never work.
  • Run it with --sudo or you get an error ( useradd: cannot lock /etc/passwd; try again later )
+2
Oct. 15 '15 at 2:37
source share

You can use hidden storage to use secret keys in books. Define your password in yml.

ex. pass: secret or

 user: pass: secret name: fake 

encrypt your secrets file with

ansible-vault encrypt /path/to/credential.yml

ansible will ask for a password to encrypt it. (I will explain how to use this passage)

And then you can use your variables wherever you want. No one can read them without a storage key.

Using the storage key:

via the passing argument when the playbook starts.

 --ask-vault-pass: secret 

or you can save to a file, for example password.txt, and hide it somewhere. (useful for CI users)

 --vault-password-file=/path/to/file.txt 

In your case: enable vars yml and use variables.

 - include_vars: /path/credential.yml - name: Add deployment user action: user name={{user.name}} password={{user.pass}} 
+2
Oct 16 '15 at 17:50
source share

How to create an encrypted password to go to password var in the Ansible user task (from @Brendan Wood's comment):

 openssl passwd -salt 'some_plain_salt' -1 'some_plain_pass' 

The result will look like this:

 $1$some_pla$lmVKJwdV3Baf.o.F0OOy71 

user task example:

 - name: Create user user: name="my_user" password="$1$some_pla$lmVKJwdV3Baf.o.F0OOy71" 

UPD: crypt using SHA-512 see here and here :

Python

 $ python -c "import crypt, getpass, pwd; print crypt.crypt('password', '\$6\$saltsalt\$')" $6$saltsalt$qFmFH.bQmmtXzyBY0s9v7Oicd2z4XSIecDzlB5KiA2/jctKu9YterLp8wwnSq.qc.eoxqOmSuNp2xS0ktL3nh/ 

Perl

 $ perl -e 'print crypt("password","\$6\$saltsalt\$") . "\n"' $6$saltsalt$qFmFH.bQmmtXzyBY0s9v7Oicd2z4XSIecDzlB5KiA2/jctKu9YterLp8wwnSq.qc.eoxqOmSuNp2xS0ktL3nh/ 

ruby

 $ ruby -e 'puts "password".crypt("$6$saltsalt$")' $6$saltsalt$qFmFH.bQmmtXzyBY0s9v7Oicd2z4XSIecDzlB5KiA2/jctKu9YterLp8wwnSq.qc.eoxqOmSuNp2xS0ktL3nh/ 
+1
Aug 14 '14 at 9:23
source share

Mxx's answer is correct, but the python crypt.crypt() method is unsafe when different operating systems are involved (related to the glibc hashing algorithm used on your system.)

For example, it will not work if you create your hash from MacOS and run the playbook on linux. In this case, you can use passlib ( pip install passlib to install locally).

 from passlib.hash import md5_crypt python -c 'import crypt; print md5_crypt.encrypt("This is my Password,salt="SomeSalt")' '$1$SomeSalt$UqddPX3r4kH3UL5jq5/ZI.' 
+1
Nov 30 '15 at 12:10
source share

None of the solutions worked directly on my Mac running Ubuntu. So, for others, combining the answers of Mxx and JoelB, here is the current Python 3 solution:

 pip3 install passlib python3 -c 'from passlib.hash import md5_crypt; \ print(md5_crypt.encrypt("This is my Password", salt="SomeSalt"))' 

The result will be $1$SomeSalt$UqddPX3r4kH3UL5jq5/ZI. as in Mxx's answer.

Even better , use SHA512 instead of MD5:

 python3 -c 'from passlib.hash import sha512_crypt; \ print(sha512_crypt.encrypt("This is my Password", salt="SomeSalt"))' 

Result:

$ 6 $ rounds = 656000 $ SomeSalt $ oYpmnpZahIsvn5FK8g4bDFEAmGpEN114Fe6Ko4HvinzFaz5Rq2UXQxoJZ9ZQyQoi9zaBo3gBH / FEAov3FHv48

+1
05 Oct '17 at 22:22
source share

If you want to do this as Ansible ad-hoc, you can do the following:

 $ password='SomethingSecret!' $ ansible 192.168.1.10 -i some_inventory -b -m user -a "name=joe_user \ update_password=always password=\"{{ \"$password\" | password_hash('sha512') }}\"" 

The output of the command above:

 192.168.1.10 | SUCCESS => { "append": false, "changed": true, "comment": "Joe User", "group": 999, "home": "/home/joe_user", "move_home": false, "name": "joe_user", "password": "NOT_LOGGING_PASSWORD", "shell": "/bin/bash", "state": "present", "uid": 999 } 
0
Oct 22 '17 at 6:05
source share

I know I'm late for the party, but I'm using a different solution. This may be useful for distributions that do not have --stdin in the passwd binary.

 - hosts: localhost become: True tasks: - name: Change user password shell: "yes '{{ item.pass }}' | passwd {{ item.user }}" loop: - { pass: 123123, user: foo } - { pass: asdf, user: bar } loop_control: label: "{{ item.user }}" 

The label in loop_control is responsible for printing only the username. All vars_files: or only user variables (you can use vars_files: must be encrypted using ansible-vault.

0
Aug 20 '18 at 2:02
source share

Random password generation for user

first you need to define a user variable, and then follow below

tasks:

 - name: Generate Passwords become: no local_action: command pwgen -N 1 8 with_items: '{{ users }}' register: user_passwords - name: Update User Passwords user: name: '{{ item.item }}' password: "{{ item.stdout | password_hash('sha512')}}" update_password: on_create with_items: '{{ user_passwords.results }}' - name: Save Passwords Locally become: no local_action: copy content={{ item.stdout }} dest=./{{ item.item }}.txt with_items: '{{ user_passwords.results }}' 
0
Mar 06 '19 at 16:26
source share

My solution uses search and automatically generate a password.

 --- - hosts: 'all' remote_user: root gather_facts: no vars: deploy_user: deploy deploy_password: "{{ lookup('password', '/tmp/password chars=ascii_letters') }}" tasks: - name: Create deploy user user: name: "{{ deploy_user }}" password: "{{ deploy_password | password_hash('sha512') }}" 
0
Mar 27 '19 at 13:15
source share

Well, I was really late for the party :) I had a need for a skillful game that creates several local users with random passwords. This is what I came up with, used some examples from above and combined them with some changes.

create user c-password.yml itself

 --- # create_user playbook - hosts: all become: True user: root vars: #Create following user users: - test24 - test25 #with group group: wheel roles: - create-user-with-password 

/roles/create-user-with-password/tasks/main.yml

 - name: Generate password for new user local_action: shell pwgen -s -N 1 20 register: user_password with_items: "{{ users }}" run_once: true - name: Generate encrypted password local_action: shell python -c 'import crypt; print(crypt.crypt( "{{ item.stdout }}", crypt.mksalt(crypt.METHOD_SHA512)))' register: encrypted_user_password with_items: "{{ user_password.results }}" run_once: true - name: Create new user with group user: name: "{{ item }}" groups: "{{ group }}" shell: /bin/bash append: yes createhome: yes comment: 'Created with ansible' with_items: - "{{ users }}" register: user_created - name: Update user Passwords user: name: '{{ item.0 }}' password: '{{ item.1.stdout }}' with_together: - "{{ users }}" - "{{ encrypted_user_password.results }}" when: user_created.changed - name: Force user to change the password at first login shell: chage -d 0 "{{ item }}" with_items: - "{{ users }}" when: user_created.changed - name: Save Passwords Locally become: no local_action: copy content={{ item.stdout }} dest=./{{ item.item }}.txt with_items: "{{ user_password.results }}" when: user_created.changed 
-one
Feb 05 '19 at 20:18
source share



All Articles