Address PR comments

This commit is contained in:
Carlos Monastyrski
2025-09-05 10:48:02 -03:00
parent 392b72bdbd
commit 34e9d68700
3 changed files with 172 additions and 192 deletions
@@ -31,8 +31,6 @@ import { compileUsernameTemplate } from "./templateUtils";
// AWS STS duration constants (in seconds) // AWS STS duration constants (in seconds)
const AWS_STS_MIN_DURATION = 900; const AWS_STS_MIN_DURATION = 900;
const AWS_STS_MAX_DURATION_SESSION_TOKEN = 43200; // 12 hours for GetSessionToken
const AWS_STS_MAX_DURATION_ASSUME_ROLE = 3600; // 1 hour for AssumeRole when using temp credentials
const generateUsername = (usernameTemplate?: string | null, identity?: { name: string }) => { const generateUsername = (usernameTemplate?: string | null, identity?: { name: string }) => {
const randomUsername = alphaNumericNanoId(32); const randomUsername = alphaNumericNanoId(32);
@@ -229,8 +227,8 @@ export const AwsIamProvider = (): TDynamicProviderFns => {
let stsClient: STSClient; let stsClient: STSClient;
let entityId: string; let entityId: string;
const currentTime = Math.floor(Date.now() / 1000); const currentTime = Date.now();
const requestedDuration = expireAt - currentTime; const requestedDuration = Math.floor((expireAt - currentTime) / 1000);
if (requestedDuration <= 0) { if (requestedDuration <= 0) {
throw new BadRequestError({ message: "Expiration time must be in the future" }); throw new BadRequestError({ message: "Expiration time must be in the future" });
@@ -239,8 +237,7 @@ export const AwsIamProvider = (): TDynamicProviderFns => {
let durationSeconds: number; let durationSeconds: number;
if (providerInputs.method === AwsIamAuthType.AssumeRole) { if (providerInputs.method === AwsIamAuthType.AssumeRole) {
// AssumeRole has a lower maximum duration when using temporary credentials durationSeconds = requestedDuration;
durationSeconds = Math.min(requestedDuration, AWS_STS_MAX_DURATION_ASSUME_ROLE);
const appCfg = getConfig(); const appCfg = getConfig();
stsClient = new STSClient({ stsClient = new STSClient({
region: providerInputs.region, region: providerInputs.region,
@@ -259,7 +256,7 @@ export const AwsIamProvider = (): TDynamicProviderFns => {
new AssumeRoleCommand({ new AssumeRoleCommand({
RoleArn: providerInputs.roleArn, RoleArn: providerInputs.roleArn,
RoleSessionName: `infisical-temp-cred-${crypto.nativeCrypto.randomUUID()}`, RoleSessionName: `infisical-temp-cred-${crypto.nativeCrypto.randomUUID()}`,
DurationSeconds: Math.max(durationSeconds, AWS_STS_MIN_DURATION), DurationSeconds: durationSeconds,
ExternalId: metadata.projectId ExternalId: metadata.projectId
}) })
); );
@@ -283,8 +280,7 @@ export const AwsIamProvider = (): TDynamicProviderFns => {
}; };
} }
if (providerInputs.method === AwsIamAuthType.AccessKey) { if (providerInputs.method === AwsIamAuthType.AccessKey) {
// GetSessionToken supports longer durations durationSeconds = requestedDuration;
durationSeconds = Math.min(requestedDuration, AWS_STS_MAX_DURATION_SESSION_TOKEN);
stsClient = new STSClient({ stsClient = new STSClient({
region: providerInputs.region, region: providerInputs.region,
useFipsEndpoint: crypto.isFipsModeEnabled(), useFipsEndpoint: crypto.isFipsModeEnabled(),
@@ -297,7 +293,7 @@ export const AwsIamProvider = (): TDynamicProviderFns => {
const sessionTokenRes = await stsClient.send( const sessionTokenRes = await stsClient.send(
new GetSessionTokenCommand({ new GetSessionTokenCommand({
DurationSeconds: Math.max(durationSeconds, AWS_STS_MIN_DURATION) DurationSeconds: durationSeconds
}) })
); );
@@ -320,8 +316,7 @@ export const AwsIamProvider = (): TDynamicProviderFns => {
}; };
} }
if (providerInputs.method === AwsIamAuthType.IRSA) { if (providerInputs.method === AwsIamAuthType.IRSA) {
// GetSessionToken supports longer durations durationSeconds = requestedDuration;
durationSeconds = Math.min(requestedDuration, AWS_STS_MAX_DURATION_SESSION_TOKEN);
stsClient = new STSClient({ stsClient = new STSClient({
region: providerInputs.region, region: providerInputs.region,
useFipsEndpoint: crypto.isFipsModeEnabled(), useFipsEndpoint: crypto.isFipsModeEnabled(),
@@ -330,7 +325,7 @@ export const AwsIamProvider = (): TDynamicProviderFns => {
const sessionTokenRes = await stsClient.send( const sessionTokenRes = await stsClient.send(
new GetSessionTokenCommand({ new GetSessionTokenCommand({
DurationSeconds: Math.max(durationSeconds, AWS_STS_MIN_DURATION) DurationSeconds: durationSeconds
}) })
); );
@@ -364,8 +359,18 @@ export const AwsIamProvider = (): TDynamicProviderFns => {
if (providerInputs.method === AwsIamAuthType.AssumeRole) { if (providerInputs.method === AwsIamAuthType.AssumeRole) {
sensitiveTokens.push(providerInputs.roleArn); sensitiveTokens.push(providerInputs.roleArn);
} }
let errorMessage = (err as Error)?.message || "Unknown error";
if (err && typeof err === "object" && "name" in err && "$metadata" in err) {
const awsError = err as { name?: string; message?: string; $metadata?: object };
if (awsError.name) {
errorMessage = `${awsError.name}: ${errorMessage}`;
}
}
const sanitizedErrorMessage = sanitizeString({ const sanitizedErrorMessage = sanitizeString({
unsanitizedString: (err as Error)?.message, unsanitizedString: errorMessage,
tokens: sensitiveTokens tokens: sensitiveTokens
}); });
throw new BadRequestError({ throw new BadRequestError({
@@ -25,8 +25,7 @@ import { WorkspaceEnv } from "@app/hooks/api/types";
import { MetadataForm } from "../../DynamicSecretListView/MetadataForm"; import { MetadataForm } from "../../DynamicSecretListView/MetadataForm";
const formSchema = z const formSchema = z.object({
.object({
provider: z.discriminatedUnion("method", [ provider: z.discriminatedUnion("method", [
z.object({ z.object({
method: z.literal(DynamicSecretAwsIamAuth.AccessKey), method: z.literal(DynamicSecretAwsIamAuth.AccessKey),
@@ -115,19 +114,7 @@ const formSchema = z
name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"), name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"),
environment: z.object({ name: z.string(), slug: z.string() }), environment: z.object({ name: z.string(), slug: z.string() }),
usernameTemplate: z.string().nullable().optional() usernameTemplate: z.string().nullable().optional()
}) });
.refine(
(data) => {
if (data.provider.credentialType === DynamicSecretAwsIamCredentialType.TemporaryCredentials) {
return !data.provider.awsPath || data.provider.awsPath === "";
}
return true;
},
{
message: "AWS IAM Path cannot be set when using temporary credentials",
path: ["provider", "awsPath"]
}
);
type TForm = z.infer<typeof formSchema>; type TForm = z.infer<typeof formSchema>;
type Props = { type Props = {
@@ -16,8 +16,7 @@ import { slugSchema } from "@app/lib/schemas";
import { MetadataForm } from "../MetadataForm"; import { MetadataForm } from "../MetadataForm";
const formSchema = z const formSchema = z.object({
.object({
inputs: z.discriminatedUnion("method", [ inputs: z.discriminatedUnion("method", [
z.object({ z.object({
method: z.literal(DynamicSecretAwsIamAuth.AccessKey), method: z.literal(DynamicSecretAwsIamAuth.AccessKey),
@@ -91,19 +90,8 @@ const formSchema = z
.nullable(), .nullable(),
newName: slugSchema().optional(), newName: slugSchema().optional(),
usernameTemplate: z.string().trim().nullable().optional() usernameTemplate: z.string().trim().nullable().optional()
}) });
.refine(
(data) => {
if (data.inputs.credentialType === DynamicSecretAwsIamCredentialType.TemporaryCredentials) {
return !data.inputs.awsPath || data.inputs.awsPath === "";
}
return true;
},
{
message: "AWS IAM Path cannot be set when using temporary credentials",
path: ["inputs", "awsPath"]
}
);
type TForm = z.infer<typeof formSchema>; type TForm = z.infer<typeof formSchema>;
type Props = { type Props = {