feat(infisical-pg): completed secret rotation with queue service

This commit is contained in:
Akhil Mohan
2024-01-27 12:38:23 +05:30
parent 17e61bfc68
commit 784cdb4201
64 changed files with 3093 additions and 459 deletions
+49 -7
View File
@@ -4,7 +4,18 @@ import { z } from "zod";
import { registerV1EERoutes } from "@app/ee/routes/v1";
import { permissionDalFactory } from "@app/ee/services/permission/permission-dal";
import { permissionServiceFactory } from "@app/ee/services/permission/permission-service";
import { sapApproverDalFactory } from "@app/ee/services/secret-approval-policy/sap-approver-dal";
import { secretApprovalPolicyDalFactory } from "@app/ee/services/secret-approval-policy/secret-approval-policy-dal";
import { secretApprovalPolicyServiceFactory } from "@app/ee/services/secret-approval-policy/secret-approval-policy-service";
import { sarReviewerDalFactory } from "@app/ee/services/secret-approval-request/sar-reviewer-dal";
import { sarSecretDalFactory } from "@app/ee/services/secret-approval-request/sar-secret-dal";
import { secretApprovalRequestDalFactory } from "@app/ee/services/secret-approval-request/secret-approval-request-dal";
import { secretApprovalRequestServiceFactory } from "@app/ee/services/secret-approval-request/secret-approval-request-service";
import { secretRotationDalFactory } from "@app/ee/services/secret-rotation/secret-rotation-dal";
import { secretRotationQueueFactory } from "@app/ee/services/secret-rotation/secret-rotation-queue";
import { secretRotationServiceFactory } from "@app/ee/services/secret-rotation/secret-rotation-service";
import { getConfig } from "@app/lib/config/env";
import { TQueueServiceFactory } from "@app/queue";
import { apiKeyDalFactory } from "@app/services/api-key/api-key-dal";
import { apiKeyServiceFactory } from "@app/services/api-key/api-key-service";
import { authDalFactory } from "@app/services/auth/auth-dal";
@@ -69,13 +80,14 @@ import { injectPermission } from "../plugins/auth/inject-permission";
import { registerV1Routes } from "./v1";
import { registerV2Routes } from "./v2";
import { registerV3Routes } from "./v3";
import { secretApprovalPolicyDalFactory } from "@app/ee/services/secret-approval-policy/secret-approval-policy-dal";
import { sapApproverDalFactory } from "@app/ee/services/secret-approval-policy/sap-approver-dal";
import { secretApprovalPolicyServiceFactory } from "@app/ee/services/secret-approval-policy/secret-approval-policy-service";
export const registerRoutes = async (
server: FastifyZodProvider,
{ db, smtp: smtpService }: { db: Knex; smtp: TSmtpService }
{
db,
smtp: smtpService,
queue: queueService
}: { db: Knex; smtp: TSmtpService; queue: TQueueServiceFactory }
) => {
// db layers
const userDal = userDalFactory(db);
@@ -118,8 +130,12 @@ export const registerRoutes = async (
const permissionDal = permissionDalFactory(db);
const sapApproverDal = sapApproverDalFactory(db);
const secretApprovalPolicyDal = secretApprovalPolicyDalFactory(db);
const secretApprovalRequestDal = secretApprovalRequestDalFactory(db);
const sarReviewerDal = sarReviewerDalFactory(db);
const sarSecretDal = sarSecretDalFactory(db);
const secretRotationDal = secretRotationDalFactory(db);
// ee services
const permissionService = permissionServiceFactory({ permissionDal, orgRoleDal, projectRoleDal });
const sapService = secretApprovalPolicyServiceFactory({
projectMembershipDal,
@@ -128,8 +144,17 @@ export const registerRoutes = async (
permissionService,
secretApprovalPolicyDal
});
const sarService = secretApprovalRequestServiceFactory({
permissionService,
folderDal,
secretDal,
sarSecretDal,
sarReviewerDal,
secretVersionDal,
secretBlindIndexDal,
secretApprovalRequestDal
});
// service layers
const tokenService = tokenServiceFactory({ tokenDal: authTokenDal });
const userService = userServiceFactory({ userDal });
const loginService = authLoginServiceFactory({ userDal, smtpService, tokenService });
@@ -211,6 +236,21 @@ export const registerRoutes = async (
secretImportDal
});
const projectBotService = projectBotServiceFactory({ permissionService, projectBotDal });
const secretRotationQueue = secretRotationQueueFactory({
secretRotationDal,
queue: queueService,
secretDal,
secretVersionDal,
projectBotService
});
const secretRotationService = secretRotationServiceFactory({
permissionService,
projectEnvDal,
secretRotationDal,
secretRotationQueue
});
const integrationService = integrationServiceFactory({
permissionService,
folderDal,
@@ -287,7 +327,9 @@ export const registerRoutes = async (
identityAccessToken: identityAccessTokenService,
identityProject: identityProjectService,
identityUa: identityUaService,
secretApprovalPolicy: sapService
secretApprovalPolicy: sapService,
secretApprovalRequest: sarService,
secretRotation: secretRotationService
});
server.decorate<FastifyZodProvider["store"]>("store", {
+323 -68
View File
@@ -1,8 +1,9 @@
import { z } from "zod";
import { SecretsSchema,SecretType } from "@app/db/schemas";
import { SecretApprovalRequestsSchema, SecretsSchema, SecretType } from "@app/db/schemas";
import { CommitType } from "@app/ee/services/secret-approval-request/secret-approval-request-types";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
import { ActorType, AuthMode } from "@app/services/auth/auth-type";
export const registerSecretRouter = async (server: FastifyZodProvider) => {
server.route({
@@ -102,32 +103,92 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
secretName: z.string().trim()
}),
response: {
200: z.object({
secret: SecretsSchema.omit({ secretBlindIndex: true })
})
200: z.union([
z.object({
secret: SecretsSchema.omit({ secretBlindIndex: true })
}),
z
.object({ approval: SecretApprovalRequestsSchema })
.describe("When secret protection policy is enabled")
])
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
handler: async (req) => {
const {
workspaceId: projectId,
secretPath,
environment,
metadata,
type,
secretKeyIV,
secretKeyTag,
secretValueIV,
secretValueTag,
secretCommentIV,
secretCommentTag,
secretKeyCiphertext,
secretValueCiphertext,
secretCommentCiphertext,
skipMultilineEncoding
} = req.body;
if (req.body.type !== SecretType.Personal && req.permission.type === ActorType.USER) {
const policy = await server.services.secretApprovalPolicy.getSapOfFolder({
actorId: req.permission.id,
actor: req.permission.type,
secretPath,
environment,
projectId
});
if (policy) {
const approval =
await server.services.secretApprovalRequest.generateSecretApprovalRequest({
actorId: req.permission.id,
actor: req.permission.type,
secretPath,
environment,
projectId,
policy,
data: {
[CommitType.Create]: [
{
secretName: req.params.secretName,
secretValueCiphertext,
secretValueIV,
secretValueTag,
secretCommentIV,
secretCommentTag,
secretCommentCiphertext,
skipMultilineEncoding,
secretKeyTag,
secretKeyCiphertext,
secretKeyIV
}
]
}
});
return { approval };
}
}
const secret = await server.services.secret.createSecret({
actorId: req.permission.id,
actor: req.permission.type,
path: req.body.secretPath,
type: req.body.type,
path: secretPath,
type,
environment: req.body.environment,
secretName: req.params.secretName,
projectId: req.body.workspaceId,
secretKeyIV: req.body.secretKeyIV,
secretKeyTag: req.body.secretKeyTag,
secretKeyCiphertext: req.body.secretKeyCiphertext,
secretValueIV: req.body.secretValueIV,
secretValueTag: req.body.secretValueTag,
secretValueCiphertext: req.body.secretValueCiphertext,
secretCommentIV: req.body.secretCommentIV,
secretCommentTag: req.body.secretCommentTag,
secretCommentCiphertext: req.body.secretCommentCiphertext,
skipMultilineEncoding: req.body.skipMultilineEncoding,
metadata: req.body.metadata
projectId,
secretKeyIV,
secretKeyTag,
secretKeyCiphertext,
secretValueIV,
secretValueTag,
secretValueCiphertext,
secretCommentIV,
secretCommentTag,
secretCommentCiphertext,
skipMultilineEncoding,
metadata
});
return { secret };
@@ -165,35 +226,103 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
metadata: z.record(z.string()).optional()
}),
response: {
200: z.object({
secret: SecretsSchema.omit({ secretBlindIndex: true })
})
200: z.union([
z.object({
secret: SecretsSchema.omit({ secretBlindIndex: true })
}),
z
.object({ approval: SecretApprovalRequestsSchema })
.describe("When secret protection policy is enabled")
])
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
handler: async (req) => {
const {
secretValueCiphertext,
secretValueTag,
secretValueIV,
type,
environment,
secretPath,
workspaceId: projectId,
tags,
secretCommentIV,
secretCommentTag,
secretCommentCiphertext,
secretName: newSecretName,
secretKeyIV,
secretKeyTag,
secretKeyCiphertext,
skipMultilineEncoding,
secretReminderRepeatDays,
secretReminderNote,
metadata
} = req.body;
if (req.body.type !== SecretType.Personal && req.permission.type === ActorType.USER) {
const policy = await server.services.secretApprovalPolicy.getSapOfFolder({
actorId: req.permission.id,
actor: req.permission.type,
secretPath,
environment,
projectId
});
if (policy) {
const approval =
await server.services.secretApprovalRequest.generateSecretApprovalRequest({
actorId: req.permission.id,
actor: req.permission.type,
secretPath,
environment,
projectId,
policy,
data: {
[CommitType.Update]: [
{
secretName: req.params.secretName,
newSecretName,
secretValueCiphertext,
secretValueIV,
secretValueTag,
secretCommentIV,
secretCommentTag,
secretCommentCiphertext,
skipMultilineEncoding,
secretKeyTag,
secretKeyCiphertext,
secretKeyIV
}
]
}
});
return { approval };
}
}
const secret = await server.services.secret.updateSecret({
actorId: req.permission.id,
actor: req.permission.type,
path: req.body.secretPath,
type: req.body.type,
environment: req.body.environment,
path: secretPath,
type,
environment,
secretName: req.params.secretName,
projectId: req.body.workspaceId,
secretKeyIV: req.body.secretKeyIV,
secretKeyTag: req.body.secretKeyTag,
secretKeyCiphertext: req.body.secretKeyCiphertext,
secretValueIV: req.body.secretValueIV,
secretValueTag: req.body.secretValueTag,
secretValueCiphertext: req.body.secretValueCiphertext,
secretCommentIV: req.body.secretCommentIV,
secretCommentTag: req.body.secretCommentTag,
secretCommentCiphertext: req.body.secretCommentCiphertext,
skipMultilineEncoding: req.body.skipMultilineEncoding,
metadata: req.body.metadata,
secretReminderRepeatDays: req.body.secretReminderRepeatDays,
secretReminderNote: req.body.secretReminderNote,
newSecretName: req.body.secretName
projectId,
secretKeyIV,
secretKeyTag,
secretKeyCiphertext,
secretValueIV,
tags,
secretValueTag,
secretValueCiphertext,
secretCommentIV,
secretCommentTag,
secretCommentCiphertext,
skipMultilineEncoding,
metadata,
secretReminderRepeatDays,
secretReminderNote,
newSecretName
});
return { secret };
@@ -215,22 +344,57 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
environment: z.string().trim()
}),
response: {
200: z.object({
secret: SecretsSchema.omit({ secretBlindIndex: true })
})
200: z.union([
z.object({
secret: SecretsSchema.omit({ secretBlindIndex: true })
}),
z
.object({ approval: SecretApprovalRequestsSchema })
.describe("When secret protection policy is enabled")
])
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
handler: async (req) => {
const { secretPath, type, workspaceId: projectId, secretId, environment } = req.body;
if (req.body.type !== SecretType.Personal && req.permission.type === ActorType.USER) {
const policy = await server.services.secretApprovalPolicy.getSapOfFolder({
actorId: req.permission.id,
actor: req.permission.type,
secretPath,
environment,
projectId
});
if (policy) {
const approval =
await server.services.secretApprovalRequest.generateSecretApprovalRequest({
actorId: req.permission.id,
actor: req.permission.type,
secretPath,
environment,
projectId,
policy,
data: {
[CommitType.Delete]: [
{
secretName: req.params.secretName
}
]
}
});
return { approval };
}
}
const secret = await server.services.secret.deleteSecret({
actorId: req.permission.id,
actor: req.permission.type,
path: req.body.secretPath,
type: req.body.type,
environment: req.body.environment,
path: secretPath,
type,
environment,
secretName: req.params.secretName,
projectId: req.body.workspaceId,
secretId: req.body.secretId
projectId,
secretId
});
return { secret };
@@ -265,20 +429,51 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
.min(1)
}),
response: {
200: z.object({
secrets: SecretsSchema.omit({ secretBlindIndex: true }).array()
})
200: z.union([
z.object({
secrets: SecretsSchema.omit({ secretBlindIndex: true }).array()
}),
z
.object({ approval: SecretApprovalRequestsSchema })
.describe("When secret protection policy is enabled")
])
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
handler: async (req) => {
const { environment, workspaceId: projectId, secretPath, secrets: inputSecrets } = req.body;
if (req.permission.type === ActorType.USER) {
const policy = await server.services.secretApprovalPolicy.getSapOfFolder({
actorId: req.permission.id,
actor: req.permission.type,
secretPath,
environment,
projectId
});
if (policy) {
const approval =
await server.services.secretApprovalRequest.generateSecretApprovalRequest({
actorId: req.permission.id,
actor: req.permission.type,
secretPath,
environment,
projectId,
policy,
data: {
[CommitType.Create]: inputSecrets.filter(({ type }) => type === "shared")
}
});
return { approval };
}
}
const secrets = await server.services.secret.createManySecret({
actorId: req.permission.id,
actor: req.permission.type,
path: req.body.secretPath,
environment: req.body.environment,
projectId: req.body.workspaceId,
secrets: req.body.secrets
path: secretPath,
environment,
projectId,
secrets: inputSecrets
});
return { secrets };
@@ -313,20 +508,50 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
.min(1)
}),
response: {
200: z.object({
secrets: SecretsSchema.omit({ secretBlindIndex: true }).array()
})
200: z.union([
z.object({
secrets: SecretsSchema.omit({ secretBlindIndex: true }).array()
}),
z
.object({ approval: SecretApprovalRequestsSchema })
.describe("When secret protection policy is enabled")
])
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
handler: async (req) => {
const { environment, workspaceId: projectId, secretPath, secrets: inputSecrets } = req.body;
if (req.permission.type === ActorType.USER) {
const policy = await server.services.secretApprovalPolicy.getSapOfFolder({
actorId: req.permission.id,
actor: req.permission.type,
secretPath,
environment,
projectId
});
if (policy) {
const approval =
await server.services.secretApprovalRequest.generateSecretApprovalRequest({
actorId: req.permission.id,
actor: req.permission.type,
secretPath,
environment,
projectId,
policy,
data: {
[CommitType.Update]: inputSecrets.filter(({ type }) => type === "shared")
}
});
return { approval };
}
}
const secrets = await server.services.secret.updateManySecret({
actorId: req.permission.id,
actor: req.permission.type,
path: req.body.secretPath,
environment: req.body.environment,
projectId: req.body.workspaceId,
secrets: req.body.secrets
path: secretPath,
environment,
projectId,
secrets: inputSecrets
});
return { secrets };
@@ -350,20 +575,50 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
.min(1)
}),
response: {
200: z.object({
secrets: SecretsSchema.omit({ secretBlindIndex: true }).array()
})
200: z.union([
z.object({
secrets: SecretsSchema.omit({ secretBlindIndex: true }).array()
}),
z
.object({ approval: SecretApprovalRequestsSchema })
.describe("When secret protection policy is enabled")
])
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
handler: async (req) => {
const { environment, workspaceId: projectId, secretPath, secrets: inputSecrets } = req.body;
if (req.permission.type === ActorType.USER) {
const policy = await server.services.secretApprovalPolicy.getSapOfFolder({
actorId: req.permission.id,
actor: req.permission.type,
secretPath,
environment,
projectId
});
if (policy) {
const approval =
await server.services.secretApprovalRequest.generateSecretApprovalRequest({
actorId: req.permission.id,
actor: req.permission.type,
secretPath,
environment,
projectId,
policy,
data: {
[CommitType.Delete]: inputSecrets.filter(({ type }) => type === "shared")
}
});
return { approval };
}
}
const secrets = await server.services.secret.deleteManySecret({
actorId: req.permission.id,
actor: req.permission.type,
path: req.body.secretPath,
environment: req.body.environment,
projectId: req.body.workspaceId,
secrets: req.body.secrets
environment,
projectId,
secrets: inputSecrets
});
return { secrets };