diff --git a/roles/auth/defaults/main.yml b/roles/auth/defaults/main.yml index aaed167..f1b976b 100644 --- a/roles/auth/defaults/main.yml +++ b/roles/auth/defaults/main.yml @@ -3,34 +3,46 @@ auth__role_enabled: false auth__manage_groups: false auth__manage_users: false auth__manage_authorized_keys: false +auth__manage_sshd_config: false auth__manage_ssh_config: false auth__manage_sudoers: false -##### BEGIN - SSH Config ##### -auth__ssh_config_dir: /etc/ssh/ssh_config.d +##### BEGIN: SSH Config ##### +auth__ssh_dir: /etc/ssh +# module can be 'systemd_service' or 'service' +# module can be left empty to skip the service restart +# immediate can be true or false (Flushes the handlers immediately) +# smart can be true or false +# auth__sshd_validate or /usr/sbin/sshd -t command in this sense, hijacks the sshd daemon service. +# So, even though no changes, template module will always validate the sshd config file causing the sshd hijacked. +# If smart enabled and auth__sshd_validate provided then a dummy command task will run to trigger ssh service handlers as provided. +# This is a workaround to avoid using changed_when in the template module to prevent misleading output. +auth__ssh_changes_strategy: + module: service + immediate: true + smart: true + name: 'ssh.service' + enabled: true + state: started +# Set  auth__sshd_validate variable to validate the ssh daemon config +# auth__sshd_validate: "/usr/sbin/sshd -t -f %s" +auth__sshd_config_dir: "{{ auth__ssh_dir }}/sshd_config.d" +auth__sshd_config_file: "{{ auth__sshd_config_dir }}/50-ansible.conf" +auth__sshd_config_template: etc/ssh/sshd_config.d/50-ansible.conf.j2 +auth__sshd_config_backup: true +auth__ssh_config_dir: "{{ auth__ssh_dir }}/ssh_config.d" auth__ssh_config_file: "{{ auth__ssh_config_dir }}/50-ansible.conf" auth__ssh_config_template: etc/ssh/ssh_config.d/50-ansible.conf.j2 auth__ssh_config_backup: true -# module can be 'systemd_service' or 'service' -# module can be left empty to skip the service restart -# when can be immediate or at the end of the play -auth__ssh_config_change_strategy: - module: systemd_service - when: immediate -# Uncomment the following line to validate the sshd config -# auth__sshd_validate: "/usr/sbin/sshd -t -f %s" -##### END - SSH Config ##### +##### END: SSH Config ##### -##### BEGIN - SSH Config ##### +##### BEGIN: SUDOERS Config ##### auth__sudoers_dir: /etc/sudoers.d auth__sudoers_file: "{{ auth__sudoers_dir }}/50-ansible" auth__sudoers_template: etc/sudoers.d/50-ansible.j2 -auth__sudoers_backup: true -# Set false to prevent consolidation of sudoers files for community.general.sudoers module -# (Merges all sudoers module entries' name (basename of auth__sudoers_file) and sudoers_path (dirname of auth__sudoers_file) as provided above) -# Consult https://docs.ansible.com/ansible/latest/collections/community/general/sudoers_module.html -auth__sudoers_consolidate: true -##### END - SSH Config ##### +# Uncomment the following line to validate the sudoers file +# auth__sudoers_validate: "/usr/sbin/visudo -c -f %s" +##### END: SUDOERS Config ##### auth__default: [] auth__group: [] diff --git a/roles/auth/handlers/main.yml b/roles/auth/handlers/main.yml index 7c94989..ea6a757 100644 --- a/roles/auth/handlers/main.yml +++ b/roles/auth/handlers/main.yml @@ -1,45 +1,39 @@ --- -- name: Effect systemd service for ssh config changes +- name: Effect systemd service for ssh changes become: true ansible.builtin.systemd_service: - daemon_reexec: "{{ change_strategy.daemon_reexec | default(omit) | bool }}" - daemon_reload: "{{ change_strategy.daemon_reload | default(omit) | bool }}" - enabled: "{{ change_strategy.enabled | default(omit) | bool }}" - force: "{{ change_strategy.force | default(omit) | bool }}" - masked: "{{ change_strategy.masked | default(omit) | bool }}" - name: "{{ change_strategy.name | default('ssh.service') }}" - no_block : "{{ change_strategy.no_block | default(omit) | bool }}" - scope: "{{ change_strategy.scope | default(omit) }}" - state: "{{ change_strategy.state | default(omit) }}" + daemon_reexec: "{{ service.daemon_reexec | default(omit) | bool }}" + daemon_reload: "{{ service.daemon_reload | default(omit) | bool }}" + enabled: "{{ service.enabled | default(omit) | bool }}" + force: "{{ service.force | default(omit) | bool }}" + masked: "{{ service.masked | default(omit) | bool }}" + name: "{{ service.name | default('ssh.service') }}" + no_block : "{{ service.no_block | default(omit) | bool }}" + scope: "{{ service.scope | default(omit) }}" + state: "{{ service.state | default(omit) }}" vars: - change_strategy: "{{ (__ansible__config is defined) | - ternary( - (auth__ssh_config_change_strategy | aybarsm.helper.replace_aliases(__ansible__config.modules.ansible.builtin.systemd_service.aliases)), - auth__ssh_config_change_strategy) }}" - register: auth__ssh_config_apply_changes_systemd_service - listen: "auth__ssh_config_apply_changes" + service: "{{ auth__ssh_changes_strategy | aybarsm.helper.replace_aliases(__ansible__config.modules.ansible.builtin.systemd_service.aliases) }}" + register: auth__ssh_apply_changes_systemd_service + listen: "auth__ssh_apply_changes" when: - - auth__ssh_config_change_strategy.module is defined - - auth__ssh_config_change_strategy.module == 'systemd_service' + - auth__ssh_changes_strategy.module is defined + - auth__ssh_changes_strategy.module == 'systemd_service' -- name: Effect service for ssh config changes +- name: Effect service for ssh changes become: true ansible.builtin.service: - arguments: "{{ change_strategy.arguments | default(omit) }}" - enabled: "{{ change_strategy.enabled | default(omit) }}" - name: "{{ change_strategy.name | default('ssh.service') }}" - pattern: "{{ change_strategy.pattern | default(omit) }}" - runlevel: "{{ change_strategy.runlevel | default(omit) }}" - sleep: "{{ change_strategy.sleep | default(omit) }}" - state: "{{ change_strategy.state | default(omit) }}" - use: "{{ change_strategy.use | default(omit) }}" + arguments: "{{ service.arguments | default(omit) }}" + enabled: "{{ service.enabled | default(omit) }}" + name: "{{ service.name | default('ssh.service') }}" + pattern: "{{ service.pattern | default(omit) }}" + runlevel: "{{ service.runlevel | default(omit) }}" + sleep: "{{ service.sleep | default(omit) }}" + state: "{{ service.state | default(omit) }}" + use: "{{ service.use | default(omit) }}" vars: - change_strategy: "{{ (__ansible__config is defined) | - ternary( - (auth__ssh_config_change_strategy | aybarsm.helper.replace_aliases(__ansible__config.modules.ansible.builtin.service.aliases)), - auth__ssh_config_change_strategy) }}" - register: auth__ssh_config_apply_changes_service - listen: "auth__ssh_config_apply_changes" + service: "{{ auth__ssh_changes_strategy | aybarsm.helper.replace_aliases(__ansible__config.modules.ansible.builtin.service.aliases) }}" + register: auth__ssh_apply_changes_service + listen: "auth__ssh_apply_changes" when: - - auth__ssh_config_change_strategy.module is defined - - auth__ssh_config_change_strategy.module == 'service' \ No newline at end of file + - auth__ssh_changes_strategy.module is defined + - auth__ssh_changes_strategy.module == 'service' \ No newline at end of file diff --git a/roles/auth/tasks/main.yml b/roles/auth/tasks/main.yml index 351ba0d..5ca4de8 100644 --- a/roles/auth/tasks/main.yml +++ b/roles/auth/tasks/main.yml @@ -3,30 +3,37 @@ - name: Load aybarsm ansible role main variables ansible.builtin.include_vars: ../ansible/vars/main.yml -# - name: Include groups tasks -# ansible.builtin.include_tasks: -# file: groups.yml -# when: -# - auth__role_enabled | default(false) | bool -# - auth__manage_groups | default(false) | bool +- name: Include groups tasks + ansible.builtin.include_tasks: + file: groups.yml + when: + - auth__role_enabled | default(false) | bool + - auth__manage_groups | default(false) | bool -# - name: Include users tasks -# ansible.builtin.include_tasks: -# file: users.yml -# when: -# - auth__role_enabled | default(false) | bool -# - auth__manage_users | default(false) | bool +- name: Include users tasks + ansible.builtin.include_tasks: + file: users.yml + when: + - auth__role_enabled | default(false) | bool + - auth__manage_users | default(false) | bool -# - name: Include authroized keys tasks -# ansible.builtin.include_tasks: -# file: authorized_keys.yml -# when: -# - auth__role_enabled | default(false) | bool -# - auth__manage_authorized_keys | default(false) | bool +- name: Include authroized keys tasks + ansible.builtin.include_tasks: + file: authorized_keys.yml + when: + - auth__role_enabled | default(false) | bool + - auth__manage_authorized_keys | default(false) | bool -# - name: Include ssh config tasks -# ansible.builtin.include_tasks: -# file: ssh_config.yml -# when: -# - auth__role_enabled | default(false) | bool -# - auth__manage_ssh_config | default(false) | bool \ No newline at end of file +- name: Include ssh config tasks + ansible.builtin.include_tasks: + file: ssh.yml + when: + - auth__role_enabled | default(false) | bool + - (auth__manage_sshd_config | default(false) | bool) or (auth__manage_ssh_config | default(false) | bool) + +- name: Include sudoers tasks + ansible.builtin.include_tasks: + file: sudoers.yml + when: + - auth__role_enabled | default(false) | bool + - auth__manage_sudoers | default(false) | bool \ No newline at end of file diff --git a/roles/auth/tasks/ssh.yml b/roles/auth/tasks/ssh.yml new file mode 100644 index 0000000..72aa949 --- /dev/null +++ b/roles/auth/tasks/ssh.yml @@ -0,0 +1,45 @@ +--- +- name: Apply ssh daemon configuration + become: true + ansible.builtin.template: + src: "{{ auth__sshd_config_template }}" + dest: "{{ auth__sshd_config_file }}" + backup: "{{ auth__sshd_config_backup | default(omit) | bool }}" + validate: "{{ auth__sshd_validate | default(omit) }}" + register: auth__sshd_config_apply + notify: "auth__ssh_apply_changes" + when: + - auth__manage_sshd_config | default(false) | bool + - auth__sshd_config_all | type_debug == 'list' + - auth__sshd_config_all | length > 0 + +- name: Apply ssh client configuration + become: true + ansible.builtin.template: + src: "{{ auth__ssh_config_template }}" + dest: "{{ auth__ssh_config_file }}" + backup: "{{ auth__ssh_config_backup | default(omit) | bool }}" + register: auth__ssh_config_apply + notify: "auth__ssh_apply_changes" + when: + - auth__manage_ssh_config | default(false) | bool + - auth__ssh_config_all | type_debug == 'list' + - auth__ssh_config_all | length > 0 + +- name: Run smart sshd configuration changes + ansible.builtin.command: + cmd: /usr/bin/true + changed_when: true + notify: "auth__ssh_apply_changes" + when: + - auth__sshd_validate is defined + - auth__sshd_config_apply is not change + - auth__ssh_config_apply is not change + - auth__ssh_changes_strategy.smart | default(false) | bool + +- name: Effect ssh changes + ansible.builtin.meta: 'flush_handlers' + when: + - auth__ssh_changes_strategy.module is defined + - auth__ssh_changes_strategy.immediate | default(false) | bool + \ No newline at end of file diff --git a/roles/auth/tasks/ssh_config.yml b/roles/auth/tasks/ssh_config.yml deleted file mode 100644 index dd5cebd..0000000 --- a/roles/auth/tasks/ssh_config.yml +++ /dev/null @@ -1,21 +0,0 @@ ---- -- name: Apply ssh configuration - become: true - ansible.builtin.template: - src: "{{ auth__ssh_config_template }}" - dest: "{{ auth__ssh_config_file }}" - backup: "{{ auth__ssh_config_backup | default(omit) | bool }}" - validate: "{{ auth__sshd_validate | default(omit) }}" - register: auth__ssh_config_apply - notify: "auth__ssh_config_apply_changes" - when: - - auth__ssh_config_all | type_debug == 'list' - - auth__ssh_config_all | length > 0 - -- name: Effect ssh config changes - ansible.builtin.meta: 'flush_handlers' - when: - - auth__ssh_config_change_strategy.module is defined - - auth__ssh_config_change_strategy.when is defined - - auth__ssh_config_change_strategy.when == 'immediate' - \ No newline at end of file diff --git a/roles/auth/tasks/sudoers.yml b/roles/auth/tasks/sudoers.yml index 3ac8593..cd23fa2 100644 --- a/roles/auth/tasks/sudoers.yml +++ b/roles/auth/tasks/sudoers.yml @@ -1,15 +1,14 @@ --- -- name: Apply sudoers configuration template +- name: Apply sudoers configuration file become: true ansible.builtin.template: - src: "{{ auth__ssh_config_template }}" - dest: "{{ auth__ssh_config_file }}" - backup: "{{ auth__ssh_config_backup | default(omit) | bool }}" - validate: "{{ auth__sshd_validate | default(omit) }}" - register: auth__sudoers_apply + src: "{{ auth__sudoers_template }}" + dest: "{{ auth__sudoers_file }}" + validate: "{{  auth__sudoers_validate | default(omit) }}" + register: auth__sudoers_file_apply when: - - auth__sudoers_all | type_debug == 'list' - - auth__sudoers_all | length > 0 + - auth__sudoers_file_all | type_debug == 'list' + - auth__sudoers_file_all | length > 0 - name: Apply sudoers configuration via community.general.sudoers module become: true diff --git a/roles/auth/templates/etc/ssh/ssh_config.d/50-ansible.conf.j2 b/roles/auth/templates/etc/ssh/ssh_config.d/50-ansible.conf.j2 index 40d632f..b52d114 100644 --- a/roles/auth/templates/etc/ssh/ssh_config.d/50-ansible.conf.j2 +++ b/roles/auth/templates/etc/ssh/ssh_config.d/50-ansible.conf.j2 @@ -1,2 +1,2 @@ {{ ansible_managed | comment }} -{{ auth__ssh_config_all | aybarsm.helper.to_querystring('name', 'value', ' ', '\n', 'children', 4, ' ', true) }} \ No newline at end of file +{{ auth__ssh_config_all | aybarsm.helper.to_querystring('name', 'value', ' ', '\n', 'children', 4, ' ', true) }} diff --git a/roles/auth/templates/etc/ssh/sshd_config.d/50-ansible.conf.j2 b/roles/auth/templates/etc/ssh/sshd_config.d/50-ansible.conf.j2 new file mode 100644 index 0000000..002347d --- /dev/null +++ b/roles/auth/templates/etc/ssh/sshd_config.d/50-ansible.conf.j2 @@ -0,0 +1,2 @@ +{{ ansible_managed | comment }} +{{ auth__sshd_config_all | aybarsm.helper.to_querystring('name', 'value', ' ', '\n', 'children', 4, ' ', true) }} diff --git a/roles/auth/templates/etc/sudoers.d/50-ansible.conf.j2 b/roles/auth/templates/etc/sudoers.d/50-ansible.conf.j2 deleted file mode 100644 index 5c02948..0000000 --- a/roles/auth/templates/etc/sudoers.d/50-ansible.conf.j2 +++ /dev/null @@ -1 +0,0 @@ -{{ ansible_managed | comment }} diff --git a/roles/auth/templates/etc/sudoers.d/50-ansible.j2 b/roles/auth/templates/etc/sudoers.d/50-ansible.j2 new file mode 100644 index 0000000..d8b6d01 --- /dev/null +++ b/roles/auth/templates/etc/sudoers.d/50-ansible.j2 @@ -0,0 +1,2 @@ +{{ ansible_managed | comment }} +{{ auth__sudoers_file_all | aybarsm.helper.to_querystring(keyAttr='entry', joinChar='\n\n') }} \ No newline at end of file diff --git a/roles/auth/vars/main.yml b/roles/auth/vars/main.yml index d0437a5..e48516c 100644 --- a/roles/auth/vars/main.yml +++ b/roles/auth/vars/main.yml @@ -3,41 +3,51 @@ __auth__config: authorized_keys: selectattr: - when: - - ['type', 'defined'] - - ['type', 'equalto', 'authorized_key'] - - ['user', 'defined'] - - ['key', 'defined'] + - ['type', 'defined'] + - ['type', 'equalto', 'authorized_key'] + - ['user', 'defined'] + - ['key', 'defined'] groups: selectattr: - when: - - ['type', 'defined'] - - ['type', 'equalto', 'group'] + - ['type', 'defined'] + - ['type', 'equalto', 'group'] - when: "{{ __ansible__config.modules.ansible_builtin_group.uniques | product(['defined']) | list }}" logic: or users: selectattr: - when: - - ['type', 'defined'] - - ['type', 'equalto', 'user'] + - ['type', 'defined'] + - ['type', 'equalto', 'user'] - when: "{{ __ansible__config.modules.ansible_builtin_user.uniques | product(['defined']) | list }}" logic: or + sshd_config: + selectattr: + - when: + - ['type', 'defined'] + - ['type', 'equalto', 'sshd_config'] + - ['name', 'defined'] + - ['value', 'defined'] ssh_config: selectattr: - when: - - ['type', 'defined'] - - ['type', 'equalto', 'ssh_config'] - - ['name', 'defined'] - - ['value', 'defined'] + - ['type', 'defined'] + - ['type', 'equalto', 'ssh_config'] + - ['name', 'defined'] + - ['value', 'defined'] + sudoers_file: + selectattr: + - when: + - ['type', 'defined'] + - ['type', 'equalto', 'sudoers_file'] + - ['entry', 'defined'] sudoers_module: selectattr: - - when: "{{ [['type', 'defined'], ['type', 'equalto', 'sudoers_module']] + - ([['name', 'defined']] if (auth__sudoers_consolidate | default(true) | bool) else []) }}" - -auth__authorized_keys_all: "{{ auth__all | - aybarsm.helper.selectattr(__auth__config.authorized_keys.selectattr) | - aybarsm.helper.unique_combinations([['user', 'key']]) | - default([]) }}" - + - when: + - ['type', 'defined'] + - ['type', 'equalto', 'sudoers_module'] + - ['name', 'defined'] + auth__groups_all: "{{ auth__all | aybarsm.helper.selectattr(__auth__config.groups.selectattr) | aybarsm.helper.unique_recursive(__ansible__config.modules.ansible_builtin_group.uniques) | @@ -49,12 +59,26 @@ auth__users_all: "{{ auth__all | aybarsm.helper.unique_recursive(__ansible__config.modules.ansible_builtin_user.uniques) | default([]) }}" +auth__authorized_keys_all: "{{ auth__all | + aybarsm.helper.selectattr(__auth__config.authorized_keys.selectattr) | + aybarsm.helper.unique_combinations([['user', 'key']]) | + default([]) }}" + +auth__sshd_config_all: "{{ auth__all | + aybarsm.helper.selectattr(__auth__config.sshd_config.selectattr) | + aybarsm.helper.unique_recursive('name', 'children') | + default([]) }}" + auth__ssh_config_all: "{{ auth__all | aybarsm.helper.selectattr(__auth__config.ssh_config.selectattr) | - aybarsm.helper.replace_aliases(__ansible__config.modules.ansible_builtin_user.aliases) | aybarsm.helper.unique_recursive('name', 'children') | default([]) }}" +auth__sudoers_file_all: "{{ auth__all | + aybarsm.helper.selectattr(__auth__config.sudoers_file.selectattr) | + aybarsm.helper.unique_recursive('entry') | + default([]) }}" + auth__sudoers_module_all: "{{ auth__all | aybarsm.helper.selectattr(__auth__config.sudoers_module.selectattr) | aybarsm.helper.unique_recursive('name') |