AWS Security Blog
Using IAM Roles to Distribute Non-AWS Credentials to Your EC2 Instances
Last week’s blog post explained how to distribute AWS credentials to EC2 instances using IAM roles. Will Kruse, Security Engineer on the AWS Identity and Access Management (IAM) team, is back again this week to discuss how roles can also be used to distribute arbitrary secrets to EC2 instances.
As we discussed last week, Amazon EC2 Roles for Instances gives customers a great way to make sure that their EC2 instances have access to exactly the AWS resources they need. Not only is this more secure than bundling the credentials with the AMI or manually distributing them, but it’s also more convenient and easier to manage.
Of course, not all resources accept authentication using AWS access keys. For example, passwords are required for Amazon RDS and Redshift native database users, as well as non-AWS systems running both in the cloud and on-premises. However, by using Amazon EC2 roles for Instances we can easily and securely manage these credentials as well.
The ingredients for our recipe will be the following:
- An S3 bucket for configuration files
- An IAM role with a policy that allows instances launched under that role to read only an appropriate config file
- A Java properties object stored in S3
This solution provides the added advantage of separation of duties; you can restrict access to the configuration file for a group of users separate from those who develop the application. For example, if you want to minimize access to production data, you may only grant your operations staff the ability to read and modify this file. Developers would not have access to this file and, instead, would have a separate configuration file and IAM role for their pre-production environment.
1. Store the Properties File in S3
Using the AWS Java SDK, upload the application’s properties file to S3. Our example properties file is the following:
#Wed Jun 19 10:57:47 PDT 2013 db.host=db.example.com db.username=xyz_user db.password=P43FreSpapaseCU5
We recommend that you use S3’s server-side encryption and upload the file as follows:
private static final String PROPERTIES_KEY = "xyz.properties"; private static final String BUCKET = "<your S3 bucket name>"; private static void savePropertiesToS3(AmazonS3Client client, File propertiesFile) throws IOException { client.deleteObject(BUCKET, PROPERTIES_KEY); PutObjectRequest storePropertiesRequest = new PutObjectRequest(BUCKET, PROPERTIES_KEY, propertiesFile); ObjectMetadata objMetadata = new ObjectMetadata(); objMetadata.setServerSideEncryption (ObjectMetadata.AES_256_SERVER_SIDE_ENCRYPTION); storePropertiesRequest.setMetadata(objMetadata); PutObjectResult result = client.putObject(storePropertiesRequest); }
It can also be uploaded using the S3 Console.
2. Create an IAM Role for Use with EC2
As we described in our previous blog post, create an IAM role that has permission to download this properties file from S3. Here’s a sample policy that you can attach to your role, which will allow instances launched with the role to retrieve the “xyz.properties” file.
{ "Version": "2012-10-17", "Statement": [ { "Action": [ "s3:GetObject" ], "Sid": "Stmt0123456789", "Resource": [ "arn:aws:s3:::<your S3 bucket name>/xyz.properties" ], "Effect": "Allow" } ] }
3. Load the Properties File Directly from S3
Using the AWS Java SDK, this properties file can then be loaded directly from S3 as follows:
private static final String BUCKET = "<your S3 bucket name>"; private static final String PROPERTIES_KEY = "xyz.properties"; private static Properties loadProperties(AmazonS3Client client) throws IOException { S3Object propertiesObject = client.getObject(BUCKET, PROPERTIES_KEY); Properties properties = new Properties(); properties.load(propertiesObject.getObjectContent()); return properties; }
You can then interact with this properties object as you would with one loaded from a local properties file:
properties = loadProperties(client); String db_host = properties.getProperty("db.hostname"); String db_username = properties.getProperty("db.username"); String db_password = properties.getProperty("db.password"); Connection conn = getDBConnection(db_host, db_username, db_password);
Conclusion
IAM roles for EC2 allows software developers to eliminate the need for the “hard-coded credentials” pattern, for both AWS and non-AWS credentials. It also promotes adherence to the principles of Least Privilege and Separation of Duties as we described earlier. Finally, application owners can streamline configuration updates by making a single change in a central configuration file.
– Ben