Ansible set theory filters in practice
Ansible has some really useful filters for various types of objects. A few of those are for sets of something. Recently, I had to use them in practice.
In this situation there was a set of system users in users
group. Some users needed to be present and their shell to be set to /usr/sbin/nologin
, so they would not have direct shell access, and some users were not supposed to be present so they needed to be removed. There were also some system users present in users
group, which should be left as-is.
To start, a list with legit users was created (documented_users
), along with a list of system users (system_users
):
documented_users:
- user.name
- another.user
...
system_users:
- spamas
- openvpn
...
To get what we needed, we first got all the users in users
group on remote systems, and assign them to an Ansible variable:
- name: get users in users group
shell: cut -d":" -f1,4 /etc/passwd | grep $(getent group users | cut -d":" -f3) | cut -d":" -f1
register: users_users
We then create a list of legit_users
by joining documented_users
and system_users
:
- name: set legit_users fact
set_fact:
legit_users: "{{ documented_users | union(system_users) }}"
When that was done, we could determine, which users were not needed on the system (undocumented_users
), and which of the documented users were actually present (present_documented_users
):
- name: set undocumented_users fact
set_fact:
undocumented_users: "{{ users_users.stdout_lines | difference(legit_users) }}"
- name: set present_documented_users fact
set_fact:
present_documented_users: "{{ users_users.stdout_lines | intersect(documented_users) }}"
Here, difference
and intersect
Ansible set theory filters were really useful. It would take a bit more code to do the comparison by other means. difference
returned, which elements were in the first, but not the second set, while intersect
returned a list with elements in both sets.
Now that we knew, which users are in which set, we can proceed to removing the undocumented users and seting proper shell for the documented users using the user
module:
- name: remove undocumented users
user:
name: "{{ item }}"
state: absent
with_items: "{{ undocumented_users }}"
when:
- undocumented_users is defined
- undocumented_users | length > 0
- name: set nologin as shell for documented users
user:
name: "{{ item }}"
shell: /usr/sbin/nologin
with_items: "{{ present_documented_users }}"
when:
- present_documented_users is defined
- present_documented_users | length > 0