Creating User Passwords from an Ansible Playbook

Creating a new user and password with Ansible

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.

How do I create a user and set a password using ansible?

The python example shown in the documentation depends on what version of crypt is running on the OS you are using.

I generated the crypt on OS X and the server I was targetting is ubuntu.

Due to differences in which implementation of crypt is offered by the OS, the result is different and incompatible.

Use this instead:

http://pythonhosted.org/passlib/

Passlib is a password hashing library for Python 2 & 3, which provides
cross-platform implementations of over 30 password hashing algorithms,
as well as a framework for managing existing password hashes. It’s
designed to be useful for a wide range of tasks, from verifying a hash
found in /etc/shadow, to providing full-strength password hashing for
multi-user application.

>>> # import the hash algorithm
>>> from passlib.hash import sha512_crypt

>>> # generate new salt, and hash a password
>>> hash = sha512_crypt.encrypt("password")
>>> hash

'$6$rounds=656000$BthPsosdEpqOM7Qd$l/ln9nyEfxM67ea8Bvb79JoW50pGjf6iM87taIvfSmpjasE4/wBG1.60pFS6W992T7Q1q2wikMbxYUvMHD1tT1'

User password creation in ansible playbook

in the second task you have "password | password_hash('sha512', 'mysecretsalt') }}" it must be "{{ password | password_hash('sha512', 'mysecretsalt') }}" to use use te var password or "{{ 'password' | password_hash('sha512', 'mysecretsalt') }}" to use the word password as password.

How to pass a user / password in ansible command

The docs say you can specify the password via the command line:

-k, --ask-pass.

ask for connection password

Ansible can also store the password in the ansible_password variable on a per-host basis.

Ansible create Users and Group

Couple of things:

  • To use variables from ubuntu file you need specify the vars file in playbook.
  • To use default_user_password as a variable, remove the quotes '
  • If you want admin as the users primary group then use group attribute instead. groups on the other hand takes a list and add the users to the listed groups.

And, if the group isn't created yet on the target machine then first create the group using group module.

Playbook after the above changes.

---
- name: Create Users & Groups
hosts: target1
gather_facts: false
vars_files: ubuntu
tasks:
- name: Create group
group:
name: "{{ admin_group }}"
state: present

- name: Create Users Task
user:
name: "{{ item }}"
state: present
password: "{{ default_user_password | password_hash('sha512','A512') }}"
shell: /bin/bash
group: "{{ admin_group }}"
loop:
- Rajini
- Kamal

Create password and write it to file

I'm not 100% sure I understood your question.

The below will take your actual user list, create a new one with a generated password for each and store the result in a single file for all users. Bonus: if the file exists, the var will be initialized from there bypassing the password creation.

Notes:

  • The below can be enhanced. You can put the block tasks for file creation in a separate file and use a conditional include so that the skipped loop iteration do not take place at all when the file already exists.
  • I obviously did not take security into account here and I strongly suggest you secure the way your file is stored.

Demo playbook:

---
- name: Create random passwords and store
hosts: localhost
gather_facts: false

vars:

users_with_pass_file: /tmp/test_pass.txt

students:
- Username: testuser1
E-Mail: student1@student.com
- Username: testuser2
E-Mail: student2@student.com

tasks:

- name: Try to load users and passwords from file if it exists
vars:
file_content: "{{ lookup('ansible.builtin.file', users_with_pass_file, errors='ignore') }}"
ansible.builtin.set_fact:
users_with_pass: "{{ file_content }}"
when:
- file_content | length > 0
# Unfortunately, there is no test 'is list' in jinja2...
- file_content is iterable
- file_content is not mapping
- file_content is not string
ignore_errors: true
changed_when: false
register: load_from_disk

- name: Create user list with passwords and store it if it does not exists (or is malformed...)
block:

- name: Create the list
vars:
user_password: "{{ lookup('ansible.builtin.password', '/dev/null', length=12) }}"
ansible.builtin.set_fact:
users_with_pass: "{{ users_with_pass | default([]) + [item | combine({'password': user_password})] }}"
loop: "{{ students }}"

- name: Store the result
ansible.builtin.copy:
dest: "{{ users_with_pass_file }}"
content: "{{ users_with_pass | to_json }}"

when: load_from_disk is skipped or load_from_disk is failed

- name: Show the result
ansible.builtin.debug:
var: users_with_pass

first run (with used ansible version):

$ ansible-playbook --version
ansible-playbook 2.10.1
config file = None
configured module search path = ['/home/user/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/local/lib/python3.6/dist-packages/ansible
executable location = /usr/local/bin/ansible-playbook
python version = 3.6.9 (default, Jul 17 2020, 12:50:27) [GCC 8.4.0]

$ ansible-playbook test.yml

PLAY [Create random passwords and store] ***********************************************************************************************************************************************************************************************

TASK [Try to load users and passwords from file if it exists] **************************************************************************************************************************************************************************
[WARNING]: Unable to find '/tmp/test_pass.txt' in expected paths (use -vvvvv to see paths)
skipping: [localhost]

TASK [Create the list] *****************************************************************************************************************************************************************************************************************
ok: [localhost] => (item={'Username': 'testuser1', 'E-Mail': 'student1@student.com'})
ok: [localhost] => (item={'Username': 'testuser2', 'E-Mail': 'student2@student.com'})

TASK [Store the result] ****************************************************************************************************************************************************************************************************************
changed: [localhost]

TASK [Show the result] *****************************************************************************************************************************************************************************************************************
ok: [localhost] => {
"users_with_pass": [
{
"E-Mail": "student1@student.com",
"Username": "testuser1",
"password": "5l1RG7HzqaKMWJcH:mRH"
},
{
"E-Mail": "student2@student.com",
"Username": "testuser2",
"password": "tZvLT3LVj3_60GV_WoQd"
}
]
}

PLAY RECAP *****************************************************************************************************************************************************************************************************************************
localhost : ok=3 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0

Second run:

PLAY [Create random passwords and store] ***********************************************************************************************************************************************************************************************

TASK [Try to load users and passwords from file if it exists] **************************************************************************************************************************************************************************
ok: [localhost]

TASK [Create the list] *****************************************************************************************************************************************************************************************************************
skipping: [localhost] => (item={'Username': 'testuser1', 'E-Mail': 'student1@student.com'})
skipping: [localhost] => (item={'Username': 'testuser2', 'E-Mail': 'student2@student.com'})

TASK [Store the result] ****************************************************************************************************************************************************************************************************************
skipping: [localhost]

TASK [Show the result] *****************************************************************************************************************************************************************************************************************
ok: [localhost] => {
"users_with_pass": [
{
"E-Mail": "student1@student.com",
"Username": "testuser1",
"password": "5l1RG7HzqaKMWJcH:mRH"
},
{
"E-Mail": "student2@student.com",
"Username": "testuser2",
"password": "tZvLT3LVj3_60GV_WoQd"
}
]
}

PLAY RECAP *****************************************************************************************************************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0

Getting error when changing Ansible password

I'd try to do this with an async task and check back on the result with the new password:

- hosts: rhel
become: yes

tasks:
- name: Set ansible password.
ansible.builtin.user:
name: ansible
update_password: always
password: "{{ new_ansible_pw_var | password_hash ('sha512')}}"
async: 15
poll: 0
register: change_ansible_password

- name: Check ansible password change was successful
vars:
ansible_password: "{{ new_ansible_pw_var }}"
async_status:
jid: "{{ change_ansible_password.ansible_job_id }}"
register: job_result
until: job_result.finished
retries: 15
delay: 1

- name: polite guests always clean after themselves when necessary (see doc)
vars:
ansible_password: "{{ new_ansible_pw_var }}"
async_status:
jid: "{{ change_ansible_password.ansible_job_id }}"
mode: cleanup


Related Topics



Leave a reply



Submit