From 8d7aaa476329ba27de070d3b1966874a4e8a3f13 Mon Sep 17 00:00:00 2001 From: cleberb Date: Thu, 28 Sep 2023 16:13:39 -0300 Subject: [PATCH 01/12] SSHD Improvements - Add options: - sshd_deny_groups - sshd_deny_users - sshd_host_keys_files - sshd_host_keys_group - sshd_host_keys_mode - sshd_host_keys_owner - sshd_listen - sshd_match_addresses - sshd_match_groups - sshd_match_local_ports - sshd_match_users - sshd_print_pam_motd - sshd_sftp_enabled - sshd_sftp_only_chroot - sshd_sftp_only_chroot_dir - sshd_sftp_only_group - sshd_sftp_subsystem - sshd_syslog_facility - sshd_use_privilege_separation - Change options: - String to boolean: - sshd_allow_agent_forwarding - sshd_challenge_response_authentication - sshd_compression - sshd_gssapi_authentication - sshd_hostbased_authentication - sshd_ignore_rhosts - sshd_ignore_user_known_hosts - sshd_kerberos_authentication - sshd_password_authentication - sshd_permit_empty_passwords - sshd_permit_root_login - sshd_permit_user_environment - sshd_print_last_log - sshd_print_motd - sshd_strict_modes - sshd_tcp_keep_alive - sshd_use_dns - sshd_use_pam - sshd_x11_forwarding - String to list: - sshd_allow_groups - sshd_allow_users - sshd_ca_signature_algorithms - sshd_ciphers - sshd_host_key_algorithms - sshd_kex_algorithms - sshd_macs - sshd_ports --- README.md | 258 +++++++++++++++++++++---------- defaults/main/sshd.yml | 146 ++++++++++------- molecule/default/verify.yml | 1 + tasks/sshconfig.yml | 102 +++++++++++- templates/etc/ssh/ssh_config.j2 | 19 ++- templates/etc/ssh/sshd_config.j2 | 221 +++++++++++++++++++++----- 6 files changed, 556 insertions(+), 191 deletions(-) diff --git a/README.md b/README.md index 5af0d39e..32bcc3c5 100644 --- a/README.md +++ b/README.md @@ -457,75 +457,101 @@ sshd_accept_env: LANG LC_* sshd_admin_net: - 192.168.0.0/24 - 192.168.1.0/24 -sshd_allow_agent_forwarding: "no" -sshd_allow_groups: sudo -sshd_allow_users: "{{ ansible_user | default(lookup('ansible.builtin.env', 'USER')) }}" -sshd_allow_tcp_forwarding: "no" +sshd_allow_agent_forwarding: false +sshd_allow_groups: + - sudo +sshd_allow_tcp_forwarding: false +sshd_allow_users: + - {{ ansible_user | default(lookup('ansible.builtin.env', 'USER')) }} sshd_authentication_methods: any sshd_banner: /etc/issue.net -sshd_ca_signature_algorithms: >- - ecdsa-sha2-nistp256, - ecdsa-sha2-nistp384, - ecdsa-sha2-nistp521, - ssh-ed25519, - rsa-sha2-256, - rsa-sha2-512, - ssh-rsa -sshd_challenge_response_authentication: "no" -sshd_ciphers: >- - chacha20-poly1305@openssh.com, - aes256-gcm@openssh.com, - aes256-ctr +sshd_ca_signature_algorithms: + - ecdsa-sha2-nistp256 + - ecdsa-sha2-nistp384 + - ecdsa-sha2-nistp521 + - ssh-ed25519 + - rsa-sha2-256 + - rsa-sha2-512 + - ssh-rsa +sshd_challenge_response_authentication: false +sshd_ciphers: + - chacha20-poly1305@openssh.com + - aes256-gcm@openssh.com + - aes256-ctr sshd_client_alive_count_max: 1 sshd_client_alive_interval: 200 -sshd_compression: "no" -sshd_gssapi_authentication: "no" -sshd_hostbased_authentication: "no" -sshd_host_key_algorithms: >- - ssh-ed25519-cert-v01@openssh.com, - ssh-rsa-cert-v01@openssh.com, - ssh-ed25519, - ssh-rsa, - ecdsa-sha2-nistp521-cert-v01@openssh.com, - ecdsa-sha2-nistp384-cert-v01@openssh.com, - ecdsa-sha2-nistp256-cert-v01@openssh.com, - ecdsa-sha2-nistp521, - ecdsa-sha2-nistp384, - ecdsa-sha2-nistp256 -sshd_ignore_rhosts: "yes" -sshd_ignore_user_known_hosts: "yes" -sshd_kerberos_authentication: "no" -sshd_kex_algorithms: >- - curve25519-sha256@libssh.org, - ecdh-sha2-nistp521, - ecdh-sha2-nistp384, - ecdh-sha2-nistp256, - diffie-hellman-group-exchange-sha256 -sshd_login_grace_time: 20 +sshd_compression: false +sshd_config_d_force_clear: false +sshd_config_force_replace: false +sshd_debian_banner: false +sshd_deny_groups: [] +sshd_deny_users: [] +sshd_gssapi_authentication: false +sshd_host_key_algorithms: + - ssh-ed25519-cert-v01@openssh.com + - ssh-rsa-cert-v01@openssh.com + - ssh-ed25519 + - ssh-rsa + - ecdsa-sha2-nistp521-cert-v01@openssh.com + - ecdsa-sha2-nistp384-cert-v01@openssh.com + - ecdsa-sha2-nistp256-cert-v01@openssh.com + - ecdsa-sha2-nistp521 + - ecdsa-sha2-nistp384 + - ecdsa-sha2-nistp256 +sshd_host_keys_files: [] +sshd_host_keys_group: root +sshd_host_keys_mode: 0600 +sshd_host_keys_owner: root +sshd_hostbased_authentication: false +sshd_ignore_rhosts: true +sshd_ignore_user_known_hosts: true +sshd_kerberos_authentication: false +sshd_kex_algorithms: + - curve25519-sha256@libssh.org + - ecdh-sha2-nistp521 + - ecdh-sha2-nistp384 + - ecdh-sha2-nistp256 + - diffie-hellman-group-exchange-sha256 +sshd_listen: + - 0.0.0.0 sshd_log_level: VERBOSE -sshd_macs: >- - hmac-sha2-512-etm@openssh.com, - hmac-sha2-256-etm@openssh.com, - hmac-sha2-512, - hmac-sha2-256 +sshd_login_grace_time: 20 +sshd_macs: + - hmac-sha2-512-etm@openssh.com + - hmac-sha2-256-etm@openssh.com + - hmac-sha2-512 + - hmac-sha2-256 +sshd_match_addresses: {} +sshd_match_groups: {} +sshd_match_local_ports: {} +sshd_match_users: {} sshd_max_auth_tries: 3 sshd_max_sessions: 3 -sshd_max_startups: 10:30:60 -sshd_password_authentication: "no" -sshd_permit_empty_passwords: "no" -sshd_permit_root_login: "no" -sshd_permit_user_environment: "no" -sshd_port: 22 -sshd_print_last_log: "yes" -sshd_print_motd: "no" +sshd_max_startups: '10:30:60' +sshd_password_authentication: false +sshd_permit_empty_passwords: false +sshd_permit_root_login: false +sshd_permit_tunnel: false +sshd_permit_user_environment: false +sshd_ports: + - 22 +sshd_print_last_log: true +sshd_print_motd: false +sshd_print_pam_motd: false sshd_rekey_limit: 512M 1h sshd_required_rsa_size: 2048 -sshd_strict_modes: "yes" -sshd_subsystem: sftp internal-sftp -sshd_tcp_keep_alive: "no" -sshd_use_dns: "no" -sshd_use_pam: "yes" -sshd_x11_forwarding: "no" +sshd_sftp_enabled: true +sshd_sftp_only_chroot: true +sshd_sftp_only_chroot_dir: '%h' +sshd_sftp_only_group: '' +sshd_sftp_subsystem: internal-sftp -f LOCAL6 -l INFO -u 0027 +sshd_strict_modes: true +sshd_syslog_facility: AUTH +sshd_tcp_keep_alive: false +sshd_use_dns: false +sshd_use_pam: true +sshd_use_privilege_separation: sandbox +sshd_x11_forwarding: false ``` > **Note** @@ -537,39 +563,109 @@ sshd_x11_forwarding: "no" For a explanation of the options not described below, please read [https://man.openbsd.org/sshd_config](https://man.openbsd.org/sshd_config). -Only the network(s) defined in `sshd_admin_net` are allowed to -connect to `sshd_port`. Note that additional rules need to be set up in order -to allow access to additional services. +Only the network(s) defined in `sshd_admin_net` are allowed to connect to `sshd_port`. Note that additional rules need to be set up in order to allow access to additional services. -OpenSSH login is allowed only for users whose primary group or supplementary -group list matches one of the patterns in `sshd_allow_groups`. -OpenSSH login is also allowed for users in `sshd_allow_users`. +OpenSSH login is allowed only for users whose primary group or supplementary group list matches one of the patterns in `sshd_allow_groups`. OpenSSH login is also allowed for users in `sshd_allow_users`. To do the opposite and deny access, use the `sshd_deny_groups` and `sshd_deny_users` parameters, which in turn have priority over the previous parameters. -`sshd_allow_agent_forwarding` specifies whether ssh-agent(1) forwarding is -permitted. +`sshd_allow_agent_forwarding` specifies whether ssh-agent(1) forwarding is permitted. -`sshd_allow_tcp_forwarding` specifies whether TCP forwarding is permitted. -The available options are `yes` or all to allow TCP forwarding, `no` to prevent -all TCP forwarding, `local` to allow local (from the perspective of ssh(1)) -forwarding only or `remote` to allow remote forwarding only. +`sshd_allow_tcp_forwarding` specifies whether TCP forwarding is permitted. The available options are `true|yes` or all to allow TCP forwarding, `false|no` to prevent all TCP forwarding, `local` to allow local (from the perspective of ssh(1)) forwarding only or `remote` to allow remote forwarding only. -`sshd_authentication_methods` specifies the authentication methods that must -be successfully completed in order to grant access to a user. +`sshd_authentication_methods` specifies the authentication methods that must be successfully completed in order to grant access to a user. `sshd_log_level` gives the verbosity level that is used when logging messages. -`sshd_max_auth_tries` and `sshd_max_sessions` specifies the maximum number of -SSH authentication attempts permitted per connection and the maximum number of -open shell, login or subsystem (e.g. sftp) sessions permitted per network +`sshd_max_auth_tries` and `sshd_max_sessions` specifies the maximum number of SSH authentication attempts permitted per connection and the maximum number of open shell, login or subsystem (e.g. sftp) sessions permitted per network connection. -`sshd_password_authentication` specifies whether password authentication is -allowed. +`sshd_password_authentication` specifies whether password authentication is allowed. `sshd_port` specifies the port number that sshd(8) listens on. -`sshd_required_rsa_size`, RequiredRSASize, will only be set if SSH version is -higher than 9.1. +`sshd_required_rsa_size`, RequiredRSASize, will only be set if SSH version is higher than 9.1. + +`sshd_config_d_force_clear` force clear directory `/etc/sshd_config.d`. Default: `false`. + +`sshd_config_force_replace` force replace configuration file `/etc/sshd_config`. Default: `false`. + +> **Note** +> +> By default, the role checks whether the directory `/etc/sshd_config.d` exists and whether it is linked via the `Include` parameter in the `/etc/sshd_config` file, if so, an additional configuration file is created in `/ etc/sshd_config.d`, if not, the `/etc/sshd_config` file is overwritten. + +> **Warning** +> +> If any `sshd_match_(users|groups|addresses|local_ports)` parameters is set, the value `true` will be implicit. + +`sshd_host_keys_files` host keys for sshd. If empty `['/etc/ssh/ssh_host_rsa_key', '/etc/ssh/ssh_host_ecdsa_key', '/etc/ssh/ssh_host_ed25519_key']` will be used, as far as supported by the installed sshd version. + +`sshd_host_keys_owner` set owner of host keys for sshd. Default: `root`. +`sshd_host_keys_group` set group of host keys for sshd. Default: `root`. +`sshd_host_keys_mode` set permission of host keys for sshd. Default: `"0600"`. + +`sshd_match_users` add a conditional block for users. If all of the criteria on the Match line are satisfied, the rules/parameters defined on the following lines override those set in the global section of the config file, until either another Match line or the end of the file. + +Expected configuration structure: +```yaml +sshd_match_users: + - user: + rules: + - + - +``` +Example, allow `ubuntu` user access through password authentication and allow `ansible` user access without banner: +```yaml +sshd_match_users: + - user: ubuntu + rules: + - AllowUsers ubuntu + - AuthenticationMethods password + - PasswordAuthentication yes + - user: ansible + rules: + - AllowUsers ansible + - Banner none +``` +`sshd_match_groups` add a conditional block for groups. More details and examples in the parameter description `sshd_match_users`. + +Expected configuration structure: +```yaml +sshd_match_groups: + - group: + rules: + - + - +``` + +`sshd_match_addresses` add a conditional block for adddresses. More details and examples in the parameter description `sshd_match_users`. + +Expected configuration structure: +```yaml +sshd_match_addresses: + - address: + rules: + - + - +``` +`sshd_match_local_ports` add a conditional block for ports. More details and examples in the parameter description `sshd_match_users`. + +Expected configuration structure: +```yaml +sshd_match_ports: + - port: + rules: + - + - +``` + +`sshd_print_pam_motd` specifies whether printing of the MOTD via pam (Debian and Ubuntu). Default: `false`. + +`sshd_sftp_enabled` specifies whether enabled sftp configuration. Default: `true`. +`sshd_sftp_subsystem` Set external subsystem for file transfer daemon. Default: `internal-sftp -f LOCAL6 -l INFO -u 0027`. +`sshd_sftp_only_group` specifies the name of the group that will have access restricted to the sftp service only. Default: `""`. +`sshd_sftp_only_chroot` specifies group access will be via chroot isolation. Default: `true`. +`sshd_sftp_only_chroot_dir` specifies the chroot directory. Accepts the tokens `%%` (a literal `%`), `%h` (home directory of the user), and `%u` (username). Default: `"%h"`. + +`sshd_syslog_facility` set the facility code that is used when logging messages from sshd.Default: `AUTH`. ### ./defaults/main/suid_sgid_blocklist.yml diff --git a/defaults/main/sshd.yml b/defaults/main/sshd.yml index 3456d0d4..692977ae 100644 --- a/defaults/main/sshd.yml +++ b/defaults/main/sshd.yml @@ -3,72 +3,98 @@ sshd_accept_env: LANG LC_* sshd_admin_net: - 192.168.0.0/24 - 192.168.1.0/24 -sshd_allow_agent_forwarding: "no" -sshd_allow_groups: sudo -sshd_allow_users: "{{ ansible_user | default(lookup('ansible.builtin.env', 'USER')) }}" -sshd_allow_tcp_forwarding: "no" +sshd_allow_agent_forwarding: false +sshd_allow_groups: + - sudo +sshd_allow_tcp_forwarding: false +sshd_allow_users: + - "{{ ansible_user | default(lookup('ansible.builtin.env', 'USER')) }}" sshd_authentication_methods: any sshd_banner: /etc/issue.net -sshd_ca_signature_algorithms: >- - ecdsa-sha2-nistp256, - ecdsa-sha2-nistp384, - ecdsa-sha2-nistp521, - ssh-ed25519, - rsa-sha2-256, - rsa-sha2-512, - ssh-rsa -sshd_challenge_response_authentication: "no" -sshd_ciphers: >- - chacha20-poly1305@openssh.com, - aes256-gcm@openssh.com, - aes256-ctr +sshd_ca_signature_algorithms: + - ecdsa-sha2-nistp256 + - ecdsa-sha2-nistp384 + - ecdsa-sha2-nistp521 + - ssh-ed25519 + - rsa-sha2-256 + - rsa-sha2-512 + - ssh-rsa +sshd_challenge_response_authentication: false +sshd_ciphers: + - chacha20-poly1305@openssh.com + - aes256-gcm@openssh.com + - aes256-ctr sshd_client_alive_count_max: 1 sshd_client_alive_interval: 200 -sshd_compression: "no" -sshd_gssapi_authentication: "no" -sshd_hostbased_authentication: "no" -sshd_host_key_algorithms: >- - ssh-ed25519-cert-v01@openssh.com, - ssh-rsa-cert-v01@openssh.com, - ssh-ed25519, - ssh-rsa, - ecdsa-sha2-nistp521-cert-v01@openssh.com, - ecdsa-sha2-nistp384-cert-v01@openssh.com, - ecdsa-sha2-nistp256-cert-v01@openssh.com, - ecdsa-sha2-nistp521, - ecdsa-sha2-nistp384, - ecdsa-sha2-nistp256 -sshd_ignore_rhosts: "yes" -sshd_ignore_user_known_hosts: "yes" -sshd_kerberos_authentication: "no" -sshd_kex_algorithms: >- - curve25519-sha256@libssh.org, - ecdh-sha2-nistp521, - ecdh-sha2-nistp384, - ecdh-sha2-nistp256, - diffie-hellman-group-exchange-sha256 -sshd_login_grace_time: 20 +sshd_compression: false +sshd_config_d_force_clear: false +sshd_config_force_replace: false +sshd_debian_banner: false +sshd_deny_groups: [] +sshd_deny_users: [] +sshd_gssapi_authentication: false +sshd_host_key_algorithms: + - ssh-ed25519-cert-v01@openssh.com + - ssh-rsa-cert-v01@openssh.com + - ssh-ed25519 + - ssh-rsa + - ecdsa-sha2-nistp521-cert-v01@openssh.com + - ecdsa-sha2-nistp384-cert-v01@openssh.com + - ecdsa-sha2-nistp256-cert-v01@openssh.com + - ecdsa-sha2-nistp521 + - ecdsa-sha2-nistp384 + - ecdsa-sha2-nistp256 +sshd_host_keys_files: [] +sshd_host_keys_group: root +sshd_host_keys_mode: 0600 +sshd_host_keys_owner: root +sshd_hostbased_authentication: false +sshd_ignore_rhosts: true +sshd_ignore_user_known_hosts: true +sshd_kerberos_authentication: false +sshd_kex_algorithms: + - curve25519-sha256@libssh.org + - ecdh-sha2-nistp521 + - ecdh-sha2-nistp384 + - ecdh-sha2-nistp256 + - diffie-hellman-group-exchange-sha256 +sshd_listen: + - 0.0.0.0 sshd_log_level: VERBOSE -sshd_macs: >- - hmac-sha2-512-etm@openssh.com, - hmac-sha2-256-etm@openssh.com, - hmac-sha2-512, - hmac-sha2-256 +sshd_login_grace_time: 20 +sshd_macs: + - hmac-sha2-512-etm@openssh.com + - hmac-sha2-256-etm@openssh.com + - hmac-sha2-512 + - hmac-sha2-256 +sshd_match_addresses: {} +sshd_match_groups: {} +sshd_match_local_ports: {} +sshd_match_users: {} sshd_max_auth_tries: 3 sshd_max_sessions: 3 -sshd_max_startups: 10:30:60 -sshd_password_authentication: "no" -sshd_permit_empty_passwords: "no" -sshd_permit_root_login: "no" -sshd_permit_user_environment: "no" -sshd_port: 22 -sshd_print_last_log: "yes" -sshd_print_motd: "no" +sshd_max_startups: '10:30:60' +sshd_password_authentication: false +sshd_permit_empty_passwords: false +sshd_permit_root_login: false +sshd_permit_tunnel: false +sshd_permit_user_environment: false +sshd_ports: + - 22 +sshd_print_last_log: true +sshd_print_motd: false +sshd_print_pam_motd: false sshd_rekey_limit: 512M 1h sshd_required_rsa_size: 2048 -sshd_strict_modes: "yes" -sshd_subsystem: sftp internal-sftp -sshd_tcp_keep_alive: "no" -sshd_use_dns: "no" -sshd_use_pam: "yes" -sshd_x11_forwarding: "no" +sshd_sftp_enabled: true +sshd_sftp_only_chroot: true +sshd_sftp_only_chroot_dir: '%h' +sshd_sftp_only_group: '' +sshd_sftp_subsystem: internal-sftp -f LOCAL6 -l INFO -u 0027 +sshd_strict_modes: true +sshd_syslog_facility: AUTH +sshd_tcp_keep_alive: false +sshd_use_dns: false +sshd_use_pam: true +sshd_use_privilege_separation: sandbox +sshd_x11_forwarding: false diff --git a/molecule/default/verify.yml b/molecule/default/verify.yml index 6c4fa95a..11b14a1b 100644 --- a/molecule/default/verify.yml +++ b/molecule/default/verify.yml @@ -62,6 +62,7 @@ cmd: ssh -V changed_when: false failed_when: false + check_mode: false register: ssh_version tags: - sshd diff --git a/tasks/sshconfig.yml b/tasks/sshconfig.yml index 16b58190..7eef8ebe 100644 --- a/tasks/sshconfig.yml +++ b/tasks/sshconfig.yml @@ -4,6 +4,7 @@ cmd: ssh -V changed_when: false failed_when: false + check_mode: false register: ssh_version tags: - sshd @@ -43,6 +44,7 @@ register: grep_include changed_when: false failed_when: false + check_mode: false tags: - sshd - sshd_config @@ -57,6 +59,28 @@ - sshd_config - M1041 +- name: Clear pre-existing custom configurations in /etc/ssh/sshd_config.d + when: + - sshd_config_d_force_clear | bool + - sshd_config_d.stat.exists + tags: + - sshd + - sshd_config + block: + - name: Search pre-existing custom configurations in /etc/ssh/sshd_config.d + become: true + find: + path: /etc/ssh/sshd_config.d + patterns: '*' + register: sshd_config_d_content + + - name: Clear pre-existing custom configurations in /etc/ssh/sshd_config.d + become: true + file: + path: "{{ item.path }}" + state: absent + loop: "{{ sshd_config_d_content.files }}" + - name: Ensure /etc/ssh/sshd_config permissions become: true ansible.builtin.file: @@ -68,6 +92,76 @@ - sshd - sshd_config +- name: Set default for sshd_host_keys_files if not supplied + when: not sshd_host_keys_files + tags: + - sshd + block: + - name: Replace default 2048 bits RSA keypair + community.crypto.openssh_keypair: + state: present + type: rsa + size: "{{ sshd_required_rsa_size }}" + path: "/etc/ssh/ssh_host_rsa_key" + force: false + regenerate: partial_idempotence + + - name: Set hostkeys according to openssh-version if openssh >= 5.3 + ansible.builtin.set_fact: + sshd_host_keys_files: + - "/etc/ssh/ssh_host_rsa_key" + when: + - ssh_installed_version is version('5.3', '>=') + - ssh_installed_version is version('6.0', '<') + + - name: Set hostkeys according to openssh-version if openssh >= 6.0 + ansible.builtin.set_fact: + sshd_host_keys_files: + - "/etc/ssh/ssh_host_rsa_key" + - "/etc/ssh/ssh_host_ecdsa_key" + when: + - ssh_installed_version is version('6.0', '>=') + - ssh_installed_version is version('6.3', '<') + + - name: Set hostkeys according to openssh-version if openssh >= 6.3 + ansible.builtin.set_fact: + sshd_host_keys_files: + - "/etc/ssh/ssh_host_rsa_key" + - "/etc/ssh/ssh_host_ecdsa_key" + - "/etc/ssh/ssh_host_ed25519_key" + when: ssh_installed_version is version('6.3', '>=') + + - name: Change host private key ownership, group and permissions + ansible.builtin.file: + path: "{{ item }}" + owner: "{{ sshd_host_keys_owner }}" + group: "{{ sshd_host_keys_group }}" + mode: "{{ sshd_host_keys_mode }}" + loop: "{{ sshd_host_keys_files }}" + +- name: Disable PAM dynamic MOTD + community.general.pamd: + name: sshd + type: session + control: optional + module_path: pam_motd.so + state: absent + backup: true + when: + - sshd_use_pam | bool + - not (sshd_print_pam_motd | bool) + tags: + - sshd + +- name: Check variable sshd_config_force_replace + ansible.builtin.set_fact: + sshd_config_force_replace: true + when: >- + sshd_match_users | length > 0 or + sshd_match_groups | length > 0 or + sshd_match_addresses | length > 0 or + sshd_match_local_ports | length > 0 + - name: Configure sshd become: true ansible.builtin.template: @@ -77,8 +171,8 @@ mode: "0600" owner: root group: root - validate: sshd -t -f %s - when: not sshd_config_d.stat.exists or grep_include.rc != 0 + validate: "/usr/sbin/sshd -T -C user=root -C host=localhost -C addr=localhost -C lport=22 -f %s" + when: sshd_config_force_replace | bool or not sshd_config_d.stat.exists or grep_include.rc != 0 notify: - Restart sshd service - Restart ssh service @@ -131,8 +225,8 @@ mode: "0600" owner: root group: root - validate: sshd -t -f %s - when: sshd_config_d.stat.exists and grep_include.rc == 0 + validate: "/usr/sbin/sshd -T -C user=root -C host=localhost -C addr=localhost -C lport=22 -f %s" + when: not ( sshd_config_force_replace | bool ) or sshd_config_d.stat.exists and grep_include.rc == 0 notify: - Restart sshd service - Restart ssh service diff --git a/templates/etc/ssh/ssh_config.j2 b/templates/etc/ssh/ssh_config.j2 index e495bdc8..07b59016 100644 --- a/templates/etc/ssh/ssh_config.j2 +++ b/templates/etc/ssh/ssh_config.j2 @@ -1,15 +1,20 @@ +#jinja2: trim_blocks: "true", lstrip_blocks: "true" # {{ ansible_managed }} +# Generated by Ansible role {{ ansible_role_name }} + +# OpenSSH SSH client configuration files +# See ssh_config(5) for more information + {% if ssh_config_d.stat.exists and ssh_config_d.stat.isdir %} Include /etc/ssh/ssh_config.d/*.conf -{% endif %} - +{%+ endif +%} Host * {% if not crypto_policies_config or not set_crypto_policy %} - Ciphers {{ sshd_ciphers | replace(', ', ',') }} - HostKeyAlgorithms {{ sshd_host_key_algorithms | replace(', ', ',') }} - KexAlgorithms {{ sshd_kex_algorithms | replace(', ', ',') }} - MACs {{ sshd_macs | replace(', ', ',') }} + {{ 'Ciphers ' ~ sshd_ciphers|join(',') if sshd_ciphers }} + {{ 'HostKeyAlgorithms ' ~ sshd_host_key_algorithms|join(',') if sshd_host_key_algorithms }} + {{ 'KexAlgorithms ' ~ sshd_kex_algorithms|join(',') if sshd_kex_algorithms }} + {{ 'MACs ' ~ sshd_macs|join(',') if sshd_macs }} {% endif %} - GSSAPIAuthentication {{ sshd_gssapi_authentication }} + GSSAPIAuthentication {{ 'yes' if (sshd_gssapi_authentication|bool) else 'no' }} HashKnownHosts yes RekeyLimit {{ sshd_rekey_limit }} diff --git a/templates/etc/ssh/sshd_config.j2 b/templates/etc/ssh/sshd_config.j2 index 8ac198d2..afceb3f0 100644 --- a/templates/etc/ssh/sshd_config.j2 +++ b/templates/etc/ssh/sshd_config.j2 @@ -1,50 +1,193 @@ +#jinja2: trim_blocks: "true", lstrip_blocks: "true" # {{ ansible_managed }} +# Generated by Ansible role {{ ansible_role_name }} + +# OpenSSH SSH daemon configuration file +# See sshd_config(5) for more information + +####################################################### +# Basic configuration +####################################################### + +{% for port in sshd_ports %} +Port {{ port }} +{% endfor %} +AddressFamily {{ 'inet' if (disable_ipv6|bool) else 'any' }} +{% for address in sshd_listen %} +ListenAddress {{ address }} +{% endfor %} +{% for key in sshd_host_keys_files %} +HostKey {{ key }} +{% endfor %} + +####################################################### +# Security configuration +####################################################### + +{% if ssh_installed_version is version('7.6', '<') %} +Protocol 2 +{% endif %} +StrictModes {{ 'yes' if (sshd_strict_modes|bool) else 'no' }} +SyslogFacility {{ sshd_syslog_facility }} +LogLevel {{ sshd_log_level }} + +####################################################### +# Cryptography +####################################################### + {% if not crypto_policies_config or not set_crypto_policy %} +{{ 'CASignatureAlgorithms ' ~ sshd_ca_signature_algorithms|join(',') if sshd_ca_signature_algorithms }} +{{ 'Ciphers ' ~ sshd_ciphers|join(',') if sshd_ciphers }} +{{ 'HostKeyAlgorithms ' ~ sshd_host_key_algorithms|join(',') if sshd_host_key_algorithms }} +{{ 'KexAlgorithms ' ~ sshd_kex_algorithms|join(',') if sshd_kex_algorithms }} +{{ 'MACs ' ~ sshd_macs|join(',') if sshd_macs }} +{% endif %} +RekeyLimit {{ sshd_rekey_limit }} +{% if ssh_installed_version is version('9.1', '>') and (not crypto_policies_config or not set_crypto_policy) %} +RequiredRSASize {{ sshd_required_rsa_size }} +{% endif %} -CASignatureAlgorithms {{ sshd_ca_signature_algorithms | replace(', ', ',') }} -Ciphers {{ sshd_ciphers | replace(', ', ',') }} -HostKeyAlgorithms {{ sshd_host_key_algorithms | replace(', ', ',') }} -KexAlgorithms {{ sshd_kex_algorithms | replace(', ', ',') }} -MACs {{ sshd_macs | replace(', ', ',') }} +####################################################### +# Authentication +####################################################### +PermitRootLogin {{ 'yes' if (sshd_permit_root_login|bool) else 'no' }} +{% if ssh_installed_version is version('7.4', '<') %} +UseLogin no {% endif %} -AcceptEnv {{ sshd_accept_env }} -AllowAgentForwarding {{ sshd_allow_agent_forwarding }} -AllowGroups {{ sshd_allow_groups }} -{% if sshd_allow_users is defined and sshd_allow_users %} -AllowUsers {{ sshd_allow_users }} +{% if ssh_installed_version is version('7.5', '<') %} +UsePrivilegeSeparation {{ sshd_use_privilege_separation if (sshd_use_privilege_separation in ('yes', 'no', 'sandbox')) else ('yes' if (sshd_use_privilege_separation|bool) else 'no') }} {% endif %} -AllowTcpForwarding {{ sshd_allow_tcp_forwarding }} -AuthenticationMethods {{ sshd_authentication_methods }} -Banner {{ sshd_banner }} -ChallengeResponseAuthentication {{ sshd_challenge_response_authentication }} -ClientAliveCountMax {{ sshd_client_alive_count_max | int }} -ClientAliveInterval {{ sshd_client_alive_interval | int }} -Compression {{ sshd_compression }} -GSSAPIAuthentication {{ sshd_gssapi_authentication }} -HostbasedAuthentication {{ sshd_hostbased_authentication }} -IgnoreRhosts {{ sshd_ignore_rhosts }} -IgnoreUserKnownHosts {{ sshd_ignore_user_known_hosts }} -KerberosAuthentication {{ sshd_kerberos_authentication }} -LogLevel {{ sshd_log_level }} LoginGraceTime {{ sshd_login_grace_time | int }} MaxAuthTries {{ sshd_max_auth_tries | int }} MaxSessions {{ sshd_max_sessions | int }} MaxStartups {{ sshd_max_startups }} -PasswordAuthentication {{ sshd_password_authentication }} -PermitEmptyPasswords {{ sshd_permit_empty_passwords }} -PermitRootLogin {{ sshd_permit_root_login }} -PermitUserEnvironment {{ sshd_permit_user_environment }} -Port {{ sshd_port|int }} -PrintLastLog {{ sshd_print_last_log }} -PrintMotd {{ sshd_print_motd }} -RekeyLimit {{ sshd_rekey_limit }} -{% if ssh_installed_version is version('9.1', '>') and (not crypto_policies_config or not set_crypto_policy) %} -RequiredRSASize {{ sshd_required_rsa_size }} +PubkeyAuthentication yes +IgnoreRhosts {{ 'yes' if (sshd_ignore_rhosts|bool) else 'no' }} +IgnoreUserKnownHosts {{ 'yes' if (sshd_ignore_user_known_hosts|bool) else 'no' }} +HostbasedAuthentication {{ 'yes' if (sshd_hostbased_authentication|bool) else 'no' }} +UsePAM {{ 'yes' if (sshd_use_pam|bool) else 'no' }} +{% if ssh_installed_version is version('6.2', '>=') %} +AuthenticationMethods {{ sshd_authentication_methods }} +{% endif %} +PasswordAuthentication {{ 'yes' if (sshd_password_authentication|bool) else 'no' }} +PermitEmptyPasswords {{ 'yes' if (sshd_permit_empty_passwords|bool) else 'no' }} +ChallengeResponseAuthentication {{ 'yes' if (sshd_challenge_response_authentication|bool) else 'no' }} +KerberosAuthentication {{ 'yes' if (sshd_kerberos_authentication|bool) else 'no' }} +GSSAPIAuthentication {{ 'yes' if (sshd_gssapi_authentication|bool) else 'no' }} +GSSAPICleanupCredentials yes +{% if sshd_deny_groups %} +{{ 'DenyGroups ' ~ sshd_deny_groups|join(' ') }} +{% endif %} +{% if sshd_allow_groups %} +{{ 'AllowGroups ' ~ sshd_allow_groups|join(' ') }} +{% endif %} +{% if sshd_deny_users %} +{{ 'DenyUsers ' ~ sshd_deny_users|join(' ') }} +{% endif %} +{% if sshd_allow_users %} +{{ 'AllowUsers ' ~ sshd_allow_users|join(' ') }} +{% endif %} + +####################################################### +# Network +####################################################### + +TCPKeepAlive {{ 'yes' if (sshd_tcp_keep_alive|bool) else 'no' }} +ClientAliveCountMax {{ sshd_client_alive_count_max | int }} +ClientAliveInterval {{ sshd_client_alive_interval | int }} +PermitTunnel {{ 'yes' if (sshd_permit_tunnel|bool) else 'no' }} +{% if ssh_installed_version is version('6.2', '>=') %} +AllowTcpForwarding {{ sshd_allow_tcp_forwarding if (sshd_allow_tcp_forwarding in ('yes', 'no', 'local', 'all', 'remote')) else ('yes' if (sshd_allow_tcp_forwarding|bool) else 'no') }} +{% else %} +AllowTcpForwarding {{ sshd_allow_tcp_forwarding if (sshd_allow_tcp_forwarding in ('yes', 'no')) else ('yes' if (sshd_allow_tcp_forwarding|bool) else 'no') }} +{% endif %} +AllowAgentForwarding {{ 'yes' if (sshd_allow_agent_forwarding|bool) else 'no' }} +X11Forwarding {{ 'yes' if (sshd_x11_forwarding|bool) else 'no' }} +X11UseLocalhost yes + +####################################################### +# User environment configuration +####################################################### + +PermitUserEnvironment {{ 'yes' if (sshd_permit_user_environment|bool) else 'no' }} +{% if sshd_accept_env %} +AcceptEnv {{ sshd_accept_env }} +{% endif %} + +####################################################### +# Misc. configuration +####################################################### + +Compression {{ 'yes' if (sshd_compression|bool) else 'no' }} +UseDNS {{ 'yes' if (sshd_use_dns|bool) else 'no' }} +PrintMotd {{ 'yes' if (sshd_print_motd|bool) else 'no' }} +PrintLastLog {{ 'yes' if (sshd_print_last_log|bool) else 'no' }} +Banner {{ sshd_banner if sshd_banner else 'none' }} +{% if ansible_facts.os_family == 'Debian' %} +DebianBanner {{ 'yes' if (sshd_debian_banner|bool) else 'no' }} +{% endif %} + +{%+ if sshd_sftp_enabled +%} +####################################################### +# SFTP matching configuration +####################################################### + +Subsystem sftp {{ sshd_sftp_subsystem }} +{%+ if sshd_sftp_only_group %} +Match Group {{ sshd_sftp_only_group }} + ForceCommand {{ sshd_sftp_subsystem }} +{% if sshd_sftp_chroot %} + ChrootDirectory {{ sshd_sftp_chroot_dir }} +{% endif %} + AllowTcpForwarding no + AllowAgentForwarding no + PasswordAuthentication {{ 'yes' if (sshd_password_authentication|bool) else 'no' }} + PermitRootLogin no + X11Forwarding no {% endif %} -StrictModes {{ sshd_strict_modes }} -Subsystem {{ sshd_subsystem }} -TCPKeepAlive {{ sshd_tcp_keep_alive }} -UseDNS {{ sshd_use_dns }} -UsePAM {{ sshd_use_pam }} -X11Forwarding {{ sshd_x11_forwarding }} +{%+ endif +%} +{% for item in sshd_match_addresses %} +{%+ if loop.first +%} +####################################################### +# Address matching configuration +####################################################### +{%+ endif +%} +Match Address {{ item.address }} + {% for rule in item.rules %} + {{ rule | indent(4) }} + {% endfor %} +{% endfor %} +{% for item in sshd_match_groups %} +{%+ if loop.first +%} +####################################################### +# Group matching configuration +####################################################### +{%+ endif +%} +Match Group {{ item.group }} + {% for rule in item.rules %} + {{ rule | indent(4) }} + {% endfor %} +{% endfor %} +{% for item in sshd_match_users %} +{%+ if loop.first +%} +####################################################### +# User matching configuration +####################################################### +{%+ endif +%} +Match User {{ item.user }} + {% for rule in item.rules %} + {{ rule | indent(4) }} + {% endfor %} +{% endfor %} +{% for item in sshd_match_local_ports %} +{%+ if loop.first +%} +####################################################### +# LocalPort matching configuration +####################################################### +{%+ endif +%} +Match LocalPort {{ item.port }} + {% for rule in item.rules %} + {{ rule | indent(4) }} + {% endfor %} +{% endfor %} From 3ec1495e5dd2fc646b5da6164d5fda7621239e71 Mon Sep 17 00:00:00 2001 From: cleberb Date: Fri, 29 Sep 2023 10:09:16 -0300 Subject: [PATCH 02/12] Fix ansible-lint --- README.md | 2 +- defaults/main/sshd.yml | 2 +- tasks/sshconfig.yml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 32bcc3c5..ac74a925 100644 --- a/README.md +++ b/README.md @@ -500,7 +500,7 @@ sshd_host_key_algorithms: - ecdsa-sha2-nistp256 sshd_host_keys_files: [] sshd_host_keys_group: root -sshd_host_keys_mode: 0600 +sshd_host_keys_mode: "0600" sshd_host_keys_owner: root sshd_hostbased_authentication: false sshd_ignore_rhosts: true diff --git a/defaults/main/sshd.yml b/defaults/main/sshd.yml index 692977ae..6de918bf 100644 --- a/defaults/main/sshd.yml +++ b/defaults/main/sshd.yml @@ -46,7 +46,7 @@ sshd_host_key_algorithms: - ecdsa-sha2-nistp256 sshd_host_keys_files: [] sshd_host_keys_group: root -sshd_host_keys_mode: 0600 +sshd_host_keys_mode: "0600" sshd_host_keys_owner: root sshd_hostbased_authentication: false sshd_ignore_rhosts: true diff --git a/tasks/sshconfig.yml b/tasks/sshconfig.yml index 7eef8ebe..511f0962 100644 --- a/tasks/sshconfig.yml +++ b/tasks/sshconfig.yml @@ -69,14 +69,14 @@ block: - name: Search pre-existing custom configurations in /etc/ssh/sshd_config.d become: true - find: + ansible.builtin.find: path: /etc/ssh/sshd_config.d patterns: '*' register: sshd_config_d_content - name: Clear pre-existing custom configurations in /etc/ssh/sshd_config.d become: true - file: + ansible.builtin.file: path: "{{ item.path }}" state: absent loop: "{{ sshd_config_d_content.files }}" From e8f6389ce14979ba4e27559b2fc7a1b8cfc90f16 Mon Sep 17 00:00:00 2001 From: cleberb Date: Fri, 29 Sep 2023 19:17:23 -0300 Subject: [PATCH 03/12] Fix variable sshd_ports and update molecule (verify.yml) --- README.md | 6 +- genREADME.sh | 2 +- molecule/default/verify.yml | 197 +++++++++++++++++------------------- tasks/ufw.yml | 27 +++-- 4 files changed, 108 insertions(+), 124 deletions(-) diff --git a/README.md b/README.md index ac74a925..40977b49 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ disruption, the role deletes every `ufw` rule without The role also sets default deny policies, which means that firewall rules needs to be created for any additional ports except those specified in -the `sshd_port` and `ufw_outgoing_traffic` variables. +the `sshd_ports` and `ufw_outgoing_traffic` variables. ## Task Execution and Structure @@ -563,7 +563,7 @@ sshd_x11_forwarding: false For a explanation of the options not described below, please read [https://man.openbsd.org/sshd_config](https://man.openbsd.org/sshd_config). -Only the network(s) defined in `sshd_admin_net` are allowed to connect to `sshd_port`. Note that additional rules need to be set up in order to allow access to additional services. +Only the network(s) defined in `sshd_admin_net` are allowed to connect to `sshd_ports`. Note that additional rules need to be set up in order to allow access to additional services. OpenSSH login is allowed only for users whose primary group or supplementary group list matches one of the patterns in `sshd_allow_groups`. OpenSSH login is also allowed for users in `sshd_allow_users`. To do the opposite and deny access, use the `sshd_deny_groups` and `sshd_deny_users` parameters, which in turn have priority over the previous parameters. @@ -580,7 +580,7 @@ connection. `sshd_password_authentication` specifies whether password authentication is allowed. -`sshd_port` specifies the port number that sshd(8) listens on. +`sshd_ports` specifies the port(s) number that sshd(8) listens on. `sshd_required_rsa_size`, RequiredRSASize, will only be set if SSH version is higher than 9.1. diff --git a/genREADME.sh b/genREADME.sh index b018f0c1..b01381d2 100644 --- a/genREADME.sh +++ b/genREADME.sh @@ -103,7 +103,7 @@ disruption, the role deletes every \`ufw\` rule without The role also sets default deny policies, which means that firewall rules needs to be created for any additional ports except those specified in -the \`sshd_port\` and \`ufw_outgoing_traffic\` variables. +the \`sshd_ports\` and \`ufw_outgoing_traffic\` variables. ## Task Execution and Structure diff --git a/molecule/default/verify.yml b/molecule/default/verify.yml index 11b14a1b..248501ad 100644 --- a/molecule/default/verify.yml +++ b/molecule/default/verify.yml @@ -226,47 +226,92 @@ failed_when: sshd_config_d is changed when: sshd_config_directory.stat.exists + - name: Set sshd_config_parameters + ansible.builtin.set_fact: + sshd_config_parameters: + - AddressFamily {{ 'inet' if (disable_ipv6|bool) else 'any' }} + - AllowGroups vagrant sudo + - AllowAgentForwarding {{ 'yes' if (sshd_allow_agent_forwarding|bool) else 'no' }} + - >- + {% if ssh_installed_version is version('6.2', '>=') %} + AllowTcpForwarding {{ sshd_allow_tcp_forwarding if (sshd_allow_tcp_forwarding in ('yes', 'no', 'local', 'all', 'remote')) else ('yes' if (sshd_allow_tcp_forwarding|bool) else 'no') }} + {% else %} + AllowTcpForwarding {{ sshd_allow_tcp_forwarding if (sshd_allow_tcp_forwarding in ('yes', 'no')) else ('yes' if (sshd_allow_tcp_forwarding|bool) else 'no') }} + {% endif %} + - Banner {{ sshd_banner if sshd_banner else 'none' }} + - ChallengeResponseAuthentication {{ 'yes' if (sshd_challenge_response_authentication|bool) else 'no' }} + - ClientAliveCountMax {{ sshd_client_alive_count_max | int }} + - ClientAliveInterval {{ sshd_client_alive_interval | int }} + - Compression {{ 'yes' if (sshd_compression|bool) else 'no' }} + - DebianBanner {{ 'yes' if (sshd_debian_banner|bool) else 'no' }} + - GSSAPIAuthentication {{ 'yes' if (sshd_gssapi_authentication|bool) else 'no' }} + - GSSAPICleanupCredentials yes + - HostbasedAuthentication {{ 'yes' if (sshd_hostbased_authentication|bool) else 'no' }} + - IgnoreRhosts {{ 'yes' if (sshd_ignore_rhosts|bool) else 'no' }} + - IgnoreUserKnownHosts {{ 'yes' if (sshd_ignore_user_known_hosts|bool) else 'no' }} + - KerberosAuthentication {{ 'yes' if (sshd_kerberos_authentication|bool) else 'no' }} + - LogLevel {{ sshd_log_level }} + - LoginGraceTime {{ sshd_login_grace_time | int }} + - MaxAuthTries {{ sshd_max_auth_tries | int }} + - MaxSessions {{ sshd_max_sessions | int }} + - MaxStartups {{ sshd_max_startups }} + - PasswordAuthentication {{ 'yes' if (sshd_password_authentication|bool) else 'no' }} + - PermitEmptyPasswords {{ 'yes' if (sshd_permit_empty_passwords|bool) else 'no' }} + - PermitRootLogin {{ 'yes' if (sshd_permit_root_login|bool) else 'no' }} + - PermitTunnel {{ 'yes' if (sshd_permit_tunnel|bool) else 'no' }} + - PermitUserEnvironment {{ 'yes' if (sshd_permit_user_environment|bool) else 'no' }} + - PrintLastLog {{ 'yes' if (sshd_print_last_log|bool) else 'no' }} + - PrintMotd {{ 'yes' if (sshd_print_motd|bool) else 'no' }} + - PubkeyAuthentication yes + - RekeyLimit {{ sshd_rekey_limit }} + - StrictModes {{ 'yes' if (sshd_strict_modes|bool) else 'no' }} + - SyslogFacility {{ sshd_syslog_facility }} + - TCPKeepAlive {{ 'yes' if (sshd_tcp_keep_alive|bool) else 'no' }} + - UseDNS {{ 'yes' if (sshd_use_dns|bool) else 'no' }} + - UsePAM {{ 'yes' if (sshd_use_pam|bool) else 'no' }} + - X11Forwarding {{ 'yes' if (sshd_x11_forwarding|bool) else 'no' }} + - X11UseLocalhost yes + + - name: Set sshd_config_parameters AuthenticationMethods + ansible.builtin.set_fact: + sshd_config_parameters: "{{ sshd_config_parameters + [ 'AuthenticationMethods ' + sshd_authentication_methods ] }}" + when: ssh_installed_version is version('6.2', '>=') + + - name: Set sshd_config_parameters HostKey + ansible.builtin.set_fact: + sshd_config_parameters: "{{ sshd_config_parameters + [ 'HostKey ' + item ] }}" + loop: "{{ sshd_host_keys_files }}" + + - name: Set sshd_config_parameters ListenAddress + ansible.builtin.set_fact: + sshd_config_parameters: "{{ sshd_config_parameters + [ 'ListenAddress ' + item ] }}" + loop: "{{ sshd_listen }}" + + - name: Set sshd_config_parameters Port + ansible.builtin.set_fact: + sshd_config_parameters: "{{ sshd_config_parameters + [ 'Port ' + item|string ] }}" + loop: "{{ sshd_ports }}" + + - name: Set sshd_config_parameters RequiredRSASize + ansible.builtin.set_fact: + sshd_config_parameters: "{{ sshd_config_parameters + [ 'RequiredRSASize ' + sshd_required_rsa_size ] }}" + when: ssh_installed_version is version('9.1', '>') + + - name: Set sshd_config_parameters Subsystem + ansible.builtin.set_fact: + sshd_config_parameters: "{{ sshd_config_parameters + [ 'Subsystem sftp ' + sshd_sftp_subsystem ] }}" + when: sshd_sftp_enabled | bool + - name: Verify sshd configuration become: true ansible.builtin.lineinfile: dest: /etc/ssh/sshd_config - line: "{{ item | replace(', ', ',') }}" + line: "{{ item }}" state: present check_mode: true register: sshd_config failed_when: sshd_config is changed - with_items: - - AllowGroups vagrant sudo - - AllowAgentForwarding {{ sshd_allow_agent_forwarding }} - - AllowTcpForwarding {{ sshd_allow_tcp_forwarding }} - - AuthenticationMethods {{ sshd_authentication_methods }} - - Banner {{ sshd_banner }} - - ChallengeResponseAuthentication {{ sshd_challenge_response_authentication }} - - ClientAliveCountMax {{ sshd_client_alive_count_max | int }} - - ClientAliveInterval {{ sshd_client_alive_interval | int }} - - Compression {{ sshd_compression }} - - GSSAPIAuthentication {{ sshd_gssapi_authentication }} - - HostbasedAuthentication {{ sshd_hostbased_authentication }} - - IgnoreUserKnownHosts {{ sshd_ignore_user_known_hosts }} - - KerberosAuthentication {{ sshd_kerberos_authentication }} - - LogLevel {{ sshd_log_level }} - - LoginGraceTime {{ sshd_login_grace_time | int }} - - MaxAuthTries {{ sshd_max_auth_tries | int }} - - MaxSessions {{ sshd_max_sessions | int }} - - MaxStartups {{ sshd_max_startups }} - - PasswordAuthentication {{ sshd_password_authentication }} - - PermitEmptyPasswords {{ sshd_permit_empty_passwords }} - - PermitRootLogin {{ sshd_permit_root_login }} - - PermitUserEnvironment {{ sshd_permit_user_environment }} - - Port {{ sshd_port | int }} - - PrintLastLog {{ sshd_print_last_log }} - - PrintMotd {{ sshd_print_motd }} - - RekeyLimit {{ sshd_rekey_limit }} - - StrictModes {{ sshd_strict_modes }} - - TCPKeepAlive {{ sshd_tcp_keep_alive }} - - UseDNS {{ sshd_use_dns }} - - UsePAM {{ sshd_use_pam }} - - X11Forwarding {{ sshd_x11_forwarding }} + loop: "{{ sshd_config_parameters }}" when: not sshd_config_directory.stat.exists - name: Verify sshd config.d configuration @@ -278,39 +323,7 @@ check_mode: true register: sshd_config failed_when: sshd_config is changed - with_items: - - AllowGroups vagrant sudo - - AllowAgentForwarding {{ sshd_allow_agent_forwarding }} - - AllowTcpForwarding {{ sshd_allow_tcp_forwarding }} - - AuthenticationMethods {{ sshd_authentication_methods }} - - Banner {{ sshd_banner }} - - ChallengeResponseAuthentication {{ sshd_challenge_response_authentication }} - - ClientAliveCountMax {{ sshd_client_alive_count_max | int }} - - ClientAliveInterval {{ sshd_client_alive_interval | int }} - - Compression {{ sshd_compression }} - - GSSAPIAuthentication {{ sshd_gssapi_authentication }} - - HostbasedAuthentication {{ sshd_hostbased_authentication }} - - IgnoreUserKnownHosts {{ sshd_ignore_user_known_hosts }} - - KerberosAuthentication {{ sshd_kerberos_authentication }} - - LogLevel {{ sshd_log_level }} - - LoginGraceTime {{ sshd_login_grace_time | int }} - - MaxAuthTries {{ sshd_max_auth_tries | int }} - - MaxSessions {{ sshd_max_sessions | int }} - - MaxStartups {{ sshd_max_startups }} - - PasswordAuthentication {{ sshd_password_authentication }} - - PermitEmptyPasswords {{ sshd_permit_empty_passwords }} - - PermitRootLogin {{ sshd_permit_root_login }} - - PermitUserEnvironment {{ sshd_permit_user_environment }} - - Port {{ sshd_port | int }} - - PrintLastLog {{ sshd_print_last_log }} - - PrintMotd {{ sshd_print_motd }} - - RekeyLimit {{ sshd_rekey_limit }} - - StrictModes {{ sshd_strict_modes }} - - Subsystem {{ sshd_subsystem }} - - TCPKeepAlive {{ sshd_tcp_keep_alive }} - - UseDNS {{ sshd_use_dns }} - - UsePAM {{ sshd_use_pam }} - - X11Forwarding {{ sshd_x11_forwarding }} + loop: "{{ sshd_config_parameters }}" when: sshd_config_directory.stat.exists - name: Verify sshd runtime configuration @@ -320,27 +333,10 @@ ansible.builtin.command: sshd -T register: sshd_config changed_when: false - failed_when: item not in sshd_config.stdout_lines - with_items: - - allowgroups sudo - - allowgroups vagrant - - allowagentforwarding {{ sshd_allow_agent_forwarding }} - - allowtcpforwarding {{ sshd_allow_tcp_forwarding }} - - authenticationmethods {{ sshd_authentication_methods }} - - banner {{ sshd_banner }} - - clientalivecountmax {{ sshd_client_alive_count_max | int }} - - clientaliveinterval {{ sshd_client_alive_interval | int }} - - compression {{ sshd_compression }} - - logingracetime {{ sshd_login_grace_time | int }} - - maxauthtries {{ sshd_max_auth_tries | int }} - - maxsessions {{ sshd_max_sessions | int }} - - maxstartups {{ sshd_max_startups }} - - permitrootlogin {{ sshd_permit_root_login }} - - port {{ sshd_port | int }} - - subsystem {{ sshd_subsystem }} - - usedns {{ sshd_use_dns }} - - usepam {{ sshd_use_pam }} - - x11forwarding {{ sshd_x11_forwarding }} + failed_when: >- + {%- set lower_parameter = item.split( )[0] | lower -%} + {{ ( item | regex_replace('^[^\ ]+', lower_parameter) ) not in sshd_config.stdout_lines }} + loop: "{{ ( sshd_config_parameters | reject('regex', 'Allowgroups ') | list ) + [ 'allowgroups vagrant', 'allowgroups sudo' ] }}" - name: Verify sshd runtime ciphers and algorithms become: true @@ -351,35 +347,24 @@ changed_when: false failed_when: item not in sshd_algo_runtime.stdout_lines when: not crypto_policies_config or not set_crypto_policy - with_items: - - casignaturealgorithms {{ sshd_ca_signature_algorithms | replace(', ', ',') }} - - ciphers {{ sshd_ciphers | replace(', ', ',') }} - - hostkeyalgorithms {{ sshd_host_key_algorithms | replace(', ', ',') }} - - kexalgorithms {{ sshd_kex_algorithms | replace(', ', ',') }} - - macs {{ sshd_macs | replace(', ', ',') }} - - - name: Verify sshd RequiredRSASize - become: true - ansible.builtin.lineinfile: - dest: /etc/ssh/sshd_config.d/01-hardening.conf - line: RequiredRSASize {{ sshd_required_rsa_size }} - state: present - check_mode: true - register: sshd_config_rsasize - failed_when: sshd_config_rsasize is changed - when: sshd_config_directory.stat.exists and ssh_installed_version is version('9.1', '>') + loop: + - "{{ 'casignaturealgorithms ' ~ sshd_ca_signature_algorithms|join(',') if sshd_ca_signature_algorithms }}" + - "{{ 'ciphers ' ~ sshd_ciphers|join(',') if sshd_ciphers }}" + - "{{ 'hostkeyalgorithms ' ~ sshd_host_key_algorithms|join(',') if sshd_host_key_algorithms }}" + - "{{ 'kexalgorithms ' ~ sshd_kex_algorithms|join(',') if sshd_kex_algorithms }}" + - "{{ 'macs ' ~ sshd_macs|join(',') if sshd_macs }}" - name: Verify ssh client configuration become: true ansible.builtin.lineinfile: dest: /etc/ssh/ssh_config - line: " {{ item }}" + line: "{{ item | indent(4) }}" state: present check_mode: true register: ssh_config failed_when: ssh_config is changed with_items: - - GSSAPIAuthentication {{ sshd_gssapi_authentication }} + - GSSAPIAuthentication {{ 'yes' if (sshd_gssapi_authentication|bool) else 'no' }} - HashKnownHosts yes - RekeyLimit {{ sshd_rekey_limit }} diff --git a/tasks/ufw.yml b/tasks/ufw.yml index bfe41f46..22780b64 100644 --- a/tasks/ufw.yml +++ b/tasks/ufw.yml @@ -1,4 +1,17 @@ --- +- name: Allow sshd port from administrator networks + become: true + community.general.ufw: + rule: limit + src: "{{ item.0 }}" + port: "{{ item.1 | int }}" + proto: tcp + comment: ansible managed + loop: "{{ sshd_admin_net | product(sshd_ports) | list }}" + tags: + - ufw + - M1037 + - name: Add the nf_conntrack module become: true community.general.modprobe: @@ -114,20 +127,6 @@ - ufw - M1037 -- name: Allow sshd port from administrator networks - become: true - community.general.ufw: - rule: limit - src: "{{ item }}" - port: "{{ sshd_port | int }}" - proto: tcp - comment: ansible managed - with_items: - - "{{ sshd_admin_net }}" - tags: - - ufw - - M1037 - - name: Allow outgoing specified ports become: true community.general.ufw: From 55a23e9d3dd306a205b9be185421f8fbb8596f6f Mon Sep 17 00:00:00 2001 From: cleberb Date: Sat, 30 Sep 2023 13:35:59 -0300 Subject: [PATCH 04/12] Fixed indentation in `verify.yml` and some spacing errors identified by `ansible-lint`. --- molecule/default/verify.yml | 78 ++++++++++--------- .../etc/audit/rules.d/hardening.rules.j2 | 2 +- templates/etc/ssh/ssh_config.j2 | 10 +-- templates/etc/ssh/sshd_config.j2 | 70 ++++++++--------- templates/etc/systemd/resolved.conf.j2 | 2 +- templates/etc/systemd/timesyncd.conf.j2 | 2 +- 6 files changed, 83 insertions(+), 81 deletions(-) diff --git a/molecule/default/verify.yml b/molecule/default/verify.yml index 248501ad..5b9b5f74 100644 --- a/molecule/default/verify.yml +++ b/molecule/default/verify.yml @@ -229,77 +229,79 @@ - name: Set sshd_config_parameters ansible.builtin.set_fact: sshd_config_parameters: - - AddressFamily {{ 'inet' if (disable_ipv6|bool) else 'any' }} + - AddressFamily {{ 'inet' if (disable_ipv6 | bool) else 'any' }} - AllowGroups vagrant sudo - - AllowAgentForwarding {{ 'yes' if (sshd_allow_agent_forwarding|bool) else 'no' }} + - AllowAgentForwarding {{ 'yes' if (sshd_allow_agent_forwarding | bool) else 'no' }} - >- + {# Set variable "tcp_fw" for ignore ansible-lint yaml[line-length] -#} + {% set tcp_fw = sshd_allow_tcp_forwarding %} {% if ssh_installed_version is version('6.2', '>=') %} - AllowTcpForwarding {{ sshd_allow_tcp_forwarding if (sshd_allow_tcp_forwarding in ('yes', 'no', 'local', 'all', 'remote')) else ('yes' if (sshd_allow_tcp_forwarding|bool) else 'no') }} + AllowTcpForwarding {{ tcp_fw if (tcp_fw in ('yes', 'no', 'local', 'all', 'remote')) else ('yes' if (tcp_fw | bool) else 'no') }} {% else %} - AllowTcpForwarding {{ sshd_allow_tcp_forwarding if (sshd_allow_tcp_forwarding in ('yes', 'no')) else ('yes' if (sshd_allow_tcp_forwarding|bool) else 'no') }} + AllowTcpForwarding {{ tcp_fw if (tcp_fw in ('yes', 'no')) else ('yes' if (tcp_fw | bool) else 'no') }} {% endif %} - Banner {{ sshd_banner if sshd_banner else 'none' }} - - ChallengeResponseAuthentication {{ 'yes' if (sshd_challenge_response_authentication|bool) else 'no' }} + - ChallengeResponseAuthentication {{ 'yes' if (sshd_challenge_response_authentication | bool) else 'no' }} - ClientAliveCountMax {{ sshd_client_alive_count_max | int }} - ClientAliveInterval {{ sshd_client_alive_interval | int }} - - Compression {{ 'yes' if (sshd_compression|bool) else 'no' }} - - DebianBanner {{ 'yes' if (sshd_debian_banner|bool) else 'no' }} - - GSSAPIAuthentication {{ 'yes' if (sshd_gssapi_authentication|bool) else 'no' }} + - Compression {{ 'yes' if (sshd_compression | bool) else 'no' }} + - DebianBanner {{ 'yes' if (sshd_debian_banner | bool) else 'no' }} + - GSSAPIAuthentication {{ 'yes' if (sshd_gssapi_authentication | bool) else 'no' }} - GSSAPICleanupCredentials yes - - HostbasedAuthentication {{ 'yes' if (sshd_hostbased_authentication|bool) else 'no' }} - - IgnoreRhosts {{ 'yes' if (sshd_ignore_rhosts|bool) else 'no' }} - - IgnoreUserKnownHosts {{ 'yes' if (sshd_ignore_user_known_hosts|bool) else 'no' }} - - KerberosAuthentication {{ 'yes' if (sshd_kerberos_authentication|bool) else 'no' }} + - HostbasedAuthentication {{ 'yes' if (sshd_hostbased_authentication | bool) else 'no' }} + - IgnoreRhosts {{ 'yes' if (sshd_ignore_rhosts | bool) else 'no' }} + - IgnoreUserKnownHosts {{ 'yes' if (sshd_ignore_user_known_hosts | bool) else 'no' }} + - KerberosAuthentication {{ 'yes' if (sshd_kerberos_authentication | bool) else 'no' }} - LogLevel {{ sshd_log_level }} - LoginGraceTime {{ sshd_login_grace_time | int }} - MaxAuthTries {{ sshd_max_auth_tries | int }} - MaxSessions {{ sshd_max_sessions | int }} - MaxStartups {{ sshd_max_startups }} - - PasswordAuthentication {{ 'yes' if (sshd_password_authentication|bool) else 'no' }} - - PermitEmptyPasswords {{ 'yes' if (sshd_permit_empty_passwords|bool) else 'no' }} - - PermitRootLogin {{ 'yes' if (sshd_permit_root_login|bool) else 'no' }} - - PermitTunnel {{ 'yes' if (sshd_permit_tunnel|bool) else 'no' }} - - PermitUserEnvironment {{ 'yes' if (sshd_permit_user_environment|bool) else 'no' }} - - PrintLastLog {{ 'yes' if (sshd_print_last_log|bool) else 'no' }} - - PrintMotd {{ 'yes' if (sshd_print_motd|bool) else 'no' }} + - PasswordAuthentication {{ 'yes' if (sshd_password_authentication | bool) else 'no' }} + - PermitEmptyPasswords {{ 'yes' if (sshd_permit_empty_passwords | bool) else 'no' }} + - PermitRootLogin {{ 'yes' if (sshd_permit_root_login | bool) else 'no' }} + - PermitTunnel {{ 'yes' if (sshd_permit_tunnel | bool) else 'no' }} + - PermitUserEnvironment {{ 'yes' if (sshd_permit_user_environment | bool) else 'no' }} + - PrintLastLog {{ 'yes' if (sshd_print_last_log | bool) else 'no' }} + - PrintMotd {{ 'yes' if (sshd_print_motd | bool) else 'no' }} - PubkeyAuthentication yes - RekeyLimit {{ sshd_rekey_limit }} - - StrictModes {{ 'yes' if (sshd_strict_modes|bool) else 'no' }} + - StrictModes {{ 'yes' if (sshd_strict_modes | bool) else 'no' }} - SyslogFacility {{ sshd_syslog_facility }} - - TCPKeepAlive {{ 'yes' if (sshd_tcp_keep_alive|bool) else 'no' }} - - UseDNS {{ 'yes' if (sshd_use_dns|bool) else 'no' }} - - UsePAM {{ 'yes' if (sshd_use_pam|bool) else 'no' }} - - X11Forwarding {{ 'yes' if (sshd_x11_forwarding|bool) else 'no' }} + - TCPKeepAlive {{ 'yes' if (sshd_tcp_keep_alive | bool) else 'no' }} + - UseDNS {{ 'yes' if (sshd_use_dns | bool) else 'no' }} + - UsePAM {{ 'yes' if (sshd_use_pam | bool) else 'no' }} + - X11Forwarding {{ 'yes' if (sshd_x11_forwarding | bool) else 'no' }} - X11UseLocalhost yes - name: Set sshd_config_parameters AuthenticationMethods ansible.builtin.set_fact: - sshd_config_parameters: "{{ sshd_config_parameters + [ 'AuthenticationMethods ' + sshd_authentication_methods ] }}" + sshd_config_parameters: "{{ sshd_config_parameters + ['AuthenticationMethods ' + sshd_authentication_methods] }}" when: ssh_installed_version is version('6.2', '>=') - name: Set sshd_config_parameters HostKey ansible.builtin.set_fact: - sshd_config_parameters: "{{ sshd_config_parameters + [ 'HostKey ' + item ] }}" + sshd_config_parameters: "{{ sshd_config_parameters + ['HostKey ' + item] }}" loop: "{{ sshd_host_keys_files }}" - name: Set sshd_config_parameters ListenAddress ansible.builtin.set_fact: - sshd_config_parameters: "{{ sshd_config_parameters + [ 'ListenAddress ' + item ] }}" + sshd_config_parameters: "{{ sshd_config_parameters + ['ListenAddress ' + item] }}" loop: "{{ sshd_listen }}" - - name: Set sshd_config_parameters Port + - name: Set sshd_config_parameters Port ansible.builtin.set_fact: - sshd_config_parameters: "{{ sshd_config_parameters + [ 'Port ' + item|string ] }}" + sshd_config_parameters: "{{ sshd_config_parameters + ['Port ' + item | string] }}" loop: "{{ sshd_ports }}" - name: Set sshd_config_parameters RequiredRSASize ansible.builtin.set_fact: - sshd_config_parameters: "{{ sshd_config_parameters + [ 'RequiredRSASize ' + sshd_required_rsa_size ] }}" + sshd_config_parameters: "{{ sshd_config_parameters + ['RequiredRSASize ' + sshd_required_rsa_size] }}" when: ssh_installed_version is version('9.1', '>') - name: Set sshd_config_parameters Subsystem ansible.builtin.set_fact: - sshd_config_parameters: "{{ sshd_config_parameters + [ 'Subsystem sftp ' + sshd_sftp_subsystem ] }}" + sshd_config_parameters: "{{ sshd_config_parameters + ['Subsystem sftp ' + sshd_sftp_subsystem] }}" when: sshd_sftp_enabled | bool - name: Verify sshd configuration @@ -336,7 +338,7 @@ failed_when: >- {%- set lower_parameter = item.split( )[0] | lower -%} {{ ( item | regex_replace('^[^\ ]+', lower_parameter) ) not in sshd_config.stdout_lines }} - loop: "{{ ( sshd_config_parameters | reject('regex', 'Allowgroups ') | list ) + [ 'allowgroups vagrant', 'allowgroups sudo' ] }}" + loop: "{{ (sshd_config_parameters | reject('regex', 'Allowgroups ') | list) + ['allowgroups vagrant', 'allowgroups sudo'] }}" - name: Verify sshd runtime ciphers and algorithms become: true @@ -348,11 +350,11 @@ failed_when: item not in sshd_algo_runtime.stdout_lines when: not crypto_policies_config or not set_crypto_policy loop: - - "{{ 'casignaturealgorithms ' ~ sshd_ca_signature_algorithms|join(',') if sshd_ca_signature_algorithms }}" - - "{{ 'ciphers ' ~ sshd_ciphers|join(',') if sshd_ciphers }}" - - "{{ 'hostkeyalgorithms ' ~ sshd_host_key_algorithms|join(',') if sshd_host_key_algorithms }}" - - "{{ 'kexalgorithms ' ~ sshd_kex_algorithms|join(',') if sshd_kex_algorithms }}" - - "{{ 'macs ' ~ sshd_macs|join(',') if sshd_macs }}" + - "{{ 'casignaturealgorithms ' ~ sshd_ca_signature_algorithms | join(',') if sshd_ca_signature_algorithms }}" + - "{{ 'ciphers ' ~ sshd_ciphers | join(',') if sshd_ciphers }}" + - "{{ 'hostkeyalgorithms ' ~ sshd_host_key_algorithms | join(',') if sshd_host_key_algorithms }}" + - "{{ 'kexalgorithms ' ~ sshd_kex_algorithms | join(',') if sshd_kex_algorithms }}" + - "{{ 'macs ' ~ sshd_macs | join(',') if sshd_macs }}" - name: Verify ssh client configuration become: true @@ -364,7 +366,7 @@ register: ssh_config failed_when: ssh_config is changed with_items: - - GSSAPIAuthentication {{ 'yes' if (sshd_gssapi_authentication|bool) else 'no' }} + - GSSAPIAuthentication {{ 'yes' if (sshd_gssapi_authentication | bool) else 'no' }} - HashKnownHosts yes - RekeyLimit {{ sshd_rekey_limit }} diff --git a/templates/etc/audit/rules.d/hardening.rules.j2 b/templates/etc/audit/rules.d/hardening.rules.j2 index 33e70d15..0dbeae85 100644 --- a/templates/etc/audit/rules.d/hardening.rules.j2 +++ b/templates/etc/audit/rules.d/hardening.rules.j2 @@ -11,7 +11,7 @@ -c # Failure Mode --f {{ auditd_mode|int }} +-f {{ auditd_mode | int }} # File and directory access -a always,exit -F arch=b32 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=-1 -k access diff --git a/templates/etc/ssh/ssh_config.j2 b/templates/etc/ssh/ssh_config.j2 index 07b59016..b2730095 100644 --- a/templates/etc/ssh/ssh_config.j2 +++ b/templates/etc/ssh/ssh_config.j2 @@ -10,11 +10,11 @@ Include /etc/ssh/ssh_config.d/*.conf {%+ endif +%} Host * {% if not crypto_policies_config or not set_crypto_policy %} - {{ 'Ciphers ' ~ sshd_ciphers|join(',') if sshd_ciphers }} - {{ 'HostKeyAlgorithms ' ~ sshd_host_key_algorithms|join(',') if sshd_host_key_algorithms }} - {{ 'KexAlgorithms ' ~ sshd_kex_algorithms|join(',') if sshd_kex_algorithms }} - {{ 'MACs ' ~ sshd_macs|join(',') if sshd_macs }} + {{ 'Ciphers ' ~ sshd_ciphers | join(',') if sshd_ciphers }} + {{ 'HostKeyAlgorithms ' ~ sshd_host_key_algorithms | join(',') if sshd_host_key_algorithms }} + {{ 'KexAlgorithms ' ~ sshd_kex_algorithms | join(',') if sshd_kex_algorithms }} + {{ 'MACs ' ~ sshd_macs | join(',') if sshd_macs }} {% endif %} - GSSAPIAuthentication {{ 'yes' if (sshd_gssapi_authentication|bool) else 'no' }} + GSSAPIAuthentication {{ 'yes' if (sshd_gssapi_authentication | bool) else 'no' }} HashKnownHosts yes RekeyLimit {{ sshd_rekey_limit }} diff --git a/templates/etc/ssh/sshd_config.j2 b/templates/etc/ssh/sshd_config.j2 index afceb3f0..98a0ce97 100644 --- a/templates/etc/ssh/sshd_config.j2 +++ b/templates/etc/ssh/sshd_config.j2 @@ -12,7 +12,7 @@ {% for port in sshd_ports %} Port {{ port }} {% endfor %} -AddressFamily {{ 'inet' if (disable_ipv6|bool) else 'any' }} +AddressFamily {{ 'inet' if (disable_ipv6 | bool) else 'any' }} {% for address in sshd_listen %} ListenAddress {{ address }} {% endfor %} @@ -27,7 +27,7 @@ HostKey {{ key }} {% if ssh_installed_version is version('7.6', '<') %} Protocol 2 {% endif %} -StrictModes {{ 'yes' if (sshd_strict_modes|bool) else 'no' }} +StrictModes {{ 'yes' if (sshd_strict_modes | bool) else 'no' }} SyslogFacility {{ sshd_syslog_facility }} LogLevel {{ sshd_log_level }} @@ -36,11 +36,11 @@ LogLevel {{ sshd_log_level }} ####################################################### {% if not crypto_policies_config or not set_crypto_policy %} -{{ 'CASignatureAlgorithms ' ~ sshd_ca_signature_algorithms|join(',') if sshd_ca_signature_algorithms }} -{{ 'Ciphers ' ~ sshd_ciphers|join(',') if sshd_ciphers }} -{{ 'HostKeyAlgorithms ' ~ sshd_host_key_algorithms|join(',') if sshd_host_key_algorithms }} -{{ 'KexAlgorithms ' ~ sshd_kex_algorithms|join(',') if sshd_kex_algorithms }} -{{ 'MACs ' ~ sshd_macs|join(',') if sshd_macs }} +{{ 'CASignatureAlgorithms ' ~ sshd_ca_signature_algorithms | join(',') if sshd_ca_signature_algorithms }} +{{ 'Ciphers ' ~ sshd_ciphers | join(',') if sshd_ciphers }} +{{ 'HostKeyAlgorithms ' ~ sshd_host_key_algorithms | join(',') if sshd_host_key_algorithms }} +{{ 'KexAlgorithms ' ~ sshd_kex_algorithms | join(',') if sshd_kex_algorithms }} +{{ 'MACs ' ~ sshd_macs | join(',') if sshd_macs }} {% endif %} RekeyLimit {{ sshd_rekey_limit }} {% if ssh_installed_version is version('9.1', '>') and (not crypto_policies_config or not set_crypto_policy) %} @@ -51,66 +51,66 @@ RequiredRSASize {{ sshd_required_rsa_size }} # Authentication ####################################################### -PermitRootLogin {{ 'yes' if (sshd_permit_root_login|bool) else 'no' }} +PermitRootLogin {{ 'yes' if (sshd_permit_root_login | bool) else 'no' }} {% if ssh_installed_version is version('7.4', '<') %} UseLogin no {% endif %} {% if ssh_installed_version is version('7.5', '<') %} -UsePrivilegeSeparation {{ sshd_use_privilege_separation if (sshd_use_privilege_separation in ('yes', 'no', 'sandbox')) else ('yes' if (sshd_use_privilege_separation|bool) else 'no') }} +UsePrivilegeSeparation {{ sshd_use_privilege_separation if (sshd_use_privilege_separation in ('yes', 'no', 'sandbox')) else ('yes' if (sshd_use_privilege_separation | bool) else 'no') }} {% endif %} LoginGraceTime {{ sshd_login_grace_time | int }} MaxAuthTries {{ sshd_max_auth_tries | int }} MaxSessions {{ sshd_max_sessions | int }} MaxStartups {{ sshd_max_startups }} PubkeyAuthentication yes -IgnoreRhosts {{ 'yes' if (sshd_ignore_rhosts|bool) else 'no' }} -IgnoreUserKnownHosts {{ 'yes' if (sshd_ignore_user_known_hosts|bool) else 'no' }} -HostbasedAuthentication {{ 'yes' if (sshd_hostbased_authentication|bool) else 'no' }} -UsePAM {{ 'yes' if (sshd_use_pam|bool) else 'no' }} +IgnoreRhosts {{ 'yes' if (sshd_ignore_rhosts | bool) else 'no' }} +IgnoreUserKnownHosts {{ 'yes' if (sshd_ignore_user_known_hosts | bool) else 'no' }} +HostbasedAuthentication {{ 'yes' if (sshd_hostbased_authentication | bool) else 'no' }} +UsePAM {{ 'yes' if (sshd_use_pam | bool) else 'no' }} {% if ssh_installed_version is version('6.2', '>=') %} AuthenticationMethods {{ sshd_authentication_methods }} {% endif %} -PasswordAuthentication {{ 'yes' if (sshd_password_authentication|bool) else 'no' }} -PermitEmptyPasswords {{ 'yes' if (sshd_permit_empty_passwords|bool) else 'no' }} -ChallengeResponseAuthentication {{ 'yes' if (sshd_challenge_response_authentication|bool) else 'no' }} -KerberosAuthentication {{ 'yes' if (sshd_kerberos_authentication|bool) else 'no' }} -GSSAPIAuthentication {{ 'yes' if (sshd_gssapi_authentication|bool) else 'no' }} +PasswordAuthentication {{ 'yes' if (sshd_password_authentication | bool) else 'no' }} +PermitEmptyPasswords {{ 'yes' if (sshd_permit_empty_passwords | bool) else 'no' }} +ChallengeResponseAuthentication {{ 'yes' if (sshd_challenge_response_authentication | bool) else 'no' }} +KerberosAuthentication {{ 'yes' if (sshd_kerberos_authentication | bool) else 'no' }} +GSSAPIAuthentication {{ 'yes' if (sshd_gssapi_authentication | bool) else 'no' }} GSSAPICleanupCredentials yes {% if sshd_deny_groups %} -{{ 'DenyGroups ' ~ sshd_deny_groups|join(' ') }} +{{ 'DenyGroups ' ~ sshd_deny_groups | join(' ') }} {% endif %} {% if sshd_allow_groups %} -{{ 'AllowGroups ' ~ sshd_allow_groups|join(' ') }} +{{ 'AllowGroups ' ~ sshd_allow_groups | join(' ') }} {% endif %} {% if sshd_deny_users %} -{{ 'DenyUsers ' ~ sshd_deny_users|join(' ') }} +{{ 'DenyUsers ' ~ sshd_deny_users | join(' ') }} {% endif %} {% if sshd_allow_users %} -{{ 'AllowUsers ' ~ sshd_allow_users|join(' ') }} +{{ 'AllowUsers ' ~ sshd_allow_users | join(' ') }} {% endif %} ####################################################### # Network ####################################################### -TCPKeepAlive {{ 'yes' if (sshd_tcp_keep_alive|bool) else 'no' }} +TCPKeepAlive {{ 'yes' if (sshd_tcp_keep_alive | bool) else 'no' }} ClientAliveCountMax {{ sshd_client_alive_count_max | int }} ClientAliveInterval {{ sshd_client_alive_interval | int }} -PermitTunnel {{ 'yes' if (sshd_permit_tunnel|bool) else 'no' }} +PermitTunnel {{ 'yes' if (sshd_permit_tunnel | bool) else 'no' }} {% if ssh_installed_version is version('6.2', '>=') %} -AllowTcpForwarding {{ sshd_allow_tcp_forwarding if (sshd_allow_tcp_forwarding in ('yes', 'no', 'local', 'all', 'remote')) else ('yes' if (sshd_allow_tcp_forwarding|bool) else 'no') }} +AllowTcpForwarding {{ sshd_allow_tcp_forwarding if (sshd_allow_tcp_forwarding in ('yes', 'no', 'local', 'all', 'remote')) else ('yes' if (sshd_allow_tcp_forwarding | bool) else 'no') }} {% else %} -AllowTcpForwarding {{ sshd_allow_tcp_forwarding if (sshd_allow_tcp_forwarding in ('yes', 'no')) else ('yes' if (sshd_allow_tcp_forwarding|bool) else 'no') }} +AllowTcpForwarding {{ sshd_allow_tcp_forwarding if (sshd_allow_tcp_forwarding in ('yes', 'no')) else ('yes' if (sshd_allow_tcp_forwarding | bool) else 'no') }} {% endif %} -AllowAgentForwarding {{ 'yes' if (sshd_allow_agent_forwarding|bool) else 'no' }} -X11Forwarding {{ 'yes' if (sshd_x11_forwarding|bool) else 'no' }} +AllowAgentForwarding {{ 'yes' if (sshd_allow_agent_forwarding | bool) else 'no' }} +X11Forwarding {{ 'yes' if (sshd_x11_forwarding | bool) else 'no' }} X11UseLocalhost yes ####################################################### # User environment configuration ####################################################### -PermitUserEnvironment {{ 'yes' if (sshd_permit_user_environment|bool) else 'no' }} +PermitUserEnvironment {{ 'yes' if (sshd_permit_user_environment | bool) else 'no' }} {% if sshd_accept_env %} AcceptEnv {{ sshd_accept_env }} {% endif %} @@ -119,13 +119,13 @@ AcceptEnv {{ sshd_accept_env }} # Misc. configuration ####################################################### -Compression {{ 'yes' if (sshd_compression|bool) else 'no' }} -UseDNS {{ 'yes' if (sshd_use_dns|bool) else 'no' }} -PrintMotd {{ 'yes' if (sshd_print_motd|bool) else 'no' }} -PrintLastLog {{ 'yes' if (sshd_print_last_log|bool) else 'no' }} +Compression {{ 'yes' if (sshd_compression | bool) else 'no' }} +UseDNS {{ 'yes' if (sshd_use_dns | bool) else 'no' }} +PrintMotd {{ 'yes' if (sshd_print_motd | bool) else 'no' }} +PrintLastLog {{ 'yes' if (sshd_print_last_log | bool) else 'no' }} Banner {{ sshd_banner if sshd_banner else 'none' }} {% if ansible_facts.os_family == 'Debian' %} -DebianBanner {{ 'yes' if (sshd_debian_banner|bool) else 'no' }} +DebianBanner {{ 'yes' if (sshd_debian_banner | bool) else 'no' }} {% endif %} {%+ if sshd_sftp_enabled +%} @@ -142,7 +142,7 @@ Match Group {{ sshd_sftp_only_group }} {% endif %} AllowTcpForwarding no AllowAgentForwarding no - PasswordAuthentication {{ 'yes' if (sshd_password_authentication|bool) else 'no' }} + PasswordAuthentication {{ 'yes' if (sshd_password_authentication | bool) else 'no' }} PermitRootLogin no X11Forwarding no {% endif %} diff --git a/templates/etc/systemd/resolved.conf.j2 b/templates/etc/systemd/resolved.conf.j2 index ce66bc48..26451174 100644 --- a/templates/etc/systemd/resolved.conf.j2 +++ b/templates/etc/systemd/resolved.conf.j2 @@ -5,6 +5,6 @@ DNS={{ dns }} FallbackDNS={{ fallback_dns }} DNSSEC={{ dnssec }} -{% if ansible_local.systemd.version|int >= 239 %} +{% if ansible_local.systemd.version | int >= 239 %} DNSOverTLS={{ dns_over_tls }} {% endif %} diff --git a/templates/etc/systemd/timesyncd.conf.j2 b/templates/etc/systemd/timesyncd.conf.j2 index 23dd48d1..8f082621 100644 --- a/templates/etc/systemd/timesyncd.conf.j2 +++ b/templates/etc/systemd/timesyncd.conf.j2 @@ -4,6 +4,6 @@ [Time] NTP={{ ntp }} FallbackNTP={{ fallback_ntp }} -{% if ansible_local.systemd.version|int >= 236 %} +{% if ansible_local.systemd.version | int >= 236 %} RootDistanceMaxSec=1 {% endif %} From 28164e85b9c16ae4f5dac47ee3d00f91515f1e3f Mon Sep 17 00:00:00 2001 From: cleberb Date: Sun, 1 Oct 2023 01:22:00 -0300 Subject: [PATCH 05/12] Fix task order and replace with_items with loop --- tasks/ufw.yml | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/tasks/ufw.yml b/tasks/ufw.yml index 22780b64..4effa9ec 100644 --- a/tasks/ufw.yml +++ b/tasks/ufw.yml @@ -1,17 +1,4 @@ --- -- name: Allow sshd port from administrator networks - become: true - community.general.ufw: - rule: limit - src: "{{ item.0 }}" - port: "{{ item.1 | int }}" - proto: tcp - comment: ansible managed - loop: "{{ sshd_admin_net | product(sshd_ports) | list }}" - tags: - - ufw - - M1037 - - name: Add the nf_conntrack module become: true community.general.modprobe: @@ -127,6 +114,19 @@ - ufw - M1037 +- name: Allow sshd port from administrator networks + become: true + community.general.ufw: + rule: limit + src: "{{ item.0 }}" + port: "{{ item.1 | int }}" + proto: tcp + comment: ansible managed + loop: "{{ sshd_admin_net | product(sshd_ports) | list }}" + tags: + - ufw + - M1037 + - name: Allow outgoing specified ports become: true community.general.ufw: @@ -134,8 +134,7 @@ port: "{{ item | int }}" direction: out comment: ansible managed - with_items: - - "{{ ufw_outgoing_traffic }}" + loop: "{{ ufw_outgoing_traffic }}" tags: - ufw - CIS-UBUNTU2004-3.5.1.5 @@ -197,8 +196,7 @@ changed_when: ufw_delete.rc != 0 failed_when: ufw_delete.rc != 0 when: ufw_not_managed.stdout_lines | length > 0 and not ansible_os_family == "RedHat" - with_items: - - "{{ ufw_not_managed.stdout_lines }}" + loop: "{{ ufw_not_managed.stdout_lines }}" tags: - ufw - D3-OTF From 01551e1756dc95231c0a45f3a26b05d45a268872 Mon Sep 17 00:00:00 2001 From: cleberb Date: Sun, 1 Oct 2023 01:22:43 -0300 Subject: [PATCH 06/12] Fix variable format in `vagrant` and `molecule` --- Vagrantfile | 16 +++++++-------- molecule/almalinux/molecule.yml | 14 +++++++++---- molecule/debian/molecule.yml | 21 ++++++++++++++------ molecule/default/molecule.yml | 35 +++++++++++++++++++++++---------- molecule/redhat/molecule.yml | 7 +++++-- molecule/single/molecule.yml | 7 +++++-- molecule/ubuntu/molecule.yml | 28 ++++++++++++++++++-------- 7 files changed, 88 insertions(+), 40 deletions(-) diff --git a/Vagrantfile b/Vagrantfile index 98ed6aa6..14529b48 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -20,8 +20,8 @@ Vagrant.configure("2") do |config| a.extra_vars = { "ansible_become_pass" => "vagrant", "ansible_python_interpreter" => "/usr/bin/python3", - "sshd_admin_net" => "0.0.0.0/0", - "sshd_allow_groups" => "vagrant sudo debian ubuntu", + "sshd_admin_net" => ["0.0.0.0/0"], + "sshd_allow_groups" => ["vagrant", "sudo", "debian", "ubuntu"], "system_upgrade" => "no", "install_aide" => "false" } @@ -40,8 +40,8 @@ Vagrant.configure("2") do |config| a.limit = "all" a.playbook = "tests/test.yml" a.extra_vars = { - "sshd_admin_net" => "0.0.0.0/0", - "sshd_allow_groups" => "vagrant sudo ubuntu", + "sshd_admin_net" => ["0.0.0.0/0"], + "sshd_allow_groups" => ["vagrant", "sudo", "ubuntu"], "ansible_python_interpreter" => "/usr/bin/python3", "install_aide" => "false" } @@ -60,8 +60,8 @@ Vagrant.configure("2") do |config| a.limit = "all" a.playbook = "tests/test.yml" a.extra_vars = { - "sshd_admin_net" => "0.0.0.0/0", - "sshd_allow_groups" => "vagrant sudo ubuntu", + "sshd_admin_net" => ["0.0.0.0/0"], + "sshd_allow_groups" => ["vagrant", "sudo", "ubuntu"], "ansible_python_interpreter" => "/usr/bin/python3", "install_aide" => "false" } @@ -83,8 +83,8 @@ Vagrant.configure("2") do |config| a.limit = "all" a.playbook = "tests/test.yml" a.extra_vars = { - "sshd_admin_net" => "0.0.0.0/0", - "sshd_allow_groups" => "vagrant sudo", + "sshd_admin_net" => ["0.0.0.0/0"], + "sshd_allow_groups" => ["vagrant", "sudo"], "ansible_python_interpreter" => "/usr/bin/python3", "install_aide" => "false" } diff --git a/molecule/almalinux/molecule.yml b/molecule/almalinux/molecule.yml index aaf7cae1..080498be 100644 --- a/molecule/almalinux/molecule.yml +++ b/molecule/almalinux/molecule.yml @@ -19,13 +19,19 @@ provisioner: host_vars: almalinux8: enable_timesyncd: false - sshd_admin_net: "0.0.0.0/0" - sshd_allow_groups: vagrant sudo + sshd_admin_net: + - 0.0.0.0/0 + sshd_allow_groups: + - vagrant + - sudo suid_sgid_permissions: false almalinux9: enable_timesyncd: false - sshd_admin_net: "0.0.0.0/0" - sshd_allow_groups: vagrant sudo + sshd_admin_net: + - 0.0.0.0/0 + sshd_allow_groups: + - vagrant + - sudo suid_sgid_permissions: false platforms: - name: almalinux8 diff --git a/molecule/debian/molecule.yml b/molecule/debian/molecule.yml index b1fe46c7..3c7afa78 100644 --- a/molecule/debian/molecule.yml +++ b/molecule/debian/molecule.yml @@ -19,21 +19,30 @@ provisioner: host_vars: bookworm: ansible_python_interpreter: /usr/bin/python3 - sshd_admin_net: "0.0.0.0/0" - sshd_allow_groups: vagrant sudo + sshd_admin_net: + - 0.0.0.0/0 + sshd_allow_groups: + - vagrant + - sudo suid_sgid_permissions: false system_upgrade: false bullseye: ansible_become_pass: vagrant ansible_python_interpreter: /usr/bin/python3 - sshd_admin_net: "0.0.0.0/0" - sshd_allow_groups: vagrant sudo + sshd_admin_net: + - 0.0.0.0/0 + sshd_allow_groups: + - vagrant + - sudo suid_sgid_permissions: false testing: ansible_become_pass: vagrant ansible_python_interpreter: /usr/bin/python3 - sshd_admin_net: "0.0.0.0/0" - sshd_allow_groups: vagrant sudo + sshd_admin_net: + - 0.0.0.0/0 + sshd_allow_groups: + - vagrant + - sudo suid_sgid_permissions: false platforms: - name: bookworm diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml index 240b44e2..1179ddab 100644 --- a/molecule/default/molecule.yml +++ b/molecule/default/molecule.yml @@ -18,33 +18,48 @@ provisioner: disable_wireless: true enable_timesyncd: false install_aide: false - sshd_admin_net: "0.0.0.0/0" - sshd_allow_groups: vagrant sudo + sshd_admin_net: + - 0.0.0.0/0 + sshd_allow_groups: + - vagrant + - sudo suid_sgid_permissions: false almalinux9: enable_timesyncd: false - sshd_admin_net: "0.0.0.0/0" - sshd_allow_groups: vagrant sudo + sshd_admin_net: + - 0.0.0.0/0 + sshd_allow_groups: + - vagrant + - sudo bookworm: ansible_become_pass: vagrant ansible_python_interpreter: /usr/bin/python3 disable_wireless: false - sshd_admin_net: "0.0.0.0/0" - sshd_allow_groups: vagrant sudo + sshd_admin_net: + - 0.0.0.0/0 + sshd_allow_groups: + - vagrant + - sudo system_upgrade: false focal: block_blacklisted: true disable_wireless: true install_aide: false - sshd_admin_net: "0.0.0.0/0" - sshd_allow_groups: vagrant sudo + sshd_admin_net: + - 0.0.0.0/0 + sshd_allow_groups: + - vagrant + - sudo suid_sgid_permissions: false jammy: disable_ipv6: true block_blacklisted: true disable_wireless: true - sshd_admin_net: "0.0.0.0/0" - sshd_allow_groups: vagrant sudo + sshd_admin_net: + - 0.0.0.0/0 + sshd_allow_groups: + - vagrant + - sudo suid_sgid_permissions: false platforms: - name: almalinux8 diff --git a/molecule/redhat/molecule.yml b/molecule/redhat/molecule.yml index 2eaa96e6..5d29a817 100644 --- a/molecule/redhat/molecule.yml +++ b/molecule/redhat/molecule.yml @@ -21,8 +21,11 @@ provisioner: inventory: host_vars: redhat: - sshd_admin_net: "0.0.0.0/0" - sshd_allow_groups: vagrant sudo + sshd_admin_net: + - 0.0.0.0/0 + sshd_allow_groups: + - vagrant + - sudo platforms: - name: redhat box: generic/rhel8 diff --git a/molecule/single/molecule.yml b/molecule/single/molecule.yml index ca9b2990..9eb7f8cf 100644 --- a/molecule/single/molecule.yml +++ b/molecule/single/molecule.yml @@ -18,8 +18,11 @@ provisioner: inventory: host_vars: focal: - sshd_admin_net: "0.0.0.0/0" - sshd_allow_groups: vagrant sudo + sshd_admin_net: + - 0.0.0.0/0 + sshd_allow_groups: + - vagrant + - sudo suid_sgid_permissions: false umask_value: "027" platforms: diff --git a/molecule/ubuntu/molecule.yml b/molecule/ubuntu/molecule.yml index 3b53ee75..46a915df 100644 --- a/molecule/ubuntu/molecule.yml +++ b/molecule/ubuntu/molecule.yml @@ -18,17 +18,29 @@ provisioner: inventory: host_vars: focal: - sshd_admin_net: "0.0.0.0/0" - sshd_allow_groups: vagrant sudo + sshd_admin_net: + - 0.0.0.0/0 + sshd_allow_groups: + - vagrant + - sudo jammy: - sshd_admin_net: "0.0.0.0/0" - sshd_allow_groups: vagrant sudo + sshd_admin_net: + - 0.0.0.0/0 + sshd_allow_groups: + - vagrant + - sudo lunar: - sshd_admin_net: "0.0.0.0/0" - sshd_allow_groups: vagrant sudo + sshd_admin_net: + - 0.0.0.0/0 + sshd_allow_groups: + - vagrant + - sudo mantic: - sshd_admin_net: "0.0.0.0/0" - sshd_allow_groups: vagrant sudo + sshd_admin_net: + - 0.0.0.0/0 + sshd_allow_groups: + - vagrant + - sudo platforms: - name: focal box: bento/ubuntu-20.04 From a5963e4772907ea8a9cd59674f706fa37ec8ad19 Mon Sep 17 00:00:00 2001 From: cleberb Date: Sun, 1 Oct 2023 14:46:50 -0300 Subject: [PATCH 07/12] Miscs Fix README.md: - Fix directory /etc/ssh/sshd_config and /etc/ssh/sshd_config.d sshconfig.yml: - Fix tasks without become: true - Fix logical operator verify.yml: - Conditional for DebianBanner parameter, only for Debian family - Fix whitespace via trim blocks --- README.md | 6 +++--- molecule/default/verify.yml | 18 +++++++++++------- tasks/sshconfig.yml | 4 +++- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 40977b49..f2b80788 100644 --- a/README.md +++ b/README.md @@ -584,13 +584,13 @@ connection. `sshd_required_rsa_size`, RequiredRSASize, will only be set if SSH version is higher than 9.1. -`sshd_config_d_force_clear` force clear directory `/etc/sshd_config.d`. Default: `false`. +`sshd_config_d_force_clear` force clear directory `/etc/ssh/sshd_config.d`. Default: `false`. -`sshd_config_force_replace` force replace configuration file `/etc/sshd_config`. Default: `false`. +`sshd_config_force_replace` force replace configuration file `/etc/ssh/sshd_config`. Default: `false`. > **Note** > -> By default, the role checks whether the directory `/etc/sshd_config.d` exists and whether it is linked via the `Include` parameter in the `/etc/sshd_config` file, if so, an additional configuration file is created in `/ etc/sshd_config.d`, if not, the `/etc/sshd_config` file is overwritten. +> By default, the role checks whether the directory `/etc/ssh/sshd_config.d` exists and whether it is linked via the `Include` parameter in the `/etc/ssh/sshd_config` file, if so, an additional configuration file is created in `/ etc/ssh/sshd_config.d`, if not, the `/etc/ssh/sshd_config` file is overwritten. > **Warning** > diff --git a/molecule/default/verify.yml b/molecule/default/verify.yml index 5b9b5f74..216fa300 100644 --- a/molecule/default/verify.yml +++ b/molecule/default/verify.yml @@ -233,19 +233,18 @@ - AllowGroups vagrant sudo - AllowAgentForwarding {{ 'yes' if (sshd_allow_agent_forwarding | bool) else 'no' }} - >- - {# Set variable "tcp_fw" for ignore ansible-lint yaml[line-length] -#} - {% set tcp_fw = sshd_allow_tcp_forwarding %} - {% if ssh_installed_version is version('6.2', '>=') %} + {#- Set variable "tcp_fw" for ignore ansible-lint yaml[line-length] -#} + {%- set tcp_fw = sshd_allow_tcp_forwarding -%} + {%- if ssh_installed_version is version('6.2', '>=') -%} AllowTcpForwarding {{ tcp_fw if (tcp_fw in ('yes', 'no', 'local', 'all', 'remote')) else ('yes' if (tcp_fw | bool) else 'no') }} - {% else %} + {%- else -%} AllowTcpForwarding {{ tcp_fw if (tcp_fw in ('yes', 'no')) else ('yes' if (tcp_fw | bool) else 'no') }} - {% endif %} + {%- endif -%} - Banner {{ sshd_banner if sshd_banner else 'none' }} - ChallengeResponseAuthentication {{ 'yes' if (sshd_challenge_response_authentication | bool) else 'no' }} - ClientAliveCountMax {{ sshd_client_alive_count_max | int }} - ClientAliveInterval {{ sshd_client_alive_interval | int }} - Compression {{ 'yes' if (sshd_compression | bool) else 'no' }} - - DebianBanner {{ 'yes' if (sshd_debian_banner | bool) else 'no' }} - GSSAPIAuthentication {{ 'yes' if (sshd_gssapi_authentication | bool) else 'no' }} - GSSAPICleanupCredentials yes - HostbasedAuthentication {{ 'yes' if (sshd_hostbased_authentication | bool) else 'no' }} @@ -279,6 +278,11 @@ sshd_config_parameters: "{{ sshd_config_parameters + ['AuthenticationMethods ' + sshd_authentication_methods] }}" when: ssh_installed_version is version('6.2', '>=') + - name: Set sshd_config_parameters DebianBanner + ansible.builtin.set_fact: + sshd_config_parameters: "{{ sshd_config_parameters + ['DebianBanner ' + 'yes' if (sshd_debian_banner | bool) else 'no'] }}" + when: ansible_facts.os_family == 'Debian' + - name: Set sshd_config_parameters HostKey ansible.builtin.set_fact: sshd_config_parameters: "{{ sshd_config_parameters + ['HostKey ' + item] }}" @@ -296,7 +300,7 @@ - name: Set sshd_config_parameters RequiredRSASize ansible.builtin.set_fact: - sshd_config_parameters: "{{ sshd_config_parameters + ['RequiredRSASize ' + sshd_required_rsa_size] }}" + sshd_config_parameters: "{{ sshd_config_parameters + ['RequiredRSASize ' + sshd_required_rsa_size | string] }}" when: ssh_installed_version is version('9.1', '>') - name: Set sshd_config_parameters Subsystem diff --git a/tasks/sshconfig.yml b/tasks/sshconfig.yml index 511f0962..f2186fda 100644 --- a/tasks/sshconfig.yml +++ b/tasks/sshconfig.yml @@ -93,6 +93,7 @@ - sshd_config - name: Set default for sshd_host_keys_files if not supplied + become: true when: not sshd_host_keys_files tags: - sshd @@ -140,6 +141,7 @@ loop: "{{ sshd_host_keys_files }}" - name: Disable PAM dynamic MOTD + become: true community.general.pamd: name: sshd type: session @@ -226,7 +228,7 @@ owner: root group: root validate: "/usr/sbin/sshd -T -C user=root -C host=localhost -C addr=localhost -C lport=22 -f %s" - when: not ( sshd_config_force_replace | bool ) or sshd_config_d.stat.exists and grep_include.rc == 0 + when: not ( sshd_config_force_replace | bool ) and sshd_config_d.stat.exists and grep_include.rc == 0 notify: - Restart sshd service - Restart ssh service From f68cbc28b7490bea4a4bf35810c7d9ca3549a31f Mon Sep 17 00:00:00 2001 From: cleberb Date: Mon, 2 Oct 2023 13:43:08 -0300 Subject: [PATCH 08/12] Miscs fix: README.md/sshconfig.yml: - Added conditional to enable the `sshd_config_force_replace` variable if the `sshd_sftp_only_group` variable is defined verify.yml: - Add more parameters for analysis - Fixed string concatenation - Remove indent(4), not working with module lineinfile --- README.md | 2 +- molecule/default/verify.yml | 60 +++++++++++++++++++++++-------------- tasks/sshconfig.yml | 3 +- 3 files changed, 41 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index f2b80788..459db00d 100644 --- a/README.md +++ b/README.md @@ -594,7 +594,7 @@ connection. > **Warning** > -> If any `sshd_match_(users|groups|addresses|local_ports)` parameters is set, the value `true` will be implicit. +> If any `sshd_match_(users|groups|addresses|local_ports)` or `sshd_sftp_only_group` parameters is set, the value `true` will be implicit. `sshd_host_keys_files` host keys for sshd. If empty `['/etc/ssh/ssh_host_rsa_key', '/etc/ssh/ssh_host_ecdsa_key', '/etc/ssh/ssh_host_ed25519_key']` will be used, as far as supported by the installed sshd version. diff --git a/molecule/default/verify.yml b/molecule/default/verify.yml index 216fa300..b78df3a9 100644 --- a/molecule/default/verify.yml +++ b/molecule/default/verify.yml @@ -273,6 +273,11 @@ - X11Forwarding {{ 'yes' if (sshd_x11_forwarding | bool) else 'no' }} - X11UseLocalhost yes + - name: Set sshd_config_parameters AcceptEnv + ansible.builtin.set_fact: + sshd_config_parameters: "{{ sshd_config_parameters + ['AcceptEnv ' + sshd_authentication_methods] }}" + when: sshd_accept_env is defined and sshd_accept_env | length != 0 + - name: Set sshd_config_parameters AuthenticationMethods ansible.builtin.set_fact: sshd_config_parameters: "{{ sshd_config_parameters + ['AuthenticationMethods ' + sshd_authentication_methods] }}" @@ -280,7 +285,7 @@ - name: Set sshd_config_parameters DebianBanner ansible.builtin.set_fact: - sshd_config_parameters: "{{ sshd_config_parameters + ['DebianBanner ' + 'yes' if (sshd_debian_banner | bool) else 'no'] }}" + sshd_config_parameters: "{{ sshd_config_parameters + ['DebianBanner ' + ('yes' if (sshd_debian_banner | bool) else 'no')] }}" when: ansible_facts.os_family == 'Debian' - name: Set sshd_config_parameters HostKey @@ -295,12 +300,17 @@ - name: Set sshd_config_parameters Port ansible.builtin.set_fact: - sshd_config_parameters: "{{ sshd_config_parameters + ['Port ' + item | string] }}" + sshd_config_parameters: "{{ sshd_config_parameters + ['Port ' + (item | string)] }}" loop: "{{ sshd_ports }}" + - name: Set sshd_config_parameters Protocol + ansible.builtin.set_fact: + sshd_config_parameters: "{{ sshd_config_parameters + ['Protocol 2'] }}" + when: ssh_installed_version is version('7.6', '<') + - name: Set sshd_config_parameters RequiredRSASize ansible.builtin.set_fact: - sshd_config_parameters: "{{ sshd_config_parameters + ['RequiredRSASize ' + sshd_required_rsa_size | string] }}" + sshd_config_parameters: "{{ sshd_config_parameters + ['RequiredRSASize ' + (sshd_required_rsa_size | string)] }}" when: ssh_installed_version is version('9.1', '>') - name: Set sshd_config_parameters Subsystem @@ -308,6 +318,27 @@ sshd_config_parameters: "{{ sshd_config_parameters + ['Subsystem sftp ' + sshd_sftp_subsystem] }}" when: sshd_sftp_enabled | bool + - name: Set sshd_config_parameters UseLogin + ansible.builtin.set_fact: + sshd_config_parameters: "{{ sshd_config_parameters + ['UseLogin no'] }}" + when: ssh_installed_version is version('7.4', '<') + + - name: Set sshd_config_parameters UsePrivilegeSeparation + ansible.builtin.set_fact: + sshd_config_parameters: "{{ sshd_config_parameters + ['UsePrivilegeSeparation ' + sshd_use_privilege_separation if (sshd_use_privilege_separation in ('yes', 'no', 'sandbox')) else ('yes' if (sshd_use_privilege_separation | bool) else 'no')] }}" # noqa yaml[line-length] + when: ssh_installed_version is version('7.5', '<') + + - name: Verify sshd runtime ciphers and algorithms + ansible.builtin.set_fact: + sshd_config_parameters: "{{ sshd_config_parameters + [item] }}" + when: not crypto_policies_config or not set_crypto_policy + loop: + - CASignatureAlgorithms {{ sshd_ca_signature_algorithms | join(',') }} + - Ciphers {{ sshd_ciphers | join(',') }} + - HostKeyAlgorithms {{ sshd_host_key_algorithms | join(',') }} + - KexAlgorithms {{ sshd_kex_algorithms | join(',') }} + - MACs {{ sshd_macs | join(',') }} + - name: Verify sshd configuration become: true ansible.builtin.lineinfile: @@ -324,7 +355,7 @@ become: true ansible.builtin.lineinfile: dest: /etc/ssh/sshd_config.d/01-hardening.conf - line: "{{ item | replace(', ', ',') }}" + line: "{{ item }}" state: present check_mode: true register: sshd_config @@ -337,6 +368,7 @@ environment: PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin ansible.builtin.command: sshd -T + check_mode: false register: sshd_config changed_when: false failed_when: >- @@ -344,32 +376,16 @@ {{ ( item | regex_replace('^[^\ ]+', lower_parameter) ) not in sshd_config.stdout_lines }} loop: "{{ (sshd_config_parameters | reject('regex', 'Allowgroups ') | list) + ['allowgroups vagrant', 'allowgroups sudo'] }}" - - name: Verify sshd runtime ciphers and algorithms - become: true - environment: - PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin - ansible.builtin.command: sshd -T - register: sshd_algo_runtime - changed_when: false - failed_when: item not in sshd_algo_runtime.stdout_lines - when: not crypto_policies_config or not set_crypto_policy - loop: - - "{{ 'casignaturealgorithms ' ~ sshd_ca_signature_algorithms | join(',') if sshd_ca_signature_algorithms }}" - - "{{ 'ciphers ' ~ sshd_ciphers | join(',') if sshd_ciphers }}" - - "{{ 'hostkeyalgorithms ' ~ sshd_host_key_algorithms | join(',') if sshd_host_key_algorithms }}" - - "{{ 'kexalgorithms ' ~ sshd_kex_algorithms | join(',') if sshd_kex_algorithms }}" - - "{{ 'macs ' ~ sshd_macs | join(',') if sshd_macs }}" - - name: Verify ssh client configuration become: true ansible.builtin.lineinfile: dest: /etc/ssh/ssh_config - line: "{{ item | indent(4) }}" + line: " {{ item }}" state: present check_mode: true register: ssh_config failed_when: ssh_config is changed - with_items: + loop: - GSSAPIAuthentication {{ 'yes' if (sshd_gssapi_authentication | bool) else 'no' }} - HashKnownHosts yes - RekeyLimit {{ sshd_rekey_limit }} diff --git a/tasks/sshconfig.yml b/tasks/sshconfig.yml index f2186fda..a0f5bc13 100644 --- a/tasks/sshconfig.yml +++ b/tasks/sshconfig.yml @@ -162,7 +162,8 @@ sshd_match_users | length > 0 or sshd_match_groups | length > 0 or sshd_match_addresses | length > 0 or - sshd_match_local_ports | length > 0 + sshd_match_local_ports | length > 0 or + (sshd_sftp_only_group is defined and sshd_sftp_only_group | length != 0) - name: Configure sshd become: true From 79a38f127286df0a910a05def3ae796a11174d40 Mon Sep 17 00:00:00 2001 From: cleberb Date: Tue, 10 Oct 2023 17:43:55 -0300 Subject: [PATCH 09/12] Changes: - Update logic `verify.yml` - Fix/change option `KbdInteractiveAuthentication` --- README.md | 2 +- defaults/main/sshd.yml | 2 +- molecule/default/verify.yml | 114 ++++++++++++------------------- templates/etc/ssh/sshd_config.j2 | 6 +- 4 files changed, 51 insertions(+), 73 deletions(-) diff --git a/README.md b/README.md index 459db00d..5735a432 100644 --- a/README.md +++ b/README.md @@ -473,7 +473,7 @@ sshd_ca_signature_algorithms: - rsa-sha2-256 - rsa-sha2-512 - ssh-rsa -sshd_challenge_response_authentication: false +sshd_kbd_interactive_authentication: false sshd_ciphers: - chacha20-poly1305@openssh.com - aes256-gcm@openssh.com diff --git a/defaults/main/sshd.yml b/defaults/main/sshd.yml index 6de918bf..37cdc416 100644 --- a/defaults/main/sshd.yml +++ b/defaults/main/sshd.yml @@ -19,7 +19,7 @@ sshd_ca_signature_algorithms: - rsa-sha2-256 - rsa-sha2-512 - ssh-rsa -sshd_challenge_response_authentication: false +sshd_kbd_interactive_authentication: false sshd_ciphers: - chacha20-poly1305@openssh.com - aes256-gcm@openssh.com diff --git a/molecule/default/verify.yml b/molecule/default/verify.yml index b78df3a9..f5db4ca3 100644 --- a/molecule/default/verify.yml +++ b/molecule/default/verify.yml @@ -229,30 +229,49 @@ - name: Set sshd_config_parameters ansible.builtin.set_fact: sshd_config_parameters: + - "{{ 'AcceptEnv ' + sshd_accept_env if (sshd_accept_env is defined and sshd_accept_env | length != 0)}}" - AddressFamily {{ 'inet' if (disable_ipv6 | bool) else 'any' }} - AllowGroups vagrant sudo - AllowAgentForwarding {{ 'yes' if (sshd_allow_agent_forwarding | bool) else 'no' }} - >- - {#- Set variable "tcp_fw" for ignore ansible-lint yaml[line-length] -#} - {%- set tcp_fw = sshd_allow_tcp_forwarding -%} - {%- if ssh_installed_version is version('6.2', '>=') -%} - AllowTcpForwarding {{ tcp_fw if (tcp_fw in ('yes', 'no', 'local', 'all', 'remote')) else ('yes' if (tcp_fw | bool) else 'no') }} + {%- if (ssh_installed_version is version('6.2', '>=')) -%} + {%- if (sshd_allow_tcp_forwarding in ('yes', 'no', 'local', 'all', 'remote')) -%} + AllowTcpForwarding {{ sshd_allow_tcp_forwarding }} {%- else -%} - AllowTcpForwarding {{ tcp_fw if (tcp_fw in ('yes', 'no')) else ('yes' if (tcp_fw | bool) else 'no') }} + AllowTcpForwarding {{ 'yes' if (sshd_allow_tcp_forwarding | bool) else 'no' }} {%- endif -%} + {%- else -%} + {%- if (sshd_allow_tcp_forwarding in ('yes', 'no')) -%} + AllowTcpForwarding {{ sshd_allow_tcp_forwarding }} + {%- else -%} + AllowTcpForwarding {{ 'yes' if (sshd_allow_tcp_forwarding | bool) else 'no' }} + {%- endif -%} + {%- endif -%} + - "{{ 'AuthenticationMethods ' + sshd_authentication_methods if (ssh_installed_version is version('6.2', '>='))}}" - Banner {{ sshd_banner if sshd_banner else 'none' }} - - ChallengeResponseAuthentication {{ 'yes' if (sshd_challenge_response_authentication | bool) else 'no' }} + - "{{ 'CASignatureAlgorithms ' + sshd_ca_signature_algorithms | join(',') if (not crypto_policies_config or not set_crypto_policy)}}" + - "{{ 'Ciphers ' + sshd_ciphers | join(',') if (not crypto_policies_config or not set_crypto_policy)}}" - ClientAliveCountMax {{ sshd_client_alive_count_max | int }} - ClientAliveInterval {{ sshd_client_alive_interval | int }} - Compression {{ 'yes' if (sshd_compression | bool) else 'no' }} + - "{{ 'DebianBanner ' + ('yes' if (sshd_debian_banner | bool) else 'no') if (ansible_facts.os_family == 'Debian')}}" - GSSAPIAuthentication {{ 'yes' if (sshd_gssapi_authentication | bool) else 'no' }} - GSSAPICleanupCredentials yes - HostbasedAuthentication {{ 'yes' if (sshd_hostbased_authentication | bool) else 'no' }} + - "{{ 'HostKeyAlgorithms ' + sshd_host_key_algorithms | join(',') if (not crypto_policies_config or not set_crypto_policy)}}" - IgnoreRhosts {{ 'yes' if (sshd_ignore_rhosts | bool) else 'no' }} - IgnoreUserKnownHosts {{ 'yes' if (sshd_ignore_user_known_hosts | bool) else 'no' }} + - >- + {%- if ssh_installed_version is version('8.7', '>=') -%} + KbdInteractiveAuthentication {{ 'yes' if (sshd_kbd_interactive_authentication | bool) else 'no' }} + {%- else -%} + ChallengeResponseAuthentication {{ 'yes' if (sshd_kbd_interactive_authentication | bool) else 'no' }} + {%- endif -%} - KerberosAuthentication {{ 'yes' if (sshd_kerberos_authentication | bool) else 'no' }} + - "{{ 'KexAlgorithms ' + sshd_kex_algorithms | join(',') if (not crypto_policies_config or not set_crypto_policy)}}" - LogLevel {{ sshd_log_level }} - LoginGraceTime {{ sshd_login_grace_time | int }} + - "{{ 'MACs ' + sshd_macs | join(',') if (not crypto_policies_config or not set_crypto_policy)}}" - MaxAuthTries {{ sshd_max_auth_tries | int }} - MaxSessions {{ sshd_max_sessions | int }} - MaxStartups {{ sshd_max_startups }} @@ -263,81 +282,36 @@ - PermitUserEnvironment {{ 'yes' if (sshd_permit_user_environment | bool) else 'no' }} - PrintLastLog {{ 'yes' if (sshd_print_last_log | bool) else 'no' }} - PrintMotd {{ 'yes' if (sshd_print_motd | bool) else 'no' }} + - "{{ 'Protocol 2' if (ssh_installed_version is version('7.6', '<'))}}" - PubkeyAuthentication yes - RekeyLimit {{ sshd_rekey_limit }} + - "{{ 'RequiredRSASize ' + (sshd_required_rsa_size | string) if (ssh_installed_version is version('9.1', '>'))}}" - StrictModes {{ 'yes' if (sshd_strict_modes | bool) else 'no' }} + - "{{ 'Subsystem sftp ' + sshd_sftp_subsystem if (sshd_sftp_enabled | bool)}}" - SyslogFacility {{ sshd_syslog_facility }} - TCPKeepAlive {{ 'yes' if (sshd_tcp_keep_alive | bool) else 'no' }} - UseDNS {{ 'yes' if (sshd_use_dns | bool) else 'no' }} + - "{{ 'UseLogin no' if (ssh_installed_version is version('7.4', '<'))}}" - UsePAM {{ 'yes' if (sshd_use_pam | bool) else 'no' }} + - >- + {%- if ssh_installed_version is version('7.5', '<') -%} + {%- if sshd_use_privilege_separation in ('yes', 'no', 'sandbox') -%} + UsePrivilegeSeparation {{ sshd_use_privilege_separation }} + {%- else -%} + UsePrivilegeSeparation {{ 'yes' if (sshd_use_privilege_separation | bool) else 'no' }} + {%- endif -%} + {%- endif -%} - X11Forwarding {{ 'yes' if (sshd_x11_forwarding | bool) else 'no' }} - X11UseLocalhost yes - - name: Set sshd_config_parameters AcceptEnv + - name: Set repeating parameters and clear empty values in sshd_config_parameters + vars: + _hostkey: "{{ ['HostKey '] | product(sshd_host_keys_files) | map('join') | list }}" + _listenaddress: "{{ ['ListenAddress '] | product(sshd_listen) | map('join') | list }}" + _port: "{{ ['Port '] | product(sshd_ports) | map('join') | list }}" ansible.builtin.set_fact: - sshd_config_parameters: "{{ sshd_config_parameters + ['AcceptEnv ' + sshd_authentication_methods] }}" - when: sshd_accept_env is defined and sshd_accept_env | length != 0 - - - name: Set sshd_config_parameters AuthenticationMethods - ansible.builtin.set_fact: - sshd_config_parameters: "{{ sshd_config_parameters + ['AuthenticationMethods ' + sshd_authentication_methods] }}" - when: ssh_installed_version is version('6.2', '>=') - - - name: Set sshd_config_parameters DebianBanner - ansible.builtin.set_fact: - sshd_config_parameters: "{{ sshd_config_parameters + ['DebianBanner ' + ('yes' if (sshd_debian_banner | bool) else 'no')] }}" - when: ansible_facts.os_family == 'Debian' - - - name: Set sshd_config_parameters HostKey - ansible.builtin.set_fact: - sshd_config_parameters: "{{ sshd_config_parameters + ['HostKey ' + item] }}" - loop: "{{ sshd_host_keys_files }}" - - - name: Set sshd_config_parameters ListenAddress - ansible.builtin.set_fact: - sshd_config_parameters: "{{ sshd_config_parameters + ['ListenAddress ' + item] }}" - loop: "{{ sshd_listen }}" - - - name: Set sshd_config_parameters Port - ansible.builtin.set_fact: - sshd_config_parameters: "{{ sshd_config_parameters + ['Port ' + (item | string)] }}" - loop: "{{ sshd_ports }}" - - - name: Set sshd_config_parameters Protocol - ansible.builtin.set_fact: - sshd_config_parameters: "{{ sshd_config_parameters + ['Protocol 2'] }}" - when: ssh_installed_version is version('7.6', '<') - - - name: Set sshd_config_parameters RequiredRSASize - ansible.builtin.set_fact: - sshd_config_parameters: "{{ sshd_config_parameters + ['RequiredRSASize ' + (sshd_required_rsa_size | string)] }}" - when: ssh_installed_version is version('9.1', '>') - - - name: Set sshd_config_parameters Subsystem - ansible.builtin.set_fact: - sshd_config_parameters: "{{ sshd_config_parameters + ['Subsystem sftp ' + sshd_sftp_subsystem] }}" - when: sshd_sftp_enabled | bool - - - name: Set sshd_config_parameters UseLogin - ansible.builtin.set_fact: - sshd_config_parameters: "{{ sshd_config_parameters + ['UseLogin no'] }}" - when: ssh_installed_version is version('7.4', '<') - - - name: Set sshd_config_parameters UsePrivilegeSeparation - ansible.builtin.set_fact: - sshd_config_parameters: "{{ sshd_config_parameters + ['UsePrivilegeSeparation ' + sshd_use_privilege_separation if (sshd_use_privilege_separation in ('yes', 'no', 'sandbox')) else ('yes' if (sshd_use_privilege_separation | bool) else 'no')] }}" # noqa yaml[line-length] - when: ssh_installed_version is version('7.5', '<') - - - name: Verify sshd runtime ciphers and algorithms - ansible.builtin.set_fact: - sshd_config_parameters: "{{ sshd_config_parameters + [item] }}" - when: not crypto_policies_config or not set_crypto_policy - loop: - - CASignatureAlgorithms {{ sshd_ca_signature_algorithms | join(',') }} - - Ciphers {{ sshd_ciphers | join(',') }} - - HostKeyAlgorithms {{ sshd_host_key_algorithms | join(',') }} - - KexAlgorithms {{ sshd_kex_algorithms | join(',') }} - - MACs {{ sshd_macs | join(',') }} + sshd_config_parameters: + "{{ (sshd_config_parameters + _hostkey + _listenaddress + _port) | select() }}" - name: Verify sshd configuration become: true diff --git a/templates/etc/ssh/sshd_config.j2 b/templates/etc/ssh/sshd_config.j2 index 98a0ce97..7ee7e9fc 100644 --- a/templates/etc/ssh/sshd_config.j2 +++ b/templates/etc/ssh/sshd_config.j2 @@ -72,7 +72,11 @@ AuthenticationMethods {{ sshd_authentication_methods }} {% endif %} PasswordAuthentication {{ 'yes' if (sshd_password_authentication | bool) else 'no' }} PermitEmptyPasswords {{ 'yes' if (sshd_permit_empty_passwords | bool) else 'no' }} -ChallengeResponseAuthentication {{ 'yes' if (sshd_challenge_response_authentication | bool) else 'no' }} +{% if ssh_installed_version is version('8.7', '>=') %} +KbdInteractiveAuthentication {{ 'yes' if (sshd_kbd_interactive_authentication | bool) else 'no' }} +{% else %} +ChallengeResponseAuthentication {{ 'yes' if (sshd_kbd_interactive_authentication | bool) else 'no' }} +{% endif %} KerberosAuthentication {{ 'yes' if (sshd_kerberos_authentication | bool) else 'no' }} GSSAPIAuthentication {{ 'yes' if (sshd_gssapi_authentication | bool) else 'no' }} GSSAPICleanupCredentials yes From 92bfbf5cfd998acca43e05953914bc2bf970b1d2 Mon Sep 17 00:00:00 2001 From: cleberb Date: Wed, 11 Oct 2023 16:50:42 -0300 Subject: [PATCH 10/12] Remove umask of sftp --- README.md | 4 ++-- defaults/main/sshd.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5735a432..577acd79 100644 --- a/README.md +++ b/README.md @@ -544,7 +544,7 @@ sshd_sftp_enabled: true sshd_sftp_only_chroot: true sshd_sftp_only_chroot_dir: '%h' sshd_sftp_only_group: '' -sshd_sftp_subsystem: internal-sftp -f LOCAL6 -l INFO -u 0027 +sshd_sftp_subsystem: internal-sftp -f LOCAL6 -l INFO sshd_strict_modes: true sshd_syslog_facility: AUTH sshd_tcp_keep_alive: false @@ -660,7 +660,7 @@ sshd_match_ports: `sshd_print_pam_motd` specifies whether printing of the MOTD via pam (Debian and Ubuntu). Default: `false`. `sshd_sftp_enabled` specifies whether enabled sftp configuration. Default: `true`. -`sshd_sftp_subsystem` Set external subsystem for file transfer daemon. Default: `internal-sftp -f LOCAL6 -l INFO -u 0027`. +`sshd_sftp_subsystem` Set external subsystem for file transfer daemon. Default: `internal-sftp -f LOCAL6 -l INFO`. `sshd_sftp_only_group` specifies the name of the group that will have access restricted to the sftp service only. Default: `""`. `sshd_sftp_only_chroot` specifies group access will be via chroot isolation. Default: `true`. `sshd_sftp_only_chroot_dir` specifies the chroot directory. Accepts the tokens `%%` (a literal `%`), `%h` (home directory of the user), and `%u` (username). Default: `"%h"`. diff --git a/defaults/main/sshd.yml b/defaults/main/sshd.yml index 37cdc416..41a132b2 100644 --- a/defaults/main/sshd.yml +++ b/defaults/main/sshd.yml @@ -90,7 +90,7 @@ sshd_sftp_enabled: true sshd_sftp_only_chroot: true sshd_sftp_only_chroot_dir: '%h' sshd_sftp_only_group: '' -sshd_sftp_subsystem: internal-sftp -f LOCAL6 -l INFO -u 0027 +sshd_sftp_subsystem: internal-sftp -f LOCAL6 -l INFO sshd_strict_modes: true sshd_syslog_facility: AUTH sshd_tcp_keep_alive: false From cf4db9761e5e108db3adf0fec41c7bc972a62765 Mon Sep 17 00:00:00 2001 From: cleberb Date: Fri, 13 Oct 2023 17:54:59 -0300 Subject: [PATCH 11/12] Fix verify sshd runtime --- molecule/default/verify.yml | 43 +++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/molecule/default/verify.yml b/molecule/default/verify.yml index f5db4ca3..bd10e6a8 100644 --- a/molecule/default/verify.yml +++ b/molecule/default/verify.yml @@ -337,6 +337,43 @@ loop: "{{ sshd_config_parameters }}" when: sshd_config_directory.stat.exists + - name: Set parameters for runtime check + ansible.builtin.set_fact: + sshd_config_parameters_runtime: >- + {{ + sshd_config_parameters_runtime | default([]) + + [(item.split(' ')[0] | lower) + ' ' + (item.split(' ')[1:] | join(' '))] + }} + loop: "{{ sshd_config_parameters }}" + + - name: Set multiple parameters in runtime checking + ansible.builtin.set_fact: + sshd_config_parameters_runtime: >- + {{ + ( sshd_config_parameters_runtime | reject('regex', '^' + item + ' ') | list ) + + ( [item + ' '] | + product( sshd_config_parameters_runtime | + select('match', '^' + item + ' ') | + map('split', ' ', 1) | + map('last') | + map('split', ' ') | + unique | + flatten ) | + map('join') | list ) + }} + loop: + - allowgroups + - acceptenv + + - name: Ignore parameters for runtime check + ansible.builtin.set_fact: + sshd_config_parameters_runtime: "{{ (sshd_config_parameters_runtime | reject('regex', '^' + item + ' ') | list) }}" + loop: + # rekeylimit: runtime returns values only in bytes and seconds, having to treat these values would be a lot of work. + - rekeylimit + # listenaddress: runtime returns values addresses and ports(Ex: 0.0.0.0:22), ports is optional and can have multiple values. + - listenaddress + - name: Verify sshd runtime configuration become: true environment: @@ -345,10 +382,8 @@ check_mode: false register: sshd_config changed_when: false - failed_when: >- - {%- set lower_parameter = item.split( )[0] | lower -%} - {{ ( item | regex_replace('^[^\ ]+', lower_parameter) ) not in sshd_config.stdout_lines }} - loop: "{{ (sshd_config_parameters | reject('regex', 'Allowgroups ') | list) + ['allowgroups vagrant', 'allowgroups sudo'] }}" + failed_when: item not in sshd_config.stdout_lines + loop: "{{ sshd_config_parameters_runtime }}" - name: Verify ssh client configuration become: true From 5bdf999c00acab472ca2dcb6dc1b0c2a442b2d00 Mon Sep 17 00:00:00 2001 From: cleberb Date: Mon, 16 Oct 2023 09:53:38 -0300 Subject: [PATCH 12/12] Ignore `debianbanner` for runtime check --- molecule/default/verify.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/molecule/default/verify.yml b/molecule/default/verify.yml index bd10e6a8..f431ff3a 100644 --- a/molecule/default/verify.yml +++ b/molecule/default/verify.yml @@ -369,10 +369,12 @@ ansible.builtin.set_fact: sshd_config_parameters_runtime: "{{ (sshd_config_parameters_runtime | reject('regex', '^' + item + ' ') | list) }}" loop: - # rekeylimit: runtime returns values only in bytes and seconds, having to treat these values would be a lot of work. - - rekeylimit + # debianbanner: not show in runtime. + - debianbanner # listenaddress: runtime returns values addresses and ports(Ex: 0.0.0.0:22), ports is optional and can have multiple values. - listenaddress + # rekeylimit: runtime returns values only in bytes and seconds, having to treat these values would be a lot of work. + - rekeylimit - name: Verify sshd runtime configuration become: true