Bug 1966711

Summary: Unable to set sshd_hostkey_group and sshd_hostkey_mode
Product: Red Hat Enterprise Linux 8 Reporter: Brian Smith <briasmit>
Component: rhel-system-rolesAssignee: Rich Megginson <rmeggins>
Status: CLOSED ERRATA QA Contact: David Jež <djez>
Severity: unspecified Docs Contact: Eliane Ramos Pereira <elpereir>
Priority: unspecified    
Version: 8.4CC: djez, elpereir, jjelen, lmanasko, nhosoi, spetrosi
Target Milestone: beta   
Target Release: 8.5   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard: role:sshd role:ssh
Fixed In Version: rhel-system-roles-1.4.0-1.el8 Doc Type: Bug Fix
Doc Text:
.`sshd_hostkey_group` and `sshd_hostkey_mode` variables now configurable in the playbook Previously, the `sshd_hostkey_group` and `sshd_hostkey_mode` variables were unintentionally defined in both `defaults` and `vars` files. Consequently, users were unable to configure those variables in the playbook. With this fix, the `sshd_hostkey_group` is renamed to `pass:[__sshd_hostkey_group]` and `sshd_hostkey_mode` to `pass:[__sshd_hostkey_mode]` for defining the constant value in the `vars` files. In the `default` file, `sshd_hostkey_group` is set to `pass:[__sshd_hostkey_group]` and `sshd_hostkey_mode` to `pass:[__sshd_hostkey_mode]`. As a result, users can now configure the `sshd_hostkey_group` and `sshd_hostkey_mode` variables in the playbook.
Story Points: ---
Clone Of:
: 1978745 (view as bug list) Environment:
Last Closed: 2021-11-09 17:45:29 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On:    
Bug Blocks: 1978745    

Description Brian Smith 2021-06-01 17:50:17 UTC
Description of problem:
The sshd_hostkey_group and sshd_hostkey_mode variables are not working as expected. 


Version-Release number of selected component (if applicable):
rhel-system-roles-1.0.1-1.el8.noarch


How reproducible:
Every time


Steps to Reproduce:
$ cat test.yml 
- hosts: all
  vars:
    sshd_hostkey_group: root
    sshd_hostkey_mode: 0600

  roles:
    - role: redhat.rhel_system_roles.sshd


Run this playbook on RHEL 8 host.  


Actual results:
TASK [redhat.rhel_system_roles.sshd : Make sure private hostkeys have expected permissions] **********************************************************************************************************************************************************************************************************************************
ok: [rhel8-server1] => (item=/etc/ssh/ssh_host_rsa_key)
ok: [rhel8-server1] => (item=/etc/ssh/ssh_host_ecdsa_key)
ok: [rhel8-server1] => (item=/etc/ssh/ssh_host_ed25519_key)


However, the group and permissions do not match the variables I had defined:

$ ssh rhel8-server1 ls -al /etc/ssh/ssh_host_rsa_key /etc/ssh/ssh_host_ecdsa_key /etc/ssh/ssh_host_ed25519_key
-rw-r-----. 1 root ssh_keys  480 Mar 29 18:57 /etc/ssh/ssh_host_ecdsa_key
-rw-r-----. 1 root ssh_keys  387 Mar 29 18:57 /etc/ssh/ssh_host_ed25519_key
-rw-r-----. 1 root ssh_keys 2578 Mar 29 18:57 /etc/ssh/ssh_host_rsa_key



Expected results:
The group and permission on the keys is updated to match the variable values.


Additional info:
sshd_hostkey_group and sshd_hostkey_mode might be getting overridden here:

$ grep sshd_hostkey /usr/share/ansible/roles/rhel-system-roles.sshd/vars/*
/usr/share/ansible/roles/rhel-system-roles.sshd/vars/Fedora_31.yml:sshd_hostkey_group: ssh_keys
/usr/share/ansible/roles/rhel-system-roles.sshd/vars/Fedora_31.yml:sshd_hostkey_mode: "0640"
/usr/share/ansible/roles/rhel-system-roles.sshd/vars/Fedora.yml:sshd_hostkey_group: ssh_keys
/usr/share/ansible/roles/rhel-system-roles.sshd/vars/Fedora.yml:sshd_hostkey_mode: "0640"
/usr/share/ansible/roles/rhel-system-roles.sshd/vars/RedHat_7.yml:sshd_hostkey_group: ssh_keys
/usr/share/ansible/roles/rhel-system-roles.sshd/vars/RedHat_7.yml:sshd_hostkey_mode: "0640"
/usr/share/ansible/roles/rhel-system-roles.sshd/vars/RedHat_8.yml:sshd_hostkey_group: ssh_keys
/usr/share/ansible/roles/rhel-system-roles.sshd/vars/RedHat_8.yml:sshd_hostkey_mode: "0640"

Comment 1 Rich Megginson 2021-06-01 18:21:00 UTC
@jjelen any ideas?

Comment 2 Jakub Jelen 2021-06-01 22:25:57 UTC
We have exactly this covered in the tests/tests_hostkeys.yml

Interestingly enough, it works if you use the "include_role" syntax:

- hosts: localhost
  tasks:
    - name: sshd
      include_role:
        name: redhat.rhel_system_roles.sshd
      vars:
        sshd_hostkey_group: root
        sshd_hostkey_mode: 0600

It is possible that I misunderstood the variable precedence in [1]. The vars/RedHat_8.yml is indeed loaded (and is supposed to get precedence 18 if I see right), but it is supposed to be possible to override with the variables from the playbook (it is with precedence 20), but it looks like plain vars in play have precedence only 12, which is probably the cause.

[1] https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable

Comment 3 Rich Megginson 2021-06-01 22:47:41 UTC
My bad - I should have seen this:

defaults/main.yml:sshd_hostkey_mode: "0600"
tasks/install.yml:        mode: "{{ sshd_hostkey_mode }}"
tests/tests_hostkeys.yml:        sshd_hostkey_mode: "0664"
vars/Fedora.yml:sshd_hostkey_mode: "0640"
vars/Fedora_31.yml:sshd_hostkey_mode: "0640"
vars/RedHat_7.yml:sshd_hostkey_mode: "0640"
vars/RedHat_8.yml:sshd_hostkey_mode: "0640"

This is bad.  You _cannot_ define variables in both defaults and vars files.  If you want to define the default values for variables that users should be able to provide and override.

The general pattern for this is that variables defined in vars files *must be role internal variables* and *must begin with two underscores* as in https://github.com/redhat-cop/automation-good-practices/tree/main/roles#naming-things

Then, in defaults/main.yml, you would set the default value to whatever is the default value for that platform, which was set in the vars/Platform.yml file.  So it would look like this:

defaults/main.yml:sshd_hostkey_mode: "{{ __ssh_hostkey_mode }}"
tasks/install.yml:        mode: "{{ sshd_hostkey_mode }}"
tests/tests_hostkeys.yml:        sshd_hostkey_mode: "0664"
vars/Fedora.yml:__sshd_hostkey_mode: "0640"
vars/Fedora_31.yml:__sshd_hostkey_mode: "0640"
vars/RedHat_7.yml:__sshd_hostkey_mode: "0640"
vars/RedHat_8.yml:__sshd_hostkey_mode: "0640"

Comment 4 Rich Megginson 2021-06-01 22:50:33 UTC
Looks like we have the same problem with the ssh role:

defaults/main.yml:ssh_drop_in_name: null
tasks/main.yml:        {% if ssh_drop_in_name is not none and __ssh_supports_drop_in %}
tasks/main.yml:        {% if ssh_drop_in_name is not none and __ssh_supports_drop_in %}
tasks/main.yml:          {{ __ssh_drop_in_template | replace("{name}", ssh_drop_in_name) }}
tests/tests_global_drop_in.yml:        ssh_drop_in_name: 99-last
vars/Fedora.yml:ssh_drop_in_name: "00-ansible"
vars/RedHat_8.yml:ssh_drop_in_name: "00-ansible"
vars/RedHat_9.yml:ssh_drop_in_name: "00-ansible"

This should be 

defaults/main.yml:ssh_drop_in_name: "{{ __ssh_drop_in_name }}"
tasks/main.yml:        {% if ssh_drop_in_name is not none and __ssh_supports_drop_in %}
tasks/main.yml:        {% if ssh_drop_in_name is not none and __ssh_supports_drop_in %}
tasks/main.yml:          {{ __ssh_drop_in_template | replace("{name}", ssh_drop_in_name) }}
tests/tests_global_drop_in.yml:        ssh_drop_in_name: 99-last
vars/Fedora.yml:__ssh_drop_in_name: "00-ansible"
vars/RedHat_8.yml:__ssh_drop_in_name: "00-ansible"
vars/RedHat_9.yml:__ssh_drop_in_name: "00-ansible"
vars/main.yml:__ssh_drop_in_name: null

Comment 5 Rich Megginson 2021-06-01 22:55:56 UTC
and in the sshd case you would have to define the platform defaults not specified elsewhere in vars/default.yml - so

vars/default.yml:__sshd_hostkey_mode: "0640"

because the sshd role uses a variant of the "first found" strategy like https://github.com/redhat-cop/automation-good-practices/tree/main/roles#platform-specific-tasks

whereas the ssh role and most of the other system roles use the "override" strategy like https://github.com/redhat-cop/automation-good-practices/tree/main/roles#platform-specific-variables

Comment 6 Jakub Jelen 2021-06-02 10:45:57 UTC
Thank you for checking. Looks like I misunderstood this somehow. I am afraid this will be in more places than only in case of hostkeys (certainly also sshd_config_*). But good that we have a reproducer.

I created the following changes for the sshd role including a testcases:

https://github.com/Jakuje/ansible-sshd/tree/precedence

Reading through the vars/ files, I see that sshd_packages is using similar schematics, but there is not much a good reason to use this variable as public. For now, it is mentioned in "Secondary role variables", where previously used to be the above variables too (but they should really be in public API).

Let me have a look to the ssh client role too.

Comment 7 Rich Megginson 2021-06-02 14:17:59 UTC
(In reply to Jakub Jelen from comment #6)
> Thank you for checking. Looks like I misunderstood this somehow. I am afraid
> this will be in more places than only in case of hostkeys (certainly also
> sshd_config_*). But good that we have a reproducer.
> 
> I created the following changes for the sshd role including a testcases:
> 
> https://github.com/Jakuje/ansible-sshd/tree/precedence
> 
> Reading through the vars/ files, I see that sshd_packages is using similar
> schematics, but there is not much a good reason to use this variable as
> public. For now, it is mentioned in "Secondary role variables", where
> previously used to be the above variables too (but they should really be in
> public API).

Typically the packages and services for the role will be defined in vars as role internal variables https://github.com/linux-system-roles/kernel_settings/blob/master/vars/default.yml - usually it doesn't make sense for the user to set these.
In some rare cases, if you want the user to be able to provide additional packages, you could have a variable defined in defaults/main.yml like "sshd_additional_packages: []", but usually the optional packages to install depend on some optional feature, in which case the role should know which packages go with which feature.  The cockpit role defines different package sets depending on which features are required by the user - 
https://github.com/linux-system-roles/cockpit/blob/master/vars/default.yml


> Let me have a look to the ssh client role too.

Comment 8 Jakub Jelen 2021-06-02 14:31:02 UTC
Would be glad for reviews on the PRs whether they make sense or if you notice some similar issues elsewhere:

https://github.com/linux-system-roles/ssh/pull/15
https://github.com/willshersystems/ansible-sshd/pull/159

Comment 20 errata-xmlrpc 2021-11-09 17:45:29 UTC
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory (rhel-system-roles bug fix and enhancement update), and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

https://access.redhat.com/errata/RHBA-2021:4159