Skip to content

Commit abbe616

Browse files
authored
Merge pull request #714 from Portkey-AI/feat/aws-assume-role-setup
chore: update aws bedrock assume role logic to allow 2 step process f…
2 parents f02f521 + 4394eae commit abbe616

File tree

2 files changed

+61
-20
lines changed

2 files changed

+61
-20
lines changed

src/providers/bedrock/api.ts

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { env } from 'hono/adapter';
12
import { GatewayError } from '../../errors/GatewayError';
23
import { ProviderAPIConfig } from '../types';
34
import { bedrockInvokeModels } from './constants';
@@ -17,16 +18,38 @@ const BedrockAPIConfig: ProviderAPIConfig = {
1718
};
1819

1920
if (providerOptions.awsAuthType === 'assumedRole') {
20-
const { accessKeyId, secretAccessKey, sessionToken } =
21-
(await getAssumedRoleCredentials(
21+
try {
22+
// Assume the role in the source account
23+
const sourceRoleCredentials = await getAssumedRoleCredentials(
2224
c,
23-
providerOptions.awsRoleArn || '',
24-
providerOptions.awsExternalId || '',
25+
env(c).AWS_ASSUME_ROLE_SOURCE_ARN, // Role ARN in the source account
26+
env(c).AWS_ASSUME_ROLE_SOURCE_EXTERNAL_ID || '', // External ID for source role (if needed)
2527
providerOptions.awsRegion || ''
26-
)) || {};
27-
providerOptions.awsAccessKeyId = accessKeyId;
28-
providerOptions.awsSecretAccessKey = secretAccessKey;
29-
providerOptions.awsSessionToken = sessionToken;
28+
);
29+
30+
if (!sourceRoleCredentials) {
31+
throw new Error('Server Error while assuming internal role');
32+
}
33+
34+
// Assume role in destination account using temporary creds obtained in first step
35+
const { accessKeyId, secretAccessKey, sessionToken } =
36+
(await getAssumedRoleCredentials(
37+
c,
38+
providerOptions.awsRoleArn || '',
39+
providerOptions.awsExternalId || '',
40+
providerOptions.awsRegion || '',
41+
{
42+
accessKeyId: sourceRoleCredentials.accessKeyId,
43+
secretAccessKey: sourceRoleCredentials.secretAccessKey,
44+
sessionToken: sourceRoleCredentials.sessionToken,
45+
}
46+
)) || {};
47+
providerOptions.awsAccessKeyId = accessKeyId;
48+
providerOptions.awsSecretAccessKey = secretAccessKey;
49+
providerOptions.awsSessionToken = sessionToken;
50+
} catch (e) {
51+
throw new GatewayError('Error while assuming bedrock role');
52+
}
3053
}
3154

3255
return generateAWSHeaders(

src/providers/bedrock/utils.ts

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -161,27 +161,43 @@ export async function getAssumedRoleCredentials(
161161
c: Context,
162162
awsRoleArn: string,
163163
awsExternalId: string,
164-
awsRegion: string
164+
awsRegion: string,
165+
creds?: {
166+
accessKeyId: string;
167+
secretAccessKey: string;
168+
sessionToken?: string;
169+
}
165170
) {
166171
const cacheKey = `${awsRoleArn}/${awsExternalId}/${awsRegion}`;
167172
const getFromCacheByKey = c.get('getFromCacheByKey');
168173
const putInCacheWithValue = c.get('putInCacheWithValue');
169174

170-
const {
171-
AWS_ASSUME_ROLE_ACCESS_KEY_ID,
172-
AWS_ASSUME_ROLE_SECRET_ACCESS_KEY,
173-
AWS_ASSUME_ROLE_REGION,
174-
} = env(c);
175175
const resp = getFromCacheByKey
176176
? await getFromCacheByKey(env(c), cacheKey)
177177
: null;
178178
if (resp) {
179179
return resp;
180180
}
181-
// Long-term credentials to assume role, static values from ENV
182-
const accessKeyId: string = AWS_ASSUME_ROLE_ACCESS_KEY_ID || '';
183-
const secretAccessKey: string = AWS_ASSUME_ROLE_SECRET_ACCESS_KEY || '';
184-
const region = awsRegion || AWS_ASSUME_ROLE_REGION || 'us-east-1';
181+
182+
// Determine which credentials to use
183+
let accessKeyId: string;
184+
let secretAccessKey: string;
185+
let sessionToken: string | undefined;
186+
187+
if (creds) {
188+
// Use provided credentials
189+
accessKeyId = creds.accessKeyId;
190+
secretAccessKey = creds.secretAccessKey;
191+
sessionToken = creds.sessionToken;
192+
} else {
193+
// Use environment credentials
194+
const { AWS_ASSUME_ROLE_ACCESS_KEY_ID, AWS_ASSUME_ROLE_SECRET_ACCESS_KEY } =
195+
env(c);
196+
accessKeyId = AWS_ASSUME_ROLE_ACCESS_KEY_ID || '';
197+
secretAccessKey = AWS_ASSUME_ROLE_SECRET_ACCESS_KEY || '';
198+
}
199+
200+
const region = awsRegion || 'us-east-1';
185201
const service = 'sts';
186202
const hostname = `sts.${region}.amazonaws.com`;
187203
const signer = new SignatureV4({
@@ -190,10 +206,13 @@ export async function getAssumedRoleCredentials(
190206
credentials: {
191207
accessKeyId,
192208
secretAccessKey,
209+
sessionToken,
193210
},
194211
sha256: Sha256,
195212
});
196-
const url = `https://${hostname}?Action=AssumeRole&Version=2011-06-15&RoleArn=${awsRoleArn}&ExternalId=${awsExternalId}&RoleSessionName=random`;
213+
const date = new Date();
214+
const sessionName = `${date.getFullYear()}${date.getMonth()}${date.getDay()}`;
215+
const url = `https://${hostname}?Action=AssumeRole&Version=2011-06-15&RoleArn=${awsRoleArn}&RoleSessionName=${sessionName}${awsExternalId ? `&ExternalId=${awsExternalId}` : ''}`;
197216
const urlObj = new URL(url);
198217
const requestHeaders = { host: hostname };
199218
const options = {
@@ -227,7 +246,6 @@ export async function getAssumedRoleCredentials(
227246
} catch (error) {
228247
console.error({ message: `Error assuming role:, ${error}` });
229248
}
230-
231249
return credentials;
232250
}
233251

0 commit comments

Comments
 (0)