From d3e3bdce5a3e738efa3f98b76c1ec0f21c702853 Mon Sep 17 00:00:00 2001 From: Jakub Jelen Date: Mon, 22 Jan 2024 16:17:38 +0100 Subject: [PATCH 1/6] Add whitespace around the filter symbol Signed-off-by: Jakub Jelen --- handlers/main.yml | 2 +- tasks/find_ports.yml | 2 +- tasks/install.yml | 4 ++-- tasks/install_service.yml | 4 ++-- tests/tasks/restore.yml | 2 +- tests/tasks/setup.yml | 4 ++-- tests/tests_alternative_file.yml | 14 +++++++------- tests/tests_alternative_file_role.yml | 15 +++++++-------- tests/tests_sysconfig.yml | 2 +- 9 files changed, 24 insertions(+), 25 deletions(-) diff --git a/handlers/main.yml b/handlers/main.yml index 8e4633b..183b4e2 100644 --- a/handlers/main.yml +++ b/handlers/main.yml @@ -6,7 +6,7 @@ state: reloaded when: - sshd_allow_reload|bool - - ansible_facts['virtualization_type']|default(None) not in __sshd_skip_virt_env + - ansible_facts['virtualization_type'] | default(None) not in __sshd_skip_virt_env - ansible_connection != 'chroot' - ansible_facts['os_family'] != 'AIX' - ansible_facts['os_family'] != 'OpenWrt' diff --git a/tasks/find_ports.yml b/tasks/find_ports.yml index e243e44..2d05cec 100644 --- a/tasks/find_ports.yml +++ b/tasks/find_ports.yml @@ -23,4 +23,4 @@ when: - sshd_manage_firewall | bool or sshd_manage_selinux | bool - ansible_facts['os_family'] == 'RedHat' - - ansible_facts['virtualization_type']|default(None) not in __sshd_skip_virt_env + - ansible_facts['virtualization_type'] | default(None) not in __sshd_skip_virt_env diff --git a/tasks/install.yml b/tasks/install.yml index 228af84..211cbf3 100644 --- a/tasks/install.yml +++ b/tasks/install.yml @@ -132,14 +132,14 @@ - sshd_manage_firewall | bool - ansible_facts['os_family'] == 'RedHat' - ansible_facts['distribution_version'] is version('7', '>=') - - ansible_facts['virtualization_type']|default(None) not in __sshd_skip_virt_env + - ansible_facts['virtualization_type'] | default(None) not in __sshd_skip_virt_env - name: Configure selinux ansible.builtin.include_tasks: selinux.yml when: - sshd_manage_selinux | bool - ansible_facts['os_family'] == 'RedHat' - - ansible_facts['virtualization_type']|default(None) not in __sshd_skip_virt_env + - ansible_facts['virtualization_type'] | default(None) not in __sshd_skip_virt_env - name: Create the complete configuration file ansible.builtin.include_tasks: install_config.yml diff --git a/tasks/install_service.yml b/tasks/install_service.yml index d663e41..fc972cf 100644 --- a/tasks/install_service.yml +++ b/tasks/install_service.yml @@ -34,7 +34,7 @@ state: started when: - sshd_manage_service|bool - - ansible_facts['virtualization_type']|default(None) not in __sshd_skip_virt_env + - ansible_facts['virtualization_type'] | default(None) not in __sshd_skip_virt_env - ansible_connection != 'chroot' # Due to ansible bug 21026, cannot use service module on RHEL 7 @@ -43,5 +43,5 @@ when: - ansible_connection == 'chroot' - ansible_facts['os_family'] == 'RedHat' - - ansible_facts['distribution_major_version']|int >= 7 + - ansible_facts['distribution_major_version'] | int >= 7 changed_when: true diff --git a/tests/tasks/restore.yml b/tests/tasks/restore.yml index 8d01c4b..2a1959a 100644 --- a/tests/tasks/restore.yml +++ b/tests/tasks/restore.yml @@ -38,6 +38,6 @@ changed_when: false when: - __sshd_test_backup is defined - - ansible_facts['virtualization_type']|default(None) not in __sshd_skip_virt_env + - ansible_facts['virtualization_type'] | default(None) not in __sshd_skip_virt_env - ansible_connection != 'chroot' - ansible_facts['os_family'] != 'AIX' diff --git a/tests/tasks/setup.yml b/tests/tasks/setup.yml index d5fbd43..02f56ac 100644 --- a/tests/tasks/setup.yml +++ b/tests/tasks/setup.yml @@ -57,5 +57,5 @@ main_sshd_config_name: 00-ansible_system_role.conf main_sshd_config_path: /etc/ssh/sshd_config.d/ when: - - (ansible_facts['os_family'] == 'RedHat' and ansible_facts['distribution_major_version']|int > 8) or - (ansible_facts['distribution'] == 'Ubuntu' and ansible_facts['distribution_major_version']|int >= 22) + - (ansible_facts['os_family'] == 'RedHat' and ansible_facts['distribution_major_version'] | int > 8) or + (ansible_facts['distribution'] == 'Ubuntu' and ansible_facts['distribution_major_version'] | int >= 22) diff --git a/tests/tests_alternative_file.yml b/tests/tests_alternative_file.yml index a16a3a2..2d9c22c 100644 --- a/tests/tests_alternative_file.yml +++ b/tests/tests_alternative_file.yml @@ -104,7 +104,7 @@ - "'AuthorizedKeysFile .ssh/authorized_keys' in config.content | b64decode" when: - ansible_facts['os_family'] == 'RedHat' - - ansible_facts['distribution_major_version']|int > 8 + - ansible_facts['distribution_major_version'] | int > 8 - name: Check RHEL7 and RHEL8 defaults are present in the first configuration file ansible.builtin.assert: @@ -114,8 +114,8 @@ - "'UsePAM yes' in config.content | b64decode" when: - ansible_facts['os_family'] == 'RedHat' - - ansible_facts['distribution_major_version']|int > 6 - - ansible_facts['distribution_major_version']|int < 9 + - ansible_facts['distribution_major_version'] | int > 6 + - ansible_facts['distribution_major_version'] | int < 9 - name: Check RHEL6 defaults are present in the first configuration file ansible.builtin.assert: @@ -133,7 +133,7 @@ - "'UsePAM yes' in config.content | b64decode" when: - ansible_facts['os_family'] == 'Debian' - - ansible_facts['distribution_major_version']|int < 22 + - ansible_facts['distribution_major_version'] | int < 22 - name: Check Ubuntu 22 defaults are present in the first configuration file ansible.builtin.assert: @@ -143,7 +143,7 @@ - "'UsePAM yes' in config.content | b64decode" when: - ansible_facts['distribution'] == 'Ubuntu' - - ansible_facts['distribution_major_version']|int >= 22 + - ansible_facts['distribution_major_version'] | int >= 22 - name: Check content of second configuration file ansible.builtin.assert: @@ -172,7 +172,7 @@ - "'Subsystem sftp /usr/libexec/openssh/sftp-server' in config3.content | b64decode" when: - ansible_facts['os_family'] == 'RedHat' - - ansible_facts['distribution_major_version']|int > 8 + - ansible_facts['distribution_major_version'] | int > 8 - ansible_facts['distribution'] != 'Fedora' - name: Check the main configuration file contains some default values for Fedora @@ -183,7 +183,7 @@ - "'Subsystem sftp /usr/libexec/sftp-server' in config3.content | b64decode" when: - ansible_facts['os_family'] == 'RedHat' - - ansible_facts['distribution_major_version']|int > 8 + - ansible_facts['distribution_major_version'] | int > 8 - ansible_facts['distribution'] == 'Fedora' - name: Check the generated config has requested properties diff --git a/tests/tests_alternative_file_role.yml b/tests/tests_alternative_file_role.yml index ee5c2f5..08a8109 100644 --- a/tests/tests_alternative_file_role.yml +++ b/tests/tests_alternative_file_role.yml @@ -122,7 +122,7 @@ - "'AuthorizedKeysFile .ssh/authorized_keys' in config.content | b64decode" when: - ansible_facts['os_family'] == 'RedHat' - - ansible_facts['distribution_major_version']|int > 8 + - ansible_facts['distribution_major_version'] | int > 8 - name: Check RHEL7 and RHEL8 defaults are present in the first configuration file ansible.builtin.assert: @@ -132,8 +132,8 @@ - "'UsePAM yes' in config.content | b64decode" when: - ansible_facts['os_family'] == 'RedHat' - - ansible_facts['distribution_major_version']|int > 6 - - ansible_facts['distribution_major_version']|int < 9 + - ansible_facts['distribution_major_version'] | int > 6 + - ansible_facts['distribution_major_version'] | int < 9 - name: Check RHEL6 defaults are present in the first configuration file ansible.builtin.assert: @@ -151,7 +151,7 @@ - "'UsePAM yes' in config.content | b64decode" when: - ansible_facts['os_family'] == 'Debian' - - ansible_facts['distribution_major_version']|int < 22 + - ansible_facts['distribution_major_version'] | int < 22 - name: Check Ubuntu 22 defaults are present in the first configuration file ansible.builtin.assert: @@ -161,8 +161,7 @@ - "'UsePAM yes' in config.content | b64decode" when: - ansible_facts['distribution'] == 'Ubuntu' - - ansible_facts['distribution_major_version']|int >= 22 - + - ansible_facts['distribution_major_version'] | int >= 22 - name: Check content of second configuration file ansible.builtin.assert: @@ -191,7 +190,7 @@ - "'Subsystem sftp /usr/libexec/openssh/sftp-server' in config3.content | b64decode" when: - ansible_facts['os_family'] == 'RedHat' - - ansible_facts['distribution_major_version']|int > 8 + - ansible_facts['distribution_major_version'] | int > 8 - ansible_facts['distribution'] != 'Fedora' - name: Check the main configuration file contains some default values for Fedora @@ -202,7 +201,7 @@ - "'Subsystem sftp /usr/libexec/sftp-server' in config3.content | b64decode" when: - ansible_facts['os_family'] == 'RedHat' - - ansible_facts['distribution_major_version']|int > 8 + - ansible_facts['distribution_major_version'] | int > 8 - ansible_facts['distribution'] == 'Fedora' - name: Check the generated config has requested properties diff --git a/tests/tests_sysconfig.yml b/tests/tests_sysconfig.yml index 96b0c32..dd797e0 100644 --- a/tests/tests_sysconfig.yml +++ b/tests/tests_sysconfig.yml @@ -23,7 +23,7 @@ when: - ansible_facts['os_family'] == "RedHat" - ansible_facts['distribution'] != 'Fedora' - - ansible_facts['distribution_major_version']|int < 9 + - ansible_facts['distribution_major_version'] | int < 9 block: - name: Flush handlers ansible.builtin.meta: flush_handlers From 793cca4c9759bf16648821cfc895f2d396925097 Mon Sep 17 00:00:00 2001 From: Jakub Jelen Date: Mon, 22 Jan 2024 16:35:45 +0100 Subject: [PATCH 2/6] ci: Add missing requirements Signed-off-by: Jakub Jelen --- .github/workflows/ansible-debian-check.yml | 3 +++ .github/workflows/ansible-ubuntu.yml | 2 ++ 2 files changed, 5 insertions(+) diff --git a/.github/workflows/ansible-debian-check.yml b/.github/workflows/ansible-debian-check.yml index 1a9a4a9..9c8751f 100644 --- a/.github/workflows/ansible-debian-check.yml +++ b/.github/workflows/ansible-debian-check.yml @@ -15,6 +15,7 @@ jobs: group: local hosts: localhost targets: "tests/tests_*.yml" + requirements: tests/requirements.yml debian-bullseye: runs-on: ubuntu-latest @@ -28,6 +29,7 @@ jobs: group: local hosts: localhost targets: "tests/tests_*.yml" + requirements: tests/requirements.yml debian-buster: runs-on: ubuntu-latest @@ -41,3 +43,4 @@ jobs: group: local hosts: localhost targets: "tests/tests_*.yml" + requirements: tests/requirements.yml diff --git a/.github/workflows/ansible-ubuntu.yml b/.github/workflows/ansible-ubuntu.yml index 8e3f91f..8703094 100644 --- a/.github/workflows/ansible-ubuntu.yml +++ b/.github/workflows/ansible-ubuntu.yml @@ -16,6 +16,7 @@ jobs: group: local hosts: localhost targets: "tests/tests_*.yml" + requirements: tests/requirements.yml ubuntu-20: runs-on: ubuntu-latest @@ -30,3 +31,4 @@ jobs: group: local hosts: localhost targets: "tests/tests_*.yml" + requirements: tests/requirements.yml From cea077a704a9315b1676ea221e1c089650168dd2 Mon Sep 17 00:00:00 2001 From: Jakub Jelen Date: Mon, 27 Nov 2023 14:19:41 +0100 Subject: [PATCH 3/6] tests: The new manual pages have different indentation Signed-off-by: Jakub Jelen --- tests/tests_all_options.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/tests_all_options.yml b/tests/tests_all_options.yml index 08be499..d085c09 100644 --- a/tests/tests_all_options.yml +++ b/tests/tests_all_options.yml @@ -90,10 +90,10 @@ ansible.builtin.shell: >- set -o pipefail && man sshd_config \ | sed 's/\x08.//g' \ - | grep -o '^ [A-Z][A-Za-z0-9]*\(.\| \)' \ + | grep -o '^\( \| \)[A-Z][A-Za-z0-9]*\(.\| \)' \ | grep -v "[A-Za-z0-9] $" | grep -v "[^A-Za-z0-9 ]$" \ | awk '{ print $1 }' \ - | grep -v '^$' | grep -v "^Match$" + | grep -v '^$' | grep -v "^\(Match\|OpenSSH\|The\|Arguments\|Theo\)$" args: executable: /bin/bash register: sshd_options @@ -102,7 +102,7 @@ - name: Print all the possible options ansible.builtin.debug: - var: ssh_options.stdout_lines + var: sshd_options.stdout_lines - name: Construct the configuration list ansible.builtin.set_fact: From 84e6a71509dd3c94f11344b2c13d007a2b20aa91 Mon Sep 17 00:00:00 2001 From: Jakub Jelen Date: Tue, 31 Oct 2023 15:11:43 +0100 Subject: [PATCH 4/6] Ubuntu 20 already supports drop-in directory Signed-off-by: Jakub Jelen --- tests/tasks/setup.yml | 2 +- tests/tests_alternative_file.yml | 11 +++++++++-- tests/tests_alternative_file_role.yml | 11 +++++++++-- tests/tests_include_present.yml | 6 +++--- vars/Ubuntu_20.yml | 12 +++++++++++- 5 files changed, 33 insertions(+), 9 deletions(-) diff --git a/tests/tasks/setup.yml b/tests/tasks/setup.yml index 02f56ac..a88234c 100644 --- a/tests/tasks/setup.yml +++ b/tests/tasks/setup.yml @@ -58,4 +58,4 @@ main_sshd_config_path: /etc/ssh/sshd_config.d/ when: - (ansible_facts['os_family'] == 'RedHat' and ansible_facts['distribution_major_version'] | int > 8) or - (ansible_facts['distribution'] == 'Ubuntu' and ansible_facts['distribution_major_version'] | int >= 22) + (ansible_facts['distribution'] == 'Ubuntu' and ansible_facts['distribution_major_version'] | int >= 20) diff --git a/tests/tests_alternative_file.yml b/tests/tests_alternative_file.yml index 2d9c22c..ef59400 100644 --- a/tests/tests_alternative_file.yml +++ b/tests/tests_alternative_file.yml @@ -135,12 +135,19 @@ - ansible_facts['os_family'] == 'Debian' - ansible_facts['distribution_major_version'] | int < 22 - - name: Check Ubuntu 22 defaults are present in the first configuration file + - name: Check Ubuntu 20+ defaults are present in the first configuration file ansible.builtin.assert: that: - "'Include /etc/ssh/sshd_config.d/*.conf' in config3.content | b64decode" - - "'KbdInteractiveAuthentication no' in config.content | b64decode" - "'UsePAM yes' in config.content | b64decode" + when: + - ansible_facts['distribution'] == 'Ubuntu' + - ansible_facts['distribution_major_version'] | int >= 20 + + - name: Check Ubuntu 22+ defaults are present in the first configuration file + ansible.builtin.assert: + that: + - "'KbdInteractiveAuthentication no' in config.content | b64decode" when: - ansible_facts['distribution'] == 'Ubuntu' - ansible_facts['distribution_major_version'] | int >= 22 diff --git a/tests/tests_alternative_file_role.yml b/tests/tests_alternative_file_role.yml index 08a8109..30c0567 100644 --- a/tests/tests_alternative_file_role.yml +++ b/tests/tests_alternative_file_role.yml @@ -153,12 +153,19 @@ - ansible_facts['os_family'] == 'Debian' - ansible_facts['distribution_major_version'] | int < 22 - - name: Check Ubuntu 22 defaults are present in the first configuration file + - name: Check Ubuntu 20+ defaults are present in the first configuration file ansible.builtin.assert: that: - "'Include /etc/ssh/sshd_config.d/*.conf' in config3.content | b64decode" - - "'KbdInteractiveAuthentication no' in config.content | b64decode" - "'UsePAM yes' in config.content | b64decode" + when: + - ansible_facts['distribution'] == 'Ubuntu' + - ansible_facts['distribution_major_version'] | int >= 20 + + - name: Check Ubuntu 22+ defaults are present in the first configuration file + ansible.builtin.assert: + that: + - "'KbdInteractiveAuthentication no' in config.content | b64decode" when: - ansible_facts['distribution'] == 'Ubuntu' - ansible_facts['distribution_major_version'] | int >= 22 diff --git a/tests/tests_include_present.yml b/tests/tests_include_present.yml index c82c3fd..aeac6f6 100644 --- a/tests/tests_include_present.yml +++ b/tests/tests_include_present.yml @@ -17,7 +17,7 @@ state: absent when: - (ansible_facts['os_family'] == 'RedHat' and ansible_facts['distribution_major_version'] | int > 8) or - (ansible_facts['distribution'] == 'Ubuntu' and ansible_facts['distribution_major_version'] | int >= 22) + (ansible_facts['distribution'] == 'Ubuntu' and ansible_facts['distribution_major_version'] | int >= 20) - name: Create a new configuration in drop-in directory ansible.builtin.include_role: @@ -29,12 +29,12 @@ Ciphers: aes192-ctr when: - (ansible_facts['os_family'] == 'RedHat' and ansible_facts['distribution_major_version'] | int > 8) or - (ansible_facts['distribution'] == 'Ubuntu' and ansible_facts['distribution_major_version'] | int >= 22) + (ansible_facts['distribution'] == 'Ubuntu' and ansible_facts['distribution_major_version'] | int >= 20) - name: Verify the options are correctly set when: - (ansible_facts['os_family'] == 'RedHat' and ansible_facts['distribution_major_version'] | int > 8) or - (ansible_facts['distribution'] == 'Ubuntu' and ansible_facts['distribution_major_version'] | int >= 22) + (ansible_facts['distribution'] == 'Ubuntu' and ansible_facts['distribution_major_version'] | int >= 20) tags: tests::verify block: - name: Flush handlers diff --git a/vars/Ubuntu_20.yml b/vars/Ubuntu_20.yml index c8f8088..5dd4512 100644 --- a/vars/Ubuntu_20.yml +++ b/vars/Ubuntu_20.yml @@ -1,15 +1,25 @@ --- +__sshd_os_supported: true + __sshd_service: ssh __sshd_packages: - openssh-server - openssh-sftp-server +# Ubuntu 20.04 backported support for drop-in directory so we touch +# just the included file with highest priority by default +__sshd_config_file: /etc/ssh/sshd_config.d/00-ansible_system_role.conf __sshd_config_mode: "0644" +# the defaults here represent the defaults shipped in the main sshd_config __sshd_defaults: + Include: /etc/ssh/sshd_config.d/*.conf ChallengeResponseAuthentication: false UsePAM: true X11Forwarding: true PrintMotd: false AcceptEnv: LANG LC_* Subsystem: "sftp /usr/lib/openssh/sftp-server" -__sshd_os_supported: true + __sshd_runtime_directory: sshd + +__sshd_drop_in_dir_mode: '0755' +__sshd_main_config_file: /etc/ssh/sshd_config From f6ae2094fe23eed94ce64eee1d0f5f1109dfe1da Mon Sep 17 00:00:00 2001 From: Jakub Jelen Date: Mon, 30 Oct 2023 17:51:44 +0100 Subject: [PATCH 5/6] Update service/socket files to match main OS's defaults Specifics: * Debian 12 has no longer the instantiated service using inet, see the following commit: https://salsa.debian.org/ssh-team/openssh/-/commit/0dc73888bbfc17fae04b891ac0c80f35f9c44f48 * I am not matching the Description tag verbosely as I do not find it crucial for functionality. * We generate additional -f switch to the sshd CLI pointing go the main sshd config we manage * The Before=sshd.service in the socket is not generated as I find it unnecessary when we conflict the service. * Recent Ubuntu versions have RuntimeDirectoryPreserve option, which I set for all Ubuntu/Debian as it should not hurt. Signed-off-by: Jakub Jelen --- tasks/install_service.yml | 4 ++++ templates/sshd.service.j2 | 27 ++++++++++++++++++++++++++- templates/sshd.socket.j2 | 9 ++++++++- templates/sshd@.service.j2 | 25 +++++++++++++++++++++++-- tests/tests_runtime_directory.yml | 8 ++++++++ vars/Debian_10.yml | 5 +++++ vars/Debian_11.yml | 5 +++++ vars/Debian_12.yml | 6 ++++++ vars/Fedora.yml | 8 ++++++++ vars/Fedora_37.yml | 7 +++++++ vars/RedHat_7.yml | 6 ++++++ vars/RedHat_8.yml | 8 ++++++++ vars/RedHat_9.yml | 6 ++++++ vars/Ubuntu_20.yml | 6 ++++++ vars/Ubuntu_22.yml | 5 +++++ vars/main.yml | 22 ++++++++++++++++++++++ 16 files changed, 153 insertions(+), 4 deletions(-) diff --git a/tasks/install_service.yml b/tasks/install_service.yml index fc972cf..b92d51e 100644 --- a/tasks/install_service.yml +++ b/tasks/install_service.yml @@ -10,6 +10,7 @@ group: root mode: "0644" notify: reload_sshd + - name: Install instanced service unit file ansible.builtin.template: src: "{{ sshd_service_template_at_service }}" @@ -18,6 +19,9 @@ group: root mode: "0644" notify: reload_sshd + when: + - __sshd_socket_accept | bool + - name: Install socket unit file ansible.builtin.template: src: "{{ sshd_service_template_socket }}" diff --git a/templates/sshd.service.j2 b/templates/sshd.service.j2 index 71042c5..ec6da4e 100644 --- a/templates/sshd.service.j2 +++ b/templates/sshd.service.j2 @@ -1,15 +1,37 @@ [Unit] Description=OpenBSD Secure Shell server +After=network.target{{ (__sshd_service_after is none) | ternary('', ' ' ~ __sshd_service_after) }} +{% if __sshd_service_wants is string %} +Wants={{ __sshd_service_wants }} +{% elif __sshd_service_wants is iterable %} +{% for file in __sshd_service_wants %} +Wants={{ file }} +{% endfor %} +{% endif %} Documentation=man:sshd(8) man:sshd_config(5) [Service] Type=notify +{% if __sshd_environment_file is string %} +EnvironmentFile=-{{ __sshd_environment_file }} +{% elif __sshd_environment_file is iterable %} +{% for file in __sshd_environment_file %} +EnvironmentFile=-{{ file }} +{% endfor %} +{% endif %} ExecStartPre={{ sshd_binary }} -t -ExecStart={{ sshd_binary }} -D -f {{ sshd_config_file }} +ExecStart={{ sshd_binary }} -D {{ __sshd_environment_variable }} -f {% if sshd_main_config_file is not none %} +{{- sshd_main_config_file }} +{% else %} +{{- sshd_config_file }} +{% endif %} ExecReload={{ sshd_binary }} -t ExecReload=/bin/kill -HUP $MAINPID KillMode=process Restart=on-failure +{% if __sshd_service_restart_timeout is not none %} +RestartSec={{ __sshd_service_restart_timeout }} +{% endif %} RestartPreventExitStatus=255 {% if __sshd_runtime_directory is not none %} RuntimeDirectory={{ __sshd_runtime_directory }} @@ -18,3 +40,6 @@ RuntimeDirectoryMode={{ __sshd_runtime_directory_mode }} [Install] WantedBy=multi-user.target +{% if __sshd_service_alias is not none %} +Alias={{ __sshd_service_alias }}.service +{% endif %} diff --git a/templates/sshd.socket.j2 b/templates/sshd.socket.j2 index 30d424f..9e0c2fb 100644 --- a/templates/sshd.socket.j2 +++ b/templates/sshd.socket.j2 @@ -1,12 +1,19 @@ [Unit] Description=OpenBSD Secure Shell server socket Documentation=man:sshd(8) man:sshd_config(5) -Before={{ sshd_service }}.service +{% if __sshd_socket_accept %} Conflicts={{ sshd_service }}.service +{% else %} +Before=sockets.target +{% endif %} [Socket] ListenStream=22 +{% if __sshd_socket_accept %} Accept=yes +{% else %} +Accept=no +{% endif %} [Install] WantedBy=sockets.target diff --git a/templates/sshd@.service.j2 b/templates/sshd@.service.j2 index 673373a..d48d27a 100644 --- a/templates/sshd@.service.j2 +++ b/templates/sshd@.service.j2 @@ -1,12 +1,33 @@ [Unit] Description=OpenBSD Secure Shell server per-connection daemon Documentation=man:sshd(8) man:sshd_config(5) -After=auditd.service +{% if __sshd_service_after is not none %} +After={{ __sshd_service_after }} +{% endif %} +{% if __sshd_service_wants is string %} +Wants={{ __sshd_service_wants }} +{% elif __sshd_service_wants is iterable %} +{% for file in __sshd_service_wants %} +Wants={{ file }} +{% endfor %} +{% endif %} [Service] -ExecStart=-{{ sshd_binary }} -i -f {{ sshd_config_file }} +{% if __sshd_environment_file is string %} +EnvironmentFile=-{{ __sshd_environment_file }} +{% elif __sshd_environment_file is iterable %} +{% for file in __sshd_environment_file %} +EnvironmentFile=-{{ file }} +{% endfor %} +{% endif %} +ExecStart=-{{ sshd_binary }} -i {{ __sshd_environment_variable }} -f {% if sshd_main_config_file is not none %} +{{- sshd_main_config_file }} +{% else %} +{{- sshd_config_file }} +{% endif %} StandardInput=socket {% if __sshd_runtime_directory is not none %} RuntimeDirectory={{ __sshd_runtime_directory }} +RuntimeDirectoryPreserve=yes RuntimeDirectoryMode={{ __sshd_runtime_directory_mode }} {% endif %} diff --git a/tests/tests_runtime_directory.yml b/tests/tests_runtime_directory.yml index 8f4fbd4..291a045 100644 --- a/tests/tests_runtime_directory.yml +++ b/tests/tests_runtime_directory.yml @@ -45,6 +45,8 @@ - name: Read the instantiated service file ansible.builtin.slurp: src: /etc/systemd/system/ssh@.service + when: + - ansible_facts['distribution_major_version'] | int < 12 register: service_inst - name: Read the main socket file @@ -57,6 +59,12 @@ that: - '"RuntimeDirectory=sshd" in service.content | b64decode' - '"RuntimeDirectoryMode=0755" in service.content | b64decode' + + - name: Check the runtime directory is in instantiated service files + when: + - ansible_facts['distribution_major_version'] | int < 12 + ansible.builtin.assert: + that: - '"RuntimeDirectory=sshd" in service_inst.content | b64decode' - '"RuntimeDirectoryMode=0755" in service_inst.content | b64decode' diff --git a/vars/Debian_10.yml b/vars/Debian_10.yml index 83fc9f1..ebe8e5e 100644 --- a/vars/Debian_10.yml +++ b/vars/Debian_10.yml @@ -13,3 +13,8 @@ __sshd_defaults: Subsystem: "sftp {{ __sshd_sftp_server }}" __sshd_os_supported: true __sshd_runtime_directory: sshd + +__sshd_environment_file: /etc/default/ssh +__sshd_environment_variable: $SSHD_OPTS +__sshd_service_after: auditd.service +__sshd_service_alias: sshd diff --git a/vars/Debian_11.yml b/vars/Debian_11.yml index df9ffee..0f2777d 100644 --- a/vars/Debian_11.yml +++ b/vars/Debian_11.yml @@ -14,3 +14,8 @@ __sshd_defaults: Subsystem: "sftp {{ __sshd_sftp_server }}" __sshd_os_supported: true __sshd_runtime_directory: sshd + +__sshd_environment_file: /etc/default/ssh +__sshd_environment_variable: $SSHD_OPTS +__sshd_service_after: auditd.service +__sshd_service_alias: sshd diff --git a/vars/Debian_12.yml b/vars/Debian_12.yml index 141abe3..a2ff398 100644 --- a/vars/Debian_12.yml +++ b/vars/Debian_12.yml @@ -14,3 +14,9 @@ __sshd_defaults: Subsystem: "sftp {{ __sshd_sftp_server }}" __sshd_os_supported: true __sshd_runtime_directory: sshd + +__sshd_environment_file: /etc/default/ssh +__sshd_environment_variable: $SSHD_OPTS +__sshd_service_after: auditd.service +__sshd_service_alias: sshd +__sshd_socket_accept: false diff --git a/vars/Fedora.yml b/vars/Fedora.yml index 236d165..4d978a8 100644 --- a/vars/Fedora.yml +++ b/vars/Fedora.yml @@ -23,3 +23,11 @@ __sshd_hostkeys_nofips: __sshd_drop_in_dir_mode: '0700' __sshd_main_config_file: /etc/ssh/sshd_config + +__sshd_environment_file: /etc/sysconfig/sshd +__sshd_environment_variable: $OPTIONS +__sshd_service_after: sshd-keygen.target +__sshd_service_wants: + - sshd-keygen.target + - ssh-host-keys-migration.service +__sshd_service_restart_timeout: 42s diff --git a/vars/Fedora_37.yml b/vars/Fedora_37.yml index 31b8b9b..6be93c3 100644 --- a/vars/Fedora_37.yml +++ b/vars/Fedora_37.yml @@ -20,8 +20,15 @@ __sshd_verify_hostkeys_default: - /etc/ssh/ssh_host_ed25519_key __sshd_hostkeys_nofips: - /etc/ssh/ssh_host_ed25519_key + __sshd_hostkey_group: ssh_keys __sshd_hostkey_mode: "0640" __sshd_drop_in_dir_mode: '0700' __sshd_main_config_file: /etc/ssh/sshd_config + +__sshd_environment_file: /etc/sysconfig/sshd +__sshd_environment_variable: $OPTIONS +__sshd_service_after: sshd-keygen.target +__sshd_service_wants: sshd-keygen.target +__sshd_service_restart_timeout: 42s diff --git a/vars/RedHat_7.yml b/vars/RedHat_7.yml index 08ed976..061993c 100644 --- a/vars/RedHat_7.yml +++ b/vars/RedHat_7.yml @@ -31,3 +31,9 @@ __sshd_hostkey_group: ssh_keys __sshd_hostkey_mode: "0640" __sshd_hostkeys_nofips: - /etc/ssh/ssh_host_ed25519_key + +__sshd_environment_file: /etc/sysconfig/sshd +__sshd_environment_variable: $OPTIONS +__sshd_service_after: sshd-keygen.service +__sshd_service_wants: sshd-keygen.service +__sshd_service_restart_timeout: 42s diff --git a/vars/RedHat_8.yml b/vars/RedHat_8.yml index 4e6dd28..d39d6dd 100644 --- a/vars/RedHat_8.yml +++ b/vars/RedHat_8.yml @@ -33,3 +33,11 @@ __sshd_hostkey_group: ssh_keys __sshd_hostkey_mode: "0640" __sshd_hostkeys_nofips: - /etc/ssh/ssh_host_ed25519_key + +__sshd_environment_file: + - /etc/crypto-policies/back-ends/opensshserver.config + - /etc/sysconfig/sshd +__sshd_environment_variable: $OPTIONS $CRYPTO_POLICY +__sshd_service_after: sshd-keygen.target +__sshd_service_wants: sshd-keygen.target ssh-host-keys-migration.service +__sshd_service_restart_timeout: 42s diff --git a/vars/RedHat_9.yml b/vars/RedHat_9.yml index 50a05a6..401c1c8 100644 --- a/vars/RedHat_9.yml +++ b/vars/RedHat_9.yml @@ -25,3 +25,9 @@ __sshd_hostkey_mode: "0640" __sshd_drop_in_dir_mode: '0700' __sshd_main_config_file: /etc/ssh/sshd_config + +__sshd_environment_file: /etc/sysconfig/sshd +__sshd_environment_variable: $OPTIONS +__sshd_service_after: sshd-keygen.target +__sshd_service_wants: sshd-keygen.target +__sshd_service_restart_timeout: 42s diff --git a/vars/Ubuntu_20.yml b/vars/Ubuntu_20.yml index 5dd4512..9e2da2a 100644 --- a/vars/Ubuntu_20.yml +++ b/vars/Ubuntu_20.yml @@ -23,3 +23,9 @@ __sshd_runtime_directory: sshd __sshd_drop_in_dir_mode: '0755' __sshd_main_config_file: /etc/ssh/sshd_config + +__sshd_environment_file: /etc/default/ssh +__sshd_environment_variable: $SSHD_OPTS +# the defaults here represent the defaults shipped in the main sshd_config +__sshd_service_after: auditd.service +__sshd_service_alias: sshd diff --git a/vars/Ubuntu_22.yml b/vars/Ubuntu_22.yml index 9128d8b..75b48b0 100644 --- a/vars/Ubuntu_22.yml +++ b/vars/Ubuntu_22.yml @@ -21,3 +21,8 @@ __sshd_runtime_directory: sshd __sshd_drop_in_dir_mode: '0755' __sshd_main_config_file: /etc/ssh/sshd_config + +__sshd_environment_file: /etc/default/ssh +__sshd_environment_variable: $SSHD_OPTS +__sshd_service_after: auditd.service +__sshd_service_alias: sshd diff --git a/vars/main.yml b/vars/main.yml index b6e8298..3dbfcca 100644 --- a/vars/main.yml +++ b/vars/main.yml @@ -64,3 +64,25 @@ __sshd_verify_hostkeys_default: [] # This switch can control if the validate step is supported by the target OS. # This is useful for very old OpenSSH or for tests that generate invalid configurations __sshd_supports_validate: true + +# The path to an environment file for the SSHD service +__sshd_environment_file: ~ + +# The variable name we are passing from the environment file as an argument to the sshd +__sshd_environment_variable: $OPTIONS + +# The systemd targets that need to be up before starting the service. +# The `network.target` is included by default in the main sshd.service (not the instantiated one) +__sshd_service_after: ~ + +# The systemd service name alias +__sshd_service_alias: ~ + +# The systemd service wants directive +__sshd_service_wants: ~ + +# The systemd service RestartSec directive +__sshd_service_restart_timeout: ~ + +# The systemd socket file does not accept the connection +__sshd_socket_accept: true From f59b40b5c90aea6e9f0d0fc2fda59e90738c2a1c Mon Sep 17 00:00:00 2001 From: Jakub Jelen Date: Mon, 30 Oct 2023 18:03:30 +0100 Subject: [PATCH 6/6] tests: Verify generated services/socket units do not miss any important options Signed-off-by: Jakub Jelen --- tests/tests_systemd_services.yml | 159 +++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 tests/tests_systemd_services.yml diff --git a/tests/tests_systemd_services.yml b/tests/tests_systemd_services.yml new file mode 100644 index 0000000..e1e3f1a --- /dev/null +++ b/tests/tests_systemd_services.yml @@ -0,0 +1,159 @@ +--- +- name: Test systemd services and sockets files can be installed + hosts: all + vars: + __sshd_test_backup_files: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d/00-ansible_system_role.conf + - /etc/systemd/system/sshd.service + - /etc/systemd/system/sshd@.service + - /etc/systemd/system/sshd.socket + - /etc/systemd/system/ssh.service + - /etc/systemd/system/ssh@.service + - /etc/systemd/system/ssh.socket + __sshd_test_service_name: sshd + __sshd_service_list: [] + __sshd_service_inst_list: [] + __sshd_socket_list: [] + tasks: + - name: Fix the service name on Debian + ansible.builtin.set_fact: + __sshd_test_service_name: ssh + when: + - ansible_facts['os_family'] == "Debian" + + - name: Backup configuration files + ansible.builtin.include_tasks: tasks/backup.yml + + - name: Configure sshd with default options and install service files + ansible.builtin.include_role: + name: ansible-sshd + vars: + sshd_install_service: true + + - name: Read the service files and verify they are reasonable + tags: tests::verify + when: + - ansible_facts['service_mgr'] == 'systemd' + block: + - name: Read the distribution service file + ansible.builtin.slurp: + src: "/lib/systemd/system/{{ __sshd_test_service_name }}.service" + register: service_old + + - name: Read the distribution socket file + ansible.builtin.slurp: + src: "/lib/systemd/system/{{ __sshd_test_service_name }}.socket" + register: socket_old + + - name: Read the created service file + ansible.builtin.slurp: + src: "/etc/systemd/system/{{ __sshd_test_service_name }}.service" + register: service + + - name: Read the created socket file + ansible.builtin.slurp: + src: "/etc/systemd/system/{{ __sshd_test_service_name }}.socket" + register: socket + + - name: Decode service file + ansible.builtin.set_fact: + service_old: "{{ service_old.content | b64decode }}" + + # quite basic, but it should do the job + # * I do not think the ConditionPathExists is much useful so skipping on Ubuntu + # * I do not think the Description needs to match verbatim either + - name: Construct the options list from old service file + ansible.builtin.set_fact: + __sshd_service_list: "{{ __sshd_service_list + [item] }}" + when: + - not item.startswith("#") + - not item.startswith("ConditionPathExists=") + - not item.startswith("Description=") + loop: + "{{ service_old.splitlines() }}" + + - name: Test options in sshd.service are kept + ansible.builtin.assert: + that: + - "item in service.content | b64decode" + loop: + "{{ __sshd_service_list }}" + + - name: Verify the ExecStart line contains the configuration file + ansible.builtin.assert: + that: + - "' -f /etc/ssh/' in service.content | b64decode" + + - name: Decode socket file + ansible.builtin.set_fact: + socket_old: "{{ socket_old.content | b64decode }}" + + # quite basic, but it should do the job + # * I do not think the ConditionPathExists is much useful so skipping on Ubuntu + # * Before= does not make any sense in combination with Conflicts= + # * I do not think the Description needs to match verbatim either + - name: Construct the options list from old socket file + ansible.builtin.set_fact: + __sshd_socket_list: "{{ __sshd_socket_list + [item] }}" + when: + - not item.startswith("#") + - not item.startswith("ConditionPathExists=") + - not item.startswith("Before=") + - not item.startswith("Description=") + loop: + "{{ socket_old.splitlines() }}" + + - name: Test options in sshd.socket are kept + ansible.builtin.assert: + that: + - "item in socket.content | b64decode" + loop: + "{{ __sshd_socket_list }}" + + - name: Read the instantiated service file and verify they are reasonable + tags: tests::verify + when: + - ansible_facts['service_mgr'] == 'systemd' + - ansible_facts['distribution'] != "Debian" or ansible_facts['distribution_major_version'] | int < 12 + block: + - name: Read the distribution instantiated service file + ansible.builtin.slurp: + src: "/lib/systemd/system/{{ __sshd_test_service_name }}@.service" + register: service_inst_old + + - name: Read the created instantiated service file + ansible.builtin.slurp: + src: "/etc/systemd/system/{{ __sshd_test_service_name }}@.service" + register: service_inst + + - name: Decode instantiated service file + ansible.builtin.set_fact: + service_inst_old: "{{ service_inst_old.content | b64decode }}" + + # quite basic, but it should do the job + # * I do not think the Description needs to match verbatim either + - name: Construct the options list from old instantiated service file + ansible.builtin.set_fact: + __sshd_service_inst_list: "{{ __sshd_service_inst_list + [item] }}" + when: + - not item.startswith("#") + - not item.startswith("Description=") + loop: + "{{ service_inst_old.splitlines() }}" + + - name: Test options in sshd@.service are kept + ansible.builtin.assert: + that: + - "item in service_inst.content | b64decode" + loop: + "{{ __sshd_service_inst_list }}" + + - name: Verify the ExecStart line contains the configuration file + ansible.builtin.assert: + that: + - "' -f /etc/ssh/' in service_inst.content | b64decode" + + + - name: "Restore configuration files" + ansible.builtin.include_tasks: tasks/restore.yml