One of the most important aspects of running a server is a good security policy. It is also one of the things that comes last, usually. But if you don’t pay attention to it up front, it’s going to cost you in the long run in case you are breached. This tutorial is one in a series of security-related tutorials (not all will be released sequentially).
When you install a new machine, the default security configuration often isn’t optimal. For example: CentOS gives you just a root account and Ubuntu doesn’t come with a preconfigured firewall. You often want to secure your server, but most beginners don’t know how to (on the other hand, I’ve seen people with years of experience not understanding the sudo-concept). My goal is to show you how to initially harden your server a bit by configuring the SSH server and my enabling sudo. This can be both done on new installations or on existing machines.
NOTE: I’m using ‘mpkossen’ as an example username here. Please replace it with a username of your choosing.
Securing SSH
The first thing you should always do with a server, it upload your public key (that matches your private key) and enable password-less login. This will prevent people from guessing passwords to enter your server from ever succeeding. Let’s first upload the public key. From a terminal on a Linux or Mac OS machine, run:
ssh-copy-id -i ~/.ssh/id_rsa.pub root@198.51.100.100
It then asks for the password for the root user. Fill that in. Once that’s done, it gives you a notice telling what has happened.
What you do here, is copy a public key (in this case .ssh/id_rsa.pub [indicated by -i], which is often the default name for an SSH key) to your server at 198.51.100.100. It then adds the public key to the .ssh/authorized_keys file on the server for the user you’ve used in the command. From this point on, you only need your SSH key to log in. Be sure to use a strong password for it and don’t leave it lying around, since it is the entrance to your server.
Next, login to the server. We’re going to tweak some SSH server settings to make it more secure. Open up /etc/ssh/sshd_config with an editor (vim, nano, or anything else). First, we’re going to disable password authentication. Look for the following line:
#PasswordAuthentication yes
And change it to:
PasswordAuthentication no
This disables password authentication and forces you to use only public keys. No worries, in case you ever loose your private key you can always access your server via an out-of-band console. In case you have a dedicated server without any out-of-band access, well, don’t loose your private key ;-)
Now look for the following line:
PermitRootLogin yes
And change it to:
PermitRootLogin no
This disables logging in as root. When these things are done, we would usually restart SSH to get these changes live. However, this time, we need to make sure we have a non-root account with sudo access first. If you’ve installed Ubuntu on a KVM machine, this should already be the case and you can safely run the following command. WARNING: if you are currently logged in as root, do not log out, or you’ll have a nice trip to your console ;-)
Again, only as a non-root user with sudo privileges, run:
sudo /etc/init.d/ssh restart
Now, if you’ve run this command, that’s it for you! Otherwise, head over to the next part.
How to Install and Configure Sudo
Sudo… the ground of quite some discussion. To many, sudo is an inconvenience. Rightly so, because inconvenience in security is good. If your security doesn’t annoy you ever, you’re either a very patient human being or your security isn’t good enough.
But why should you use sudo, because inconvenience in itself isn’t an argument. Sudo adds an extra layer of security. When you log in as root, the only thing you need is either your private key or your root password. When you’re in, you’re in and you can do everything you want. Sudo prevents that last part. If you use sudo and somebody manages to get hold of your private key, they can log into the server but still not do much to ruin it, since they haven’t got your password. That alone is, for me, enough reason to use sudo rather than log in as root.
There are additional reasons for using sudo, which are listed here. Not all of them are very strong, though.
So, let’s enable sudo for you. These are instructions for both Ubuntu and CentOS.
Installing Sudo: Ubuntu
Logged in as root, make sure sudo is installed first:
apt-get install sudo
Once that is done, add a new user:
adduser mpkossen
This will ask you for the password twice, make sure you pick a strong one. It then asks some additional questions like you name, room number, etc. Fill these out to your liking. Once done, you need to confirm the information after which your user was created.
Next, add it to the sudo group:
usermod -a -G sudo mpkossen
The above command modifies the user. It adds it to the group(s) mentioned by using -G. The -a is for append. If you wouldn’t use -a, the user would only be in the sudo group, causing all kinds of different problems.
Now the newly created user is all set up, log out and transfer the SSH key for this user (like we’ve done above):
ssh-copy-id -i ~/.ssh/id_rsa.pub mpkossen@198.51.100.100
Finally, log in to the server to disable the root account and clean up. First, disable the root account:
sudo passwd -dl root
What you do here, is delete the root password (-d) and lock the account (-l). From this point on, logging in a root is impossible, even via the CLI.
Finally, remove root’s SSH authorized_keys:
rm -rf /root/.ssh
And you’re done! From now on, commands that require root access should be prefixed with sudo and you will be asked for your password.
Installing Sudo: CentOS
Logged in as root, make sure sudo is installed first:
yum install sudo
Once that is done, add a new user:
adduser mpkossen
And add a password to the user:
passwd mpkossen
This will ask you for the password twice, make sure you pick a strong one.
Next, add sudo right to the user. Run ‘visudo’. It will open a file. Look for the following line:
root ALL=(ALL) ALL
Add the following line under it:
root ALL=(ALL) ALL
mpkossen ALL=(ALL) ALL
Now, save the file and exit. What you just did was ensure that user ‘mpkossen’ can run any command as any user (even as root).
Now the newly created user is all set up, log out and transfer the SSH key for this user (like we’ve done above):
ssh-copy-id -i ~/.ssh/id_rsa.pub mpkossen@198.51.100.100
Finally, log in to the server to lock the root account and clean up. First, disable the root account:
sudo passwd -l root
What you did here is lock (-l) the root account. You could optionally delete (-d) the password first. CentOS doesn’t like combining -d and -l, though.
Remove root’s SSH authorized_keys:
rm -rf /root/.ssh
And you’re done! From now on, commands that require root access should be prefixed with sudo and you will be asked for your password.
Final notes
Now, with the above, you’ve definitely made your server more secure. Other good security practices would add to this one, though. Like keeping a strong password and changing it regularly. The same goes for your SSH key. A good firewall is a must as well, but that is something for a future guide!
For now, get used to a life with sudo! It’s going to get annoying at some moments, but it is more secure.
Related Posts:
- How to Rapidly Install Java, OpenJDK & Oracle JDK on your VPS - December 14, 2015
- It’s been a great ride - December 14, 2015
- Cheap Windows VPS – $21/quarter 1GB KVM-based Windows VPS in 11 worldwide locations - November 30, 2015
> ssh-copy-id -i ~/.ssh/id_rsa.pub root@198.51.100.100
It’s enough to just do:
> ssh-copy-id root@198.51.100.100
Correct. If you’re just using the default private key (with the default name), that is the shortest command to do it.
I wanted to show how to point to a private key file, though. In case you’re not using the default name or if you have more than one, then you need the -i flag :-)
Nice! I didn’t know about ssh-copy-id … this makes things a lot easier.
I know! I only found out about it about 4 years ago after having done it manually for ages…
In addition to enforce authentication to via SSH, how about to change sshd’s listening port and install an intrusion prevention system like fail2ban or Suricata?
Thank you for your suggestions! Those are topics I wanted to cover in a future guide. If I were to do it all in one article, I’d spend over a week writing it and it’d be quite long ;-)
I personally use Denyhosts (although just slightly dated) and don’t bother to change listening ports. It seems to have done the job well enough.
Thank you for sharing this with us. Expecting more how-tos in the near future :)
Public keys are a great way to secure your SSH server, but can often be a hassle. As an alternative, consider something like Google Authenticator (which uses time-based one-time passwords) as a way of strengthening your login credentials. See https://scottlinux.com/2013/06/02/use-google-authenticator-for-two-factor-ssh-authentication-in-linux/ and http://highball.se/2012/08/how-to-install-google-authenticator-under-debian-squeeze/ for examples of how to set it up.
It’s worth pointing out that although Google developed the Google Authenticator PAM module and code-generating app for iOS and Android, these are merely implementations of the open TOTP standard. No connection to Google is necessary, nor do you need to rely on them for any aspect of the authentication: it’s entirely local. Any TOTP-compatible code generator will work fine.
For users who are seeking slightly more security (at the cost of a slight extra hassle) and want to avoid bad guys trying to gain access to your server using SSH, you can firewall out SSH from the outside world and only allow it over OpenVPN connections to your server. Using OpenVPN’s tls-auth functionality, the OpenVPN server will silently reject any packets without the correct HMAC signature. Port scans and other attacks by bad guys will not receive any response from the server, so they have no way of knowing if OpenVPN exists or not — only users in possession of the correct keys will be able to get any sort of response from the OpenVPN server. If you use certificate-based logins with OpenVPN, you gain comparable security as using SSH with public keys but with the benefit of hiding the existence of your SSH server from the world. See http://openvpn.net/index.php/open-source/documentation/howto.html#security for details.
Restricting certain server-management tools like Webmin to only be accessible from a VPN connection (rather than available to the entire internet) helps secure these tools from potential access or compromise by bad guys on the internet.
Thanks for your response and highlighting Google Authenticator! I’ve considered explaining it as an alternative, but I thought it was too off-topic. I may consider it for a future guide, as it’s quite nice.
Also, great suggestion on the VPN usage!
Nice read Maarten. Few points:
– talk about how tot generate a key pair (ssh-keygen)
– make sure there is a password on your private key
– install a key agent so that you only have to type your key password once (ssh-add)
ssh on another port only keeps standard bots away, it keeps your loges clean. It is not extra secure, an nmap reveals your port right away. fail2ban however works quite well for targetet brute force attacks.
Confession: I’m lazy, I always use sudo su – or sudo -i to become root…
Looking forward to the rest of the articles in this series.
I agree about changing port, it’s super easy to find, and even some automated bots will search for the port these days. An inconvenience not worth the tiny amount of extra security you get.
Thanks, Raymii! I’m sometimes lazy as well! But sudo hasn’t lost its purpose if you sudo su, because you still need the password to do that!
Generating an SSH-key and using a secure password would indeed have been a good addition to this guide. I may devote a separate one to it and include key agent instructions (or recommend people to use Ubuntu, which does it by default ;-)). It would be a Linux-only guide, though.
On paranoid mode, you can add with Authy or Google Authenticator.
I don’t know why, if I’m using non-root user I can’t upload file but I can download them.
Upload to and download from where?
What if I do this:
I log in into my server using normal user (non root), then I issue this command
“su -”
After this I can manage my server, do you think this is better?
Thanks
“su -” makes the current shell a just login shell, so i wonder which user you use to log into that shell.
However, I rather like to use su as well, since for sudo you have to enter the root passport ‘almost’ every time again.
“sudo su -” means you sudo into root. Not sure if it is that much better than logging into root other than that it’s probably logged to some extent. Would be best to perform your actions without root as much as possible, including via “sudo su -“.
It’s always better than logging in as root. If you do “sudo su -” you still need the password of the sudo user to get access, which is basically the main reason I use sudo. You SSH private key + password are not enough anymore to gain root access on your server.
Makes sense, but I just hope it’s not an excuse to run everything as “sudo su -“, i.e. still root. If root isn’t required – don’t use it.
How about port-knocking?
Your ssh server will not allow mpkossen to log in, unless you configure it accordingly. You would need to add something like “AllowUsers mkpossen” to your sshd configuration.
I’ve never had to do that myself. What kind of distribution did you have to do this on?
Thanks for the great post. :)
A little corrention:
“and disable password-less login.”
I think it should be: “and enable password-less login.”
or “and disable password login.”
Am I missing anything?
You’re right. Corrected! Thanks for pointing that out!
I always take similar steps on new systems. In addition, I also change the SSH port and make /tmp non-executable amongst other things.
Locking it down to a gateway server / single ip is always a plus, then securing the gateway server
This would also be simple if you had several employees that needed access to all the servers. Are there any security implications to using a single server/single ip to access everything? Does that create a single point that attackers could try to exploit?… although how would an attacker know about your single gateway server…
Like BA-Corey says, this isn’t an option for many environments. If I’m on a holiday, I definitely want to be able to access my servers. Also when I’m on the move.
It’s a very common (and unsolved) problem, though. You want to limit access to yourself (or a number of people) but you don’t want to “lock” yourself out. The only solution that comes to mind at this moment is using a VPN to limit access to your servers. But the downside of that is more latency, single point of failure, etc.
thanks Maarten for another informative post
Thanks!
A summary of what should be added, methinks:
ssh:
– selection of alternate SSH port
– usage of [Allow/Deny][Users/Groups] directives. Personally, I’d strongly recommended using AllowGroups to further restrict access to known users only
– usage of ‘~/.ssh/config’ file and, say, ‘Host’ sections in it, to create easy to remember aliases
– modifying public key files, to restrict capabilities, to allow logging in from certain hosts only
– advanced techniques such as port knocking, to still further restrict access and to prevent port scanning
sudo:
– usage of per-group rights instead of per-user rights
– logging success/failures and alerting sysadm in case of those
There are otehr topics, of course.
Thanks for good intro.
Hi Konstantin! Thanks for your suggestions.
I’ve tried to keep this tutorial as simple and as limited as possible. Just hit some basic (and obvious) security principles. Security is a very broad subject and it deserves much more than one tutorial.
I’ll make sure to include (some of) your suggestions in any future tutorials. You’ve actually given me a good idea for an additional one ;-)
Good tips. I do similar. Even knocked-up a script that does it automatically on a clean server:
– Move ssh port (for good of my logfiles if nothing else).
– Disable root logins
– Disable passwords – use keys
– Install UFW to manage the firewall.
– Install denyhosts
Personally i just change the default ssh port in /etc/ssh/sshd_config
to something like 1993 and add in /etc/rc.local:
iptables -A INPUT -j ACCEPT -p tcp –dport 1993 -s 151.22.14.10
iptables -A INPUT -j DROP -p tcp –dport 1993
then reboot afterwards
now only one valid ip (151.22.14.10) can log into the server,
i use this way on all my virtual private servers so they only can log into eachother.
There is another great service called Dome9 that’ll manage your firewall for you (instead of UFW), and you can generate temporary leases when you’re out of town!
There is no point in using sudo over su. There is no big difference between issuing your password to get root access (sudo) or a specific root password (su). The big difference apperas when your hard drives fail and fsck asks for your root password on boot. You are kind of screwed when fsck does not accept your users password here. You can easily disable root logins in ssh, there is no need to use sudo to “disable” root.
Well, there is, actually. When using su, the root account still has a password and everybody who needs root access will need and know that password. With sudo, that isn’t the case, because everybody has his own password. But using su over sudo is more secure than logging in as root :-)
I’m relatively new to managing my servers, but I must say… sudo is super annoying. My root password is like 20 chars long and I have fail2ban running… SSH is also on a different port. Would you say I’m at risk?
The biggest reason I use root is because my text editor, Coda, always gets these annoying “permissions” errors when I SFTP with the non-root account. It got so annoying, I just said screw it, I’ll be root!. And since then, I really enjoy not ever having to type sudo.
I think the file permissions are wrong if Coda keeps giving errors. Or Coda should log in as the user who can edit the files (except root).
Annoyance is good, because it often means it’s secure. If it’s easy for you, it’s easy for an attacker. I don’t know you or what you do. But people try to break into servers regardless who runs them.
It has also been my experience that some VPS providers don’t generate new ssh host keys (Chicago VPS comes to mind) when deployed. This means that anybody else on the same VPS image could launch a man-in-the-middle attack because they have access to the same ssh host key.
Regenerating it is simple:
ssh-keygen -N “” -t rsa -f /etc/ssh/ssh_host_rsa_key
ssh-keygen -N “” -t dsa -f /etc/ssh/ssh_host_dsa_key
ssh-keygen -N “” -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key
chmod 600 /etc/ssh/ssh_host_*_key
Oh yeah, restart sshd when you’re done re-generating the keys to put the new keys in to effect.
On Ubuntu, this is as easy as `sudo restart ssh`
And you can double check the path to the keys are correct by reviewing /etc/ssh/sshd.conf (or your specific sshd.conf file)
Thanks for pointing this out!
Hi, thanks for tuts, and its a good practice to change your default 22 port :)