Ansible create user with password, dont change it if user exists - ansible

I have some servers which I want to administer with ansible. Currently I need to create user acounts on all of them. On some of them, some accounts are already present. I want to create the users with a default password, but if the user exist don't change his password.
Can someone help me with this condition ?
Here is my playbook :
---
- hosts: all
become: yes
vars:
sudo_users:
# password is generated through "mkpasswd" command from 'whois' package
- login: user1
password: hashed_password
- login: user1
password: hashed_password
tasks:
- name: Make sure we have a 'sudo' group
group:
name: sudo
state: present
- user:
name: "{{ item.login }}"
#password: "{{ item.password }}"
shell: /bin/bash
groups: "{{ item.login }},sudo"
append: yes
with_items: "{{ sudo_users }}"

From the docs of user module:
update_password (added in 1.3) always/on_create
always will update passwords if they differ. on_create will only set the password for newly created users.

Related

Getting error when changing Ansible password

I am building an ansible playbook to change multiple passwords on our network. And it works! It changes all of the passwords like it is supposed to. However, the last password it changes is the ansible password, which then throws an error because it tries to do the success check using the old Ansible password. Is there a way to tell Ansible to use a different password after changing the password? Below is the entire playbook.
---
# Update local administrator on all Windows systems
- hosts: windows
gather_facts: yes
ignore_errors: no
tasks:
- name: Set Windows Administrator password
ansible.windows.win_user:
name: administrator
update_password: always
password: "{{ new_win_admin_pass }}"
- name: Set ansible password.
ansible.windows.win_user:
name: ansible
update_password: always
password: "{{ new_ansible_pass }}"
# Update all Linux accounts.
# This must always run last, once ansible password is changed, no further changes can occur.
- hosts: rhel
become: yes
gather_facts: yes
ignore_errors: no
tasks:
- name: Set Workstation admin password.
hosts: rhel_workstations
ansible.builtin.user:
name: admin
update_password: always
password: "{{ new_admin_pass | password_hash ('sha512')}}"
- name: Set Linux root password.
ansible.builtin.user:
name: root
update_password: always
password: "{{ new_root_pass | password_hash ('sha512')}}"
- name: Set ansible password.
ansible.builtin.user:
name: ansible
update_password: always
password: "{{ new_ansible_pw_var | password_hash ('sha512')}}"
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

Ansible playbook that runs a script and fetch the outpot back to the playbook

im trying to run a playbook that will create a user and will add it to /etc/sudoers,
so i wrote this thing
- hosts: "{{ hostname }}"
vars_prompt:
- name: user
prompt: "Enter user"
private: no
- name: password
prompt: "Enter password"
tasks:
- name: Create the new user
user:
name: "{{ user }}"
state: present
#state: absent
password: "{{ password | password_hash('sha512', 'password') }}"
groups: SSHusers
- name: Add line in /etc/sudoers
lineinfile:
dest: /etc/sudoers
line: "User_Alias LINUX_ADMINS = Example, {{ user }}"
regexp: "^User_Alias LINUX_ADMINS."
state: present
#state: absent
- name: Run chage for user
command: chage -d 9999999999 "{{ user }}"
- name: Run chage for user
command: chage -M -1 "{{ user }}"
the problem is that i replace the line in - name: Add line in /etc/sudoers
an the i have to change it every time i add a new user.
i need to run something like that on the host Admin_Users=$(grep -w 'LINUX_ADMINS =' /etc/sudoers) and bring the var back so that my playbook will be able to use it ,
any suggestion to how should i do it ?
thanks for the help
You have to restructure your playbook.
You still run the "user" task for each user.
But you run the "lineinfile" task not for a single user but for all users together.
If you pass all users to "lineinfile", the task can craft the whole line at once. And so the problem to change the line incrementally for each user disappears.

Adding users in ansible and enforcing password change, resets user's password when adding new user

I am having problems with Ansible and adding new users to servers.
Firstly I check if the users are present on the system and if not, then I proceed to create them.
I found a somewhat similar problem here: ansible user module always shows changed
and I was able to fix the changed status when adding a new user in the file userlist with adding a simple salt.
However, the last part, which is the handler, is always performed.
This is how my playbook looks like:
---
- hosts: all
become: yes
vars_files:
- /home/ansible/userlist
tasks:
# check if user exists in system, using the username
# and trying to search inside passwd file
- name: check user exists
getent:
database: passwd
key: "{{ item }}"
loop: "{{ users }}"
register: userexists
ignore_errors: yes
- name: add user if it does not exit
user:
name: "{{ item }}"
password: "{{ 'password' | password_hash('sha512', 'mysecretsalt') }}"
update_password: on_create
loop: "{{ users }}"
when: userexists is failed
notify: change password
handlers:
- name: change user password upon creation
shell: chage -d 0 "{{ item }}"
loop: "{{ users }}"
listen: change password
And here is the simple file called userlist:
users:
- testuser1
- testuser2
- testuser3
- testuser22
When I am running the playbook without changes to the userlist file, everything is fine.
However, if I add a new user to the file, then, when an existing user tries to log in, the system enforces them to change their password, because the handler is always called.
Is there any way to alter the code in a way that the enforcing of changing the password immediately is only performed on newly created users?
There are 2 main issues in your playbook:
userexists is registering each result individually, but you are referencing only the overall "failure" result. Use a debug statement to show the variable to see what I mean
If the handler is notified, you are looping on all users, rather than only those that have "changed" (i.e. have been created)
There's a couple of different approaches to fix this, but I think this might be the most succinct:
tasks:
- name: add user if it does not exist
user:
name: "{{ item }}"
password: "{{ 'password' | password_hash('sha512', 'mysecretsalt') }}"
update_password: on_create
loop: "{{ users }}"
register: useradd
notify: change password
handlers:
- name: change user password upon creation
shell: chage -d 0 {{ item.name }}
loop: "{{ useradd.results }}"
when: item.changed
listen: change password

Become a sudoer user with password associated with host information

I need to access a few servers whose passwords are built using servers hostname, so, let's suppose hostname is: fancyHost and password prefix is "principio", then the sudoer user's (contoso-r in this example) password is going to be: "principiofancyHost". This in order to assign a new password to each host.
Problem is I managed to connect and stablish a custom password as a variable, and scalate to sudoer, but seems like ansible become_pass is not meant to be manipulated inside the task, which makes difficult to concatenate the prefix with the hostname.
- hosts: test
vars:
prefix: "principio"
ansible_become_pass: “hardToGuessPassword123”
tasks:
- name: getting current server hostname
command: hostname
register: hostname
- name: getting current user name
command: whoami
register: current_username
- name: print current server hostname
debug:
msg: "Current user: {{current_username.stdout}} |||  Hostname is: {{ hostname.stdout}} ||| Password should be: {{ prefix + hostname.stdout}}"
- name: changing contoso-r' s password
become: True
become_user: contoso-r
become_method: su
user:
name: contoso-r
password: "{{ (prefix + hostname.stdout) | password_hash('sha512') }}"
state: present
shell: /bin/bash
system: no
createhome: no
How could I set a custom password relative to each host instead a global become_pass or ansible_become_pass?
Thanks for your time
You stated:
I managed to connect ... and escalate to sudoer, ...
It's not necessary to "become_user: contoso-r" when "changing contoso-r' s password".
- name: changing contoso-r' s password
user:
name: contoso-r
password: "{{ (prefix + hostname.stdout) | password_hash('sha512') }}"

How to get the list of authorized_keys of a given user?

I want to write a ansible playbook where we can provide a username and ansible will display the authorized keys for that user. The path to the authorized keys is {{user_home_dir}}/.ssh/authorized_keys.
I tried with shell module like below:
---
- name: Get authorized_keys
shell: cat "{{ user_home_dir }}"/.ssh/authorized_keys
register: read_key
- name: Prints out authorized_key
debug: var=read_key.stdout_lines
The problem is, it will show me the file inside /home/ansible/.ssh/authorized_keys. "ansible" is the user that I am using to connect to remote machine.
Below is vars/main.yml
---
authorized_user: username
user_home_dir: "{{ lookup('env','HOME') }}"
Any idea? FYI I am new to ansible and tried this link already.
In your vars file, you have
user_home_dir: "{{ lookup('env','HOME') }}"
Thanks to Konstantin for pointing it out... All lookups are executed on the control host. So the lookup to env HOME will always resolve to the home directory of the user, from which ansible is being invoked.
You could use the getent module from ansible to retrieve an user's info. The below snippet should help
---
- hosts: localhost
connection: local
remote_user: myuser
gather_facts: no
vars:
username: myuser
tasks:
- name: get user info
getent:
database: passwd
key: "{{ username }}"
register: info
- shell: "echo {{ getent_passwd[username][4] }}"
Below worked. We need to have become too otherwise we will get permission denied error.
---
- hosts: local
remote_user: ansible
gather_facts: no
become: yes
become_method: sudo
vars:
username: myuser
tasks:
- name: get user info
getent:
split: ":"
database: passwd
key: "{{ username }}"
- name: Get authorized_keys
shell: cat "{{ getent_passwd[username][4] }}"/.ssh/authorized_keys
register: read_key
- name: Prints out authorized_key
debug: var=read_key.stdout_lines

Resources