Skip to content

Commit 036a4a1

Browse files
author
Richard H Boyd
authored
feat: upgraded to new GH OIDC API (#284)
1 parent 9aaa1da commit 036a4a1

File tree

4 files changed

+35
-4220
lines changed

4 files changed

+35
-4220
lines changed

README.md

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,10 @@ jobs:
3737
deploy:
3838
name: Upload to Amazon S3
3939
runs-on: ubuntu-latest
40-
40+
# These permissions are needed to interact with GitHub's OIDC Token endpoint.
41+
permissions:
42+
id-token: write
43+
contents: read
4144
steps:
4245
- name: Checkout
4346
uses: actions/checkout@v2
@@ -136,24 +139,28 @@ Resources:
136139
Role:
137140
Type: AWS::IAM::Role
138141
Properties:
139-
RoleName: ExampleGithubRole
140142
AssumeRolePolicyDocument:
141143
Statement:
142144
- Effect: Allow
143145
Action: sts:AssumeRoleWithWebIdentity
144146
Principal:
145-
Federated: !Ref GithubOidc
147+
Federated: !If
148+
- CreateOIDCProvider
149+
- !Ref GithubOidc
150+
- !Ref OIDCProviderArn
146151
Condition:
147152
StringLike:
148-
vstoken.actions.githubusercontent.com:sub: !Sub repo:${GitHubOrg}/${RepositoryName}:*
153+
token.actions.githubusercontent.com:sub: !Sub repo:${GitHubOrg}/${RepositoryName}:*
149154
150155
GithubOidc:
151156
Type: AWS::IAM::OIDCProvider
152157
Condition: CreateOIDCProvider
153158
Properties:
154-
Url: https://vstoken.actions.githubusercontent.com
155-
ClientIdList: [sigstore]
156-
ThumbprintList: [a031c46782e6e6c662c2c87c76da9aa62ccabd8e]
159+
Url: https://token.actions.githubusercontent.com
160+
ClientIdList:
161+
- sts.amazonaws.com
162+
ThumbprintList:
163+
- a031c46782e6e6c662c2c87c76da9aa62ccabd8e
157164
158165
Outputs:
159166
Role:

dist/index.js

Lines changed: 6 additions & 4183 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

index.js

Lines changed: 6 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ const aws = require('aws-sdk');
33
const assert = require('assert');
44
const fs = require('fs');
55
const path = require('path');
6-
const axios = require('axios');
76

87
// The max time that a GitHub action is allowed to run is 6 hours.
98
// That seems like a reasonable default to use if no role duration is defined.
@@ -185,21 +184,6 @@ async function exportAccountId(maskAccountId, region) {
185184
return accountId;
186185
}
187186

188-
async function getWebIdentityToken() {
189-
const isDefined = i => !!i;
190-
const {ACTIONS_ID_TOKEN_REQUEST_URL, ACTIONS_ID_TOKEN_REQUEST_TOKEN} = process.env;
191-
192-
assert(
193-
[ACTIONS_ID_TOKEN_REQUEST_URL, ACTIONS_ID_TOKEN_REQUEST_TOKEN].every(isDefined),
194-
'Missing required environment value. Are you running in GitHub Actions?'
195-
);
196-
const { data } = await axios.get(`${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=sigstore`, {
197-
headers: {"Authorization": `bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}`}
198-
}
199-
);
200-
return data.value;
201-
}
202-
203187
function loadCredentials() {
204188
// Force the SDK to re-resolve credentials with the default provider chain.
205189
//
@@ -303,7 +287,7 @@ async function run() {
303287
let sourceAccountId;
304288
let webIdentityToken;
305289
if(useGitHubOIDCProvider()) {
306-
webIdentityToken = await getWebIdentityToken();
290+
webIdentityToken = await core.getIDToken('sts.amazonaws.com');
307291
roleDurationSeconds = core.getInput('role-duration-seconds', {required: false}) || DEFAULT_ROLE_DURATION_FOR_OIDC_ROLES;
308292
// We don't validate the credentials here because we don't have them yet when using OIDC.
309293
} else {
@@ -331,13 +315,11 @@ async function run() {
331315
webIdentityToken
332316
});
333317
exportCredentials(roleCredentials);
334-
// I don't know a good workaround for this. I'm not sure why we're validating the credentials
335-
// so frequently inside the action. The approach I've taken here is that if the GH OIDC token
336-
// isn't set, then we're in a self-hosted runner and we need to validate the credentials for
337-
// some mysterious reason that wasn't explained by whoever wrote this aciton.
338-
//
339-
// It's gross but it works so ... ¯\_(ツ)_/¯
340-
if (!process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN) {
318+
// We need to validate the credentials in 2 of our use-cases
319+
// First: self-hosted runners. If the GITHUB_ACTIONS environment variable
320+
// is set to `true` then we are NOT in a self-hosted runner.
321+
// Second: Customer provided credentials manually (IAM User keys stored in GH Secrets)
322+
if (!process.env.GITHUB_ACTIONS || accessKeyId) {
341323
await validateCredentials(roleCredentials.accessKeyId);
342324
}
343325
await exportAccountId(maskAccountId, region);

index.test.js

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@ const core = require('@actions/core');
22
const assert = require('assert');
33
const aws = require('aws-sdk');
44
const run = require('./index.js');
5-
const axios = require('axios');
65

76
jest.mock('@actions/core');
8-
jest.mock("axios");
97

108
const FAKE_ACCESS_KEY_ID = 'MY-AWS-ACCESS-KEY-ID';
119
const FAKE_SECRET_ACCESS_KEY = 'MY-AWS-SECRET-ACCESS-KEY';
@@ -91,6 +89,12 @@ describe('Configure AWS Credentials', () => {
9189
.fn()
9290
.mockImplementation(mockGetInput(DEFAULT_INPUTS));
9391

92+
core.getIDToken = jest
93+
.fn()
94+
.mockImplementation(() => {
95+
return "testtoken"
96+
});
97+
9498
mockStsCallerIdentity.mockReset();
9599
mockStsCallerIdentity
96100
.mockReturnValueOnce({
@@ -569,9 +573,9 @@ describe('Configure AWS Credentials', () => {
569573
});
570574

571575
test('only role arn and region provided to use GH OIDC Token', async () => {
576+
process.env.GITHUB_ACTIONS = 'true';
572577
process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'test-token';
573-
process.env.ACTIONS_ID_TOKEN_REQUEST_URL = 'https://www.example.com/token/endpoint';
574-
axios.get.mockImplementation(() => Promise.resolve({ data: {value: "testtoken"} }));
578+
575579
core.getInput = jest
576580
.fn()
577581
.mockImplementation(mockGetInput({'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION}));
@@ -590,9 +594,8 @@ describe('Configure AWS Credentials', () => {
590594

591595
test('GH OIDC With custom role duration', async () => {
592596
const CUSTOM_ROLE_DURATION = 1234;
597+
process.env.GITHUB_ACTIONS = 'true';
593598
process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'test-token';
594-
process.env.ACTIONS_ID_TOKEN_REQUEST_URL = 'https://www.example.com/token/endpoint';
595-
axios.get.mockImplementation(() => Promise.resolve({ data: {value: "testtoken"} }));
596599
core.getInput = jest
597600
.fn()
598601
.mockImplementation(mockGetInput({'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION, 'role-duration-seconds': CUSTOM_ROLE_DURATION}));

0 commit comments

Comments
 (0)