Chapter 1. Using secure communications between two systems with OpenSSH


Use OpenSSH to create secure communication between two systems. OpenSSH encrypts the connection. It protects remote login sessions from eavesdropping and intrusions.

1.1. SSH and OpenSSH

SSH (Secure Shell) is a program for remote machine login and command execution. The SSH protocol provides encrypted communication between two untrusted hosts over an insecure network. You can also forward X11 connections and arbitrary TCP/IP ports over the secure channel.

The SSH protocol reduces security threats when you use it for remote shell login or file copying. It prevents interception of communication between two systems. It also prevents impersonation of a particular host.

The SSH client and server use digital signatures to verify their identities. All communication between the client and server systems is encrypted.

A host key authenticates hosts in the SSH protocol. Host keys are cryptographic keys. They are generated automatically when OpenSSH starts for the first time or when the host boots for the first time.

OpenSSH is an implementation of the SSH protocol supported by Linux, UNIX, and similar operating systems. It includes the core files necessary for both the OpenSSH client and server. The OpenSSH suite consists of the following user-space tools:

  • ssh is a remote login program (SSH client).
  • sshd is an OpenSSH SSH daemon.
  • scp is a secure remote file copy program.
  • sftp is a secure file transfer program.
  • ssh-agent is an authentication agent for caching private keys.
  • ssh-add adds private key identities to ssh-agent.
  • ssh-keygen generates, manages, and converts authentication keys for ssh.
  • ssh-copy-id is a script that adds local public keys to the authorized_keys file on a remote SSH server.
  • ssh-keyscan gathers SSH public host keys.

For more information, use the man -k ssh command.

Note

In RHEL 9 and later, SFTP replaces SCP by default. SCP has security issues such as CVE-2020-15778.

You can force the use of the original SCP/RCP protocol if SFTP is unavailable or incompatible in your scenario. Use the scp command with the -O option.

The OpenSSH suite in RHEL supports only SSH version 2. It has an enhanced key-exchange algorithm. This algorithm is not vulnerable to exploits known in the older version 1.

Red Hat Enterprise Linux includes the openssh, openssh-server, and openssh-clients packages. These OpenSSH packages require the OpenSSL package openssl-libs. This package contains cryptographic libraries for securing data exchange.

OpenSSH is one of the core cryptographic subsystems of RHEL. It uses system-wide cryptographic policies. This ensures that weak cipher suites and cryptographic algorithms are disabled in the default configuration.

To modify the policy, you can:

  • Use the update-crypto-policies command to adjust the settings.
  • Manually opt out of the system-wide cryptographic policies.

The OpenSSH suite uses two sets of configuration files. One set is for client programs (ssh, scp, and sftp). Another set is for the server (the sshd daemon).

System-wide SSH configuration information is stored in the /etc/ssh/ directory. The /etc/ssh/ssh_config file contains the client configuration. The /etc/ssh/sshd_config file is the default OpenSSH server configuration file.

User-specific SSH configuration information is stored in ~/.ssh/. For a detailed list of OpenSSH configuration files, see the FILES section in the sshd(8) man page on your system.

1.2. Generating SSH key pairs

Generate an SSH key pair on your local system and copy the public key to the OpenSSH server to enable password-free login. Each user who wants to create a key must run this procedure.

To preserve generated key pairs after you reinstall the system, back up the ~/.ssh/ directory before you create new keys. After reinstalling, copy it back to your home directory. You can do this for all users on your system, including root.

Prerequisites

  • You are logged in as a user who wants to connect to the OpenSSH server by using keys.
  • The OpenSSH server is configured to allow key-based authentication.

Procedure

  1. Generate an ECDSA key pair:

    $ ssh-keygen -t ecdsa
    Generating public/private ecdsa key pair.
    Enter file in which to save the key (/home/<username>/.ssh/id_ecdsa):
    Enter passphrase (empty for no passphrase): <password>
    Enter same passphrase again: <password>
    Your identification has been saved in /home/<username>/.ssh/id_ecdsa.
    Your public key has been saved in /home/<username>/.ssh/id_ecdsa.pub.
    The key fingerprint is:
    SHA256:Q/x+qms4j7PCQ0qFd09iZEFHA+SqwBKRNaU72oZfaCI <username>@<localhost.example.com>
    The key's randomart image is:
    +---[ECDSA 256]---+
    |.oo..o=++        |
    |.. o .oo .       |
    |. .. o. o        |
    |....o.+...       |
    |o.oo.o +S .      |
    |.=.+.   .o       |
    |E.*+.  .  . .    |
    |.=..+ +..  o     |
    |  .  oo*+o.      |
    +----[SHA256]-----+

    Alternative: Instead of ECDSA, you can generate:

    • an RSA key pair by using the ssh-keygen command without any parameter
    • an Ed25519 key pair by entering the ssh-keygen -t ed25519 command

      Note that the Ed25519 algorithm is not FIPS-140-compliant, and OpenSSH does not work with Ed25519 keys in FIPS mode.

  2. Copy the public key to a remote machine:

    $ ssh-copy-id <username>@<ssh-server-example.com>
    /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
    <username>@<ssh-server-example.com>'s password:
    …
    Number of key(s) added: 1
    
    Now try logging into the machine, with: "ssh '<username>@<ssh-server-example.com>'" and check to make sure that only the key(s) you wanted were added.

    Replace <username>@<ssh-server-example.com> with your credentials.

    If you do not use ssh-agent, the command copies the most recently modified ~/.ssh/id*.pub public key. To use a different public-key file, or to prefer keys from files over keys stored in memory by ssh-agent, use the ssh-copy-id command with the -i option.

Verification

  1. Log in to the OpenSSH server by using the key file:

    $ ssh -o PreferredAuthentications=publickey <username>@<ssh-server-example.com>

To improve system security, enforce key-based authentication by disabling password authentication on your OpenSSH server.

Warning

If you disable password authentication without ensuring that key-based authentication works correctly, you can lock yourself out of the server. Test your SSH key authentication thoroughly before applying this configuration, and keep a current session open while testing to revert changes if necessary.

Prerequisites

  • The openssh-server package is installed.
  • The sshd daemon is running on the server.
  • You can already connect to the OpenSSH server by using a key.

    See the Generating SSH key pairs section for details.

Procedure

  1. Open the /etc/ssh/sshd_config configuration in a text editor, for example:

    # vi /etc/ssh/sshd_config
  2. Change the PasswordAuthentication option to no:

    PasswordAuthentication no
  3. On a system other than a new default installation, check that the PubkeyAuthentication parameter is either not set or set to yes.
  4. Set the KbdInteractiveAuthentication directive to no.

    The corresponding entry is commented out in the configuration file and the default value is yes.

  5. To use key-based authentication with NFS-mounted home directories, enable the use_nfs_home_dirs SELinux boolean:

    # setsebool -P use_nfs_home_dirs 1
  6. Reload the sshd daemon to apply the changes:

    # systemctl reload sshd
  7. If you are connected remotely, test the configuration by opening a new SSH session in a separate terminal while keeping your current session open. If the new connection fails, you can revert the changes in your existing session.

Verification

  1. Confirm that password authentication is disabled:

    # sshd -T | grep -i passwordauthentication
    passwordauthentication no
  2. Confirm that keyboard-interactive authentication is disabled:

    # sshd -T | grep -i kbdinteractiveauthentication
    kbdinteractiveauthentication no
  3. From a different system, attempt to connect using password authentication to verify it is rejected:

    $ ssh -o PreferredAuthentications=password <username>@<server>
    <username>@<server>: Permission denied (publickey).

    The connection is rejected because only public key authentication is allowed.

Use SSH keys stored on a smart card for authentication to add a physical layer of protection to your credentials. This method provides enhanced security against unauthorized access.

You can create and store ECDSA and RSA keys on a smart card and authenticate by the smart card on an OpenSSH client. Smart-card authentication replaces the default password authentication.

Prerequisites

  • On the client side, the opensc package is installed and the pcscd service is running.

Procedure

  1. List all keys provided by the OpenSC PKCS #11 module including their PKCS #11 URIs and save the output to the keys.pub file:

    $ ssh-keygen -D pkcs11: > keys.pub
  2. Transfer the public key to the remote server. Use the ssh-copy-id command with the keys.pub file created in the previous step:

    $ ssh-copy-id -f -i keys.pub <username@ssh-server-example.com>
  3. Connect to <ssh-server-example.com> by using the ECDSA key. You can use just a subset of the URI, which uniquely references your key, for example:

    $ ssh -i "pkcs11:id=%01?module-path=/usr/lib64/pkcs11/opensc-pkcs11.so" <ssh-server-example.com>
    Enter PIN for 'SSH key':
    [ssh-server-example.com] $

    Because OpenSSH uses the p11-kit-proxy wrapper and the OpenSC PKCS #11 module is registered to the p11-kit tool, you can simplify the previous command:

    $ ssh -i "pkcs11:id=%01" <ssh-server-example.com>
    Enter PIN for 'SSH key':
    [ssh-server-example.com] $

    If you skip the id= part of a PKCS #11 URI, OpenSSH loads all keys that are available in the proxy module. This can reduce the amount of typing required:

    $ ssh -i pkcs11: <ssh-server-example.com>
    Enter PIN for 'SSH key':
    [ssh-server-example.com] $
  4. Optional: You can use the same URI string in the ~/.ssh/config file to make the configuration permanent:

    $ cat ~/.ssh/config
    IdentityFile "pkcs11:id=%01?module-path=/usr/lib64/pkcs11/opensc-pkcs11.so"
    $ ssh <ssh-server-example.com>
    Enter PIN for 'SSH key':
    [ssh-server-example.com] $

    The ssh client utility now automatically uses this URI and the key from the smart card.

1.5. Making OpenSSH more secure

Harden your system security by modifying OpenSSH configurations, such as implementing stronger keys and restricting user access. This helps protect your server against various attacks.

To make SSH truly effective, prevent the use of insecure connection protocols and replace them with the OpenSSH suite. Otherwise, a user’s password might be protected by SSH for one session only, only to be captured later when logging in through Telnet. Also, disabling passwords for authentication and allowing only key pairs reduces the attack surface.

In RHEL 10, the PermitRootLogin option is set to prohibit-password by default. This enforces key-based authentication instead of passwords for logging in as root and reduces risk by preventing brute-force attacks.

Warning

Enabling logging in as the root user is not a secure practice because the administrator cannot audit which users run which privileged commands. For using administrative commands, log in and use sudo instead.

Generate only ECDSA or Ed25519 keys to use their security and performance advantages over older algorithms. You can also configure the OpenSSH server to disable the automatic generation of RSA host keys and enforce the use of stronger key types.

You can instruct the ssh-keygen command to generate Elliptic Curve Digital Signature Algorithm (ECDSA) or Edwards-Curve 25519 (Ed25519) keys by using the -t option. The ECDSA offers better performance than RSA at the equivalent symmetric key strength. It also generates shorter keys. The Ed25519 public-key algorithm is an implementation of twisted Edwards curves that is more secure and also faster than RSA, DSA, and ECDSA.

Important

The Ed25519 algorithm is not FIPS-140-compliant, and OpenSSH does not work with Ed25519 keys in FIPS mode.

Prerequisites

  • The openssh-server package is installed on your system.

Procedure

  1. To configure the host key creation in RHEL, use the sshd-keygen@.service instantiated service. For example, to disable the automatic creation of the RSA key type:

    # systemctl mask sshd-keygen@rsa.service
    Note

    In images with the cloud-init method enabled, the ssh-keygen units are automatically disabled. This is because the ssh-keygen template service can interfere with the cloud-init tool and cause problems with host key generation. To prevent these problems, the etc/systemd/system/sshd-keygen@.service.d/disable-sshd-keygen-if-cloud-init-active.conf drop-in configuration file disables the ssh-keygen units if cloud-init is running.

  2. Because OpenSSH creates RSA, ECDSA, and Ed25519 server host keys automatically if they are missing, remove the keys with less secure cryptography:

    # rm -f /etc/ssh/ssh_host_rsa_key
  3. To allow only a particular key type for SSH connections, uncomment the relevant line in /etc/ssh/sshd_config. For example, to allow only Ed25519 host keys, the corresponding lines must be as follows:

    # HostKey /etc/ssh/ssh_host_rsa_key
    # HostKey /etc/ssh/ssh_host_ecdsa_key
    HostKey /etc/ssh/ssh_host_ed25519_key
  4. Restart the sshd service:

    # systemctl restart sshd

Verification

  • Verify that only the configured host key types exist:

    # ls -l /etc/ssh/ssh_host_*_key

    The output shows only the key types you configured. If you enforce Ed25519 only, only ssh_host_ed25519_key files appear.

  • Verify the SSH server uses only the configured key types by connecting from a client:

    $ ssh -v <server> 2>&1 | grep "Server host key"
    Server host key: ssh-ed25519 SHA256:...

You can specify the cryptography configuration of your OpenSSH server either by using the /etc/ssh/sshd_config.d/ directory or by applying a custom system-wide cryptographic policy. This enables you to harden or loosen SSH connections depending on your scenario.

To override the system-wide cryptographic policies for your OpenSSH server, specify the cryptographic policy in a drop-in configuration file located in /etc/ssh/sshd_config.d/. Because the first match wins, name the file with a two-digit number prefix smaller than 50 and with a .conf suffix, for example, 49-crypto-policy-override.conf. This way, it lexicographically precedes the 50-redhat.conf file and overrides the default configuration.

See the sshd_config(5) man page for more information.

Prerequisites

  • The openssh-server package is installed.
  • The sshd daemon is running on the server.

Procedure

  1. Create a new configuration file with a name that lexicographically precedes 50-redhat.conf, for example:

    # touch /etc/ssh/sshd_config.d/49-crypto-policy-override.conf
  2. Open the file in a text editor, and specify ciphers and message authentication codes (MACs) you want to allow, for example:

    Ciphers aes256-gcm@openssh.com,aes128-gcm@openssh.com
    MACs hmac-sha2-512,hmac-sha2-256
  3. Save the changes, and reload the sshd service:

    # systemctl reload sshd

Verification

  • Check ciphers and MACs allowed on your OpenSSH server in the output of the sshd -T command:

    # sshd -T | grep -iE '(ciphers|macs)'

Next steps

1.5.3. Setting a non-default port for SSH

By default, the sshd daemon listens on TCP port 22. Changing the port reduces the exposure of the system to attacks based on automated network scanning on the default port and therefore increases security through obscurity.

Note

Changing the SSH port provides only limited security benefits. An attacker performing a full port scan can discover the service regardless of the port number. Real security improvements come from disabling password authentication, using key-based authentication, and implementing proper access controls.

Important

After changing the SSH port, update client configurations to use the new port. This includes:

  • user SSH configuration files (~/.ssh/config)
  • automation tools and scripts that connect to the server
  • monitoring systems and backup tools
  • load balancers and proxy configurations

Without these updates, connections to the server fail.

Prerequisites

  • Commands that start with the # command prompt require administrative privileges provided by sudo or root user access. For information on how to configure sudo access, see Enabling unprivileged users to run certain commands.
  • The policycoreutils-python-utils package is installed on your system.

Procedure

  1. Open the /etc/ssh/sshd_config configuration file in a text editor of your choice.
  2. Remove the # character before the Port directive and specify a port number different from 22, for example:

    Port <49286>
  3. Update the default SELinux policy to allow the use of a non-default port:

    # semanage port -a -t ssh_port_t -p tcp <49286>
  4. Update the firewalld configuration:

    # firewall-cmd --add-port <49286>/tcp
    # firewall-cmd --remove-port=22/tcp
    # firewall-cmd --runtime-to-permanent
  5. Restart the sshd service:

    # systemctl restart sshd

Verification

  • Use a tool that displays port numbers of running services, for example:

    # ss -tulpn | grep sshd
    tcp   LISTEN 0      128             [::]:49286            [::]:*    users:(("sshd",pid=1784,fd=8))

    Check the output for the new port number.

By using the AllowUsers and AllowGroups directives in the /etc/ssh/sshd_config configuration file, you can permit only certain users, domains, or groups to connect to your OpenSSH server.

Warning

Misconfiguring AllowUsers or AllowGroups can lock you out of the server. Before applying these directives, verify that your user account and source IP match the restrictions. Test the configuration by opening a new SSH session while keeping your current session active, so you can revert changes if the new connection fails.

You can combine AllowUsers and AllowGroups to restrict access more precisely, for example:

AllowUsers *@192.168.1.* *@10.0.0.* !*@192.168.1.2
AllowGroups example-group

This configuration allows only connections if all of the following conditions are met:

  • The connection’s source IP is within the 192.168.1.0/24 or 10.0.0.0/24 subnet.
  • The source IP is not 192.168.1.2.
  • The user is a member of the example-group group.

The OpenSSH server permits only connections that pass all Allow and Deny directives in /etc/ssh/sshd_config. For example, if the AllowUsers directive lists a user that is not part of a group listed in the AllowGroups directive, then the user cannot log in.

Using allowlists (directives starting with Allow) is more secure than using denylists (options starting with Deny) because allowlists also block new unauthorized users or groups.

1.5.5. X Security extension

Disable X11 forwarding in the OpenSSH server configuration if you do not need it to reduce your system’s attack surface.

The X server in Red Hat Enterprise Linux clients does not provide the X Security extension. Without this extension, clients cannot request an additional security layer when connecting to untrusted SSH servers with X11 forwarding.

By default, the ForwardX11Trusted option in the /etc/ssh/ssh_config.d/50-redhat.conf file is set to yes. This means the ssh -X remote_machine and ssh -Y remote_machine commands behave identically.

To disable X11 forwarding, set the X11Forwarding directive to no in the /etc/ssh/sshd_config configuration file.

Connect securely from your local system to a remote server by using a jump host as an intermediary. This approach manages connections between hosts located in different security zones.

Prerequisites

  • A jump host accepts SSH connections from your local system.
  • A remote server accepts SSH connections from the jump host.

Procedure

  1. Use the ssh -J command to connect through one or more intermediary jump servers. Specify the jump servers directly in the command, for example:

    $ ssh -J <jump-1.example.com>,<jump-2.example.com>,<jump-3.example.com> <target-server-1.example.com>

    Change the hostname-only notation if needed. Use this format when user names or SSH ports differ between the jump servers and the remote server, for example:

    $ ssh -J <example.user.1>@<jump-1.example.com>:<75>,<example.user.2>@<jump-2.example.com>:<75>,<example.user.3>@<jump-3.example.com>:<75> <example.user.f>@<target-server-1.example.com>:<220>
  2. For regular connections through jump servers, store the configuration in your SSH configuration file:

    1. Define the jump host by editing the ~/.ssh/config file on your local system, for example:

      Host <jump-server-1>
        HostName <jump-1.example.com>
      • The Host parameter defines a name or alias for the host you can use in ssh commands. The value can match the real hostname, but can also be any string.
      • The HostName parameter sets the actual hostname or IP address of the jump host.
    2. Add the remote server jump configuration with the ProxyJump directive to ~/.ssh/config file on your local system, for example:

      Host <remote-server-1>
        HostName <target-server-1.example.com>
        ProxyJump <jump-server-1>
    3. Use your local system to connect to the remote server through the jump server:

      $ ssh <remote-server-1>

      This command is equivalent to the ssh -J jump-server1 remote-server command if you omit the previous configuration steps.

You can use the sshd RHEL system role to configure OpenSSH servers and the ssh RHEL system role to configure OpenSSH clients consistently, in an automated fashion, and on any number of RHEL systems at the same time.

Such configurations are necessary for any system where secure remote interaction is needed, for example:

  • Remote system administration: securely connecting to your machine from another computer by using an SSH client.
  • Secure file transfers: the Secure File Transfer Protocol (SFTP) provided by OpenSSH securely transfers files between your local machine and a remote system.
  • Automated DevOps pipelines: automating software deployments that require secure connection to remote servers (CI/CD pipelines).
  • Tunneling and port forwarding: forwarding a local port to access a web service on a remote server behind a firewall. For example a remote database or a development server.
  • Key-based authentication: more secure alternative to password-based logins.
  • Certificate-based authentication: centralized trust management and better scalability.
  • Enhanced security: disabling root logins, restricting user access, enforcing strong encryption and other such forms of hardening ensures stronger system security.

In the sshd RHEL system role playbook, you can define the parameters for the server SSH configuration file. If you do not specify these settings, the role produces the sshd_config file that matches the RHEL defaults.

In all cases, booleans correctly render as yes and no in the final configuration on your managed nodes. You can use lists to define multi-line configuration items. For example:

sshd_ListenAddress:
  - 0.0.0.0
  - '::'

renders as:

ListenAddress 0.0.0.0
ListenAddress ::

You can use the sshd RHEL system role to configure multiple OpenSSH servers for secure remote access.

The role ensures secure communication environment for remote users by providing namely:

  • Management of incoming SSH connections from remote clients
  • Credentials verification
  • Secure data transfer and command execution
Note

You can use the sshd RHEL system role alongside with other RHEL system roles that change SSHD configuration, for example the Identity Management in RHEL system roles. To prevent the configuration from being overwritten, ensure the sshd RHEL system role uses namespaces (RHEL 8 and earlier versions) or a drop-in directory (RHEL 9 and later).

Prerequisites

Procedure

  1. Create a playbook file, for example, ~/playbook.yml, with the following content:

    ---
    - name: SSH server configuration
      hosts: managed-node-01.example.com
      tasks:
        - name: Configure sshd to prevent root and password login except from particular subnet
          ansible.builtin.include_role:
            name: redhat.rhel_system_roles.sshd
          vars:
            sshd_config:
              PermitRootLogin: no
              PasswordAuthentication: no
              Match:
                - Condition: "Address 192.0.2.0/24"
                  PermitRootLogin: yes
                  PasswordAuthentication: yes

    The settings specified in the example playbook include the following:

    PasswordAuthentication: yes|no
    Controls whether the OpenSSH server (sshd) accepts authentication from clients that use the username and password combination.
    Match:
    The match block allows the root user to log in by using a password only from the subnet 192.0.2.0/24.

    For details about the role variables and the OpenSSH configuration options used in the playbook, see the /usr/share/ansible/roles/rhel-system-roles.sshd/README.md file and the sshd_config(5) manual page on the control node.

  2. Validate the playbook syntax:

    $ ansible-playbook --syntax-check ~/playbook.yml

    Note that this command only validates the syntax and does not protect against a wrong but valid configuration.

  3. Run the playbook:

    $ ansible-playbook ~/playbook.yml

Verification

  1. Log in to the SSH server:

    $ ssh <username>@<ssh_server>
  2. Verify the contents of the sshd_config file on the SSH server:

    $ cat /etc/ssh/sshd_config.d/00-ansible_system_role.conf
    #
    # Ansible managed
    #
    PasswordAuthentication no
    PermitRootLogin no
    Match Address 192.0.2.0/24
      PasswordAuthentication yes
      PermitRootLogin yes
  3. Check that you can connect to the server as root from the 192.0.2.0/24 subnet:

    1. Determine your IP address:

      $ hostname -I
      192.0.2.1

      If the IP address is within the 192.0.2.1 - 192.0.2.254 range, you can connect to the server.

    2. Connect to the server as root:

      $ ssh root@<ssh_server>

Troubleshooting

  • If the playbook fails with syntax errors, validate the YAML structure:

    $ ansible-playbook --syntax-check ~/playbook.yml
  • If the managed node is unreachable, verify SSH connectivity and authentication:

    $ ansible managed-node-01.example.com -m ping
  • If the playbook completes but the SSH configuration is not applied, check the sshd service status on the managed node:

    $ ansible managed-node-01.example.com -m shell -a 'systemctl status sshd'
  • If configuration validation fails, check the sshd configuration test:

    $ ansible managed-node-01.example.com -m shell -a 'sshd -t'
  • For detailed output during playbook execution, run with verbose mode:

    $ ansible-playbook -vvv ~/playbook.yml

By default, applying the sshd RHEL system role overwrites the entire configuration. This can be problematic if you have previously adjusted the configuration with a different playbook. You can use the non-exclusive configuration to apply changes only to selected configuration options.

You can apply a non-exclusive configuration:

  • In RHEL 8 and earlier by using a configuration snippet.
  • In RHEL 9 and later by using files in a drop-in directory. The default configuration file is already placed in the drop-in directory as /etc/ssh/sshd_config.d/00-ansible_system_role.conf.

Prerequisites

Procedure

  1. Create a playbook file, for example, ~/playbook.yml, with the following content:

    • For managed nodes that run RHEL 8 or earlier:

      ---
      - name: Non-exclusive sshd configuration
        hosts: managed-node-01.example.com
        tasks:
          - name: Configure SSHD to accept environment variables
            ansible.builtin.include_role:
              name: redhat.rhel_system_roles.sshd
            vars:
              sshd_config_namespace: <my_application>
              sshd_config:
                # Environment variables to accept
                AcceptEnv:
                  LANG
                  LS_COLORS
                  EDITOR
    • For managed nodes that run RHEL 9 or later:

      - name: Non-exclusive sshd configuration
        hosts: managed-node-01.example.com
        tasks:
          - name: Configure sshd to accept environment variables
            ansible.builtin.include_role:
              name: redhat.rhel_system_roles.sshd
            vars:
              sshd_config_file: /etc/ssh/sshd_config.d/<42-my_application>.conf
              sshd_config:
                # Environment variables to accept
                AcceptEnv:
                  LANG
                  LS_COLORS
                  EDITOR

      The settings specified in the example playbooks include the following:

      sshd_config_namespace: <my_application>
      The role places the configuration that you specify in the playbook to configuration snippets in the existing configuration file under the given namespace. You need to select a different namespace when running the role from a different context.
      sshd_config_file: /etc/ssh/sshd_config.d/<42-my_application>.conf
      In the sshd_config_file variable, define the .conf file into which the sshd system role writes the configuration options. Use a two-digit prefix, for example 42- to specify the order in which the configuration files are applied.
      AcceptEnv:

      Controls which environment variables the OpenSSH server (sshd) accepts from a client:

      • LANG: defines the language and locale settings.
      • LS_COLORS: defines the displaying color scheme for the ls command on the command line.
      • EDITOR: specifies the default text editor for the command-line programs that need to open an editor.

      For details about the role variables and the OpenSSH configuration options used in the playbook, see the /usr/share/ansible/roles/rhel-system-roles.sshd/README.md file and the sshd_config(5) manual page on the control node.

  2. Validate the playbook syntax:

    $ ansible-playbook --syntax-check ~/playbook.yml

    Note that this command only validates the syntax and does not protect against a wrong but valid configuration.

  3. Run the playbook:

    $ ansible-playbook ~/playbook.yml

Verification

  • Verify the configuration on the SSH server:

    • For managed nodes that run RHEL 8 or earlier:

      # cat /etc/ssh/sshd_config
      ...
      # BEGIN sshd system role managed block: namespace <my_application>
      Match all
        AcceptEnv LANG LS_COLORS EDITOR
      # END sshd system role managed block: namespace <my_application>
    • For managed nodes that run RHEL 9 or later:

      # cat /etc/ssh/sshd_config.d/42-my_application.conf
      # Ansible managed
      #
      AcceptEnv LANG LS_COLORS EDITOR

When the default cryptographic settings do not meet certain security or compatibility needs, you can override the system-wide cryptographic policy on the OpenSSH server by using the sshd RHEL system role.

Override the system-wide cryptographic policy in the following notable situations:

  • Compatibility with older clients: necessity to use weaker-than-default encryption algorithms, key exchange protocols, or ciphers.
  • Enforcing stronger security policies: simultaneously, you can disable weaker algorithms. Such a measure could exceed the default system cryptographic policies, especially in the highly secure and regulated environments.
  • Performance considerations: the system defaults could enforce stronger algorithms that can be computationally intensive for some systems.
  • Customizing for specific security needs: adapting for unique requirements that are not covered by the default cryptographic policies.
Warning

It is not possible to override all aspects of the cryptographic policies from the sshd RHEL system role. For example, SHA-1 signatures might be forbidden on a different layer so for a more generic solution, see Setting a custom cryptographic policy by using RHEL system roles.

Prerequisites

Procedure

  1. Create a playbook file, for example, ~/playbook.yml, with the following content:

    - name: Deploy SSH configuration for OpenSSH server
      hosts: managed-node-01.example.com
      tasks:
        - name: Overriding the system-wide cryptographic policy
          ansible.builtin.include_role:
            name: redhat.rhel_system_roles.sshd
          vars:
            sshd_sysconfig: true
            sshd_sysconfig_override_crypto_policy: true
            sshd_KexAlgorithms: ecdh-sha2-nistp521
            sshd_Ciphers: aes256-ctr
            sshd_MACs: hmac-sha2-512-etm@openssh.com
            sshd_HostKeyAlgorithms: rsa-sha2-512,rsa-sha2-256

    The settings specified in the example playbook include the following:

    sshd_KexAlgorithms
    You can choose key exchange algorithms, for example, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521,diffie-hellman-group14-sha1, or diffie-hellman-group-exchange-sha256.
    sshd_Ciphers
    You can choose ciphers, for example, aes128-ctr, aes192-ctr, or aes256-ctr.
    sshd_MACs
    You can choose MACs, for example, hmac-sha2-256, hmac-sha2-512, or hmac-sha1.
    sshd_HostKeyAlgorithms
    You can choose a public key algorithm, for example, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521, or ssh-rsa.

    For details about all variables used in the playbook, see the /usr/share/ansible/roles/rhel-system-roles.sshd/README.md file on the control node.

    Note

    On RHEL 9 managed nodes, the system role writes the configuration into the /etc/ssh/sshd_config.d/00-ansible_system_role.conf file, where cryptographic options are applied automatically. You can change the file by using the sshd_config_file variable. However, to ensure the configuration is effective, use a file name that lexicographically precedes the /etc/ssh/sshd_config.d/50-redhat.conf file, which includes the configured crypto policies.

    On RHEL 8 managed nodes, you must enable override by setting the sshd_sysconfig_override_crypto_policy and sshd_sysconfig variables to true.

  2. Validate the playbook syntax:

    $ ansible-playbook --syntax-check ~/playbook.yml

    Note that this command only validates the syntax and does not protect against a wrong but valid configuration.

  3. Run the playbook:

    $ ansible-playbook ~/playbook.yml

Verification

  • You can verify the success of the procedure by using the verbose SSH connection and check the defined variables in the following output:

    $ ssh -vvv <ssh_server>
    ...
    debug2: peer server KEXINIT proposal
    debug2: KEX algorithms: ecdh-sha2-nistp521
    debug2: host key algorithms: rsa-sha2-512,rsa-sha2-256
    debug2: ciphers ctos: aes256-ctr
    debug2: ciphers stoc: aes256-ctr
    debug2: MACs ctos: hmac-sha2-512-etm@openssh.com
    debug2: MACs stoc: hmac-sha2-512-etm@openssh.com
    ...

In the ssh RHEL system role playbook, you can define the parameters for the client SSH configuration file. If you do not specify these settings, the role produces a global ssh_config file that matches the RHEL defaults.

In all the cases, booleans correctly render as yes or no in the final configuration on your managed nodes. You can use lists to define multi-line configuration items. For example:

LocalForward:
  - 22 localhost:2222
  - 403 localhost:4003

renders as:

LocalForward 22 localhost:2222
LocalForward 403 localhost:4003
Note

The configuration options are case sensitive.

You can use the ssh RHEL system role to configure multiple OpenSSH clients.

OpenSSH clients establish a secure connection between the local user and the remote OpenSSH server. They ensure:

  • Secure connection initiation
  • Credentials provision
  • Negotiation with the OpenSSH server on the encryption method used for the secure communication channel
  • Ability to send files securely to and from the OpenSSH server
Note

You can use the ssh RHEL system role alongside with other system roles that change SSH configuration, for example the Identity Management in RHEL system roles. To prevent the configuration from being overwritten, make sure that the ssh RHEL system role uses a drop-in directory (default in RHEL 8 and later).

Prerequisites

Procedure

  1. Create a playbook file, for example, ~/playbook.yml, with the following content:

    ---
    - name: SSH client configuration
      hosts: managed-node-01.example.com
      tasks:
        - name: Configure ssh clients
          ansible.builtin.include_role:
            name: redhat.rhel_system_roles.ssh
          vars:
            ssh_user: root
            ssh:
              Compression: true
              GSSAPIAuthentication: no
              ControlMaster: auto
              ControlPath: ~/.ssh/.cm%C
              Host:
                - Condition: example
                  Hostname: server.example.com
                  User: user1
            ssh_ForwardX11: no

    The settings specified in the example playbook include the following:

    ssh_user: root
    Configures the root user’s SSH client preferences on the managed nodes with certain configuration specifics.
    Compression: true
    Compression is enabled.
    ControlMaster: auto
    ControlMaster multiplexing is set to auto.
    Host
    Creates alias example for connecting to the server.example.com host as a user called user1.
    ssh_ForwardX11: no
    X11 forwarding is disabled.

    For details about the role variables and the OpenSSH configuration options used in the playbook, see the /usr/share/ansible/roles/rhel-system-roles.ssh/README.md file and the ssh_config(5) manual page on the control node.

  2. Validate the playbook syntax:

    $ ansible-playbook --syntax-check ~/playbook.yml

    Note that this command only validates the syntax and does not protect against a wrong but valid configuration.

  3. Run the playbook:

    $ ansible-playbook ~/playbook.yml

Verification

  • Verify that the managed node has the correct configuration by displaying the SSH configuration file:

    # cat ~/root/.ssh/config
    # Ansible managed
    Compression yes
    ControlMaster auto
    ControlPath ~/.ssh/.cm%C
    ForwardX11 no
    GSSAPIAuthentication no
    Host example
      Hostname example.com
      User user1

Troubleshooting

  • If the playbook fails with syntax errors, validate the YAML structure:

    $ ansible-playbook --syntax-check ~/playbook.yml
  • If the managed node is unreachable, verify SSH connectivity and authentication:

    $ ansible managed-node-01.example.com -m ping
  • If the SSH client configuration is not applied, verify that the configuration file was created in the correct location for the specified user.
  • For detailed output during playbook execution, run with verbose mode:

    $ ansible-playbook -vvv ~/playbook.yml
Red Hat logoGithubRedditYoutubeTwitter

Learn

Try, buy, & sell

Communities

About Red Hat

We deliver hardened solutions that make it easier for enterprises to work across platforms and environments, from the core datacenter to the network edge.

Making open source more inclusive

Red Hat is committed to replacing problematic language in our code, documentation, and web properties. For more details, see the Red Hat Blog.

About Red Hat Documentation

Legal Notice

Theme

© 2026 Red Hat
Back to top