diff --git a/backend/src/ee/routes/v1/pam-account-routers/pam-account-router.ts b/backend/src/ee/routes/v1/pam-account-routers/pam-account-router.ts index d201ea0e2..df46a6753 100644 --- a/backend/src/ee/routes/v1/pam-account-routers/pam-account-router.ts +++ b/backend/src/ee/routes/v1/pam-account-routers/pam-account-router.ts @@ -126,11 +126,37 @@ export const registerPamAccountRouter = async (server: FastifyZodProvider) => { }) }), response: { - 200: z.union([ - // Gateway-based resources (Postgres, MySQL, SSH) + 200: z.discriminatedUnion("resourceType", [ + // Gateway-based resources (Postgres) z.object({ sessionId: z.string(), - resourceType: z.nativeEnum(PamResource), + resourceType: z.literal(PamResource.Postgres), + relayClientCertificate: z.string(), + relayClientPrivateKey: z.string(), + relayServerCertificateChain: z.string(), + gatewayClientCertificate: z.string(), + gatewayClientPrivateKey: z.string(), + gatewayServerCertificateChain: z.string(), + relayHost: z.string(), + metadata: z.record(z.string(), z.string().optional()).optional() + }), + // Gateway-based resources (MySQL) + z.object({ + sessionId: z.string(), + resourceType: z.literal(PamResource.MySQL), + relayClientCertificate: z.string(), + relayClientPrivateKey: z.string(), + relayServerCertificateChain: z.string(), + gatewayClientCertificate: z.string(), + gatewayClientPrivateKey: z.string(), + gatewayServerCertificateChain: z.string(), + relayHost: z.string(), + metadata: z.record(z.string(), z.string().optional()).optional() + }), + // Gateway-based resources (SSH) + z.object({ + sessionId: z.string(), + resourceType: z.literal(PamResource.SSH), relayClientCertificate: z.string(), relayClientPrivateKey: z.string(), relayServerCertificateChain: z.string(), @@ -145,7 +171,7 @@ export const registerPamAccountRouter = async (server: FastifyZodProvider) => { sessionId: z.string(), resourceType: z.literal(PamResource.AwsIam), consoleUrl: z.string().url(), - projectId: z.string(), + projectId: z.string().uuid(), metadata: z.record(z.string(), z.string().optional()).optional() }) ]) diff --git a/backend/src/ee/services/pam-resource/aws-iam/aws-iam-federation.ts b/backend/src/ee/services/pam-resource/aws-iam/aws-iam-federation.ts index 367e908d3..eb28e008b 100644 --- a/backend/src/ee/services/pam-resource/aws-iam/aws-iam-federation.ts +++ b/backend/src/ee/services/pam-resource/aws-iam/aws-iam-federation.ts @@ -204,6 +204,6 @@ export const generateConsoleFederationUrl = async ({ return { consoleUrl, - expiresAt: Expiration + expiresAt: Expiration ?? new Date(Date.now() + sessionDuration * 1000) }; }; diff --git a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/AwsIamAccountForm.tsx b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/AwsIamAccountForm.tsx index 21ab2a41f..0d8ef5336 100644 --- a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/AwsIamAccountForm.tsx +++ b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/AwsIamAccountForm.tsx @@ -24,7 +24,7 @@ type Props = { onSubmit: (formData: FormData) => Promise; }; -const arnRoleRegex = /^arn:aws:iam::\d{12}:role\/[\w+=,.@-]+$/; +const arnRoleRegex = /^arn:aws:iam::\d{12}:role\/[\w+=,.@/-]+$/; const AwsIamCredentialsSchema = z.object({ targetRoleArn: z diff --git a/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/AwsIamResourceForm.tsx b/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/AwsIamResourceForm.tsx index 0c8ef0808..62149f2d6 100644 --- a/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/AwsIamResourceForm.tsx +++ b/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/AwsIamResourceForm.tsx @@ -21,7 +21,7 @@ type Props = { onSubmit: (formData: FormData) => Promise; }; -const arnRoleRegex = /^arn:aws:iam::\d{12}:role\/[\w+=,.@-]+$/; +const arnRoleRegex = /^arn:aws:iam::\d{12}:role\/[\w+=,.@/-]+$/; const AwsIamConnectionDetailsSchema = z.object({ region: z.string().trim().min(1, "Region is required"),