AWS OIDC and role_arn interpolation

Hey,

I’m trying to get CircleCI to talk to AWS using OIDC and assumed roles.
However the challenge I’m hitting is that I need to be able to interpolate the role_arn value.

I’ve posted more details over on the aws-cli-orb Github repo, but copying here:

Circleci config extract:

version: 2.1

orbs:
  aws-cli: circleci/aws-cli@4.1.3

jobs:
  check-and-validate:
    docker:
      - image: hashicorp/terraform:1.5.7
    working_directory: ~/src/core
    steps:
      - checkout:
          path: ~/src
      - run: terraform fmt -check=true
      - run: terraform init -backend=false
      - run: terraform validate

  plan:
    parameters:
      app-env:
        type: string
        default: DEV
    docker:
      - image: hashicorp/terraform:1.5.7
    working_directory: ~/src
      - run: |
          export ENV_NAME=<< parameters.app-env >>
          account_id_env="${ENV_NAME}_AWS_ACCOUNT_ID"
          echo "Looking for ${account_id_env} env"
          aws_account_id=$(eval echo \$${account_id_env})
          if [ -z "${aws_account_id}" ]; then
            echo "Didn't find a matching AWS_ACCOUNT_ID env"
            exit 1
          else
            echo "Found a valid AWS Account ID"
            echo "AWS Account ID last 4 = $(echo "$aws_account_id" |tr -c 4)"
            echo "export AWS_ACCOUNT_ID='$aws_account_id'" >> "$BASH_ENV"

			# Generate Role ARN
            echo "export AWS_ROLE_ARN='arn:aws:iam::${aws_account_id}:role/TerraformAdmin'" >> "$BASH_ENV"
            echo "export AWS_CLI_STR_ROLE_ARN='arn:aws:iam::${aws_account_id}:role/TerraformAdmin'" >> "$BASH_ENV"
          fi
      - run: |
          source $BASH_ENV
          if [ -z "$AWS_ACCOUNT_ID" ]; then
            echo "AWS Account ID env is empty"
            exit 1
          else
            echo "Found AWS_ACCOUNT_ID, last 4: $(echo "$AWS_ACCOUNT_ID" | tail -c 5)"
          fi
      - aws-cli/install
      - aws-cli/assume_role_with_web_identity:
          role_arn: "arn:aws:iam::${AWS_ACCOUNT_ID}:role/TerraformAdmin"
          role_session_name: "CircleCI-${CIRCLE_WORKFLOW_ID}-${CIRCLE_JOB}"

...snipped...

workflows:
  "DEV: plan and apply":
    jobs:
      - check-and-validate:
          filters:
            branches:
              ignore: 
                - uat
                - prod
      - plan:
          app-env: DEV
          requires:
            - check-and-validate
          filters:
            branches:
              ignore:
                - uat
                - prod

I’ve tried setting AWS_ACCOUNT_ID using $BASH_ENV redirection, and that works fine for the run step, but not for the aws-cli/assume_role_with_web_identity step, which fails with:

An error occurred (ValidationError) when calling the AssumeRoleWithWebIdentity operation: Request ARN is invalid
Failed to assume role

Exited with code exit status 1

The run command which tests for AWS_ACCOUNT_ID works fine and prints:

Found AWS_ACCOUNT_ID, last 4: 4060

I also tried setting the AWS_CLI_STR_ROLE_ARN env and comment the role_arn input, but that complains with:

Error calling job: 'plan'
Error calling command: 'aws-cli/assume_role_with_web_identity'
Missing required argument(s): role_arn

Any ideas on how I might be able to use a dynamic role_arn value?

Thanks in advance.

Gavin

OK, after lots of trials and error, I managed to get a working solution:

version: 2.1

orbs:
  aws-cli: circleci/aws-cli@4.1.3

commands:
  get-target-aws-account-id:
    description: Get target AWS Account ID
    parameters:
      app-env:
        type: string
    steps:
      - run:
          name: Get Target AWS Account ID
          command: |
            export ENV_NAME=<< parameters.app-env >>
            account_id_env="${ENV_NAME}_AWS_ACCOUNT_ID"
            echo "Looking for ${account_id_env} env"
            aws_account_id=$(eval echo \$${account_id_env})
            if [ -z "${aws_account_id}" ]; then
              echo "Didn't find a matching AWS_ACCOUNT_ID env"
              exit 1
            else
              echo "Found a valid AWS Account ID"
              echo "export TARGET_AWS_ACCOUNT_ID='$aws_account_id'" >> "$BASH_ENV"
              echo "export TERRAFORM_ADMIN_AWS_ROLE_ARN='arn:aws:iam::${aws_account_id}:role/TerraformAdmin'" >> "$BASH_ENV"
            fi
 
jobs:
  check-and-validate:
    docker:
      - image: hashicorp/terraform:1.5.7
    working_directory: ~/src/core
    steps:
      - checkout:
          path: ~/src
      - run:
          name: Check Terraform fmt
          command: terraform fmt -check=true
      - run:
          name: Run Terraform init for validation
          command: terraform init -backend=false
      - run:
          name: Validate Terraform code
          command: terraform validate
      - save_cache:
          key: v1-dot-terraform-{{ .Environment.CIRCLE_SHA1 }}
          paths:
            - ~/src/core/.terraform
  plan:
    parameters:
      app-env:
        type: string
        default: DEV
    docker:
      - image: hashicorp/terraform:1.5.7
    shell: /bin/sh -leo pipefail
    environment:
      BASH_ENV: /etc/profile
    working_directory: ~/src
    steps:
      - get-target-aws-account-id:
          app-env: << parameters.app-env >>
      - aws-cli/setup:
          region: eu-west-2
          role_arn: "arn:aws:iam::<ci-account-id>:role/CircleCITerraformAuth"
          role_session_name: "CircleCI-${CIRCLE_WORKFLOW_ID}-${CIRCLE_JOB}"
          profile_name: oidc
      - aws-cli/role_arn_setup:
          role_arn: "${TERRAFORM_ADMIN_AWS_ROLE_ARN}"
          profile_name: default
          source_profile: oidc
      - checkout

... snipped ...