Merge pull request #207 from Jakuje/test-all

Introduce automatic test for new configuration options in OpenSSH and add missing options so far
This commit is contained in:
Matt Willsher 2022-10-10 07:22:57 +01:00 committed by GitHub
commit 237de5ba6d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 146 additions and 9 deletions

View file

@ -28,12 +28,14 @@ DebianBanner
DenyGroups
DenyUsers
DisableForwarding
ExposeAuthenticationMethods
ExposeAuthInfo
FingerprintHash
ForceCommand
GatewayPorts
GSSAPIAuthentication
GSSAPICleanupCredentials
GSSAPIEnablek5users
GSSAPIKeyExchange
GSSAPIKexAlgorithms
GSSAPIStoreCredentialsOnRekey
@ -57,6 +59,8 @@ KerberosGetAFSToken
KerberosOrLocalPasswd
KerberosTicketCleanup
KerberosUniqueTicket
KerberosUniqueCCache
KerberosUseKuserok
KexAlgorithms
KeyRegenerationInterval
LogLevel
@ -96,6 +100,7 @@ RhostsRSAAuthentication
SecurityKeyProvider
SetEnv
ServerKeyBits
ShowPatchLevel
StreamLocalBindMask
StreamLocalBindUnlink
StrictModes

View file

@ -103,6 +103,7 @@
changed_when: false
when:
- __sshd_hostkeys_from_config | from_json == []
- __sshd_supports_validate
- name: Generate temporary hostkey
ansible.builtin.command: >

View file

@ -16,7 +16,9 @@
group: "{{ sshd_config_group }}"
mode: "{{ sshd_config_mode }}"
validate: >-
{% if sshd_test_hostkey is defined and sshd_test_hostkey.path is defined %}
{% if not __sshd_supports_validate %}
true %s
{% elif sshd_test_hostkey is defined and sshd_test_hostkey.path is defined %}
{{ sshd_binary }} -t -f %s -h {{ sshd_test_hostkey.path }}/rsa_key
{% else %}
{{ sshd_binary }} -t -f %s
@ -33,7 +35,9 @@
group: "{{ sshd_config_group }}"
mode: "{{ sshd_config_mode }}"
validate: >-
{% if sshd_test_hostkey is defined and sshd_test_hostkey.path is defined %}
{% if not __sshd_supports_validate %}
true %s
{% elif sshd_test_hostkey is defined and sshd_test_hostkey.path is defined %}
{{ sshd_binary }} -t -f %s -h {{ sshd_test_hostkey.path }}/rsa_key
{% else %}
{{ sshd_binary }} -t -f %s

View file

@ -13,7 +13,9 @@
create: yes
marker: "# {mark} sshd system role managed block: namespace {{ sshd_config_namespace }}"
validate: >-
{% if sshd_test_hostkey is defined and sshd_test_hostkey.path is defined %}
{% if not __sshd_supports_validate %}
true %s
{% elif sshd_test_hostkey is defined and sshd_test_hostkey.path is defined %}
{{ sshd_binary }} -t -f %s -h {{ sshd_test_hostkey.path }}/rsa_key
{% else %}
{{ sshd_binary }} -t -f %s

View file

@ -1,7 +1,9 @@
[Unit]
Description=OpenBSD Secure Shell server
Documentation=man:sshd(8) man:sshd_config(5)
[Service]
Type=notify
ExecStartPre={{ sshd_binary }} -t
ExecStart={{ sshd_binary }} -D -f {{ sshd_config_file }}
ExecReload={{ sshd_binary }} -t
@ -9,9 +11,8 @@ ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartPreventExitStatus=255
Type=notify
RuntimeDirectory={{ sshd_binary | basename }}
RuntimeDirectoryMode=0755
RuntimeDirectory={{ __sshd_runtime_directory }}
RuntimeDirectoryMode={{ __sshd_runtime_directory_mode }}
[Install]
WantedBy=multi-user.target

View file

@ -1,7 +1,8 @@
[Unit]
Description=OpenBSD Secure Shell server socket
Documentation=man:sshd(8) man:sshd_config(5)
Before={{ sshd_service }}.service
Conflicts={{sshd_service }}.service
Conflicts={{ sshd_service }}.service
[Socket]
ListenStream=22

View file

@ -1,9 +1,10 @@
[Unit]
Description=OpenBSD Secure Shell server per-connection daemon
Documentation=man:sshd(8) man:sshd_config(5)
After=auditd.service
[Service]
ExecStart=-{{ sshd_binary }} -i -f {{ sshd_config_file }}
StandardInput=socket
RuntimeDirectory={{ sshd_binary }}
RuntimeDirectoryMode=0755
RuntimeDirectory={{ __sshd_runtime_directory }}
RuntimeDirectoryMode={{ __sshd_runtime_directory_mode }}

View file

@ -143,12 +143,14 @@ Match {{ match["Condition"] }}
{{ body_option("DenyGroups",sshd_DenyGroups) -}}
{{ body_option("DenyUsers",sshd_DenyUsers) -}}
{{ body_option("DisableForwarding",sshd_DisableForwarding) -}}
{{ body_option("ExposeAuthenticationMethods",sshd_ExposeAuthenticationMethods) -}}
{{ body_option("ExposeAuthInfo",sshd_ExposeAuthInfo) -}}
{{ body_option("FingerprintHash",sshd_FingerprintHash) -}}
{{ body_option("ForceCommand",sshd_ForceCommand) -}}
{{ body_option("GatewayPorts",sshd_GatewayPorts) -}}
{{ body_option("GSSAPIAuthentication",sshd_GSSAPIAuthentication) -}}
{{ body_option("GSSAPICleanupCredentials",sshd_GSSAPICleanupCredentials) -}}
{{ body_option("GSSAPIEnablek5users",sshd_GSSAPIEnablek5users) -}}
{{ body_option("GSSAPIKeyExchange",sshd_GSSAPIKeyExchange) -}}
{{ body_option("GSSAPIKexAlgorithms",sshd_GSSAPIKexAlgorithms) -}}
{{ body_option("GSSAPIStoreCredentialsOnRekey",sshd_GSSAPIStoreCredentialsOnRekey) -}}
@ -172,6 +174,8 @@ Match {{ match["Condition"] }}
{{ body_option("KerberosOrLocalPasswd",sshd_KerberosOrLocalPasswd) -}}
{{ body_option("KerberosTicketCleanup",sshd_KerberosTicketCleanup) -}}
{{ body_option("KerberosUniqueTicket",sshd_KerberosUniqueTicket) -}}
{{ body_option("KerberosUniqueCCache",sshd_KerberosUniqueCCache) -}}
{{ body_option("KerberosUseKuserok",sshd_KerberosUseKuserok) -}}
{{ body_option("KexAlgorithms",sshd_KexAlgorithms) -}}
{{ body_option("KeyRegenerationInterval",sshd_KeyRegenerationInterval) -}}
{{ body_option("LogLevel",sshd_LogLevel) -}}
@ -211,6 +215,7 @@ Match {{ match["Condition"] }}
{{ body_option("SecurityKeyProvider",sshd_SecurityKeyProvider) -}}
{{ body_option("SetEnv",sshd_SetEnv) -}}
{{ body_option("ServerKeyBits",sshd_ServerKeyBits) -}}
{{ body_option("ShowPatchLevel",sshd_ShowPatchLevel) -}}
{{ body_option("StreamLocalBindMask",sshd_StreamLocalBindMask) -}}
{{ body_option("StreamLocalBindUnlink",sshd_StreamLocalBindUnlink) -}}
{{ body_option("StrictModes",sshd_StrictModes) -}}

View file

@ -142,12 +142,14 @@ Match {{ match["Condition"] }}
{{ body_option("DenyGroups",sshd_DenyGroups) -}}
{{ body_option("DenyUsers",sshd_DenyUsers) -}}
{{ body_option("DisableForwarding",sshd_DisableForwarding) -}}
{{ body_option("ExposeAuthenticationMethods",sshd_ExposeAuthenticationMethods) -}}
{{ body_option("ExposeAuthInfo",sshd_ExposeAuthInfo) -}}
{{ body_option("FingerprintHash",sshd_FingerprintHash) -}}
{{ body_option("ForceCommand",sshd_ForceCommand) -}}
{{ body_option("GatewayPorts",sshd_GatewayPorts) -}}
{{ body_option("GSSAPIAuthentication",sshd_GSSAPIAuthentication) -}}
{{ body_option("GSSAPICleanupCredentials",sshd_GSSAPICleanupCredentials) -}}
{{ body_option("GSSAPIEnablek5users",sshd_GSSAPIEnablek5users) -}}
{{ body_option("GSSAPIKeyExchange",sshd_GSSAPIKeyExchange) -}}
{{ body_option("GSSAPIKexAlgorithms",sshd_GSSAPIKexAlgorithms) -}}
{{ body_option("GSSAPIStoreCredentialsOnRekey",sshd_GSSAPIStoreCredentialsOnRekey) -}}
@ -171,6 +173,8 @@ Match {{ match["Condition"] }}
{{ body_option("KerberosOrLocalPasswd",sshd_KerberosOrLocalPasswd) -}}
{{ body_option("KerberosTicketCleanup",sshd_KerberosTicketCleanup) -}}
{{ body_option("KerberosUniqueTicket",sshd_KerberosUniqueTicket) -}}
{{ body_option("KerberosUniqueCCache",sshd_KerberosUniqueCCache) -}}
{{ body_option("KerberosUseKuserok",sshd_KerberosUseKuserok) -}}
{{ body_option("KexAlgorithms",sshd_KexAlgorithms) -}}
{{ body_option("KeyRegenerationInterval",sshd_KeyRegenerationInterval) -}}
{{ body_option("LogLevel",sshd_LogLevel) -}}
@ -210,6 +214,7 @@ Match {{ match["Condition"] }}
{{ body_option("SecurityKeyProvider",sshd_SecurityKeyProvider) -}}
{{ body_option("SetEnv",sshd_SetEnv) -}}
{{ body_option("ServerKeyBits",sshd_ServerKeyBits) -}}
{{ body_option("ShowPatchLevel",sshd_ShowPatchLevel) -}}
{{ body_option("StreamLocalBindMask",sshd_StreamLocalBindMask) -}}
{{ body_option("StreamLocalBindUnlink",sshd_StreamLocalBindUnlink) -}}
{{ body_option("StrictModes",sshd_StrictModes) -}}

105
tests/tests_all_options.yml Normal file
View file

@ -0,0 +1,105 @@
---
- name: Test we can handle all configuration options documented in manual page
hosts: all
gather_facts: true
vars:
__sshd_test_backup_files:
- /etc/dnf/dnf.conf
- /etc/yum.conf
- /tmp/sshd_config
sshd_c: {}
sshd_skip_test: false
pkg_mgr: "{{ 'dnf' if ansible_facts['distribution_version'] | int > 7 else 'yum' }}"
tasks:
- name: Backup configuration files
ansible.builtin.include_tasks: tasks/backup.yml
- name: Skip test on EL6 as it has some crippled manpages
ansible.builtin.set_fact:
sshd_skip_test: true
when:
- ansible_facts['os_family'] == "RedHat"
- ansible_facts['distribution_version'] | int <= 6
- name: Enable installation of manual pages on Fedora/RHEL
ansible.builtin.lineinfile:
line: tsflags=nodocs
path: "{{ '/etc/dnf/dnf.conf' if ansible_facts['distribution_version'] | int > 7 else '/etc/yum.conf' }}"
state: absent
when:
- ansible_facts['os_family'] == "RedHat"
- name: Reinstall manual pages for openssh-server on RHEL
ansible.builtin.command: "{{ pkg_mgr|quote }} reinstall -y openssh-server"
when:
- ansible_facts['os_family'] == "RedHat"
- name: Unminimize image on Debian. It looks like there is no simpler way to get manual pages
ansible.builtin.shell: yes | unminimize
when:
- ansible_facts['distribution'] == "Ubuntu"
- name: Make sure manual pages and bash are installed
ansible.builtin.package:
name:
- man
- bash
state: present
- name: Get list of options from manual page
ansible.builtin.shell: >-
man sshd_config |cat
- name: Get list of options from manual page
ansible.builtin.shell: >-
set -o pipefail && man sshd_config \
| 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$"
args:
executable: /bin/bash
register: sshd_options
changed_when: false
when: not sshd_skip_test
- name: Print all the possible options
ansible.builtin.debug:
var: ssh_options.stdout_lines
- name: Construct the configuration list
ansible.builtin.set_fact:
sshd_c: "{{ sshd_c | combine({item: 'yes'}) }}"
loop:
"{{ sshd_options.stdout_lines }}"
when: not sshd_skip_test
- name: Run role
ansible.builtin.include_role:
name: ansible-sshd
vars:
# The configuration is not valid as we are using bogus values
__sshd_supports_validate: false
# The hostkeys are not valid either so do not validate them
sshd_verify_hostkeys: []
sshd_config_file: /tmp/sshd_config
sshd:
"{{ sshd_c }}"
when: not sshd_skip_test
- name: Download the configuration file
ansible.builtin.slurp:
src: /tmp/sshd_config
register: config
when: not sshd_skip_test
- name: Verify the options are in the file
ansible.builtin.assert:
that:
- "'{{ item }} yes' in config.content | b64decode "
loop:
"{{ sshd_options.stdout_lines }}"
when: not sshd_skip_test
- name: Restore configuration files
ansible.builtin.include_tasks: tasks/restore.yml

View file

@ -31,6 +31,9 @@ __sshd_os_supported: no
__sshd_sysconfig_supports_crypto_policy: false
__sshd_sysconfig_supports_use_strong_rng: false
# The runtime directory is used by systemd to provide termoporary directory for the service
# This is used as a RuntimeDirectory= option in the service file and it needs to exist
# before running sshd for example in the validate mode.
__sshd_runtime_directory: ~
__sshd_runtime_directory_mode: "0755"
@ -44,3 +47,7 @@ __sshd_drop_in_dir_mode: '0755'
# This is usually the case when the selection is up to the OpenSSH defaults or
# drop-in directory is used.
__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