loading...

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

sahays profile image Sanjeet Sahay ・4 min read

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>"
 }
})

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": "*"
  }
}

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"]
        }
    ]
}

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>"

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
 }
})

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>"

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

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

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

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;

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

Posted on by:

sahays profile

Sanjeet Sahay

@sahays

Build stuff and aspire to write about it

Discussion

markdown guide
 

Using the ~/.aws/credentials approach is useful for a development environment where you potentially need to test things with multiple profiles, but for a production deployment, the ENV Variable is preferred, right?

Another important consideration: Don't check credentials into VCS in plain text. It may not seem to bad if the team is small and the repo is private, but eventually, the team will grow and it will be necessary to limit access to the credentials!

 

Good point with the VCS! itβ€˜s very important never commit credentials.

If you use a CI/CD tool like CircleCI or Jenkins you can store the credentials as environment variables so the Containers in the build process have access to them.

So yes for not local environments itβ€˜s a good pattern to use the ENV variable.

 

You make a great point here. In fact, with IAM roles, these environment variables are set which means reading credentials from environment variables is the way to go. I will clarify these in the post πŸ‘πŸΌ