Skip to content

Commit 6fbd316

Browse files
siggimooMilo Hysonpeterwoodworthmergify[bot]
authored
Add role-chaining support (#688)
* Add role-chaining support * fix version in readme * minor readme adjustment --------- Co-authored-by: Milo Hyson <mhyson@tunein.com> Co-authored-by: peterwoodworth <woodwoop@amazon.com> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
1 parent 19f3a6d commit 6fbd316

File tree

4 files changed

+55
-22
lines changed

4 files changed

+55
-22
lines changed

README.md

+26-8
Original file line numberDiff line numberDiff line change
@@ -108,17 +108,18 @@ There are four different supported ways to retrieve credentials. We recommend
108108
using [GitHub's OIDC provider](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services)
109109
to get short-lived credentials needed for your actions. Specifying
110110
`role-to-assume` **without** providing an `aws-access-key-id` or a
111-
`web-identity-token-file` will signal to the action that you wish to use the
112-
OIDC provider.
111+
`web-identity-token-file`, or setting `role-chaining`, will signal to the action that you wish to use the
112+
OIDC provider. If `role-chaining` is `true`, existing credentials in the environment will be used to assume `role-to-assume`.
113113

114114
The following table describes which identity is used based on which values are supplied to the Action:
115115

116-
| **Identity Used** | `aws-access-key-id` | `role-to-assume` | `web-identity-token-file` |
117-
| --------------------------------------------------------------- | ------------------- | ---------------- | ------------------------- |
118-
| [✅ Recommended] Assume Role directly using GitHub OIDC provider | | ✔ | |
119-
| IAM User | ✔ | | |
120-
| Assume Role using IAM User credentials | ✔ | ✔ | |
121-
| Assume Role using WebIdentity Token File credentials | | ✔ | ✔ |
116+
| **Identity Used** | `aws-access-key-id` | `role-to-assume` | `web-identity-token-file` | `role-chaining` |
117+
| --------------------------------------------------------------- | ------------------- | ---------------- | ------------------------- | - |
118+
| [✅ Recommended] Assume Role directly using GitHub OIDC provider | | ✔ | | |
119+
| IAM User | ✔ | | | |
120+
| Assume Role using IAM User credentials | ✔ | ✔ | | |
121+
| Assume Role using WebIdentity Token File credentials | | ✔ | ✔ | |
122+
| Assume Role using existing credentials | | ✔ | | ✔ |
122123

123124
### Credential Lifetime
124125
The default session duration is **1 hour** when using the OIDC provider to
@@ -148,6 +149,23 @@ In this example, the Action will load the OIDC token from the GitHub-provided en
148149
```yaml
149150
- name: Configure AWS Credentials
150151
uses: aws-actions/configure-aws-credentials@v2
152+
with:
153+
aws-region: us-east-2
154+
role-to-assume: arn:aws:iam::123456789100:role/my-github-actions-role
155+
role-session-name: MySessionName
156+
- name: Configure other AWS Credentials
157+
uses: aws-actions/configure-aws-credentials@v2
158+
with:
159+
aws-region: us-east-2
160+
role-to-assume: arn:aws:iam::987654321000:role/my-second-role
161+
role-session-name: MySessionName
162+
role-chaining: true
163+
```
164+
In this two-step example, the first step will use OIDC to assume the role `arn:aws:iam::123456789100:role/my-github-actions-role` just as in the prior example. Following that, a second step will use this role to assume a different role, `arn:aws:iam::987654321000:role/my-second-role`.
165+
166+
```yaml
167+
- name: Configure AWS Credentials
168+
uses: aws-actions/configure-aws-credentials@v1
151169
with:
152170
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
153171
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

action.yml

+3
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ inputs:
5858
http-proxy:
5959
description: 'Proxy to use for the AWS SDK agent'
6060
required: false
61+
role-chaining:
62+
description: 'Use existing credentials from the environment to assume a new role'
63+
required: false
6164
outputs:
6265
aws-account-id:
6366
description: 'The AWS account ID for the provided credentials'

dist/index.js

+13-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

index.js

+13-7
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ function loadCredentials() {
211211
});
212212
}
213213

214-
async function validateCredentials(expectedAccessKeyId) {
214+
async function validateCredentials(expectedAccessKeyId, roleChaining) {
215215
let credentials;
216216
try {
217217
credentials = await loadCredentials();
@@ -223,10 +223,12 @@ async function validateCredentials(expectedAccessKeyId) {
223223
throw new Error(`Credentials could not be loaded, please check your action inputs: ${error.message}`);
224224
}
225225

226-
const actualAccessKeyId = credentials.accessKeyId;
226+
if (!roleChaining) {
227+
const actualAccessKeyId = credentials.accessKeyId;
227228

228-
if (expectedAccessKeyId && expectedAccessKeyId != actualAccessKeyId) {
229-
throw new Error('Unexpected failure: Credentials loaded by the SDK do not match the access key ID configured by the action');
229+
if (expectedAccessKeyId && expectedAccessKeyId != actualAccessKeyId) {
230+
throw new Error('Unexpected failure: Credentials loaded by the SDK do not match the access key ID configured by the action');
231+
}
230232
}
231233
}
232234

@@ -292,11 +294,14 @@ async function run() {
292294
const maskAccountId = core.getInput('mask-aws-account-id', { required: false });
293295
const roleToAssume = core.getInput('role-to-assume', {required: false});
294296
const roleExternalId = core.getInput('role-external-id', { required: false });
297+
const roleChainingInput = core.getInput('role-chaining', { required: false }) || 'false';
298+
const roleChaining = roleChainingInput.toLowerCase() === 'true';
295299
let roleDurationSeconds = core.getInput('role-duration-seconds', {required: false})
296300
|| (sessionToken && SESSION_ROLE_DURATION)
301+
|| (roleChaining && SESSION_ROLE_DURATION)
297302
|| MAX_ACTION_RUNTIME;
298303
const roleSessionName = core.getInput('role-session-name', { required: false }) || ROLE_SESSION_NAME;
299-
const roleSkipSessionTaggingInput = core.getInput('role-skip-session-tagging', { required: false })|| 'false';
304+
const roleSkipSessionTaggingInput = core.getInput('role-skip-session-tagging', { required: false }) || 'false';
300305
const roleSkipSessionTagging = roleSkipSessionTaggingInput.toLowerCase() === 'true';
301306
const webIdentityTokenFile = core.getInput('web-identity-token-file', { required: false });
302307
const proxyServer = core.getInput('http-proxy', { required: false });
@@ -314,7 +319,8 @@ async function run() {
314319
// environment variable and they won't be providing a web idenity token file or access key either.
315320
// V2 of the action might relax this a bit and create an explicit precedence for these so that customers
316321
// can provide as much info as they want and we will follow the established credential loading precedence.
317-
return roleToAssume && process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN && !accessKeyId && !webIdentityTokenFile
322+
323+
return roleToAssume && process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN && !accessKeyId && !webIdentityTokenFile && !roleChaining
318324
}
319325

320326
// Always export the source credentials and account ID.
@@ -348,7 +354,7 @@ async function run() {
348354
// cases where this action is on a self-hosted runner that doesn't have credentials
349355
// configured correctly, and cases where the user intended to provide input
350356
// credentials but the secrets inputs resolved to empty strings.
351-
await validateCredentials(accessKeyId);
357+
await validateCredentials(accessKeyId, roleChaining);
352358

353359
sourceAccountId = await exportAccountId(maskAccountId, region);
354360
}

0 commit comments

Comments
 (0)