diff --git a/.ostree/packages-runtime.txt b/.ostree/packages-runtime.txt new file mode 100644 index 0000000..7864d0d --- /dev/null +++ b/.ostree/packages-runtime.txt @@ -0,0 +1 @@ +sudo diff --git a/README.md b/README.md index cda4b60..0bf814e 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,13 @@ Consider reading sudo documentation before setting it up. ### Collection requirements -None. +The role requires external collections only for management of `rpm-ostree` +nodes. Please run the following command to install them if you need to manage +`rpm-ostree` nodes: + +```bash +ansible-galaxy collection install -vv -r meta/collection-requirements.yml +``` ## Role Variables @@ -30,8 +36,8 @@ Type: `bool` ***Dangerous!*** Setting this to `true` removes each existing sudoers file in the `include_directories` dictionary that are not defined in the`sudo_sudoers_files` variable. This allows for enforcing a desired state. -Default: `false` -Type: `bool` +Default: `false` +Type: `bool` ### sudo_visudo_path @@ -114,7 +120,7 @@ Optional, a list of directories that your configurations must include. This is a list of fully-qualified paths to directories to include via the `#includedir` option of a sudoers configuration. -Type: `list` +Type: `list` #### user_specifications @@ -147,25 +153,25 @@ You can use a defined `cmnd_alias` name as well as commands. Example definition: ```yaml - sudo_sudoers_files: - - path: /etc/sudoers.d/pingers - user_specifications: - - users: - - root - hosts: - - ALL - operators: - - ALL - commands: - - ALL - - users: - - "%wheel" - hosts: - - ALL - operators: - - ALL - commands: - - ALL +sudo_sudoers_files: + - path: /etc/sudoers.d/pingers + user_specifications: + - users: + - root + hosts: + - ALL + operators: + - ALL + commands: + - ALL + - users: + - "%wheel" + hosts: + - ALL + operators: + - ALL + commands: + - ALL ``` #### default_overrides @@ -194,31 +200,31 @@ List of `user_alias` names as well as individual user names to override specific Example Definition: ```yaml - sudo_sudoers_files: - - path: /etc/sudoers.d/pingers - default_overrides: - - type: user - defaults: - - "!requiretty" - users: - - PINGERS - - type: runas - defaults: - - "!set_logname" - operators: - - root - - type: host - defaults: - - "!requiretty" - - "!requiretty" - hosts: - - host1 - - host2 - - type: command - defaults: - - "!requiretty" - commands: - - /usr/bin/ls +sudo_sudoers_files: + - path: /etc/sudoers.d/pingers + default_overrides: + - type: user + defaults: + - "!requiretty" + users: + - PINGERS + - type: runas + defaults: + - "!set_logname" + operators: + - root + - type: host + defaults: + - "!requiretty" + - "!requiretty" + hosts: + - host1 + - host2 + - type: command + defaults: + - "!requiretty" + commands: + - /usr/bin/ls ``` ## Example Playbooks @@ -241,16 +247,16 @@ Example Definition: hosts: all vars: sudoers_files: - - path: /etc/sudoers - user_specifications: - - users: - - root - hosts: - - x - commands: - - /usr/bin/ls + - path: /etc/sudoers + user_specifications: + - users: + - root + hosts: + - x + commands: + - /usr/bin/ls roles: - - role: linux-system-roles.sudo + - role: linux-system-roles.sudo ``` ### Applying defaults @@ -428,6 +434,10 @@ Example Definition: - root ``` +## rpm-ostree + +See README-ostree.md + ## License MIT diff --git a/meta/collection-requirements.yml b/meta/collection-requirements.yml new file mode 100644 index 0000000..a0cd255 --- /dev/null +++ b/meta/collection-requirements.yml @@ -0,0 +1,3 @@ +--- +collections: + - name: ansible.posix diff --git a/tasks/main.yml b/tasks/main.yml index 2453457..32107a3 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -1,8 +1,13 @@ --- +- name: Set version specific variables + include_tasks: set_vars.yml + - name: Ensure sudo is installed package: - name: sudo + name: "{{ __sudo_packages }}" state: present + use: "{{ (__sudo_is_ostree | d(false)) | + ternary('ansible.posix.rhel_rpm_ostree', omit) }}" - name: Set include directories variable set_fact: @@ -37,7 +42,7 @@ with_items: "{{ sudo_sudoers_files }}" loop_control: label: "{{ item.path }}" - when: item.path != '/etc/sudoers' + when: item.path != "/etc/sudoers" - name: Ensure /etc/sudoers is configured template: @@ -51,7 +56,7 @@ loop_control: label: "{{ item.path }}" when: - - item.path == '/etc/sudoers' + - item.path == "/etc/sudoers" - sudo_rewrite_default_sudoers_file | bool - name: Remove unauthorized included sudoer files @@ -70,8 +75,8 @@ - name: Set unauthorized included sudoers files variable set_fact: sudo_unauthorized_files: "{{ sudo_existing_included_files['files'] - | selectattr('path', 'defined') | map(attribute='path') - | flatten | difference(sudo_file_paths) }}" + | selectattr('path', 'defined') | map(attribute='path') + | flatten | difference(sudo_file_paths) }}" - name: Remove unauthorized included sudoers files file: diff --git a/tasks/set_vars.yml b/tasks/set_vars.yml index c1ef3f6..4dd653f 100644 --- a/tasks/set_vars.yml +++ b/tasks/set_vars.yml @@ -1,12 +1,12 @@ --- - name: Ensure ansible_facts used by role setup: - gather_subset: "{{ __template_required_facts_subsets }}" - when: __template_required_facts | + gather_subset: "{{ __sudo_required_facts_subsets }}" + when: __sudo_required_facts | difference(ansible_facts.keys() | list) | length > 0 - name: Determine if system is ostree and set flag - when: not __template_is_ostree is defined + when: not __sudo_is_ostree is defined block: - name: Check if system is ostree stat: @@ -15,7 +15,7 @@ - name: Set flag to indicate system is ostree set_fact: - __template_is_ostree: "{{ __ostree_booted_stat.stat.exists }}" + __sudo_is_ostree: "{{ __ostree_booted_stat.stat.exists }}" - name: Set platform/version specific variables include_vars: "{{ __vars_file }}" diff --git a/templates/sudoers.j2 b/templates/sudoers.j2 index 6d0fd8a..83a9f28 100644 --- a/templates/sudoers.j2 +++ b/templates/sudoers.j2 @@ -21,8 +21,8 @@ {% for spec_default in spec.defaults %} {% set _ = _spec_default.append(spec_default) %} {% endfor %} -Defaults{{ sign }} {{ _spec_original | join(", ")}} {{ _spec_default | - join(", ")}} +Defaults{{ sign }} {{ _spec_original | join(", ") }} {{ _spec_default | + join(", ") }} {% endif %} {% endmacro -%} {{ ansible_managed | default('Ansible managed') | comment }} @@ -164,7 +164,7 @@ Defaults {{ default }} #include {{ file }} {% endfor %} {% endif %} -{% if item.include_directories is defined and item.include_directories | +{% if item.include_directories is defined and item.include_directories | length > 0 %} ## Include directories {% for dir in item.include_directories %} diff --git a/tests/roles/linux-system-roles.template/defaults b/tests/roles/linux-system-roles.template/defaults deleted file mode 120000 index 30459c3..0000000 --- a/tests/roles/linux-system-roles.template/defaults +++ /dev/null @@ -1 +0,0 @@ -../../../defaults \ No newline at end of file diff --git a/tests/roles/linux-system-roles.template/handlers b/tests/roles/linux-system-roles.template/handlers deleted file mode 120000 index 3b11237..0000000 --- a/tests/roles/linux-system-roles.template/handlers +++ /dev/null @@ -1 +0,0 @@ -../../../handlers \ No newline at end of file diff --git a/tests/roles/linux-system-roles.template/meta b/tests/roles/linux-system-roles.template/meta deleted file mode 120000 index 8df72eb..0000000 --- a/tests/roles/linux-system-roles.template/meta +++ /dev/null @@ -1 +0,0 @@ -../../../meta \ No newline at end of file diff --git a/tests/roles/linux-system-roles.template/tasks b/tests/roles/linux-system-roles.template/tasks deleted file mode 120000 index d97297b..0000000 --- a/tests/roles/linux-system-roles.template/tasks +++ /dev/null @@ -1 +0,0 @@ -../../../tasks \ No newline at end of file diff --git a/tests/roles/linux-system-roles.template/templates b/tests/roles/linux-system-roles.template/templates deleted file mode 120000 index 0e4c94f..0000000 --- a/tests/roles/linux-system-roles.template/templates +++ /dev/null @@ -1 +0,0 @@ -../../../templates \ No newline at end of file diff --git a/tests/roles/linux-system-roles.template/vars b/tests/roles/linux-system-roles.template/vars deleted file mode 120000 index 663079d..0000000 --- a/tests/roles/linux-system-roles.template/vars +++ /dev/null @@ -1 +0,0 @@ -../../../vars \ No newline at end of file diff --git a/tests/tasks/cleanup.yml b/tests/tasks/cleanup.yml new file mode 100644 index 0000000..71c681a --- /dev/null +++ b/tests/tasks/cleanup.yml @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: MIT +--- +- name: Restore sudoers + copy: + src: "{{ __sudo_tmpdir.path }}/sudoers" + dest: /etc/sudoers + owner: root + group: root + mode: 0644 + remote_src: true + +- name: Restore sudoers.d + copy: + src: "{{ __sudo_tmpdir.path }}/sudoers.d" + dest: /etc/sudoers.d + owner: root + group: root + mode: 0644 + remote_src: true + +- name: Clean up temp directory + file: + path: "{{ __sudo_tmpdir.path }}" + state: absent diff --git a/tests/tasks/setup.yml b/tests/tasks/setup.yml new file mode 100644 index 0000000..359bf8f --- /dev/null +++ b/tests/tasks/setup.yml @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: MIT +--- +- name: Create temp test directory + tempfile: + path: /var/tmp + prefix: sudo_ + state: directory + register: __sudo_tmpdir + +- name: Backup sudoers + copy: + src: /etc/sudoers + dest: "{{ __sudo_tmpdir.path }}/sudoers" + owner: root + group: root + mode: 0644 + remote_src: true + +- name: Backup sudoers.d + copy: + src: /etc/sudoers.d + dest: "{{ __sudo_tmpdir.path }}/sudoers.d" + owner: root + group: root + mode: 0644 + remote_src: true diff --git a/tests/tests_default.yml b/tests/tests_default.yml index 1a72731..c52706e 100644 --- a/tests/tests_default.yml +++ b/tests/tests_default.yml @@ -3,11 +3,22 @@ - name: Ensure that the role runs with default parameters hosts: all gather_facts: false # test that role works in this case - roles: - - linux-system-roles.sudo tasks: - - name: Check header for ansible_managed, fingerprint - include_tasks: tasks/check_header.yml - vars: - __file: /etc/sudoers - __fingerprint: system_role:sudo + - name: Run tests + block: + - name: Test setup + include_tasks: tasks/setup.yml + + - name: Run the role + include_role: + name: linux-system-roles.sudo + + - name: Check header for ansible_managed, fingerprint + include_tasks: tasks/check_header.yml + vars: + __file: /etc/sudoers + __fingerprint: system_role:sudo + + always: + - name: Test cleanup + include_tasks: tasks/cleanup.yml diff --git a/tests/tests_include_vars_from_parent.yml b/tests/tests_include_vars_from_parent.yml index 749b0ef..73feb8a 100644 --- a/tests/tests_include_vars_from_parent.yml +++ b/tests/tests_include_vars_from_parent.yml @@ -3,53 +3,63 @@ hosts: all gather_facts: true tasks: - - name: Create var file in caller that can override the one in called role - delegate_to: localhost - copy: - # usually the fake file will cause the called role to crash of - # overriding happens, but if not, set a variable that will - # allow to detect the bug - content: "__caller_override: true" - # XXX ugly, self-modifying code - changes the "caller" role on - # the controller - dest: "{{ playbook_dir }}/roles/caller/vars/{{ item }}.yml" - mode: preserve - loop: "{{ varfiles | unique }}" - # In case the playbook is executed against multiple hosts, use - # only the first one. Otherwise the hosts would stomp on each - # other since they are changing files on the controller. - when: inventory_hostname == ansible_play_hosts_all[0] - vars: - # change to hostvars['localhost']['ansible_facts'] to use the - # information for localhost - facts: "{{ ansible_facts }}" - versions: - - "{{ facts['distribution_version'] }}" - - "{{ facts['distribution_major_version'] }}" - separators: ["-", "_"] - # create all variants like CentOS, CentOS_8.1, CentOS-8.1, - # CentOS-8, CentOS-8.1 - # more formally: - # {{ ansible_distribution }}-{{ ansible_distribution_version }} - # {{ ansible_distribution }}-{{ ansible_distribution_major_version }} - # {{ ansible_distribution }} - # {{ ansible_os_family }} - # and the same for _ as separator. - varfiles: "{{ [facts['distribution']] | product(separators) | - map('join') | product(versions) | map('join') | list + - [facts['distribution'], facts['os_family']] }}" - register: __varfiles_created + - name: Run tests + block: + - name: >- + Create var file in caller that can override the one in called role + delegate_to: localhost + copy: + # usually the fake file will cause the called role to crash of + # overriding happens, but if not, set a variable that will + # allow to detect the bug + content: "__caller_override: true" + # XXX ugly, self-modifying code - changes the "caller" role on + # the controller + dest: "{{ playbook_dir }}/roles/caller/vars/{{ item }}.yml" + mode: preserve + loop: "{{ varfiles | unique }}" + # In case the playbook is executed against multiple hosts, use + # only the first one. Otherwise the hosts would stomp on each + # other since they are changing files on the controller. + when: inventory_hostname == ansible_play_hosts_all[0] + vars: + # change to hostvars['localhost']['ansible_facts'] to use the + # information for localhost + facts: "{{ ansible_facts }}" + versions: + - "{{ facts['distribution_version'] }}" + - "{{ facts['distribution_major_version'] }}" + separators: ["-", "_"] + # create all variants like CentOS, CentOS_8.1, CentOS-8.1, + # CentOS-8, CentOS-8.1 + # more formally: + # {{ ansible_distribution }}-{{ ansible_distribution_version }} + # {{ ansible_distribution }}-{{ distribution_major_version }} + # {{ ansible_distribution }} + # {{ ansible_os_family }} + # and the same for _ as separator. + varfiles: "{{ [facts['distribution']] | product(separators) | + map('join') | product(versions) | map('join') | list + + [facts['distribution'], facts['os_family']] }}" + register: __varfiles_created - - name: Import role - import_role: - name: caller - vars: - roletoinclude: linux-system-roles.sudo + - name: Test setup + include_tasks: tasks/setup.yml - - name: Cleanup - file: - path: "{{ item.dest }}" - state: absent - loop: "{{ __varfiles_created.results }}" - delegate_to: localhost - when: inventory_hostname == ansible_play_hosts_all[0] + - name: Import role + import_role: + name: caller + vars: + roletoinclude: linux-system-roles.sudo + + always: + - name: Test cleanup + include_tasks: tasks/cleanup.yml + + - name: Cleanup + file: + path: "{{ item.dest }}" + state: absent + loop: "{{ __varfiles_created.results }}" + delegate_to: localhost + when: inventory_hostname == ansible_play_hosts_all[0] diff --git a/tests/tests_large_configuration.yml b/tests/tests_large_configuration.yml index 3ce46c9..4db7c3a 100644 --- a/tests/tests_large_configuration.yml +++ b/tests/tests_large_configuration.yml @@ -1,9 +1,12 @@ --- -- name: Basic test for Sudo +- name: Test for Sudo - large configuration hosts: all tasks: - name: Run tests block: + - name: Test setup + include_tasks: tasks/setup.yml + - name: Run the role include_role: name: linux-system-roles.sudo @@ -146,31 +149,6 @@ operators: - root - - name: Create temp test directory - tempfile: - path: /var/tmp - prefix: sudo_ - state: directory - register: __sudo_tmpdir - - - name: Backup sudoers - copy: - src: /etc/sudoers - dest: "{{ __sudo_tmpdir.path }}/sudoers" - owner: root - group: root - mode: 0644 - remote_src: true - - - name: Backup sudoers.d - copy: - src: /etc/sudoers.d - dest: "{{ __sudo_tmpdir.path }}/sudoers.d" - owner: root - group: root - mode: 0644 - remote_src: true - - name: Get stat of {{ ok_path }} delegate_to: localhost vars: @@ -198,25 +176,6 @@ __sudo_ok_path: files/tests_large_configuration_root.ok __sudo_test_path: /etc/sudoers.d/root - - name: Restore sudoers - copy: - src: "{{ __sudo_tmpdir.path }}/sudoers" - dest: /etc/sudoers - owner: root - group: root - mode: 0644 - remote_src: true - - - name: Restore sudoers.d - copy: - src: "{{ __sudo_tmpdir.path }}/sudoers.d" - dest: /etc/sudoers.d - owner: root - group: root - mode: 0644 - remote_src: true - - - name: Clean up temp directory - file: - path: "{{ __sudo_tmpdir.path }}" - state: absent + always: + - name: Test cleanup + include_tasks: tasks/cleanup.yml diff --git a/tests/tests_multiple_sudoers.yml b/tests/tests_multiple_sudoers.yml index 0907bca..7b87d41 100644 --- a/tests/tests_multiple_sudoers.yml +++ b/tests/tests_multiple_sudoers.yml @@ -1,9 +1,12 @@ --- -- name: Basic test for Sudo +- name: Test multiple sudoers hosts: all tasks: - name: Run tests block: + - name: Test setup + include_tasks: tasks/setup.yml + - name: Run the role include_role: name: linux-system-roles.sudo @@ -98,31 +101,6 @@ operators: - root - - name: Create temp test directory - tempfile: - path: /var/tmp - prefix: sudo_ - state: directory - register: __sudo_tmpdir - - - name: Backup sudoers - copy: - src: /etc/sudoers - dest: "{{ __sudo_tmpdir.path }}/sudoers" - owner: root - group: root - mode: 0644 - remote_src: true - - - name: Backup sudoers.d - copy: - src: /etc/sudoers.d - dest: "{{ __sudo_tmpdir.path }}/sudoers.d" - owner: root - group: root - mode: 0644 - remote_src: true - - name: Get stat of {{ ok_path }} delegate_to: localhost vars: @@ -150,25 +128,6 @@ __sudo_ok_path: files/tests_multiple_sudoers_root.ok __sudo_test_path: /etc/sudoers.d/root - - name: Restore sudoers - copy: - src: "{{ __sudo_tmpdir.path }}/sudoers" - dest: /etc/sudoers - owner: root - group: root - mode: 0644 - remote_src: true - - - name: Restore sudoers.d - copy: - src: "{{ __sudo_tmpdir.path }}/sudoers.d" - dest: /etc/sudoers.d - owner: root - group: root - mode: 0644 - remote_src: true - - - name: Clean up temp directory - file: - path: "{{ __sudo_tmpdir.path }}" - state: absent + always: + - name: Test cleanup + include_tasks: tasks/cleanup.yml diff --git a/tests/tests_role_applied.yml b/tests/tests_role_applied.yml index c1a7e81..b932cd7 100644 --- a/tests/tests_role_applied.yml +++ b/tests/tests_role_applied.yml @@ -1,9 +1,12 @@ --- -- name: Basic test for Sudo +- name: Test rewrite default sudoers and remove unauthorized files hosts: all tasks: - name: Run tests block: + - name: Test setup + include_tasks: tasks/setup.yml + - name: Run the role include_role: name: linux-system-roles.sudo @@ -11,56 +14,12 @@ sudo_rewrite_default_sudoers_file: true sudo_remove_unauthorized_included_files: true - - name: Create temp test directory - tempfile: - path: /var/tmp - prefix: sudo_ - state: directory - register: __sudo_tmpdir - - - name: Backup sudoers - copy: - src: /etc/sudoers - dest: "{{ __sudo_tmpdir.path }}/sudoers" - owner: root - group: root - mode: 0644 - remote_src: true - - - name: Backup sudoers.d - copy: - src: /etc/sudoers.d - dest: "{{ __sudo_tmpdir.path }}/sudoers.d" - owner: root - group: root - mode: 0644 - remote_src: true - - name: Check sudoers include_tasks: tasks/assert_files_identical.yml vars: __sudo_ok_path: files/tests_role_applied.ok __sudo_test_path: /etc/sudoers - - name: Restore sudoers - copy: - src: "{{ __sudo_tmpdir.path }}/sudoers" - dest: /etc/sudoers - owner: root - group: root - mode: 0644 - remote_src: true - - - name: Restore sudoers.d - copy: - src: "{{ __sudo_tmpdir.path }}/sudoers.d" - dest: /etc/sudoers.d - owner: root - group: root - mode: 0644 - remote_src: true - - - name: Clean up temp directory - file: - path: "{{ __sudo_tmpdir.path }}" - state: absent + always: + - name: Test cleanup + include_tasks: tasks/cleanup.yml