Ansible with_items a second list as condition - ansible

I have a full list of users that I create on every system. How can I make a condition for every system to create users only defined in the group_vars variable system_users?
vars: users.yml
users:
user1:
username: user1
password: "example"
user2:
username: user2
password: "example"
user3:
username: user3
password: "example"
group_var: dev-systems.yml
system_users:
- "user1"
- "user2"
task: main.yml
- name: Create users and change password
user:
name: "{{ users[item].username }}"
password: "{{ users[item].password }}"
shell: /bin/bash
state: present
update_password: on_create
become: true
with_items: "{{ users }}"
hosts
[dev-systems]
example-system.local

Try this
- name: Create users and change password
user:
name: "{{ item.username }}"
password: "{{ item.password }}"
shell: /bin/bash
state: present
update_password: on_create
become: true
loop: "{{ system_users|map('extract',users)|list }}"

Related

Hi is there a way to use 2 different variable files within same task in ansible?

This is playbook that creates users.I want to create user(that takes username and uid) accoording to userlist.yml but passwords will be taken in passwords.yml. But don't know exact syntax
- name: add users
hosts: new
vars_files:
- userlist.yml
- passwords.yml
tasks:
- name: adduser
user:
name: "{{ item.username }}"
password: "{{ item.password | password_hash('sha512') }}"
uid: "{{item.uid}}"
state: present
with_items:
?????????????
#userlist.yml
users:
- username: xman
uid: 8254
- username: yman
uid: 8252
- username: zman
uid: 8258
#passwords.yml
password: devops2019!
Given "passwords will be taken in passwords.yml". For example
#passwords.yml
password:
- 'devops2019!'
- 'devops2020!'
- 'devops2021!'
The task below does the job
- name: adduser
user:
name: "{{ item.0.username }}"
password: "{{ item.1 | password_hash('sha512') }}"
uid: "{{ item.0.uid }}"
state: present
loop: "{{ users | zip(password) | list }}"
(not tested)

Ansible manage ssh users with templates

I've got an ansible playbook for adding over 50 ssh-users for a packer ami build.
Here is how my /playbooks/roles/users/tasks/create_user.yml: looks like.
---
- name: "User {{ item.name }}"
user:
comment: "Add {{ item.name }} account"
name: "{{ item.name }}"
home: "/data/companies/project/{{ item.name }}"
state: present
uid: "{{ item.uid }}"
group: company
groups: company
shell: /sbin/nologin
state: present
generate_ssh_key: no
password: "{{ item.password }}"
- name: "Create home directory for {{ item.name }}"
file:
path: "/data/companies/project/{{ item.name }}"
state: directory
owner: "{{ item.name }}"
group: company
mode: 0700
Here's how /playbooks/roles/users/vars/main.yml file looks like
---
location: UK
users:
- name: user1
password: $6$8T8lH2vS$JKIdqkQmHUHR/s75RYMguPyHTisnNrXIPOjJ9IWxMHB4LY9PJX.3rgkmfLCWAHDi5VYZno2ntlYm7Kkdy0iAZ.
uid: 601
location: UK
- name: user2
password: $6$8T8lH2vS$JKIdqkQmHUHR/s75RYMguPyHTisnNrXIPOjJ9IWxMHB4LY9PJX.3rgkmfLCWAHDi5VYZno2ntlYm7Kkdy0iAZ
uid: 602
location: USA
Here's how my "/playbooks/roles/users/tasks/main.yml" looks like
---
- name: Create users based on location
include: create_users.yml
loop: "{{ users | selectattr('location', 'equalto', location) | list }}"
When the corresponding packer build has been run there are no errors but user1,user2 and their attributes are not getting created.
amazon-ebs: TASK [: Create users based on location] ***********************************
amazon-ebs:
amazon-ebs: PLAY RECAP *********************************************************************
amazon-ebs: default : ok=10 changed=7 unreachable=0 failed=0
amazon-ebs:
Please can someone help me understand as to why users are not getting created? Thanks
This is commonly approached through the use of variables and loops. Extract all the variable stuff out into a list variable, containing dictionaries of params, then use a loop to read through and apply. So based on your role approach:
Create a task file containing the two tasks to run - /playbooks/roles/users/tasks/create_user.yml:
---
- name: User "{{ item.name }}"
user:
comment "{{ item.name }} company account"
name: "{{ item.name }}"
home: "/data/company/{{ item.name }}"
state: present
uid: 666
group: company
groups: company
shell: /bin/bash
state: present
generate_ssh_key: no
password: "{{ item.password }}"
- name: "Create home directory for {{ item.name }}"
file:
path: "/data/company/{{ item.name }}"
state: directory
owner: "{{ item.name }}"
group: company
mode: 0700
Create a vars file containing your users - /playbooks/roles/users/vars/main.yml:
---
location: UK # This will be your default. It can be overridden in a variety of places
users:
- name: user1
password: <some password>
location: US
- name: user2
password: <some password>
location: UK
- name: user3
password: <some password>
location: UK
then in /playbooks/roles/users/tasks/main.yml:
---
- name: Create users based on location
include: create_user.yml
loop: "{{ users | selectattr('location', 'equalto', location) | list }}"
Hopefully most of it is self explanatory. Because you are using a role, by placing the users variable in /playbooks/roles/users/vars/main.yml, the variable is automatically made available. The users | selectattr('location', 'equalto', location) expression, takes the user variable and filters the list to only include objects where the 'location' element is equal to the value specified in the 'location' variable.
Variables
Loops
Roles
Some additional hints, you can use defaults too.
Also, in case you want to protect the encrypted passwords, you can store them in Ansible Vault:
users.yml example:
users:
- name: user1
uid: 666
group: group1
groups: [allusers]
comment: User One
home: /home/user1
shell: /bin/bash
passwords: "{{ vault_passwords }}"
The vault file you crypt with 'ansible-vault' command looks like (decrypted):
passwords:
- name: user1
password: $6$509875346RH.RAaVNW2iWtf/QJ4zUGaJiEyh.
playbook included tasks file example:
- name: Set up user accounts
user:
name: "{{ item.name }}"
create_home: '{{ item.createhome | default("no") }}'
uid: "{{ item.uid }}"
group: "{{ item.group }}"
state: '{{ item.state | default("present") }}'
comment: '{{ item.comment | default("Ansible created comment") }}'
home: "{{ item.home }}"
shell: '{{ item.shell | default("/bin/bash") }}'
with_items: "{{ users }}"
- name: Set up user account passwords
user:
name: "{{ item.name }}"
password: '{{ item.password | default("*") }}'
with_items: "{{ passwords }}"

Granularly manage system users with Ansible

I am using an Ansible playbook to manage users (taken from https://keksi.io/tutorials/2016/12/05/how-to-manage-remote-server-users-with-ansible/):
vars/users.yml file (users, user to group assignments, passwords, SSH keys):
---
users:
- username: user1
comment: "User 1"
group: admin
password: "sha password"
keys:
active:
- "ssh-rsa etc"
admin: yes
- username: user2
comment: "User 2"
group: users
groups: deployer
keys:
active:
- "ssh-rsa etc"
- username: user3
[...]
And this is the playbook:
- hosts: all
become: true
tasks:
- include_vars: ../vars/users.yml
- name: Install sudo
apt: name=sudo state=present
- name: Add the group admin
group:
name: admin
state: present
- name: Create users
user:
name: "{{ item.username }}"
comment: "{{ item.comment | default('User {{item.username}}') }}"
password: "{{ item.password | default('!') }}"
state: "{{ item.state | default('present') }}"
shell: "{{ item.shell | default('/bin/bash') }}"
group: "{{ item.group | default('users') }}"
when: item.username is defined
with_items: '{{ users }}'
- name: Setup administrator users with complete sudo access
user: name={{ item.username }} groups=sudo append=yes
with_items: '{{ users }}'
when: item.admin is defined and item.admin == True
- name: Add SSH-keys to users
authorized_key:
user: "{{ item.0.username }}"
key: "{{ item.1 }}"
with_subelements:
- "{{ users }}"
- keys.active
- flags:
skip_missing: True
when: item.0.state is not defined or item.0.state != "absent"
- name: Remove old SSH-keys from users
authorized_key:
user: "{{ item.0.username }}"
key: "{{ item.1 }}"
state: absent
with_subelements:
- "{{ users }}"
- keys.disabled
- flags:
skip_missing: True
when: item.0.state is not defined or item.0.state != "absent"
I can correctly execute this playbook on all servers and have admin and normal users created and managed on them.
Now I want to add a new step. I have several servers, and not every users should be configured on every server, and some users should be in an additional group only on some servers (for example developers on developing servers).
So I wish to create some assignments for users on hosts or host groups, something like:
- host: host1
admins:
- user1
- user2
deployers:
- user2
- user3
users:
- user4
- user5
- host: hostgroup1
admins:
- user2
users:
- user3
- user5
So I would like to be able to execute the playbook on all servers to have users created or updated based on this declarations, without writing a duplication of the playbook for every host.
I don't have any idea about how to achieve this, could you help me please?
Edit: I tried to add a new "hosts" key in my users.yml variable file, this way:
---
users:
- username: user1
comment: "User 1"
group: admin
password: "sha password"
keys:
active:
- "ssh-rsa etc"
admin: yes
- username: user2
comment: "User 2"
group: users
groups: deployer
keys:
active:
- "ssh-rsa etc"
hosts:
user:
- host1
- host2
deployer:
- host3
And I modified the task this way:
- name: Create users
user:
name: "{{ item.username }}"
comment: "{{ item.comment | default('User {{item.username}}') }}"
password: "{{ item.password | default('!') }}"
state: "{{ item.state | default('present') }}"
shell: "{{ item.shell | default('/bin/bash') }}"
group: "{{ item.group | default('users') }}"
with_items: '{{ users }}'
when: item.username is defined and ((item.admin is defined and item.admin == True) or (item.hosts is defined and item.hosts.user is defined and inventory_hostname in item.hosts.user)
My explanation: I need to create the user if it's admin (so it must be created on every host or if the current host's inventory_hostname is listed into one of the hosts subkeys arrays (in a second step I wish to extend this check also if the current host is in an hostgroup listed in one of item.hosts subkeys.
The problem is that this way user1 is created (because item.admin is True) but user2 not because the other condition is always False.
You could use host_vars or group_vars to store the users data instead of vars/users.yml
When you run the playbook against multiple hosts the appropriate values for each host or group member will be read from the related group_vars or host_cars file
See here for more information: https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html#splitting-out-host-and-group-specific-data

Ansible check if inventory_hostname is in list

I am trying to check if inventory_hostname is in a list into an imported variable.
vars/users.yml file:
---
users:
- username: user1
comment: "User 1"
group: admin
password: "sha password"
keys:
active:
- "ssh-rsa etc"
admin: yes
- username: user2
comment: "User 2"
group: users
groups: deployer
keys:
active:
- "ssh-rsa etc"
hosts:
user:
- host1
- host2
deployer:
- host3
I want to execute a task only if inventory_hostname is into any of hosts lists (user, deployer, others ...).
I tried this:
- name: Create users
user:
name: "{{ item.username }}"
comment: "{{ item.comment | default('User {{item.username}}') }}"
password: "{{ item.password | default('!') }}"
state: "{{ item.state | default('present') }}"
shell: "{{ item.shell | default('/bin/bash') }}"
group: "{{ item.group | default('users') }}"
with_items: '{{ users }}'
when: item.username is defined and ((item.admin is defined and item.admin == True) or (item.hosts is defined and item.hosts.user is defined and inventory_hostname in item.hosts.user)
It works for user1 (which have admin enabled) but not for user2 (if this play is executed on host1 which is included into user2's hosts.user list).
Well .. I tried your code snippet and it works well for both users. Only thing which can make it fail is that hostnames in item.host.user are not matching the inventory_hostname. You can try to debug the inventory_hostname before this task to see what are the inventory hostnames read by ansible and whether you have specified them correctly in item.host.user list.
- debug: var=inventory_hostname

Ansible password_hash with variable

I am writing a simple task to create a user. As part of this task, I want to read the password from defaults/main.yml
defaults/main.yml
test_user: testuser
test_group: testgroup
test_user_password: somepassword
my tasks file is as below
- name: "Creating Group for testuser"
group:
name: "{{ test_group }}"
state: present
- name: "Creating testuser"
user:
name: "{{ test_user }}"
password: "{{ [test_user_password] | password_hash('sha512') }}"
shell: /bin/ksh
group: "{{ test_group }}"
update_password: on_create
This gives me a unexpected templating error. How can I read the password from main.yml and use it inside the password filter?
In the Creating testuser task remove the square brackets around test_user_password. When a variable is referenced in Ansible it has to be enclosed with {{}}.
- hosts: localhost
remote_user: user
become: yes
vars:
test_user: testuser
test_group: testgroup
test_user_password: somepassword
tasks:
- name: Creating Group for testuser
group:
name: "{{ test_group }}"
state: present
- name: Creating testuser
user:
name: "{{ test_user }}"
password: "{{ test_user_password | password_hash('sha512') }}"
shell: /bin/bash
group: "{{ test_group }}"
update_password: on_create
Take into account that given task will always be marked as "changed" meaning that it is not idempotent. To avoid this behaviour you can add salt as a second parameter to password_hash function, like this:
- name: Creating testuser
user:
name: "{{ test_user }}"
password: "{{ test_user_password | password_hash('sha512', test_user_salt) }}"
shell: /bin/bash
group: "{{ test_group }}"
update_password: on_create

Resources