17

At my unit tests, I'm using aws-sdk to test the SES, which needs some credentials, we are facing a problem to access the secrets with GitHub Actions.

At beginning I was trying to set the values to ~/.aws/credentials using the run command from github workflows:

# .github/workflows/nodejs.yml
steps:
  ...
  - name: Unit Test
    run: |
      mkdir -p ~/.aws
      touch ~/.aws/credentials

      echo "[default]
      aws_access_key_id = ${{ secrets.AWS_ACCESS_KEY_ID }}
      aws_secret_access_key = ${{ secrets.AWS_SECRET_KEY_ID }}
      region = ${AWS_DEFAULT_REGION}

      [github]
      role_arn = arn:aws:iam::{accountID}:role/{role}
      source_profile = default" > ~/.aws/credentials 

      npm test
    env:
      AWS_DEFAULT_REGION: us-east-1
      CI: true

Originally my test file:

// ses.test.js
const AWS = require("aws-sdk")
const credentials = new AWS.SharedIniFileCredentials({ profile: "github" })
AWS.config.update({ credentials })
...

I tried to use another way to get credentials at my tests like, and also doesn't work:

const AWS = require("aws-sdk")
const credentials = new AWS.ChainableTemporaryCredentials({
  params: {RoleArn: "arn:aws:iam::{accountID}:role/{role}"},
  masterCredentials: new AWS.EnvironmentCredentials("AWS")
)}

AWS.config.update({ credentials })

Finally I tried to create an Action customized (using actions js library like: @actions/core, @actions/io, @actions/exec), to get the AWS env values and set it at ~/.aws/credentials, but also doesn't work as expected

One way that worked was exposing AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY (without use GitHub Actions secrets, not ideal, for security purposes)

Someone has any ideas how AWS credentials could work at GitHub Actions with secrets ?

Thanks a lot for your attention.

fsilva
  • 406
  • 1
  • 3
  • 9
  • 1
    Shouldn't you have a look at the pre-packaged actions for this? https://github.com/actions/aws – Romain Prévost Oct 31 '19 at 13:50
  • hi @RomainPrévost thanks for you answer, it action pretends to use aws cli... maybe I could use to set credentials with the cli, I'll see AWS docs for that. thank you again. – fsilva Oct 31 '19 at 15:52

5 Answers5

23

Luckily the aws-sdk should automatically detect credentials set as environment variables and use them for requests

To get access to secrets in your action, you need to set them in the repo. Then you can expose them to the step as an env var.

For more details see GitHub Encrypted secrets

  1. On GitHub, navigate to the main page of the repository
  2. Under your repository name, click the ⚙ Settings tab
  3. Repository settings button
  4. In the left sidebar, click Secrets
  5. Type a name for your secret in the "Name" input box
  6. Type the value for your secret
  7. Click Add secret

In your case you will want to add secrets for both AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.

Now that those are set you can pass those values into the action via the workflow yaml:

steps:
...
- name: Unit Test
  uses: ...
  env:
    AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
    AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
  run: ...
sql_knievel
  • 1,199
  • 1
  • 13
  • 26
csexton
  • 24,061
  • 15
  • 54
  • 57
  • 2
    actually there should be something more to do as I get this error: `Error: ENOENT: no such file or directory, open '/home/runner/.aws/credentials'` – Matteo Jul 22 '20 at 10:50
14

Avoid using long term and hard coded credentials.

The configure-aws-credentials action provides a mechanism to configure AWS credential and region environment variables for use in other GitHub Actions. The environment variables will be detected by both the AWS SDKs and the AWS CLI to determine the credentials and region to use for AWS API calls.

I recommend configuring configure-aws-credentials to use OpenID Connect (OIDC). This allows your GitHub Actions workflows to access resources in AWS, without needing to store the AWS credentials as long-lived GitHub secrets. The GitHub Configuring OpenID Connect in AWS post walks through setting this up.

To give you a practical example, I set up a pipeline to upload dummy data to a S3 bucket. First set up an OpenID Connect provider, and a role for github to federate into in your AWS account. The examples in configure-aws-credentials are written in CloudFormation but I've translated them to the Python Cloud-Development-Kit(CDK) below. Make sure to change the role condition to match your repository.

        github_oidc_provider = iam.OpenIdConnectProvider(
            self,
            "GithubOIDC",
            url="https://token.actions.githubusercontent.com",  
            thumbprints=["a031c46782e6e6c662c2c87c76da9aa62ccabd8e"],
            client_ids=[
                "sts.amazonaws.com" 
            ]
        )

        github_actions_role = iam.Role(
            self,
            "DeployToBucketRole",
            max_session_duration=cdk.Duration.seconds(3600),
            role_name="github-actions-role",
            description="Github actions deployment role to S3",
            assumed_by=iam.FederatedPrincipal(
                federated=github_oidc_provider.open_id_connect_provider_arn,
                conditions={
                    "StringLike": {
                        # <GITHUB USERNAME>/<YOUR REPO NAME>
                        "token.actions.githubusercontent.com:sub": 'repo:arbitraryrw/cdk-github-actions-demo:*' 
                    }
                },
                assume_role_action="sts:AssumeRoleWithWebIdentity"
            )
        )

        bucket = s3.Bucket(
            self,
            f"example_bucket",
            bucket_name="cdk-github-actions-demo",
            encryption=s3.BucketEncryption.S3_MANAGED,
            enforce_ssl=True,
            block_public_access=s3.BlockPublicAccess.BLOCK_ALL,
            removal_policy=cdk.RemovalPolicy.DESTROY,
            auto_delete_objects=True
        )

        # Give the role permissions to read / write to the bucket
        bucket.grant_read_write(github_actions_role)

You can then reference this in your pipeline and run AWS CLI / SDK commands using these credentials. Notice that the snippet references Github Encrypted Secrets, I recommend leveraging this functionality:

name: Example CDK Pipeline

on:
  push:
    branches: [ main ]

jobs:
  build:
    name: Emulate build step
    runs-on: ubuntu-latest

    steps:
    - name: Checking out repository
      uses: actions/checkout@v2
    - name: "Upload artifacts"
      uses: actions/upload-artifact@v2
      with:
        name: build-artifacts
        path: ${{ github.workspace }}/resources

  deploy:
    needs: build
    name: Deploy build artifacts to S3
    runs-on: ubuntu-latest
    # These permissions are needed to interact with GitHub's OIDC Token endpoint.
    permissions:
      id-token: write
      contents: read

    steps:
    - name: "Download build artifacts"
      uses: actions/download-artifact@v2
      with:
        name: build-artifacts
        path: ${{ github.workspace }}/resources

    - name: Configure AWS credentials from Test account
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-region: us-east-1
        role-to-assume: ${{ secrets.AWS_ROLE_FOR_GITHUB }}
        role-session-name: GitHubActions
    - run: aws sts get-caller-identity
    - name: Copy files to the test website with the AWS CLI
      run: |
        aws s3 sync ./resources s3://${{ secrets.BUCKET_NAME }}

For a full example on how to set this up using the CDK you can take a look at the cdk-github-actions-demo repo I set up.

Dharman
  • 30,962
  • 25
  • 85
  • 135
arbitraryrw
  • 140
  • 1
  • 4
4

Take a look at: https://github.com/aws-actions/configure-aws-credentials

It allows you to configure AWS credential and region environment variables for use in other GitHub Actions. The environment variables will be detected by both the AWS SDKs and the AWS CLI to determine the credentials and region to use for AWS API calls.

Dennis Kieselhorst
  • 1,280
  • 1
  • 13
  • 23
2

I was hitting my head against the wall on the same thing for a while. In my case the setting profile = default was the issue.

I was able to remove that from my script and only having env. If I had both it would throw an error.

env:
    AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
    AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
    AWS_DEFAULT_REGION: 'us-east-1'
0

If running aws from the command line is acceptable for you, you can set the following ENV vars and just use aws commands without needing to run aws configure:

env:
  AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
  AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
  AWS_DEFAULT_REGION: us-east-1
  AWS_DEFAULT_OUTPUT: json
thisismydesign
  • 21,553
  • 9
  • 123
  • 126