mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
misc: modified encryption/decryption of external kms config
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
const hasKmsDataKeyCol = await knex.schema.hasColumn(TableName.Organization, "kmsEncryptedDataKey");
|
||||
await knex.schema.alterTable(TableName.Organization, (tb) => {
|
||||
if (!hasKmsDataKeyCol) {
|
||||
tb.binary("kmsEncryptedDataKey");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
const hasKmsDataKeyCol = await knex.schema.hasColumn(TableName.Organization, "kmsEncryptedDataKey");
|
||||
await knex.schema.alterTable(TableName.Organization, (t) => {
|
||||
if (hasKmsDataKeyCol) {
|
||||
t.dropColumn("kmsEncryptedDataKey");
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
import { z } from "zod";
|
||||
|
||||
import { zodBuffer } from "@app/lib/zod";
|
||||
|
||||
import { TImmutableDBKeys } from "./models";
|
||||
|
||||
export const OrganizationsSchema = z.object({
|
||||
@@ -16,7 +18,8 @@ export const OrganizationsSchema = z.object({
|
||||
updatedAt: z.date(),
|
||||
authEnforced: z.boolean().default(false).nullable().optional(),
|
||||
scimEnabled: z.boolean().default(false).nullable().optional(),
|
||||
kmsDefaultKeyId: z.string().uuid().nullable().optional()
|
||||
kmsDefaultKeyId: z.string().uuid().nullable().optional(),
|
||||
kmsEncryptedDataKey: zodBuffer.nullable().optional()
|
||||
});
|
||||
|
||||
export type TOrganizations = z.infer<typeof OrganizationsSchema>;
|
||||
|
||||
@@ -22,7 +22,10 @@ import { ExternalKmsAwsSchema, KmsProviders } from "./providers/model";
|
||||
|
||||
type TExternalKmsServiceFactoryDep = {
|
||||
externalKmsDAL: TExternalKmsDALFactory;
|
||||
kmsService: Pick<TKmsServiceFactory, "getOrgKmsKeyId" | "encryptWithKmsKey" | "decryptWithKmsKey">;
|
||||
kmsService: Pick<
|
||||
TKmsServiceFactory,
|
||||
"getOrgKmsKeyId" | "decryptWithInputKey" | "encryptWithInputKey" | "getOrgKmsDataKey"
|
||||
>;
|
||||
kmsDAL: Pick<TKmsKeyDALFactory, "create" | "updateById" | "findById" | "deleteById" | "findOne">;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
||||
};
|
||||
@@ -69,10 +72,11 @@ export const externalKmsServiceFactory = ({
|
||||
throw new BadRequestError({ message: "external kms provided is invalid" });
|
||||
}
|
||||
|
||||
const orgKmsKeyId = await kmsService.getOrgKmsKeyId(actorOrgId);
|
||||
const kmsEncryptor = await kmsService.encryptWithKmsKey({
|
||||
kmsId: orgKmsKeyId
|
||||
const orgKmsDataKey = await kmsService.getOrgKmsDataKey(actorOrgId);
|
||||
const kmsEncryptor = await kmsService.encryptWithInputKey({
|
||||
key: orgKmsDataKey
|
||||
});
|
||||
|
||||
const { cipherTextBlob: encryptedProviderInputs } = kmsEncryptor({
|
||||
plainText: Buffer.from(sanitizedProviderInput, "utf8")
|
||||
});
|
||||
@@ -125,12 +129,13 @@ export const externalKmsServiceFactory = ({
|
||||
const externalKmsDoc = await externalKmsDAL.findOne({ kmsKeyId: kmsDoc.id });
|
||||
if (!externalKmsDoc) throw new BadRequestError({ message: "External kms not found" });
|
||||
|
||||
const orgDefaultKmsId = await kmsService.getOrgKmsKeyId(kmsDoc.orgId);
|
||||
let sanitizedProviderInput = "";
|
||||
if (provider) {
|
||||
const kmsDecryptor = await kmsService.decryptWithKmsKey({
|
||||
kmsId: orgDefaultKmsId
|
||||
const orgKmsDataKey = await kmsService.getOrgKmsDataKey(kmsDoc.orgId);
|
||||
const kmsDecryptor = await kmsService.decryptWithInputKey({
|
||||
key: orgKmsDataKey
|
||||
});
|
||||
|
||||
const decryptedProviderInputBlob = kmsDecryptor({
|
||||
cipherTextBlob: externalKmsDoc.encryptedProviderInputs
|
||||
});
|
||||
@@ -154,8 +159,9 @@ export const externalKmsServiceFactory = ({
|
||||
|
||||
let encryptedProviderInputs: Buffer | undefined;
|
||||
if (sanitizedProviderInput) {
|
||||
const kmsEncryptor = await kmsService.encryptWithKmsKey({
|
||||
kmsId: orgDefaultKmsId
|
||||
const orgKmsDataKey = await kmsService.getOrgKmsDataKey(actorOrgId);
|
||||
const kmsEncryptor = await kmsService.encryptWithInputKey({
|
||||
key: orgKmsDataKey
|
||||
});
|
||||
const { cipherTextBlob } = kmsEncryptor({
|
||||
plainText: Buffer.from(sanitizedProviderInput, "utf8")
|
||||
@@ -239,10 +245,11 @@ export const externalKmsServiceFactory = ({
|
||||
const externalKmsDoc = await externalKmsDAL.findOne({ kmsKeyId: kmsDoc.id });
|
||||
if (!externalKmsDoc) throw new BadRequestError({ message: "External kms not found" });
|
||||
|
||||
const orgDefaultKmsId = await kmsService.getOrgKmsKeyId(kmsDoc.orgId);
|
||||
const kmsDecryptor = await kmsService.decryptWithKmsKey({
|
||||
kmsId: orgDefaultKmsId
|
||||
const orgKmsDataKey = await kmsService.getOrgKmsDataKey(kmsDoc.orgId);
|
||||
const kmsDecryptor = await kmsService.decryptWithInputKey({
|
||||
key: orgKmsDataKey
|
||||
});
|
||||
|
||||
const decryptedProviderInputBlob = kmsDecryptor({
|
||||
cipherTextBlob: externalKmsDoc.encryptedProviderInputs
|
||||
});
|
||||
@@ -278,10 +285,11 @@ export const externalKmsServiceFactory = ({
|
||||
const externalKmsDoc = await externalKmsDAL.findOne({ kmsKeyId: kmsDoc.id });
|
||||
if (!externalKmsDoc) throw new BadRequestError({ message: "External kms not found" });
|
||||
|
||||
const orgDefaultKmsId = await kmsService.getOrgKmsKeyId(kmsDoc.orgId);
|
||||
const kmsDecryptor = await kmsService.decryptWithKmsKey({
|
||||
kmsId: orgDefaultKmsId
|
||||
const orgKmsDataKey = await kmsService.getOrgKmsDataKey(kmsDoc.orgId);
|
||||
const kmsDecryptor = await kmsService.decryptWithInputKey({
|
||||
key: orgKmsDataKey
|
||||
});
|
||||
|
||||
const decryptedProviderInputBlob = kmsDecryptor({
|
||||
cipherTextBlob: externalKmsDoc.encryptedProviderInputs
|
||||
});
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import crypto from "node:crypto";
|
||||
|
||||
import slugify from "@sindresorhus/slugify";
|
||||
import { Knex } from "knex";
|
||||
|
||||
@@ -166,6 +168,50 @@ export const kmsServiceFactory = ({
|
||||
return keyId;
|
||||
};
|
||||
|
||||
const getOrgKmsDataKey = async (orgId: string) => {
|
||||
const kmsKeyId = await getOrgKmsKeyId(orgId);
|
||||
const orgKmsDataKey = await orgDAL.transaction(async (tx) => {
|
||||
const org = await orgDAL.findById(orgId, tx);
|
||||
|
||||
if (!org) {
|
||||
throw new BadRequestError({ message: "Org not found" });
|
||||
}
|
||||
|
||||
let encryptedDataKey = org.kmsEncryptedDataKey;
|
||||
if (!encryptedDataKey) {
|
||||
const dataKey = crypto.randomBytes(32);
|
||||
const kmsEncryptor = await encryptWithKmsKey({
|
||||
kmsId: kmsKeyId
|
||||
});
|
||||
|
||||
const { cipherTextBlob } = kmsEncryptor({
|
||||
plainText: dataKey
|
||||
});
|
||||
|
||||
encryptedDataKey = cipherTextBlob;
|
||||
await orgDAL.updateById(
|
||||
org.id,
|
||||
{
|
||||
kmsEncryptedDataKey: encryptedDataKey
|
||||
},
|
||||
tx
|
||||
);
|
||||
|
||||
return dataKey;
|
||||
}
|
||||
|
||||
const kmsDecryptor = await decryptWithKmsKey({
|
||||
kmsId: kmsKeyId
|
||||
});
|
||||
|
||||
return kmsDecryptor({
|
||||
cipherTextBlob: encryptedDataKey
|
||||
});
|
||||
});
|
||||
|
||||
return orgKmsDataKey;
|
||||
};
|
||||
|
||||
const getProjectSecretManagerKmsKeyId = async (projectId: string) => {
|
||||
let project = await projectDAL.findById(projectId);
|
||||
if (!project) {
|
||||
@@ -337,6 +383,6 @@ export const kmsServiceFactory = ({
|
||||
decryptWithInputKey,
|
||||
getOrgKmsKeyId,
|
||||
getProjectSecretManagerKmsKeyId,
|
||||
getProjectSecretManagerKmsDataKey
|
||||
getOrgKmsDataKey
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user