From 0cdade6a2d5296fa01ee06f32ad72d5c2ba23f86 Mon Sep 17 00:00:00 2001 From: Tuan Dang Date: Fri, 10 May 2024 19:07:44 -0700 Subject: [PATCH 1/5] Update AWS SM integration to allow updating tags --- .../server/routes/v1/integration-router.ts | 28 +++++- .../integration-sync-secret.ts | 85 +++++++++++++++++++ .../integration/integration-service.ts | 15 +++- .../services/integration/integration-types.ts | 14 +++ .../integrations/cloud/aws-secret-manager.mdx | 1 + 5 files changed, 140 insertions(+), 3 deletions(-) diff --git a/backend/src/server/routes/v1/integration-router.ts b/backend/src/server/routes/v1/integration-router.ts index 975e6e7c8..fdd9cf4f4 100644 --- a/backend/src/server/routes/v1/integration-router.ts +++ b/backend/src/server/routes/v1/integration-router.ts @@ -154,7 +154,33 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => { .describe(INTEGRATION.UPDATE.secretPath), targetEnvironment: z.string().trim().describe(INTEGRATION.UPDATE.targetEnvironment), owner: z.string().trim().describe(INTEGRATION.UPDATE.owner), - environment: z.string().trim().describe(INTEGRATION.UPDATE.environment) + environment: z.string().trim().describe(INTEGRATION.UPDATE.environment), + metadata: z + .object({ + secretPrefix: z.string().optional().describe(INTEGRATION.CREATE.metadata.secretPrefix), + secretSuffix: z.string().optional().describe(INTEGRATION.CREATE.metadata.secretSuffix), + initialSyncBehavior: z.string().optional().describe(INTEGRATION.CREATE.metadata.initialSyncBehavoir), + shouldAutoRedeploy: z.boolean().optional().describe(INTEGRATION.CREATE.metadata.shouldAutoRedeploy), + secretGCPLabel: z + .object({ + labelName: z.string(), + labelValue: z.string() + }) + .optional() + .describe(INTEGRATION.CREATE.metadata.secretGCPLabel), + secretAWSTag: z + .array( + z.object({ + key: z.string(), + value: z.string() + }) + ) + .optional() + .describe(INTEGRATION.CREATE.metadata.secretAWSTag), + kmsKeyId: z.string().optional().describe(INTEGRATION.CREATE.metadata.kmsKeyId), + shouldDisableDelete: z.boolean().optional().describe(INTEGRATION.CREATE.metadata.shouldDisableDelete) + }) + .optional() }), response: { 200: z.object({ diff --git a/backend/src/services/integration-auth/integration-sync-secret.ts b/backend/src/services/integration-auth/integration-sync-secret.ts index 4e1dbd7ae..963db1e1e 100644 --- a/backend/src/services/integration-auth/integration-sync-secret.ts +++ b/backend/src/services/integration-auth/integration-sync-secret.ts @@ -9,9 +9,12 @@ import { CreateSecretCommand, + DescribeSecretCommand, GetSecretValueCommand, ResourceNotFoundException, SecretsManagerClient, + TagResourceCommand, + UntagResourceCommand, UpdateSecretCommand } from "@aws-sdk/client-secrets-manager"; import { Octokit } from "@octokit/rest"; @@ -574,6 +577,7 @@ const syncSecretsAWSSecretManager = async ({ if (awsSecretManagerSecret?.SecretString) { awsSecretManagerSecretObj = JSON.parse(awsSecretManagerSecret.SecretString); } + if (!isEqual(awsSecretManagerSecretObj, secKeyVal)) { await secretsManager.send( new UpdateSecretCommand({ @@ -582,7 +586,88 @@ const syncSecretsAWSSecretManager = async ({ }) ); } + + const secretAWSTag = metadata.secretAWSTag as { key: string; value: string }[] | undefined; + + if (secretAWSTag && secretAWSTag.length) { + const describedSecret = await secretsManager.send( + // requires secretsmanager:DescribeSecret policy + new DescribeSecretCommand({ + SecretId: integration.app as string + }) + ); + + if (!describedSecret.Tags) return; + + const integrationTagObj = secretAWSTag.reduce( + (acc, item) => { + acc[item.key] = item.value; + return acc; + }, + {} as Record + ); + + const awsTagObj = (describedSecret.Tags || []).reduce( + (acc, item) => { + if (item.Key && item.Value) { + acc[item.Key] = item.Value; + } + return acc; + }, + {} as Record + ); + + const tagsToUpdate: { Key: string; Value: string }[] = []; + const tagsToDelete: { Key: string; Value: string }[] = []; + + describedSecret.Tags?.forEach((tag) => { + if (tag.Key && tag.Value) { + if (!(tag.Key in integrationTagObj)) { + // delete tag from AWS secret manager + tagsToDelete.push({ + Key: tag.Key, + Value: tag.Value + }); + } else if (tag.Value !== integrationTagObj[tag.Key]) { + // update tag in AWS secret manager + tagsToUpdate.push({ + Key: tag.Key, + Value: integrationTagObj[tag.Key] + }); + } + } + }); + + secretAWSTag?.forEach((tag) => { + if (!(tag.key in awsTagObj)) { + // create tag in AWS secret manager + tagsToUpdate.push({ + Key: tag.key, + Value: tag.value + }); + } + }); + + if (tagsToUpdate.length) { + await secretsManager.send( + new TagResourceCommand({ + SecretId: integration.app as string, + Tags: tagsToUpdate + }) + ); + } + + if (tagsToDelete.length) { + await secretsManager.send( + new UntagResourceCommand({ + SecretId: integration.app as string, + TagKeys: tagsToDelete.map((tag) => tag.Key) + }) + ); + } + } } catch (err) { + // case when AWS manager can't find the specified secret if (err instanceof ResourceNotFoundException && secretsManager) { await secretsManager.send( new CreateSecretCommand({ diff --git a/backend/src/services/integration/integration-service.ts b/backend/src/services/integration/integration-service.ts index a3c4c84db..f4f8cdb44 100644 --- a/backend/src/services/integration/integration-service.ts +++ b/backend/src/services/integration/integration-service.ts @@ -103,7 +103,8 @@ export const integrationServiceFactory = ({ owner, isActive, environment, - secretPath + secretPath, + metadata }: TUpdateIntegrationDTO) => { const integration = await integrationDAL.findById(id); if (!integration) throw new BadRequestError({ message: "Integration auth not found" }); @@ -127,7 +128,17 @@ export const integrationServiceFactory = ({ appId, targetEnvironment, owner, - secretPath + secretPath, + metadata: { + ...(integration.metadata as object), + ...metadata + } + }); + + await secretQueueService.syncIntegrations({ + environment: folder.environment.slug, + secretPath, + projectId: folder.projectId }); return updatedIntegration; diff --git a/backend/src/services/integration/integration-types.ts b/backend/src/services/integration/integration-types.ts index 1913dd31f..909ab517a 100644 --- a/backend/src/services/integration/integration-types.ts +++ b/backend/src/services/integration/integration-types.ts @@ -40,6 +40,20 @@ export type TUpdateIntegrationDTO = { targetEnvironment: string; owner: string; environment: string; + metadata?: { + secretPrefix?: string; + secretSuffix?: string; + secretGCPLabel?: { + labelName: string; + labelValue: string; + }; + secretAWSTag?: { + key: string; + value: string; + }[]; + kmsKeyId?: string; + shouldDisableDelete?: boolean; + }; } & Omit; export type TDeleteIntegrationDTO = { diff --git a/docs/integrations/cloud/aws-secret-manager.mdx b/docs/integrations/cloud/aws-secret-manager.mdx index 6fc83eaff..120326f66 100644 --- a/docs/integrations/cloud/aws-secret-manager.mdx +++ b/docs/integrations/cloud/aws-secret-manager.mdx @@ -29,6 +29,7 @@ Prerequisites: "secretsmanager:GetSecretValue", "secretsmanager:CreateSecret", "secretsmanager:UpdateSecret", + "secretsmanager:DescribeSecret", // if you need to add tags to secrets "secretsmanager:TagResource", // if you need to add tags to secrets "kms:ListKeys", // if you need to specify the KMS key "kms:ListAliases", // if you need to specify the KMS key From 818b136836fa5f7661cdb5abed69065d1fabeafe Mon Sep 17 00:00:00 2001 From: Tuan Dang Date: Fri, 10 May 2024 19:17:40 -0700 Subject: [PATCH 2/5] Make app and appId optional in update integration endpoint --- backend/src/server/routes/v1/integration-router.ts | 4 ++-- backend/src/services/integration/integration-types.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/src/server/routes/v1/integration-router.ts b/backend/src/server/routes/v1/integration-router.ts index fdd9cf4f4..e40e3f799 100644 --- a/backend/src/server/routes/v1/integration-router.ts +++ b/backend/src/server/routes/v1/integration-router.ts @@ -143,8 +143,8 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => { integrationId: z.string().trim().describe(INTEGRATION.UPDATE.integrationId) }), body: z.object({ - app: z.string().trim().describe(INTEGRATION.UPDATE.app), - appId: z.string().trim().describe(INTEGRATION.UPDATE.appId), + app: z.string().trim().optional().describe(INTEGRATION.UPDATE.app), + appId: z.string().trim().optional().describe(INTEGRATION.UPDATE.appId), isActive: z.boolean().describe(INTEGRATION.UPDATE.isActive), secretPath: z .string() diff --git a/backend/src/services/integration/integration-types.ts b/backend/src/services/integration/integration-types.ts index 909ab517a..50d0de762 100644 --- a/backend/src/services/integration/integration-types.ts +++ b/backend/src/services/integration/integration-types.ts @@ -33,8 +33,8 @@ export type TCreateIntegrationDTO = { export type TUpdateIntegrationDTO = { id: string; - app: string; - appId: string; + app?: string; + appId?: string; isActive?: boolean; secretPath: string; targetEnvironment: string; From a58d6ebdace3e2db4223dd32df9535006c40f19d Mon Sep 17 00:00:00 2001 From: = Date: Sat, 11 May 2024 20:54:00 +0530 Subject: [PATCH 3/5] feat: maintaince mode enable machine identity login and renew --- backend/src/server/plugins/maintenanceMode.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/backend/src/server/plugins/maintenanceMode.ts b/backend/src/server/plugins/maintenanceMode.ts index f40f1ff6d..201dd05b8 100644 --- a/backend/src/server/plugins/maintenanceMode.ts +++ b/backend/src/server/plugins/maintenanceMode.ts @@ -5,8 +5,13 @@ import { getConfig } from "@app/lib/config/env"; export const maintenanceMode = fp(async (fastify) => { fastify.addHook("onRequest", async (req) => { const serverEnvs = getConfig(); - if (req.url !== "/api/v1/auth/checkAuth" && req.method !== "GET" && serverEnvs.MAINTENANCE_MODE) { - throw new Error("Infisical is in maintenance mode. Please try again later."); + if (serverEnvs.MAINTENANCE_MODE) { + // skip if its universal auth login or renew + if (req.url === "/api/v1/auth/universal-auth/login" && req.method === "POST") return; + if (req.url === "/api/v1/auth/token/renew" && req.method === "POST") return; + if (req.url !== "/api/v1/auth/checkAuth" && req.method !== "GET") { + throw new Error("Infisical is in maintenance mode. Please try again later."); + } } }); }); From ce01f8d099adbab17903724e343b5a5d269770f7 Mon Sep 17 00:00:00 2001 From: = Date: Sat, 11 May 2024 23:04:43 +0530 Subject: [PATCH 4/5] fix: removed migration notice --- .../src/pages/org/[id]/overview/index.tsx | 226 +++++++----------- 1 file changed, 93 insertions(+), 133 deletions(-) diff --git a/frontend/src/pages/org/[id]/overview/index.tsx b/frontend/src/pages/org/[id]/overview/index.tsx index ab9fa790d..17cf8537c 100644 --- a/frontend/src/pages/org/[id]/overview/index.tsx +++ b/frontend/src/pages/org/[id]/overview/index.tsx @@ -21,9 +21,7 @@ import { faNetworkWired, faPlug, faPlus, - faUserPlus, - faWarning, - faXmark + faUserPlus } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { yupResolver } from "@hookform/resolvers/yup"; @@ -56,7 +54,6 @@ import { fetchOrgUsers, useAddUserToWsNonE2EE, useCreateWorkspace, - useGetUserAction, useRegisterUserAction } from "@app/hooks/api"; // import { fetchUserWsKey } from "@app/hooks/api/keys/queries"; @@ -312,9 +309,8 @@ const LearningItem = ({ href={link} >
null} @@ -325,11 +321,10 @@ const LearningItem = ({ await registerUserAction.mutateAsync(userAction); } }} - className={`group relative flex h-[5.5rem] w-full items-center justify-between overflow-hidden rounded-md border ${ - complete + className={`group relative flex h-[5.5rem] w-full items-center justify-between overflow-hidden rounded-md border ${complete ? "cursor-default border-mineshaft-900 bg-gradient-to-r from-[#0e1f01] to-mineshaft-700" : "cursor-pointer border-mineshaft-600 bg-mineshaft-800 shadow-xl hover:bg-mineshaft-700" - } text-mineshaft-100 duration-200`} + } text-mineshaft-100 duration-200`} >
@@ -407,9 +402,8 @@ const LearningItemSquare = ({ href={link} >
null} @@ -420,11 +414,10 @@ const LearningItemSquare = ({ await registerUserAction.mutateAsync(userAction); } }} - className={`group relative flex w-full items-center justify-between overflow-hidden rounded-md border ${ - complete + className={`group relative flex w-full items-center justify-between overflow-hidden rounded-md border ${complete ? "cursor-default border-mineshaft-900 bg-gradient-to-r from-[#0e1f01] to-mineshaft-700" : "cursor-pointer border-mineshaft-600 bg-mineshaft-800 shadow-xl hover:bg-mineshaft-700" - } text-mineshaft-100 duration-200`} + } text-mineshaft-100 duration-200`} >
@@ -438,9 +431,8 @@ const LearningItemSquare = ({
)}
{complete ? "Complete!" : `About ${time}`}
@@ -480,14 +472,8 @@ const OrganizationPage = withPermission( const { currentOrg } = useOrganization(); const routerOrgId = String(router.query.id); const orgWorkspaces = workspaces?.filter((workspace) => workspace.orgId === routerOrgId) || []; - - const addUsersToProject = useAddUserToWsNonE2EE(); - const { data: updateClosed } = useGetUserAction("april_13_2024_db_update_closed"); - const registerUserAction = useRegisterUserAction(); - const closeUpdate = async () => { - await registerUserAction.mutateAsync("april_13_2024_db_update_closed"); - }; + const addUsersToProject = useAddUserToWsNonE2EE(); const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([ "addNewWs", @@ -594,31 +580,6 @@ const OrganizationPage = withPermission(
)}
- {(window.location.origin.includes("https://app.infisical.com") || window.location.origin.includes("http://localhost:8080")) && ( -
- -
- Scheduled maintenance on May 11th 2024 {" "} -
- Infisical will undergo scheduled maintenance for approximately 2 hour on Saturday, May 11th, 11am EST. During these hours, read - operations to Infisical will continue to function normally but no resources will be editable. - No action is required on your end — your applications will continue to fetch secrets. -
-
- -
)} -

Projects

-

Onboarding Guide

-
- - {orgWorkspaces.length !== 0 && ( - <> - - - - )} -
+
+

Onboarding Guide

+
+ {orgWorkspaces.length !== 0 && ( + <> + + + + )} +
+ +
-
- {orgWorkspaces.length !== 0 && ( -
-
-
- - {false && ( -
- -
- )} -
-
Inject secrets locally
-
- Replace .env files with a more secure and efficient alternative. + {orgWorkspaces.length !== 0 && ( +
+
+
+ + {false && ( +
+ +
+ )} +
+
Inject secrets locally
+
+ Replace .env files with a more secure and efficient alternative. +
+
+ About 2 min +
-
- About 2 min -
+ + {false &&
}
- - {false &&
} -
- )} - {orgWorkspaces.length !== 0 && ( - - )} -
- )} + )} + {orgWorkspaces.length !== 0 && ( + + )} +
+ )} { From c1fb8f47bf17b325f2374cb2b7acd02913f8e349 Mon Sep 17 00:00:00 2001 From: Tuan Dang Date: Sun, 12 May 2024 08:57:41 -0700 Subject: [PATCH 5/5] Add UntagResource IAM policy requirement for AWS SM integration docs --- docs/integrations/cloud/aws-secret-manager.mdx | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/integrations/cloud/aws-secret-manager.mdx b/docs/integrations/cloud/aws-secret-manager.mdx index 120326f66..db95c8308 100644 --- a/docs/integrations/cloud/aws-secret-manager.mdx +++ b/docs/integrations/cloud/aws-secret-manager.mdx @@ -31,6 +31,7 @@ Prerequisites: "secretsmanager:UpdateSecret", "secretsmanager:DescribeSecret", // if you need to add tags to secrets "secretsmanager:TagResource", // if you need to add tags to secrets + "secretsmanager:UntagResource", // if you need to add tags to secrets "kms:ListKeys", // if you need to specify the KMS key "kms:ListAliases", // if you need to specify the KMS key "kms:Encrypt", // if you need to specify the KMS key