Address greptile comments

This commit is contained in:
Carlos Monastyrski
2025-09-03 23:48:38 -03:00
parent 78493bf32a
commit 392b72bdbd
5 changed files with 370 additions and 262 deletions
@@ -31,7 +31,8 @@ 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; 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);
@@ -200,14 +201,6 @@ export const AwsIamProvider = (): TDynamicProviderFns => {
if (providerInputs.method === AwsIamAuthType.AssumeRole) { if (providerInputs.method === AwsIamAuthType.AssumeRole) {
sensitiveTokens.push(providerInputs.roleArn); sensitiveTokens.push(providerInputs.roleArn);
} }
if (providerInputs.credentialType === AwsIamCredentialType.TemporaryCredentials) {
if (providerInputs.method === AwsIamAuthType.AccessKey) {
sensitiveTokens.push(providerInputs.accessKey, providerInputs.secretAccessKey);
}
if (providerInputs.method === AwsIamAuthType.AssumeRole) {
sensitiveTokens.push(providerInputs.roleArn);
}
}
const sanitizedErrorMessage = sanitizeString({ const sanitizedErrorMessage = sanitizeString({
unsanitizedString: (err as Error)?.message, unsanitizedString: (err as Error)?.message,
tokens: sensitiveTokens tokens: sensitiveTokens
@@ -243,9 +236,11 @@ export const AwsIamProvider = (): TDynamicProviderFns => {
throw new BadRequestError({ message: "Expiration time must be in the future" }); throw new BadRequestError({ message: "Expiration time must be in the future" });
} }
let durationSeconds = Math.min(requestedDuration, AWS_STS_MAX_DURATION_SESSION_TOKEN); let durationSeconds: number;
if (providerInputs.method === AwsIamAuthType.AssumeRole) { if (providerInputs.method === AwsIamAuthType.AssumeRole) {
// AssumeRole has a lower maximum duration when using temporary credentials
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,
@@ -260,8 +255,6 @@ export const AwsIamProvider = (): TDynamicProviderFns => {
: undefined : undefined
}); });
durationSeconds = Math.min(durationSeconds, AWS_STS_MAX_DURATION_SESSION_TOKEN);
const assumeRoleRes = await stsClient.send( const assumeRoleRes = await stsClient.send(
new AssumeRoleCommand({ new AssumeRoleCommand({
RoleArn: providerInputs.roleArn, RoleArn: providerInputs.roleArn,
@@ -290,6 +283,8 @@ export const AwsIamProvider = (): TDynamicProviderFns => {
}; };
} }
if (providerInputs.method === AwsIamAuthType.AccessKey) { if (providerInputs.method === AwsIamAuthType.AccessKey) {
// GetSessionToken supports longer durations
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(),
@@ -325,6 +320,8 @@ export const AwsIamProvider = (): TDynamicProviderFns => {
}; };
} }
if (providerInputs.method === AwsIamAuthType.IRSA) { if (providerInputs.method === AwsIamAuthType.IRSA) {
// GetSessionToken supports longer durations
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(),
@@ -5,6 +5,17 @@ description: "Learn how to dynamically generate AWS IAM Users."
The Infisical AWS IAM dynamic secret allows you to generate AWS IAM Users and temporary credentials on demand based on a configured AWS policy. Infisical supports several authentication methods to connect to your AWS account, including assuming an IAM Role, using IAM Roles for Service Accounts (IRSA) on EKS, or static Access Keys. The Infisical AWS IAM dynamic secret allows you to generate AWS IAM Users and temporary credentials on demand based on a configured AWS policy. Infisical supports several authentication methods to connect to your AWS account, including assuming an IAM Role, using IAM Roles for Service Accounts (IRSA) on EKS, or static Access Keys.
## AWS STS Duration Limits
When using **Temporary Credentials**, AWS STS has specific maximum duration limits:
- **AssumeRole operations**: Maximum 1 hour (3600 seconds) when using temporary credentials
- **GetSessionToken operations** (Access Key & IRSA): Maximum 12 hours (43200 seconds)
<Info>
**Automatic Duration Adjustment**: If you specify a TTL that exceeds these AWS limits, Infisical will automatically use the maximum allowed duration instead of failing the operation. This ensures your dynamic secrets work reliably within AWS constraints.
</Info>
## Prerequisite ## Prerequisite
Infisical needs an AWS IAM principal (a user or a role) with the required permissions to create and manage other IAM users and temporary credentials. This principal will be responsible for the lifecycle of the dynamically generated users and temporary credentials. Infisical needs an AWS IAM principal (a user or a role) with the required permissions to create and manage other IAM users and temporary credentials. This principal will be responsible for the lifecycle of the dynamically generated users and temporary credentials.
@@ -267,6 +278,10 @@ Infisical needs an AWS IAM principal (a user or a role) with the required permis
- Include an AWS Session Token - Include an AWS Session Token
- Be valid for the duration specified in Default TTL - Be valid for the duration specified in Default TTL
</Info> </Info>
<Warning>
**Duration Limit**: AssumeRole temporary credentials are limited to 1 hour maximum by AWS. TTL values exceeding this limit will be automatically adjusted to 1 hour.
</Warning>
</Tab> </Tab>
</Tabs> </Tabs>
</Step> </Step>
@@ -479,6 +494,10 @@ Infisical needs an AWS IAM principal (a user or a role) with the required permis
- Include an AWS Session Token - Include an AWS Session Token
- Be valid for the duration specified in Default TTL - Be valid for the duration specified in Default TTL
</Info> </Info>
<Note>
**Duration Limit**: IRSA temporary credentials support up to 12 hours maximum via GetSessionToken. TTL values exceeding this limit will be automatically adjusted.
</Note>
</Tab> </Tab>
</Tabs> </Tabs>
</Step> </Step>
@@ -606,6 +625,10 @@ Infisical needs an AWS IAM principal (a user or a role) with the required permis
- Include an AWS Session Token - Include an AWS Session Token
- Be valid for the duration specified in Default TTL - Be valid for the duration specified in Default TTL
</Info> </Info>
<Note>
**Duration Limit**: Access Key temporary credentials support up to 12 hours maximum via GetSessionToken. TTL values exceeding this limit will be automatically adjusted.
</Note>
</Tab> </Tab>
</Tabs> </Tabs>
@@ -102,7 +102,7 @@ export type TDynamicSecretProvider =
inputs: inputs:
| { | {
method: DynamicSecretAwsIamAuth.AccessKey; method: DynamicSecretAwsIamAuth.AccessKey;
credentialType?: DynamicSecretAwsIamCredentialType; credentialType: DynamicSecretAwsIamCredentialType;
accessKey: string; accessKey: string;
secretAccessKey: string; secretAccessKey: string;
region: string; region: string;
@@ -113,7 +113,7 @@ export type TDynamicSecretProvider =
} }
| { | {
method: DynamicSecretAwsIamAuth.AssumeRole; method: DynamicSecretAwsIamAuth.AssumeRole;
credentialType?: DynamicSecretAwsIamCredentialType; credentialType: DynamicSecretAwsIamCredentialType;
roleArn: string; roleArn: string;
region: string; region: string;
awsPath?: string; awsPath?: string;
@@ -123,7 +123,7 @@ export type TDynamicSecretProvider =
} }
| { | {
method: DynamicSecretAwsIamAuth.IRSA; method: DynamicSecretAwsIamAuth.IRSA;
credentialType?: DynamicSecretAwsIamCredentialType; credentialType: DynamicSecretAwsIamCredentialType;
region: string; region: string;
awsPath?: string; awsPath?: string;
policyDocument?: string; policyDocument?: string;
@@ -25,85 +25,74 @@ import { WorkspaceEnv } from "@app/hooks/api/types";
import { MetadataForm } from "../../DynamicSecretListView/MetadataForm"; import { MetadataForm } from "../../DynamicSecretListView/MetadataForm";
const formSchema = z.object({ const formSchema = z
provider: z.discriminatedUnion("method", [ .object({
z.object({ provider: z.discriminatedUnion("method", [
method: z.literal(DynamicSecretAwsIamAuth.AccessKey), z.object({
credentialType: z method: z.literal(DynamicSecretAwsIamAuth.AccessKey),
.nativeEnum(DynamicSecretAwsIamCredentialType) credentialType: z
.default(DynamicSecretAwsIamCredentialType.IamUser), .nativeEnum(DynamicSecretAwsIamCredentialType)
accessKey: z.string().trim().min(1), .default(DynamicSecretAwsIamCredentialType.IamUser),
secretAccessKey: z.string().trim().min(1), accessKey: z.string().trim().min(1),
region: z.string().trim().min(1), secretAccessKey: z.string().trim().min(1),
awsPath: z.string().trim().optional(), region: z.string().trim().min(1),
permissionBoundaryPolicyArn: z.string().trim().optional(), awsPath: z.string().trim().optional(),
policyDocument: z.string().trim().optional(), permissionBoundaryPolicyArn: z.string().trim().optional(),
userGroups: z.string().trim().optional(), policyDocument: z.string().trim().optional(),
policyArns: z.string().trim().optional(), userGroups: z.string().trim().optional(),
tags: z policyArns: z.string().trim().optional(),
.array( tags: z
z.object({ .array(
key: z.string().trim().min(1).max(128), z.object({
value: z.string().trim().min(1).max(256) key: z.string().trim().min(1).max(128),
}) value: z.string().trim().min(1).max(256)
) })
.optional() )
}), .optional()
z.object({ }),
method: z.literal(DynamicSecretAwsIamAuth.AssumeRole), z.object({
credentialType: z method: z.literal(DynamicSecretAwsIamAuth.AssumeRole),
.nativeEnum(DynamicSecretAwsIamCredentialType) credentialType: z
.default(DynamicSecretAwsIamCredentialType.IamUser), .nativeEnum(DynamicSecretAwsIamCredentialType)
roleArn: z.string().trim().min(1), .default(DynamicSecretAwsIamCredentialType.IamUser),
region: z.string().trim().min(1), roleArn: z.string().trim().min(1),
awsPath: z.string().trim().optional(), region: z.string().trim().min(1),
permissionBoundaryPolicyArn: z.string().trim().optional(), awsPath: z.string().trim().optional(),
policyDocument: z.string().trim().optional(), permissionBoundaryPolicyArn: z.string().trim().optional(),
userGroups: z.string().trim().optional(), policyDocument: z.string().trim().optional(),
policyArns: z.string().trim().optional(), userGroups: z.string().trim().optional(),
tags: z policyArns: z.string().trim().optional(),
.array( tags: z
z.object({ .array(
key: z.string().trim().min(1).max(128), z.object({
value: z.string().trim().min(1).max(256) key: z.string().trim().min(1).max(128),
}) value: z.string().trim().min(1).max(256)
) })
.optional() )
}), .optional()
z.object({ }),
method: z.literal(DynamicSecretAwsIamAuth.IRSA), z.object({
credentialType: z method: z.literal(DynamicSecretAwsIamAuth.IRSA),
.nativeEnum(DynamicSecretAwsIamCredentialType) credentialType: z
.default(DynamicSecretAwsIamCredentialType.IamUser), .nativeEnum(DynamicSecretAwsIamCredentialType)
region: z.string().trim().min(1), .default(DynamicSecretAwsIamCredentialType.IamUser),
awsPath: z.string().trim().optional(), region: z.string().trim().min(1),
permissionBoundaryPolicyArn: z.string().trim().optional(), awsPath: z.string().trim().optional(),
policyDocument: z.string().trim().optional(), permissionBoundaryPolicyArn: z.string().trim().optional(),
userGroups: z.string().trim().optional(), policyDocument: z.string().trim().optional(),
policyArns: z.string().trim().optional(), userGroups: z.string().trim().optional(),
tags: z policyArns: z.string().trim().optional(),
.array( tags: z
z.object({ .array(
key: z.string().trim().min(1).max(128), z.object({
value: z.string().trim().min(1).max(256) key: z.string().trim().min(1).max(128),
}) value: z.string().trim().min(1).max(256)
) })
.optional() )
}) .optional()
]), })
defaultTTL: z.string().superRefine((val, ctx) => { ]),
const valMs = ms(val); defaultTTL: z.string().superRefine((val, ctx) => {
if (valMs < 60 * 1000)
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" });
// a day
if (valMs > 24 * 60 * 60 * 1000)
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
maxTTL: z
.string()
.optional()
.superRefine((val, ctx) => {
if (!val) return;
const valMs = ms(val); const valMs = ms(val);
if (valMs < 60 * 1000) if (valMs < 60 * 1000)
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" });
@@ -111,10 +100,34 @@ const formSchema = z.object({
if (valMs > 24 * 60 * 60 * 1000) if (valMs > 24 * 60 * 60 * 1000)
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}), }),
name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"), maxTTL: z
environment: z.object({ name: z.string(), slug: z.string() }), .string()
usernameTemplate: z.string().nullable().optional() .optional()
}); .superRefine((val, ctx) => {
if (!val) return;
const valMs = ms(val);
if (valMs < 60 * 1000)
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" });
// a day
if (valMs > 24 * 60 * 60 * 1000)
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"),
environment: z.object({ name: z.string(), slug: z.string() }),
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 = {
@@ -7,77 +7,103 @@ import { TtlFormLabel } from "@app/components/features";
import { createNotification } from "@app/components/notifications"; import { createNotification } from "@app/components/notifications";
import { Button, FormControl, Input, Select, SelectItem, TextArea } from "@app/components/v2"; import { Button, FormControl, Input, Select, SelectItem, TextArea } from "@app/components/v2";
import { useGetServerConfig, useUpdateDynamicSecret } from "@app/hooks/api"; import { useGetServerConfig, useUpdateDynamicSecret } from "@app/hooks/api";
import { DynamicSecretAwsIamAuth, TDynamicSecret } from "@app/hooks/api/dynamicSecret/types"; import {
DynamicSecretAwsIamAuth,
DynamicSecretAwsIamCredentialType,
TDynamicSecret
} from "@app/hooks/api/dynamicSecret/types";
import { slugSchema } from "@app/lib/schemas"; import { slugSchema } from "@app/lib/schemas";
import { MetadataForm } from "../MetadataForm"; import { MetadataForm } from "../MetadataForm";
const formSchema = z.object({ const formSchema = z
inputs: z.discriminatedUnion("method", [ .object({
z.object({ inputs: z.discriminatedUnion("method", [
method: z.literal(DynamicSecretAwsIamAuth.AccessKey), z.object({
accessKey: z.string().trim().min(1), method: z.literal(DynamicSecretAwsIamAuth.AccessKey),
secretAccessKey: z.string().trim().min(1), credentialType: z
region: z.string().trim().min(1), .nativeEnum(DynamicSecretAwsIamCredentialType)
awsPath: z.string().trim().optional(), .default(DynamicSecretAwsIamCredentialType.IamUser),
permissionBoundaryPolicyArn: z.string().trim().optional(), accessKey: z.string().trim().min(1),
policyDocument: z.string().trim().optional(), secretAccessKey: z.string().trim().min(1),
userGroups: z.string().trim().optional(), region: z.string().trim().min(1),
policyArns: z.string().trim().optional(), awsPath: z.string().trim().optional(),
tags: z permissionBoundaryPolicyArn: z.string().trim().optional(),
.array(z.object({ key: z.string().trim().min(1), value: z.string().trim().min(1) })) policyDocument: z.string().trim().optional(),
.optional() userGroups: z.string().trim().optional(),
}), policyArns: z.string().trim().optional(),
z.object({ tags: z
method: z.literal(DynamicSecretAwsIamAuth.AssumeRole), .array(z.object({ key: z.string().trim().min(1), value: z.string().trim().min(1) }))
roleArn: z.string().trim().min(1), .optional()
region: z.string().trim().min(1), }),
awsPath: z.string().trim().optional(), z.object({
permissionBoundaryPolicyArn: z.string().trim().optional(), method: z.literal(DynamicSecretAwsIamAuth.AssumeRole),
policyDocument: z.string().trim().optional(), credentialType: z
userGroups: z.string().trim().optional(), .nativeEnum(DynamicSecretAwsIamCredentialType)
policyArns: z.string().trim().optional(), .default(DynamicSecretAwsIamCredentialType.IamUser),
tags: z roleArn: z.string().trim().min(1),
.array(z.object({ key: z.string().trim().min(1), value: z.string().trim().min(1) })) region: z.string().trim().min(1),
.optional() awsPath: z.string().trim().optional(),
}), permissionBoundaryPolicyArn: z.string().trim().optional(),
z.object({ policyDocument: z.string().trim().optional(),
method: z.literal(DynamicSecretAwsIamAuth.IRSA), userGroups: z.string().trim().optional(),
region: z.string().trim().min(1), policyArns: z.string().trim().optional(),
awsPath: z.string().trim().optional(), tags: z
permissionBoundaryPolicyArn: z.string().trim().optional(), .array(z.object({ key: z.string().trim().min(1), value: z.string().trim().min(1) }))
policyDocument: z.string().trim().optional(), .optional()
userGroups: z.string().trim().optional(), }),
policyArns: z.string().trim().optional(), z.object({
tags: z method: z.literal(DynamicSecretAwsIamAuth.IRSA),
.array(z.object({ key: z.string().trim().min(1), value: z.string().trim().min(1) })) credentialType: z
.optional() .nativeEnum(DynamicSecretAwsIamCredentialType)
}) .default(DynamicSecretAwsIamCredentialType.IamUser),
]), region: z.string().trim().min(1),
defaultTTL: z.string().superRefine((val, ctx) => { awsPath: z.string().trim().optional(),
const valMs = ms(val); permissionBoundaryPolicyArn: z.string().trim().optional(),
if (valMs < 60 * 1000) policyDocument: z.string().trim().optional(),
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); userGroups: z.string().trim().optional(),
// a day policyArns: z.string().trim().optional(),
if (valMs > 24 * 60 * 60 * 1000) tags: z
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); .array(z.object({ key: z.string().trim().min(1), value: z.string().trim().min(1) }))
}), .optional()
maxTTL: z })
.string() ]),
.optional() defaultTTL: z.string().superRefine((val, ctx) => {
.superRefine((val, ctx) => {
if (!val) return;
const valMs = ms(val); const valMs = ms(val);
if (valMs < 60 * 1000) if (valMs < 60 * 1000)
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" });
// a day // a day
if (valMs > 24 * 60 * 60 * 1000) if (valMs > 24 * 60 * 60 * 1000)
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}) }),
.nullable(), maxTTL: z
newName: slugSchema().optional(), .string()
usernameTemplate: z.string().trim().nullable().optional() .optional()
}); .superRefine((val, ctx) => {
if (!val) return;
const valMs = ms(val);
if (valMs < 60 * 1000)
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" });
// a day
if (valMs > 24 * 60 * 60 * 1000)
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
})
.nullable(),
newName: slugSchema().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 = {
@@ -115,6 +141,7 @@ export const EditDynamicSecretAwsIamForm = ({
} }
}); });
const method = watch("inputs.method"); const method = watch("inputs.method");
const credentialType = watch("inputs.credentialType");
const updateDynamicSecret = useUpdateDynamicSecret(); const updateDynamicSecret = useUpdateDynamicSecret();
@@ -235,6 +262,39 @@ export const EditDynamicSecretAwsIamForm = ({
</FormControl> </FormControl>
)} )}
/> />
<Controller
name="inputs.credentialType"
control={control}
render={({ field: { value, onChange }, fieldState: { error } }) => (
<FormControl
errorText={error?.message}
isError={Boolean(error?.message)}
label="Credential Type"
>
<>
<Select
value={value}
onValueChange={(val) => onChange(val)}
className="w-full border border-mineshaft-500"
position="popper"
dropdownContainerClassName="max-w-none"
>
<SelectItem value={DynamicSecretAwsIamCredentialType.IamUser}>
IAM User
</SelectItem>
<SelectItem value={DynamicSecretAwsIamCredentialType.TemporaryCredentials}>
Temporary Credentials
</SelectItem>
</Select>
<div className="mt-1 text-xs text-mineshaft-300">
{value === DynamicSecretAwsIamCredentialType.IamUser
? "Creates temporary IAM users with access keys"
: "Uses STS to generate temporary credentials from your connection. Duration is controlled by the Default TTL setting above."}
</div>
</>
</FormControl>
)}
/>
{method === DynamicSecretAwsIamAuth.AccessKey && ( {method === DynamicSecretAwsIamAuth.AccessKey && (
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<Controller <Controller
@@ -289,21 +349,24 @@ export const EditDynamicSecretAwsIamForm = ({
</div> </div>
)} )}
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<Controller {credentialType !== DynamicSecretAwsIamCredentialType.TemporaryCredentials && (
control={control} <Controller
name="inputs.awsPath" control={control}
defaultValue="" name="inputs.awsPath"
render={({ field, fieldState: { error } }) => ( defaultValue=""
<FormControl render={({ field, fieldState: { error } }) => (
label="AWS IAM Path" <FormControl
className="flex-grow" label="AWS IAM Path"
isError={Boolean(error?.message)} className="flex-grow"
errorText={error?.message} isOptional
> isError={Boolean(error?.message)}
<Input {...field} /> errorText={error?.message}
</FormControl> >
)} <Input {...field} />
/> </FormControl>
)}
/>
)}
<Controller <Controller
control={control} control={control}
name="inputs.region" name="inputs.region"
@@ -311,7 +374,11 @@ export const EditDynamicSecretAwsIamForm = ({
render={({ field, fieldState: { error } }) => ( render={({ field, fieldState: { error } }) => (
<FormControl <FormControl
label="AWS Region" label="AWS Region"
className="flex-grow" className={
credentialType === DynamicSecretAwsIamCredentialType.TemporaryCredentials
? "w-full"
: "flex-grow"
}
isError={Boolean(error?.message)} isError={Boolean(error?.message)}
errorText={error?.message} errorText={error?.message}
> >
@@ -320,93 +387,101 @@ export const EditDynamicSecretAwsIamForm = ({
)} )}
/> />
</div> </div>
<Controller {credentialType !== DynamicSecretAwsIamCredentialType.TemporaryCredentials && (
control={control} <>
name="inputs.userGroups" <Controller
defaultValue="" control={control}
render={({ field, fieldState: { error } }) => ( name="inputs.userGroups"
<FormControl defaultValue=""
label="AWS IAM Groups" render={({ field, fieldState: { error } }) => (
isError={Boolean(error?.message)} <FormControl
isOptional label="AWS IAM Groups"
errorText={error?.message} isError={Boolean(error?.message)}
helperText="Generated users will get attached to given groups." isOptional
> errorText={error?.message}
<Input {...field} placeholder="group1,group2" /> helperText="Generated users will get attached to given groups."
</FormControl> >
)} <Input {...field} placeholder="group1,group2" />
/> </FormControl>
<Controller )}
control={control} />
name="inputs.permissionBoundaryPolicyArn" <Controller
defaultValue="" control={control}
render={({ field, fieldState: { error } }) => ( name="inputs.permissionBoundaryPolicyArn"
<FormControl defaultValue=""
label="IAM User Permission Boundary ARN" render={({ field, fieldState: { error } }) => (
isError={Boolean(error?.message)} <FormControl
isOptional label="IAM User Permission Boundary ARN"
errorText={error?.message} isError={Boolean(error?.message)}
helperText="ARN to be attached to the generated user for AWS Permission Boundary." isOptional
> errorText={error?.message}
<Input {...field} /> helperText="ARN to be attached to the generated user for AWS Permission Boundary."
</FormControl> >
)} <Input {...field} />
/> </FormControl>
<Controller )}
control={control} />
name="inputs.policyArns" <Controller
defaultValue="datacenter1" control={control}
render={({ field, fieldState: { error } }) => ( name="inputs.policyArns"
<FormControl defaultValue="datacenter1"
label="AWS Policy ARNs" render={({ field, fieldState: { error } }) => (
isError={Boolean(error?.message)} <FormControl
isOptional label="AWS Policy ARNs"
errorText={error?.message} isError={Boolean(error?.message)}
helperText="Generated users will get attached to given policy arns." isOptional
> errorText={error?.message}
<Input {...field} /> helperText="Generated users will get attached to given policy arns."
</FormControl> >
)} <Input {...field} />
/> </FormControl>
<Controller )}
control={control} />
name="inputs.policyDocument" <Controller
render={({ field, fieldState: { error } }) => ( control={control}
<FormControl name="inputs.policyDocument"
label="AWS IAM Policy Document" render={({ field, fieldState: { error } }) => (
isOptional <FormControl
isError={Boolean(error?.message)} label="AWS IAM Policy Document"
errorText={error?.message} isOptional
helperText="Generated users will have the inline policy." isError={Boolean(error?.message)}
> errorText={error?.message}
<TextArea helperText="Generated users will have the inline policy."
{...field} >
reSize="none" <TextArea
rows={3} {...field}
className="border-mineshaft-600 bg-mineshaft-900 text-sm" reSize="none"
/> rows={3}
</FormControl> className="border-mineshaft-600 bg-mineshaft-900 text-sm"
)} />
/> </FormControl>
<Controller )}
control={control} />
name="usernameTemplate" </>
defaultValue="" )}
render={({ field, fieldState: { error } }) => ( {credentialType !== DynamicSecretAwsIamCredentialType.TemporaryCredentials && (
<FormControl <Controller
label="Username Template" control={control}
isError={Boolean(error?.message)} name="usernameTemplate"
errorText={error?.message} defaultValue=""
> render={({ field, fieldState: { error } }) => (
<Input <FormControl
{...field} label="Username Template"
value={field.value || undefined} isError={Boolean(error?.message)}
className="border-mineshaft-600 bg-mineshaft-900 text-sm" errorText={error?.message}
/> >
</FormControl> <Input
)} {...field}
/> value={field.value || undefined}
<MetadataForm control={control} name="inputs.tags" title="Tags" isValueRequired /> className="border-mineshaft-600 bg-mineshaft-900 text-sm"
/>
</FormControl>
)}
/>
)}
{credentialType !== DynamicSecretAwsIamCredentialType.TemporaryCredentials && (
<MetadataForm control={control} name="inputs.tags" title="Tags" isValueRequired />
)}
</div> </div>
</div> </div>
<div className="mt-4 flex items-center space-x-4"> <div className="mt-4 flex items-center space-x-4">