4

I have two GitHub Actions, both are identical except that one is triggered manually, and the other when a pull request is completed on the main branch. The manual-deploy workflow works just fine, however the deploy one is failing with "Error: Not authorized to perform sts:AssumeRoleWithWebIdentity". What am I missing? My guess is that the sub must be different between the two events? How do I check?

This works

name: manual-deploy
on:
  workflow_dispatch:

env:
  REACT_APP_VERSION: 0.1.0

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    steps:
      - name: checkout code
        uses: actions/checkout@v3
        
      - name: install node
        uses: actions/setup-node@v3
        # using later versions of node breaks due to react-scripts v5.0.1 incompatible with typescript v5;
        # this specific node version works though
        with:
          node-version: "16.14.2"

      - name: install dependencies
        run: npm install
        
      - name: run tests
        run: npm run test

      - name: get current date
        id: date
        # pacific time = UTC-7:00
        run: echo "REACT_APP_BUILD_DATE=$(date -u +'%m/%d/%Y %H:%M:%SPT' -d '7 hours ago')" >> $GITHUB_ENV
        
      - name: build project
        run: npm run build
        
      - name: configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v2
        with:
          role-to-assume: ${{ SECRETS.AWS_GITHUB_ROLE }}
          aws-region: us-west-2

      - name: deploy to S3 bucket
        run: aws s3 sync ./build/ s3://myProject --delete

      - name: invalidate cloudfront cache
        run: aws cloudfront create-invalidation --distribution-id ${{ SECRETS.AWS_CLOUDFRONT_DIST_ID}} --paths "/*"

This doesn't work

name: deploy
on:
  pull_request:
    branches:
      - main
    types: closed
    paths-ignore:
      - '.github/workflows/**'

env:
  REACT_APP_VERSION: 0.1.0

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    if: github.event.pull_request.merged == true
    permissions:
      id-token: write
      contents: read
    steps:
      - name: checkout code
        uses: actions/checkout@v3
        
      - name: install node
        uses: actions/setup-node@v3
        # using later versions of node breaks due to react-scripts v5.0.1 incompatible with typescript v5;
        # this specific node version works though
        with:
          node-version: "16.14.2"
          
      - name: install dependencies
        run: npm install
        
      - name: run tests
        run: npm run test

      - name: get current date
        id: date
        # pacific time = UTC-7:00
        run: echo "REACT_APP_BUILD_DATE=$(date -u +'%m/%d/%Y %H:%M:%SPT' -d '7 hours ago')" >> $GITHUB_ENV
        
      - name: build project
        run: npm run build
        
      - name: configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v2
        with:
          role-to-assume: ${{ SECRETS.AWS_GITHUB_ROLE }}
          aws-region: us-west-2

      - name: deploy to S3 bucket
        run: aws s3 sync ./build/ s3://myProject --delete

      - name: invalidate cloudfront cache
        run: aws cloudfront create-invalidation --distribution-id ${{ SECRETS.AWS_CLOUDFRONT_DIST_ID}} --paths "/*"

Trust policy

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::<not-sure-if-this-is-sensitive-info>:oidc-provider/token.actions.githubusercontent.com"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    "token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
                },
                "StringLike": {
                    "token.actions.githubusercontent.com:sub": "repo:myGitHub/myProject:ref:refs/heads/main"
                }
            }
        }
    ]
}

I tried rerunning the action in debug mode but that did not provide more useful information.

3 Answers 3

7

Ok, so figured it out. The pull request event uses a different sub, which is "repo:myGitHub/myProject:pull_request". Found this out by setting up AWS ClouldTrail and searched the logs for failed attempts to connect from github.

Sign up to request clarification or add additional context in comments.

4 Comments

Just spent at least 30 minutes trying to track down my issue and this was the only answer that helped. on: pull_request has different results than on: push.
@BenWhaley how did you track this down in cloudTrail, and is management events alone sufficient to catch this? I created a trail an have been waiting for several minutes after a failed github pipeline complaining about permissions but I'm not seeing any new events.?
Just to close the loop on this one, once you setup CloudTrail, you go to management-events, click on the Trail log location, which is an S3 bucket, then after going through the logs you'll find a userIdentity object, with a sibling "errorCode": "AccessDenied" property. userIdentity has the correct arn of the principal, which is "arn:aws:iam::ACCOUNT_ID:oidc-provider/token.actions.githubusercontent.com:sts.amazonaws.com:repo:ORG/REPO:pull_request".
This fixed my issue <3
3

I just spent a few hours on this and found the solution for on: pull_request -

Change

"StringLike": {
                "token.actions.githubusercontent.com:sub": "repo:myGitHub/myProject:ref:refs/heads/main"
            }

To

"StringLike": {
                "token.actions.githubusercontent.com:sub": "repo:myGitHub/myProject:*"
            }

This will make the condition to AssumeRoleWithWebIdentity true.

1 Comment

using * fixes it, but makes it overly open
0

For others who are trying to figure out what OIDC subject is being hit on the AWS side, you can find the SUB like this: in the AWS Console/UI: navigate to the AWS CloudTrail service, create a new CloudTrail with management-events (name it whatever you like, and just stick to management-events, leave the rest defaulted "as is"). Then rerun your github action, wait a little for all the events to be in Cloudtrail, then, in AWS CloudTrail:

  • click on Lake->Query in the left nav,

  • select your event datastore,

  • in the query textarea, enter this request (but replace the ID with the one from the datastore you selected in the previous step):

    SELECT * FROM fffabafbafb-bbb-98748-5ba-babababa616161 WHERE errorCode = 'AccessDenied' AND eventTime > '2024-02-11 00:00:00' AND eventTime < '2024-02-13 00:00:00'

Make sure you enter your own datastore ID, and the dates when you ran your github action.

Now look at the "query results" below, expand all the columns, look at the userIdentity column: you should see what it's trying to use as the SUB. It will be something of this format:

  • repo:<orgName/repoName>:environment:
  • repo:<orgName/repoName>:ref:refs/heads/branchName
  • repo:<orgName/repoName>:ref:refs/tags/
  • repo:<orgName/repoName>:pull_request

With the SUB in hand, just put that in your IAM ROLE (in the example below, the github action can talk to the listed AWS Services/resources IIF the gh action was triggered by a push the main, or "on release" for a certain tag):

Resources:
GithubFederationRole:
  Type: AWS::IAM::Role
  Properties:
    RoleName: my-github-federation-role
    Description: My IAM role for the Github federation
    ManagedPolicyArns:
      - !Ref GithubFederationRolePolicy
    AssumeRolePolicyDocument:
      Version: "2012-10-17"
      Statement:
        - Effect: Allow
          Action: sts:AssumeRoleWithWebIdentity
          Principal:
            Federated: !ImportValue MyGithubFederationOIDCProviderArn
          Condition:
            StringEquals:
              token.actions.githubusercontent.com:aud: sts.amazonaws.com
            StringLike:
              token.actions.githubusercontent.com:sub:
              - !Sub repo:myorgname/myreponame:ref:refs/heads/main
              - !Sub repo:myorgname/myreponame:ref:refs/tags/*

GithubFederationRolePolicy:
  Type: AWS::IAM::ManagedPolicy
  Properties:
    ManagedPolicyName: my-github-federation-role-policy
    PolicyDocument:
      Version: "2012-10-17"
      Statement:
        - Effect: Allow
          Action:
            - sts:GetCallerIdentity
          Resource: "*"

        # Allow access to the source/dev S3 bucket
        - Effect: Allow
          Action:
            - s3:GetObject
            - s3:GetObjectTagging
            - s3:GetObjectVersion
            - s3:GetObjectVersionTagging
            - s3:ListBucket
          Resource:
            - !Sub "arn:aws:s3:::my-bucket-name"
            - !Sub "arn:aws:s3:::my-bucket-name/*"

For completeness of my code sample, you also need to create this ONCE per AWS account:

  GithubFederationOIDCProvider:
Type: AWS::IAM::OIDCProvider
Properties:
  Url: https://token.actions.githubusercontent.com
  ClientIdList:
    - sts.amazonaws.com
  ThumbprintList:
    - ffffffffffffffffffffffffffffffffffffffff

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.