< Home

Maybe you’ve hit this problem while trying to use a Dockerfile with some AWS cli commands or codeartifact repositories but when building an image with Docker many people forget that in every build-phase Docker is actually creating a new image in a containerized environment. This environment has no idea what is running, storage, environment… on the parent machine.

Good thing Docker provides a lot of ways on how we can pass files to our Docker build or even… how we can set environmental variables.

So how do we do it with an IAM codebuild Role?

Fetching the IAM CodeBuild role temporary credentials

In AWS instances, the credentials aren’t set in the environment but in the instance metadata. This data is provided to you through the HTTP protocol from the URL http://169.254.169.254/latest/meta-data/, you have many categories which provide you a way to easily get a lot of instance data.

ami-id
ami-launch-index
ami-manifest-path
block-device-mapping/
hostname
iam/
instance-action
instance-id
instance-type
local-hostname
local-ipv4
mac
metrics/
network/
placement/
profile
public-hostname
public-ipv4
public-keys/
reservation-id
security-groups
services/

Now, I won’t keep you waiting for much longer but to parse the metadata and set it in your environment of your parent machine is (which will be step 1)

Make sure to copy everything, the first $ is part of the command!

$(jq -r 'keys[] as $k | "export \($k)=\(.[$k])"' <<<$(curl http://169.254.169.254/latest/meta-data/iam/security-credentials/$(curl http://169.254.169.254/latest/meta-data/iam/security-credentials/) | jq '. | { "AWS_SESSION_TOKEN": .["Token"], "AWS_ACCESS_KEY_ID": .["AccessKeyId"], "AWS_SECRET_ACCESS_KEY": .["SecretAccessKey"] }'))

Let me beautify that for a second for you

$(
    jq -r 'keys[] as $k | "export \($k)=\(.[$k])"' 
        <<< $(
            curl http://169.254.169.254/latest/meta-data/iam/security-credentials/
                $(curl http://169.254.169.254/latest/meta-data/iam/security-credentials/) 
                | 
                    jq '. | 
                        { 
                            "AWS_SESSION_TOKEN": .["Token"], 
                            "AWS_ACCESS_KEY_ID": .["AccessKeyId"], 
                            "AWS_SECRET_ACCESS_KEY": .["SecretAccessKey"] 
                        }'
            )
)
  1. We first fetch the AWS metadata JSON with the IAM credentials in it.
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/$(curl http://169.254.169.254/latest/meta-data/iam/security-credentials/)

Now if you are wondering, why two curls? Well, to get the credential information you also need to pass the role-name that is attached to the instance. There is no default way to do this. So the rightmost curl fetches the names and we append that to the left curl which will give us a nice JSON that looks like

{
  "Code" : "Success",
  "LastUpdated" : "2021-12-10T18:47:19Z",
  "Type" : "AWS-HMAC",
  "AccessKeyId" : "ASIAYOVA4...JYLRQW",
  "SecretAccessKey" : "0R7UUIQlib...72nUTx8alPdJDNVkV",
  "Token" : "1gO2OvxrR3tuERahr....kmNeA2WmcyZPpf3Q==",
  "Expiration" : "2021-12-11T01:22:44Z"
}
  1. At the highest level we convert the metadata JSON which gives us the keys Token, AccessKeyId and SecretAccessKey to a JSON output we can more easily craft to the correct environment variables AWS_SESSION_TOKEN, AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY. (I do it this way now as maybe some people have other use-cases where they aren’t going to pass it to another environment but want to use it in the parent environment)
{
  "Code" : "Success",
  "LastUpdated" : "2021-12-10T18:47:19Z",
  "Type" : "AWS-HMAC",
  "AccessKeyId" : "ASIAYOVA4...JYLRQW",
  "SecretAccessKey" : "0R7UUIQlib...72nUTx8alPdJDNVkV",
  "Token" : "1gO2OvxrR3tuERahr....kmNeA2WmcyZPpf3Q==",
  "Expiration" : "2021-12-11T01:22:44Z"
}

Converted to

{
  "AWS_SESSION_TOKEN": "1gO2OvxrR3tuERahr....kmNeA2WmcyZPpf3Q==",
  "AWS_ACCESS_KEY_ID": "ASIAYOVA4...JYLRQW",
  "AWS_SECRET_ACCESS_KEY": "0R7UUIQlib...72nUTx8alPdJDNVkV"
}
  1. So, now you do some weird <<< into another jq?

Correct. First <<< is what they name a here-string. It passes what is on the right to the stdin from the left command. So our well crafted JSON that we see here above will be passed to the last command jq -r 'keys[] as $k | "export \($k)=\(.[$k])"'

jq is quite powerful actually, it can also loop over JSON’s and create strings out of it. Here we will create 3 strings that look like

export AWS_ACCESS_KEY_ID=ASIAYOVA4...JYLRQW
export AWS_SECRET_ACCESS_KEY=0R7UUIQlib...72nUTx8alPdJDNVkV
export AWS_SESSION_TOKEN=1gO2OvxrR3tuERahr....kmNeA2WmcyZPpf3Q==

Notice something? I do hope so. As export is the normal way to set environmental variables

So that is how you can convert the AWS Metadata AWS IAM credentials to environmental variables in Linux!

So let me repeat the command for the scrollers that don’t read the explanation.

Make sure to copy everything, the first $ is part of the command!

$(jq -r 'keys[] as $k | "export \($k)=\(.[$k])"' <<<$(curl http://169.254.169.254/latest/meta-data/iam/security-credentials/$(curl http://169.254.169.254/latest/meta-data/iam/security-credentials/) | jq '. | { "AWS_SESSION_TOKEN": .["Token"], "AWS_ACCESS_KEY_ID": .["AccessKeyId"], "AWS_SECRET_ACCESS_KEY": .["SecretAccessKey"] }'))

Pass it to Docker build

Ok, part 1 is complete, for some this will be probably enough but for those we were reading on how to pass those credentials to the Docker environment. You’ll need to do following changes to your Dockerfile

FROM...

ARG AWS_DEFAULT_REGION=eu-west-1
ARG AWS_ACCESS_KEY_ID 
ARG AWS_SECRET_ACCESS_KEY 
ARG AWS_SESSION_TOKEN 

RUN aws sts get-caller-identity 

And you need to pass those args as build-args!

$ docker build --build-arg AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} --build-arg AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} --build-arg AWS_SESSION_TOKEN=${AWS_SESSION_TOKEN} --build-arg AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION} .

And that is one of the ways you can pass the credentials of a codebuild instance to a docker build!

You can also read about another way were you use a specific role purely for your docker build on the premium support website of AWS. Here they generate the credentials in the parent machine and pass it almost the same way as we do to the docker build.

< Home