Photo by Aaron Thomas on Unsplash

Cloud Security Fitness Guide – Exercise #4: Use Roles for EC2

By now, you’re getting the theme that security on AWS is all about being proactive. The point of proactive security is to reduce the attack surface area for people who desire to do you harm. If there’s less area for an attacker, the damage will be smaller. Less damage means more sleep, or more time on the game console, or on the beach, or … you get the idea!

We’ve covered proactive measures like making sure the root account is disabled, we’ve enabled multi-factor authentication on all of our AWS users, and we’ve also recommended that you reduce the number of administrative users to only those that really need it.

Done? Awesome!

We’re now getting into the meat of proactive security practices.  For this installment, we’re going to go a bit deeper into the DevOps world of deploying applications on AWS.

If you’re deploying an application on AWS that requires more than a simple web server, you’re going to quickly want to take advantage of AWS’ giant list of services. After all, we use AWS because we love building awesome things with these services.

In order for an application on an EC2 instance to store objects in S3, process messages from an SQS queue or any number of other AWS services, it will require permission to access the service’s API. The only way to communicate with the API is with an authentication token.

AWS uses API Access and Secret keys to get that authentication token, and yes, your application running on an EC2 instance will need that key pair to get to S3.

One approach is to create an IAM user, generate an Access Key for that user, and place it in a config file for the application to read.

This presents a huge problem, though. That file is now readable, and depending on the permission given to the IAM user who this key belongs to, this can be a massive security problem. Remember practice #4 (about Admin users)? Well, if that key belonged to an Admin user, it’d have access to all AWS services and resources. Imagine if an EC2 instance with this Access key was compromised?

At, one of the top security issues we see is people’s IAM credentials getting compromised. Most of those incidents are due to accidental, non-malicious leaking of API access keys in code committed to a GitHub repo or placed in a config file on a world-readable S3 bucket (more on that in a later tip).

In the past, we mitigated this by using a combination of configuration management, file encryption, EC2 instance metadata, or some other sort of trickery in order to make it harder for someone to read the Access key. None of these were every really that great.

Enter IAM Roles for EC2.

IAM allows for the creation of a Role entity. One of the things you can do with Roles is the ability to assume it using the AWS Security Token Service. In other words, an IAM user can assume a Role to increase their level of privilege. Roles can also be used in combination with external identity providers, such as SAML, to enable Identity Federation to your corporate directory.

Finally, Roles can also be used to allow 3rd parties, such as, to access resources on your behalf. In fact, we at propose that all 3rd party access should be given via Roles only and the only keys you mange are the ones to your home.

AWS also allows EC2 instances the ability to get Role credentials. So how does my application get to those credentials?

If you’re using any of the official AWS SDKs or the AWS CLI, you don’t have to do anything. The SDKs know to look for the temporary credentials that STS has generated for the EC2 instance. If you’re writing an application that isn’t using one of the AWS SDKs, you can also get to the credentials by looking them up in the EC2 instance metadata service.

From the documentation:

$ curl

Results in

"Code" : "Success",
"LastUpdated" : "2012-04-26T16:39:16Z",
"Type" : "AWS-HMAC",
"SecretAccessKey" : "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
"Token" : "token",
"Expiration" : "2012-04-27T22:39:16Z"

That Access and Secret Key pair can be used in any code that requires AWS credentials.

From security perspective, this is an awesome feature to have because we’ve taken care of the following security best practices:

1. Reduced the surface area of attack

EC2 Role credentials are unique to an EC2 instance, if an instance is compromised, terminate the instance and let AutoScaling take care of launching a new one. No need to rotate keys like when an IAM Access Key is compromised.

2. Temporary authentication credentials

STS automatically rotates the credentials when the token expires, and the SDKs and CLI know how to handle this automatically.

3. Auditable activity

The AWS CloudTrail service allows you to examine activity from Roles.

4. Automatically generated authentication credentials

The Access key is not statically assigned to an IAM user, so there is no need to store them in a configuration file.

5. Limited privilege

Roles can be assigned IAM policies, so you can create Roles with very specific access to AWS services and resources. If a group of instances should send messages to a specific SNS topic, then you can restrict it to that topic ARN in the policy.

One other big benefit to DevOps shops is that you no longer have to worry about providing Access Keys to deployment scripts or devise a way to decrypt data bags if you’re running your deployment toolchain on EC2. You have a simple, built-in way to get secure AWS Access Keys to your application deployments.

A quick recap of our past AWS Best Practice posts:

  1. Disable Root API Access Key and Secret Key
  2. Enable MFA Tokens Everywhere
  3. Reduce Number of IAM Users with Admin Rights
  4. Use Roles for EC2
  5. Least Privilege: Limit what IAM Entities Can Do with Strong Policies
  6. Rotate all the Keys Regularly
  7. Use IAM Roles with STS AssumeRole Where Possible
  8. Use AutoScaling to Dampen DDoS Effects
  9. Do Not Allow Unless You Mean It
  10. Watch World-Readable and Listable S3 Bucket Policies