From 489bd124d235712e10a144eae6909853fd89c0c0 Mon Sep 17 00:00:00 2001 From: carlosmonastyrski Date: Tue, 17 Jun 2025 16:06:35 -0300 Subject: [PATCH 1/4] feat(dynamic-secret): Add custom tags to AWS IAM dynamic secret --- .../20250617181915_add-dynamic-secret-tags.ts | 21 ++++++++++++++++ backend/src/db/schemas/dynamic-secrets.ts | 3 ++- .../src/ee/routes/v1/dynamic-secret-router.ts | 2 ++ .../dynamic-secret-lease-service.ts | 1 + .../dynamic-secret/dynamic-secret-service.ts | 8 +++++-- .../dynamic-secret/dynamic-secret-types.ts | 2 ++ .../dynamic-secret/providers/aws-iam.ts | 15 ++++++++++-- .../dynamic-secret/providers/models.ts | 1 + frontend/src/hooks/api/dynamicSecret/types.ts | 4 ++++ .../AwsIamInputForm.tsx | 17 +++++++++---- .../EditDynamicSecretAwsIamForm.tsx | 16 ++++++++++--- .../DynamicSecretListView/MetadataForm.tsx | 24 ++++++++++++++----- 12 files changed, 96 insertions(+), 18 deletions(-) create mode 100644 backend/src/db/migrations/20250617181915_add-dynamic-secret-tags.ts diff --git a/backend/src/db/migrations/20250617181915_add-dynamic-secret-tags.ts b/backend/src/db/migrations/20250617181915_add-dynamic-secret-tags.ts new file mode 100644 index 000000000..d11a98028 --- /dev/null +++ b/backend/src/db/migrations/20250617181915_add-dynamic-secret-tags.ts @@ -0,0 +1,21 @@ +import { Knex } from "knex"; + +import { TableName } from "../schemas"; + +export async function up(knex: Knex): Promise { + const hasCol = await knex.schema.hasColumn(TableName.DynamicSecret, "tags"); + if (!hasCol) { + await knex.schema.alterTable(TableName.DynamicSecret, (t) => { + t.jsonb("tags").nullable(); + }); + } +} + +export async function down(knex: Knex): Promise { + const hasCol = await knex.schema.hasColumn(TableName.DynamicSecret, "tags"); + if (hasCol) { + await knex.schema.alterTable(TableName.DynamicSecret, (t) => { + t.dropColumn("tags"); + }); + } +} diff --git a/backend/src/db/schemas/dynamic-secrets.ts b/backend/src/db/schemas/dynamic-secrets.ts index 637d0c632..2720aa729 100644 --- a/backend/src/db/schemas/dynamic-secrets.ts +++ b/backend/src/db/schemas/dynamic-secrets.ts @@ -29,7 +29,8 @@ export const DynamicSecretsSchema = z.object({ encryptedInput: zodBuffer, projectGatewayId: z.string().uuid().nullable().optional(), gatewayId: z.string().uuid().nullable().optional(), - usernameTemplate: z.string().nullable().optional() + usernameTemplate: z.string().nullable().optional(), + tags: z.unknown().nullable().optional() }); export type TDynamicSecrets = z.infer; diff --git a/backend/src/ee/routes/v1/dynamic-secret-router.ts b/backend/src/ee/routes/v1/dynamic-secret-router.ts index b916bab67..e931d4f82 100644 --- a/backend/src/ee/routes/v1/dynamic-secret-router.ts +++ b/backend/src/ee/routes/v1/dynamic-secret-router.ts @@ -80,6 +80,7 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) => environmentSlug: z.string().describe(DYNAMIC_SECRETS.CREATE.environmentSlug).min(1), name: slugSchema({ min: 1, max: 64, field: "Name" }).describe(DYNAMIC_SECRETS.CREATE.name), metadata: ResourceMetadataSchema.optional(), + tags: ResourceMetadataSchema.optional(), usernameTemplate: userTemplateSchema.optional() }), response: { @@ -146,6 +147,7 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) => .nullable(), newName: z.string().describe(DYNAMIC_SECRETS.UPDATE.newName).optional(), metadata: ResourceMetadataSchema.optional(), + tags: ResourceMetadataSchema.optional(), usernameTemplate: userTemplateSchema.nullable().optional() }) }), diff --git a/backend/src/ee/services/dynamic-secret-lease/dynamic-secret-lease-service.ts b/backend/src/ee/services/dynamic-secret-lease/dynamic-secret-lease-service.ts index 168b16c5f..90d3c9603 100644 --- a/backend/src/ee/services/dynamic-secret-lease/dynamic-secret-lease-service.ts +++ b/backend/src/ee/services/dynamic-secret-lease/dynamic-secret-lease-service.ts @@ -166,6 +166,7 @@ export const dynamicSecretLeaseServiceFactory = ({ usernameTemplate: dynamicSecretCfg.usernameTemplate, identity, metadata: { projectId }, + tags: dynamicSecretCfg.tags as Record[] | undefined, config }); } catch (error: unknown) { diff --git a/backend/src/ee/services/dynamic-secret/dynamic-secret-service.ts b/backend/src/ee/services/dynamic-secret/dynamic-secret-service.ts index 5a7da6a3e..a46ef1c9c 100644 --- a/backend/src/ee/services/dynamic-secret/dynamic-secret-service.ts +++ b/backend/src/ee/services/dynamic-secret/dynamic-secret-service.ts @@ -79,6 +79,7 @@ export const dynamicSecretServiceFactory = ({ defaultTTL, actorAuthMethod, metadata, + tags, usernameTemplate }: TCreateDynamicSecretDTO) => { const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId); @@ -165,7 +166,8 @@ export const dynamicSecretServiceFactory = ({ folderId: folder.id, name, gatewayId: selectedGatewayId, - usernameTemplate + usernameTemplate, + tags: JSON.stringify(tags) }, tx ); @@ -202,6 +204,7 @@ export const dynamicSecretServiceFactory = ({ actorOrgId, actorAuthMethod, metadata, + tags, usernameTemplate }: TUpdateDynamicSecretDTO) => { const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId); @@ -315,7 +318,8 @@ export const dynamicSecretServiceFactory = ({ name: newName ?? name, status: null, gatewayId: selectedGatewayId, - usernameTemplate + usernameTemplate, + tags: JSON.stringify(tags) }, tx ); diff --git a/backend/src/ee/services/dynamic-secret/dynamic-secret-types.ts b/backend/src/ee/services/dynamic-secret/dynamic-secret-types.ts index 6720cf2c8..e8fa010b1 100644 --- a/backend/src/ee/services/dynamic-secret/dynamic-secret-types.ts +++ b/backend/src/ee/services/dynamic-secret/dynamic-secret-types.ts @@ -23,6 +23,7 @@ export type TCreateDynamicSecretDTO = { projectSlug: string; metadata?: ResourceMetadataDTO; usernameTemplate?: string | null; + tags?: ResourceMetadataDTO; } & Omit; export type TUpdateDynamicSecretDTO = { @@ -35,6 +36,7 @@ export type TUpdateDynamicSecretDTO = { inputs?: TProvider["inputs"]; projectSlug: string; metadata?: ResourceMetadataDTO; + tags?: ResourceMetadataDTO; usernameTemplate?: string | null; } & Omit; diff --git a/backend/src/ee/services/dynamic-secret/providers/aws-iam.ts b/backend/src/ee/services/dynamic-secret/providers/aws-iam.ts index f7383d4ac..12a9558c9 100644 --- a/backend/src/ee/services/dynamic-secret/providers/aws-iam.ts +++ b/backend/src/ee/services/dynamic-secret/providers/aws-iam.ts @@ -119,20 +119,31 @@ export const AwsIamProvider = (): TDynamicProviderFns => { identity?: { name: string; }; + tags?: Record[]; metadata: { projectId: string }; }) => { - const { inputs, usernameTemplate, metadata, identity } = data; + const { inputs, usernameTemplate, metadata, identity, tags } = data; const providerInputs = await validateProviderInputs(inputs); const client = await $getClient(providerInputs, metadata.projectId); const username = generateUsername(usernameTemplate, identity); const { policyArns, userGroups, policyDocument, awsPath, permissionBoundaryPolicyArn } = providerInputs; + const awsTags = [{ Key: "createdBy", Value: "infisical-dynamic-secret" }]; + + if (tags && Array.isArray(tags)) { + const additionalTags = tags.map((tag) => ({ + Key: tag.key, + Value: tag.value + })); + awsTags.push(...additionalTags); + } + const createUserRes = await client.send( new CreateUserCommand({ Path: awsPath, PermissionsBoundary: permissionBoundaryPolicyArn || undefined, - Tags: [{ Key: "createdBy", Value: "infisical-dynamic-secret" }], + Tags: awsTags, UserName: username }) ); diff --git a/backend/src/ee/services/dynamic-secret/providers/models.ts b/backend/src/ee/services/dynamic-secret/providers/models.ts index 8f361e166..c86361583 100644 --- a/backend/src/ee/services/dynamic-secret/providers/models.ts +++ b/backend/src/ee/services/dynamic-secret/providers/models.ts @@ -525,6 +525,7 @@ export type TDynamicProviderFns = { name: string; }; metadata: { projectId: string }; + tags?: Record[]; config?: TDynamicSecretLeaseConfig; }) => Promise<{ entityId: string; data: unknown }>; validateConnection: (inputs: unknown, metadata: { projectId: string }) => Promise; diff --git a/frontend/src/hooks/api/dynamicSecret/types.ts b/frontend/src/hooks/api/dynamicSecret/types.ts index e8d80e632..a569e94ba 100644 --- a/frontend/src/hooks/api/dynamicSecret/types.ts +++ b/frontend/src/hooks/api/dynamicSecret/types.ts @@ -15,6 +15,7 @@ export type TDynamicSecret = { maxTTL: string; usernameTemplate?: string | null; metadata?: { key: string; value: string }[]; + tags?: { key: string; value: string }[]; }; export enum DynamicSecretProviders { @@ -89,6 +90,7 @@ export type TDynamicSecretProvider = } | { type: DynamicSecretProviders.AwsIam; + tags?: { key: string; value: string }[]; inputs: | { method: DynamicSecretAwsIamAuth.AccessKey; @@ -345,6 +347,7 @@ export type TCreateDynamicSecretDTO = { name: string; metadata?: { key: string; value: string }[]; usernameTemplate?: string; + tags?: { key: string; value: string }[]; }; export type TUpdateDynamicSecretDTO = { @@ -359,6 +362,7 @@ export type TUpdateDynamicSecretDTO = { maxTTL?: string | null; inputs?: unknown; usernameTemplate?: string | null; + tags?: { key: string; value: string }[]; }; }; diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx index 80c80ee61..60bfa6304 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx @@ -21,6 +21,8 @@ import { } from "@app/hooks/api/dynamicSecret/types"; import { WorkspaceEnv } from "@app/hooks/api/types"; +import { MetadataForm } from "../../DynamicSecretListView/MetadataForm"; + const formSchema = z.object({ provider: z.discriminatedUnion("method", [ z.object({ @@ -67,7 +69,10 @@ const formSchema = z.object({ }), 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() + usernameTemplate: z.string().nullable().optional(), + tags: z + .array(z.object({ key: z.string().trim().min(1), value: z.string().trim().min(1) })) + .optional() }); type TForm = z.infer; @@ -100,7 +105,8 @@ export const AwsIamInputForm = ({ usernameTemplate: "{{randomUsername}}", provider: { method: DynamicSecretAwsIamAuth.AssumeRole - } + }, + tags: [] } }); @@ -113,7 +119,8 @@ export const AwsIamInputForm = ({ provider, defaultTTL, environment, - usernameTemplate + usernameTemplate, + tags }: TForm) => { // wait till previous request is finished if (createDynamicSecret.isPending) return; @@ -129,7 +136,8 @@ export const AwsIamInputForm = ({ projectSlug, environmentSlug: environment.slug, usernameTemplate: - !usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate + !usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate, + tags }); onCompleted(); } catch { @@ -398,6 +406,7 @@ export const AwsIamInputForm = ({ )} /> + {!isSingleEnvironmentMode && ( ; @@ -89,7 +94,8 @@ export const EditDynamicSecretAwsIamForm = ({ usernameTemplate: dynamicSecret?.usernameTemplate || "{{randomUsername}}", inputs: { ...(dynamicSecret.inputs as TForm["inputs"]) - } + }, + tags: dynamicSecret.tags } }); const isAccessKeyMethod = watch("inputs.method") === DynamicSecretAwsIamAuth.AccessKey; @@ -101,7 +107,8 @@ export const EditDynamicSecretAwsIamForm = ({ maxTTL, defaultTTL, newName, - usernameTemplate + usernameTemplate, + tags }: TForm) => { // wait till previous request is finished if (updateDynamicSecret.isPending) return; @@ -117,7 +124,9 @@ export const EditDynamicSecretAwsIamForm = ({ defaultTTL, inputs, newName: newName === dynamicSecret.name ? undefined : newName, - usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate + usernameTemplate: + !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate, + tags } }); onClose(); @@ -380,6 +389,7 @@ export const EditDynamicSecretAwsIamForm = ({ )} /> +
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/MetadataForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/MetadataForm.tsx index 986ba9e46..c7ca96b14 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/MetadataForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/MetadataForm.tsx @@ -4,14 +4,22 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FormControl, FormLabel, IconButton, Input } from "@app/components/v2"; -export const MetadataForm = ({ control }: { control: Control }) => { +export const MetadataForm = ({ + control, + name = "metadata", + isValueRequired = false +}: { + control: Control; + name?: string; + isValueRequired?: boolean; +}) => { const metadataFormFields = useFieldArray({ control, - name: "metadata" + name }); return ( - +
{metadataFormFields.fields.map(({ id: metadataFieldId }, i) => (
@@ -19,7 +27,7 @@ export const MetadataForm = ({ control }: { control: Control }) => { {i === 0 && Key} ( }) => {
{i === 0 && ( - + )} ( Date: Tue, 17 Jun 2025 16:21:29 -0300 Subject: [PATCH 2/4] feat(dynamic-secret): Add tags to AWS IAM docs and add aws key-value limits to the schema --- docs/documentation/platform/dynamic-secrets/aws-iam.mdx | 9 +++++++++ .../CreateDynamicSecretForm/AwsIamInputForm.tsx | 4 +++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/documentation/platform/dynamic-secrets/aws-iam.mdx b/docs/documentation/platform/dynamic-secrets/aws-iam.mdx index a02d80a5c..03bc5df84 100644 --- a/docs/documentation/platform/dynamic-secrets/aws-iam.mdx +++ b/docs/documentation/platform/dynamic-secrets/aws-iam.mdx @@ -161,6 +161,11 @@ Replace **\** with your AWS account id and **\** w {{replace identity.name 'user' 'replace'}} // testreplace ``` + + + Tags to be added to the created IAM User resource. + + Select *Assume Role* method. @@ -304,6 +309,10 @@ Replace **\** with your AWS account id and **\** w - `{{unixTimestamp}}`: Current Unix timestamp + + Tags to be added to the created IAM User resource. + + diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx index 60bfa6304..f0750e07e 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx @@ -71,7 +71,9 @@ const formSchema = z.object({ environment: z.object({ name: z.string(), slug: z.string() }), usernameTemplate: z.string().nullable().optional(), tags: z - .array(z.object({ key: z.string().trim().min(1), value: z.string().trim().min(1) })) + .array( + z.object({ key: z.string().trim().min(1).max(128), value: z.string().trim().min(1).max(256) }) + ) .optional() }); type TForm = z.infer; From 20f0eeed35c7d8c9d00097658b56174095cb4765 Mon Sep 17 00:00:00 2001 From: carlosmonastyrski Date: Thu, 19 Jun 2025 15:01:35 -0300 Subject: [PATCH 3/4] Moved tags to aws iam provider inputs --- .../20250617181915_add-dynamic-secret-tags.ts | 21 ------------ backend/src/db/schemas/dynamic-secrets.ts | 3 +- .../src/ee/routes/v1/dynamic-secret-router.ts | 2 -- .../dynamic-secret-lease-service.ts | 1 - .../dynamic-secret/dynamic-secret-service.ts | 10 +++--- .../dynamic-secret/dynamic-secret-types.ts | 2 -- .../dynamic-secret/providers/aws-iam.ts | 8 ++--- .../dynamic-secret/providers/models.ts | 8 +++-- .../AwsIamInputForm.tsx | 32 ++++++++++--------- .../EditDynamicSecretAwsIamForm.tsx | 22 ++++++------- .../DynamicSecretListView/MetadataForm.tsx | 4 ++- 11 files changed, 45 insertions(+), 68 deletions(-) delete mode 100644 backend/src/db/migrations/20250617181915_add-dynamic-secret-tags.ts diff --git a/backend/src/db/migrations/20250617181915_add-dynamic-secret-tags.ts b/backend/src/db/migrations/20250617181915_add-dynamic-secret-tags.ts deleted file mode 100644 index d11a98028..000000000 --- a/backend/src/db/migrations/20250617181915_add-dynamic-secret-tags.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Knex } from "knex"; - -import { TableName } from "../schemas"; - -export async function up(knex: Knex): Promise { - const hasCol = await knex.schema.hasColumn(TableName.DynamicSecret, "tags"); - if (!hasCol) { - await knex.schema.alterTable(TableName.DynamicSecret, (t) => { - t.jsonb("tags").nullable(); - }); - } -} - -export async function down(knex: Knex): Promise { - const hasCol = await knex.schema.hasColumn(TableName.DynamicSecret, "tags"); - if (hasCol) { - await knex.schema.alterTable(TableName.DynamicSecret, (t) => { - t.dropColumn("tags"); - }); - } -} diff --git a/backend/src/db/schemas/dynamic-secrets.ts b/backend/src/db/schemas/dynamic-secrets.ts index 2720aa729..637d0c632 100644 --- a/backend/src/db/schemas/dynamic-secrets.ts +++ b/backend/src/db/schemas/dynamic-secrets.ts @@ -29,8 +29,7 @@ export const DynamicSecretsSchema = z.object({ encryptedInput: zodBuffer, projectGatewayId: z.string().uuid().nullable().optional(), gatewayId: z.string().uuid().nullable().optional(), - usernameTemplate: z.string().nullable().optional(), - tags: z.unknown().nullable().optional() + usernameTemplate: z.string().nullable().optional() }); export type TDynamicSecrets = z.infer; diff --git a/backend/src/ee/routes/v1/dynamic-secret-router.ts b/backend/src/ee/routes/v1/dynamic-secret-router.ts index e931d4f82..b916bab67 100644 --- a/backend/src/ee/routes/v1/dynamic-secret-router.ts +++ b/backend/src/ee/routes/v1/dynamic-secret-router.ts @@ -80,7 +80,6 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) => environmentSlug: z.string().describe(DYNAMIC_SECRETS.CREATE.environmentSlug).min(1), name: slugSchema({ min: 1, max: 64, field: "Name" }).describe(DYNAMIC_SECRETS.CREATE.name), metadata: ResourceMetadataSchema.optional(), - tags: ResourceMetadataSchema.optional(), usernameTemplate: userTemplateSchema.optional() }), response: { @@ -147,7 +146,6 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) => .nullable(), newName: z.string().describe(DYNAMIC_SECRETS.UPDATE.newName).optional(), metadata: ResourceMetadataSchema.optional(), - tags: ResourceMetadataSchema.optional(), usernameTemplate: userTemplateSchema.nullable().optional() }) }), diff --git a/backend/src/ee/services/dynamic-secret-lease/dynamic-secret-lease-service.ts b/backend/src/ee/services/dynamic-secret-lease/dynamic-secret-lease-service.ts index 90d3c9603..168b16c5f 100644 --- a/backend/src/ee/services/dynamic-secret-lease/dynamic-secret-lease-service.ts +++ b/backend/src/ee/services/dynamic-secret-lease/dynamic-secret-lease-service.ts @@ -166,7 +166,6 @@ export const dynamicSecretLeaseServiceFactory = ({ usernameTemplate: dynamicSecretCfg.usernameTemplate, identity, metadata: { projectId }, - tags: dynamicSecretCfg.tags as Record[] | undefined, config }); } catch (error: unknown) { diff --git a/backend/src/ee/services/dynamic-secret/dynamic-secret-service.ts b/backend/src/ee/services/dynamic-secret/dynamic-secret-service.ts index a46ef1c9c..0b28f5e0e 100644 --- a/backend/src/ee/services/dynamic-secret/dynamic-secret-service.ts +++ b/backend/src/ee/services/dynamic-secret/dynamic-secret-service.ts @@ -79,7 +79,6 @@ export const dynamicSecretServiceFactory = ({ defaultTTL, actorAuthMethod, metadata, - tags, usernameTemplate }: TCreateDynamicSecretDTO) => { const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId); @@ -166,8 +165,7 @@ export const dynamicSecretServiceFactory = ({ folderId: folder.id, name, gatewayId: selectedGatewayId, - usernameTemplate, - tags: JSON.stringify(tags) + usernameTemplate }, tx ); @@ -204,9 +202,10 @@ export const dynamicSecretServiceFactory = ({ actorOrgId, actorAuthMethod, metadata, - tags, usernameTemplate }: TUpdateDynamicSecretDTO) => { + console.log({ inputs }); + const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId); if (!project) throw new NotFoundError({ message: `Project with slug '${projectSlug}' not found` }); @@ -318,8 +317,7 @@ export const dynamicSecretServiceFactory = ({ name: newName ?? name, status: null, gatewayId: selectedGatewayId, - usernameTemplate, - tags: JSON.stringify(tags) + usernameTemplate }, tx ); diff --git a/backend/src/ee/services/dynamic-secret/dynamic-secret-types.ts b/backend/src/ee/services/dynamic-secret/dynamic-secret-types.ts index e8fa010b1..6720cf2c8 100644 --- a/backend/src/ee/services/dynamic-secret/dynamic-secret-types.ts +++ b/backend/src/ee/services/dynamic-secret/dynamic-secret-types.ts @@ -23,7 +23,6 @@ export type TCreateDynamicSecretDTO = { projectSlug: string; metadata?: ResourceMetadataDTO; usernameTemplate?: string | null; - tags?: ResourceMetadataDTO; } & Omit; export type TUpdateDynamicSecretDTO = { @@ -36,7 +35,6 @@ export type TUpdateDynamicSecretDTO = { inputs?: TProvider["inputs"]; projectSlug: string; metadata?: ResourceMetadataDTO; - tags?: ResourceMetadataDTO; usernameTemplate?: string | null; } & Omit; diff --git a/backend/src/ee/services/dynamic-secret/providers/aws-iam.ts b/backend/src/ee/services/dynamic-secret/providers/aws-iam.ts index 12a9558c9..fc65e0aec 100644 --- a/backend/src/ee/services/dynamic-secret/providers/aws-iam.ts +++ b/backend/src/ee/services/dynamic-secret/providers/aws-iam.ts @@ -119,20 +119,20 @@ export const AwsIamProvider = (): TDynamicProviderFns => { identity?: { name: string; }; - tags?: Record[]; metadata: { projectId: string }; }) => { - const { inputs, usernameTemplate, metadata, identity, tags } = data; + const { inputs, usernameTemplate, metadata, identity } = data; const providerInputs = await validateProviderInputs(inputs); + console.log({ providerInputs, inputs }); const client = await $getClient(providerInputs, metadata.projectId); const username = generateUsername(usernameTemplate, identity); const { policyArns, userGroups, policyDocument, awsPath, permissionBoundaryPolicyArn } = providerInputs; const awsTags = [{ Key: "createdBy", Value: "infisical-dynamic-secret" }]; - if (tags && Array.isArray(tags)) { - const additionalTags = tags.map((tag) => ({ + if (providerInputs.tags && Array.isArray(providerInputs.tags)) { + const additionalTags = providerInputs.tags.map((tag) => ({ Key: tag.key, Value: tag.value })); diff --git a/backend/src/ee/services/dynamic-secret/providers/models.ts b/backend/src/ee/services/dynamic-secret/providers/models.ts index c86361583..c52630701 100644 --- a/backend/src/ee/services/dynamic-secret/providers/models.ts +++ b/backend/src/ee/services/dynamic-secret/providers/models.ts @@ -2,6 +2,7 @@ import RE2 from "re2"; import { z } from "zod"; import { CharacterType, characterValidator } from "@app/lib/validator/validate-string"; +import { ResourceMetadataSchema } from "@app/services/resource-metadata/resource-metadata-schema"; import { TDynamicSecretLeaseConfig } from "../../dynamic-secret-lease/dynamic-secret-lease-types"; @@ -207,7 +208,8 @@ export const DynamicSecretAwsIamSchema = z.preprocess( permissionBoundaryPolicyArn: z.string().trim().optional(), policyDocument: z.string().trim().optional(), userGroups: z.string().trim().optional(), - policyArns: z.string().trim().optional() + policyArns: z.string().trim().optional(), + tags: ResourceMetadataSchema.optional() }), z.object({ method: z.literal(AwsIamAuthType.AssumeRole), @@ -217,7 +219,8 @@ export const DynamicSecretAwsIamSchema = z.preprocess( permissionBoundaryPolicyArn: z.string().trim().optional(), policyDocument: z.string().trim().optional(), userGroups: z.string().trim().optional(), - policyArns: z.string().trim().optional() + policyArns: z.string().trim().optional(), + tags: ResourceMetadataSchema.optional() }) ]) ); @@ -525,7 +528,6 @@ export type TDynamicProviderFns = { name: string; }; metadata: { projectId: string }; - tags?: Record[]; config?: TDynamicSecretLeaseConfig; }) => Promise<{ entityId: string; data: unknown }>; validateConnection: (inputs: unknown, metadata: { projectId: string }) => Promise; diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx index f0750e07e..48e942d0a 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx @@ -34,7 +34,12 @@ const formSchema = z.object({ permissionBoundaryPolicyArn: z.string().trim().optional(), policyDocument: z.string().trim().optional(), userGroups: z.string().trim().optional(), - policyArns: z.string().trim().optional() + policyArns: z.string().trim().optional(), + tags: z + .array( + z.object({ key: z.string().trim().min(1).max(128), value: z.string().trim().min(1).max(256) }) + ) + .optional() }), z.object({ method: z.literal(DynamicSecretAwsIamAuth.AssumeRole), @@ -44,7 +49,12 @@ const formSchema = z.object({ permissionBoundaryPolicyArn: z.string().trim().optional(), policyDocument: z.string().trim().optional(), userGroups: z.string().trim().optional(), - policyArns: z.string().trim().optional() + policyArns: z.string().trim().optional(), + tags: z + .array( + z.object({ key: z.string().trim().min(1).max(128), value: z.string().trim().min(1).max(256) }) + ) + .optional() }) ]), defaultTTL: z.string().superRefine((val, ctx) => { @@ -69,12 +79,7 @@ const formSchema = z.object({ }), 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(), - tags: z - .array( - z.object({ key: z.string().trim().min(1).max(128), value: z.string().trim().min(1).max(256) }) - ) - .optional() + usernameTemplate: z.string().nullable().optional() }); type TForm = z.infer; @@ -107,8 +112,7 @@ export const AwsIamInputForm = ({ usernameTemplate: "{{randomUsername}}", provider: { method: DynamicSecretAwsIamAuth.AssumeRole - }, - tags: [] + } } }); @@ -121,8 +125,7 @@ export const AwsIamInputForm = ({ provider, defaultTTL, environment, - usernameTemplate, - tags + usernameTemplate }: TForm) => { // wait till previous request is finished if (createDynamicSecret.isPending) return; @@ -138,8 +141,7 @@ export const AwsIamInputForm = ({ projectSlug, environmentSlug: environment.slug, usernameTemplate: - !usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate, - tags + !usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate }); onCompleted(); } catch { @@ -408,7 +410,7 @@ export const AwsIamInputForm = ({ )} /> - + {!isSingleEnvironmentMode && ( { @@ -58,9 +64,6 @@ const formSchema = z.object({ }) .nullable(), newName: slugSchema().optional(), - tags: z - .array(z.object({ key: z.string().trim().min(1), value: z.string().trim().min(1) })) - .optional(), usernameTemplate: z.string().trim().nullable().optional() }); type TForm = z.infer; @@ -95,7 +98,6 @@ export const EditDynamicSecretAwsIamForm = ({ inputs: { ...(dynamicSecret.inputs as TForm["inputs"]) }, - tags: dynamicSecret.tags } }); const isAccessKeyMethod = watch("inputs.method") === DynamicSecretAwsIamAuth.AccessKey; @@ -107,8 +109,7 @@ export const EditDynamicSecretAwsIamForm = ({ maxTTL, defaultTTL, newName, - usernameTemplate, - tags + usernameTemplate }: TForm) => { // wait till previous request is finished if (updateDynamicSecret.isPending) return; @@ -125,8 +126,7 @@ export const EditDynamicSecretAwsIamForm = ({ inputs, newName: newName === dynamicSecret.name ? undefined : newName, usernameTemplate: - !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate, - tags + !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate } }); onClose(); @@ -389,7 +389,7 @@ export const EditDynamicSecretAwsIamForm = ({ )} /> - +
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/MetadataForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/MetadataForm.tsx index c7ca96b14..510bc2a05 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/MetadataForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/MetadataForm.tsx @@ -7,10 +7,12 @@ import { FormControl, FormLabel, IconButton, Input } from "@app/components/v2"; export const MetadataForm = ({ control, name = "metadata", + title = "Metadata", isValueRequired = false }: { control: Control; name?: string; + title?: string; isValueRequired?: boolean; }) => { const metadataFormFields = useFieldArray({ @@ -19,7 +21,7 @@ export const MetadataForm = ({ }); return ( - +
{metadataFormFields.fields.map(({ id: metadataFieldId }, i) => (
From a8c54d27ef0cf692699e0df586a3f5d5665a3608 Mon Sep 17 00:00:00 2001 From: carlosmonastyrski Date: Thu, 19 Jun 2025 16:19:02 -0300 Subject: [PATCH 4/4] remove debug console logs --- .../src/ee/services/dynamic-secret/dynamic-secret-service.ts | 2 -- backend/src/ee/services/dynamic-secret/providers/aws-iam.ts | 1 - 2 files changed, 3 deletions(-) diff --git a/backend/src/ee/services/dynamic-secret/dynamic-secret-service.ts b/backend/src/ee/services/dynamic-secret/dynamic-secret-service.ts index 0b28f5e0e..5a7da6a3e 100644 --- a/backend/src/ee/services/dynamic-secret/dynamic-secret-service.ts +++ b/backend/src/ee/services/dynamic-secret/dynamic-secret-service.ts @@ -204,8 +204,6 @@ export const dynamicSecretServiceFactory = ({ metadata, usernameTemplate }: TUpdateDynamicSecretDTO) => { - console.log({ inputs }); - const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId); if (!project) throw new NotFoundError({ message: `Project with slug '${projectSlug}' not found` }); diff --git a/backend/src/ee/services/dynamic-secret/providers/aws-iam.ts b/backend/src/ee/services/dynamic-secret/providers/aws-iam.ts index fc65e0aec..ec75bb2e4 100644 --- a/backend/src/ee/services/dynamic-secret/providers/aws-iam.ts +++ b/backend/src/ee/services/dynamic-secret/providers/aws-iam.ts @@ -124,7 +124,6 @@ export const AwsIamProvider = (): TDynamicProviderFns => { const { inputs, usernameTemplate, metadata, identity } = data; const providerInputs = await validateProviderInputs(inputs); - console.log({ providerInputs, inputs }); const client = await $getClient(providerInputs, metadata.projectId); const username = generateUsername(usernameTemplate, identity);