ansible-sshd/tasks/install.yml
Jakub Jelen 860e533713 Introduce default hostkeys to check when using drop-in directory
Previously no hostkeys were checked if they were not present
in the generated configuration file. When the drop-in directory is
used, usually, there are no hostkeys in that file and no sanity
check for hostkeys was executed.

This amends the "auto" value for the hostkeys check to allow checking
for default hostkeys that are read by OpenSSH by default.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
2022-04-19 17:20:27 +02:00

239 lines
7.7 KiB
YAML

---
- name: OS is supported
meta: end_host
when:
- not __sshd_os_supported|bool
- name: Install ssh packages
package:
name: "{{ sshd_packages }}"
state: present
- name: Sysconfig configuration
template:
src: sysconfig.j2
dest: "/etc/sysconfig/sshd"
owner: "root"
group: "root"
mode: "600"
backup: "{{ sshd_backup }}"
when:
- sshd_sysconfig|bool
- __sshd_sysconfig_supports_use_strong_rng or __sshd_sysconfig_supports_crypto_policy
notify: reload_sshd
- name: Check the kernel FIPS mode
slurp:
src: /proc/sys/crypto/fips_enabled
register: __sshd_kernel_fips_mode
failed_when: false
when:
- __sshd_hostkeys_nofips | d([])
- name: Check the userspace FIPS mode
slurp:
src: /etc/system-fips
register: __sshd_userspace_fips_mode
failed_when: false
when:
- __sshd_hostkeys_nofips | d([])
- name: Make sure hostkeys are available and have expected permissions
vars: &share_vars
__sshd_fips_mode: >-
{{ __sshd_hostkeys_nofips | d([]) and
(__sshd_kernel_fips_mode.content | d('MAo=') | b64decode | trim == '1' or
__sshd_userspace_fips_mode.content | d('MAo=') | b64decode | trim != '0') }}
# This mimics the macro body_option() in sshd_config.j2
# The explicit to_json filter is needed for Python 2 compatibility
__sshd_hostkeys_from_config: >-
{% if sshd_HostKey is defined %}
{{ sshd_HostKey | to_json }}
{% elif sshd['HostKey'] is defined %}
{{ sshd['HostKey'] | to_json }}
{% elif __sshd_defaults['HostKey'] is defined and not sshd_skip_defaults %}
{% if __sshd_fips_mode %}
{{ __sshd_defaults['HostKey'] | difference(__sshd_hostkeys_nofips) | to_json }}
{% else %}
{{ __sshd_defaults['HostKey'] | to_json }}
{% endif %}
{% else %}
{{ [] | to_json }}
{% endif %}
__sshd_verify_hostkeys: >-
{% if not sshd_verify_hostkeys %}
{{ [] | to_json }}
{% elif sshd_verify_hostkeys == 'auto' %}
{% if not __sshd_hostkeys_from_config | from_json %}
{% if __sshd_fips_mode %}
{{ __sshd_verify_hostkeys_default | difference(__sshd_hostkeys_nofips) | to_json }}
{% else %}
{{ __sshd_verify_hostkeys_default | to_json }}
{% endif %}
{% elif __sshd_hostkeys_from_config | from_json is string %}
{{ [ __sshd_hostkeys_from_config | from_json ] | to_json }}
{% else %}
{{ __sshd_hostkeys_from_config }}
{% endif %}
{% else %}
{{ sshd_verify_hostkeys | to_json }}
{% endif %}
block:
- name: Make sure hostkeys are available
shell: |
set -eu
if set -o | grep pipefail 2>&1 /dev/null ; then
set -o pipefail
fi
{% if sshd_sysconfig %}
source /etc/sysconfig/sshd
{% endif %}
ssh-keygen -q -t {{ item | regex_search('(rsa|dsa|ecdsa|ed25519)') }} -f {{ item }} -C '' -N ''
args:
creates: "{{ item }}"
loop: "{{ __sshd_verify_hostkeys | from_json | list }}"
changed_when: false
- name: Make sure private hostkeys have expected permissions
file:
path: "{{ item }}"
owner: "{{ sshd_hostkey_owner }}"
group: "{{ sshd_hostkey_group }}"
mode: "{{ sshd_hostkey_mode }}"
loop: "{{ __sshd_verify_hostkeys | from_json | list }}"
- name: Apply configuration
vars:
<<: *share_vars
block:
- name: Create a temporary hostkey for syntax verification if needed
tempfile:
state: directory
register: sshd_test_hostkey
changed_when: false
when:
- __sshd_hostkeys_from_config | from_json == []
- name: Generate temporary hostkey
command: >
ssh-keygen -q -t rsa -f '{{ sshd_test_hostkey.path }}/rsa_key' -C '' -N ''
changed_when: false
when: sshd_test_hostkey.path is defined
- name: Make sure sshd runtime directory is present
file:
path: "{{ __sshd_runtime_directory }}"
state: directory
owner: root
group: root
mode: "{{ __sshd_runtime_directory_mode }}"
when:
- __sshd_runtime_directory | d(false)
- name: Create the complete configuration file
template:
src: sshd_config.j2
dest: "{{ sshd_config_file }}"
owner: "{{ sshd_config_owner }}"
group: "{{ sshd_config_group }}"
mode: "{{ sshd_config_mode }}"
validate: >-
{% if sshd_test_hostkey is defined and sshd_test_hostkey.path is defined %}
{{ sshd_binary }} -t -f %s -h {{ sshd_test_hostkey.path }}/rsa_key
{% else %}
{{ sshd_binary }} -t -f %s
{% endif %}
backup: "{{ sshd_backup }}"
notify: reload_sshd
when: sshd_config_namespace is none
- name: Update configuration file snippet
vars:
sshd_skip_defaults: true
blockinfile:
path: "{{ sshd_config_file }}"
owner: "{{ sshd_config_owner }}"
group: "{{ sshd_config_group }}"
mode: "{{ sshd_config_mode }}"
block: |
{{ __sshd_compat_match_all }}
{{ lookup('template', 'sshd_config_snippet.j2') }}
create: yes
marker: "# {mark} sshd system role managed block: namespace {{ sshd_config_namespace }}"
validate: >-
{% if sshd_test_hostkey is defined and sshd_test_hostkey.path is defined %}
{{ sshd_binary }} -t -f %s -h {{ sshd_test_hostkey.path }}/rsa_key
{% else %}
{{ sshd_binary }} -t -f %s
{% endif %}
backup: "{{ sshd_backup }}"
notify: reload_sshd
when: sshd_config_namespace is not none
rescue:
- name: re-raise the error
fail:
msg: "{{ ansible_failed_result }}"
always:
- name: Remove temporary host keys
file:
path: "{{ sshd_test_hostkey.path }}"
state: absent
changed_when: false
when: sshd_test_hostkey.path is defined
- name: Install systemd service files
block:
- name: Install service unit file
template:
src: "{{ sshd_service_template_service }}"
dest: "/etc/systemd/system/{{ sshd_service }}.service"
owner: root
group: root
mode: "0644"
notify: reload_sshd
- name: Install instanced service unit file
template:
src: "{{ sshd_service_template_at_service }}"
dest: "/etc/systemd/system/{{ sshd_service }}@.service"
owner: root
group: root
mode: "0644"
notify: reload_sshd
- name: Install socket unit file
template:
src: "{{ sshd_service_template_socket }}"
dest: "/etc/systemd/system/{{ sshd_service }}.socket"
owner: root
group: root
mode: "0644"
notify: reload_sshd
when: sshd_install_service|bool
- name: Service enabled and running
service:
name: "{{ sshd_service }}"
enabled: true
state: started
when:
- sshd_manage_service|bool
- ansible_virtualization_type|default(None) != 'kvm'
- ansible_virtualization_type|default(None) != 'docker'
- ansible_virtualization_type|default(None) != 'podman'
- ansible_virtualization_type|default(None) != 'container'
- ansible_virtualization_type|default(None) != 'containerd'
- ansible_virtualization_type|default(None) != 'VirtualPC' # for Github Actions
- ansible_connection != 'chroot'
# Due to ansible bug 21026, cannot use service module on RHEL 7
- name: Enable service in chroot
command: systemctl enable {{ sshd_service }} # noqa 303
when:
- ansible_connection == 'chroot'
- ansible_os_family == 'RedHat'
- ansible_distribution_major_version|int >= 7
- name: Register that this role has run
set_fact:
sshd_has_run: true
when: sshd_has_run is not defined