• Sales: 1-800-961-2888
  • Support: 1-800-961-4454

Rackspace Cloud Essentials 3 - Basic Cloud Server Security


Although Rackspace Cloud has taken steps to make your default Cloud Server image as secure as possible, the first line of defense lies in the hands of you, our customer.  Follow these steps immediately after creating your Cloud Server to help protect the integrity of your data. (Note: The commands in this article are meant for Ubuntu.  Small modifications may be required for other distributions.)

Contents

Log in

As soon as you have your IP address and password for your Cloud Server, login via SSH:

ssh root@123.45.67.890

If you rebuilt your Cloud Server, you may get a message informing you that the "remote host identification has changed".

When logging into a Cloud Server via SSH, we learned about the security features of matching the remote host with known keys.  When you rebuild a Cloud Server, the remote host key changes.  As such, your computer thinks there is something dodgy going on.

All you need to do is remove the older entry for the Cloud Server IP:

On your local computer, edit the SSH known_hosts file and remove any entries that point to your Cloud Server IP address.

nano ~/.ssh/known_hosts

If you are not using Linux or a Mac on your local computer, the location of the known_hosts file will differ.  Please refer to your own OS for details of where this file is kept.

User administration

Once logged in to the Cloud Server, immediately change your root password to one of your choosing.

passwd

Add an admin user (we've used the name demo here but any name will do).

adduser demo

Best security practices for system administration state that you should not operate on your system as the root user (this initial setup is the only time you would need to log in as root).  As such, the main administration user (demo) needs to have sudo (Super User) privileges so they can, with a password, complete administrative tasks.

To configure this, use the visudo command, which invokes the 'nano' editor by default in Ubuntu:

visudo

At the end of the file add:

demo   ALL=(ALL) ALL

When you are finished, press the key combination Ctrl-X to exit, press 'y' to confirm your saving the changes, and press the Enter key to save as the indicated file, '/etc/sudoers.tmp' .

NOTE: You may find that while working in the nano editor, the backspace/delete key works backwards, deleting characters in front of the cursor rather than behind it.  This can be resolved by editing the '/etc/nanorc' file (with nano, for example) and either uncommenting or adding the line:

set rebinddelete

The corrected behavior will take effect after the file has been saved and nano has been opened again.

SSH keygen

One effective way of securing SSH access to your cloud server is to use a public/private key.  This means that a 'public' key is placed on the server and the 'private' key is on your local workstation. This makes it impossible for someone to log in using just a password - they must have the private key.  This consists of 3 basic steps: create the key on your local workstation, copy the public key to the Cloud Server, and set the correct permissions for the key.

The first step is to create a folder to hold your keys. On your LOCAL workstation:

mkdir ~/.ssh

That's assuming you use Linux or a Mac and the folder does not exist.  Follow the link to read a detailed article for key generation using Putty for Windows.

To create the ssh keys, on your local workstation enter:

ssh-keygen -t rsa

If you do not want a passphrase then just press enter when prompted.

That created two files in the .ssh directory: id_rsa and id_rsa.pub. The pub file holds the public key. This is the file that is placed on the Cloud Server.

The other file is your private key. Never show, give away or keep this file on a public computer.

SSH copy

Now we need to get the public key file onto the Cloud Server.

We'll use the 'scp' (secure copy) command for this as it is an easy and secure means of transferring files.

Still on your local workstation enter this command:

scp ~/.ssh/id_rsa.pub demo@123.45.67.890:/home/demo/

When prompted, enter the demo user password.

Change the IP address to your cloud server and the location to your admin user's home directory (remember the admin user in this example is called demo).

SSH Permissions

OK, so now we've created the public/private keys and we've copied the public key onto the Cloud Server.

Now we need to sort out a few permissions for the ssh key.

On your Cloud Server, create a directory called .ssh in the 'demo' user's home folder and move the pub key into it.

mkdir /home/demo/.ssh
mv /home/demo/id_rsa.pub /home/demo/.ssh/authorized_keys

Now we can set the correct permissions on the key:

chown -R demo:demo /home/demo/.ssh
chmod 700 /home/demo/.ssh
chmod 600 /home/demo/.ssh/authorized_keys

Again, change the 'demo' user and group to your admin user and group.

It may seem a long set of steps but once you have done it once you can see the order of things: create the key on your local workstation, copy the public key to the Cloud Server, and set the correct permissions for the key.

SSH config

Because keeping the SSH service on the default port of 22 makes it an easier target, we'll change the default SSH configuration to make it more secure:

nano /etc/ssh/sshd_config

The main things to change, check, and add are:

Port 22                           <--- change to a port of your choosing
Protocol 2
PermitRootLogin no
PasswordAuthentication no
UseDNS no
AllowUsers demo

The settings are fairly self explanatory but the main thing is to move the server from the default port of 22 to one of your choosing, turn off root logins, and define which users can log in.

NOTE: the port number can readily be any integer between 1025 and 65536 (inclusive), but should be noted for reference later when any additional listening processes are setup, as it will be important to avoid conflicts.

PasswordAuthentication has been turned off as we setup the public/private key earlier.  If you intend to access your Cloud Server from different computers, you may want leave PasswordAuthentication set to yes. Only use the private key if the local computer is secure (i.e. don't put the private key on a work computer).

Note that we haven't enabled the new settings yet - we need to create a simple firewall using iptables before it's safe to restart ssh using the new port.

That's worth emphasizing:  Do not restart ssh yet.

iptables in Ubuntu

The utility called iptables is the default firewall for Linux systems.  It works by refusing to allow connections to ports or services that you specify.

The next thing is to set up iptables so that you have a more secure installation while allowing the server to run the services that it needs to run.  

To start with, we're going to have three ports open: ssh, http, and https.

We're going to create two files, /etc/iptables.test.rules and /etc/iptables.up.rules. The first is a temporary (test) set of rules and the second the 'permanent' set of rules (this is the one iptables will use when starting up after a reboot for example).

Note that we are logged in as the root user.  This is the only time we will log in as the root user.  If you are completing this step at a later date using the admin user, you will need to use 'sudo' in front of the commands.

Now let's see what's running at the moment:

iptables -L

You will see something similar to this:

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

What this tells us is that we are accepting anything from anyone on any port and allowing anything to happen.

Some think that this is not dangerous if there are no services running on the server, and it doesn't matter that all ports are open.  We disagree.  If connections to unused (and popular) ports are blocked or dropped, then the vast majority of malicious intruders will move on to another machine where ports are accepting connections.  It only takes a few minutes to set up a firewall - is it really worth not doing?

To build the firewall, create the file /etc/iptables.test.rules and add some rules.  If you, or another admin user for this Cloud Server, have worked through these steps previously, this file may not be empty:

nano /etc/iptables.test.rules

You can change and add ports as you see fit.

Defined your rules?  Good.  Then lets apply those rules to our server:

iptables-restore < /etc/iptables.test.rules

Let's see if there is any difference:

iptables -L

Notice the change? (If there is no change in the output, you did something wrong and should try again from the start).

Have a look at the rules and see exactly what is being accepted, rejected and dropped. Once you are happy with the rules, it's time to save your rules permanently:

iptables-save > /etc/iptables.up.rules

Add a networking script

Now we need to ensure that the iptables rules are applied when we reboot the server.  If the server was rebooted before this step the changes would be lost and the server would revert to allowing everything from everywhere.

We'll add a small script that the system will run when your network interfaces are started. Create the file by running:

nano /etc/network/if-pre-up.d/iptables

Add the following lines to the new file:

    #!/bin/sh
    /sbin/iptables-restore < /etc/iptables.up.rules

Save your changes, and then make the new script executable:

chmod +x /etc/network/if-pre-up.d/iptables

That should ensure that whenever your network interfaces are brought up (usually just at boot time), the firewall will be too.

iptables in Red Hat

If you are using a Red Hat distribution, iptables works a little differently.  Using the commands below, you can change your iptables ruleset directly from the command line.

HTTP - Port 80

Use the following command to open port 80 for HTTP (web) traffic in your iptables firewall:

    # sudo /sbin/iptables -I RH-Firewall-1-INPUT 1 -p tcp --dport http -j ACCEPT

HTTPS/SSL - Port 443

Use the following command to open port 443 for Secure HTTP traffic:

    # sudo /sbin/iptables -I RH-Firewall-1-INPUT 1 -p tcp --dport https -j ACCEPT

SSH - Port 22

Though port 22 is open by default to allow you to SSH to your server after it is built, this command shows you how you would open port 22:

    # sudo /sbin/iptables -I RH-Firewall-1-INPUT 1 -p tcp --dport ssh -j ACCEPT

FTP - Port 21

FTP is a common service for file transfer, but it is largely obsolete due to the fact that it is not a secure protocol and we strongly recommend using a secure file transfer protocol like vsftpd.  If you absolutely have to use FTP, use these commands to open the default port of 21.

    # sudo /sbin/iptables -I RH-Firewall-1-INPUT 1 -p tcp --dport ftp -j ACCEPT
    # sudo /sbin/iptables -I RH-Firewall-1-INPUT 1 -p tcp --dport ftp-data -j ACCEPT

MySQL - Port 3306

If you need to make a remote connection to your MySQL database from another server, you will need to open port 3306 in iptables.

    # sudo /sbin/iptables -I RH-Firewall-1-INPUT 1 -p tcp --dport mysql -j ACCEPT

Saving Your Rules

Use the following command to save all the rules you’ve created.  If not saved before your server is rebooted, the iptables ruleset will revert to the default ruleset blocking all traffic except on port 22!

    # sudo /sbin/service iptables save

Restarting iptables

Your changes to iptables will not take effect until you save your rules, and then restart the iptables service.  Remember, if you restart iptables before saving your rules, iptables will revert to the default ruleset!

    # sudo /sbin/service iptables restart

Restarting ssh

Now we'll restart the ssh service.  Make sure you stay logged in while you restart ssh and test it with a new connection.  That way if something goes wrong you can troubleshoot it more easily.

On most distributions the service is "sshd", and you restart it with the command:

    # sudo service sshd restart

On Ubuntu and some other distributions it's called "ssh", and is restarted with a similar command:

    # sudo service ssh restart

If you have trouble making a new connection after restarting ssh, check the symptoms to see what may be wrong.  If the connection times out, there may be a problem with the iptables config.  If you get a warning about a private key, your key may not be installed on the server properly (check for extra linebreaks or characters that were missed in a copy and paste operation).  If you've been rebuilding the server then you may need to remove the host key from your known hosts file before you can make a connection.

If you're locked out...

The incorrect configuration of SSH, sudo and/or iptables could cause you to be locked out of your system.  If this occurs, please log into the The Rackspace Cloud Control Panel and use the Web Console or Rescue Mode to repair the configurations.

These are the basics of connecting to a Linux Cloud Server and setting up security.  In the next articles we will show you how to complete these steps for a Windows Cloud Server.



© 2011-2013 Rackspace US, Inc.

Except where otherwise noted, content on this site is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License


See license specifics and DISCLAIMER

25 Comments

In the visudo step above (to add a user to sudoers), the changes for Ubuntu 11.04+ are:

demo ALL=(ALL:ALL) ALL

Instead of:

demo ALL=(ALL) ALL

That's odd. The ":ALL" addition to that line only specifies that the user can execute as any group (the "ALL" before the colon means they can execute as any user). Omitting it shouldn't affect a typical user's ability to execute commands with sudo. Usually if I see someone specify "ALL:ALL" they're just covering all their bases.

I'll look into this. I don't find any documentation referencing this change offhand. Could you have changed anything else on the system that might have caused sudo to worry about group permissions?

you can just use "adduser demo sudo" after making the account to add the user to the sudo group :) handy if your remotely setting up the box via a script :)

Thanks Paul. That's assuming you have the "sudo" group set up with sudo access, of course - it's usually the default on Ubuntu, but it can still be worth checking beforehand with a "sudo cat /etc/sudoers". Other distributions might use the "wheel" group for that purpose, or the appropriate group has its permission line commented out and has to be activated with the right tweak through "sudo visudo".

When using visudo, I found this to be useful :

demo ALL=(ALL) NOPASSWD: ALL

Otherwise I kept being asked for a password when running sudo commands using a key-based ssh connection.

I admit, I tend to avoid using the NOPASSWD directive because it makes the security-conscious part of me all twitchy. Since sudo only asks for the password again after a few minutes of inactivity I haven't really found entering a password to be that much of a burden. The times I have used NOPASSWD on a system it's been for a user with access to a limited list of commands.

(1) The contents of the "/etc/ssh/sshd_config" file for Debian-6 is considerably different than your example.
(2) "mkdir /home/demo/.ssh" should be "mkdir /home/demo/.ssh/authorized_keys"
(3) What about "#AuthorizedKeysFile %h/.ssh/authorized_keys" in "/etc/ssh/sshd_config"? Should that be uncommented?
(4) This RackSpace server setup is a bit smoother, but does not address key: http://niccolofavari.com/rackspace-cloud-server-setup-part-i-ubuntu-9.10-configuration

Possibly you could update these steps blending the two articles together?

I'll have to look at sshd on Debian 6 more closely for (1). The sample we show should work fine regardless, but I'll see if we can account for any changes between 5 and 6 more smoothly.

For (2), "authorized_keys" should be a file, unless something really changed in Debian 6. If you have more than one key that should be authorized they would be entered in the same file on different lines.

Number (3), it's okay if that line stays commented - the value listed is the default if the setting isn't specified. If you do want to change where you keep the authorized keys file, you can uncomment the line and change it there.

And to (4), this article grew out of the template used for that Ubuntu 9.10 setup article you point to. The goal, I believe, was for this to be a more platform-neutral set of instructions. We are definitely looking into ways we can consolidate the articles, or at least make those instructions easier to find together.

Thanks for the feedback, and I hope this helped. If you have more questions don't hesitate to ask.

Above, you talk about opening specific ports in Ubuntu, and your steps include creating the rules file, but you never show appropriate contents for that file.

We'll get that article edited to include some sample rules, sorry about that Rick. Until we do, here are some sample rules you can use in that file:

*filter
# Allows all loopback (lo0) traffic and drop all traffic to 127/8 that doesn't use lo0
-A INPUT -i lo -j ACCEPT
-A INPUT ! -i lo -d 127.0.0.0/8 -j REJECT
# Accepts all established inbound connections
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Allows all outbound traffic
# You can modify this to only allow certain traffic
-A OUTPUT -j ACCEPT
# Allows HTTP and HTTPS connections from anywhere (the normal ports for websites)
-A INPUT -p tcp --dport 80 -j ACCEPT
-A INPUT -p tcp --dport 443 -j ACCEPT
# Allows SSH connections
#
# THE -dport NUMBER IS THE SAME ONE YOU SET UP IN THE SSHD_CONFIG FILE
#
-A INPUT -p tcp -m state --state NEW --dport 30000 -j ACCEPT
# Allow ping
-A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT
# log iptables denied calls
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7
# Reject all other inbound - default deny unless explicitly allowed policy
-A INPUT -j REJECT
-A FORWARD -j REJECT
COMMIT

Or you could just link to the excellent article on setting up Ubuntu on the Rackspace Knowledge Center at 'www.rackspace.com/knowledge_center/article/ubuntu-setup'. It's focused on Ubuntu 9.10 and has a couple of minor problems in the instructions on saving and restoring the rules file (which you have covered here very nicely) but has a good set of step-by-step instructions on how to create the key rules.

It says "We'll restart SSH later," but does it actually get around to doing it in this tutorial?

Hm. It doesn't look that way. We'll get this updated. Depending on the distribution, you'll restart ssh by running either:

sudo service sshd restart

or:

sudo service ssh restart

It depends on the distribution, but most call the service sshd. You'd want to make sure to save this step for after you've ensured a port is open for ssh in iptables.

I go through all of this, thanks for the ip rules which I see now, but when I am all done I can not ftp into the server. I want to use Rackspace but man, I'm spending way too much time on this. Do you have a basic LAMP/Ubuntu setup that is secure and good to go. I am fine with the command line, just new to RS.

It might be that iptables rules would block FTP - it usually wants to use a broad range of ports, so you have to do some iptables tweaking to get it to work through a firewall. If possible I'd recommend using sftp instead (which is ftp over ssh, and works with programs like Filezilla and Cyberduck).

We don't have a preconfigured LAMP server image, but the AMP part isn't that hard to get going. This article is more about securing your server to keep people from hacking into your machine after you've put the work into getting it running.

If you do want a fairly painless way to get a LAMP server going on Ubuntu you might look into the "tasksel" package.

Just a heads up,

In Ubuntu, if you include the line

pre-up iptables-restore < /etc/iptables.up.rules

in /etc/network/interfaces, then save the image to CloudFiles and build a NEW server out of that image, you'll lose the rule as the /etc/network/interfaces gets overwritten by Rackspace's server build automation tool.

if new cloud servers support ipv6, should this page contain information regarding the setup of ip6tables information too?

You're right, it should. We'll work on updating it. Fortunately the syntax between iptables and ip6tables is pretty similar (to the point that I think you can re-use the same rules file between them if you don't refer to any specific IPv4 addresses).

cheers

In this tutorial you don't specify how to add passwords for admin users

You should use sudo to control admin access to the server (this was written for Linux, anyway - Windows would be different). The simplest way to add sudo access for a user is to use visudo and add an entry for the user (either giving it "all" access as we do for "demo" above, or listing just the commands they should be able to access via sudo).

In CentOS 5 there was a chain called RH-Firewall-1-INPUT that was jumped to from the INPUT chain. In CentOS 6 this has been removed and everything is in the INPUT chain instead. So instead of rules like:

# sudo /sbin/iptables -I RH-Firewall-1-INPUT 1 -p tcp --dport http -j ACCEPT

In centos 6+ you should write:

# sudo /sbin/iptables -I INPUT 1 -p tcp --dport http -j ACCEPT

Thanks Tamik. We'll try to get this article updated soon to account for the CentOS 6 changes.

I had to chown the cloud directory before I could scp the public key there:

(as root) chown demo /home/demo/

Then it worked fine.

Curious. Normally when the user is created the home directory should also be created and chowned to the new user. If you had to create the directory manually, though, you would indeed need to make sure the directory was owned by and accessible to the demo user.

Add new comment