Using OIDC to deploy CDK to an AWS Account

I have a CDK app that I am trying to deploy using gitlab. I currently have the build working and OIDC configured.

OIDC is working as confirmed with the aws --profile oidc sts get-caller-identity

stages:
  - build
  - deploy

build-cdk:
  stage: build
  image: node:latest
  script:
    - npm install
    - npm run build

deploy:
  stage: deploy
  image:
    name: sleavely/node-awscli:latest
    entrypoint: [""]
  id_tokens:
    GITLAB_OIDC_TOKEN:
      aud: https://gitlab.com
  before_script:
    - mkdir -p ~/.aws
    - echo "${GITLAB_OIDC_TOKEN}" > /tmp/web_identity_token
    - echo -e "[profile oidc]\nregion=us-west-1\nrole_arn=arn:aws:iam::<accountid_redacted>:role/GitLabRunner-backend-cdk\nweb_identity_token_file=/tmp/web_identity_token" > ~/.aws/config
    - echo -e "[oidc]\nsource_profile=oidc" > ~/.aws/credentials
    - export AWS_DEFAULT_PROFILE=oidc
  script:
    - aws --profile oidc sts get-caller-identity
    - npm install
    - npm run cdk -- --verbose deploy StackNameRedacted

This configuration gives this error:

[15:20:23] Unable to determine the default AWS account (ProcessCredentialsProviderFailure): Profile oidc did not include credential process

I’ve tried quite a few things:

  • Explicitly set CDK_DEFAULT_ACCOUNT
  • npm run cdk -- --verbose --profile oidc deploy StackNameRedacted
  • Setting “profile” field in cdk.json

Does anyone have a working example of using cdk deploy from gitlab with OIDC?

So I found a way to do this. It’s a little hackier than I’d like, but it gets the job done:

General idea:

  1. Create an OIDC provider in your AWS account per GitLab’s documentation
  2. Create a role that can be assumed by your OIDC provider (henceforth known as GitLab-OIDC)
  3. Create a second role that can be assumed by GitLab-OIDC (henceforth known as CdkDeployer)
  4. Grant GitLab-OIDC permission to assume the CdkDeployer role
  5. Grant CdkDeployer any permissions needed for your cdk process.
  6. Configure a oidc profile in ~/.aws/config
  7. Add a script to your package that uses the oidc profile to call sts:AssumeRole on CdkDeployer
  8. Configure a deployer profile in ~/.aws/config that uses credential_process calling the script from Step 7
  9. Use the deployer profile when calling CDK: npm run cdk -- --profile deployer [command]

Code, as committed to your package

assume_deploy_role.sh
This will be used for the credential_process on the deployer role

#!/bin/sh
aws --profile oidc sts assume-role --role-arn [cdk deployer arn]  --role-session-name GitLabRunner | ~/jq-linux64 '.Credentials + {"Version": 1}'

aws_config
This will be copied to ~/.aws/config

[profile oidc]
region=us-west-1
role_arn=[oidc role arn]
web_identity_token_file=/tmp/web_identity_token

[profile deployer]
region=us-west-1
credential_process=./assume_deploy_role.sh

.gitlab-ci.yml
This will:

  1. install JQ
  2. copy your aws_config file to ~/.aws/config
  3. prep the OIDC token
  4. Verify both profiles are working using the CLI (optional)
  5. Use the deployer profile to bootstrap the account, if needed
  6. Use the deployer profile to deploy the stack
  deploy:
  stage: deploy
  image:
    name: sleavely/node-awscli:latest
    entrypoint: [""]
  id_tokens:
    GITLAB_OIDC_TOKEN:
      aud: https://gitlab.com
  before_script:
    # Download JQ because this image doesn't have it.
    - wget -O ~/jq-linux64 https://github.com/jqlang/jq/releases/download/jq-1.6/jq-linux64
    - chmod +x ~/jq-linux64
    # Create the ~/.aws/ folder and copy the config over
    - mkdir -p ~/.aws
    - cp ./aws_config ~/.aws/config
    # Prep OIDC token
    - echo "${GITLAB_OIDC_TOKEN}" > /tmp/web_identity_token
  script:
    # Verify OIDC works
    - aws --profile oidc sts get-caller-identity && echo "Profile oidc works"
    # Verify Deployer role works
    - aws --profile deployer sts get-caller-identity && echo "Profile deployer works"
    # install npm modules for cdk
    - npm install
    # run CDK commands with the deployer profile
    - npm run cdk -- --profile deployer --verbose bootstrap
    - npm run cdk -- --profile deployer --verbose deploy [StackName] --require-approval never