People often wonder whether SSH uses SSL/TLS for traffic encryption. The short answer is NO, even though both protocols have much in common, under the hood SSH has its own transport protocol, independent from SSL.
- Both of them were created to secure and encrypt traffic between clients and servers (SSL for website traffic, SSH for remote control over host)
- They both start with asymmetric encryption in order to negotiate static key for the rest of the session using symmetric encryption (SSH uses proprietary key exchange protocol, SSL/TLS uses PKI infrastructure)
Also, keep in mind that both were developed almost in parallel somewhere in 1995 (SSL1.0 was first though) so they couldn’t actually use each other’s implementation at the time.
However, instead of comparing both protocols, I would like to dedicate most of this post to the attempt to combine both protocols in order to achieve the most secure, scalable and easy-to-use mass-scale SSH control over multiple Linux servers.
Most Common SSH Authentication Methods
Password authentication
This is probably the most easy-to-use method (at least for humans), but also probably the least secure method for authenticating.
The biggest downside of password authentication is that it can be guessed by an unauthorized party, or in some cases just be broken by brute forcing.
This option can by configured using this file: /etc/ssh/sshd_config
Just add the following lines in order to support password authentication method:
Match User
PasswordAuthentication yes
(Also make sure that the following line is also commented out)
ChallengeResponseAuthentication yes
Private key authentication
This method is more secure than plain passwords. There are several ways to approach regarding how to manage private keys in multiple servers and user environments.
- Having private keys per user — each user has its own private key, which will be distributed to all relevant servers (using public key distribution tools such chef, puppet, ansible, etc.)
- Having private key per server — each server has its own private key, and stored in protected centralized location, while each user could access the relevant private key
Of course, there are pros and cons for each method, and every organization should choose according to their specific needs and requirements.
However, both methods above have the following two crucial disadvantages in terms of security:
- Both password and private keys are static, and rarely being rotated. And if they are rotated, it is usually in terms of months. During this time, a compromised credential could give hackers all the time they need to achieve their malicious goals.
- The identity of the remote server (on first connection) is basically unknown — well, in the real world at least. We are all familiar with the following message while trying to establish connection for the first time:
In general, the right approach would be to ask the IT department for the required server’s fingerprint and verify that the received fingerprint actually belongs to the server. HOWEVER, in reality most of people would just hit YES, and add the host to the trusted list of servers located in the following file: ~/.ssh/known_hosts, without verifying that there is no man-in-the-middle attack is being conducted
And, if for some reason, the server is replaced (keeping the old IP address or hostname), connecting to the new server will give you this much scarier message:
By the way, these messages are no different from the well-known messages from your browser while browsing ‘untrustworthy’ websites:
These disadvantages lead me to the third and less common authentication method:
Certificate authentication
This method giving us a secure and convenient way to access Linux servers with short-term certificates signed by a preconfigure CA.
First you should generate your CA (if you haven’t done it yet), in general the best way to do that is using a dedicated CA server which will sign the future certificates and will contain the CA private key.
$ umask 77 # This info should be kept private
$ mkdir ~/my-ca && cd ~/my-ca
$ ssh-keygen -C CA -f ca # make sure to use Passphrase!
At this step you should distribute the CA’s public key to the remote Linux server which will be later accessed by the clients. (You can do it using SCP or an existing puppet/ansible automatically)
$ scp ~/.ssh/ca.pub root@some_server.xmcyber-staging.com:/etc/ssh/
To enable certificate authentication, simply configure clients and hosts to trust any certificates signed by your CA’s public key.
/etc/ssh/sshd_config
# Path to the CA public key for verifying user certificates
TrustedUserCAKeys /etc/ssh/ca.pub
The next step would be to sign a short term certificate which will be trusted by the host
Now configure your SSH servers to trust it, in this example the certificate generated to the client will be valid for 2 weeks. After expiration, this certificate will be useless and it could not be used to authenticate against the remote server.
ssh-keygen -s ~/.ssh/ca_key -n senior-developer -I host_name -h -Z some_server.xmcyber-staging.com -V -1d:+2w /home/admin/keys/ssh_host_rsa_key.pub
(note that the -n parameter is used to specify the principal of that certificate, you may use that later to configure which principals will have access to each server)
On each client, add a line to ~/.ssh/known_hosts specifying the CA public key for verifying host certificates:
@cert-authority *.xmcyber-staging.com ecdsa-sha2-nistp256 AAAAE…=
The certificate issue process of course can be automated, there are plenty of open sources that do just that, it’s a pain in the butt for the initial setup but the advantages are just too great to miss them.
Another cool feature of this method is the ability to have role-based access using:
$ sudo mkdir /etc/ssh/auth_principals
For example create the following file:
/etc/ssh/auth_principals/%u
List all principals that should be able to login to that particular server (one principal per line):
sys-admin
qa-engineer
it-support
senior-developer
#{see the singing command above — this is the principal being used in the user certificate}
Configure on the server to use roles by again adding a line to: /etc/ssh/sshd_config
AuthorizedPrincipalsFile /etc/ssh/auth_principals/%u
There are more complicated implementations such as using external identity providers (idP) that can be used as CA (google for example). Using external idP would also give us the multifactor authentication as a bonus for even more secure infrastructure.
Cloudfalre has a nice integration of using SSH with SSO. You will then of course need to install a third party software on your Linux servers, but while having a good automation platform, it should not be an issue.
https://blog.cloudflare.com/public-keys-are-not-enough-for-ssh-security/
Artiom Levinton is Head of DevOps at XM Cyber