EC2 Instance Hardening for Beginners

Amazon EC2 is a core part of the AWS Platform, providing a near limitless amount of compute for a surprisingly low cost.

It is possible to expose an EC2 instance to the internet, and by default, this is likely exactly what will happen – and whilst you should endevour to avoid this, reality kicks in and this will not always be the case.

Whilst it’s impossible to remove all risks associated with running a computer system, a couple of simple steps the first time you spin up your instance can go a long way in mitigating the potential for external attack in the future.

Assumptions

  • You have an EC2 Instance with a default security group
  • You have Amazon Linux 2 installed on this EC2 Instance

Tighten up your security group(s)

A security group is a VPC (Virtual Private Cloud) concept that acts as a virtual stateful firewall around your network interface. They are the last layer of protection around the instance itself, and are often the easiest way to configure and restrict networking in the AWS Cloud.

When using security groups, you should always try and follow the principle of least privilege – meaning, allow the lowest amount of access, to the lowest number of clients required to complete your task.
Let’s say; for example – you’re trying to configure a simple Apache Web Server on this instance – and you want to allow SSH from only your IP address – you’d want a security group with inbound rules that looks like this

EC2 Inbound Rules allowing SSH from one IP address, and HTTP(S) from everywhere else.

An often missed, but important step beyond the inbound rules, are the outbound rules – by limiting the destination of traffic sent from your instance, you protect yourself if your instance becomes compromised in the future – for example by preventing a botnet from sending out requests from this machine. A good starting point, if you don’t know how you plan on limiting your traffic down is to allow only particular protocols;

Replace your SSH Key and Default User

By default, when you create an EC2 instance, you generate an RSA key, that can be used for root access to the instance. It is generally considered bad practice to log in as root. What we will do next, is create a new user on the machine, with super-user permissions, using a different private key.

$ # Log in to your instance
$ ssh -i /path/to/your/key.pem [email protected]

If you see an error like so, you can fix that by running the below

[email protected]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for '/path/to/your/key.pem' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
$ chmod 400 /path/to/your/key.pem

Now, you can create your new user to replace the existing user. Replace the word “username” with your username.
These two commands will create a user with the name username, and a home directory in /home/username – as well as add that user to the “wheel” group, which is the superusers group.

$ sudo useradd -m username
$ sudo usermod -aG wheel username

Now, we need to add this user to the sudoers list – this will allow them to run the sudo command

$ sudo visudo

# Press the "i" key to go into insert mode
# Then using your arrow keys, go all the way to the bottom
# Paste the following there (replacing username with your username)

username ALL=(ALL) NOPASSWD:ALL

# Then, press the ESC key on your keyboard, and type in ":wq" and press Enter/Return

Next up, back on your own machine in a new terminal (or you can do this on the server if you like, just make sure you copy the resulting files back to your machine) – we will generate a new SSH Private Key that you can use to connect to this instance, as your new user

$ ssh-keygen -o -t ed25519 -a 1000 -f ~/.ssh/id_ed25519 -C "your_name_goes_here"

$ # If you're on a Mac, you can copy the contents of the file automatically to your clipboard with the below command
$ pbcopy < ~/.ssh/id_ed25519.pub

Now, you need to copy the contents of the “~/.ssh/id_ed25519.pub” file and paste it into the text editor in the last step

$ sudo su username # This command will let you become the other user
$ mkdir -p ~/.ssh/
$ touch ~/.ssh/authorized_keys
$ chmod 700 ~/.ssh
$ chmod 600 ~/.ssh/authorized_keys
$ chmod go-w ~
$ nano ~/.ssh/authorized_keys

To exit the last step, first verify your terminal and key looks similar to the below then you can press
CTRL+X then Y then Enter/Return

Next, test it – let’s try and log in to your instance again using your newly generated private key, and you should then see the below.

$ ssh -i ~/.ssh/id_ed25519 [email protected]

Now that you’ve logged in as this user, there is likely never going to be a need for you to log in as the root user again, so – store away the Private Key your instance was created somewhere safe, and don’t lose it.

Update Your Instance

Your instance, whilst reasonably up to date – is likely missing recent versions of some packages. This is because the AMI’s you boot from are generated periodically, updating is simple, and the same as any other RHEL Linux machine.

$ sudo yum update -y

Install Fail2Ban

Fail2Ban is a piece of software that analyses your SSH logs and bans IP’s that show malicious behaviour (e.g. Brute Force attacks).

Because of the way your instance has been set up previously (no passwords, and IP’s restricted for SSH access) – the need for fail2ban is minimal, however there is very little reason not to install it as a preventative measure – for example, if you were to accidently open your security group rules.

$ sudo yum install -y fail2ban

And… that’s it – you’ll find the default config will probably be fine for most use cases

Set up Automatic Updates

Automatic updates are, unfortunately a double edged sword – if you plan on keeping your instance up, and untouched for a long time they are beneficial from a security point of view – however there is very little preventing an update from breaking a piece of software that you are using on the instance itself, though – this is very unlikely if you only configure security updates.

$ sudo yum install -y yum-cron
$ systemctl enable yum-cron

Now, we are going to modify our config for this package – you want to uncomment (remove the # from the line) each of the types of updates we want – in our case, we only want security updates

Once you are done, you can press CTRL+X then Y and then Enter/Return
And then finally

$ sudo service yum-cron start

# It can't hurt to restart the machine, though this is not necessary.
$ sudo reboot