In the previous post, I covered how to get started with the sshd Red Hat Enterprise Linux (RHEL) System Role, which can help you automate and manage your SSH server configuration across your RHEL environment. This is important because having a properly configured and secured SSH server is a key component of securing a RHEL system.
I intentionally made the first part of this series very simple by specifying the role variables directly in the playbook. This requires editing the playbook any time the variables need to be updated or changed. A better method would be to store the role variables in the inventory, which I will cover in this post.
I also had the same SSH server configuration applied to all of my hosts in the previous post. However, in the real world, there are frequent exceptions to be made and servers with special requirements that need to deviate slightly from the usual configuration.
Thus, in this post, I will also cover how to override settings for servers that need a slightly different configuration.
Example environment overview
I’m using the same environment used in the first post, which includes an Red Hat Ansible control node, two RHEL 8 servers, and two RHEL 7 servers:
My desired SSH server configuration for these five servers is:
The /etc/ssh/sshd_config file should have the owner/group set to root/root, and the 0600 file permissions
The following options should be set in the sshd_config file:
However, two of the systems have special requirements, and should deviate from that configuration with the following differences:
On rhel8-server1 the PermitRootLogin should be set to yes.
On rhel7-server2 the PermitRootLogin and X11Forwarding should both be set to yes.
Setting up the inventory with the role variables
In part 1, I created the inventory file at sshd_playbook/inventory/inventory.yml with the following contents:
all: hosts: rhel8-server1.example.com: rhel8-server2.example.com: rhel7-server1.example.com: rhel7-server2.example.com: controlnode.example.com: ansible_connection: local
No additional changes are needed to the inventory.yml file. However, to define the general configuration outside of the playbook and to implement the special requirements for the servers mentioned above, I will need to create two additional directories under the inventory directory: group_vars and host_vars.
$ mkdir -p sshd_playbook/inventory/group_vars $ mkdir -p sshd_playbook/inventory/host_vars
The group_vars directory can be used to set variables at the group level and, in this example, we’ll be setting variables for the all group. The host_vars directory can be used to set variables at the host level and we’ll use this functionality to override the settings rhel8-server1.example.com and rhel7-server2.example.com need to deviate on.
I’ll create the sshd_playbook/inventory/group_vars/all.yml file to specify the role variables that should apply to all of the hosts with the following content:
sshd_config_owner: root sshd_config_group: root sshd_config_mode: 0600 sshd: X11Forwarding: false MaxAuthTries: 4 ClientAliveInterval: 300 LoginGraceTime: 60 AllowTcpForwarding: no PermitRootLogin: no MaxStartups: 10:30:60
Note that the sshd_config options we would like to be set are defined in the sshd dictionary variable. Simple variables named sshd_option (for example, sshd_PermitRootLogin) can also be used and these will override the configuration specified in the sshd dictionary variable.
Due to this, we can easily specify the deviated configuration options the rhel8-server1.example.com and rhel7-server2.example.com should have by creating files for each server under the sshd_playbook/inventory/host_vars directory. In these files we will define the sshd_option variables each host should have to override the global configuration specified in the all.yml group_vars file.
There will be a file for rhel8-server1 named sshd_playbook/inventory/host_vars/rhel8-server1.example.com.yml which contains:
In addition, there will be a file for rhel7-server2 named sshd_playbook/inventory/host_vars/rhel7-server2.example.com.yml which contains:
sshd_X11Forwarding: yes sshd_PermitRootLogin: yes
With this configuration, the rhel8-server1 and rhel7-server2 hosts will use the configuration specified in the all.yml file, with the exception of the options specified in each of their host_vars files, which will override just those settings for each host.
Creating and running the playbook
In part 1, the playbook contained the role variables. Now that these have been moved to the inventory, the role variables can be removed from the playbook, making it very short and simple.
The updated playbook at sshd_playbook/sshd.yml file will now only contain:
- hosts: all become: true roles: - role: redhat.rhel_system_roles.sshd
At this point I’m ready to run the playbook, which will apply our desired SSH server configuration on the five hosts.
I’ll change directory into the sshd_playbook directory and use the ansible-playbook command to run the playbook, specifying the playbook name and inventory file that should be used:
$ cd sshd_playbook $ ansible-playbook sshd.yml -i inventory/inventory.yml
The playbook runs and at the end a summary is shown:
I verified by checking the contents of the sshd_config file on a couple of the hosts:
$ ssh rhel7-server1.example.com sudo cat /etc/ssh/sshd_config # Ansible managed HostKey /etc/ssh/ssh_host_rsa_key HostKey /etc/ssh/ssh_host_ecdsa_key HostKey /etc/ssh/ssh_host_ed25519_key AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT AcceptEnv LC_IDENTIFICATION LC_ALL LANGUAGE AcceptEnv XMODIFIERS AllowTcpForwarding no AuthorizedKeysFile .ssh/authorized_keys ChallengeResponseAuthentication no ClientAliveInterval 300 GSSAPIAuthentication yes GSSAPICleanupCredentials no LoginGraceTime 60 MaxAuthTries 4 MaxStartups 10:30:60 PasswordAuthentication yes PermitRootLogin no Subsystem sftp /usr/libexec/openssh/sftp-server SyslogFacility AUTHPRIV UsePAM yes UsePrivilegeSeparation sandbox X11Forwarding no $ ssh rhel7-server2.example.com sudo cat /etc/ssh/sshd_config # Ansible managed HostKey /etc/ssh/ssh_host_rsa_key HostKey /etc/ssh/ssh_host_ecdsa_key HostKey /etc/ssh/ssh_host_ed25519_key AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT AcceptEnv LC_IDENTIFICATION LC_ALL LANGUAGE AcceptEnv XMODIFIERS AllowTcpForwarding no AuthorizedKeysFile .ssh/authorized_keys ChallengeResponseAuthentication no ClientAliveInterval 300 GSSAPIAuthentication yes GSSAPICleanupCredentials no LoginGraceTime 60 MaxAuthTries 4 MaxStartups 10:30:60 PasswordAuthentication yes PermitRootLogin yes Subsystem sftp /usr/libexec/openssh/sftp-server SyslogFacility AUTHPRIV UsePAM yes UsePrivilegeSeparation sandbox X11Forwarding yes
Note that there is a comment at the top of each of the files mentioning it is managed by Ansible. Also note that on rhel7-server2 the deviated configuration settings we specified for PermitRootLogin and X11Forwarding in the server’s host_vars file were properly set.
While the first part detailed a simple example of using the sshd RHEL System Role, this post covered how to move the role variables out of the playbook and included a more real world scenario where some servers need a slightly different configuration applied.
Review the list of available RHEL System Roles and start managing your RHEL servers in a more efficient, consistent and automated manner today.
Take RHEL System Roles for a quick test drive in our hands-on interactive lab environment that walks you through a common RHEL System Roles use case.
About the author
Brian Smith is a Product Manager at Red Hat focused on RHEL automation and management. He has been at Red Hat since 2018, previously working with Public Sector customers as a Technical Account Manager (TAM).