Skip to content

Commit 0ec87e3

Browse files
committed
fix: test credential role-chaining failure
1 parent bd944ce commit 0ec87e3

1 file changed

Lines changed: 41 additions & 9 deletions

File tree

packages/amplify-gen2-migration-e2e-system/src/core/credentials.ts

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import fs from 'fs-extra';
22
import path from 'path';
33
import os from 'os';
4-
import { STSClient, AssumeRoleCommand } from '@aws-sdk/client-sts';
4+
import { STSClient, AssumeRoleCommand, AssumeRoleCommandOutput } from '@aws-sdk/client-sts';
55
import { Logger } from './logger';
66

77
/**
@@ -81,14 +81,7 @@ export class CredentialManager {
8181
}
8282
try {
8383
this.logger.info('Refreshing credentials...');
84-
const sts = new STSClient({});
85-
const assumed = await sts.send(
86-
new AssumeRoleCommand({
87-
RoleArn: this.source.roleArn,
88-
RoleSessionName: `gen2-migration-e2e-${Date.now()}`,
89-
DurationSeconds: SESSION_DURATION_SECONDS,
90-
}),
91-
);
84+
const assumed = await this.assumeRoleAsOriginalIdentity();
9285
const creds = assumed.Credentials;
9386
if (!creds?.AccessKeyId || !creds?.SecretAccessKey || !creds?.SessionToken) {
9487
throw new Error('STS AssumeRole returned incomplete credentials');
@@ -110,6 +103,45 @@ export class CredentialManager {
110103
}
111104
}
112105

106+
/**
107+
* Call STS AssumeRole as the original caller (e.g., CodeBuild instance role),
108+
* not as whoever is currently in `AWS_*` env vars. After the first refresh,
109+
* env vars hold the assumed-role credentials; re-assuming from those would
110+
* fail with "not authorized to perform sts:AssumeRole on <role>" because the
111+
* role's trust policy only allows the original caller, not itself.
112+
*
113+
* Temporarily removing env vars forces the SDK default chain to skip them
114+
* and fall through to container/instance metadata, which points at the
115+
* original identity.
116+
*/
117+
private async assumeRoleAsOriginalIdentity(): Promise<AssumeRoleCommandOutput> {
118+
if (this.source.kind !== 'role') {
119+
throw new Error('assumeRoleAsOriginalIdentity called outside role mode');
120+
}
121+
const saved = {
122+
AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID,
123+
AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY,
124+
AWS_SESSION_TOKEN: process.env.AWS_SESSION_TOKEN,
125+
};
126+
delete process.env.AWS_ACCESS_KEY_ID;
127+
delete process.env.AWS_SECRET_ACCESS_KEY;
128+
delete process.env.AWS_SESSION_TOKEN;
129+
try {
130+
const sts = new STSClient({});
131+
return await sts.send(
132+
new AssumeRoleCommand({
133+
RoleArn: this.source.roleArn,
134+
RoleSessionName: `gen2-migration-e2e-${Date.now()}`,
135+
DurationSeconds: SESSION_DURATION_SECONDS,
136+
}),
137+
);
138+
} finally {
139+
if (saved.AWS_ACCESS_KEY_ID !== undefined) process.env.AWS_ACCESS_KEY_ID = saved.AWS_ACCESS_KEY_ID;
140+
if (saved.AWS_SECRET_ACCESS_KEY !== undefined) process.env.AWS_SECRET_ACCESS_KEY = saved.AWS_SECRET_ACCESS_KEY;
141+
if (saved.AWS_SESSION_TOKEN !== undefined) process.env.AWS_SESSION_TOKEN = saved.AWS_SESSION_TOKEN;
142+
}
143+
}
144+
113145
private writeCredentialsFile(accessKeyId: string, secretAccessKey: string, sessionToken: string): void {
114146
const awsDir = path.join(os.homedir(), '.aws');
115147
fs.mkdirSync(awsDir, { recursive: true });

0 commit comments

Comments
 (0)