mirror of
https://github.com/aws-actions/configure-aws-credentials.git
synced 2026-09-04 06:15:07 +09:00
feat: upgraded to new GH OIDC API (#284)
This commit is contained in:
@@ -37,7 +37,10 @@ jobs:
|
|||||||
deploy:
|
deploy:
|
||||||
name: Upload to Amazon S3
|
name: Upload to Amazon S3
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
# These permissions are needed to interact with GitHub's OIDC Token endpoint.
|
||||||
|
permissions:
|
||||||
|
id-token: write
|
||||||
|
contents: read
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
@@ -136,24 +139,28 @@ Resources:
|
|||||||
Role:
|
Role:
|
||||||
Type: AWS::IAM::Role
|
Type: AWS::IAM::Role
|
||||||
Properties:
|
Properties:
|
||||||
RoleName: ExampleGithubRole
|
|
||||||
AssumeRolePolicyDocument:
|
AssumeRolePolicyDocument:
|
||||||
Statement:
|
Statement:
|
||||||
- Effect: Allow
|
- Effect: Allow
|
||||||
Action: sts:AssumeRoleWithWebIdentity
|
Action: sts:AssumeRoleWithWebIdentity
|
||||||
Principal:
|
Principal:
|
||||||
Federated: !Ref GithubOidc
|
Federated: !If
|
||||||
|
- CreateOIDCProvider
|
||||||
|
- !Ref GithubOidc
|
||||||
|
- !Ref OIDCProviderArn
|
||||||
Condition:
|
Condition:
|
||||||
StringLike:
|
StringLike:
|
||||||
vstoken.actions.githubusercontent.com:sub: !Sub repo:${GitHubOrg}/${RepositoryName}:*
|
token.actions.githubusercontent.com:sub: !Sub repo:${GitHubOrg}/${RepositoryName}:*
|
||||||
|
|
||||||
GithubOidc:
|
GithubOidc:
|
||||||
Type: AWS::IAM::OIDCProvider
|
Type: AWS::IAM::OIDCProvider
|
||||||
Condition: CreateOIDCProvider
|
Condition: CreateOIDCProvider
|
||||||
Properties:
|
Properties:
|
||||||
Url: https://vstoken.actions.githubusercontent.com
|
Url: https://token.actions.githubusercontent.com
|
||||||
ClientIdList: [sigstore]
|
ClientIdList:
|
||||||
ThumbprintList: [a031c46782e6e6c662c2c87c76da9aa62ccabd8e]
|
- sts.amazonaws.com
|
||||||
|
ThumbprintList:
|
||||||
|
- a031c46782e6e6c662c2c87c76da9aa62ccabd8e
|
||||||
|
|
||||||
Outputs:
|
Outputs:
|
||||||
Role:
|
Role:
|
||||||
|
|||||||
Vendored
+6
-4183
File diff suppressed because one or more lines are too long
@@ -3,7 +3,6 @@ const aws = require('aws-sdk');
|
|||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const axios = require('axios');
|
|
||||||
|
|
||||||
// The max time that a GitHub action is allowed to run is 6 hours.
|
// The max time that a GitHub action is allowed to run is 6 hours.
|
||||||
// That seems like a reasonable default to use if no role duration is defined.
|
// That seems like a reasonable default to use if no role duration is defined.
|
||||||
@@ -185,21 +184,6 @@ async function exportAccountId(maskAccountId, region) {
|
|||||||
return accountId;
|
return accountId;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getWebIdentityToken() {
|
|
||||||
const isDefined = i => !!i;
|
|
||||||
const {ACTIONS_ID_TOKEN_REQUEST_URL, ACTIONS_ID_TOKEN_REQUEST_TOKEN} = process.env;
|
|
||||||
|
|
||||||
assert(
|
|
||||||
[ACTIONS_ID_TOKEN_REQUEST_URL, ACTIONS_ID_TOKEN_REQUEST_TOKEN].every(isDefined),
|
|
||||||
'Missing required environment value. Are you running in GitHub Actions?'
|
|
||||||
);
|
|
||||||
const { data } = await axios.get(`${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=sigstore`, {
|
|
||||||
headers: {"Authorization": `bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}`}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return data.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadCredentials() {
|
function loadCredentials() {
|
||||||
// Force the SDK to re-resolve credentials with the default provider chain.
|
// Force the SDK to re-resolve credentials with the default provider chain.
|
||||||
//
|
//
|
||||||
@@ -303,7 +287,7 @@ async function run() {
|
|||||||
let sourceAccountId;
|
let sourceAccountId;
|
||||||
let webIdentityToken;
|
let webIdentityToken;
|
||||||
if(useGitHubOIDCProvider()) {
|
if(useGitHubOIDCProvider()) {
|
||||||
webIdentityToken = await getWebIdentityToken();
|
webIdentityToken = await core.getIDToken('sts.amazonaws.com');
|
||||||
roleDurationSeconds = core.getInput('role-duration-seconds', {required: false}) || DEFAULT_ROLE_DURATION_FOR_OIDC_ROLES;
|
roleDurationSeconds = core.getInput('role-duration-seconds', {required: false}) || DEFAULT_ROLE_DURATION_FOR_OIDC_ROLES;
|
||||||
// We don't validate the credentials here because we don't have them yet when using OIDC.
|
// We don't validate the credentials here because we don't have them yet when using OIDC.
|
||||||
} else {
|
} else {
|
||||||
@@ -331,13 +315,11 @@ async function run() {
|
|||||||
webIdentityToken
|
webIdentityToken
|
||||||
});
|
});
|
||||||
exportCredentials(roleCredentials);
|
exportCredentials(roleCredentials);
|
||||||
// I don't know a good workaround for this. I'm not sure why we're validating the credentials
|
// We need to validate the credentials in 2 of our use-cases
|
||||||
// so frequently inside the action. The approach I've taken here is that if the GH OIDC token
|
// First: self-hosted runners. If the GITHUB_ACTIONS environment variable
|
||||||
// isn't set, then we're in a self-hosted runner and we need to validate the credentials for
|
// is set to `true` then we are NOT in a self-hosted runner.
|
||||||
// some mysterious reason that wasn't explained by whoever wrote this aciton.
|
// Second: Customer provided credentials manually (IAM User keys stored in GH Secrets)
|
||||||
//
|
if (!process.env.GITHUB_ACTIONS || accessKeyId) {
|
||||||
// It's gross but it works so ... ¯\_(ツ)_/¯
|
|
||||||
if (!process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN) {
|
|
||||||
await validateCredentials(roleCredentials.accessKeyId);
|
await validateCredentials(roleCredentials.accessKeyId);
|
||||||
}
|
}
|
||||||
await exportAccountId(maskAccountId, region);
|
await exportAccountId(maskAccountId, region);
|
||||||
|
|||||||
+9
-6
@@ -2,10 +2,8 @@ const core = require('@actions/core');
|
|||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const aws = require('aws-sdk');
|
const aws = require('aws-sdk');
|
||||||
const run = require('./index.js');
|
const run = require('./index.js');
|
||||||
const axios = require('axios');
|
|
||||||
|
|
||||||
jest.mock('@actions/core');
|
jest.mock('@actions/core');
|
||||||
jest.mock("axios");
|
|
||||||
|
|
||||||
const FAKE_ACCESS_KEY_ID = 'MY-AWS-ACCESS-KEY-ID';
|
const FAKE_ACCESS_KEY_ID = 'MY-AWS-ACCESS-KEY-ID';
|
||||||
const FAKE_SECRET_ACCESS_KEY = 'MY-AWS-SECRET-ACCESS-KEY';
|
const FAKE_SECRET_ACCESS_KEY = 'MY-AWS-SECRET-ACCESS-KEY';
|
||||||
@@ -91,6 +89,12 @@ describe('Configure AWS Credentials', () => {
|
|||||||
.fn()
|
.fn()
|
||||||
.mockImplementation(mockGetInput(DEFAULT_INPUTS));
|
.mockImplementation(mockGetInput(DEFAULT_INPUTS));
|
||||||
|
|
||||||
|
core.getIDToken = jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementation(() => {
|
||||||
|
return "testtoken"
|
||||||
|
});
|
||||||
|
|
||||||
mockStsCallerIdentity.mockReset();
|
mockStsCallerIdentity.mockReset();
|
||||||
mockStsCallerIdentity
|
mockStsCallerIdentity
|
||||||
.mockReturnValueOnce({
|
.mockReturnValueOnce({
|
||||||
@@ -569,9 +573,9 @@ describe('Configure AWS Credentials', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('only role arn and region provided to use GH OIDC Token', async () => {
|
test('only role arn and region provided to use GH OIDC Token', async () => {
|
||||||
|
process.env.GITHUB_ACTIONS = 'true';
|
||||||
process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'test-token';
|
process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'test-token';
|
||||||
process.env.ACTIONS_ID_TOKEN_REQUEST_URL = 'https://www.example.com/token/endpoint';
|
|
||||||
axios.get.mockImplementation(() => Promise.resolve({ data: {value: "testtoken"} }));
|
|
||||||
core.getInput = jest
|
core.getInput = jest
|
||||||
.fn()
|
.fn()
|
||||||
.mockImplementation(mockGetInput({'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION}));
|
.mockImplementation(mockGetInput({'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION}));
|
||||||
@@ -590,9 +594,8 @@ describe('Configure AWS Credentials', () => {
|
|||||||
|
|
||||||
test('GH OIDC With custom role duration', async () => {
|
test('GH OIDC With custom role duration', async () => {
|
||||||
const CUSTOM_ROLE_DURATION = 1234;
|
const CUSTOM_ROLE_DURATION = 1234;
|
||||||
|
process.env.GITHUB_ACTIONS = 'true';
|
||||||
process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'test-token';
|
process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'test-token';
|
||||||
process.env.ACTIONS_ID_TOKEN_REQUEST_URL = 'https://www.example.com/token/endpoint';
|
|
||||||
axios.get.mockImplementation(() => Promise.resolve({ data: {value: "testtoken"} }));
|
|
||||||
core.getInput = jest
|
core.getInput = jest
|
||||||
.fn()
|
.fn()
|
||||||
.mockImplementation(mockGetInput({'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION, 'role-duration-seconds': CUSTOM_ROLE_DURATION}));
|
.mockImplementation(mockGetInput({'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION, 'role-duration-seconds': CUSTOM_ROLE_DURATION}));
|
||||||
|
|||||||
Reference in New Issue
Block a user