Ansible role for a Secure OpenSSH configuration.
⚠️All versions prior to 1.2.2 contain a bug which causes both the ED25519 and RSA key files to contain ED25519 keys.
You should update immediately.
- What does the role configure?
- Supported Operating Systems and Versions
- Test matrix
- Role variables
While SSH offers quite some security, its security heavily depends on its configuration.
Generally speaking, SSH aims to provide
- The ability for the user to make sure he is talking to the endpoint he wants to talk to (server authentication)
- Encrypted communication, so that the user can be sure that his or her credentials and command are sent to the server securely
- the ability for the server to authenticate the user who wants to communicate.
This is achieved through a variety of mechanisms discussed in depth elsewhere. But the bottom line is: if the ssh server is not configured correctly, the security provided by the use of SSH may be reduced or even be eliminated.
This repository contains an ansible role based on@stribika's excellent blog post on securely configuring the OpenSSH server. If you have not read it yet, I strongly recommend doing so.
What does the role configure?
The role configures various aspects of OpenSSH, explained below.
The SSH protocol version is limited to version 2, as there are several problems with protocol version 1
Key Exchange algorithms
In the initial stages of an SSH connection, the client and the server negotiate a random session key to encrypt the communication. If an attacker can get hold of the session key, he or she can eavesdrop the remaining communication. Therefor it is important to secure the initial key exchange. This means using only the most trustworthy algorithms with proper key sizes.
Per default, only the libssh.org implementation of curve25519-sha256 and diffie-hellman-group-exchange-sha256 are allowed.
The ciphers are used to encrypt the actual communication between the client and the server. Since there is a known vulnerability on the CBC cipher mode, all ciphers using this mode are excluded by default.
The DES and and RC4 ciphers are not deemed suffciently secured any more and therefor are excluded by default.
You might wonder why
aes128-ctrare included by default. Since they are run in Counter Mode (ctr) or Galois/Counter Mode(gcm) they are considered suffciently secure, despite its relative small key size.
Message Authentication Codes
The Message Authentication Codes (MACs) are used to ensure that a message has not been modified by a third party and that the message was actually sent by the communication partner.
There are multiple ways to combine ciphers and MACs - not all of these are useful. The 3 most common:
Encrypt-then-MAC: encrypt the message, then attach the MAC of the ciphertext.
MAC-then-encrypt: attach the MAC of the plaintext, then encrypt everything.
Encrypt-and-MAC: encrypt the message, then attach the MAC of the plaintext.
excerpt from @stribika's blog post on Secure SSH
Only MACs which attach the MAC of the cyphertext ("Encrypt-then-MAC") are permitted by default.
The server authenticates itself to the client so that the client can be sure to communicate with the correct endpoint. The authentication is done via public key algotithms.
When the client could not authenticate that he or she is communicating with the intended server, a man-in-the-middle attack could easily be mounted.
As of the time of this writing, there are four public key algorithms available:
The DSA algorithm has a fixed keylength of 1024, which is not considered secure nowadays.
The ECDSA relies on questionable elliptic curves and should therefor not be used.
Hence, only the RSA and ED25519 algorithms are permitted and the DSA and ECDSA keys are removed.
The client authentication will be limited to Public Key Authentication.
After applying this role on a server, you will not be able to log into that server via SSH using passwords any more!
Make sure you have Public Key Authentication tested for your administrative account.
/etc/ssh/moduli file is used by the diffie-hellman-group-exchange-sha256 key
exchange algorithm to provide suffciently large prime numbers.
If you set
sssh_moduli_generate to true and
"diffie-hellman-group-exchange-sha256", new moduli will be generated with a bit size
The generation is a two-step process. First, a large number of large numbers are generated. In the second step, those numbers are tested wether they are actually suffciently large prime numbers.
Note that with the default setting of 4096 for
sssh_moduli_size this process
will take at least hours, if not days to finish. This is a failsafe default,
so that when you accidentally activate the regeneration of
you end up with a rock solid state.
As of the time of this writing, a
sssh_moduli_size of 1024 is considered secure
by todays standards. A size of 2048 bit is considered secure for the foreseeable
Supported Operating Systems and Versions
Since I am limited in the time I can put into this project, this role will support the last two releases of the following operating systems.
- CentOS and RedHat Enterprise Linux
- Ubuntu (last two LTS releases)
As for the exact versions, please see the role information on Galaxy.
The role is tested against a complete matrix consisting of the following:
- Python Versions 3.6, 3.7 and 3.8
- Ansible Versions 2.9.2, 2.9.8, 2.9.9 and 2.9.10
- OS Versions:
- CentOS 7 and 8
- Debian 9 and 10
- Ubuntu 18.04 and 20.04
Before using the role in production, I strongly suggest to look up whether your specific setup was successfully tested.
$ ansible-galaxy install mwmahlberg.sssh
into your shell.
Below you will find the variables used in this role.
|sssh_moduli_generate||false||wether a new modulus file should be generated|
|sssh_moduli_size||4096||size of each individual modulus|
|key exchange algorithms permitted|
|sssh_ciphers supported for encryption|
|Message Authentication Codes supported|
Notes on variables
If set to
true, the file
/etc/ssh/moduli will be regenerated.
With the default
sssh_moduli_sizeof 4096, the generated moduli will be very secure.
The downside of it is that the generation will take hours to even days.
You should choose a proper modulus size carefully.
It should only be set to
true via commandline. If you set this to
true in a playbook or inventory,
/etc/ssh/moduli will be generated each time the role is applied.
This setting is useless when you exclude
ssh_kex_algotithms and will be ignored in this case.
The minimum modulus size is 1024 and is considered suffciently secure as of the time of this writing. However, the suggested modulus size is 2048, which is considered secure in the foreseeable future.
The default value for
sssh_moduli_size is 4096. This roughly translates to "Should be secure for all practical purposes".
- Make sure you have Public Key Authentication tested on all target hosts! Otherwise, you will not be able to log in to the target hosts via SSH any more after applying the role. See Client authentication for details.
- Add the role to the requirements of your playbook
$ cd ~/path/to/playbook/dir $ echo "- src: mwmahlberg.sssh" >> requirements.yml
- Install your requirements
$ ansible-galaxy install -r requirements.yml
- Assign the role to a host or a group and configure it.
- hosts: all vars: sssh_kex_algorithms: - "firstname.lastname@example.org" roles: - mwmahlberg.sssh
- Run your playbook