mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 04:27:29 +00:00
fix: requested changes
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
|
|
||||||
import { KmsKeyIntent } from "@app/services/kms/kms-types";
|
import { KmsKeyUsage } from "@app/services/kms/kms-types";
|
||||||
|
|
||||||
import { TableName } from "../schemas";
|
import { TableName } from "../schemas";
|
||||||
|
|
||||||
@@ -8,12 +8,12 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
const hasTypeColumn = await knex.schema.hasColumn(TableName.KmsKey, "type");
|
const hasTypeColumn = await knex.schema.hasColumn(TableName.KmsKey, "type");
|
||||||
|
|
||||||
await knex.schema.alterTable(TableName.KmsKey, (t) => {
|
await knex.schema.alterTable(TableName.KmsKey, (t) => {
|
||||||
if (!hasTypeColumn) t.string("type").notNullable().defaultTo(KmsKeyIntent.ENCRYPT_DECRYPT);
|
if (!hasTypeColumn) t.string("keyUsage").notNullable().defaultTo(KmsKeyUsage.ENCRYPT_DECRYPT);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function down(knex: Knex): Promise<void> {
|
export async function down(knex: Knex): Promise<void> {
|
||||||
await knex.schema.alterTable(TableName.KmsKey, (t) => {
|
await knex.schema.alterTable(TableName.KmsKey, (t) => {
|
||||||
t.dropColumn("type");
|
t.dropColumn("keyUsage");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export const KmsKeysSchema = z.object({
|
|||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
projectId: z.string().nullable().optional(),
|
projectId: z.string().nullable().optional(),
|
||||||
type: z.string().default("encrypt-decrypt")
|
keyUsage: z.string().default("encrypt-decrypt")
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TKmsKeys = z.infer<typeof KmsKeysSchema>;
|
export type TKmsKeys = z.infer<typeof KmsKeysSchema>;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import z from "zod";
|
|||||||
|
|
||||||
import { KmsKeysSchema } from "@app/db/schemas";
|
import { KmsKeysSchema } from "@app/db/schemas";
|
||||||
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import { SymmetricKeyEncryptDecrypt } from "@app/lib/crypto/cipher";
|
import { SymmetricKeyAlgorithm } from "@app/lib/crypto/cipher";
|
||||||
import { ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
|
import { ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
|
||||||
import { writeLimit } from "@app/server/config/rateLimiter";
|
import { writeLimit } from "@app/server/config/rateLimiter";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
@@ -74,7 +74,7 @@ export const registerKmipSpecRouter = async (server: FastifyZodProvider) => {
|
|||||||
schema: {
|
schema: {
|
||||||
description: "KMIP endpoint for creating managed objects",
|
description: "KMIP endpoint for creating managed objects",
|
||||||
body: z.object({
|
body: z.object({
|
||||||
algorithm: z.nativeEnum(SymmetricKeyEncryptDecrypt)
|
algorithm: z.nativeEnum(SymmetricKeyAlgorithm)
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: KmsKeysSchema
|
200: KmsKeysSchema
|
||||||
@@ -433,7 +433,7 @@ export const registerKmipSpecRouter = async (server: FastifyZodProvider) => {
|
|||||||
body: z.object({
|
body: z.object({
|
||||||
key: z.string(),
|
key: z.string(),
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
algorithm: z.nativeEnum(SymmetricKeyEncryptDecrypt)
|
algorithm: z.nativeEnum(SymmetricKeyAlgorithm)
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import {
|
|||||||
} from "@app/ee/services/project-template/project-template-types";
|
} from "@app/ee/services/project-template/project-template-types";
|
||||||
import { SshCaStatus, SshCertType } from "@app/ee/services/ssh/ssh-certificate-authority-types";
|
import { SshCaStatus, SshCertType } from "@app/ee/services/ssh/ssh-certificate-authority-types";
|
||||||
import { SshCertTemplateStatus } from "@app/ee/services/ssh-certificate-template/ssh-certificate-template-types";
|
import { SshCertTemplateStatus } from "@app/ee/services/ssh-certificate-template/ssh-certificate-template-types";
|
||||||
import { SymmetricKeyEncryptDecrypt } from "@app/lib/crypto/cipher";
|
import { SymmetricKeyAlgorithm } from "@app/lib/crypto/cipher";
|
||||||
import { AsymmetricKeySignVerify, SigningAlgorithm } from "@app/lib/crypto/sign/types";
|
import { AsymmetricKeyAlgorithm, SigningAlgorithm } from "@app/lib/crypto/sign/types";
|
||||||
import { TProjectPermission } from "@app/lib/types";
|
import { TProjectPermission } from "@app/lib/types";
|
||||||
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||||
import { TCreateAppConnectionDTO, TUpdateAppConnectionDTO } from "@app/services/app-connection/app-connection-types";
|
import { TCreateAppConnectionDTO, TUpdateAppConnectionDTO } from "@app/services/app-connection/app-connection-types";
|
||||||
@@ -1903,7 +1903,7 @@ interface CreateCmekEvent {
|
|||||||
keyId: string;
|
keyId: string;
|
||||||
name: string;
|
name: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
encryptionAlgorithm: SymmetricKeyEncryptDecrypt | AsymmetricKeySignVerify;
|
encryptionAlgorithm: SymmetricKeyAlgorithm | AsymmetricKeyAlgorithm;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { BadRequestError, InternalServerError, NotFoundError } from "@app/lib/er
|
|||||||
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
||||||
import { TKmsKeyDALFactory } from "@app/services/kms/kms-key-dal";
|
import { TKmsKeyDALFactory } from "@app/services/kms/kms-key-dal";
|
||||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||||
import { KmsDataKey, KmsKeyIntent } from "@app/services/kms/kms-types";
|
import { KmsDataKey, KmsKeyUsage } from "@app/services/kms/kms-types";
|
||||||
|
|
||||||
import { TLicenseServiceFactory } from "../license/license-service";
|
import { TLicenseServiceFactory } from "../license/license-service";
|
||||||
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
|
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
|
||||||
@@ -115,7 +115,7 @@ export const externalKmsServiceFactory = ({
|
|||||||
{
|
{
|
||||||
isReserved: false,
|
isReserved: false,
|
||||||
description,
|
description,
|
||||||
type: KmsKeyIntent.ENCRYPT_DECRYPT,
|
keyUsage: KmsKeyUsage.ENCRYPT_DECRYPT,
|
||||||
name: kmsName,
|
name: kmsName,
|
||||||
orgId: actorOrgId
|
orgId: actorOrgId
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { ForbiddenError } from "@casl/ability";
|
|||||||
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
|
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
|
||||||
import { TKmsKeyDALFactory } from "@app/services/kms/kms-key-dal";
|
import { TKmsKeyDALFactory } from "@app/services/kms/kms-key-dal";
|
||||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||||
import { KmsKeyIntent } from "@app/services/kms/kms-types";
|
import { KmsKeyUsage } from "@app/services/kms/kms-types";
|
||||||
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
||||||
|
|
||||||
import { OrgPermissionKmipActions, OrgPermissionSubjects } from "../permission/org-permission";
|
import { OrgPermissionKmipActions, OrgPermissionSubjects } from "../permission/org-permission";
|
||||||
@@ -404,7 +404,7 @@ export const kmipOperationServiceFactory = ({
|
|||||||
algorithm,
|
algorithm,
|
||||||
isReserved: false,
|
isReserved: false,
|
||||||
projectId,
|
projectId,
|
||||||
type: KmsKeyIntent.ENCRYPT_DECRYPT,
|
keyUsage: KmsKeyUsage.ENCRYPT_DECRYPT,
|
||||||
orgId: project.orgId
|
orgId: project.orgId
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { SymmetricKeyEncryptDecrypt } from "@app/lib/crypto/cipher";
|
import { SymmetricKeyAlgorithm } from "@app/lib/crypto/cipher";
|
||||||
import { OrderByDirection, TOrgPermission, TProjectPermission } from "@app/lib/types";
|
import { OrderByDirection, TOrgPermission, TProjectPermission } from "@app/lib/types";
|
||||||
import { CertKeyAlgorithm } from "@app/services/certificate/certificate-types";
|
import { CertKeyAlgorithm } from "@app/services/certificate/certificate-types";
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ type KmipOperationBaseDTO = {
|
|||||||
} & Omit<TOrgPermission, "orgId">;
|
} & Omit<TOrgPermission, "orgId">;
|
||||||
|
|
||||||
export type TKmipCreateDTO = {
|
export type TKmipCreateDTO = {
|
||||||
algorithm: SymmetricKeyEncryptDecrypt;
|
algorithm: SymmetricKeyAlgorithm;
|
||||||
} & KmipOperationBaseDTO;
|
} & KmipOperationBaseDTO;
|
||||||
|
|
||||||
export type TKmipGetDTO = {
|
export type TKmipGetDTO = {
|
||||||
@@ -77,7 +77,7 @@ export type TKmipLocateDTO = KmipOperationBaseDTO;
|
|||||||
export type TKmipRegisterDTO = {
|
export type TKmipRegisterDTO = {
|
||||||
name: string;
|
name: string;
|
||||||
key: string;
|
key: string;
|
||||||
algorithm: SymmetricKeyEncryptDecrypt;
|
algorithm: SymmetricKeyAlgorithm;
|
||||||
} & KmipOperationBaseDTO;
|
} & KmipOperationBaseDTO;
|
||||||
|
|
||||||
export type TSetupOrgKmipDTO = {
|
export type TSetupOrgKmipDTO = {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import crypto from "crypto";
|
import crypto from "crypto";
|
||||||
|
|
||||||
import { SymmetricKeyEncryptDecrypt, TSymmetricEncryptionFns } from "./types";
|
import { SymmetricKeyAlgorithm, TSymmetricEncryptionFns } from "./types";
|
||||||
|
|
||||||
const getIvLength = () => {
|
const getIvLength = () => {
|
||||||
return 12;
|
return 12;
|
||||||
@@ -11,7 +11,7 @@ const getTagLength = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const symmetricCipherService = (
|
export const symmetricCipherService = (
|
||||||
type: SymmetricKeyEncryptDecrypt.AES_GCM_128 | SymmetricKeyEncryptDecrypt.AES_GCM_256
|
type: SymmetricKeyAlgorithm.AES_GCM_128 | SymmetricKeyAlgorithm.AES_GCM_256
|
||||||
): TSymmetricEncryptionFns => {
|
): TSymmetricEncryptionFns => {
|
||||||
const IV_LENGTH = getIvLength();
|
const IV_LENGTH = getIvLength();
|
||||||
const TAG_LENGTH = getTagLength();
|
const TAG_LENGTH = getTagLength();
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
export { symmetricCipherService } from "./cipher";
|
export { symmetricCipherService } from "./cipher";
|
||||||
export { AllowedEncryptionKeyAlgorithms, SymmetricKeyEncryptDecrypt } from "./types";
|
export { AllowedEncryptionKeyAlgorithms, SymmetricKeyAlgorithm } from "./types";
|
||||||
|
|||||||
@@ -1,19 +1,17 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { AsymmetricKeySignVerify } from "../sign/types";
|
import { AsymmetricKeyAlgorithm } from "../sign/types";
|
||||||
|
|
||||||
// Supported symmetric encrypt/decrypt algorithms
|
// Supported symmetric encrypt/decrypt algorithms
|
||||||
export enum SymmetricKeyEncryptDecrypt {
|
export enum SymmetricKeyAlgorithm {
|
||||||
AES_GCM_256 = "aes-256-gcm",
|
AES_GCM_256 = "aes-256-gcm",
|
||||||
AES_GCM_128 = "aes-128-gcm"
|
AES_GCM_128 = "aes-128-gcm"
|
||||||
}
|
}
|
||||||
export const SymmetricKeyEncryptDecryptEnum = z.enum(
|
export const SymmetricKeyAlgorithmEnum = z.enum(Object.values(SymmetricKeyAlgorithm) as [string, ...string[]]).options;
|
||||||
Object.values(SymmetricKeyEncryptDecrypt) as [string, ...string[]]
|
|
||||||
).options;
|
|
||||||
|
|
||||||
export const AllowedEncryptionKeyAlgorithms = z.enum([
|
export const AllowedEncryptionKeyAlgorithms = z.enum([
|
||||||
...Object.values(SymmetricKeyEncryptDecrypt),
|
...Object.values(SymmetricKeyAlgorithm),
|
||||||
...Object.values(AsymmetricKeySignVerify)
|
...Object.values(AsymmetricKeyAlgorithm)
|
||||||
] as [string, ...string[]]).options;
|
] as [string, ...string[]]).options;
|
||||||
|
|
||||||
export type TSymmetricEncryptionFns = {
|
export type TSymmetricEncryptionFns = {
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
export { signingService } from "./signing";
|
export { signingService } from "./signing";
|
||||||
export { AsymmetricKeySignVerify, SigningAlgorithm } from "./types";
|
export { AsymmetricKeyAlgorithm, SigningAlgorithm } from "./types";
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import crypto from "crypto";
|
|||||||
import { BadRequestError } from "@app/lib/errors";
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
import { logger } from "@app/lib/logger";
|
import { logger } from "@app/lib/logger";
|
||||||
|
|
||||||
import { AsymmetricKeySignVerify, SigningAlgorithm, TAsymmetricSignVerifyFns } from "./types";
|
import { AsymmetricKeyAlgorithm, SigningAlgorithm, TAsymmetricSignVerifyFns } from "./types";
|
||||||
|
|
||||||
// Map of signing algorithms to their parameters
|
// Map of signing algorithms to their parameters
|
||||||
interface SigningParams {
|
interface SigningParams {
|
||||||
@@ -22,7 +22,7 @@ const SHA512_DIGEST_LENGTH = 64;
|
|||||||
* @param algorithm The signing algorithm to use
|
* @param algorithm The signing algorithm to use
|
||||||
* @returns Object with sign and verify functions
|
* @returns Object with sign and verify functions
|
||||||
*/
|
*/
|
||||||
export const signingService = (algorithm: AsymmetricKeySignVerify): TAsymmetricSignVerifyFns => {
|
export const signingService = (algorithm: AsymmetricKeyAlgorithm): TAsymmetricSignVerifyFns => {
|
||||||
const $getSigningParams = (signingAlgorithm: SigningAlgorithm): SigningParams => {
|
const $getSigningParams = (signingAlgorithm: SigningAlgorithm): SigningParams => {
|
||||||
switch (signingAlgorithm) {
|
switch (signingAlgorithm) {
|
||||||
// RSA PSS
|
// RSA PSS
|
||||||
@@ -76,10 +76,10 @@ export const signingService = (algorithm: AsymmetricKeySignVerify): TAsymmetricS
|
|||||||
};
|
};
|
||||||
|
|
||||||
// For ECC key generation, nodejs has some strange and hardly documented curve naming conventions
|
// For ECC key generation, nodejs has some strange and hardly documented curve naming conventions
|
||||||
const $getEcCurveName = (keyAlgorithm: AsymmetricKeySignVerify): string => {
|
const $getEcCurveName = (keyAlgorithm: AsymmetricKeyAlgorithm): string => {
|
||||||
// We will support more in the future
|
// We will support more in the future
|
||||||
switch (keyAlgorithm) {
|
switch (keyAlgorithm) {
|
||||||
case AsymmetricKeySignVerify.ECC_NIST_P256:
|
case AsymmetricKeyAlgorithm.ECC_NIST_P256:
|
||||||
return "prime256v1";
|
return "prime256v1";
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported EC curve: ${keyAlgorithm}`);
|
throw new Error(`Unsupported EC curve: ${keyAlgorithm}`);
|
||||||
@@ -172,7 +172,6 @@ export const signingService = (algorithm: AsymmetricKeySignVerify): TAsymmetricS
|
|||||||
type: "pkcs8"
|
type: "pkcs8"
|
||||||
});
|
});
|
||||||
|
|
||||||
// Return public key in PEM format for both RSA and EC
|
|
||||||
const publicKey = crypto.createPublicKey(privateKeyObj).export({
|
const publicKey = crypto.createPublicKey(privateKeyObj).export({
|
||||||
type: "spki",
|
type: "spki",
|
||||||
format: "pem"
|
format: "pem"
|
||||||
@@ -210,7 +209,8 @@ export const signingService = (algorithm: AsymmetricKeySignVerify): TAsymmetricS
|
|||||||
}
|
}
|
||||||
// For PKCS1 v1.5 padding
|
// For PKCS1 v1.5 padding
|
||||||
return signer.sign({
|
return signer.sign({
|
||||||
key: privateKeyObject
|
key: privateKeyObject,
|
||||||
|
padding
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (signingAlgorithm.startsWith("ECDSA")) {
|
if (signingAlgorithm.startsWith("ECDSA")) {
|
||||||
@@ -252,7 +252,8 @@ export const signingService = (algorithm: AsymmetricKeySignVerify): TAsymmetricS
|
|||||||
// For PKCS1 v1.5 padding
|
// For PKCS1 v1.5 padding
|
||||||
return verifier.verify(
|
return verifier.verify(
|
||||||
{
|
{
|
||||||
key: publicKey.toString()
|
key: publicKey.toString(),
|
||||||
|
padding
|
||||||
},
|
},
|
||||||
signature
|
signature
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -8,13 +8,13 @@ export type TAsymmetricSignVerifyFns = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Supported asymmetric key types
|
// Supported asymmetric key types
|
||||||
export enum AsymmetricKeySignVerify {
|
export enum AsymmetricKeyAlgorithm {
|
||||||
RSA_4096 = "rsa-4096",
|
RSA_4096 = "rsa-4096",
|
||||||
ECC_NIST_P256 = "ecc-nist-p256"
|
ECC_NIST_P256 = "ecc-nist-p256"
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AsymmetricKeySignVerifyEnum = z.enum(
|
export const AsymmetricKeyAlgorithmEnum = z.enum(
|
||||||
Object.values(AsymmetricKeySignVerify) as [string, ...string[]]
|
Object.values(AsymmetricKeyAlgorithm) as [string, ...string[]]
|
||||||
).options;
|
).options;
|
||||||
|
|
||||||
export enum SigningAlgorithm {
|
export enum SigningAlgorithm {
|
||||||
|
|||||||
@@ -4,22 +4,20 @@ import { InternalKmsSchema, KmsKeysSchema } from "@app/db/schemas";
|
|||||||
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import { KMS } from "@app/lib/api-docs";
|
import { KMS } from "@app/lib/api-docs";
|
||||||
import { getBase64SizeInBytes, isBase64 } from "@app/lib/base64";
|
import { getBase64SizeInBytes, isBase64 } from "@app/lib/base64";
|
||||||
import { AllowedEncryptionKeyAlgorithms, SymmetricKeyEncryptDecrypt } from "@app/lib/crypto/cipher";
|
import { AllowedEncryptionKeyAlgorithms, SymmetricKeyAlgorithm } from "@app/lib/crypto/cipher";
|
||||||
import { AsymmetricKeySignVerify, SigningAlgorithm } from "@app/lib/crypto/sign";
|
import { AsymmetricKeyAlgorithm, SigningAlgorithm } from "@app/lib/crypto/sign";
|
||||||
import { OrderByDirection } from "@app/lib/types";
|
import { OrderByDirection } from "@app/lib/types";
|
||||||
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||||
import { slugSchema } from "@app/server/lib/schemas";
|
import { slugSchema } from "@app/server/lib/schemas";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
import { CmekOrderBy, TCmekKeyEncryptionAlgorithm } from "@app/services/cmek/cmek-types";
|
import { CmekOrderBy, TCmekKeyEncryptionAlgorithm } from "@app/services/cmek/cmek-types";
|
||||||
import { KmsKeyIntent } from "@app/services/kms/kms-types";
|
import { KmsKeyUsage } from "@app/services/kms/kms-types";
|
||||||
|
|
||||||
const keyNameSchema = slugSchema({ min: 1, max: 32, field: "Name" });
|
const keyNameSchema = slugSchema({ min: 1, max: 32, field: "Name" });
|
||||||
const keyDescriptionSchema = z.string().trim().max(500).optional();
|
const keyDescriptionSchema = z.string().trim().max(500).optional();
|
||||||
|
|
||||||
const CmekSchema = KmsKeysSchema.merge(
|
const CmekSchema = KmsKeysSchema.merge(InternalKmsSchema.pick({ version: true, encryptionAlgorithm: true })).omit({
|
||||||
InternalKmsSchema.pick({ version: true, encryptionAlgorithm: true, type: true })
|
|
||||||
).omit({
|
|
||||||
isReserved: true
|
isReserved: true
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -54,37 +52,37 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => {
|
|||||||
projectId: z.string().describe(KMS.CREATE_KEY.projectId),
|
projectId: z.string().describe(KMS.CREATE_KEY.projectId),
|
||||||
name: keyNameSchema.describe(KMS.CREATE_KEY.name),
|
name: keyNameSchema.describe(KMS.CREATE_KEY.name),
|
||||||
description: keyDescriptionSchema.describe(KMS.CREATE_KEY.description),
|
description: keyDescriptionSchema.describe(KMS.CREATE_KEY.description),
|
||||||
type: z
|
keyUsage: z
|
||||||
.nativeEnum(KmsKeyIntent)
|
.nativeEnum(KmsKeyUsage)
|
||||||
.optional()
|
.optional()
|
||||||
.default(KmsKeyIntent.ENCRYPT_DECRYPT)
|
.default(KmsKeyUsage.ENCRYPT_DECRYPT)
|
||||||
.describe(KMS.CREATE_KEY.type),
|
.describe(KMS.CREATE_KEY.type),
|
||||||
encryptionAlgorithm: z
|
encryptionAlgorithm: z
|
||||||
.enum(AllowedEncryptionKeyAlgorithms)
|
.enum(AllowedEncryptionKeyAlgorithms)
|
||||||
.optional()
|
.optional()
|
||||||
.default(SymmetricKeyEncryptDecrypt.AES_GCM_256)
|
.default(SymmetricKeyAlgorithm.AES_GCM_256)
|
||||||
.describe(KMS.CREATE_KEY.encryptionAlgorithm)
|
.describe(KMS.CREATE_KEY.encryptionAlgorithm)
|
||||||
})
|
})
|
||||||
.superRefine((data, ctx) => {
|
.superRefine((data, ctx) => {
|
||||||
if (
|
if (
|
||||||
data.type === KmsKeyIntent.ENCRYPT_DECRYPT &&
|
data.keyUsage === KmsKeyUsage.ENCRYPT_DECRYPT &&
|
||||||
!Object.values(SymmetricKeyEncryptDecrypt).includes(data.encryptionAlgorithm as SymmetricKeyEncryptDecrypt)
|
!Object.values(SymmetricKeyAlgorithm).includes(data.encryptionAlgorithm as SymmetricKeyAlgorithm)
|
||||||
) {
|
) {
|
||||||
ctx.addIssue({
|
ctx.addIssue({
|
||||||
code: z.ZodIssueCode.custom,
|
code: z.ZodIssueCode.custom,
|
||||||
message: `encryptionAlgorithm must be a valid symmetric encryption algorithm. Valid options are: ${Object.values(
|
message: `encryptionAlgorithm must be a valid symmetric encryption algorithm. Valid options are: ${Object.values(
|
||||||
SymmetricKeyEncryptDecrypt
|
SymmetricKeyAlgorithm
|
||||||
).join(", ")}`
|
).join(", ")}`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
data.type === KmsKeyIntent.SIGN_VERIFY &&
|
data.keyUsage === KmsKeyUsage.SIGN_VERIFY &&
|
||||||
!Object.values(AsymmetricKeySignVerify).includes(data.encryptionAlgorithm as AsymmetricKeySignVerify)
|
!Object.values(AsymmetricKeyAlgorithm).includes(data.encryptionAlgorithm as AsymmetricKeyAlgorithm)
|
||||||
) {
|
) {
|
||||||
ctx.addIssue({
|
ctx.addIssue({
|
||||||
code: z.ZodIssueCode.custom,
|
code: z.ZodIssueCode.custom,
|
||||||
message: `encryptionAlgorithm must be a valid asymmetric sign-verify algorithm. Valid options are: ${Object.values(
|
message: `encryptionAlgorithm must be a valid asymmetric sign-verify algorithm. Valid options are: ${Object.values(
|
||||||
AsymmetricKeySignVerify
|
AsymmetricKeyAlgorithm
|
||||||
).join(", ")}`
|
).join(", ")}`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -98,7 +96,7 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => {
|
|||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const {
|
const {
|
||||||
body: { projectId, name, description, encryptionAlgorithm, type },
|
body: { projectId, name, description, encryptionAlgorithm, keyUsage },
|
||||||
permission
|
permission
|
||||||
} = req;
|
} = req;
|
||||||
|
|
||||||
@@ -109,7 +107,7 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => {
|
|||||||
name,
|
name,
|
||||||
description,
|
description,
|
||||||
encryptionAlgorithm: encryptionAlgorithm as TCmekKeyEncryptionAlgorithm,
|
encryptionAlgorithm: encryptionAlgorithm as TCmekKeyEncryptionAlgorithm,
|
||||||
type
|
keyUsage
|
||||||
},
|
},
|
||||||
permission
|
permission
|
||||||
);
|
);
|
||||||
@@ -167,7 +165,7 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => {
|
|||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: permission.orgId,
|
projectId: cmek.projectId!,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.UPDATE_CMEK,
|
type: EventType.UPDATE_CMEK,
|
||||||
metadata: {
|
metadata: {
|
||||||
@@ -210,7 +208,7 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => {
|
|||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: permission.orgId,
|
projectId: cmek.projectId!,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.DELETE_CMEK,
|
type: EventType.DELETE_CMEK,
|
||||||
metadata: {
|
metadata: {
|
||||||
@@ -390,11 +388,11 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => {
|
|||||||
permission
|
permission
|
||||||
} = req;
|
} = req;
|
||||||
|
|
||||||
const ciphertext = await server.services.cmek.cmekEncrypt({ keyId, plaintext }, permission);
|
const { ciphertext, projectId } = await server.services.cmek.cmekEncrypt({ keyId, plaintext }, permission);
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: permission.orgId,
|
projectId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.CMEK_ENCRYPT,
|
type: EventType.CMEK_ENCRYPT,
|
||||||
metadata: {
|
metadata: {
|
||||||
@@ -431,11 +429,11 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => {
|
|||||||
permission
|
permission
|
||||||
} = req;
|
} = req;
|
||||||
|
|
||||||
const publicKey = await server.services.cmek.getPublicKey({ keyId }, permission);
|
const { publicKey, projectId } = await server.services.cmek.getPublicKey({ keyId }, permission);
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: permission.orgId,
|
projectId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.CMEK_GET_PUBLIC_KEY,
|
type: EventType.CMEK_GET_PUBLIC_KEY,
|
||||||
metadata: {
|
metadata: {
|
||||||
@@ -444,7 +442,7 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return publicKey;
|
return { publicKey };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -469,11 +467,14 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => {
|
|||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const { keyId } = req.params;
|
const { keyId } = req.params;
|
||||||
|
|
||||||
const result = await server.services.cmek.listSigningAlgorithms({ keyId }, req.permission);
|
const { signingAlgorithms, projectId } = await server.services.cmek.listSigningAlgorithms(
|
||||||
|
{ keyId },
|
||||||
|
req.permission
|
||||||
|
);
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: req.permission.orgId,
|
projectId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.CMEK_LIST_SIGNING_ALGORITHMS,
|
type: EventType.CMEK_LIST_SIGNING_ALGORITHMS,
|
||||||
metadata: {
|
metadata: {
|
||||||
@@ -482,7 +483,7 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return result;
|
return { signingAlgorithms };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -527,11 +528,14 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => {
|
|||||||
permission
|
permission
|
||||||
} = req;
|
} = req;
|
||||||
|
|
||||||
const result = await server.services.cmek.cmekSign({ keyId: inputKeyId, data, signingAlgorithm }, permission);
|
const { projectId, ...result } = await server.services.cmek.cmekSign(
|
||||||
|
{ keyId: inputKeyId, data, signingAlgorithm },
|
||||||
|
permission
|
||||||
|
);
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: permission.orgId,
|
projectId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.CMEK_SIGN,
|
type: EventType.CMEK_SIGN,
|
||||||
metadata: {
|
metadata: {
|
||||||
@@ -597,11 +601,14 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => {
|
|||||||
permission
|
permission
|
||||||
} = req;
|
} = req;
|
||||||
|
|
||||||
const result = await server.services.cmek.cmekVerify({ keyId, data, signature, signingAlgorithm }, permission);
|
const { projectId, ...result } = await server.services.cmek.cmekVerify(
|
||||||
|
{ keyId, data, signature, signingAlgorithm },
|
||||||
|
permission
|
||||||
|
);
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: permission.orgId,
|
projectId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.CMEK_VERIFY,
|
type: EventType.CMEK_VERIFY,
|
||||||
metadata: {
|
metadata: {
|
||||||
@@ -645,11 +652,11 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => {
|
|||||||
permission
|
permission
|
||||||
} = req;
|
} = req;
|
||||||
|
|
||||||
const plaintext = await server.services.cmek.cmekDecrypt({ keyId, ciphertext }, permission);
|
const { plaintext, projectId } = await server.services.cmek.cmekDecrypt({ keyId, ciphertext }, permission);
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: permission.orgId,
|
projectId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.CMEK_DECRYPT,
|
type: EventType.CMEK_DECRYPT,
|
||||||
metadata: {
|
metadata: {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import {
|
|||||||
import { TKmsKeyDALFactory } from "@app/services/kms/kms-key-dal";
|
import { TKmsKeyDALFactory } from "@app/services/kms/kms-key-dal";
|
||||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||||
|
|
||||||
import { KmsKeyIntent } from "../kms/kms-types";
|
import { KmsKeyUsage } from "../kms/kms-types";
|
||||||
import { TProjectDALFactory } from "../project/project-dal";
|
import { TProjectDALFactory } from "../project/project-dal";
|
||||||
|
|
||||||
type TCmekServiceFactoryDep = {
|
type TCmekServiceFactoryDep = {
|
||||||
@@ -228,7 +228,10 @@ export const cmekServiceFactory = ({ kmsService, kmsDAL, permissionService, proj
|
|||||||
|
|
||||||
const { cipherTextBlob } = await encrypt({ plainText: Buffer.from(plaintext, "base64") });
|
const { cipherTextBlob } = await encrypt({ plainText: Buffer.from(plaintext, "base64") });
|
||||||
|
|
||||||
return cipherTextBlob.toString("base64");
|
return {
|
||||||
|
ciphertext: cipherTextBlob.toString("base64"),
|
||||||
|
projectId: key.projectId
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const listSigningAlgorithms = async ({ keyId }: TCmekListSigningAlgorithmsDTO, actor: OrgServiceActor) => {
|
const listSigningAlgorithms = async ({ keyId }: TCmekListSigningAlgorithmsDTO, actor: OrgServiceActor) => {
|
||||||
@@ -249,7 +252,7 @@ export const cmekServiceFactory = ({ kmsService, kmsDAL, permissionService, proj
|
|||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionCmekActions.Read, ProjectPermissionSub.Cmek);
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionCmekActions.Read, ProjectPermissionSub.Cmek);
|
||||||
|
|
||||||
if (key.type !== KmsKeyIntent.SIGN_VERIFY) {
|
if (key.keyUsage !== KmsKeyUsage.SIGN_VERIFY) {
|
||||||
throw new BadRequestError({ message: `Key with ID '${keyId}' is not intended for signing` });
|
throw new BadRequestError({ message: `Key with ID '${keyId}' is not intended for signing` });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,7 +279,7 @@ export const cmekServiceFactory = ({ kmsService, kmsDAL, permissionService, proj
|
|||||||
throw new BadRequestError({ message: `Unsupported encryption algorithm: ${encryptionAlgorithm}` });
|
throw new BadRequestError({ message: `Unsupported encryption algorithm: ${encryptionAlgorithm}` });
|
||||||
}
|
}
|
||||||
|
|
||||||
return { signingAlgorithms: selectedAlgorithm.signingAlgorithms };
|
return { signingAlgorithms: selectedAlgorithm.signingAlgorithms, projectId: key.projectId };
|
||||||
};
|
};
|
||||||
|
|
||||||
const getPublicKey = async ({ keyId }: TCmekGetPublicKeyDTO, actor: OrgServiceActor) => {
|
const getPublicKey = async ({ keyId }: TCmekGetPublicKeyDTO, actor: OrgServiceActor) => {
|
||||||
@@ -299,7 +302,7 @@ export const cmekServiceFactory = ({ kmsService, kmsDAL, permissionService, proj
|
|||||||
|
|
||||||
const publicKey = await kmsService.getPublicKey({ kmsId: keyId });
|
const publicKey = await kmsService.getPublicKey({ kmsId: keyId });
|
||||||
|
|
||||||
return { publicKey };
|
return { publicKey, projectId: key.projectId };
|
||||||
};
|
};
|
||||||
|
|
||||||
const cmekSign = async ({ keyId, data, signingAlgorithm }: TCmekSignDTO, actor: OrgServiceActor) => {
|
const cmekSign = async ({ keyId, data, signingAlgorithm }: TCmekSignDTO, actor: OrgServiceActor) => {
|
||||||
@@ -329,6 +332,7 @@ export const cmekServiceFactory = ({ kmsService, kmsDAL, permissionService, proj
|
|||||||
return {
|
return {
|
||||||
signature: signature.toString("base64"),
|
signature: signature.toString("base64"),
|
||||||
keyId: key.id,
|
keyId: key.id,
|
||||||
|
projectId: key.projectId,
|
||||||
signingAlgorithm: algorithm
|
signingAlgorithm: algorithm
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -363,6 +367,7 @@ export const cmekServiceFactory = ({ kmsService, kmsDAL, permissionService, proj
|
|||||||
return {
|
return {
|
||||||
signatureValid,
|
signatureValid,
|
||||||
keyId: key.id,
|
keyId: key.id,
|
||||||
|
projectId: key.projectId,
|
||||||
signingAlgorithm: algorithm
|
signingAlgorithm: algorithm
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -391,7 +396,10 @@ export const cmekServiceFactory = ({ kmsService, kmsDAL, permissionService, proj
|
|||||||
|
|
||||||
const plaintextBlob = await decrypt({ cipherTextBlob: Buffer.from(ciphertext, "base64") });
|
const plaintextBlob = await decrypt({ cipherTextBlob: Buffer.from(ciphertext, "base64") });
|
||||||
|
|
||||||
return plaintextBlob.toString("base64");
|
return {
|
||||||
|
plaintext: plaintextBlob.toString("base64"),
|
||||||
|
projectId: key.projectId
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { SymmetricKeyEncryptDecrypt } from "@app/lib/crypto/cipher";
|
import { SymmetricKeyAlgorithm } from "@app/lib/crypto/cipher";
|
||||||
import { AsymmetricKeySignVerify, SigningAlgorithm } from "@app/lib/crypto/sign";
|
import { AsymmetricKeyAlgorithm, SigningAlgorithm } from "@app/lib/crypto/sign";
|
||||||
import { OrderByDirection } from "@app/lib/types";
|
import { OrderByDirection } from "@app/lib/types";
|
||||||
|
|
||||||
import { KmsKeyIntent } from "../kms/kms-types";
|
import { KmsKeyUsage } from "../kms/kms-types";
|
||||||
|
|
||||||
export type TCmekKeyEncryptionAlgorithm = SymmetricKeyEncryptDecrypt | AsymmetricKeySignVerify;
|
export type TCmekKeyEncryptionAlgorithm = SymmetricKeyAlgorithm | AsymmetricKeyAlgorithm;
|
||||||
|
|
||||||
export type TCreateCmekDTO = {
|
export type TCreateCmekDTO = {
|
||||||
orgId: string;
|
orgId: string;
|
||||||
@@ -12,7 +12,7 @@ export type TCreateCmekDTO = {
|
|||||||
name: string;
|
name: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
encryptionAlgorithm: TCmekKeyEncryptionAlgorithm;
|
encryptionAlgorithm: TCmekKeyEncryptionAlgorithm;
|
||||||
type: KmsKeyIntent;
|
keyUsage: KmsKeyUsage;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TUpdabteCmekByIdDTO = {
|
export type TUpdabteCmekByIdDTO = {
|
||||||
|
|||||||
@@ -1,36 +1,36 @@
|
|||||||
import { SymmetricKeyEncryptDecrypt } from "@app/lib/crypto/cipher";
|
import { SymmetricKeyAlgorithm } from "@app/lib/crypto/cipher";
|
||||||
import { AsymmetricKeySignVerify } from "@app/lib/crypto/sign";
|
import { AsymmetricKeyAlgorithm } from "@app/lib/crypto/sign";
|
||||||
import { BadRequestError } from "@app/lib/errors";
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
|
|
||||||
import { KmsKeyIntent } from "./kms-types";
|
import { KmsKeyUsage } from "./kms-types";
|
||||||
|
|
||||||
export const KMS_ROOT_CONFIG_UUID = "00000000-0000-0000-0000-000000000000";
|
export const KMS_ROOT_CONFIG_UUID = "00000000-0000-0000-0000-000000000000";
|
||||||
|
|
||||||
export const getByteLengthForSymmetricEncryptionAlgorithm = (encryptionAlgorithm: SymmetricKeyEncryptDecrypt) => {
|
export const getByteLengthForSymmetricEncryptionAlgorithm = (encryptionAlgorithm: SymmetricKeyAlgorithm) => {
|
||||||
switch (encryptionAlgorithm) {
|
switch (encryptionAlgorithm) {
|
||||||
case SymmetricKeyEncryptDecrypt.AES_GCM_128:
|
case SymmetricKeyAlgorithm.AES_GCM_128:
|
||||||
return 16;
|
return 16;
|
||||||
case SymmetricKeyEncryptDecrypt.AES_GCM_256:
|
case SymmetricKeyAlgorithm.AES_GCM_256:
|
||||||
default:
|
default:
|
||||||
return 32;
|
return 32;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const verifyKeyTypeAndAlgorithm = (
|
export const verifyKeyTypeAndAlgorithm = (
|
||||||
type: KmsKeyIntent,
|
keyUsage: KmsKeyUsage,
|
||||||
algorithm: SymmetricKeyEncryptDecrypt | AsymmetricKeySignVerify,
|
algorithm: SymmetricKeyAlgorithm | AsymmetricKeyAlgorithm,
|
||||||
extra?: {
|
extra?: {
|
||||||
forceType?: KmsKeyIntent;
|
forceType?: KmsKeyUsage;
|
||||||
}
|
}
|
||||||
) => {
|
) => {
|
||||||
if (extra?.forceType && type !== extra.forceType) {
|
if (extra?.forceType && keyUsage !== extra.forceType) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: `Unsupported key type, expected ${extra.forceType} but got ${type}`
|
message: `Unsupported key type, expected ${extra.forceType} but got ${keyUsage}`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === KmsKeyIntent.ENCRYPT_DECRYPT) {
|
if (keyUsage === KmsKeyUsage.ENCRYPT_DECRYPT) {
|
||||||
if (!Object.values(SymmetricKeyEncryptDecrypt).includes(algorithm as SymmetricKeyEncryptDecrypt)) {
|
if (!Object.values(SymmetricKeyAlgorithm).includes(algorithm as SymmetricKeyAlgorithm)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: `Unsupported encryption algorithm for encrypt/decrypt key: ${algorithm as string}`
|
message: `Unsupported encryption algorithm for encrypt/decrypt key: ${algorithm as string}`
|
||||||
});
|
});
|
||||||
@@ -39,8 +39,8 @@ export const verifyKeyTypeAndAlgorithm = (
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === KmsKeyIntent.SIGN_VERIFY) {
|
if (keyUsage === KmsKeyUsage.SIGN_VERIFY) {
|
||||||
if (!Object.values(AsymmetricKeySignVerify).includes(algorithm as AsymmetricKeySignVerify)) {
|
if (!Object.values(AsymmetricKeyAlgorithm).includes(algorithm as AsymmetricKeyAlgorithm)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: `Unsupported sign/verify algorithm for sign/verify key: ${algorithm as string}`
|
message: `Unsupported sign/verify algorithm for sign/verify key: ${algorithm as string}`
|
||||||
});
|
});
|
||||||
@@ -50,6 +50,6 @@ export const verifyKeyTypeAndAlgorithm = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: `Unsupported key type: ${type as string}`
|
message: `Unsupported key type: ${keyUsage as string}`
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ import { THsmServiceFactory } from "@app/ee/services/hsm/hsm-service";
|
|||||||
import { KeyStorePrefixes, PgSqlLock, TKeyStoreFactory } from "@app/keystore/keystore";
|
import { KeyStorePrefixes, PgSqlLock, TKeyStoreFactory } from "@app/keystore/keystore";
|
||||||
import { TEnvConfig } from "@app/lib/config/env";
|
import { TEnvConfig } from "@app/lib/config/env";
|
||||||
import { randomSecureBytes } from "@app/lib/crypto";
|
import { randomSecureBytes } from "@app/lib/crypto";
|
||||||
import { symmetricCipherService, SymmetricKeyEncryptDecrypt } from "@app/lib/crypto/cipher";
|
import { symmetricCipherService, SymmetricKeyAlgorithm } from "@app/lib/crypto/cipher";
|
||||||
import { generateHash } from "@app/lib/crypto/encryption";
|
import { generateHash } from "@app/lib/crypto/encryption";
|
||||||
import { AsymmetricKeySignVerify, signingService } from "@app/lib/crypto/sign";
|
import { AsymmetricKeyAlgorithm, signingService } from "@app/lib/crypto/sign";
|
||||||
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
|
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
|
||||||
import { logger } from "@app/lib/logger";
|
import { logger } from "@app/lib/logger";
|
||||||
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
||||||
@@ -36,7 +36,7 @@ import { TKmsKeyDALFactory } from "./kms-key-dal";
|
|||||||
import { TKmsRootConfigDALFactory } from "./kms-root-config-dal";
|
import { TKmsRootConfigDALFactory } from "./kms-root-config-dal";
|
||||||
import {
|
import {
|
||||||
KmsDataKey,
|
KmsDataKey,
|
||||||
KmsKeyIntent,
|
KmsKeyUsage,
|
||||||
KmsType,
|
KmsType,
|
||||||
RootKeyEncryptionStrategy,
|
RootKeyEncryptionStrategy,
|
||||||
TDecryptWithKeyDTO,
|
TDecryptWithKeyDTO,
|
||||||
@@ -94,21 +94,21 @@ export const kmsServiceFactory = ({
|
|||||||
tx,
|
tx,
|
||||||
name,
|
name,
|
||||||
projectId,
|
projectId,
|
||||||
encryptionAlgorithm = SymmetricKeyEncryptDecrypt.AES_GCM_256,
|
encryptionAlgorithm = SymmetricKeyAlgorithm.AES_GCM_256,
|
||||||
type = KmsKeyIntent.ENCRYPT_DECRYPT,
|
keyUsage = KmsKeyUsage.ENCRYPT_DECRYPT,
|
||||||
description
|
description
|
||||||
}: TGenerateKMSDTO) => {
|
}: TGenerateKMSDTO) => {
|
||||||
// daniel: ensure that the key type (sign/encrypt) and the encryption algorithm are compatible.
|
// daniel: ensure that the key type (sign/encrypt) and the encryption algorithm are compatible.
|
||||||
verifyKeyTypeAndAlgorithm(type, encryptionAlgorithm);
|
verifyKeyTypeAndAlgorithm(keyUsage, encryptionAlgorithm);
|
||||||
|
|
||||||
let kmsKeyMaterial: Buffer | null = null;
|
let kmsKeyMaterial: Buffer | null = null;
|
||||||
if (type === KmsKeyIntent.ENCRYPT_DECRYPT) {
|
if (keyUsage === KmsKeyUsage.ENCRYPT_DECRYPT) {
|
||||||
kmsKeyMaterial = randomSecureBytes(
|
kmsKeyMaterial = randomSecureBytes(
|
||||||
getByteLengthForSymmetricEncryptionAlgorithm(encryptionAlgorithm as SymmetricKeyEncryptDecrypt)
|
getByteLengthForSymmetricEncryptionAlgorithm(encryptionAlgorithm as SymmetricKeyAlgorithm)
|
||||||
);
|
);
|
||||||
} else if (type === KmsKeyIntent.SIGN_VERIFY) {
|
} else if (keyUsage === KmsKeyUsage.SIGN_VERIFY) {
|
||||||
const { generateAsymmetricPrivateKey, getPublicKeyFromPrivateKey } = signingService(
|
const { generateAsymmetricPrivateKey, getPublicKeyFromPrivateKey } = signingService(
|
||||||
encryptionAlgorithm as AsymmetricKeySignVerify
|
encryptionAlgorithm as AsymmetricKeyAlgorithm
|
||||||
);
|
);
|
||||||
kmsKeyMaterial = await generateAsymmetricPrivateKey();
|
kmsKeyMaterial = await generateAsymmetricPrivateKey();
|
||||||
|
|
||||||
@@ -118,18 +118,18 @@ export const kmsServiceFactory = ({
|
|||||||
|
|
||||||
if (!kmsKeyMaterial) {
|
if (!kmsKeyMaterial) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: `Invalid KMS key type. No key material was created for key type '${type}' using algorithm '${encryptionAlgorithm}'`
|
message: `Invalid KMS key type. No key material was created for key usage '${keyUsage}' using algorithm '${encryptionAlgorithm}'`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const cipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
|
const cipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
|
||||||
const encryptedKeyMaterial = cipher.encrypt(kmsKeyMaterial, ROOT_ENCRYPTION_KEY);
|
const encryptedKeyMaterial = cipher.encrypt(kmsKeyMaterial, ROOT_ENCRYPTION_KEY);
|
||||||
const sanitizedName = name ? slugify(name) : slugify(alphaNumericNanoId(8).toLowerCase());
|
const sanitizedName = name ? slugify(name) : slugify(alphaNumericNanoId(8).toLowerCase());
|
||||||
const dbQuery = async (db: Knex) => {
|
const dbQuery = async (db: Knex) => {
|
||||||
const kmsDoc = await kmsDAL.create(
|
const kmsDoc = await kmsDAL.create(
|
||||||
{
|
{
|
||||||
name: sanitizedName,
|
name: sanitizedName,
|
||||||
type,
|
keyUsage,
|
||||||
orgId,
|
orgId,
|
||||||
isReserved,
|
isReserved,
|
||||||
projectId,
|
projectId,
|
||||||
@@ -169,7 +169,7 @@ export const kmsServiceFactory = ({
|
|||||||
*/
|
*/
|
||||||
const encryptWithInputKey = async ({ key }: Omit<TEncryptionWithKeyDTO, "plainText">) => {
|
const encryptWithInputKey = async ({ key }: Omit<TEncryptionWithKeyDTO, "plainText">) => {
|
||||||
// akhilmhdh: as more encryption are added do a check here on kmsDoc.encryptionAlgorithm
|
// akhilmhdh: as more encryption are added do a check here on kmsDoc.encryptionAlgorithm
|
||||||
const cipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
|
const cipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
|
||||||
return ({ plainText }: Pick<TEncryptWithKmsDTO, "plainText">) => {
|
return ({ plainText }: Pick<TEncryptWithKmsDTO, "plainText">) => {
|
||||||
const encryptedPlainTextBlob = cipher.encrypt(plainText, key);
|
const encryptedPlainTextBlob = cipher.encrypt(plainText, key);
|
||||||
// Buffer#1 encrypted text + Buffer#2 version number
|
// Buffer#1 encrypted text + Buffer#2 version number
|
||||||
@@ -184,7 +184,7 @@ export const kmsServiceFactory = ({
|
|||||||
* This can be even later exposed directly as api for encryption as function
|
* This can be even later exposed directly as api for encryption as function
|
||||||
*/
|
*/
|
||||||
const decryptWithInputKey = async ({ key }: Omit<TDecryptWithKeyDTO, "cipherTextBlob">) => {
|
const decryptWithInputKey = async ({ key }: Omit<TDecryptWithKeyDTO, "cipherTextBlob">) => {
|
||||||
const cipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
|
const cipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
|
||||||
|
|
||||||
return ({ cipherTextBlob: versionedCipherTextBlob }: Pick<TDecryptWithKeyDTO, "cipherTextBlob">) => {
|
return ({ cipherTextBlob: versionedCipherTextBlob }: Pick<TDecryptWithKeyDTO, "cipherTextBlob">) => {
|
||||||
const cipherTextBlob = versionedCipherTextBlob.subarray(0, -KMS_VERSION_BLOB_LENGTH);
|
const cipherTextBlob = versionedCipherTextBlob.subarray(0, -KMS_VERSION_BLOB_LENGTH);
|
||||||
@@ -262,7 +262,7 @@ export const kmsServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const encryptWithRootKey = () => {
|
const encryptWithRootKey = () => {
|
||||||
const cipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
|
const cipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
|
||||||
|
|
||||||
return (plainTextBuffer: Buffer) => {
|
return (plainTextBuffer: Buffer) => {
|
||||||
const encryptedBuffer = cipher.encrypt(plainTextBuffer, ROOT_ENCRYPTION_KEY);
|
const encryptedBuffer = cipher.encrypt(plainTextBuffer, ROOT_ENCRYPTION_KEY);
|
||||||
@@ -271,7 +271,7 @@ export const kmsServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const decryptWithRootKey = () => {
|
const decryptWithRootKey = () => {
|
||||||
const cipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
|
const cipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
|
||||||
|
|
||||||
return (cipherTextBuffer: Buffer) => {
|
return (cipherTextBuffer: Buffer) => {
|
||||||
return cipher.decrypt(cipherTextBuffer, ROOT_ENCRYPTION_KEY);
|
return cipher.decrypt(cipherTextBuffer, ROOT_ENCRYPTION_KEY);
|
||||||
@@ -290,9 +290,9 @@ export const kmsServiceFactory = ({
|
|||||||
throw new NotFoundError({ message: `KMS with ID '${kmsId}' not found` });
|
throw new NotFoundError({ message: `KMS with ID '${kmsId}' not found` });
|
||||||
}
|
}
|
||||||
|
|
||||||
const encryptionAlgorithm = kmsDoc.internalKms?.encryptionAlgorithm as SymmetricKeyEncryptDecrypt;
|
const encryptionAlgorithm = kmsDoc.internalKms?.encryptionAlgorithm as SymmetricKeyAlgorithm;
|
||||||
verifyKeyTypeAndAlgorithm(kmsDoc.type as KmsKeyIntent, encryptionAlgorithm, {
|
verifyKeyTypeAndAlgorithm(kmsDoc.keyUsage as KmsKeyUsage, encryptionAlgorithm, {
|
||||||
forceType: KmsKeyIntent.ENCRYPT_DECRYPT
|
forceType: KmsKeyUsage.ENCRYPT_DECRYPT
|
||||||
});
|
});
|
||||||
|
|
||||||
if (kmsDoc.externalKms) {
|
if (kmsDoc.externalKms) {
|
||||||
@@ -356,7 +356,7 @@ export const kmsServiceFactory = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// internal KMS
|
// internal KMS
|
||||||
const keyCipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
|
const keyCipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
|
||||||
const dataCipher = symmetricCipherService(encryptionAlgorithm);
|
const dataCipher = symmetricCipherService(encryptionAlgorithm);
|
||||||
const kmsKey = keyCipher.decrypt(kmsDoc.internalKms?.encryptedKey as Buffer, ROOT_ENCRYPTION_KEY);
|
const kmsKey = keyCipher.decrypt(kmsDoc.internalKms?.encryptedKey as Buffer, ROOT_ENCRYPTION_KEY);
|
||||||
|
|
||||||
@@ -385,22 +385,22 @@ export const kmsServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const keyCipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
|
const keyCipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
|
||||||
const kmsKey = keyCipher.decrypt(kmsDoc.internalKms?.encryptedKey as Buffer, ROOT_ENCRYPTION_KEY);
|
const kmsKey = keyCipher.decrypt(kmsDoc.internalKms?.encryptedKey as Buffer, ROOT_ENCRYPTION_KEY);
|
||||||
|
|
||||||
return kmsKey;
|
return kmsKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
const importKeyMaterial = async (
|
const importKeyMaterial = async (
|
||||||
{ key, algorithm, name, isReserved, projectId, orgId, type }: TImportKeyMaterialDTO,
|
{ key, algorithm, name, isReserved, projectId, orgId, keyUsage }: TImportKeyMaterialDTO,
|
||||||
tx?: Knex
|
tx?: Knex
|
||||||
) => {
|
) => {
|
||||||
// daniel: currently we only support imports for encrypt/decrypt keys
|
// daniel: currently we only support imports for encrypt/decrypt keys
|
||||||
verifyKeyTypeAndAlgorithm(type, algorithm, { forceType: KmsKeyIntent.ENCRYPT_DECRYPT });
|
verifyKeyTypeAndAlgorithm(keyUsage, algorithm, { forceType: KmsKeyUsage.ENCRYPT_DECRYPT });
|
||||||
|
|
||||||
const cipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
|
const cipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
|
||||||
|
|
||||||
const expectedByteLength = getByteLengthForSymmetricEncryptionAlgorithm(algorithm as SymmetricKeyEncryptDecrypt);
|
const expectedByteLength = getByteLengthForSymmetricEncryptionAlgorithm(algorithm as SymmetricKeyAlgorithm);
|
||||||
if (key.byteLength !== expectedByteLength) {
|
if (key.byteLength !== expectedByteLength) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: `Invalid key length for ${algorithm}. Expected ${expectedByteLength} bytes but got ${key.byteLength} bytes`
|
message: `Invalid key length for ${algorithm}. Expected ${expectedByteLength} bytes but got ${key.byteLength} bytes`
|
||||||
@@ -413,7 +413,7 @@ export const kmsServiceFactory = ({
|
|||||||
const kmsDoc = await kmsDAL.create(
|
const kmsDoc = await kmsDAL.create(
|
||||||
{
|
{
|
||||||
name: sanitizedName,
|
name: sanitizedName,
|
||||||
type: KmsKeyIntent.ENCRYPT_DECRYPT,
|
keyUsage: KmsKeyUsage.ENCRYPT_DECRYPT,
|
||||||
orgId,
|
orgId,
|
||||||
isReserved,
|
isReserved,
|
||||||
projectId
|
projectId
|
||||||
@@ -443,13 +443,13 @@ export const kmsServiceFactory = ({
|
|||||||
throw new NotFoundError({ message: `KMS with ID '${kmsId}' not found` });
|
throw new NotFoundError({ message: `KMS with ID '${kmsId}' not found` });
|
||||||
}
|
}
|
||||||
|
|
||||||
const encryptionAlgorithm = kmsDoc.internalKms?.encryptionAlgorithm as AsymmetricKeySignVerify;
|
const encryptionAlgorithm = kmsDoc.internalKms?.encryptionAlgorithm as AsymmetricKeyAlgorithm;
|
||||||
|
|
||||||
verifyKeyTypeAndAlgorithm(kmsDoc.type as KmsKeyIntent, encryptionAlgorithm, {
|
verifyKeyTypeAndAlgorithm(kmsDoc.keyUsage as KmsKeyUsage, encryptionAlgorithm, {
|
||||||
forceType: KmsKeyIntent.SIGN_VERIFY
|
forceType: KmsKeyUsage.SIGN_VERIFY
|
||||||
});
|
});
|
||||||
|
|
||||||
const keyCipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
|
const keyCipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
|
||||||
const kmsKey = keyCipher.decrypt(kmsDoc.internalKms?.encryptedKey as Buffer, ROOT_ENCRYPTION_KEY);
|
const kmsKey = keyCipher.decrypt(kmsDoc.internalKms?.encryptedKey as Buffer, ROOT_ENCRYPTION_KEY);
|
||||||
|
|
||||||
const publicKeyBuffer = signingService(encryptionAlgorithm).getPublicKeyFromPrivateKey(kmsKey);
|
const publicKeyBuffer = signingService(encryptionAlgorithm).getPublicKeyFromPrivateKey(kmsKey);
|
||||||
@@ -469,12 +469,12 @@ export const kmsServiceFactory = ({
|
|||||||
throw new NotFoundError({ message: `KMS with ID '${kmsId}' not found` });
|
throw new NotFoundError({ message: `KMS with ID '${kmsId}' not found` });
|
||||||
}
|
}
|
||||||
|
|
||||||
const encryptionAlgorithm = kmsDoc.internalKms?.encryptionAlgorithm as AsymmetricKeySignVerify;
|
const encryptionAlgorithm = kmsDoc.internalKms?.encryptionAlgorithm as AsymmetricKeyAlgorithm;
|
||||||
verifyKeyTypeAndAlgorithm(kmsDoc.type as KmsKeyIntent, encryptionAlgorithm, {
|
verifyKeyTypeAndAlgorithm(kmsDoc.keyUsage as KmsKeyUsage, encryptionAlgorithm, {
|
||||||
forceType: KmsKeyIntent.SIGN_VERIFY
|
forceType: KmsKeyUsage.SIGN_VERIFY
|
||||||
});
|
});
|
||||||
|
|
||||||
const keyCipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
|
const keyCipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
|
||||||
const { sign } = signingService(encryptionAlgorithm);
|
const { sign } = signingService(encryptionAlgorithm);
|
||||||
return ({ data, signingAlgorithm }: Pick<TSignWithKmsDTO, "data" | "signingAlgorithm">) => {
|
return ({ data, signingAlgorithm }: Pick<TSignWithKmsDTO, "data" | "signingAlgorithm">) => {
|
||||||
const kmsKey = keyCipher.decrypt(kmsDoc.internalKms?.encryptedKey as Buffer, ROOT_ENCRYPTION_KEY);
|
const kmsKey = keyCipher.decrypt(kmsDoc.internalKms?.encryptedKey as Buffer, ROOT_ENCRYPTION_KEY);
|
||||||
@@ -493,12 +493,12 @@ export const kmsServiceFactory = ({
|
|||||||
throw new NotFoundError({ message: `KMS with ID '${kmsId}' not found` });
|
throw new NotFoundError({ message: `KMS with ID '${kmsId}' not found` });
|
||||||
}
|
}
|
||||||
|
|
||||||
const encryptionAlgorithm = kmsDoc.internalKms?.encryptionAlgorithm as AsymmetricKeySignVerify;
|
const encryptionAlgorithm = kmsDoc.internalKms?.encryptionAlgorithm as AsymmetricKeyAlgorithm;
|
||||||
verifyKeyTypeAndAlgorithm(kmsDoc.type as KmsKeyIntent, encryptionAlgorithm, {
|
verifyKeyTypeAndAlgorithm(kmsDoc.keyUsage as KmsKeyUsage, encryptionAlgorithm, {
|
||||||
forceType: KmsKeyIntent.SIGN_VERIFY
|
forceType: KmsKeyUsage.SIGN_VERIFY
|
||||||
});
|
});
|
||||||
|
|
||||||
const keyCipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
|
const keyCipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
|
||||||
const { verify, getPublicKeyFromPrivateKey } = signingService(encryptionAlgorithm);
|
const { verify, getPublicKeyFromPrivateKey } = signingService(encryptionAlgorithm);
|
||||||
return ({ data, signature }: Pick<TVerifyWithKmsDTO, "data" | "signature">) => {
|
return ({ data, signature }: Pick<TVerifyWithKmsDTO, "data" | "signature">) => {
|
||||||
const kmsKey = keyCipher.decrypt(kmsDoc.internalKms?.encryptedKey as Buffer, ROOT_ENCRYPTION_KEY);
|
const kmsKey = keyCipher.decrypt(kmsDoc.internalKms?.encryptedKey as Buffer, ROOT_ENCRYPTION_KEY);
|
||||||
@@ -515,9 +515,9 @@ export const kmsServiceFactory = ({
|
|||||||
throw new NotFoundError({ message: `KMS with ID '${kmsId}' not found` });
|
throw new NotFoundError({ message: `KMS with ID '${kmsId}' not found` });
|
||||||
}
|
}
|
||||||
|
|
||||||
const encryptionAlgorithm = kmsDoc.internalKms?.encryptionAlgorithm as SymmetricKeyEncryptDecrypt;
|
const encryptionAlgorithm = kmsDoc.internalKms?.encryptionAlgorithm as SymmetricKeyAlgorithm;
|
||||||
verifyKeyTypeAndAlgorithm(kmsDoc.type as KmsKeyIntent, encryptionAlgorithm, {
|
verifyKeyTypeAndAlgorithm(kmsDoc.keyUsage as KmsKeyUsage, encryptionAlgorithm, {
|
||||||
forceType: KmsKeyIntent.ENCRYPT_DECRYPT
|
forceType: KmsKeyUsage.ENCRYPT_DECRYPT
|
||||||
});
|
});
|
||||||
|
|
||||||
if (kmsDoc.externalKms) {
|
if (kmsDoc.externalKms) {
|
||||||
@@ -575,7 +575,7 @@ export const kmsServiceFactory = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// internal KMS
|
// internal KMS
|
||||||
const keyCipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
|
const keyCipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
|
||||||
const dataCipher = symmetricCipherService(encryptionAlgorithm);
|
const dataCipher = symmetricCipherService(encryptionAlgorithm);
|
||||||
return ({ plainText }: Pick<TEncryptWithKmsDTO, "plainText">) => {
|
return ({ plainText }: Pick<TEncryptWithKmsDTO, "plainText">) => {
|
||||||
const kmsKey = keyCipher.decrypt(kmsDoc.internalKms?.encryptedKey as Buffer, ROOT_ENCRYPTION_KEY);
|
const kmsKey = keyCipher.decrypt(kmsDoc.internalKms?.encryptedKey as Buffer, ROOT_ENCRYPTION_KEY);
|
||||||
@@ -850,7 +850,7 @@ export const kmsServiceFactory = ({
|
|||||||
|
|
||||||
// case 2: root key is encrypted with software encryption
|
// case 2: root key is encrypted with software encryption
|
||||||
if (kmsRootConfig.encryptionStrategy === RootKeyEncryptionStrategy.Software) {
|
if (kmsRootConfig.encryptionStrategy === RootKeyEncryptionStrategy.Software) {
|
||||||
const cipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
|
const cipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
|
||||||
const encryptionKeyBuffer = $getBasicEncryptionKey();
|
const encryptionKeyBuffer = $getBasicEncryptionKey();
|
||||||
|
|
||||||
return cipher.decrypt(kmsRootConfig.encryptedRootKey, encryptionKeyBuffer);
|
return cipher.decrypt(kmsRootConfig.encryptedRootKey, encryptionKeyBuffer);
|
||||||
@@ -870,7 +870,7 @@ export const kmsServiceFactory = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (strategy === RootKeyEncryptionStrategy.Software) {
|
if (strategy === RootKeyEncryptionStrategy.Software) {
|
||||||
const cipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
|
const cipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
|
||||||
const encryptionKeyBuffer = $getBasicEncryptionKey();
|
const encryptionKeyBuffer = $getBasicEncryptionKey();
|
||||||
|
|
||||||
return cipher.encrypt(plainKeyBuffer, encryptionKeyBuffer);
|
return cipher.encrypt(plainKeyBuffer, encryptionKeyBuffer);
|
||||||
@@ -886,7 +886,7 @@ export const kmsServiceFactory = ({
|
|||||||
const createCipherPairWithDataKey = async (encryptionContext: TEncryptWithKmsDataKeyDTO, trx?: Knex) => {
|
const createCipherPairWithDataKey = async (encryptionContext: TEncryptWithKmsDataKeyDTO, trx?: Knex) => {
|
||||||
const dataKey = await $getDataKey(encryptionContext, trx);
|
const dataKey = await $getDataKey(encryptionContext, trx);
|
||||||
|
|
||||||
const cipher = symmetricCipherService(SymmetricKeyEncryptDecrypt.AES_GCM_256);
|
const cipher = symmetricCipherService(SymmetricKeyAlgorithm.AES_GCM_256);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
encryptor: ({ plainText }: Pick<TEncryptWithKmsDTO, "plainText">) => {
|
encryptor: ({ plainText }: Pick<TEncryptWithKmsDTO, "plainText">) => {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
|
|
||||||
import { SymmetricKeyEncryptDecrypt } from "@app/lib/crypto/cipher";
|
import { SymmetricKeyAlgorithm } from "@app/lib/crypto/cipher";
|
||||||
import { AsymmetricKeySignVerify, SigningAlgorithm } from "@app/lib/crypto/sign/types";
|
import { AsymmetricKeyAlgorithm, SigningAlgorithm } from "@app/lib/crypto/sign/types";
|
||||||
|
|
||||||
export enum KmsDataKey {
|
export enum KmsDataKey {
|
||||||
Organization,
|
Organization,
|
||||||
@@ -14,7 +14,7 @@ export enum KmsType {
|
|||||||
Internal = "internal"
|
Internal = "internal"
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum KmsKeyIntent {
|
export enum KmsKeyUsage {
|
||||||
ENCRYPT_DECRYPT = "encrypt-decrypt",
|
ENCRYPT_DECRYPT = "encrypt-decrypt",
|
||||||
SIGN_VERIFY = "sign-verify"
|
SIGN_VERIFY = "sign-verify"
|
||||||
}
|
}
|
||||||
@@ -31,8 +31,8 @@ export type TEncryptWithKmsDataKeyDTO =
|
|||||||
export type TGenerateKMSDTO = {
|
export type TGenerateKMSDTO = {
|
||||||
orgId: string;
|
orgId: string;
|
||||||
projectId?: string;
|
projectId?: string;
|
||||||
encryptionAlgorithm?: SymmetricKeyEncryptDecrypt | AsymmetricKeySignVerify;
|
encryptionAlgorithm?: SymmetricKeyAlgorithm | AsymmetricKeyAlgorithm;
|
||||||
type?: KmsKeyIntent;
|
keyUsage?: KmsKeyUsage;
|
||||||
isReserved?: boolean;
|
isReserved?: boolean;
|
||||||
name?: string;
|
name?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
@@ -91,10 +91,10 @@ export type TGetKeyMaterialDTO = {
|
|||||||
|
|
||||||
export type TImportKeyMaterialDTO = {
|
export type TImportKeyMaterialDTO = {
|
||||||
key: Buffer;
|
key: Buffer;
|
||||||
algorithm: SymmetricKeyEncryptDecrypt;
|
algorithm: SymmetricKeyAlgorithm;
|
||||||
name?: string;
|
name?: string;
|
||||||
isReserved: boolean;
|
isReserved: boolean;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
orgId: string;
|
orgId: string;
|
||||||
type: KmsKeyIntent;
|
keyUsage: KmsKeyUsage;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,21 +1,17 @@
|
|||||||
import {
|
import { AsymmetricKeyAlgorithm, KmsKeyUsage, SymmetricKeyAlgorithm } from "@app/hooks/api/cmeks";
|
||||||
AsymmetricKeySignVerify,
|
|
||||||
KmsKeyIntent,
|
|
||||||
SymmetricKeyEncryptDecrypt
|
|
||||||
} from "@app/hooks/api/cmeks";
|
|
||||||
|
|
||||||
export const kmsKeyUsageOptions: Record<
|
export const kmsKeyUsageOptions: Record<
|
||||||
KmsKeyIntent,
|
KmsKeyUsage,
|
||||||
{
|
{
|
||||||
label: string;
|
label: string;
|
||||||
tooltip: string;
|
tooltip: string;
|
||||||
}
|
}
|
||||||
> = {
|
> = {
|
||||||
[KmsKeyIntent.ENCRYPT_DECRYPT]: {
|
[KmsKeyUsage.ENCRYPT_DECRYPT]: {
|
||||||
label: "Encrypt/Decrypt",
|
label: "Encrypt/Decrypt",
|
||||||
tooltip: "Use the key only to encrypt and decrypt data."
|
tooltip: "Use the key only to encrypt and decrypt data."
|
||||||
},
|
},
|
||||||
[KmsKeyIntent.SIGN_VERIFY]: {
|
[KmsKeyUsage.SIGN_VERIFY]: {
|
||||||
label: "Sign/Verify",
|
label: "Sign/Verify",
|
||||||
tooltip:
|
tooltip:
|
||||||
"Key pairs for digital signing. Uses the private key for signing and the public key for verification."
|
"Key pairs for digital signing. Uses the private key for signing and the public key for verification."
|
||||||
@@ -23,9 +19,9 @@ export const kmsKeyUsageOptions: Record<
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const keyUsageDefaultOption: Record<
|
export const keyUsageDefaultOption: Record<
|
||||||
KmsKeyIntent,
|
KmsKeyUsage,
|
||||||
SymmetricKeyEncryptDecrypt | AsymmetricKeySignVerify
|
SymmetricKeyAlgorithm | AsymmetricKeyAlgorithm
|
||||||
> = {
|
> = {
|
||||||
[KmsKeyIntent.ENCRYPT_DECRYPT]: SymmetricKeyEncryptDecrypt.AES_GCM_256,
|
[KmsKeyUsage.ENCRYPT_DECRYPT]: SymmetricKeyAlgorithm.AES_GCM_256,
|
||||||
[KmsKeyIntent.SIGN_VERIFY]: AsymmetricKeySignVerify.RSA_4096
|
[KmsKeyUsage.SIGN_VERIFY]: AsymmetricKeyAlgorithm.RSA_4096
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,17 +2,17 @@ import { z } from "zod";
|
|||||||
|
|
||||||
import { OrderByDirection } from "@app/hooks/api/generic/types";
|
import { OrderByDirection } from "@app/hooks/api/generic/types";
|
||||||
|
|
||||||
export enum KmsKeyIntent {
|
export enum KmsKeyUsage {
|
||||||
ENCRYPT_DECRYPT = "encrypt-decrypt",
|
ENCRYPT_DECRYPT = "encrypt-decrypt",
|
||||||
SIGN_VERIFY = "sign-verify"
|
SIGN_VERIFY = "sign-verify"
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TCmek = {
|
export type TCmek = {
|
||||||
id: string;
|
id: string;
|
||||||
type: KmsKeyIntent;
|
keyUsage: KmsKeyUsage;
|
||||||
name: string;
|
name: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
encryptionAlgorithm: AsymmetricKeySignVerify | SymmetricKeyEncryptDecrypt;
|
encryptionAlgorithm: AsymmetricKeyAlgorithm | SymmetricKeyAlgorithm;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
isDisabled: boolean;
|
isDisabled: boolean;
|
||||||
isReserved: boolean;
|
isReserved: boolean;
|
||||||
@@ -25,7 +25,7 @@ export type TCmek = {
|
|||||||
type ProjectRef = { projectId: string };
|
type ProjectRef = { projectId: string };
|
||||||
type KeyRef = { keyId: string };
|
type KeyRef = { keyId: string };
|
||||||
|
|
||||||
export type TCreateCmek = Pick<TCmek, "name" | "description" | "encryptionAlgorithm" | "type"> &
|
export type TCreateCmek = Pick<TCmek, "name" | "description" | "encryptionAlgorithm" | "keyUsage"> &
|
||||||
ProjectRef;
|
ProjectRef;
|
||||||
export type TUpdateCmek = KeyRef &
|
export type TUpdateCmek = KeyRef &
|
||||||
Partial<Pick<TCmek, "name" | "description" | "isDisabled">> &
|
Partial<Pick<TCmek, "name" | "description" | "isDisabled">> &
|
||||||
@@ -80,20 +80,20 @@ export enum CmekOrderBy {
|
|||||||
Name = "name"
|
Name = "name"
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum AsymmetricKeySignVerify {
|
export enum AsymmetricKeyAlgorithm {
|
||||||
RSA_4096 = "rsa-4096",
|
RSA_4096 = "rsa-4096",
|
||||||
ECC_NIST_P256 = "ecc-nist-p256"
|
ECC_NIST_P256 = "ecc-nist-p256"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Supported symmetric encrypt/decrypt algorithms
|
// Supported symmetric encrypt/decrypt algorithms
|
||||||
export enum SymmetricKeyEncryptDecrypt {
|
export enum SymmetricKeyAlgorithm {
|
||||||
AES_GCM_256 = "aes-256-gcm",
|
AES_GCM_256 = "aes-256-gcm",
|
||||||
AES_GCM_128 = "aes-128-gcm"
|
AES_GCM_128 = "aes-128-gcm"
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AllowedEncryptionKeyAlgorithms = z.enum([
|
export const AllowedEncryptionKeyAlgorithms = z.enum([
|
||||||
...Object.values(SymmetricKeyEncryptDecrypt),
|
...Object.values(SymmetricKeyAlgorithm),
|
||||||
...Object.values(AsymmetricKeySignVerify)
|
...Object.values(AsymmetricKeyAlgorithm)
|
||||||
] as [string, ...string[]]).options;
|
] as [string, ...string[]]).options;
|
||||||
|
|
||||||
export enum SigningAlgorithm {
|
export enum SigningAlgorithm {
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ import { useWorkspace } from "@app/context";
|
|||||||
import { keyUsageDefaultOption, kmsKeyUsageOptions } from "@app/helpers/kms";
|
import { keyUsageDefaultOption, kmsKeyUsageOptions } from "@app/helpers/kms";
|
||||||
import {
|
import {
|
||||||
AllowedEncryptionKeyAlgorithms,
|
AllowedEncryptionKeyAlgorithms,
|
||||||
AsymmetricKeySignVerify,
|
AsymmetricKeyAlgorithm,
|
||||||
KmsKeyIntent,
|
KmsKeyUsage,
|
||||||
SymmetricKeyEncryptDecrypt,
|
SymmetricKeyAlgorithm,
|
||||||
TCmek,
|
TCmek,
|
||||||
useCreateCmek,
|
useCreateCmek,
|
||||||
useUpdateCmek
|
useUpdateCmek
|
||||||
@@ -31,7 +31,7 @@ const formSchema = z.object({
|
|||||||
name: slugSchema({ min: 1, max: 32, field: "Name" }),
|
name: slugSchema({ min: 1, max: 32, field: "Name" }),
|
||||||
description: z.string().max(500).optional(),
|
description: z.string().max(500).optional(),
|
||||||
encryptionAlgorithm: z.enum(AllowedEncryptionKeyAlgorithms),
|
encryptionAlgorithm: z.enum(AllowedEncryptionKeyAlgorithms),
|
||||||
type: z.nativeEnum(KmsKeyIntent)
|
keyUsage: z.nativeEnum(KmsKeyUsage)
|
||||||
});
|
});
|
||||||
|
|
||||||
export type FormData = z.infer<typeof formSchema>;
|
export type FormData = z.infer<typeof formSchema>;
|
||||||
@@ -65,22 +65,25 @@ const CmekForm = ({ onComplete, cmek }: FormProps) => {
|
|||||||
defaultValues: {
|
defaultValues: {
|
||||||
name: cmek?.name,
|
name: cmek?.name,
|
||||||
description: cmek?.description,
|
description: cmek?.description,
|
||||||
encryptionAlgorithm: SymmetricKeyEncryptDecrypt.AES_GCM_256,
|
encryptionAlgorithm: SymmetricKeyAlgorithm.AES_GCM_256,
|
||||||
type: KmsKeyIntent.ENCRYPT_DECRYPT
|
keyUsage: KmsKeyUsage.ENCRYPT_DECRYPT
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleCreateCmek = async ({ encryptionAlgorithm, name, description, type }: FormData) => {
|
const handleCreateCmek = async ({
|
||||||
|
encryptionAlgorithm,
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
keyUsage
|
||||||
|
}: FormData) => {
|
||||||
const mutation = isUpdate
|
const mutation = isUpdate
|
||||||
? updateCmek.mutateAsync({ keyId: cmek.id, projectId, name, description })
|
? updateCmek.mutateAsync({ keyId: cmek.id, projectId, name, description })
|
||||||
: createCmek.mutateAsync({
|
: createCmek.mutateAsync({
|
||||||
projectId,
|
projectId,
|
||||||
name,
|
name,
|
||||||
description,
|
description,
|
||||||
type,
|
keyUsage,
|
||||||
encryptionAlgorithm: encryptionAlgorithm as
|
encryptionAlgorithm: encryptionAlgorithm as AsymmetricKeyAlgorithm | SymmetricKeyAlgorithm
|
||||||
| AsymmetricKeySignVerify
|
|
||||||
| SymmetricKeyEncryptDecrypt
|
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -99,7 +102,7 @@ const CmekForm = ({ onComplete, cmek }: FormProps) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectedType = watch("type");
|
const selectedKeyUsage = watch("keyUsage");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit(handleCreateCmek)}>
|
<form onSubmit={handleSubmit(handleCreateCmek)}>
|
||||||
@@ -116,13 +119,13 @@ const CmekForm = ({ onComplete, cmek }: FormProps) => {
|
|||||||
<>
|
<>
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="type"
|
name="keyUsage"
|
||||||
render={({ field: { onChange, ...field }, fieldState: { error } }) => (
|
render={({ field: { onChange, ...field }, fieldState: { error } }) => (
|
||||||
<FormControl
|
<FormControl
|
||||||
className="w-full"
|
className="w-full"
|
||||||
tooltipText={
|
tooltipText={
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{Object.entries(KmsKeyIntent).map(([key, value]) => (
|
{Object.entries(KmsKeyUsage).map(([key, value]) => (
|
||||||
<div key={`key-usage-${key}`}>
|
<div key={`key-usage-${key}`}>
|
||||||
<p className="font-bold">{kmsKeyUsageOptions[value].label}</p>
|
<p className="font-bold">{kmsKeyUsageOptions[value].label}</p>
|
||||||
<p>{kmsKeyUsageOptions[value].tooltip}</p>
|
<p>{kmsKeyUsageOptions[value].tooltip}</p>
|
||||||
@@ -137,8 +140,8 @@ const CmekForm = ({ onComplete, cmek }: FormProps) => {
|
|||||||
<Select
|
<Select
|
||||||
defaultValue={field.value}
|
defaultValue={field.value}
|
||||||
onValueChange={(e) => {
|
onValueChange={(e) => {
|
||||||
if (keyUsageDefaultOption[e as KmsKeyIntent]) {
|
if (keyUsageDefaultOption[e as KmsKeyUsage]) {
|
||||||
setValue("encryptionAlgorithm", keyUsageDefaultOption[e as KmsKeyIntent], {
|
setValue("encryptionAlgorithm", keyUsageDefaultOption[e as KmsKeyUsage], {
|
||||||
shouldDirty: true,
|
shouldDirty: true,
|
||||||
shouldValidate: true
|
shouldValidate: true
|
||||||
});
|
});
|
||||||
@@ -148,7 +151,7 @@ const CmekForm = ({ onComplete, cmek }: FormProps) => {
|
|||||||
}}
|
}}
|
||||||
className="w-full"
|
className="w-full"
|
||||||
>
|
>
|
||||||
{Object.entries(KmsKeyIntent)?.map(([key, value]) => (
|
{Object.entries(KmsKeyUsage)?.map(([key, value]) => (
|
||||||
<SelectItem value={value} key={`key-usage-${key}`}>
|
<SelectItem value={value} key={`key-usage-${key}`}>
|
||||||
{kmsKeyUsageOptions[value].label}
|
{kmsKeyUsageOptions[value].label}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
@@ -176,14 +179,14 @@ const CmekForm = ({ onComplete, cmek }: FormProps) => {
|
|||||||
{Object.entries(AllowedEncryptionKeyAlgorithms)
|
{Object.entries(AllowedEncryptionKeyAlgorithms)
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
?.filter(([_, value]) => {
|
?.filter(([_, value]) => {
|
||||||
if (selectedType === KmsKeyIntent.ENCRYPT_DECRYPT) {
|
if (selectedKeyUsage === KmsKeyUsage.ENCRYPT_DECRYPT) {
|
||||||
return Object.values(SymmetricKeyEncryptDecrypt).includes(
|
return Object.values(SymmetricKeyAlgorithm).includes(
|
||||||
value as unknown as SymmetricKeyEncryptDecrypt
|
value as unknown as SymmetricKeyAlgorithm
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (selectedType === KmsKeyIntent.SIGN_VERIFY) {
|
if (selectedKeyUsage === KmsKeyUsage.SIGN_VERIFY) {
|
||||||
return Object.values(AsymmetricKeySignVerify).includes(
|
return Object.values(AsymmetricKeyAlgorithm).includes(
|
||||||
value as unknown as AsymmetricKeySignVerify
|
value as unknown as AsymmetricKeyAlgorithm
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ import {
|
|||||||
import { kmsKeyUsageOptions } from "@app/helpers/kms";
|
import { kmsKeyUsageOptions } from "@app/helpers/kms";
|
||||||
import { usePagination, usePopUp, useResetPageHelper, useTimedReset } from "@app/hooks";
|
import { usePagination, usePopUp, useResetPageHelper, useTimedReset } from "@app/hooks";
|
||||||
import { useGetCmeksByProjectId, useUpdateCmek } from "@app/hooks/api/cmeks";
|
import { useGetCmeksByProjectId, useUpdateCmek } from "@app/hooks/api/cmeks";
|
||||||
import { CmekOrderBy, KmsKeyIntent, TCmek } from "@app/hooks/api/cmeks/types";
|
import { CmekOrderBy, KmsKeyUsage, TCmek } from "@app/hooks/api/cmeks/types";
|
||||||
import { OrderByDirection } from "@app/hooks/api/generic/types";
|
import { OrderByDirection } from "@app/hooks/api/generic/types";
|
||||||
|
|
||||||
import { CmekDecryptModal } from "./CmekDecryptModal";
|
import { CmekDecryptModal } from "./CmekDecryptModal";
|
||||||
@@ -273,8 +273,15 @@ export const CmekTable = () => {
|
|||||||
{!isPending &&
|
{!isPending &&
|
||||||
keys.length > 0 &&
|
keys.length > 0 &&
|
||||||
keys.map((cmek) => {
|
keys.map((cmek) => {
|
||||||
const { name, id, version, description, encryptionAlgorithm, isDisabled, type } =
|
const {
|
||||||
cmek;
|
name,
|
||||||
|
id,
|
||||||
|
version,
|
||||||
|
description,
|
||||||
|
encryptionAlgorithm,
|
||||||
|
isDisabled,
|
||||||
|
keyUsage
|
||||||
|
} = cmek;
|
||||||
const { variant, label } = getStatusBadgeProps(isDisabled);
|
const { variant, label } = getStatusBadgeProps(isDisabled);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -314,8 +321,8 @@ export const CmekTable = () => {
|
|||||||
</Td>
|
</Td>
|
||||||
<Td>
|
<Td>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{kmsKeyUsageOptions[type].label}
|
{kmsKeyUsageOptions[keyUsage].label}
|
||||||
<Tooltip content={kmsKeyUsageOptions[type].tooltip}>
|
<Tooltip content={kmsKeyUsageOptions[keyUsage].tooltip}>
|
||||||
<FontAwesomeIcon icon={faInfoCircle} className="text-mineshaft-400" />
|
<FontAwesomeIcon icon={faInfoCircle} className="text-mineshaft-400" />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
@@ -339,7 +346,7 @@ export const CmekTable = () => {
|
|||||||
</IconButton>
|
</IconButton>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent className="min-w-[160px]">
|
<DropdownMenuContent className="min-w-[160px]">
|
||||||
{type === KmsKeyIntent.ENCRYPT_DECRYPT && (
|
{keyUsage === KmsKeyUsage.ENCRYPT_DECRYPT && (
|
||||||
<>
|
<>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
content={
|
content={
|
||||||
@@ -388,7 +395,7 @@ export const CmekTable = () => {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{type === KmsKeyIntent.SIGN_VERIFY && (
|
{keyUsage === KmsKeyUsage.SIGN_VERIFY && (
|
||||||
<>
|
<>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
content={
|
content={
|
||||||
|
|||||||
Reference in New Issue
Block a user