Merge pull request #2095 from akhilmhdh/feat/aws-kms-sm

aws kms support base setup
This commit is contained in:
Maidul Islam
2024-07-15 12:47:30 -04:00
committed by GitHub
34 changed files with 2487 additions and 112 deletions
@@ -75,8 +75,10 @@ export const getCaCredentials = async ({
kmsService
});
const decryptedPrivateKey = await kmsService.decrypt({
kmsId: keyId,
const kmsDecryptor = await kmsService.decryptWithKmsKey({
kmsId: keyId
});
const decryptedPrivateKey = kmsDecryptor({
cipherTextBlob: caSecret.encryptedPrivateKey
});
@@ -123,15 +125,17 @@ export const getCaCertChain = async ({
kmsService
});
const decryptedCaCert = await kmsService.decrypt({
kmsId: keyId,
const kmsDecryptor = await kmsService.decryptWithKmsKey({
kmsId: keyId
});
const decryptedCaCert = kmsDecryptor({
cipherTextBlob: caCert.encryptedCertificate
});
const caCertObj = new x509.X509Certificate(decryptedCaCert);
const decryptedChain = await kmsService.decrypt({
kmsId: keyId,
const decryptedChain = kmsDecryptor({
cipherTextBlob: caCert.encryptedCertificateChain
});
@@ -168,8 +172,11 @@ export const rebuildCaCrl = async ({
kmsService
});
const privateKey = await kmsService.decrypt({
kmsId: keyId,
const kmsDecryptor = await kmsService.decryptWithKmsKey({
kmsId: keyId
});
const privateKey = kmsDecryptor({
cipherTextBlob: caSecret.encryptedPrivateKey
});
@@ -200,8 +207,10 @@ export const rebuildCaCrl = async ({
signingKey: sk
});
const { cipherTextBlob: encryptedCrl } = await kmsService.encrypt({
kmsId: keyId,
const kmsEncryptor = await kmsService.encryptWithKmsKey({
kmsId: keyId
});
const { cipherTextBlob: encryptedCrl } = kmsEncryptor({
plainText: Buffer.from(new Uint8Array(crl.rawData))
});
@@ -25,7 +25,7 @@ type TCertificateAuthorityQueueFactoryDep = {
certificateAuthoritySecretDAL: TCertificateAuthoritySecretDALFactory;
certificateDAL: TCertificateDALFactory;
projectDAL: Pick<TProjectDALFactory, "findProjectBySlug" | "findOne" | "updateById" | "findById" | "transaction">;
kmsService: Pick<TKmsServiceFactory, "generateKmsKey" | "encrypt" | "decrypt">;
kmsService: Pick<TKmsServiceFactory, "generateKmsKey" | "encryptWithKmsKey" | "decryptWithKmsKey">;
queueService: TQueueServiceFactory;
};
export type TCertificateAuthorityQueueFactory = ReturnType<typeof certificateAuthorityQueueFactory>;
@@ -88,8 +88,10 @@ export const certificateAuthorityQueueFactory = ({
kmsService
});
const privateKey = await kmsService.decrypt({
kmsId: keyId,
const kmsDecryptor = await kmsService.decryptWithKmsKey({
kmsId: keyId
});
const privateKey = kmsDecryptor({
cipherTextBlob: caSecret.encryptedPrivateKey
});
@@ -120,8 +122,10 @@ export const certificateAuthorityQueueFactory = ({
signingKey: sk
});
const { cipherTextBlob: encryptedCrl } = await kmsService.encrypt({
kmsId: keyId,
const kmsEncryptor = await kmsService.encryptWithKmsKey({
kmsId: keyId
});
const { cipherTextBlob: encryptedCrl } = kmsEncryptor({
plainText: Buffer.from(new Uint8Array(crl.rawData))
});
@@ -53,7 +53,7 @@ type TCertificateAuthorityServiceFactoryDep = {
certificateDAL: Pick<TCertificateDALFactory, "transaction" | "create" | "find">;
certificateBodyDAL: Pick<TCertificateBodyDALFactory, "create">;
projectDAL: Pick<TProjectDALFactory, "findProjectBySlug" | "findOne" | "updateById" | "findById" | "transaction">;
kmsService: Pick<TKmsServiceFactory, "generateKmsKey" | "encrypt" | "decrypt">;
kmsService: Pick<TKmsServiceFactory, "generateKmsKey" | "encryptWithKmsKey" | "decryptWithKmsKey">;
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
};
@@ -154,11 +154,14 @@ export const certificateAuthorityServiceFactory = ({
tx
);
const keyId = await getProjectKmsCertificateKeyId({
const certificateManagerKmsId = await getProjectKmsCertificateKeyId({
projectId: project.id,
projectDAL,
kmsService
});
const kmsEncryptor = await kmsService.encryptWithKmsKey({
kmsId: certificateManagerKmsId
});
if (type === CaType.ROOT) {
// note: create self-signed cert only applicable for root CA
@@ -178,13 +181,11 @@ export const certificateAuthorityServiceFactory = ({
]
});
const { cipherTextBlob: encryptedCertificate } = await kmsService.encrypt({
kmsId: keyId,
const { cipherTextBlob: encryptedCertificate } = kmsEncryptor({
plainText: Buffer.from(new Uint8Array(cert.rawData))
});
const { cipherTextBlob: encryptedCertificateChain } = await kmsService.encrypt({
kmsId: keyId,
const { cipherTextBlob: encryptedCertificateChain } = kmsEncryptor({
plainText: Buffer.alloc(0)
});
@@ -208,8 +209,7 @@ export const certificateAuthorityServiceFactory = ({
signingKey: keys.privateKey
});
const { cipherTextBlob: encryptedCrl } = await kmsService.encrypt({
kmsId: keyId,
const { cipherTextBlob: encryptedCrl } = kmsEncryptor({
plainText: Buffer.from(new Uint8Array(crl.rawData))
});
@@ -224,8 +224,7 @@ export const certificateAuthorityServiceFactory = ({
// https://nodejs.org/api/crypto.html#static-method-keyobjectfromkey
const skObj = KeyObject.from(keys.privateKey);
const { cipherTextBlob: encryptedPrivateKey } = await kmsService.encrypt({
kmsId: keyId,
const { cipherTextBlob: encryptedPrivateKey } = kmsEncryptor({
plainText: skObj.export({
type: "pkcs8",
format: "der"
@@ -449,15 +448,17 @@ export const certificateAuthorityServiceFactory = ({
const alg = keyAlgorithmToAlgCfg(ca.keyAlgorithm as CertKeyAlgorithm);
const keyId = await getProjectKmsCertificateKeyId({
const certificateManagerKmsId = await getProjectKmsCertificateKeyId({
projectId: ca.projectId,
projectDAL,
kmsService
});
const kmsDecryptor = await kmsService.decryptWithKmsKey({
kmsId: certificateManagerKmsId
});
const caCert = await certificateAuthorityCertDAL.findOne({ caId: ca.id });
const decryptedCaCert = await kmsService.decrypt({
kmsId: keyId,
const decryptedCaCert = kmsDecryptor({
cipherTextBlob: caCert.encryptedCertificate
});
@@ -605,19 +606,20 @@ export const certificateAuthorityServiceFactory = ({
dn: parentCertSubject
});
const keyId = await getProjectKmsCertificateKeyId({
const certificateManagerKmsId = await getProjectKmsCertificateKeyId({
projectId: ca.projectId,
projectDAL,
kmsService
});
const kmsEncryptor = await kmsService.encryptWithKmsKey({
kmsId: certificateManagerKmsId
});
const { cipherTextBlob: encryptedCertificate } = await kmsService.encrypt({
kmsId: keyId,
const { cipherTextBlob: encryptedCertificate } = kmsEncryptor({
plainText: Buffer.from(new Uint8Array(certObj.rawData))
});
const { cipherTextBlob: encryptedCertificateChain } = await kmsService.encrypt({
kmsId: keyId,
const { cipherTextBlob: encryptedCertificateChain } = kmsEncryptor({
plainText: Buffer.from(certificateChain)
});
@@ -682,14 +684,16 @@ export const certificateAuthorityServiceFactory = ({
const caCert = await certificateAuthorityCertDAL.findOne({ caId: ca.id });
if (!caCert) throw new BadRequestError({ message: "CA does not have a certificate installed" });
const keyId = await getProjectKmsCertificateKeyId({
const certificateManagerKmsId = await getProjectKmsCertificateKeyId({
projectId: ca.projectId,
projectDAL,
kmsService
});
const kmsDecryptor = await kmsService.decryptWithKmsKey({
kmsId: certificateManagerKmsId
});
const decryptedCaCert = await kmsService.decrypt({
kmsId: keyId,
const decryptedCaCert = kmsDecryptor({
cipherTextBlob: caCert.encryptedCertificate
});
@@ -796,8 +800,10 @@ export const certificateAuthorityServiceFactory = ({
const skLeafObj = KeyObject.from(leafKeys.privateKey);
const skLeaf = skLeafObj.export({ format: "pem", type: "pkcs8" }) as string;
const { cipherTextBlob: encryptedCertificate } = await kmsService.encrypt({
kmsId: keyId,
const kmsEncryptor = await kmsService.encryptWithKmsKey({
kmsId: certificateManagerKmsId
});
const { cipherTextBlob: encryptedCertificate } = kmsEncryptor({
plainText: Buffer.from(new Uint8Array(leafCert.rawData))
});
@@ -95,7 +95,7 @@ export type TGetCaCredentialsDTO = {
certificateAuthorityDAL: Pick<TCertificateAuthorityDALFactory, "findById">;
certificateAuthoritySecretDAL: Pick<TCertificateAuthoritySecretDALFactory, "findOne">;
projectDAL: Pick<TProjectDALFactory, "findOne" | "updateById" | "transaction">;
kmsService: Pick<TKmsServiceFactory, "decrypt" | "generateKmsKey">;
kmsService: Pick<TKmsServiceFactory, "decryptWithKmsKey" | "generateKmsKey">;
};
export type TGetCaCertChainDTO = {
@@ -103,7 +103,7 @@ export type TGetCaCertChainDTO = {
certificateAuthorityDAL: Pick<TCertificateAuthorityDALFactory, "findById">;
certificateAuthorityCertDAL: Pick<TCertificateAuthorityCertDALFactory, "findOne">;
projectDAL: Pick<TProjectDALFactory, "findOne" | "updateById" | "transaction">;
kmsService: Pick<TKmsServiceFactory, "decrypt" | "generateKmsKey">;
kmsService: Pick<TKmsServiceFactory, "decryptWithKmsKey" | "generateKmsKey">;
};
export type TRebuildCaCrlDTO = {
@@ -113,7 +113,7 @@ export type TRebuildCaCrlDTO = {
certificateAuthoritySecretDAL: Pick<TCertificateAuthoritySecretDALFactory, "findOne">;
projectDAL: Pick<TProjectDALFactory, "findOne" | "updateById" | "transaction">;
certificateDAL: Pick<TCertificateDALFactory, "find">;
kmsService: Pick<TKmsServiceFactory, "generateKmsKey" | "decrypt" | "encrypt">;
kmsService: Pick<TKmsServiceFactory, "generateKmsKey" | "decryptWithKmsKey" | "encryptWithKmsKey">;
};
export type TRotateCaCrlTriggerDTO = {
@@ -25,7 +25,7 @@ type TCertificateServiceFactoryDep = {
certificateAuthorityCrlDAL: Pick<TCertificateAuthorityCrlDALFactory, "update">;
certificateAuthoritySecretDAL: Pick<TCertificateAuthoritySecretDALFactory, "findOne">;
projectDAL: Pick<TProjectDALFactory, "findOne" | "updateById" | "findById" | "transaction">;
kmsService: Pick<TKmsServiceFactory, "generateKmsKey" | "encrypt" | "decrypt">;
kmsService: Pick<TKmsServiceFactory, "generateKmsKey" | "encryptWithKmsKey" | "decryptWithKmsKey">;
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
};
@@ -164,14 +164,16 @@ export const certificateServiceFactory = ({
const certBody = await certificateBodyDAL.findOne({ certId: cert.id });
const keyId = await getProjectKmsCertificateKeyId({
const certificateManagerKeyId = await getProjectKmsCertificateKeyId({
projectId: ca.projectId,
projectDAL,
kmsService
});
const decryptedCert = await kmsService.decrypt({
kmsId: keyId,
const kmsDecryptor = await kmsService.decryptWithKmsKey({
kmsId: certificateManagerKeyId
});
const decryptedCert = kmsDecryptor({
cipherTextBlob: certBody.encryptedCertificate
});
@@ -0,0 +1,10 @@
import { TDbClient } from "@app/db";
import { TableName } from "@app/db/schemas";
import { ormify } from "@app/lib/knex";
export type TInternalKmsDALFactory = ReturnType<typeof internalKmsDALFactory>;
export const internalKmsDALFactory = (db: TDbClient) => {
const internalKmsOrm = ormify(db, TableName.InternalKms);
return internalKmsOrm;
};
-10
View File
@@ -1,10 +0,0 @@
import { TDbClient } from "@app/db";
import { TableName } from "@app/db/schemas";
import { ormify } from "@app/lib/knex";
export type TKmsDALFactory = ReturnType<typeof kmsDALFactory>;
export const kmsDALFactory = (db: TDbClient) => {
const kmsOrm = ormify(db, TableName.KmsKey);
return kmsOrm;
};
+64
View File
@@ -0,0 +1,64 @@
import { Knex } from "knex";
import { TDbClient } from "@app/db";
import { KmsKeysSchema, TableName } from "@app/db/schemas";
import { DatabaseError } from "@app/lib/errors";
import { ormify, selectAllTableCols } from "@app/lib/knex";
export type TKmsKeyDALFactory = ReturnType<typeof kmskeyDALFactory>;
export const kmskeyDALFactory = (db: TDbClient) => {
const kmsOrm = ormify(db, TableName.KmsKey);
const findByIdWithAssociatedKms = async (id: string, tx?: Knex) => {
try {
const result = await (tx || db.replicaNode())(TableName.KmsKey)
.where({ [`${TableName.KmsKey}.id` as "id"]: id })
.leftJoin(TableName.InternalKms, `${TableName.KmsKey}.id`, `${TableName.InternalKms}.kmsKeyId`)
.leftJoin(TableName.ExternalKms, `${TableName.KmsKey}.id`, `${TableName.ExternalKms}.kmsKeyId`)
.first()
.select(selectAllTableCols(TableName.KmsKey))
.select(
db.ref("id").withSchema(TableName.InternalKms).as("internalKmsId"),
db.ref("encryptedKey").withSchema(TableName.InternalKms).as("internalKmsEncryptedKey"),
db.ref("encryptionAlgorithm").withSchema(TableName.InternalKms).as("internalKmsEncryptionAlgorithm"),
db.ref("version").withSchema(TableName.InternalKms).as("internalKmsVersion"),
db.ref("id").withSchema(TableName.InternalKms).as("internalKmsId")
)
.select(
db.ref("id").withSchema(TableName.ExternalKms).as("externalKmsId"),
db.ref("provider").withSchema(TableName.ExternalKms).as("externalKmsProvider"),
db.ref("encryptedProviderInputs").withSchema(TableName.ExternalKms).as("externalKmsEncryptedProviderInput"),
db.ref("status").withSchema(TableName.ExternalKms).as("externalKmsStatus"),
db.ref("statusDetails").withSchema(TableName.ExternalKms).as("externalKmsStatusDetails")
);
const data = {
...KmsKeysSchema.parse(result),
isExternal: Boolean(result?.externalKmsId),
externalKms: result?.externalKmsId
? {
id: result.externalKmsId,
provider: result.externalKmsProvider,
encryptedProviderInput: result.externalKmsEncryptedProviderInput,
status: result.externalKmsStatus,
statusDetails: result.externalKmsStatusDetails
}
: undefined,
internalKms: result?.internalKmsId
? {
id: result.internalKmsId,
encryptedKey: result.internalKmsEncryptedKey,
encryptionAlgorithm: result.internalKmsEncryptionAlgorithm,
version: result.internalKmsVersion
}
: undefined
};
return data;
} catch (error) {
throw new DatabaseError({ error, name: "Find by id" });
}
};
return { ...kmsOrm, findByIdWithAssociatedKms };
};
+158 -34
View File
@@ -1,18 +1,34 @@
import slugify from "@sindresorhus/slugify";
import { Knex } from "knex";
import { TKeyStoreFactory } from "@app/keystore/keystore";
import { getConfig } from "@app/lib/config/env";
import { randomSecureBytes } from "@app/lib/crypto";
import { symmetricCipherService, SymmetricEncryption } from "@app/lib/crypto/cipher";
import { BadRequestError } from "@app/lib/errors";
import { logger } from "@app/lib/logger";
import { alphaNumericNanoId } from "@app/lib/nanoid";
import { TKmsDALFactory } from "./kms-dal";
import { TOrgDALFactory } from "../org/org-dal";
import { TProjectDALFactory } from "../project/project-dal";
import { TInternalKmsDALFactory } from "./internal-kms-dal";
import { TKmsKeyDALFactory } from "./kms-key-dal";
import { TKmsRootConfigDALFactory } from "./kms-root-config-dal";
import { TDecryptWithKmsDTO, TEncryptWithKmsDTO, TGenerateKMSDTO } from "./kms-types";
import {
TDecryptWithKeyDTO,
TDecryptWithKmsDTO,
TEncryptionWithKeyDTO,
TEncryptWithKmsDTO,
TGenerateKMSDTO
} from "./kms-types";
type TKmsServiceFactoryDep = {
kmsDAL: TKmsDALFactory;
kmsDAL: TKmsKeyDALFactory;
projectDAL: Pick<TProjectDALFactory, "findById" | "updateById" | "transaction">;
orgDAL: Pick<TOrgDALFactory, "findById" | "updateById" | "transaction">;
kmsRootConfigDAL: Pick<TKmsRootConfigDALFactory, "findById" | "create">;
keyStore: Pick<TKeyStoreFactory, "acquireLock" | "waitTillReady" | "setItemWithExpiry">;
internalKmsDAL: Pick<TInternalKmsDALFactory, "create">;
};
export type TKmsServiceFactory = ReturnType<typeof kmsServiceFactory>;
@@ -25,54 +41,158 @@ const KMS_ROOT_CREATION_WAIT_TIME = 10;
// akhilmhdh: Don't edit this value. This is measured for blob concatination in kms
const KMS_VERSION = "v01";
const KMS_VERSION_BLOB_LENGTH = 3;
export const kmsServiceFactory = ({ kmsDAL, kmsRootConfigDAL, keyStore }: TKmsServiceFactoryDep) => {
export const kmsServiceFactory = ({
kmsDAL,
kmsRootConfigDAL,
keyStore,
internalKmsDAL,
orgDAL,
projectDAL
}: TKmsServiceFactoryDep) => {
let ROOT_ENCRYPTION_KEY = Buffer.alloc(0);
// this is used symmetric encryption
const generateKmsKey = async ({ scopeId, scopeType, isReserved = true, tx }: TGenerateKMSDTO) => {
const generateKmsKey = async ({ orgId, isReserved = true, tx, slug }: TGenerateKMSDTO) => {
const cipher = symmetricCipherService(SymmetricEncryption.AES_GCM_256);
const kmsKeyMaterial = randomSecureBytes(32);
const encryptedKeyMaterial = cipher.encrypt(kmsKeyMaterial, ROOT_ENCRYPTION_KEY);
const sanitizedSlug = slug ? slugify(slug) : slugify(alphaNumericNanoId(32));
const dbQuery = async (db: Knex) => {
const kmsDoc = await kmsDAL.create({
slug: sanitizedSlug,
orgId,
isReserved
});
const { encryptedKey, ...doc } = await kmsDAL.create(
{
version: 1,
encryptedKey: encryptedKeyMaterial,
encryptionAlgorithm: SymmetricEncryption.AES_GCM_256,
isReserved,
orgId: scopeType === "org" ? scopeId : undefined,
projectId: scopeType === "project" ? scopeId : undefined
},
tx
);
const { encryptedKey, ...doc } = await internalKmsDAL.create(
{
version: 1,
encryptedKey: encryptedKeyMaterial,
encryptionAlgorithm: SymmetricEncryption.AES_GCM_256,
kmsKeyId: kmsDoc.id
},
db
);
return doc;
};
if (tx) return dbQuery(tx);
const doc = await kmsDAL.transaction(async (tx2) => dbQuery(tx2));
return doc;
};
const encrypt = async ({ kmsId, plainText }: TEncryptWithKmsDTO) => {
const kmsDoc = await kmsDAL.findById(kmsId);
const encryptWithKmsKey = async ({ kmsId }: Omit<TEncryptWithKmsDTO, "plainText">) => {
const kmsDoc = await kmsDAL.findByIdWithAssociatedKms(kmsId);
if (!kmsDoc) throw new BadRequestError({ message: "KMS ID not found" });
// akhilmhdh: as more encryption are added do a check here on kmsDoc.encryptionAlgorithm
const cipher = symmetricCipherService(SymmetricEncryption.AES_GCM_256);
return ({ plainText }: Pick<TEncryptWithKmsDTO, "plainText">) => {
const kmsKey = cipher.decrypt(kmsDoc.internalKms?.encryptedKey as Buffer, ROOT_ENCRYPTION_KEY);
const encryptedPlainTextBlob = cipher.encrypt(plainText, kmsKey);
const kmsKey = cipher.decrypt(kmsDoc.encryptedKey, ROOT_ENCRYPTION_KEY);
const encryptedPlainTextBlob = cipher.encrypt(plainText, kmsKey);
// Buffer#1 encrypted text + Buffer#2 version number
const versionBlob = Buffer.from(KMS_VERSION, "utf8"); // length is 3
const cipherTextBlob = Buffer.concat([encryptedPlainTextBlob, versionBlob]);
return { cipherTextBlob };
// Buffer#1 encrypted text + Buffer#2 version number
const versionBlob = Buffer.from(KMS_VERSION, "utf8"); // length is 3
const cipherTextBlob = Buffer.concat([encryptedPlainTextBlob, versionBlob]);
return { cipherTextBlob };
};
};
const decrypt = async ({ cipherTextBlob: versionedCipherTextBlob, kmsId }: TDecryptWithKmsDTO) => {
const kmsDoc = await kmsDAL.findById(kmsId);
if (!kmsDoc) throw new BadRequestError({ message: "KMS ID not found" });
const encryptWithInputKey = async ({ key }: Omit<TEncryptionWithKeyDTO, "plainText">) => {
// akhilmhdh: as more encryption are added do a check here on kmsDoc.encryptionAlgorithm
const cipher = symmetricCipherService(SymmetricEncryption.AES_GCM_256);
const kmsKey = cipher.decrypt(kmsDoc.encryptedKey, ROOT_ENCRYPTION_KEY);
return ({ plainText }: Pick<TEncryptWithKmsDTO, "plainText">) => {
const encryptedPlainTextBlob = cipher.encrypt(plainText, key);
// Buffer#1 encrypted text + Buffer#2 version number
const versionBlob = Buffer.from(KMS_VERSION, "utf8"); // length is 3
const cipherTextBlob = Buffer.concat([encryptedPlainTextBlob, versionBlob]);
return { cipherTextBlob };
};
};
const cipherTextBlob = versionedCipherTextBlob.subarray(0, -KMS_VERSION_BLOB_LENGTH);
const decryptedBlob = cipher.decrypt(cipherTextBlob, kmsKey);
return decryptedBlob;
const decryptWithKmsKey = async ({ kmsId }: Omit<TDecryptWithKmsDTO, "cipherTextBlob">) => {
const kmsDoc = await kmsDAL.findByIdWithAssociatedKms(kmsId);
if (!kmsDoc) throw new BadRequestError({ message: "KMS ID not found" });
const cipher = symmetricCipherService(SymmetricEncryption.AES_GCM_256);
const kmsKey = cipher.decrypt(kmsDoc.internalKms?.encryptedKey as Buffer, ROOT_ENCRYPTION_KEY);
return ({ cipherTextBlob: versionedCipherTextBlob }: Pick<TDecryptWithKmsDTO, "cipherTextBlob">) => {
const cipherTextBlob = versionedCipherTextBlob.subarray(0, -KMS_VERSION_BLOB_LENGTH);
const decryptedBlob = cipher.decrypt(cipherTextBlob, kmsKey);
return decryptedBlob;
};
};
const decryptWithInputKey = async ({ key }: Omit<TDecryptWithKeyDTO, "cipherTextBlob">) => {
const cipher = symmetricCipherService(SymmetricEncryption.AES_GCM_256);
return ({ cipherTextBlob: versionedCipherTextBlob }: Pick<TDecryptWithKeyDTO, "cipherTextBlob">) => {
const cipherTextBlob = versionedCipherTextBlob.subarray(0, -KMS_VERSION_BLOB_LENGTH);
const decryptedBlob = cipher.decrypt(cipherTextBlob, key);
return decryptedBlob;
};
};
const getOrgKmsKeyId = async (orgId: string) => {
const keyId = await orgDAL.transaction(async (tx) => {
const org = await orgDAL.findById(orgId, tx);
if (!org) {
throw new BadRequestError({ message: "Org not found" });
}
if (!org.kmsDefaultKeyId) {
// create default kms key for certificate service
const key = await generateKmsKey({
isReserved: true,
orgId: org.id,
tx
});
await orgDAL.updateById(
org.id,
{
kmsDefaultKeyId: key.id
},
tx
);
return key.id;
}
return org.kmsDefaultKeyId;
});
return keyId;
};
const getProjectSecretManagerKmsKeyId = async (projectId: string) => {
const keyId = await projectDAL.transaction(async (tx) => {
const project = await projectDAL.findById(projectId, tx);
if (!project) {
throw new BadRequestError({ message: "Project not found" });
}
if (!project.kmsSecretManagerKeyId) {
// create default kms key for certificate service
const key = await generateKmsKey({
isReserved: true,
orgId: project.orgId,
tx
});
await projectDAL.updateById(
projectId,
{
kmsSecretManagerKeyId: key.id
},
tx
);
return key.id;
}
return project.kmsSecretManagerKeyId;
});
return keyId;
};
const startService = async () => {
@@ -123,7 +243,11 @@ export const kmsServiceFactory = ({ kmsDAL, kmsRootConfigDAL, keyStore }: TKmsSe
return {
startService,
generateKmsKey,
encrypt,
decrypt
encryptWithKmsKey,
encryptWithInputKey,
decryptWithKmsKey,
decryptWithInputKey,
getOrgKmsKeyId,
getProjectSecretManagerKmsKeyId
};
};
+12 -2
View File
@@ -1,9 +1,9 @@
import { Knex } from "knex";
export type TGenerateKMSDTO = {
scopeType: "project" | "org";
scopeId: string;
orgId: string;
isReserved?: boolean;
slug?: string;
tx?: Knex;
};
@@ -12,7 +12,17 @@ export type TEncryptWithKmsDTO = {
plainText: Buffer;
};
export type TEncryptionWithKeyDTO = {
key: Buffer;
plainText: Buffer;
};
export type TDecryptWithKmsDTO = {
kmsId: string;
cipherTextBlob: Buffer;
};
export type TDecryptWithKeyDTO = {
key: Buffer;
cipherTextBlob: Buffer;
};
+2 -2
View File
@@ -207,9 +207,9 @@ export const orgDALFactory = (db: TDbClient) => {
}
};
const updateById = async (orgId: string, data: Partial<TOrganizations>) => {
const updateById = async (orgId: string, data: Partial<TOrganizations>, tx?: Knex) => {
try {
const [org] = await db(TableName.Organization)
const [org] = await (tx || db)(TableName.Organization)
.where({ id: orgId })
.update({ ...data })
.returning("*");
+1 -2
View File
@@ -71,9 +71,8 @@ export const getProjectKmsCertificateKeyId = async ({
if (!project.kmsCertificateKeyId) {
// create default kms key for certificate service
const key = await kmsService.generateKmsKey({
scopeId: projectId,
scopeType: "project",
isReserved: true,
orgId: project.orgId,
tx
});