mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-08 03:27:38 +00:00
feat: added kms encryption and decryption secret bridge
This commit is contained in:
@@ -145,7 +145,8 @@ export const fnSecretsV2FromImports = async ({
|
|||||||
secretDAL,
|
secretDAL,
|
||||||
secretImportDAL,
|
secretImportDAL,
|
||||||
depth = 0,
|
depth = 0,
|
||||||
cyclicDetector = new Set()
|
cyclicDetector = new Set(),
|
||||||
|
decryptor
|
||||||
}: {
|
}: {
|
||||||
allowedImports: (Omit<TSecretImports, "importEnv"> & {
|
allowedImports: (Omit<TSecretImports, "importEnv"> & {
|
||||||
importEnv: { id: string; slug: string; name: string };
|
importEnv: { id: string; slug: string; name: string };
|
||||||
@@ -155,6 +156,7 @@ export const fnSecretsV2FromImports = async ({
|
|||||||
secretImportDAL: Pick<TSecretImportDALFactory, "findByFolderIds">;
|
secretImportDAL: Pick<TSecretImportDALFactory, "findByFolderIds">;
|
||||||
depth?: number;
|
depth?: number;
|
||||||
cyclicDetector?: Set<string>;
|
cyclicDetector?: Set<string>;
|
||||||
|
decryptor: (value?: Buffer | null) => string | undefined;
|
||||||
}) => {
|
}) => {
|
||||||
// avoid going more than a depth
|
// avoid going more than a depth
|
||||||
if (depth >= LEVEL_BREAK) return [];
|
if (depth >= LEVEL_BREAK) return [];
|
||||||
@@ -203,7 +205,8 @@ export const fnSecretsV2FromImports = async ({
|
|||||||
folderDAL,
|
folderDAL,
|
||||||
secretDAL,
|
secretDAL,
|
||||||
depth: depth + 1,
|
depth: depth + 1,
|
||||||
cyclicDetector
|
cyclicDetector,
|
||||||
|
decryptor
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const secretsFromdeeperImportGroupedByFolderId = groupBy(secretsFromDeeperImports, (i) => i.importFolderId);
|
const secretsFromdeeperImportGroupedByFolderId = groupBy(secretsFromDeeperImports, (i) => i.importFolderId);
|
||||||
@@ -224,8 +227,8 @@ export const fnSecretsV2FromImports = async ({
|
|||||||
.map((item) => ({
|
.map((item) => ({
|
||||||
...item,
|
...item,
|
||||||
secretKey: item.key,
|
secretKey: item.key,
|
||||||
secretValue: item.encryptedValue?.toString(),
|
secretValue: decryptor(item.encryptedValue),
|
||||||
secretComment: item.encryptedComment?.toString(),
|
secretComment: decryptor(item.encryptedComment),
|
||||||
environment: importEnv.slug,
|
environment: importEnv.slug,
|
||||||
workspace: "", // This field should not be used, it's only here to keep the older Python SDK versions backwards compatible with the new Postgres backend.
|
workspace: "", // This field should not be used, it's only here to keep the older Python SDK versions backwards compatible with the new Postgres backend.
|
||||||
_id: item.id // The old Python SDK depends on the _id field being returned. We return this to keep the older Python SDK versions backwards compatible with the new Postgres backend.
|
_id: item.id // The old Python SDK depends on the _id field being returned. We return this to keep the older Python SDK versions backwards compatible with the new Postgres backend.
|
||||||
|
|||||||
@@ -365,7 +365,7 @@ export const recursivelyGetSecretPaths = async ({
|
|||||||
|
|
||||||
type TInterpolateSecretArg = {
|
type TInterpolateSecretArg = {
|
||||||
projectId: string;
|
projectId: string;
|
||||||
decryptSecret: (encryptedValue?: Buffer | null) => string;
|
decryptSecret: (encryptedValue?: Buffer | null) => string | undefined;
|
||||||
secretDAL: Pick<TSecretV2BridgeDALFactory, "findByFolderId">;
|
secretDAL: Pick<TSecretV2BridgeDALFactory, "findByFolderId">;
|
||||||
folderDAL: Pick<TSecretFolderDALFactory, "findBySecretPath">;
|
folderDAL: Pick<TSecretFolderDALFactory, "findBySecretPath">;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -44,10 +44,16 @@ import {
|
|||||||
} from "./secret-v2-bridge-types";
|
} from "./secret-v2-bridge-types";
|
||||||
import { TSecretVersionV2DALFactory } from "./secret-version-dal";
|
import { TSecretVersionV2DALFactory } from "./secret-version-dal";
|
||||||
import { TSecretVersionV2TagDALFactory } from "./secret-version-tag-dal";
|
import { TSecretVersionV2TagDALFactory } from "./secret-version-tag-dal";
|
||||||
|
import { TKmsServiceFactory } from "../kms/kms-service";
|
||||||
|
import { TSecretSnapshotServiceFactory } from "@app/ee/services/secret-snapshot/secret-snapshot-service";
|
||||||
|
|
||||||
type TSecretV2BridgeServiceFactoryDep = {
|
type TSecretV2BridgeServiceFactoryDep = {
|
||||||
secretDAL: TSecretV2BridgeDALFactory;
|
secretDAL: TSecretV2BridgeDALFactory;
|
||||||
secretVersionDAL: TSecretVersionV2DALFactory;
|
secretVersionDAL: TSecretVersionV2DALFactory;
|
||||||
|
kmsService: Pick<
|
||||||
|
TKmsServiceFactory,
|
||||||
|
"getProjectSecretManagerKmsDataKey" | "encryptWithInputKey" | "decryptWithInputKey"
|
||||||
|
>;
|
||||||
secretVersionTagDAL: Pick<TSecretVersionV2TagDALFactory, "insertMany">;
|
secretVersionTagDAL: Pick<TSecretVersionV2TagDALFactory, "insertMany">;
|
||||||
secretTagDAL: TSecretTagDALFactory;
|
secretTagDAL: TSecretTagDALFactory;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
||||||
@@ -64,10 +70,22 @@ type TSecretV2BridgeServiceFactoryDep = {
|
|||||||
TSecretApprovalRequestSecretDALFactory,
|
TSecretApprovalRequestSecretDALFactory,
|
||||||
"insertMany" | "insertApprovalSecretTags"
|
"insertMany" | "insertApprovalSecretTags"
|
||||||
>;
|
>;
|
||||||
|
snapshotService: Pick<TSecretSnapshotServiceFactory, "performSnapshot">;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TSecretV2BridgeServiceFactory = ReturnType<typeof secretV2BridgeServiceFactory>;
|
export type TSecretV2BridgeServiceFactory = ReturnType<typeof secretV2BridgeServiceFactory>;
|
||||||
|
|
||||||
|
const encryptionHelper = {
|
||||||
|
encryptValue: (encryptor: Awaited<ReturnType<TKmsServiceFactory["encryptWithKmsKey"]>>, value?: string) => {
|
||||||
|
if (typeof value === "undefined") return;
|
||||||
|
return encryptor({ plainText: Buffer.from(value) }).cipherTextBlob;
|
||||||
|
},
|
||||||
|
decryptValue: (decryptor: Awaited<ReturnType<TKmsServiceFactory["decryptWithInputKey"]>>, value?: Buffer | null) => {
|
||||||
|
if (!value) return;
|
||||||
|
return decryptor({ cipherTextBlob: value }).toString();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This service is a bridge from our old architecture towards the new architecture
|
* This service is a bridge from our old architecture towards the new architecture
|
||||||
*/
|
*/
|
||||||
@@ -84,7 +102,8 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
secretVersionTagDAL,
|
secretVersionTagDAL,
|
||||||
secretApprovalPolicyService,
|
secretApprovalPolicyService,
|
||||||
secretApprovalRequestDAL,
|
secretApprovalRequestDAL,
|
||||||
secretApprovalRequestSecretDAL
|
secretApprovalRequestSecretDAL,
|
||||||
|
kmsService
|
||||||
}: TSecretV2BridgeServiceFactoryDep) => {
|
}: TSecretV2BridgeServiceFactoryDep) => {
|
||||||
const createSecret = async ({
|
const createSecret = async ({
|
||||||
actor,
|
actor,
|
||||||
@@ -141,6 +160,9 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
|
|
||||||
const { secretName, type, ...el } = inputSecret;
|
const { secretName, type, ...el } = inputSecret;
|
||||||
const references = getAllNestedSecretReferences(inputSecret.secretValue);
|
const references = getAllNestedSecretReferences(inputSecret.secretValue);
|
||||||
|
const secretManagerDataKey = await kmsService.getProjectSecretManagerKmsDataKey(projectId);
|
||||||
|
const secretManagerEncryptor = await kmsService.encryptWithInputKey({ key: secretManagerDataKey });
|
||||||
|
|
||||||
const secret = await secretDAL.transaction((tx) =>
|
const secret = await secretDAL.transaction((tx) =>
|
||||||
fnSecretBulkInsert({
|
fnSecretBulkInsert({
|
||||||
folderId,
|
folderId,
|
||||||
@@ -149,8 +171,8 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
version: 1,
|
version: 1,
|
||||||
type,
|
type,
|
||||||
reminderRepeatDays: el.secretReminderRepeatDays,
|
reminderRepeatDays: el.secretReminderRepeatDays,
|
||||||
encryptedComment: el.secretComment ? Buffer.from(el.secretComment) : undefined,
|
encryptedComment: encryptionHelper.encryptValue(secretManagerEncryptor, el.secretComment),
|
||||||
encryptedValue: el.secretValue ? Buffer.from(el.secretValue) : undefined,
|
encryptedValue: encryptionHelper.encryptValue(secretManagerEncryptor, el.secretValue),
|
||||||
reminderNote: el.secretReminderNote,
|
reminderNote: el.secretReminderNote,
|
||||||
skipMultilineEncoding: el.skipMultilineEncoding,
|
skipMultilineEncoding: el.skipMultilineEncoding,
|
||||||
key: secretName,
|
key: secretName,
|
||||||
@@ -167,7 +189,7 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
// await snapshotService.performSnapshot(folderId);
|
await snapshotService.performSnapshot(folderId);
|
||||||
await secretQueueService.syncSecrets({
|
await secretQueueService.syncSecrets({
|
||||||
secretPath,
|
secretPath,
|
||||||
actorId,
|
actorId,
|
||||||
@@ -264,6 +286,16 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
|
|
||||||
const { secretName, secretValue, secretComment } = inputSecret;
|
const { secretName, secretValue, secretComment } = inputSecret;
|
||||||
|
|
||||||
|
const secretManagerDataKey = await kmsService.getProjectSecretManagerKmsDataKey(projectId);
|
||||||
|
const secretManagerEncryptor = await kmsService.encryptWithInputKey({ key: secretManagerDataKey });
|
||||||
|
const encryptedValue =
|
||||||
|
typeof secretValue !== "undefined"
|
||||||
|
? {
|
||||||
|
encryptedValue: encryptionHelper.encryptValue(secretManagerEncryptor, secretValue) as Buffer,
|
||||||
|
references: getAllNestedSecretReferences(secretValue)
|
||||||
|
}
|
||||||
|
: {};
|
||||||
|
|
||||||
const updatedSecret = await secretDAL.transaction(async (tx) =>
|
const updatedSecret = await secretDAL.transaction(async (tx) =>
|
||||||
fnSecretBulkUpdate({
|
fnSecretBulkUpdate({
|
||||||
folderId,
|
folderId,
|
||||||
@@ -272,20 +304,12 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
filter: { id: secretId },
|
filter: { id: secretId },
|
||||||
data: {
|
data: {
|
||||||
reminderRepeatDays: inputSecret.secretReminderRepeatDays,
|
reminderRepeatDays: inputSecret.secretReminderRepeatDays,
|
||||||
encryptedComment: secretComment ? Buffer.from(secretComment) : undefined,
|
encryptedComment: encryptionHelper.encryptValue(secretManagerEncryptor, secretComment),
|
||||||
reminderNote: inputSecret.secretReminderNote,
|
reminderNote: inputSecret.secretReminderNote,
|
||||||
skipMultilineEncoding: inputSecret.skipMultilineEncoding,
|
skipMultilineEncoding: inputSecret.skipMultilineEncoding,
|
||||||
key: inputSecret.newSecretName || secretName,
|
key: inputSecret.newSecretName || secretName,
|
||||||
tags: inputSecret.tagIds,
|
tags: inputSecret.tagIds,
|
||||||
...(secretValue
|
...encryptedValue
|
||||||
? {
|
|
||||||
encryptedValue: Buffer.from(secretValue),
|
|
||||||
references: getAllNestedSecretReferences(secretValue)
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
encryptedValue: undefined,
|
|
||||||
references: undefined
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -305,7 +329,7 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
projectId
|
projectId
|
||||||
});
|
});
|
||||||
|
|
||||||
// await snapshotService.performSnapshot(folderId);
|
await snapshotService.performSnapshot(folderId);
|
||||||
await secretQueueService.syncSecrets({
|
await secretQueueService.syncSecrets({
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
@@ -315,9 +339,8 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
});
|
});
|
||||||
return reshapeBridgeSecret(projectId, environment, secretPath, {
|
return reshapeBridgeSecret(projectId, environment, secretPath, {
|
||||||
...updatedSecret[0],
|
...updatedSecret[0],
|
||||||
// TODO(akhilmhdh-sev2): fix this
|
value: inputSecret.secretValue,
|
||||||
value: updatedSecret[0].encryptedValue?.toString(),
|
comment: inputSecret.secretComment
|
||||||
comment: updatedSecret[0].encryptedComment?.toString()
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -372,7 +395,7 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
// await snapshotService.performSnapshot(folderId);
|
await snapshotService.performSnapshot(folderId);
|
||||||
await secretQueueService.syncSecrets({
|
await secretQueueService.syncSecrets({
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
@@ -380,11 +403,13 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
projectId,
|
projectId,
|
||||||
environmentSlug: folder.environment.slug
|
environmentSlug: folder.environment.slug
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const secretManagerDataKey = await kmsService.getProjectSecretManagerKmsDataKey(projectId);
|
||||||
|
const secretManagerDecryptor = await kmsService.decryptWithInputKey({ key: secretManagerDataKey });
|
||||||
return reshapeBridgeSecret(projectId, environment, secretPath, {
|
return reshapeBridgeSecret(projectId, environment, secretPath, {
|
||||||
...deletedSecret[0],
|
...deletedSecret[0],
|
||||||
// TODO(akhilmhdh-sev2): fix this
|
value: encryptionHelper.decryptValue(secretManagerDecryptor, deletedSecret[0].encryptedValue),
|
||||||
value: deletedSecret[0].encryptedValue?.toString(),
|
comment: encryptionHelper.decryptValue(secretManagerDecryptor, deletedSecret[0].encryptedComment)
|
||||||
comment: deletedSecret[0].encryptedComment?.toString()
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -448,6 +473,9 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
actorId
|
actorId
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const secretManagerDataKey = await kmsService.getProjectSecretManagerKmsDataKey(projectId);
|
||||||
|
const secretManagerDecryptor = await kmsService.decryptWithInputKey({ key: secretManagerDataKey });
|
||||||
|
|
||||||
if (includeImports) {
|
if (includeImports) {
|
||||||
const secretImports = await secretImportDAL.findByFolderIds(paths.map((p) => p.folderId));
|
const secretImports = await secretImportDAL.findByFolderIds(paths.map((p) => p.folderId));
|
||||||
const allowedImports = secretImports.filter(({ importEnv, importPath, isReplication }) =>
|
const allowedImports = secretImports.filter(({ importEnv, importPath, isReplication }) =>
|
||||||
@@ -467,16 +495,16 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
allowedImports,
|
allowedImports,
|
||||||
secretDAL,
|
secretDAL,
|
||||||
folderDAL,
|
folderDAL,
|
||||||
secretImportDAL
|
secretImportDAL,
|
||||||
|
decryptor: (value) => encryptionHelper.decryptValue(secretManagerDecryptor, value)
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
secrets: secrets.map((secret) =>
|
secrets: secrets.map((secret) =>
|
||||||
reshapeBridgeSecret(projectId, environment, groupedPaths[secret.folderId][0].path, {
|
reshapeBridgeSecret(projectId, environment, groupedPaths[secret.folderId][0].path, {
|
||||||
...secret,
|
...secret,
|
||||||
// TODO(akhilmhdh-sev2): decryption missiong
|
value: encryptionHelper.decryptValue(secretManagerDecryptor, secret.encryptedValue),
|
||||||
value: secret.encryptedValue?.toString(),
|
comment: encryptionHelper.decryptValue(secretManagerDecryptor, secret.encryptedComment)
|
||||||
comment: secret.encryptedComment?.toString()
|
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
imports: importedSecrets
|
imports: importedSecrets
|
||||||
@@ -487,9 +515,8 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
secrets: secrets.map((secret) =>
|
secrets: secrets.map((secret) =>
|
||||||
reshapeBridgeSecret(projectId, environment, groupedPaths[secret.folderId][0].path, {
|
reshapeBridgeSecret(projectId, environment, groupedPaths[secret.folderId][0].path, {
|
||||||
...secret,
|
...secret,
|
||||||
// TODO(akhilmhdh-sev2): decrypt this
|
value: encryptionHelper.decryptValue(secretManagerDecryptor, secret.encryptedValue),
|
||||||
value: secret.encryptedValue?.toString(),
|
comment: encryptionHelper.decryptValue(secretManagerDecryptor, secret.encryptedComment)
|
||||||
comment: secret.encryptedComment?.toString()
|
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
@@ -536,6 +563,9 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
secretType = SecretType.Shared;
|
secretType = SecretType.Shared;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const secretManagerDataKey = await kmsService.getProjectSecretManagerKmsDataKey(projectId);
|
||||||
|
const secretManagerDecryptor = await kmsService.decryptWithInputKey({ key: secretManagerDataKey });
|
||||||
|
|
||||||
const secret = await (version === undefined
|
const secret = await (version === undefined
|
||||||
? secretDAL.findOneWithTags({
|
? secretDAL.findOneWithTags({
|
||||||
folderId,
|
folderId,
|
||||||
@@ -551,13 +581,13 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
key: secretName
|
key: secretName
|
||||||
})
|
})
|
||||||
.then((el) => SecretsV2Schema.parse({ ...el, id: el.secretId })));
|
.then((el) => SecretsV2Schema.parse({ ...el, id: el.secretId })));
|
||||||
// TODO(akhilmhdh-sev2): resolve this decryptSecret
|
|
||||||
const interpolateInlineSecretReference = interpolateSecrets({
|
const interpolateInlineSecretReference = interpolateSecrets({
|
||||||
projectId,
|
projectId,
|
||||||
decryptSecret: () => "",
|
decryptSecret: (encryptedValue) => encryptionHelper.decryptValue(secretManagerDecryptor, encryptedValue),
|
||||||
secretDAL,
|
secretDAL,
|
||||||
folderDAL
|
folderDAL
|
||||||
});
|
});
|
||||||
|
|
||||||
// now if secret is not found
|
// now if secret is not found
|
||||||
// then search for imported secrets
|
// then search for imported secrets
|
||||||
// here we consider the import order also thus starting from bottom
|
// here we consider the import order also thus starting from bottom
|
||||||
@@ -579,13 +609,15 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
allowedImports,
|
allowedImports,
|
||||||
secretDAL,
|
secretDAL,
|
||||||
folderDAL,
|
folderDAL,
|
||||||
secretImportDAL
|
secretImportDAL,
|
||||||
|
decryptor: (value) => encryptionHelper.decryptValue(secretManagerDecryptor, value)
|
||||||
});
|
});
|
||||||
|
|
||||||
for (let i = importedSecrets.length - 1; i >= 0; i -= 1) {
|
for (let i = importedSecrets.length - 1; i >= 0; i -= 1) {
|
||||||
for (let j = 0; j < importedSecrets[i].secrets.length; j += 1) {
|
for (let j = 0; j < importedSecrets[i].secrets.length; j += 1) {
|
||||||
if (secretName === importedSecrets[i].secrets[j].key) {
|
if (secretName === importedSecrets[i].secrets[j].key) {
|
||||||
const importedSecret = importedSecrets[i].secrets[j];
|
const importedSecret = importedSecrets[i].secrets[j];
|
||||||
let secretValue = importedSecret.encryptedValue ? importedSecret.encryptedValue.toString() : undefined;
|
let secretValue = encryptionHelper.decryptValue(secretManagerDecryptor, importedSecret.encryptedValue);
|
||||||
if (expandSecretReferences && secretValue) {
|
if (expandSecretReferences && secretValue) {
|
||||||
const secretReferenceExpandedString = {
|
const secretReferenceExpandedString = {
|
||||||
[importedSecret.key]: { value: secretValue }
|
[importedSecret.key]: { value: secretValue }
|
||||||
@@ -595,11 +627,10 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
secretValue = secretReferenceExpandedString[importedSecret.key].value;
|
secretValue = secretReferenceExpandedString[importedSecret.key].value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(akhilmhdh-sev2): decrypt this
|
|
||||||
return reshapeBridgeSecret(projectId, importedSecrets[i].environment, importedSecrets[i].secretPath, {
|
return reshapeBridgeSecret(projectId, importedSecrets[i].environment, importedSecrets[i].secretPath, {
|
||||||
...importedSecret,
|
...importedSecret,
|
||||||
value: secretValue,
|
value: secretValue,
|
||||||
comment: importedSecret.encryptedComment?.toString()
|
comment: encryptionHelper.decryptValue(secretManagerDecryptor, importedSecret.encryptedComment)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -607,7 +638,7 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
}
|
}
|
||||||
if (!secret) throw new BadRequestError({ message: "Secret not found" });
|
if (!secret) throw new BadRequestError({ message: "Secret not found" });
|
||||||
|
|
||||||
let secretValue = secret.encryptedValue ? secret.encryptedValue.toString() : undefined;
|
let secretValue = encryptionHelper.decryptValue(secretManagerDecryptor, secret.encryptedValue);
|
||||||
if (expandSecretReferences && secretValue) {
|
if (expandSecretReferences && secretValue) {
|
||||||
const secretReferenceExpandedString = {
|
const secretReferenceExpandedString = {
|
||||||
[secret.key]: { value: secretValue }
|
[secret.key]: { value: secretValue }
|
||||||
@@ -617,11 +648,10 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
secretValue = secretReferenceExpandedString[secret.key].value;
|
secretValue = secretReferenceExpandedString[secret.key].value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(akhilmhdh-sev2): fix this
|
|
||||||
return reshapeBridgeSecret(projectId, environment, path, {
|
return reshapeBridgeSecret(projectId, environment, path, {
|
||||||
...secret,
|
...secret,
|
||||||
value: secretValue,
|
value: secretValue,
|
||||||
comment: secret.encryptedComment?.toString()
|
comment: encryptionHelper.decryptValue(secretManagerDecryptor, secret.encryptedComment)
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -670,12 +700,15 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
const tags = sanitizedTagIds.length ? await secretTagDAL.findManyTagsById(projectId, sanitizedTagIds) : [];
|
const tags = sanitizedTagIds.length ? await secretTagDAL.findManyTagsById(projectId, sanitizedTagIds) : [];
|
||||||
if (tags.length !== sanitizedTagIds.length) throw new BadRequestError({ message: "Tag not found" });
|
if (tags.length !== sanitizedTagIds.length) throw new BadRequestError({ message: "Tag not found" });
|
||||||
|
|
||||||
|
const secretManagerDataKey = await kmsService.getProjectSecretManagerKmsDataKey(projectId);
|
||||||
|
const secretManagerEncryptor = await kmsService.encryptWithInputKey({ key: secretManagerDataKey });
|
||||||
|
|
||||||
const newSecrets = await secretDAL.transaction(async (tx) =>
|
const newSecrets = await secretDAL.transaction(async (tx) =>
|
||||||
fnSecretBulkInsert({
|
fnSecretBulkInsert({
|
||||||
inputSecrets: inputSecrets.map((el) => ({
|
inputSecrets: inputSecrets.map((el) => ({
|
||||||
version: 1,
|
version: 1,
|
||||||
encryptedComment: el.secretComment ? Buffer.from(el.secretComment) : undefined,
|
encryptedComment: encryptionHelper.encryptValue(secretManagerEncryptor, el.secretComment),
|
||||||
encryptedValue: el.secretValue ? Buffer.from(el.secretValue) : undefined,
|
encryptedValue: encryptionHelper.encryptValue(secretManagerEncryptor, el.secretValue),
|
||||||
skipMultilineEncoding: el.skipMultilineEncoding,
|
skipMultilineEncoding: el.skipMultilineEncoding,
|
||||||
key: el.secretKey,
|
key: el.secretKey,
|
||||||
tagIds: el.tagIds,
|
tagIds: el.tagIds,
|
||||||
@@ -691,7 +724,7 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
// await snapshotService.performSnapshot(folderId);
|
await snapshotService.performSnapshot(folderId);
|
||||||
await secretQueueService.syncSecrets({
|
await secretQueueService.syncSecrets({
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
@@ -700,12 +733,12 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
environmentSlug: folder.environment.slug
|
environmentSlug: folder.environment.slug
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const secretManagerDecryptor = await kmsService.decryptWithInputKey({ key: secretManagerDataKey });
|
||||||
return newSecrets.map((el) =>
|
return newSecrets.map((el) =>
|
||||||
reshapeBridgeSecret(projectId, environment, secretPath, {
|
reshapeBridgeSecret(projectId, environment, secretPath, {
|
||||||
...el,
|
...el,
|
||||||
// TODO(akhilmhdh-sev2): decryption missiong
|
value: encryptionHelper.decryptValue(secretManagerDecryptor, el.encryptedValue),
|
||||||
value: el.encryptedValue?.toString(),
|
comment: encryptionHelper.decryptValue(secretManagerDecryptor, el.encryptedComment)
|
||||||
comment: el.encryptedComment?.toString()
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -770,38 +803,41 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
const tags = sanitizedTagIds.length ? await secretTagDAL.findManyTagsById(projectId, sanitizedTagIds) : [];
|
const tags = sanitizedTagIds.length ? await secretTagDAL.findManyTagsById(projectId, sanitizedTagIds) : [];
|
||||||
if (tags.length !== sanitizedTagIds.length) throw new BadRequestError({ message: "Tag not found" });
|
if (tags.length !== sanitizedTagIds.length) throw new BadRequestError({ message: "Tag not found" });
|
||||||
|
|
||||||
|
const secretManagerDataKey = await kmsService.getProjectSecretManagerKmsDataKey(projectId);
|
||||||
|
const secretManagerEncryptor = await kmsService.encryptWithInputKey({ key: secretManagerDataKey });
|
||||||
|
|
||||||
const secrets = await secretDAL.transaction(async (tx) =>
|
const secrets = await secretDAL.transaction(async (tx) =>
|
||||||
fnSecretBulkUpdate({
|
fnSecretBulkUpdate({
|
||||||
folderId,
|
folderId,
|
||||||
tx,
|
tx,
|
||||||
inputSecrets: inputSecrets.map((el) => ({
|
inputSecrets: inputSecrets.map((el) => {
|
||||||
filter: { key: el.secretKey, type: SecretType.Shared },
|
const encryptedValue =
|
||||||
data: {
|
typeof el.secretValue !== "undefined"
|
||||||
reminderRepeatDays: el.secretReminderRepeatDays,
|
|
||||||
encryptedComment: el.secretComment ? Buffer.from(el.secretComment) : undefined,
|
|
||||||
reminderNote: el.secretReminderNote,
|
|
||||||
skipMultilineEncoding: el.skipMultilineEncoding,
|
|
||||||
key: el.newSecretName || el.secretKey,
|
|
||||||
tags: el.tagIds,
|
|
||||||
...(el.secretValue
|
|
||||||
? {
|
? {
|
||||||
encryptedValue: Buffer.from(el.secretValue),
|
encryptedValue: encryptionHelper.encryptValue(secretManagerEncryptor, el.secretValue) as Buffer,
|
||||||
references: getAllNestedSecretReferences(el.secretValue)
|
references: getAllNestedSecretReferences(el.secretValue)
|
||||||
}
|
}
|
||||||
: {
|
: {};
|
||||||
encryptedValue: undefined,
|
return {
|
||||||
references: undefined
|
filter: { key: el.secretKey, type: SecretType.Shared },
|
||||||
})
|
data: {
|
||||||
}
|
reminderRepeatDays: el.secretReminderRepeatDays,
|
||||||
})),
|
encryptedComment: encryptionHelper.encryptValue(secretManagerEncryptor, el.secretComment),
|
||||||
|
reminderNote: el.secretReminderNote,
|
||||||
|
skipMultilineEncoding: el.skipMultilineEncoding,
|
||||||
|
key: el.newSecretName || el.secretKey,
|
||||||
|
tags: el.tagIds,
|
||||||
|
...encryptedValue
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}),
|
||||||
secretDAL,
|
secretDAL,
|
||||||
secretVersionDAL,
|
secretVersionDAL,
|
||||||
secretTagDAL,
|
secretTagDAL,
|
||||||
secretVersionTagDAL
|
secretVersionTagDAL
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
await snapshotService.performSnapshot(folderId);
|
||||||
// await snapshotService.performSnapshot(folderId);
|
|
||||||
await secretQueueService.syncSecrets({
|
await secretQueueService.syncSecrets({
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
@@ -810,12 +846,12 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
environmentSlug: folder.environment.slug
|
environmentSlug: folder.environment.slug
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const secretManagerDecryptor = await kmsService.decryptWithInputKey({ key: secretManagerDataKey });
|
||||||
return secrets.map((el) =>
|
return secrets.map((el) =>
|
||||||
reshapeBridgeSecret(projectId, environment, secretPath, {
|
reshapeBridgeSecret(projectId, environment, secretPath, {
|
||||||
...el,
|
...el,
|
||||||
// TODO(akhilmhdh-sev2): decryption missiong
|
value: encryptionHelper.decryptValue(secretManagerDecryptor, el.encryptedValue),
|
||||||
value: el.encryptedValue?.toString(),
|
comment: encryptionHelper.decryptValue(secretManagerDecryptor, el.encryptedComment)
|
||||||
comment: el.encryptedComment?.toString()
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -884,12 +920,13 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
environmentSlug: folder.environment.slug
|
environmentSlug: folder.environment.slug
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const secretManagerDataKey = await kmsService.getProjectSecretManagerKmsDataKey(projectId);
|
||||||
|
const secretManagerDecryptor = await kmsService.decryptWithInputKey({ key: secretManagerDataKey });
|
||||||
return secretsDeleted.map((el) =>
|
return secretsDeleted.map((el) =>
|
||||||
reshapeBridgeSecret(projectId, environment, secretPath, {
|
reshapeBridgeSecret(projectId, environment, secretPath, {
|
||||||
...el,
|
...el,
|
||||||
// TODO(akhilmhdh-sev2): decryption missiong
|
value: encryptionHelper.decryptValue(secretManagerDecryptor, el.encryptedValue),
|
||||||
value: el.encryptedValue?.toString(),
|
comment: encryptionHelper.decryptValue(secretManagerDecryptor, el.encryptedComment)
|
||||||
comment: el.encryptedComment?.toString()
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -943,15 +980,20 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
if (!hasRole(ProjectMembershipRole.Admin))
|
if (!hasRole(ProjectMembershipRole.Admin))
|
||||||
throw new BadRequestError({ message: "Only admins are allowed to take this action" });
|
throw new BadRequestError({ message: "Only admins are allowed to take this action" });
|
||||||
|
|
||||||
|
const secretManagerDataKey = await kmsService.getProjectSecretManagerKmsDataKey(projectId);
|
||||||
|
const secretManagerDecryptor = await kmsService.decryptWithInputKey({ key: secretManagerDataKey });
|
||||||
await secretDAL.transaction(async (tx) => {
|
await secretDAL.transaction(async (tx) => {
|
||||||
const secrets = await secretDAL.findAllProjectSecretValues(projectId, tx);
|
const secrets = await secretDAL.findAllProjectSecretValues(projectId, tx);
|
||||||
// TODO(akhilmhdh-sev2): decryption missing
|
|
||||||
await secretDAL.upsertSecretReferences(
|
await secretDAL.upsertSecretReferences(
|
||||||
secrets
|
secrets
|
||||||
.filter((el) => Boolean(el.encryptedValue))
|
.filter((el) => Boolean(el.encryptedValue))
|
||||||
.map(({ id, encryptedValue }) => ({
|
.map(({ id, encryptedValue }) => ({
|
||||||
secretId: id,
|
secretId: id,
|
||||||
references: getAllNestedSecretReferences(encryptedValue?.toString("utf8"))
|
references: encryptedValue
|
||||||
|
? getAllNestedSecretReferences(
|
||||||
|
encryptionHelper.decryptValue(secretManagerDecryptor, encryptedValue) as string
|
||||||
|
)
|
||||||
|
: []
|
||||||
})),
|
})),
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
@@ -1028,10 +1070,11 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const secretManagerDataKey = await kmsService.getProjectSecretManagerKmsDataKey(projectId);
|
||||||
|
const secretManagerDecryptor = await kmsService.decryptWithInputKey({ key: secretManagerDataKey });
|
||||||
const decryptedSourceSecrets = sourceSecrets.map((secret) => ({
|
const decryptedSourceSecrets = sourceSecrets.map((secret) => ({
|
||||||
...secret,
|
...secret,
|
||||||
// TODO(akhilmhdh-sev2): decryption missiong
|
value: encryptionHelper.decryptValue(secretManagerDecryptor, secret.encryptedValue)
|
||||||
value: secret.encryptedValue?.toString()
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let isSourceUpdated = false;
|
let isSourceUpdated = false;
|
||||||
@@ -1050,8 +1093,7 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
const decryptedDestinationSecrets = destinationSecretsFromDB.map((secret) => {
|
const decryptedDestinationSecrets = destinationSecretsFromDB.map((secret) => {
|
||||||
return {
|
return {
|
||||||
...secret,
|
...secret,
|
||||||
// TODO(akhilmhdh-sev2): decryption missiong
|
value: encryptionHelper.decryptValue(secretManagerDecryptor, secret.encryptedValue)
|
||||||
value: secret.encryptedValue?.toString()
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1154,8 +1196,8 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
type: doc.type,
|
type: doc.type,
|
||||||
metadata: doc.metadata,
|
metadata: doc.metadata,
|
||||||
key: doc.key,
|
key: doc.key,
|
||||||
encryptedValue: doc.encryptedValue ? Buffer.from(doc.encryptedValue) : undefined,
|
encryptedValue: doc.encryptedValue,
|
||||||
encryptedComment: doc.encryptedComment ? Buffer.from(doc.encryptedComment) : undefined,
|
encryptedComment: doc.encryptedComment,
|
||||||
skipMultilineEncoding: doc.skipMultilineEncoding,
|
skipMultilineEncoding: doc.skipMultilineEncoding,
|
||||||
reminderNote: doc.reminderNote,
|
reminderNote: doc.reminderNote,
|
||||||
reminderRepeatDays: doc.reminderRepeatDays,
|
reminderRepeatDays: doc.reminderRepeatDays,
|
||||||
@@ -1188,8 +1230,7 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
...(doc.encryptedValue
|
...(doc.encryptedValue
|
||||||
? {
|
? {
|
||||||
encryptedValue: doc.encryptedValue,
|
encryptedValue: doc.encryptedValue,
|
||||||
// TODO(akhilmhdh-sev2): fix decryption
|
references: doc.value ? getAllNestedSecretReferences(doc.value) : []
|
||||||
references: getAllNestedSecretReferences(doc.encryptedValue.toString())
|
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
encryptedValue: undefined,
|
encryptedValue: undefined,
|
||||||
@@ -1275,7 +1316,7 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (isDestinationUpdated) {
|
if (isDestinationUpdated) {
|
||||||
// await snapshotService.performSnapshot(destinationFolder.id);
|
await snapshotService.performSnapshot(destinationFolder.id);
|
||||||
await secretQueueService.syncSecrets({
|
await secretQueueService.syncSecrets({
|
||||||
projectId,
|
projectId,
|
||||||
secretPath: destinationFolder.path,
|
secretPath: destinationFolder.path,
|
||||||
@@ -1286,7 +1327,7 @@ export const secretV2BridgeServiceFactory = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isSourceUpdated) {
|
if (isSourceUpdated) {
|
||||||
// await snapshotService.performSnapshot(sourceFolder.id);
|
await snapshotService.performSnapshot(sourceFolder.id);
|
||||||
await secretQueueService.syncSecrets({
|
await secretQueueService.syncSecrets({
|
||||||
projectId,
|
projectId,
|
||||||
secretPath: sourceFolder.path,
|
secretPath: sourceFolder.path,
|
||||||
|
|||||||
Reference in New Issue
Block a user