Best practices to use AWS access key and secret in your development environment

sahays

Sanjeet Sahay

Posted on May 17, 2020

Best practices to use AWS access key and secret in your development environment

If you are an AWS developer and are using AWS services in your app, then you must have found yourself looking for the best way to securely store and access your AWS credentials. To keep our AWS account secure, it's important for us to understand the AWS shared responsibility model.
shared responsibility model
In a nutshell, it states that AWS is responsible for the security of the cloud and us, the customers, are responsible for the security in the cloud. Simply put, for developers, it means that we should take special care of our AWS credentials like Access key ID and Secret Access Key.

If you are new to AWS, use the references section below for more information.

1. Anti-pattern: Hardcoding credentials

This is an anti-pattern and must be avoided at all costs. If your code looks like the following then you must act now



const AWS = require("aws-sdk");
AWS.config.update({
 credentials: {
  access_key_id: "<your-access-key-id>",
  secret_access_key: "<your-secret-access-key>"
 }
})


Enter fullscreen mode Exit fullscreen mode

1.1. Why is this bad?

As a developer, you are most likely to commit this code in some repository like a private GitHub repo or your team repository such as BitBucket or AWS CodeCommit. Besides running a risk of using an anti-pattern, you don't want someone to access your hard-coded keys, because it will allow them to access/manage all the resources that these credentials provide access to. If the IAM policy attached to the user whose credentials you are using looks like the following, it means that you have handed over the keys to your AWS kingdom to anybody who has access to your code



{
  "Version": "2012-10-17",
  "Statement": {
    "Effect": "Allow",
    "Action": "*",
    "Resource": "*"
  }
}


Enter fullscreen mode Exit fullscreen mode

1.2. How do I mitigate?

If you think that you can't make changes to your code, then you must modify the IAM policy attached to that role or move them to an IAM group with restrictive privileges e.g. IAM policy that grants least privileges to only a given Amazon S3 bucket:



{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "ListYourObjects",
            "Effect": "Allow",
            "Action": "s3:ListBucket",
            "Resource": ["arn:aws:s3:::bucket-name"]
        },
        {
            "Sid": "ReadWriteDeleteYourObjects",
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:PutObject",
                "s3:DeleteObject"
            ],
            "Resource": ["arn:aws:s3:::bucket-name"]
        }
    ]
}


Enter fullscreen mode Exit fullscreen mode

2. Look ma, no hardcoded credentials

With that anti-pattern out of the way, you may take one of the following approaches to use your AWS credentials.

2.1. Use environment variables



$ export AWS_ACCESS_KEY_ID="<your-access-key-id>"
$ export AWS_SECRET_ACCESS_KEY="<your-secret-access-key>"


Enter fullscreen mode Exit fullscreen mode

then, in your JavaScript/Node.js app, use the following



const AWS = require("aws-sdk");
AWS.config.update({
 credentials: {
  access_key_id: process.env.AWS_ACCESS_KEY_ID,
  secret_access_key: process.env.AWS_SECRET_ACCESS_KEY
 }
})


Enter fullscreen mode Exit fullscreen mode

2.2. Use AWS profile

You can use AWS named profiles to store more than one credential. You can inspect the following two files:

  • ~/.aws/credentials: contains aws_access_key_id and aws_secret_access_key
  • ~/.aws/config: contains region and output

My ~/.aws/credentials file looks like the following and it shows that I am using 2 profiles: default and personal



[default]
aws_access_key_id = "<your-access-key-id>"
aws_secret_access_key = "<your-secret-access-key>"

[personal]
aws_access_key_id = "<your-access-key-id>"
aws_secret_access_key = "<your-secret-access-key>"


Enter fullscreen mode Exit fullscreen mode

My ~/.aws/config file looks like the following:



[default]
region = us-west-2
output=json

[profile personal]
region = us-west-2
output = json


Enter fullscreen mode Exit fullscreen mode

If I want to use my default account, I can use the following code:



const AWS = require("aws-sdk");
const credentials = new AWS.SharedIniFileCredentials({ profile: "default" });
AWS.config.credentials = credentials;

Enter fullscreen mode Exit fullscreen mode




What about my code running in Amazon EC2, AWS Lambda?

I have 3 words for you: "Use IAM roles".

If you have your code running in a Docker container on an Amazon EC2 instance, then understand that every single process on the system has access to IAM roles and your container will assume that role without you having to specify it.

Conclusion

For my development environment, I have found the latter approach of using AWS profiles and using them to access credentials in code better than having to export it. The code is much cleaner and doesn't change if I rotate my keys. All I need to do is to run aws configure on my developer workstation and be done with it. Also, it saves me from the anti-pattern of hard-coding credentials in my code. However, this approach means that you may have to change the code or write conditional code (rarely a good practice) or use environment specific files for your non-development environments where the profile may or may not exist. If you run into such a decision making process, using the environment variable approach is the way to go.

References

💖 💪 🙅 🚩
sahays
Sanjeet Sahay

Posted on May 17, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related