diff --git a/defaults/main.yml b/defaults/main.yml index 0bf9b13..2aac1ae 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -1,38 +1,38 @@ # true if IPv6 is needed -network_ipv6_enable: false # sshd + ssh +network_ipv6_enable: false # sshd + ssh # true if sshd should be started and enabled -ssh_server_enabled: true # sshd +ssh_server_enabled: true # sshd # true if DNS resolutions are needed, look up the remote host name, defaults to false from 6.8, see: http://www.openssh.com/txt/release-6.8 -ssh_use_dns: false # sshd +ssh_use_dns: false # sshd # true or value if compression is needed -ssh_client_compression: false # ssh -ssh_compression: false # sshd +ssh_client_compression: false # ssh +ssh_compression: false # sshd # For which components (client and server) to generate the configuration for. Can be useful when running against a client without an SSH server. ssh_client_hardening: true # ssh ssh_server_hardening: true # sshd # If true, password login is allowed -ssh_client_password_login: false # ssh -ssh_server_password_login: false # sshd +ssh_client_password_login: false # ssh +ssh_server_password_login: false # sshd # ports on which ssh-server should listen -ssh_server_ports: ['22'] # sshd +ssh_server_ports: ['22'] # sshd # port to which ssh-client should connect -ssh_client_port: '22' # ssh +ssh_client_port: '22' # ssh # one or more ip addresses, to which ssh-server should listen to. Default is empty, but should be configured for security reasons! -ssh_listen_to: ['0.0.0.0'] # sshd +ssh_listen_to: ['0.0.0.0'] # sshd # Host keys to look for when starting sshd. -ssh_host_key_files: [] # sshd +ssh_host_key_files: [] # sshd # Specifies the host key algorithms that the server offers -ssh_host_key_algorithms: [] # sshd +ssh_host_key_algorithms: [] # sshd # specifies the time allowed for successful authentication to the SSH server ssh_login_grace_time: 30s @@ -43,13 +43,13 @@ ssh_max_auth_retries: 2 # Specifies the maximum number of open sessions permitted from a given connection ssh_max_sessions: 10 -ssh_client_alive_interval: 300 # sshd -ssh_client_alive_count: 3 # sshd +ssh_client_alive_interval: 300 # sshd +ssh_client_alive_count: 3 # sshd # Allow SSH Tunnels ssh_permit_tunnel: false -# Hosts with custom options. # ssh +# Hosts with custom options. # ssh # Example: # ssh_remote_hosts: # - names: ['example.com', 'example2.com'] @@ -59,23 +59,23 @@ ssh_permit_tunnel: false ssh_remote_hosts: [] # Set this to "without-password" or "yes" to allow root to login -ssh_permit_root_login: 'no' # sshd +ssh_permit_root_login: 'no' # sshd # false to disable TCP Forwarding. Set to true to allow TCP Forwarding. -ssh_allow_tcp_forwarding: 'no' # sshd +ssh_allow_tcp_forwarding: 'no' # sshd # false to disable binding forwarded ports to non-loopback addresses. Set to true to force binding on wildcard address. # Set to 'clientspecified' to allow the client to specify which address to bind to. -ssh_gateway_ports: false # sshd +ssh_gateway_ports: false # sshd # false to disable Agent Forwarding. Set to true to allow Agent Forwarding. -ssh_allow_agent_forwarding: false # sshd +ssh_allow_agent_forwarding: false # sshd # true if SSH has PAM support ssh_pam_support: true # false to disable pam authentication. -ssh_use_pam: true # sshd +ssh_use_pam: true # sshd # specify AuthenticationMethods sshd_authenticationmethods: 'publickey' @@ -87,29 +87,29 @@ ssh_gssapi_support: false ssh_kerberos_support: true # if specified, login is disallowed for user names that match one of the patterns. -ssh_deny_users: '' # sshd +ssh_deny_users: '' # sshd # if specified, login is allowed only for user names that match one of the patterns. -ssh_allow_users: '' # sshd +ssh_allow_users: '' # sshd # if specified, login is disallowed for users whose primary group or supplementary group list matches one of the patterns. -ssh_deny_groups: '' # sshd +ssh_deny_groups: '' # sshd # if specified, login is allowed only for users whose primary group or supplementary group list matches one of the patterns. -ssh_allow_groups: '' # sshd +ssh_allow_groups: '' # sshd # change default file that contains the public keys that can be used for user authentication. -ssh_authorized_keys_file: '' # sshd +ssh_authorized_keys_file: '' # sshd # specifies the file containing trusted certificate authorities public keys used to sign user certificates. -ssh_trusted_user_ca_keys_file: '' # sshd +ssh_trusted_user_ca_keys_file: '' # sshd # set the trusted certificate authorities public keys used to sign user certificates. # Example: # ssh_trusted_user_ca_keys: # - 'ssh-rsa ... comment1' # - 'ssh-rsa ... comment2' -ssh_trusted_user_ca_keys: [] # sshd +ssh_trusted_user_ca_keys: [] # sshd # specifies the file containing principals that are allowed. Only used if ssh_trusted_user_ca_keys_file is set. # Example: @@ -119,26 +119,26 @@ ssh_trusted_user_ca_keys: [] # sshd # replaced by the username of that user. After expansion, the path is taken to be # an absolute path or one relative to the user's home directory. # -ssh_authorized_principals_file: '' # sshd +ssh_authorized_principals_file: '' # sshd # list of hashes containing file paths and authorized principals. Only used if ssh_authorized_principals_file is set. # Example: # ssh_authorized_principals: # - { path: '/etc/ssh/auth_principals/root', principals: [ 'root' ], owner: "{{ ssh_owner }}", group: "{{ ssh_group }}", directoryowner: "{{ ssh_owner }}", directorygroup: "{{ ssh_group}}" } # - { path: '/etc/ssh/auth_principals/myuser', principals: [ 'masteradmin', 'webserver' ] } -ssh_authorized_principals: [] # sshd +ssh_authorized_principals: [] # sshd # false to disable printing of the MOTD -ssh_print_motd: false # sshd +ssh_print_motd: false # sshd # false to disable display of last login information -ssh_print_last_log: false # sshd +ssh_print_last_log: false # sshd # false to disable serving /etc/ssh/banner.txt before authentication is allowed -ssh_banner: false # sshd +ssh_banner: false # sshd # false to disable distribution version leakage during initial protocol handshake -ssh_print_debian_banner: false # sshd (Debian OS family only) +ssh_print_debian_banner: false # sshd (Debian OS family only) # true to enable sftp configuration sftp_enabled: false @@ -156,19 +156,19 @@ sftp_chroot_dir: /home/%u ssh_client_roaming: false # list of hashes (containing user and rules) to generate Match User blocks for. -ssh_server_match_user: false # sshd +ssh_server_match_user: false # sshd # list of hashes (containing group and rules) to generate Match Group blocks for. -ssh_server_match_group: false # sshd +ssh_server_match_group: false # sshd # list of hashes (containing addresses/subnets and rules) to generate Match Address blocks for. -ssh_server_match_address: false # sshd +ssh_server_match_address: false # sshd ssh_server_permit_environment_vars: 'no' ssh_server_accept_env_vars : '' # maximum number of concurrent unauthenticated connections to the SSH daemon -ssh_max_startups: '10:30:100' # sshd +ssh_max_startups: '10:30:100' # sshd ssh_ps53: 'yes' ssh_ps59: 'sandbox' diff --git a/handlers/main.yml b/handlers/main.yml index 2b39da5..7cc0fde 100644 --- a/handlers/main.yml +++ b/handlers/main.yml @@ -1,4 +1,6 @@ - name: restart sshd - service: name={{ sshd_service_name }} state=restarted - when: "(ssh_server_enabled|bool)" + service: + name: '{{ sshd_service_name }}' + state: restarted + when: ssh_server_enabled | bool become: yes diff --git a/tasks/ca_keys_and_principals.yml b/tasks/ca_keys_and_principals.yml index d628461..54b5635 100644 --- a/tasks/ca_keys_and_principals.yml +++ b/tasks/ca_keys_and_principals.yml @@ -1,5 +1,5 @@ --- -- name: Set ssh CA pub keys +- name: set ssh CA pub keys template: src: 'trusted_user_ca_keys.j2' dest: '{{ ssh_trusted_user_ca_keys_file }}' @@ -8,20 +8,20 @@ group: '{{ ssh_group }}' notify: restart sshd -- name: Create ssh authorized principals directories +- name: create ssh authorized principals directories file: path: '{{ item.path | dirname }}' mode: '{{ item.directorymode | default(0700) }}' owner: '{{ item.directoryowner | default(ssh_owner) }}' group: '{{ item.directorygroup | default(ssh_group) }}' state: directory - with_items: '{{ ssh_authorized_principals }}' + loop: '{{ ssh_authorized_principals }}' -- name: Set ssh authorized principals +- name: set ssh authorized principals template: src: 'authorized_principals.j2' dest: '{{ item.path }}' mode: '{{ item.filemode | default(0600) }}' owner: '{{ item.owner| default(ssh_owner) }}' group: '{{ item.group | default(ssh_group) }}' - with_items: '{{ ssh_authorized_principals }}' + loop: '{{ ssh_authorized_principals }}' diff --git a/tasks/crypto.yml b/tasks/crypto.yml index 364f6b7..acab54b 100644 --- a/tasks/crypto.yml +++ b/tasks/crypto.yml @@ -1,5 +1,4 @@ --- - - name: set hostkeys according to openssh-version set_fact: ssh_host_key_files: ['/etc/ssh/ssh_host_rsa_key', '/etc/ssh/ssh_host_ecdsa_key', '/etc/ssh/ssh_host_ed25519_key'] diff --git a/tasks/hardening.yml b/tasks/hardening.yml index 02be78f..3c51cc7 100644 --- a/tasks/hardening.yml +++ b/tasks/hardening.yml @@ -1,11 +1,11 @@ --- -- name: Set OS dependent variables +- name: set OS dependent variables include_vars: '{{ item }}' with_first_found: - - '{{ ansible_facts.distribution }}_{{ ansible_facts.distribution_major_version }}.yml' - - '{{ ansible_facts.distribution }}.yml' - - '{{ ansible_facts.os_family }}_{{ ansible_facts.distribution_major_version }}.yml' - - '{{ ansible_facts.os_family }}.yml' + - '{{ ansible_facts.distribution }}_{{ ansible_facts.distribution_major_version }}.yml' + - '{{ ansible_facts.distribution }}.yml' + - '{{ ansible_facts.os_family }}_{{ ansible_facts.distribution_major_version }}.yml' + - '{{ ansible_facts.os_family }}.yml' - name: get openssh-version command: ssh -V @@ -37,7 +37,7 @@ mode: '0600' owner: '{{ ssh_owner }}' group: '{{ ssh_group }}' - validate: '/usr/sbin/sshd -T -C user=root -C host=localhost -C addr=localhost -f %s' + validate: '/usr/sbin/sshd -T -C user=root -C host=localhost -C addr=localhost -C lport=22 -f %s' notify: restart sshd when: ssh_server_hardening | bool @@ -62,7 +62,7 @@ group: '{{ ssh_group }}' when: ssh_client_hardening | bool -- name: Check if {{ sshd_moduli_file }} contains weak DH parameters +- name: check if {{ sshd_moduli_file }} contains weak DH parameters shell: awk '$5 < {{ sshd_moduli_minimum }}' {{ sshd_moduli_file }} register: sshd_register_moduli changed_when: false diff --git a/tasks/main.yml b/tasks/main.yml index 32f9d02..a62da78 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -1,4 +1,3 @@ --- - - include_tasks: hardening.yml when: ssh_hardening_enabled | bool diff --git a/tasks/selinux.yml b/tasks/selinux.yml index 43b8d08..f08f5af 100644 --- a/tasks/selinux.yml +++ b/tasks/selinux.yml @@ -4,14 +4,13 @@ name: '{{ ssh_selinux_packages }}' state: present -- name: "authorize {{ ssh_server_ports }} ports for selinux" +- name: authorize {{ ssh_server_ports }} ports for selinux seport: ports: '{{ item }}' proto: tcp setype: ssh_port_t state: present - with_items: - - "{{ ssh_server_ports }}" + loop: '{{ ssh_server_ports }}' - name: check if ssh_password module is already installed shell: 'set -o pipefail && semodule -l | grep ssh_password' @@ -22,35 +21,41 @@ changed_when: false check_mode: no -# The following tasks only get executed when selinux is in state enforcing, UsePam is 'no' and the ssh_password module is installed. -# See this issue for more info: https://github.com/hardening-io/ansible-ssh-hardening/issues/23 -- block: - - name: Create selinux custom policy drop folder - file: - path: '{{ ssh_custom_selinux_dir }}' - state: 'directory' - owner: 'root' - group: 'root' - mode: '0750' - - - name: Distributing custom selinux policies - copy: - src: 'ssh_password' - dest: '{{ ssh_custom_selinux_dir }}' - - - name: check and compile policy - command: checkmodule -M -m -o {{ ssh_custom_selinux_dir }}/ssh_password.mod {{ ssh_custom_selinux_dir }}/ssh_password - - - name: create selinux policy module package - command: semodule_package -o {{ ssh_custom_selinux_dir }}/ssh_password.pp -m {{ ssh_custom_selinux_dir }}/ssh_password.mod - - - name: install selinux policy - command: semodule -i {{ ssh_custom_selinux_dir }}/ssh_password.pp - - when: not ssh_use_pam | bool and ssh_password_module.stdout.find('ssh_password') != 0 - -# The following tasks only get executed when selinux is installed, UsePam is 'yes' and the ssh_password module is installed. -# See http://danwalsh.livejournal.com/12333.html for more info +# The following tasks only get executed when selinux is in state enforcing, +# UsePam is 'no' and the ssh_password module is not installed. See this issue for +# more info: https://github.com/hardening-io/ansible-ssh-hardening/issues/23 +- when: + - not (ssh_use_pam | bool) + - ('ssh_password' not in ssh_password_module.stdout) + block: + - name: create selinux custom policy drop folder + file: + path: '{{ ssh_custom_selinux_dir }}' + state: 'directory' + owner: 'root' + group: 'root' + mode: '0750' + + - name: distributing custom selinux policies + copy: + src: 'ssh_password' + dest: '{{ ssh_custom_selinux_dir }}' + + - name: check and compile policy + command: checkmodule -M -m -o {{ ssh_custom_selinux_dir }}/ssh_password.mod {{ ssh_custom_selinux_dir }}/ssh_password + + - name: create selinux policy module package + command: semodule_package -o {{ ssh_custom_selinux_dir }}/ssh_password.pp -m {{ ssh_custom_selinux_dir }}/ssh_password.mod + + - name: install selinux policy + command: semodule -i {{ ssh_custom_selinux_dir }}/ssh_password.pp + + +# The following tasks only get executed when selinux is installed, UsePam is +# 'yes' and the ssh_password module is installed. See +# http://danwalsh.livejournal.com/12333.html for more info - name: remove selinux-policy when Pam is used, because Allowing sshd to read the shadow file directly is considered a potential security risk command: semodule -r ssh_password - when: ssh_use_pam | bool and ssh_password_module.stdout.find('ssh_password') == 0 + when: + - ssh_use_pam | bool + - ('ssh_password' in ssh_password_module.stdout) diff --git a/templates/authorized_principals.j2 b/templates/authorized_principals.j2 index 01ef844..be83791 100644 --- a/templates/authorized_principals.j2 +++ b/templates/authorized_principals.j2 @@ -1,4 +1,4 @@ -# {{ansible_managed|comment}} +{{ ansible_managed | comment }} {% for principal in item.principals %} {{ principal }} diff --git a/templates/openssh.conf.j2 b/templates/openssh.conf.j2 index ec0a714..c26957e 100644 --- a/templates/openssh.conf.j2 +++ b/templates/openssh.conf.j2 @@ -1,9 +1,10 @@ -# {{ansible_managed|comment}} +#jinja2: trim_blocks: "true", lstrip_blocks: "true" +{{ ansible_managed | comment }} # This is the ssh client system-wide configuration file. # See ssh_config(5) for more information on any settings used. Comments will be added only to clarify why a configuration was chosen. -{% if ssh_custom_options -%} +{% if ssh_custom_options %} # Custom configuration that overwrites default configuration # ========================================================== {% for line in ssh_custom_options %} @@ -17,14 +18,14 @@ # Address family should always be limited to the active network configuration. AddressFamily {{ 'any' if network_ipv6_enable else 'inet' }} -{% for host in ssh_remote_hosts -%} +{% for host in ssh_remote_hosts %} {% if loop.first %} # Host-specific configuration {% endif %} Host {{ host.names | join(' ') }} - {{ host.options | join("\n") | indent(2) }} + {{ host.options | join('\n') | indent(2) }} -{% endfor -%} +{% endfor %} # Global defaults for all Hosts Host * @@ -60,16 +61,16 @@ StrictHostKeyChecking ask # -- see: (http://net-ssh.github.com/net-ssh/classes/Net/SSH/Transport/CipherFactory.html) # -{# This outputs "Ciphers " if ssh_ciphers is defined or "#Ciphers" if ssh_ciphers is undefined #} -{{ "Ciphers "+ssh_ciphers| join(',') if ssh_ciphers else "Ciphers"|comment }} +{# This outputs 'Ciphers ' if ssh_ciphers is defined or '#Ciphers' if ssh_ciphers is undefined #} +{{ 'Ciphers ' ~ ssh_ciphers|join(',') if ssh_ciphers else 'Ciphers'|comment }} # **Hash algorithms** -- Make sure not to use SHA1 for hashing, unless it is really necessary. # Weak HMAC is sometimes required if older package versions are used # eg Ruby's Net::SSH at around 2.2.* doesn't support sha2 for hmac, so this will have to be set true in this case. # -{# This outputs "MACs " if ssh_macs is defined or "#MACs" if ssh_macs is undefined #} -{{ "MACs "+ssh_macs| join(',') if ssh_macs else "MACs"|comment }} +{# This outputs 'MACs ' if ssh_macs is defined or '#MACs' if ssh_macs is undefined #} +{{ 'MACs ' ~ ssh_macs|join(',') if ssh_macs else 'MACs'|comment }} # Alternative setting, if OpenSSH version is below v5.9 #MACs hmac-ripemd160 @@ -79,8 +80,8 @@ StrictHostKeyChecking ask # eg ruby's Net::SSH at around 2.2.* doesn't support sha2 for kex, so this will have to be set true in this case. # based on: https://bettercrypto.org/static/applied-crypto-hardening.pdf -{# This outputs "KexAlgorithms " if ssh_kex is defined or "#KexAlgorithms" if ssh_kex is undefined #} -{{ "KexAlgorithms "+ssh_kex| join(',') if ssh_kex else "KexAlgorithms"|comment }} +{# This outputs 'KexAlgorithms ' if ssh_kex is defined or '#KexAlgorithms' if ssh_kex is undefined #} +{{ 'KexAlgorithms ' ~ ssh_kex|join(',') if ssh_kex else 'KexAlgorithms'|comment }} # Disable agent forwarding, since local agent could be accessed through forwarded connection. ForwardAgent no diff --git a/templates/opensshd.conf.j2 b/templates/opensshd.conf.j2 index 564e289..738a842 100644 --- a/templates/opensshd.conf.j2 +++ b/templates/opensshd.conf.j2 @@ -1,12 +1,13 @@ -# {{ansible_managed|comment}} +#jinja2: trim_blocks: "true", lstrip_blocks: "true" +{{ ansible_managed | comment }} # This is the ssh client system-wide configuration file. # See sshd_config(5) for more information on any settings used. Comments will be added only to clarify why a configuration was chosen. -{% if sshd_custom_options -%} +{% if sshd_custom_options %} # Custom configuration that overwrites default configuration # ========================================================== -{% for line in sshd_custom_options -%} +{% for line in sshd_custom_options %} {{ line }} {% endfor %} {% endif %} @@ -18,26 +19,26 @@ PermitRootLogin {{ ssh_permit_root_login }} # Define which port sshd should listen to. Default to `22`. -{% for port in ssh_server_ports -%} -Port {{port}} +{% for port in ssh_server_ports %} +Port {{ port }} {% endfor %} # Address family should always be limited to the active network configuration. AddressFamily {{ 'any' if (network_ipv6_enable|bool) else 'inet' }} # Define which addresses sshd should listen to. Default to `0.0.0.0`, ie make sure you put your desired address in here, since otherwise sshd will listen to everyone. -{% for address in ssh_listen_to -%} -ListenAddress {{address}} +{% for address in ssh_listen_to %} +ListenAddress {{ address }} {% endfor %} # List HostKeys here. -{% for key in ssh_host_key_files -%} -HostKey {{key}} +{% for key in ssh_host_key_files %} +HostKey {{ key }} {% endfor %} # Specifies the host key algorithms that the server offers. {% if sshd_version is version('5.8', '>=') %} -{{ "HostKeyAlgorithms "+ssh_host_key_algorithms| join(',') if ssh_host_key_algorithms else "HostKeyAlgorithms"|comment }} +{{ "HostKeyAlgorithms " ~ ssh_host_key_algorithms|join(',') if ssh_host_key_algorithms else "HostKeyAlgorithms"|comment }} {% endif %} # Security configuration @@ -62,16 +63,16 @@ LogLevel {{ sshd_log_level }} # -- see: (http://net-ssh.github.com/net-ssh/classes/Net/SSH/Transport/CipherFactory.html) # -{# This outputs "Ciphers " if ssh_ciphers is defined or "#Ciphers" if ssh_ciphers is undefined #} -{{ "Ciphers "+ssh_ciphers| join(',') if ssh_ciphers else "Ciphers"|comment }} +{# This outputs 'Ciphers ' if ssh_ciphers is defined or '#Ciphers' if ssh_ciphers is undefined #} +{{ 'Ciphers ' ~ ssh_ciphers|join(',') if ssh_ciphers else 'Ciphers'|comment }} # **Hash algorithms** -- Make sure not to use SHA1 for hashing, unless it is really necessary. # Weak HMAC is sometimes required if older package versions are used # eg Ruby's Net::SSH at around 2.2.* doesn't support sha2 for hmac, so this will have to be set true in this case. # -{# This outputs "MACs " if ssh_macs is defined or "#MACs" if ssh_macs is undefined #} -{{ "MACs "+ssh_macs| join(',') if ssh_macs else "MACs"|comment }} +{# This outputs 'MACs ' if ssh_macs is defined or '#MACs' if ssh_macs is undefined #} +{{ 'MACs ' ~ ssh_macs|join(',') if ssh_macs else 'MACs'|comment }} # Alternative setting, if OpenSSH version is below v5.9 #MACs hmac-ripemd160 @@ -81,8 +82,8 @@ LogLevel {{ sshd_log_level }} # eg ruby's Net::SSH at around 2.2.* doesn't support sha2 for kex, so this will have to be set true in this case. # based on: https://bettercrypto.org/static/applied-crypto-hardening.pdf -{# This outputs "KexAlgorithms " if ssh_kex is defined or "#KexAlgorithms" if ssh_kex is undefined #} -{{ "KexAlgorithms "+ssh_kex| join(',') if ssh_kex else "KexAlgorithms"|comment }} +{# This outputs 'KexAlgorithms ' if ssh_kex is defined or '#KexAlgorithms' if ssh_kex is undefined #} +{{ 'KexAlgorithms ' ~ ssh_kex|join(',') if ssh_kex else 'KexAlgorithms'|comment }} # Authentication # -------------- @@ -92,13 +93,17 @@ LogLevel {{ sshd_log_level }} UseLogin no {% endif %} {% if sshd_version is version('7.5', '<') %} -UsePrivilegeSeparation {% if (ansible_facts.distribution == 'Debian' and ansible_facts.distribution_major_version <= '6') or (ansible_facts.os_family in ['Oracle Linux', 'RedHat'] and ansible_facts.distribution_major_version <= '6' and not ansible_facts.distribution == 'Amazon') -%}{{ssh_ps53}}{% else %}{{ssh_ps59}}{% endif %} +UsePrivilegeSeparation {{ + (ansible_facts.distribution == 'Debian' and ansible_facts.distribution_major_version <= '6') + or (ansible_facts.os_family in ['Oracle Linux', 'RedHat'] and ansible_facts.distribution_major_version <= '6' and not ansible_facts.distribution == 'Amazon') + | ternary(ssh_ps53, ssh_ps59) +}} {% endif %} -LoginGraceTime {{ssh_login_grace_time}} -MaxAuthTries {{ssh_max_auth_retries}} -MaxSessions {{ssh_max_sessions}} -MaxStartups {{ssh_max_startups}} +LoginGraceTime {{ ssh_login_grace_time }} +MaxAuthTries {{ ssh_max_auth_retries }} +MaxSessions {{ ssh_max_sessions }} +MaxStartups {{ ssh_max_startups }} # Enable public key authentication PubkeyAuthentication yes @@ -109,7 +114,7 @@ IgnoreUserKnownHosts yes HostbasedAuthentication no # Enable PAM to enforce system wide rules -{% if ssh_pam_support -%} +{% if ssh_pam_support %} UsePAM {{ 'yes' if (ssh_use_pam|bool) else 'no' }} {% endif %} @@ -124,7 +129,7 @@ PasswordAuthentication {{ 'yes' if (ssh_server_password_login|bool) else 'no' }} PermitEmptyPasswords no ChallengeResponseAuthentication {{ 'yes' if (ssh_challengeresponseauthentication|bool) else 'no' }} -{% if ssh_kerberos_support -%} +{% if ssh_kerberos_support %} # Only enable Kerberos authentication if it is configured. KerberosAuthentication no KerberosOrLocalPasswd no @@ -137,29 +142,29 @@ GSSAPIAuthentication {{ 'yes' if ssh_gssapi_support else 'no' }} GSSAPICleanupCredentials yes # In case you don't use PAM (`UsePAM no`), you can alternatively restrict users and groups here. For key-based authentication this is not necessary, since all keys must be explicitely enabled. -{% if ssh_deny_users -%} -DenyUsers {{ssh_deny_users}} +{% if ssh_deny_users %} +DenyUsers {{ ssh_deny_users }} {% endif %} -{% if ssh_allow_users -%} -AllowUsers {{ssh_allow_users}} +{% if ssh_allow_users %} +AllowUsers {{ ssh_allow_users }} {% endif %} -{% if ssh_deny_groups -%} -DenyGroups {{ssh_deny_groups}} +{% if ssh_deny_groups %} +DenyGroups {{ ssh_deny_groups }} {% endif %} -{% if ssh_allow_groups -%} -AllowGroups {{ssh_allow_groups}} +{% if ssh_allow_groups %} +AllowGroups {{ ssh_allow_groups }} {% endif %} -{% if ssh_authorized_keys_file -%} +{% if ssh_authorized_keys_file %} AuthorizedKeysFile {{ ssh_authorized_keys_file }} {% endif %} -{% if ssh_trusted_user_ca_keys_file -%} +{% if ssh_trusted_user_ca_keys_file %} TrustedUserCAKeys {{ ssh_trusted_user_ca_keys_file }} -{% if ssh_authorized_principals_file -%} +{% if ssh_authorized_principals_file %} AuthorizedPrincipalsFile {{ ssh_authorized_principals_file }} {% endif %} {% endif %} @@ -171,8 +176,8 @@ AuthorizedPrincipalsFile {{ ssh_authorized_principals_file }} TCPKeepAlive no # Manage `ClientAlive..` signals via interval and maximum count. This will periodically check up to a `..CountMax` number of times within `..Interval` timeframe, and abort the connection once these fail. -ClientAliveInterval {{ssh_client_alive_interval}} -ClientAliveCountMax {{ssh_client_alive_count}} +ClientAliveInterval {{ ssh_client_alive_interval }} +ClientAliveCountMax {{ ssh_client_alive_count }} # Disable tunneling PermitTunnel {{ 'yes' if (ssh_permit_tunnel|bool) else 'no' }} @@ -189,13 +194,13 @@ AllowTcpForwarding {{ ssh_allow_tcp_forwarding if (ssh_allow_tcp_forwarding in ( # no real advantage without denied shell access AllowAgentForwarding {{ 'yes' if (ssh_allow_agent_forwarding|bool) else 'no' }} -{% if ssh_gateway_ports|bool -%} +{% if ssh_gateway_ports|bool %} # Port forwardings are forced to bind to the wildcard address GatewayPorts yes -{% elif ssh_gateway_ports == 'clientspecified' -%} +{% elif ssh_gateway_ports == 'clientspecified' %} # Clients allowed to specify which address to bind port forwardings to GatewayPorts clientspecified -{% else -%} +{% else %} # Do not allow remote port forwardings to bind to non-loopback addresses. GatewayPorts no {% endif %} @@ -209,7 +214,7 @@ X11UseLocalhost yes PermitUserEnvironment {{ ssh_server_permit_environment_vars }} -{% if ssh_server_accept_env_vars -%} +{% if ssh_server_accept_env_vars %} AcceptEnv {{ ssh_server_accept_env_vars }} {% endif %} @@ -228,14 +233,14 @@ PrintLastLog {{ 'yes' if (ssh_print_last_log|bool) else 'no' }} Banner {{ '/etc/ssh/banner.txt' if (ssh_banner|bool) else 'none' }} -{% if ansible_facts.os_family == 'Debian' -%} +{% if ansible_facts.os_family == 'Debian' %} DebianBanner {{ 'yes' if (ssh_print_debian_banner|bool) else 'no' }} {% endif %} # Reject keys that are explicitly blacklisted RevokedKeys /etc/ssh/revoked_keys -{% if sftp_enabled -%} +{% if sftp_enabled %} # SFTP matching configuration # =========================== # Configuration, in case SFTP is used @@ -257,11 +262,11 @@ Match Group sftponly X11Forwarding no {% endif %} -{% if ssh_server_match_address -%} +{% if ssh_server_match_address %} # Address matching configuration # ============================ -{% for item in ssh_server_match_address -%} +{% for item in ssh_server_match_address %} Match Address {{ item.address }} {% for rule in item.rules %} {{ rule | indent(4) }} @@ -269,11 +274,11 @@ Match Address {{ item.address }} {% endfor %} {% endif %} -{% if ssh_server_match_group -%} +{% if ssh_server_match_group %} # Group matching configuration # ============================ -{% for item in ssh_server_match_group -%} +{% for item in ssh_server_match_group %} Match Group {{ item.group }} {% for rule in item.rules %} {{ rule | indent(4) }} @@ -281,11 +286,11 @@ Match Group {{ item.group }} {% endfor %} {% endif %} -{% if ssh_server_match_user -%} +{% if ssh_server_match_user %} # User matching configuration # =========================== -{% for item in ssh_server_match_user -%} +{% for item in ssh_server_match_user %} Match User {{ item.user }} {% for rule in item.rules %} {{ rule | indent(4) }} diff --git a/templates/revoked_keys.j2 b/templates/revoked_keys.j2 index 7156211..1a7eba6 100644 --- a/templates/revoked_keys.j2 +++ b/templates/revoked_keys.j2 @@ -1,4 +1,5 @@ -# {{ansible_managed|comment}} +{{ ansible_managed | comment }} + {% for key in ssh_server_revoked_keys %} -{{key}} +{{ key }} {% endfor %} diff --git a/templates/trusted_user_ca_keys.j2 b/templates/trusted_user_ca_keys.j2 index e6305dc..bd62ccd 100644 --- a/templates/trusted_user_ca_keys.j2 +++ b/templates/trusted_user_ca_keys.j2 @@ -1,5 +1,5 @@ -# {{ansible_managed|comment}} +{{ ansible_managed | comment }} -{% for item in ssh_trusted_user_ca_keys %} -{{ item }} +{% for key in ssh_trusted_user_ca_keys %} +{{ key }} {% endfor %} diff --git a/tests/default.yml b/tests/default.yml index f9b699c..634c5d7 100644 --- a/tests/default.yml +++ b/tests/default.yml @@ -7,26 +7,38 @@ ansible_python_interpreter: /usr/bin/python3 when: ansible_facts.distribution == 'Fedora' - - package: name="{{ packages }}" state=present + - package: + name: "{{ packages }}" + state: present vars: packages: - openssh-clients - openssh-server - libselinux-python ignore_errors: true - - apt: name="{{packages}}" state=present update_cache=true + + - apt: + name: "{{ packages }}" + state: present + update_cache: true vars: packages: - "openssh-client" - "openssh-server" ignore_errors: true + + - file: + path: "/var/run/sshd" + state: directory + + - pacman: name="{{packages}}" state=present update_cache=true vars: packages: - "openssh" - "awk" ignore_errors: true - - file: path="/var/run/sshd" state=directory + - name: create ssh host keys command: "ssh-keygen -A" when: not ((ansible_facts.os_family in ['Oracle Linux', 'RedHat']) and ansible_facts.distribution_major_version < '7') or diff --git a/tests/default_custom.yml b/tests/default_custom.yml index 5621005..36f31ca 100644 --- a/tests/default_custom.yml +++ b/tests/default_custom.yml @@ -7,26 +7,37 @@ ansible_python_interpreter: /usr/bin/python3 when: ansible_facts.distribution == 'Fedora' - - package: name="{{ packages }}" state=present + - package: + name: "{{ packages }}" + state: present vars: packages: - openssh-clients - openssh-server - libselinux-python ignore_errors: true - - apt: name="{{packages}}" state=present update_cache=true + + - apt: + name: "{{ packages }}" + state: present + update_cache: true vars: packages: - "openssh-client" - "openssh-server" ignore_errors: true + + - file: + path: "/var/run/sshd" + state: directory + - pacman: name="{{packages}}" state=present update_cache=true vars: packages: - "openssh" - "awk" ignore_errors: true - - file: path="/var/run/sshd" state=directory + - name: create ssh host keys command: "ssh-keygen -A" when: not ((ansible_facts.os_family in ['Oracle Linux', 'RedHat']) and ansible_facts.distribution_major_version < '7') or diff --git a/vars/Debian.yml b/vars/Debian.yml index df491f3..1ff2482 100644 --- a/vars/Debian.yml +++ b/vars/Debian.yml @@ -1,3 +1,4 @@ +--- sshd_service_name: ssh ssh_owner: root ssh_group: root diff --git a/vars/Fedora.yml b/vars/Fedora.yml index b42c9c2..c1246cf 100644 --- a/vars/Fedora.yml +++ b/vars/Fedora.yml @@ -1,3 +1,4 @@ +--- sshd_service_name: sshd ssh_owner: root ssh_group: root diff --git a/vars/FreeBSD.yml b/vars/FreeBSD.yml index 173b78a..ff092b4 100644 --- a/vars/FreeBSD.yml +++ b/vars/FreeBSD.yml @@ -1,3 +1,4 @@ +--- sshd_service_name: sshd ssh_owner: root ssh_group: wheel diff --git a/vars/OpenBSD.yml b/vars/OpenBSD.yml index 8e3c804..cb2a022 100644 --- a/vars/OpenBSD.yml +++ b/vars/OpenBSD.yml @@ -1,3 +1,4 @@ +--- sshd_service_name: sshd ssh_owner: root ssh_group: wheel diff --git a/vars/Oracle Linux.yml b/vars/Oracle Linux.yml index 5694cea..6abecca 100644 --- a/vars/Oracle Linux.yml +++ b/vars/Oracle Linux.yml @@ -1,3 +1,4 @@ +--- sshd_service_name: sshd ssh_owner: root ssh_group: root diff --git a/vars/RedHat.yml b/vars/RedHat.yml index 5694cea..6abecca 100644 --- a/vars/RedHat.yml +++ b/vars/RedHat.yml @@ -1,3 +1,4 @@ +--- sshd_service_name: sshd ssh_owner: root ssh_group: root diff --git a/vars/RedHat_8.yml b/vars/RedHat_8.yml index b42c9c2..c1246cf 100644 --- a/vars/RedHat_8.yml +++ b/vars/RedHat_8.yml @@ -1,3 +1,4 @@ +--- sshd_service_name: sshd ssh_owner: root ssh_group: root