From 4934148534008a69addba4a18a168760a30b937a Mon Sep 17 00:00:00 2001 From: Tristan Findley Date: Fri, 25 Oct 2024 14:47:01 +0000 Subject: [PATCH] Reworking role to simplify and bring up to current standards --- .travis.yml | 4 +- README.md | 92 ++++++----- defaults/main.yml | 26 ++- handlers/main.yml | 2 +- meta/main.yml | 33 ++-- molecule/default/INSTALL.rst | 22 --- molecule/default/converge.yml | 22 --- molecule/default/molecule.yml | 25 --- molecule/default/verify.yml | 9 -- tasks/main.yml | 160 +++++-------------- templates/etc/bind/named.conf.local | 60 ------- templates/etc/bind/named.conf.options | 46 ------ templates/etc/bind/named.conf.single.options | 44 ----- tests/test.yml | 5 +- vars/context/family/Debian.yml | 1 - vars/context/family/RedHat.yml | 1 - vars/context/os/CentOS-7.yml | 0 vars/context/os/CentOS-8.yml | 0 vars/context/os/Debian.yml | 0 vars/context/os/Raspbian.yml | 0 vars/context/os/RedHat.yml | 0 vars/context/os/Ubuntu.yml | 0 vars/main.yml | 8 + 23 files changed, 145 insertions(+), 415 deletions(-) delete mode 100644 molecule/default/INSTALL.rst delete mode 100644 molecule/default/converge.yml delete mode 100644 molecule/default/molecule.yml delete mode 100644 molecule/default/verify.yml delete mode 100644 templates/etc/bind/named.conf.local delete mode 100644 templates/etc/bind/named.conf.options delete mode 100644 templates/etc/bind/named.conf.single.options delete mode 100644 vars/context/family/Debian.yml delete mode 100644 vars/context/family/RedHat.yml delete mode 100644 vars/context/os/CentOS-7.yml delete mode 100644 vars/context/os/CentOS-8.yml delete mode 100644 vars/context/os/Debian.yml delete mode 100644 vars/context/os/Raspbian.yml delete mode 100644 vars/context/os/RedHat.yml delete mode 100644 vars/context/os/Ubuntu.yml diff --git a/.travis.yml b/.travis.yml index 36bbf62..121cc49 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ sudo: false addons: apt: packages: - - python-pip + - python-pip install: # Install ansible @@ -26,4 +26,4 @@ script: - ansible-playbook tests/test.yml -i tests/inventory --syntax-check notifications: - webhooks: https://galaxy.ansible.com/api/v1/notifications/ \ No newline at end of file + webhooks: https://galaxy.ansible.com/api/v1/notifications/ diff --git a/README.md b/README.md index 2bad257..2ed2243 100644 --- a/README.md +++ b/README.md @@ -1,61 +1,73 @@ -Role Name -========= +# Users and Groups A brief description of the role goes here. -Requirements ------------- +## Requirements Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. -Role Variables --------------- +## Role Variables A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. -Dependencies ------------- +## Dependencies A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. -Generate password ------------------ - python3 -c 'import crypt,getpass;pw=getpass.getpass();print(crypt.crypt(pw) if (pw==getpass.getpass("Confirm: ")) else exit())' -Example Playbook ----------------- +## Example Playbook Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: - - hosts: servers - become: yes - gather_facts: true - roles: - - role: '/home/tristan/ansible/roles_vss/users' - vars: - - groups_present: - - "ansible" - - groups_absent: - - "group_to_delete - - users_present: - - {username: user1, sudo: True, enabled: True, fname: User, sname: One, groups: "ansible", email: user1@ansible.com, password: EncryptedPasswordUser1, rsa: "https://github.com/user1.keys" } - - {username: user2, sudo: True, enabled: True, fname: User, sname: Two, groups: "ansible", email: user2@ansible.com, password: EncryptedPasswordUser2, rsa: "ssh-rsa enteryourrpublickeystringhere user2@usersmachine.local" } - - {username: user3, sudo: True, enabled: False, fname: User, sname: Three, groups: "ansible", email: user3@ansible.com, password: EncryptedPasswordUser3, rsa: } - - {username: user4, sudo: False, enabled: True, fname: User, sname: Four, groups: "ansible", email: user4@ansible.com, password: EncryptedPasswordUser4, rsa: "user2_id_rsa.pub"} - - users_absent: - - "user5" - - "user6" - -License -------- +```yml +- hosts: servers + become: yes + gather_facts: true + roles: + - role: 'usersandgroups' + vars: + +# Adding a user + - username: "username" + state: present + fname: "user" + sname: "name" + email: user1@ansible.com + password: 'set using openssl passwd -6' + sudo: true + groups: + - "grouphere" + sshkeys: + - 'copypaste ssh key' + - 'or use file read' + +# Removing a user + - username: "another.user" + state: absent + +# Managing Groups +usersandgroups_groups: + - name: "dcinfra" + state: present +``` + +### Generate password + +Preferred method: +```bash +set using openssl passwd -6 +``` + +Alternative method: +```bash +python3 -c 'import crypt,getpass;pw=getpass.getpass();print(crypt.crypt(pw) if (pw==getpass.getpass("Confirm: ")) else exit())' +``` + + +## License BSD -Author Information ------------------- +## Author Information An optional section for the role authors to include contact information, or a website (HTML is not allowed). diff --git a/defaults/main.yml b/defaults/main.yml index 98f7b35..e8b20ec 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -1,2 +1,26 @@ --- -# defaults file for users \ No newline at end of file +# defaults file for users + +usersandgroups_users: +# Adding a user + - username: "username" + state: present + fname: "user" + sname: "name" + email: user1@ansible.com + password: 'set using openssl passwd -6' + sudo: true + groups: + - "grouphere" + sshkeys: + - 'copypaste ssh key' + - 'or use file read' + +# Removing a user + - username: "another.user" + state: absent + +# Managing Groups +usersandgroups_groups: + - name: "dcinfra" + state: present diff --git a/handlers/main.yml b/handlers/main.yml index 8dccd6d..46e2ea7 100644 --- a/handlers/main.yml +++ b/handlers/main.yml @@ -1,2 +1,2 @@ --- -# handlers file for users \ No newline at end of file +# handlers file for users diff --git a/meta/main.yml b/meta/main.yml index a1cd1ce..0f61dfe 100644 --- a/meta/main.yml +++ b/meta/main.yml @@ -1,4 +1,6 @@ galaxy_info: + role_name: usersandgroups + namespace: tfindley author: Tristan Findley description: Manage users and groups company: TFindley (tfindley.co.uk) @@ -14,9 +16,9 @@ galaxy_info: # - GPL-3.0-only # - Apache-2.0 # - CC-BY-4.0 - license: MIT + license: BSD - min_ansible_version: 2.9 + min_ansible_version: '2.9' # If this a Container Enabled role, provide the minimum Ansible Container version. # min_ansible_container_version: @@ -28,24 +30,15 @@ galaxy_info: # https://galaxy.ansible.com/api/v1/platforms/ # platforms: - - name: RedHat - versions: - - 7 - - 8 - - name: CentOS - versions: - - 7 - - 8 - - name: Debian - versions: - - buster - - stretch - - name: Ubuntu - versions: - - 18.04 - - 18.10 - - 19.04 - - 19.10 + - name: EL + versions: + - all + - name: Debian + versions: + - all + - name: Ubuntu + versions: + - all galaxy_tags: [] # List tags for your role here, one per line. A tag is a keyword that describes diff --git a/molecule/default/INSTALL.rst b/molecule/default/INSTALL.rst deleted file mode 100644 index 6a44bde..0000000 --- a/molecule/default/INSTALL.rst +++ /dev/null @@ -1,22 +0,0 @@ -******* -Docker driver installation guide -******* - -Requirements -============ - -* Docker Engine - -Install -======= - -Please refer to the `Virtual environment`_ documentation for installation best -practices. If not using a virtual environment, please consider passing the -widely recommended `'--user' flag`_ when invoking ``pip``. - -.. _Virtual environment: https://virtualenv.pypa.io/en/latest/ -.. _'--user' flag: https://packaging.python.org/tutorials/installing-packages/#installing-to-the-user-site - -.. code-block:: bash - - $ pip install 'molecule[docker]' diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml deleted file mode 100644 index 1a88cb3..0000000 --- a/molecule/default/converge.yml +++ /dev/null @@ -1,22 +0,0 @@ ---- -- name: Converge - hosts: all - tasks: - - name: "Include users" - include_role: - name: "users" - vars: - users_present: - # python -c 'import crypt; print crypt.crypt("This is my Password", "$1$SomeSalt$")' - - {username: test, sudo: True, enabled: True, fname: Test, sname: User, groups: "testing", email: testing@somewhere.com, password: $1$221ArhSo$xQyiyPcFa19g7YQDM5CUM., rsa: "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEAhNFonYNb7t5xD0b/6OjnRdj3ZfEpBVQrn6lijAl5MIjQTy9WZdIPrLf+TaZOZFce5EbcosLX/9iItl31Xc0La1RpUa1A7nM272AFRaZ+ULygLpRcuc2S3iOhIIKmnOQ261Y9MB9yNA+BQmYf3hPZ2tveoVohrVCk6SdaFHyqS+uQ6SKVx1MEVDssnXtcS09jbMbsEL0oV1nSJ/bgdzDCIOE/RIBanKZA4BuhAo8cWYRWDCjmxqlFsMX8oP88wBGgq2O/s93wF9LIR2jFszXoO0siF9B2To0zd3GyzOJfNRKjL6qTxQLtGYsJG8rz4W++7uNT2OMTYiQvSSJmp8SOjw== testsshkey" } # noqa 204 - - {username: deletemeuser, sudo: True, enabled: True, fname: Test, sname: User, groups: "testing", email: deleteme@somewhere.com, password: $1$221ArhSo$xQyiyPcFa19g7YQDM5CUM., rsa: "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEAhNFonYNb7t5xD0b/6OjnRdj3ZfEpBVQrn6lijAl5MIjQTy9WZdIPrLf+TaZOZFce5EbcosLX/9iItl31Xc0La1RpUa1A7nM272AFRaZ+ULygLpRcuc2S3iOhIIKmnOQ261Y9MB9yNA+BQmYf3hPZ2tveoVohrVCk6SdaFHyqS+uQ6SKVx1MEVDssnXtcS09jbMbsEL0oV1nSJ/bgdzDCIOE/RIBanKZA4BuhAo8cWYRWDCjmxqlFsMX8oP88wBGgq2O/s93wF9LIR2jFszXoO0siF9B2To0zd3GyzOJfNRKjL6qTxQLtGYsJG8rz4W++7uNT2OMTYiQvSSJmp8SOjw== testsshkey" } # noqa 204 - - users_absent: - - "deletemeuser" - - groups_present: - - "testing" - - "deletemegroup" - - groups_absent: - - "deletemegroup" \ No newline at end of file diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml deleted file mode 100644 index 529c3d5..0000000 --- a/molecule/default/molecule.yml +++ /dev/null @@ -1,25 +0,0 @@ ---- - dependency: - name: galaxy - driver: - name: docker - lint: | - set -e - yamllint . - ansible-lint - flake8 - platforms: - - name: instance - image: centos:7 - command: /sbin/init - tmpfs: - - /run - - /tmp - capabilities: - - SYS_ADMIN - volumes: - - /sys/fs/cgroup:/sys/fs/cgroup:ro - provisioner: - name: ansible - verifier: - name: ansible \ No newline at end of file diff --git a/molecule/default/verify.yml b/molecule/default/verify.yml deleted file mode 100644 index a82dd6f..0000000 --- a/molecule/default/verify.yml +++ /dev/null @@ -1,9 +0,0 @@ ---- -# This is an example playbook to execute Ansible tests. - -- name: Verify - hosts: all - tasks: - - name: Example assertion - assert: - that: true diff --git a/tasks/main.yml b/tasks/main.yml index dca7f17..76bb722 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -1,131 +1,53 @@ --- # tasks file for users -# Context -# ------- -# The context section is used to load variables. This has been built in a specific order so that subsequent variable files override earlier variables. -# This generates a specicifity very similar to what we see in Chef. -# The order is as follows: -# - OS Family (i.e: Debian, RedHat) -# - Distribution (i.e: RedHat Enterprise, CentOS, Ubuntu) -# - LSB name (i.e: Raspbian) - only applicable to Debian-based OS's, and primarily needed to support Raspbian on Raspberry Pi's as its the only place Raspbian is specified -# - Distribution-Version (i.e: Debian-10) -# - Hostname (as specificed in inventory file) -# - Hostname (as read by Ansible) -# - IP Address - -# Remember these are CASE SENSITIVE - - -# This deals with family-specific variabiles. Store them in /var/family/___.yml -- name: Load OS family specific variables file - include_vars: - file: "context/family/{{ ansible_os_family }}.yml" # RedHat.yml - ignore_errors: true - - -# This deals with os-specific variabiles. Store them in /var/os/___.yml -- name: Load os specific variables file - include_vars: "{{ item }}" - with_first_found: - - "context/os/{{ ansible_distribution }}-{{ ansible_distribution_major_version }}.yml" # Debian-10.yml - - "context/os/{{ ansible_lsb.id }}.yml" # Raspbian.yml - - "context/os/{{ ansible_distribution }}.yml" # RedHat.yml - ignore_errors: true - - -# We load these in blocks to that we dont have to copy every single varialbe into files with a higher specicity. -# Remember: -# - Variables in more specific files completely overwrite variables loaded before it. -# - Variables do not concatonate. You must specify the whole variable again. -# ------- - -- name: Determine local user accounts - getent: +- name: Fetch local user accounts + become: true + ansible.builtin.getent: database: group -- name: Determine local user accounts - getent: +- name: Fetch local user accounts + become: true + ansible.builtin.getent: database: passwd -- name: Add groups - group: - name: "{{ item }}" - state: present - with_items: "{{ groups_present }}" - when: groups_present is defined - -- name: Delete groups - group: - name: "{{ item }}" - state: absent - with_items: "{{ groups_absent }}" +- name: "Manage groups" + become: true + loop: "{{ usersandgroups_groups }}" + loop_control: + label: "{{ item.name }} - {{ item.state }}" when: - - groups_absent is defined - - item in ansible_facts.getent_group - - -- name: Add sudo users - user: - name: "{{ item.username }}" - password: "{{ item.password }}" - shell: /bin/bash - groups: "{{ sudo_grp }},{{ item.groups }}" - append: yes - state: present - update_password: on_create - with_items: "{{ users_present }}" + - usersandgroups_groups is defined + ansible.builtin.group: + name: "{{ item.name }}" + state: "{{ item.state }}" + +- name: "Manage users" + become: true + loop: "{{ usersandgroups_users }}" + loop_control: + label: "{{ item.username }} - {{ item.state }}" when: - - item.sudo - - item.enabled - - -- name: Add non sudo users - user: + - usersandgroups_users + ansible.builtin.user: name: "{{ item.username }}" - password: "{{ item.password }}" - shell: /bin/bash - groups: '{{ item.groups }}' - append: yes - state: present - update_password: on_create - with_items: "{{ users_present }}" + password: "{{ item.password if item.state == 'present' else omit }}" + shell: "{{ item.shell | default('/bin/bash') if item.state == 'present' else omit }}" + groups: "{{ (item.groups | default([])) + (usersandgroups_sudo_group if item.sudo else []) if item.state == 'present' else omit }}" + append: "{{ true if item.state == 'present' else omit }}" + state: "{{ item.state }}" + update_password: "{{ 'on_create' if item.state == 'present' else omit }}" + +- name: "Manage authorized keys" + become: true + loop: "{{ usersandgroups_users | selectattr('sshkeys', 'defined') | subelements('sshkeys') }}" + loop_control: + label: "{{ item.0.username }}" when: - - not item.sudo - - item.enabled - - -- name: Add authorized key - authorized_key: - user: "{{ item.username }}" + - item.0.state == "present" + - item.1 is defined + - item.1 | length > 0 + ansible.posix.authorized_key: + user: "{{ item.0.username }}" state: present - key: "{{ item.rsa }}" - with_items: "{{ users_present }}" - when: - - item.enabled - - item.rsa is defined - - item.rsa | length > 0 - -- name: Disable users - user: - name: "{{ item.username }}" - password: "{{ item.password }}" - shell: /bin/false - groups: '' - append: yes - state: present - update_password: on_create - with_items: "{{ users_present }}" - when: - - not item.sudo - - item.enabled - - -- name: Delete accounts - user: - name: "{{ item }}" - state: absent - with_items: "{{ users_absent }}" - when: - - users_absent is defined - - item in ansible_facts.getent_passwd + key: "{{ item.1 }}" diff --git a/templates/etc/bind/named.conf.local b/templates/etc/bind/named.conf.local deleted file mode 100644 index 7dca596..0000000 --- a/templates/etc/bind/named.conf.local +++ /dev/null @@ -1,60 +0,0 @@ -// This file is {{ ansible_managed }}. -// Last Pushed on {{ ansible_date_time.date }} -// -// Do any local configuration here -// - -// Consider adding the 1918 zones here, if they are not used in your -// organization -//include "/etc/bind/zones.rfc1918"; - -zone "home" { -{% if 'bind_master' in group_names %} - type master; - file "/etc/bind/zones/db.home"; - allow-transfer { {% for host in groups['bind_slave'] -%} - {{ hostvars[host].ansible_default_ipv4.address }}; - {%- endfor %} }; -{% else %} - type slave; - file "/etc/bind/zones/db.home"; - masters { {% for host in groups['bind_master'] -%} - {{ hostvars[host].ansible_default_ipv4.address }}; - {%- endfor %} }; # ns1 private IP -{% endif %} - }; - - -zone "findley.pm" { -{% if 'bind_master' in group_names %} - type master; - file "/etc/bind/zones/db.findley.pm"; - allow-transfer { {% for host in groups['bind_slave'] -%} - {{ hostvars[host].ansible_default_ipv4.address }}; - {%- endfor %} }; -{% else %} - type slave; - file "/etc/bind/zones/db.findley.pm"; - masters { {% for host in groups['bind_master'] -%} - {{ hostvars[host].ansible_default_ipv4.address }}; - {%- endfor %} }; # ns1 private IP -{% endif %} - }; - - - -zone "0.0.10.in-addr.arpa" { -{% if 'bind_master' in group_names %} - type master; - file "/etc/bind/zones/db.0.0.10"; - allow-transfer { {% for host in groups['bind_slave'] -%} - {{ hostvars[host].ansible_default_ipv4.address }}; - {%- endfor %} }; -{% else %} - type slave; - file "/etc/bind/zones/db.0.0.10"; - masters { {% for host in groups['bind_master'] -%} - {{ hostvars[host].ansible_default_ipv4.address }}; - {%- endfor %} }; # ns1 private IP -{% endif %} - }; \ No newline at end of file diff --git a/templates/etc/bind/named.conf.options b/templates/etc/bind/named.conf.options deleted file mode 100644 index e1fbb97..0000000 --- a/templates/etc/bind/named.conf.options +++ /dev/null @@ -1,46 +0,0 @@ -// This file is {{ ansible_managed }}. -// Last Pushed on {{ ansible_date_time.date }} -// - -acl "trusted" { {% for host in groups['bind'] -%} - {{ hostvars[host].ansible_default_ipv4.address }};{% if not loop.last %}{{' - '}}{% endif %} -{%- endfor %} - - }; - - -options { - directory "/var/cache/bind"; - - // If there is a firewall between you and nameservers you want - // to talk to, you may need to fix the firewall to allow multiple - // ports to talk. See http://www.kb.cert.org/vuls/id/800113 - - // If your ISP provided one or more IP addresses for stable - // nameservers, you probably want to use them as forwarders. - // Uncomment the following block, and insert the addresses replacing - // the all-0's placeholder. - - // forwarders { - // 0.0.0.0; - // }; - - //======================================================================== - // If BIND logs error messages about the root key being expired, - // you will need to update your keys. See https://www.isc.org/bind-keys - //======================================================================== - dnssec-validation auto; - - auth-nxdomain no; # conform to RFC1035 - recursion yes; -# allow-recursion { trusted; }; - listen-on { {{ ansible_default_ipv4.address }}; }; # private IP Address - listen-on-v6 { any; }; - allow-transfer { none; }; # Disable zone transfer by default - - forwarders { - 1.1.1.1; - 1.0.0.1; - }; - }; diff --git a/templates/etc/bind/named.conf.single.options b/templates/etc/bind/named.conf.single.options deleted file mode 100644 index a241111..0000000 --- a/templates/etc/bind/named.conf.single.options +++ /dev/null @@ -1,44 +0,0 @@ -// This file is {{ ansible_managed }}. -// Last Pushed on {{ ansible_date_time.date }} -// - -acl "trusted" { - 10.0.0.11 - 10.0.0.12 - }; - - -options { - directory "/var/cache/bind"; - - // If there is a firewall between you and nameservers you want - // to talk to, you may need to fix the firewall to allow multiple - // ports to talk. See http://www.kb.cert.org/vuls/id/800113 - - // If your ISP provided one or more IP addresses for stable - // nameservers, you probably want to use them as forwarders. - // Uncomment the following block, and insert the addresses replacing - // the all-0's placeholder. - - // forwarders { - // 0.0.0.0; - // }; - - //======================================================================== - // If BIND logs error messages about the root key being expired, - // you will need to update your keys. See https://www.isc.org/bind-keys - //======================================================================== - dnssec-validation auto; - - auth-nxdomain no; # conform to RFC1035 - recursion yes; -# allow-recursion { trusted; }; - listen-on { {{ ansible_default_ipv4.address }}; }; # private IP Address - listen-on-v6 { any; }; - allow-transfer { none; }; # Disable zone transfer by default - - forwarders { - 1.1.1.1; - 1.0.0.1; - }; - }; diff --git a/tests/test.yml b/tests/test.yml index e75bc48..8f2c39e 100644 --- a/tests/test.yml +++ b/tests/test.yml @@ -1,5 +1,6 @@ --- -- hosts: localhost +- name: Test Users and Groups role + hosts: localhost remote_user: root roles: - - users \ No newline at end of file + - usersandgroups diff --git a/vars/context/family/Debian.yml b/vars/context/family/Debian.yml deleted file mode 100644 index cb6a104..0000000 --- a/vars/context/family/Debian.yml +++ /dev/null @@ -1 +0,0 @@ -sudo_grp: 'sudo,adm' \ No newline at end of file diff --git a/vars/context/family/RedHat.yml b/vars/context/family/RedHat.yml deleted file mode 100644 index a2795f9..0000000 --- a/vars/context/family/RedHat.yml +++ /dev/null @@ -1 +0,0 @@ -sudo_grp: 'wheel' \ No newline at end of file diff --git a/vars/context/os/CentOS-7.yml b/vars/context/os/CentOS-7.yml deleted file mode 100644 index e69de29..0000000 diff --git a/vars/context/os/CentOS-8.yml b/vars/context/os/CentOS-8.yml deleted file mode 100644 index e69de29..0000000 diff --git a/vars/context/os/Debian.yml b/vars/context/os/Debian.yml deleted file mode 100644 index e69de29..0000000 diff --git a/vars/context/os/Raspbian.yml b/vars/context/os/Raspbian.yml deleted file mode 100644 index e69de29..0000000 diff --git a/vars/context/os/RedHat.yml b/vars/context/os/RedHat.yml deleted file mode 100644 index e69de29..0000000 diff --git a/vars/context/os/Ubuntu.yml b/vars/context/os/Ubuntu.yml deleted file mode 100644 index e69de29..0000000 diff --git a/vars/main.yml b/vars/main.yml index 4070860..de6fbe7 100644 --- a/vars/main.yml +++ b/vars/main.yml @@ -1,2 +1,10 @@ --- # vars file for users + +_usersandgroups_sudo_group_logic: + Debian: + - 'sudo' + - 'adm' + RedHat: + - 'wheel' +usersandgroups_sudo_group: "{{ _usersandgroups_sudo_group_logic[ansible_os_family] }}"