Skip to content

Commit 91f6d5f

Browse files
authored
Support OIDC for AWS/Vercel connection (#2325)
1 parent 6ea2a6d commit 91f6d5f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+250
-169
lines changed

.changeset/little-parts-attend.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
"saleor-app-products-feed": patch
3+
"saleor-app-payment-np-atobarai": patch
4+
"saleor-app-klaviyo": patch
5+
"saleor-app-segment": patch
6+
"saleor-app-avatax": patch
7+
"saleor-app-search": patch
8+
"saleor-app-payment-stripe": patch
9+
"saleor-app-smtp": patch
10+
"saleor-app-cms": patch
11+
---
12+
13+
Added support for OIDC between AWS and Vercel (using `@vercel/oidc-aws-credentials-provider`). Now, when `AWS_ARN` env variable is provided, it will take precedence over IAM secrets. This is more secure way to authenticate and is preferred. IAM secrets stay supported, e.g. for local DynamoDB setup.

apps/avatax/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
"@trpc/next": "catalog:",
5454
"@trpc/react-query": "catalog:",
5555
"@trpc/server": "catalog:",
56+
"@vercel/oidc-aws-credentials-provider": "catalog:",
5657
"@vercel/otel": "catalog:",
5758
"avatax": "23.7.0",
5859
"decimal.js-light": "catalog:",

apps/avatax/src/env.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@ export const env = createEnv({
1717
AVATAX_CLIENT_TIMEOUT: z.coerce.number().default(15000),
1818
AVATAX_CLIENT_APP_NAME: z.string().default(packageJson.name),
1919
AVATAX_CLIENT_APP_VERSION: z.string().default(packageJson.version),
20-
AWS_ACCESS_KEY_ID: z.string(),
20+
AWS_ACCESS_KEY_ID: z.string().optional(),
2121
AWS_REGION: z.string(),
22-
AWS_SECRET_ACCESS_KEY: z.string(),
22+
AWS_ROLE_ARN: z.string().optional(),
23+
AWS_SECRET_ACCESS_KEY: z.string().optional(),
2324
DYNAMODB_LOGS_ITEM_TTL_IN_DAYS: z.coerce.number().positive().default(14),
2425
DYNAMODB_LOGS_TABLE_NAME: z.string(),
2526
DYNAMODB_MAIN_TABLE_NAME: z.string(),
@@ -72,6 +73,7 @@ export const env = createEnv({
7273
AVATAX_CLIENT_APP_VERSION: process.env.AVATAX_CLIENT_APP_VERSION,
7374
AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID,
7475
AWS_REGION: process.env.AWS_REGION,
76+
AWS_ROLE_ARN: process.env.AWS_ROLE_ARN,
7577
AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY,
7678
DYNAMODB_LOGS_ITEM_TTL_IN_DAYS: process.env.DYNAMODB_LOGS_ITEM_TTL_IN_DAYS,
7779
DYNAMODB_LOGS_TABLE_NAME: process.env.DYNAMODB_LOGS_TABLE_NAME,

apps/avatax/src/modules/dynamodb/dynamo-client.ts

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
1+
import { DynamoDBClient, type DynamoDBClientConfig } from "@aws-sdk/client-dynamodb";
22
import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb";
3+
import { awsCredentialsProvider } from "@vercel/oidc-aws-credentials-provider";
34

45
import { env } from "@/env";
56

@@ -22,30 +23,26 @@ interface DynamoDBClientOptions {
2223
}
2324

2425
export const createDynamoClient = (opts: DynamoDBClientOptions) => {
26+
const roleArn = env.AWS_ROLE_ARN;
2527
const accessKeyId = env.AWS_ACCESS_KEY_ID;
2628
const secretAccessKey = env.AWS_SECRET_ACCESS_KEY;
2729
const region = env.AWS_REGION;
2830

31+
let credentials: DynamoDBClientConfig["credentials"];
32+
33+
if (roleArn) {
34+
credentials = awsCredentialsProvider({ roleArn });
35+
} else if (accessKeyId && secretAccessKey) {
36+
credentials = { accessKeyId, secretAccessKey };
37+
}
38+
2939
const client = new DynamoDBClient({
3040
requestHandler: {
3141
requestTimeout: opts.requestTimeout,
3242
connectionTimeout: opts.connectionTimeout,
3343
},
3444
maxAttempts: opts.maxAttempts,
35-
/**
36-
* We need to explicitly pass credentials to the client. If not set, SDK will take env variables.
37-
* Some time ago Vercel started to implicitly inject AWS_SESSION_TOKEN which took precedence over AWS_SECRET_ACCESS_KEY,
38-
* but it was not *our* token, but Vercel's.
39-
*
40-
* We should eventually move to OIDC
41-
*/
42-
credentials:
43-
accessKeyId && secretAccessKey
44-
? {
45-
accessKeyId,
46-
secretAccessKey,
47-
}
48-
: undefined,
45+
credentials,
4946
region,
5047
});
5148

apps/avatax/turbo.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"AVATAX_CLIENT_APP_VERSION",
1515
"AWS_ACCESS_KEY_ID",
1616
"AWS_REGION",
17+
"AWS_ROLE_ARN",
1718
"AWS_SECRET_ACCESS_KEY",
1819
"DYNAMODB_LOGS_ITEM_TTL_IN_DAYS",
1920
"DYNAMODB_LOGS_TABLE_NAME",

apps/cms/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
"@trpc/next": "catalog:",
4747
"@trpc/react-query": "catalog:",
4848
"@trpc/server": "catalog:",
49+
"@vercel/oidc-aws-credentials-provider": "catalog:",
4950
"@vercel/otel": "catalog:",
5051
"@vitejs/plugin-react": "catalog:",
5152
"contentful-management": "10.46.4",

apps/cms/src/env-dynamodb.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const dynamoOptionalEnv = createEnv({
99
AWS_REGION: z.string().optional(),
1010
AWS_ACCESS_KEY_ID: z.string().optional(),
1111
AWS_SECRET_ACCESS_KEY: z.string().optional(),
12+
AWS_ROLE_ARN: z.string().optional(),
1213
},
1314
runtimeEnv: {
1415
DYNAMODB_MAIN_TABLE_NAME: process.env.DYNAMODB_MAIN_TABLE_NAME,
@@ -17,15 +18,17 @@ const dynamoOptionalEnv = createEnv({
1718
AWS_REGION: process.env.AWS_REGION,
1819
AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID,
1920
AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY,
21+
AWS_ROLE_ARN: process.env.AWS_ROLE_ARN,
2022
},
2123
isServer: typeof window === "undefined" || process.env.NODE_ENV === "test",
2224
});
2325

2426
const dynamoEnvSchema = z.object({
2527
DYNAMODB_MAIN_TABLE_NAME: z.string(),
2628
AWS_REGION: z.string(),
27-
AWS_ACCESS_KEY_ID: z.string(),
28-
AWS_SECRET_ACCESS_KEY: z.string(),
29+
AWS_ACCESS_KEY_ID: z.string().optional(),
30+
AWS_SECRET_ACCESS_KEY: z.string().optional(),
31+
AWS_ROLE_ARN: z.string().optional(),
2932
DYNAMODB_REQUEST_TIMEOUT_MS: z.number(),
3033
DYNAMODB_CONNECTION_TIMEOUT_MS: z.number(),
3134
});

apps/cms/src/modules/dynamodb/dynamo-main-table.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ export function createDynamoMainTable(dynamoEnv: DynamoEnv): DynamoMainTable {
6565
region: dynamoEnv.AWS_REGION,
6666
accessKeyId: dynamoEnv.AWS_ACCESS_KEY_ID,
6767
secretAccessKey: dynamoEnv.AWS_SECRET_ACCESS_KEY,
68+
roleArn: dynamoEnv.AWS_ROLE_ARN,
6869
});
6970
const documentClient = createDynamoDBDocumentClient(client);
7071

apps/cms/src/modules/dynamodb/dynamodb-client.ts

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
1+
import { DynamoDBClient, type DynamoDBClientConfig } from "@aws-sdk/client-dynamodb";
22
import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb";
3+
import { awsCredentialsProvider } from "@vercel/oidc-aws-credentials-provider";
34

45
interface DynamoDBClientOptions {
56
/**
@@ -18,33 +19,29 @@ interface DynamoDBClientOptions {
1819
*/
1920
maxAttempts?: number;
2021
region: string;
21-
accessKeyId: string;
22-
secretAccessKey: string;
22+
accessKeyId?: string;
23+
secretAccessKey?: string;
24+
roleArn?: string;
2325
}
2426

2527
export const createDynamoDBClient = (opts: DynamoDBClientOptions) => {
26-
const { accessKeyId, secretAccessKey, region } = opts;
28+
const { accessKeyId, secretAccessKey, region, roleArn } = opts;
29+
30+
let credentials: DynamoDBClientConfig["credentials"];
31+
32+
if (roleArn) {
33+
credentials = awsCredentialsProvider({ roleArn });
34+
} else if (accessKeyId && secretAccessKey) {
35+
credentials = { accessKeyId, secretAccessKey };
36+
}
2737

2838
const client = new DynamoDBClient({
2939
requestHandler: {
3040
requestTimeout: opts.requestTimeout,
3141
connectionTimeout: opts.connectionTimeout,
3242
},
3343
maxAttempts: opts.maxAttempts,
34-
/**
35-
* We need to explicitly pass credentials to the client. If not set, SDK will take env variables.
36-
* Some time ago Vercel started to implicitly inject AWS_SESSION_TOKEN which took precedence over AWS_SECRET_ACCESS_KEY,
37-
* but it was not *our* token, but Vercel's.
38-
*
39-
* We should eventually move to OIDC
40-
*/
41-
credentials:
42-
accessKeyId && secretAccessKey
43-
? {
44-
accessKeyId,
45-
secretAccessKey,
46-
}
47-
: undefined,
44+
credentials,
4845
region,
4946
});
5047

apps/cms/turbo.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"STRAPI_MILIS_DELAY_BETWEEN_BATCHES",
1919
"AWS_ACCESS_KEY_ID",
2020
"AWS_REGION",
21+
"AWS_ROLE_ARN",
2122
"AWS_SECRET_ACCESS_KEY",
2223
"DYNAMODB_MAIN_TABLE_NAME",
2324
"DYNAMODB_REQUEST_TIMEOUT_MS",

0 commit comments

Comments
 (0)