I have a job processing architecture based on AWS that requires EC2 instances query S3 and SQS. In order for running instances to have access to the API the credentials are sent as user data (-f) in the form of a base64 encoded shell script. For example:
$ cat ec2.sh
...
export AWS_ACCOUNT_NUMBER='1111-1111-1111'
export AWS_ACCESS_KEY_ID='0x0x0x0x0x0x0x0x0x0'
...
$ zip -P 'secret-password' ec2.sh
$ openssl enc -base64 -in ec2.zip
Many instances are launched...
$ ec2run ami-a83fabc0 -n 20 -f ec2.zip
Each instance decodes and decrypts ec2.zip using the 'secret-password' which is hard-coded into an init script. Although it does work, I have two issues with my approach.
- 'zip -P' is not very secure
- The password is hard-coded in the instance (it's always 'secret-password')
The method is very similar to the one described here
Is there a more elegant or accepted approach? Using gpg to encrypt the credentials and storing the private key on the instance to decrypt it is an approach I'm considering now but I'm unaware of any caveats. Can I use the AWS keypairs directly? Am I missing some super obvious part of the API?
Like others have already pointed out here, you don't really need to store AWS credentials for an EC2 instance, by using IAM Roles - https://aws.amazon.com/blogs/security/a-safer-way-to-distribute-aws-credentials-to-ec2/. I will add that you can employ the same method also for securely storing NON-AWS credentials for you EC2 instance, like say if you have some db credentials you want to keep secure. You save the non-aws credentials on a S3 Bukcet, and use IAM role to access that bucket. you can find more detailed information on that here - https://aws.amazon.com/blogs/security/using-iam-roles-to-distribute-non-aws-credentials-to-your-ec2-instances/
The best way is to use instance profiles. The basic idea is:
Assign a policy to the previously created role, for example:
{ "Statement": [ { "Sid": "Stmt1369049349504", "Action": "sqs:", "Effect": "Allow", "Resource": "" } ] }
Associate the role and instance profile together.
If all works well, and the library you use to connect to AWS services from within your EC2 instance supports retrieving the credentials from the instance meta-data, your code will be able to use the AWS services.
A complete example taken from the boto-user mailing list:
First, you have to create a JSON policy document that represents what services and resources the IAM role should have access to. for example, this policy grants all S3 actions for the bucket "my_bucket". You can use whatever policy is appropriate for your application.
Next, you need to create an Instance Profile in IAM.
Once you have the instance profile, you need to create the role, add the role to the instance profile and associate the policy with the role.
Now, you can use that instance profile when you launch an instance:
You can store the credentials on the machine (or transfer, use, then remove them.)
You can transfer the credentials over a secure channel (e.g. using
scp
with non-interactive authentication e.g. key pair) so that you would not need to perform any custom encryption (only make sure that permissions are properly set to0400
on the key file at all times, e.g. set the permissions on the master files and usescp -p
)If the above does not answer your question, please provide more specific details re. what your setup is and what you are trying to achieve. Are EC2 actions to be initiated on multiple nodes from a central location? Is SSH available between the multiple nodes and the central location? Etc.
EDIT
Have you considered parameterizing your AMI, requiring those who instantiate your AMI to first populate the user data (
ec2-run-instances -f user-data-file
) with their AWS keys? Your AMI can then dynamically retrieve these per-instance parameters fromhttp://169.254.169.254/1.0/user-data
.UPDATE
OK, here goes a security-minded comparison of the various approaches discussed so far:
user-data
unencryptedtelnet
,curl
,wget
, etc. (can access clear-texthttp://169.254.169.254/1.0/user-data
)http://169.254.169.254/1.0/user-data
)user-data
and encrypted (or decryptable) with easily obtainable keytelnet
,curl
,wget
, etc. (can access clear-texthttp://169.254.169.254/1.0/user-data
)http://169.254.169.254/1.0/user-data
, ulteriorly descrypted with the easily-obtainable key)user-data
and encrypted with not easily obtainable keytelnet
,curl
,wget
, etc. (can access encryptedhttp://169.254.169.254/1.0/user-data
)root
for interactive impersonation) improves securitySo any method involving the AMI
user-data
is not the most secure, because gaining access to any user on the machine (weakest point) compromises the data.This could be mitigated if the S3 credentials were only required for a limited period of time (i.e. during the deployment process only), if AWS allowed you to overwrite or remove the contents of
user-data
when done with it (but this does not appear to be the case.) An alternative would be the creation of temporary S3 credentials for the duration of the deployment process, if possible (compromising these credentials, fromuser-data
, after the deployment process is completed and the credentials have been invalidated with AWS, no longer poses a security threat.)If the above is not applicable (e.g. S3 credentials needed by deployed nodes indefinitely) or not possible (e.g. cannot issue temporary S3 credentials for deployment only) then the best method remains to bite the bullet and
scp
the credentials to the various nodes, possibly in parallel, with the correct ownership and permissions.I'd like to point out that it is not needed to supply any credentials to your EC2 instance anymore. Using IAM, you can create a role for your EC2 instances. In these roles, you can set fine-grained policies that allow your EC2 instance to, for example, get a specific object from a specific S3 bucket and no more. You can read more about IAM Roles in the AWS docs:
http://docs.aws.amazon.com/IAM/latest/UserGuide/WorkingWithRoles.html
I wrote an article examining various methods of passing secrets to an EC2 instance securely and the pros & cons of each.
http://www.shlomoswidler.com/2009/08/how-to-keep-your-aws-credentials-on-ec2.html