mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-06 13:27:22 +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 { z } from "zod";
|
||||||
|
|
||||||
|
import { zodBuffer } from "@app/lib/zod";
|
||||||
|
|
||||||
import { TImmutableDBKeys } from "./models";
|
import { TImmutableDBKeys } from "./models";
|
||||||
|
|
||||||
export const OrganizationsSchema = z.object({
|
export const OrganizationsSchema = z.object({
|
||||||
@@ -16,7 +18,8 @@ export const OrganizationsSchema = z.object({
|
|||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
authEnforced: z.boolean().default(false).nullable().optional(),
|
authEnforced: z.boolean().default(false).nullable().optional(),
|
||||||
scimEnabled: 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>;
|
export type TOrganizations = z.infer<typeof OrganizationsSchema>;
|
||||||
|
|||||||
@@ -22,7 +22,10 @@ import { ExternalKmsAwsSchema, KmsProviders } from "./providers/model";
|
|||||||
|
|
||||||
type TExternalKmsServiceFactoryDep = {
|
type TExternalKmsServiceFactoryDep = {
|
||||||
externalKmsDAL: TExternalKmsDALFactory;
|
externalKmsDAL: TExternalKmsDALFactory;
|
||||||
kmsService: Pick<TKmsServiceFactory, "getOrgKmsKeyId" | "encryptWithKmsKey" | "decryptWithKmsKey">;
|
kmsService: Pick<
|
||||||
|
TKmsServiceFactory,
|
||||||
|
"getOrgKmsKeyId" | "decryptWithInputKey" | "encryptWithInputKey" | "getOrgKmsDataKey"
|
||||||
|
>;
|
||||||
kmsDAL: Pick<TKmsKeyDALFactory, "create" | "updateById" | "findById" | "deleteById" | "findOne">;
|
kmsDAL: Pick<TKmsKeyDALFactory, "create" | "updateById" | "findById" | "deleteById" | "findOne">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
||||||
};
|
};
|
||||||
@@ -69,10 +72,11 @@ export const externalKmsServiceFactory = ({
|
|||||||
throw new BadRequestError({ message: "external kms provided is invalid" });
|
throw new BadRequestError({ message: "external kms provided is invalid" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const orgKmsKeyId = await kmsService.getOrgKmsKeyId(actorOrgId);
|
const orgKmsDataKey = await kmsService.getOrgKmsDataKey(actorOrgId);
|
||||||
const kmsEncryptor = await kmsService.encryptWithKmsKey({
|
const kmsEncryptor = await kmsService.encryptWithInputKey({
|
||||||
kmsId: orgKmsKeyId
|
key: orgKmsDataKey
|
||||||
});
|
});
|
||||||
|
|
||||||
const { cipherTextBlob: encryptedProviderInputs } = kmsEncryptor({
|
const { cipherTextBlob: encryptedProviderInputs } = kmsEncryptor({
|
||||||
plainText: Buffer.from(sanitizedProviderInput, "utf8")
|
plainText: Buffer.from(sanitizedProviderInput, "utf8")
|
||||||
});
|
});
|
||||||
@@ -125,12 +129,13 @@ export const externalKmsServiceFactory = ({
|
|||||||
const externalKmsDoc = await externalKmsDAL.findOne({ kmsKeyId: kmsDoc.id });
|
const externalKmsDoc = await externalKmsDAL.findOne({ kmsKeyId: kmsDoc.id });
|
||||||
if (!externalKmsDoc) throw new BadRequestError({ message: "External kms not found" });
|
if (!externalKmsDoc) throw new BadRequestError({ message: "External kms not found" });
|
||||||
|
|
||||||
const orgDefaultKmsId = await kmsService.getOrgKmsKeyId(kmsDoc.orgId);
|
|
||||||
let sanitizedProviderInput = "";
|
let sanitizedProviderInput = "";
|
||||||
if (provider) {
|
if (provider) {
|
||||||
const kmsDecryptor = await kmsService.decryptWithKmsKey({
|
const orgKmsDataKey = await kmsService.getOrgKmsDataKey(kmsDoc.orgId);
|
||||||
kmsId: orgDefaultKmsId
|
const kmsDecryptor = await kmsService.decryptWithInputKey({
|
||||||
|
key: orgKmsDataKey
|
||||||
});
|
});
|
||||||
|
|
||||||
const decryptedProviderInputBlob = kmsDecryptor({
|
const decryptedProviderInputBlob = kmsDecryptor({
|
||||||
cipherTextBlob: externalKmsDoc.encryptedProviderInputs
|
cipherTextBlob: externalKmsDoc.encryptedProviderInputs
|
||||||
});
|
});
|
||||||
@@ -154,8 +159,9 @@ export const externalKmsServiceFactory = ({
|
|||||||
|
|
||||||
let encryptedProviderInputs: Buffer | undefined;
|
let encryptedProviderInputs: Buffer | undefined;
|
||||||
if (sanitizedProviderInput) {
|
if (sanitizedProviderInput) {
|
||||||
const kmsEncryptor = await kmsService.encryptWithKmsKey({
|
const orgKmsDataKey = await kmsService.getOrgKmsDataKey(actorOrgId);
|
||||||
kmsId: orgDefaultKmsId
|
const kmsEncryptor = await kmsService.encryptWithInputKey({
|
||||||
|
key: orgKmsDataKey
|
||||||
});
|
});
|
||||||
const { cipherTextBlob } = kmsEncryptor({
|
const { cipherTextBlob } = kmsEncryptor({
|
||||||
plainText: Buffer.from(sanitizedProviderInput, "utf8")
|
plainText: Buffer.from(sanitizedProviderInput, "utf8")
|
||||||
@@ -239,10 +245,11 @@ export const externalKmsServiceFactory = ({
|
|||||||
const externalKmsDoc = await externalKmsDAL.findOne({ kmsKeyId: kmsDoc.id });
|
const externalKmsDoc = await externalKmsDAL.findOne({ kmsKeyId: kmsDoc.id });
|
||||||
if (!externalKmsDoc) throw new BadRequestError({ message: "External kms not found" });
|
if (!externalKmsDoc) throw new BadRequestError({ message: "External kms not found" });
|
||||||
|
|
||||||
const orgDefaultKmsId = await kmsService.getOrgKmsKeyId(kmsDoc.orgId);
|
const orgKmsDataKey = await kmsService.getOrgKmsDataKey(kmsDoc.orgId);
|
||||||
const kmsDecryptor = await kmsService.decryptWithKmsKey({
|
const kmsDecryptor = await kmsService.decryptWithInputKey({
|
||||||
kmsId: orgDefaultKmsId
|
key: orgKmsDataKey
|
||||||
});
|
});
|
||||||
|
|
||||||
const decryptedProviderInputBlob = kmsDecryptor({
|
const decryptedProviderInputBlob = kmsDecryptor({
|
||||||
cipherTextBlob: externalKmsDoc.encryptedProviderInputs
|
cipherTextBlob: externalKmsDoc.encryptedProviderInputs
|
||||||
});
|
});
|
||||||
@@ -278,10 +285,11 @@ export const externalKmsServiceFactory = ({
|
|||||||
const externalKmsDoc = await externalKmsDAL.findOne({ kmsKeyId: kmsDoc.id });
|
const externalKmsDoc = await externalKmsDAL.findOne({ kmsKeyId: kmsDoc.id });
|
||||||
if (!externalKmsDoc) throw new BadRequestError({ message: "External kms not found" });
|
if (!externalKmsDoc) throw new BadRequestError({ message: "External kms not found" });
|
||||||
|
|
||||||
const orgDefaultKmsId = await kmsService.getOrgKmsKeyId(kmsDoc.orgId);
|
const orgKmsDataKey = await kmsService.getOrgKmsDataKey(kmsDoc.orgId);
|
||||||
const kmsDecryptor = await kmsService.decryptWithKmsKey({
|
const kmsDecryptor = await kmsService.decryptWithInputKey({
|
||||||
kmsId: orgDefaultKmsId
|
key: orgKmsDataKey
|
||||||
});
|
});
|
||||||
|
|
||||||
const decryptedProviderInputBlob = kmsDecryptor({
|
const decryptedProviderInputBlob = kmsDecryptor({
|
||||||
cipherTextBlob: externalKmsDoc.encryptedProviderInputs
|
cipherTextBlob: externalKmsDoc.encryptedProviderInputs
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import crypto from "node:crypto";
|
||||||
|
|
||||||
import slugify from "@sindresorhus/slugify";
|
import slugify from "@sindresorhus/slugify";
|
||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
|
|
||||||
@@ -166,6 +168,50 @@ export const kmsServiceFactory = ({
|
|||||||
return keyId;
|
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) => {
|
const getProjectSecretManagerKmsKeyId = async (projectId: string) => {
|
||||||
let project = await projectDAL.findById(projectId);
|
let project = await projectDAL.findById(projectId);
|
||||||
if (!project) {
|
if (!project) {
|
||||||
@@ -337,6 +383,6 @@ export const kmsServiceFactory = ({
|
|||||||
decryptWithInputKey,
|
decryptWithInputKey,
|
||||||
getOrgKmsKeyId,
|
getOrgKmsKeyId,
|
||||||
getProjectSecretManagerKmsKeyId,
|
getProjectSecretManagerKmsKeyId,
|
||||||
getProjectSecretManagerKmsDataKey
|
getOrgKmsDataKey
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user