mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-06 21:27:10 +00:00
feat: kmip poc done
This commit is contained in:
@@ -153,7 +153,55 @@ export const registerKmipOperationRouter = async (server: FastifyZodProvider) =>
|
|||||||
|
|
||||||
server.route({
|
server.route({
|
||||||
method: "POST",
|
method: "POST",
|
||||||
url: "/delete",
|
url: "/get-attributes",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
description: "KMIP endpoint for getting attributes of managed object",
|
||||||
|
body: z.object({
|
||||||
|
id: z.string()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
id: z.string(),
|
||||||
|
algorithm: z.string(),
|
||||||
|
isActive: z.boolean(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handler: async (req) => {
|
||||||
|
const object = await server.services.kmipOperation.getAttributes({
|
||||||
|
...req.kmipUser,
|
||||||
|
id: req.body.id
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
projectId: req.kmipUser.projectId,
|
||||||
|
actor: {
|
||||||
|
type: ActorType.KMIP_CLIENT,
|
||||||
|
metadata: {
|
||||||
|
clientId: req.kmipUser.clientId,
|
||||||
|
name: req.kmipUser.name
|
||||||
|
}
|
||||||
|
},
|
||||||
|
event: {
|
||||||
|
type: EventType.KMIP_OPERATION_GET_ATTRIBUTES,
|
||||||
|
metadata: {
|
||||||
|
id: object.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "POST",
|
||||||
|
url: "/destroy",
|
||||||
config: {
|
config: {
|
||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
@@ -194,4 +242,193 @@ export const registerKmipOperationRouter = async (server: FastifyZodProvider) =>
|
|||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "POST",
|
||||||
|
url: "/activate",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
description: "KMIP endpoint for activating managed object",
|
||||||
|
body: z.object({
|
||||||
|
id: z.string()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
id: z.string(),
|
||||||
|
isActive: z.boolean()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handler: async (req) => {
|
||||||
|
const object = await server.services.kmipOperation.activate({
|
||||||
|
...req.kmipUser,
|
||||||
|
id: req.body.id
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
projectId: req.kmipUser.projectId,
|
||||||
|
actor: {
|
||||||
|
type: ActorType.KMIP_CLIENT,
|
||||||
|
metadata: {
|
||||||
|
clientId: req.kmipUser.clientId,
|
||||||
|
name: req.kmipUser.name
|
||||||
|
}
|
||||||
|
},
|
||||||
|
event: {
|
||||||
|
type: EventType.KMIP_OPERATION_ACTIVATE,
|
||||||
|
metadata: {
|
||||||
|
id: object.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "POST",
|
||||||
|
url: "/revoke",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
description: "KMIP endpoint for revoking managed object",
|
||||||
|
body: z.object({
|
||||||
|
id: z.string()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
id: z.string(),
|
||||||
|
updatedAt: z.date()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handler: async (req) => {
|
||||||
|
const object = await server.services.kmipOperation.revoke({
|
||||||
|
...req.kmipUser,
|
||||||
|
id: req.body.id
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
projectId: req.kmipUser.projectId,
|
||||||
|
actor: {
|
||||||
|
type: ActorType.KMIP_CLIENT,
|
||||||
|
metadata: {
|
||||||
|
clientId: req.kmipUser.clientId,
|
||||||
|
name: req.kmipUser.name
|
||||||
|
}
|
||||||
|
},
|
||||||
|
event: {
|
||||||
|
type: EventType.KMIP_OPERATION_REVOKE,
|
||||||
|
metadata: {
|
||||||
|
id: object.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "POST",
|
||||||
|
url: "/locate",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
description: "KMIP endpoint for locating managed objects",
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
objects: z
|
||||||
|
.object({
|
||||||
|
id: z.string(),
|
||||||
|
name: z.string(),
|
||||||
|
isActive: z.boolean(),
|
||||||
|
algorithm: z.string(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date()
|
||||||
|
})
|
||||||
|
.array()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handler: async (req) => {
|
||||||
|
const objects = await server.services.kmipOperation.locate({
|
||||||
|
...req.kmipUser
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
projectId: req.kmipUser.projectId,
|
||||||
|
actor: {
|
||||||
|
type: ActorType.KMIP_CLIENT,
|
||||||
|
metadata: {
|
||||||
|
clientId: req.kmipUser.clientId,
|
||||||
|
name: req.kmipUser.name
|
||||||
|
}
|
||||||
|
},
|
||||||
|
event: {
|
||||||
|
type: EventType.KMIP_OPERATION_LOCATE,
|
||||||
|
metadata: {
|
||||||
|
ids: objects.map((obj) => obj.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
objects
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "POST",
|
||||||
|
url: "/register",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
description: "KMIP endpoint for registering managed object",
|
||||||
|
body: z.object({
|
||||||
|
key: z.string(),
|
||||||
|
name: z.string(),
|
||||||
|
algorithm: z.nativeEnum(SymmetricEncryption)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
id: z.string()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handler: async (req) => {
|
||||||
|
const object = await server.services.kmipOperation.register({
|
||||||
|
...req.kmipUser,
|
||||||
|
...req.body
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
projectId: req.kmipUser.projectId,
|
||||||
|
actor: {
|
||||||
|
type: ActorType.KMIP_CLIENT,
|
||||||
|
metadata: {
|
||||||
|
clientId: req.kmipUser.clientId,
|
||||||
|
name: req.kmipUser.name
|
||||||
|
}
|
||||||
|
},
|
||||||
|
event: {
|
||||||
|
type: EventType.KMIP_OPERATION_REGISTER,
|
||||||
|
metadata: {
|
||||||
|
id: object.id,
|
||||||
|
algorithm: req.body.algorithm,
|
||||||
|
name: object.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -269,7 +269,12 @@ export enum EventType {
|
|||||||
CREATE_KMIP_CLIENT_CERTIFICATE = "create-kmip-client-certificate",
|
CREATE_KMIP_CLIENT_CERTIFICATE = "create-kmip-client-certificate",
|
||||||
KMIP_OPERATION_CREATE = "kmip-operation-create",
|
KMIP_OPERATION_CREATE = "kmip-operation-create",
|
||||||
KMIP_OPERATION_GET = "kmip-operation-get",
|
KMIP_OPERATION_GET = "kmip-operation-get",
|
||||||
KMIP_OPERATION_DELETE = "kmip-operation-delete"
|
KMIP_OPERATION_DELETE = "kmip-operation-delete",
|
||||||
|
KMIP_OPERATION_GET_ATTRIBUTES = "kmip-operation-get-attributes",
|
||||||
|
KMIP_OPERATION_ACTIVATE = "kmip-operation-activate",
|
||||||
|
KMIP_OPERATION_REVOKE = "kmip-operation-revoke",
|
||||||
|
KMIP_OPERATION_LOCATE = "kmip-operation-locate",
|
||||||
|
KMIP_OPERATION_REGISTER = "kmip-operation-register"
|
||||||
}
|
}
|
||||||
|
|
||||||
interface UserActorMetadata {
|
interface UserActorMetadata {
|
||||||
@@ -2165,6 +2170,43 @@ interface KmipOperationCreateEvent {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface KmipOperationGetAttributesEvent {
|
||||||
|
type: EventType.KMIP_OPERATION_GET_ATTRIBUTES;
|
||||||
|
metadata: {
|
||||||
|
id: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface KmipOperationActivateEvent {
|
||||||
|
type: EventType.KMIP_OPERATION_ACTIVATE;
|
||||||
|
metadata: {
|
||||||
|
id: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface KmipOperationRevokeEvent {
|
||||||
|
type: EventType.KMIP_OPERATION_REVOKE;
|
||||||
|
metadata: {
|
||||||
|
id: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface KmipOperationLocateEvent {
|
||||||
|
type: EventType.KMIP_OPERATION_LOCATE;
|
||||||
|
metadata: {
|
||||||
|
ids: string[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface KmipOperationRegisterEvent {
|
||||||
|
type: EventType.KMIP_OPERATION_REGISTER;
|
||||||
|
metadata: {
|
||||||
|
id: string;
|
||||||
|
algorithm: string;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export type Event =
|
export type Event =
|
||||||
| GetSecretsEvent
|
| GetSecretsEvent
|
||||||
| GetSecretEvent
|
| GetSecretEvent
|
||||||
@@ -2364,4 +2406,9 @@ export type Event =
|
|||||||
| CreateKmipClientCertificateEvent
|
| CreateKmipClientCertificateEvent
|
||||||
| KmipOperationGetEvent
|
| KmipOperationGetEvent
|
||||||
| KmipOperationDeleteEvent
|
| KmipOperationDeleteEvent
|
||||||
| KmipOperationCreateEvent;
|
| KmipOperationCreateEvent
|
||||||
|
| KmipOperationGetAttributesEvent
|
||||||
|
| KmipOperationActivateEvent
|
||||||
|
| KmipOperationRevokeEvent
|
||||||
|
| KmipOperationLocateEvent
|
||||||
|
| KmipOperationRegisterEvent;
|
||||||
|
|||||||
@@ -3,5 +3,9 @@ export enum KmipPermission {
|
|||||||
Locate = "locate",
|
Locate = "locate",
|
||||||
Check = "check",
|
Check = "check",
|
||||||
Get = "get",
|
Get = "get",
|
||||||
Delete = "delete"
|
GetAttributes = "get-attributes",
|
||||||
|
Activate = "activate",
|
||||||
|
Revoke = "revoke",
|
||||||
|
Delete = "delete",
|
||||||
|
Register = "register"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,15 @@ import { TProjectDALFactory } from "@app/services/project/project-dal";
|
|||||||
|
|
||||||
import { TKmipClientDALFactory } from "./kmip-client-dal";
|
import { TKmipClientDALFactory } from "./kmip-client-dal";
|
||||||
import { KmipPermission } from "./kmip-enum";
|
import { KmipPermission } from "./kmip-enum";
|
||||||
import { TKmipCreateDTO, TKmipDeleteDTO, TKmipGetDTO } from "./kmip-types";
|
import {
|
||||||
|
TKmipCreateDTO,
|
||||||
|
TKmipDeleteDTO,
|
||||||
|
TKmipGetAttributesDTO,
|
||||||
|
TKmipGetDTO,
|
||||||
|
TKmipLocateDTO,
|
||||||
|
TKmipRegisterDTO,
|
||||||
|
TKmipRevokeDTO
|
||||||
|
} from "./kmip-types";
|
||||||
|
|
||||||
type TKmipOperationServiceFactoryDep = {
|
type TKmipOperationServiceFactoryDep = {
|
||||||
kmsService: TKmsServiceFactory;
|
kmsService: TKmsServiceFactory;
|
||||||
@@ -143,13 +151,211 @@ export const kmipOperationServiceFactory = ({
|
|||||||
return {
|
return {
|
||||||
id: key.id,
|
id: key.id,
|
||||||
value: kmsKey.toString("base64"),
|
value: kmsKey.toString("base64"),
|
||||||
algorithm: completeKeyDetails.internalKms.encryptionAlgorithm
|
algorithm: completeKeyDetails.internalKms.encryptionAlgorithm,
|
||||||
|
isActive: !key.isDisabled,
|
||||||
|
createdAt: key.createdAt,
|
||||||
|
updatedAt: key.updatedAt
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const activate = async ({ projectId: preSplitProjectId, id, clientId }: TKmipGetDTO) => {
|
||||||
|
let projectId = preSplitProjectId;
|
||||||
|
const cmekProjectFromSplit = await projectDAL.getProjectFromSplitId(projectId, ProjectType.KMS);
|
||||||
|
|
||||||
|
if (cmekProjectFromSplit) {
|
||||||
|
projectId = cmekProjectFromSplit.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
const kmipClient = await kmipClientDAL.findOne({
|
||||||
|
id: clientId,
|
||||||
|
projectId
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!kmipClient.permissions?.includes(KmipPermission.Activate)) {
|
||||||
|
throw new ForbiddenRequestError({
|
||||||
|
message: "Client does not have sufficient permission to perform KMIP activate"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const key = await kmsDAL.findOne({
|
||||||
|
id,
|
||||||
|
projectId
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!key) {
|
||||||
|
throw new NotFoundError({ message: `Key with ID ${id} not found` });
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: key.id,
|
||||||
|
isActive: !key.isDisabled
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const revoke = async ({ projectId: preSplitProjectId, id, clientId }: TKmipRevokeDTO) => {
|
||||||
|
let projectId = preSplitProjectId;
|
||||||
|
const cmekProjectFromSplit = await projectDAL.getProjectFromSplitId(projectId, ProjectType.KMS);
|
||||||
|
|
||||||
|
if (cmekProjectFromSplit) {
|
||||||
|
projectId = cmekProjectFromSplit.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
const kmipClient = await kmipClientDAL.findOne({
|
||||||
|
id: clientId,
|
||||||
|
projectId
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!kmipClient.permissions?.includes(KmipPermission.Revoke)) {
|
||||||
|
throw new ForbiddenRequestError({
|
||||||
|
message: "Client does not have sufficient permission to perform KMIP revoke"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const key = await kmsDAL.findOne({
|
||||||
|
id,
|
||||||
|
projectId
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!key) {
|
||||||
|
throw new NotFoundError({ message: `Key with ID ${id} not found` });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key.isReserved) {
|
||||||
|
throw new BadRequestError({ message: "Cannot revoke reserved keys" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const completeKeyDetails = await kmsDAL.findByIdWithAssociatedKms(id);
|
||||||
|
|
||||||
|
if (!completeKeyDetails.internalKms) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Cannot revoke external keys"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const revokedKey = await kmsDAL.updateById(key.id, {
|
||||||
|
isDisabled: true
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: key.id,
|
||||||
|
updatedAt: revokedKey.updatedAt
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const getAttributes = async ({ projectId: preSplitProjectId, id, clientId }: TKmipGetAttributesDTO) => {
|
||||||
|
let projectId = preSplitProjectId;
|
||||||
|
const cmekProjectFromSplit = await projectDAL.getProjectFromSplitId(projectId, ProjectType.KMS);
|
||||||
|
|
||||||
|
if (cmekProjectFromSplit) {
|
||||||
|
projectId = cmekProjectFromSplit.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
const kmipClient = await kmipClientDAL.findOne({
|
||||||
|
id: clientId,
|
||||||
|
projectId
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!kmipClient.permissions?.includes(KmipPermission.GetAttributes)) {
|
||||||
|
throw new ForbiddenRequestError({
|
||||||
|
message: "Client does not have sufficient permission to perform KMIP get attributes"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const key = await kmsDAL.findOne({
|
||||||
|
id,
|
||||||
|
projectId
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!key) {
|
||||||
|
throw new NotFoundError({ message: `Key with ID ${id} not found` });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key.isReserved) {
|
||||||
|
throw new BadRequestError({ message: "Cannot get reserved keys" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const completeKeyDetails = await kmsDAL.findByIdWithAssociatedKms(id);
|
||||||
|
|
||||||
|
if (!completeKeyDetails.internalKms) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Cannot get external keys"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: key.id,
|
||||||
|
algorithm: completeKeyDetails.internalKms.encryptionAlgorithm,
|
||||||
|
isActive: !key.isDisabled,
|
||||||
|
createdAt: key.createdAt,
|
||||||
|
updatedAt: key.updatedAt
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const locate = async ({ projectId: preSplitProjectId, clientId }: TKmipLocateDTO) => {
|
||||||
|
let projectId = preSplitProjectId;
|
||||||
|
const cmekProjectFromSplit = await projectDAL.getProjectFromSplitId(projectId, ProjectType.KMS);
|
||||||
|
|
||||||
|
if (cmekProjectFromSplit) {
|
||||||
|
projectId = cmekProjectFromSplit.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
const kmipClient = await kmipClientDAL.findOne({
|
||||||
|
id: clientId,
|
||||||
|
projectId
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!kmipClient.permissions?.includes(KmipPermission.Locate)) {
|
||||||
|
throw new ForbiddenRequestError({
|
||||||
|
message: "Client does not have sufficient permission to perform KMIP locate"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const keys = await kmsDAL.findProjectCmeks(projectId);
|
||||||
|
|
||||||
|
return keys;
|
||||||
|
};
|
||||||
|
|
||||||
|
const register = async ({ projectId: preSplitProjectId, clientId, key, algorithm, name }: TKmipRegisterDTO) => {
|
||||||
|
let projectId = preSplitProjectId;
|
||||||
|
const cmekProjectFromSplit = await projectDAL.getProjectFromSplitId(projectId, ProjectType.KMS);
|
||||||
|
|
||||||
|
if (cmekProjectFromSplit) {
|
||||||
|
projectId = cmekProjectFromSplit.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
const kmipClient = await kmipClientDAL.findOne({
|
||||||
|
id: clientId,
|
||||||
|
projectId
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!kmipClient.permissions?.includes(KmipPermission.Register)) {
|
||||||
|
throw new ForbiddenRequestError({
|
||||||
|
message: "Client does not have sufficient permission to perform KMIP register"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const project = await projectDAL.findById(projectId);
|
||||||
|
|
||||||
|
const kmsKey = await kmsService.importKeyMaterial({
|
||||||
|
name,
|
||||||
|
key: Buffer.from(key, "base64"),
|
||||||
|
algorithm,
|
||||||
|
isReserved: false,
|
||||||
|
projectId,
|
||||||
|
orgId: project.orgId
|
||||||
|
});
|
||||||
|
|
||||||
|
return kmsKey;
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
create,
|
create,
|
||||||
get,
|
get,
|
||||||
deleteOp
|
activate,
|
||||||
|
getAttributes,
|
||||||
|
deleteOp,
|
||||||
|
revoke,
|
||||||
|
locate,
|
||||||
|
register
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -56,6 +56,26 @@ export type TKmipGetDTO = {
|
|||||||
id: string;
|
id: string;
|
||||||
} & KmipOperationBaseDTO;
|
} & KmipOperationBaseDTO;
|
||||||
|
|
||||||
|
export type TKmipGetAttributesDTO = {
|
||||||
|
id: string;
|
||||||
|
} & KmipOperationBaseDTO;
|
||||||
|
|
||||||
export type TKmipDeleteDTO = {
|
export type TKmipDeleteDTO = {
|
||||||
id: string;
|
id: string;
|
||||||
} & KmipOperationBaseDTO;
|
} & KmipOperationBaseDTO;
|
||||||
|
|
||||||
|
export type TKmipActivateDTO = {
|
||||||
|
id: string;
|
||||||
|
} & KmipOperationBaseDTO;
|
||||||
|
|
||||||
|
export type TKmipRevokeDTO = {
|
||||||
|
id: string;
|
||||||
|
} & KmipOperationBaseDTO;
|
||||||
|
|
||||||
|
export type TKmipLocateDTO = KmipOperationBaseDTO;
|
||||||
|
|
||||||
|
export type TKmipRegisterDTO = {
|
||||||
|
name: string;
|
||||||
|
key: string;
|
||||||
|
algorithm: SymmetricEncryption;
|
||||||
|
} & KmipOperationBaseDTO;
|
||||||
|
|||||||
@@ -73,6 +73,34 @@ export const kmskeyDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const findProjectCmeks = async (projectId: string, tx?: Knex) => {
|
||||||
|
try {
|
||||||
|
const result = await (tx || db.replicaNode())(TableName.KmsKey)
|
||||||
|
.where({
|
||||||
|
[`${TableName.KmsKey}.projectId` as "projectId"]: projectId,
|
||||||
|
[`${TableName.KmsKey}.isReserved` as "isReserved"]: false
|
||||||
|
})
|
||||||
|
.join(TableName.Organization, `${TableName.KmsKey}.orgId`, `${TableName.Organization}.id`)
|
||||||
|
.join(TableName.InternalKms, `${TableName.KmsKey}.id`, `${TableName.InternalKms}.kmsKeyId`)
|
||||||
|
.select(selectAllTableCols(TableName.KmsKey))
|
||||||
|
.select(
|
||||||
|
db.ref("encryptedKey").withSchema(TableName.InternalKms).as("internalKmsEncryptedKey"),
|
||||||
|
db.ref("encryptionAlgorithm").withSchema(TableName.InternalKms).as("internalKmsEncryptionAlgorithm"),
|
||||||
|
db.ref("version").withSchema(TableName.InternalKms).as("internalKmsVersion")
|
||||||
|
);
|
||||||
|
|
||||||
|
return result.map((entry) => ({
|
||||||
|
...KmsKeysSchema.parse(entry),
|
||||||
|
isActive: !entry.isDisabled,
|
||||||
|
encryptedKey: entry.internalKmsEncryptedKey,
|
||||||
|
algorithm: entry.internalKmsEncryptionAlgorithm,
|
||||||
|
version: entry.internalKmsVersion
|
||||||
|
}));
|
||||||
|
} catch (error) {
|
||||||
|
throw new DatabaseError({ error, name: "Find project cmeks" });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const findKmsKeysByProjectId = async (
|
const findKmsKeysByProjectId = async (
|
||||||
{
|
{
|
||||||
projectId,
|
projectId,
|
||||||
@@ -118,5 +146,5 @@ export const kmskeyDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return { ...kmsOrm, findByIdWithAssociatedKms, findKmsKeysByProjectId };
|
return { ...kmsOrm, findByIdWithAssociatedKms, findKmsKeysByProjectId, findProjectCmeks };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import {
|
|||||||
TEncryptWithKmsDTO,
|
TEncryptWithKmsDTO,
|
||||||
TGenerateKMSDTO,
|
TGenerateKMSDTO,
|
||||||
TGetKeyMaterialDTO,
|
TGetKeyMaterialDTO,
|
||||||
|
TImportKeyMaterialDTO,
|
||||||
TUpdateProjectSecretManagerKmsKeyDTO
|
TUpdateProjectSecretManagerKmsKeyDTO
|
||||||
} from "./kms-types";
|
} from "./kms-types";
|
||||||
|
|
||||||
@@ -351,6 +352,48 @@ export const kmsServiceFactory = ({
|
|||||||
return kmsKey;
|
return kmsKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const importKeyMaterial = async (
|
||||||
|
{ key, algorithm, name, isReserved, projectId, orgId }: TImportKeyMaterialDTO,
|
||||||
|
tx?: Knex
|
||||||
|
) => {
|
||||||
|
const cipher = symmetricCipherService(SymmetricEncryption.AES_GCM_256);
|
||||||
|
|
||||||
|
const expectedByteLength = getByteLengthForAlgorithm(algorithm);
|
||||||
|
if (key.byteLength !== expectedByteLength) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: `Invalid key length for ${algorithm}. Expected ${expectedByteLength} bytes but got ${key.byteLength} bytes`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const encryptedKeyMaterial = cipher.encrypt(key, ROOT_ENCRYPTION_KEY);
|
||||||
|
const sanitizedName = name ? slugify(name) : slugify(alphaNumericNanoId(8).toLowerCase());
|
||||||
|
const dbQuery = async (db: Knex) => {
|
||||||
|
const kmsDoc = await kmsDAL.create(
|
||||||
|
{
|
||||||
|
name: sanitizedName,
|
||||||
|
orgId,
|
||||||
|
isReserved,
|
||||||
|
projectId
|
||||||
|
},
|
||||||
|
db
|
||||||
|
);
|
||||||
|
|
||||||
|
await internalKmsDAL.create(
|
||||||
|
{
|
||||||
|
version: 1,
|
||||||
|
encryptedKey: encryptedKeyMaterial,
|
||||||
|
encryptionAlgorithm: algorithm,
|
||||||
|
kmsKeyId: kmsDoc.id
|
||||||
|
},
|
||||||
|
db
|
||||||
|
);
|
||||||
|
return kmsDoc;
|
||||||
|
};
|
||||||
|
if (tx) return dbQuery(tx);
|
||||||
|
const doc = await kmsDAL.transaction(async (tx2) => dbQuery(tx2));
|
||||||
|
return doc;
|
||||||
|
};
|
||||||
|
|
||||||
const encryptWithKmsKey = async ({ kmsId }: Omit<TEncryptWithKmsDTO, "plainText">, tx?: Knex) => {
|
const encryptWithKmsKey = async ({ kmsId }: Omit<TEncryptWithKmsDTO, "plainText">, tx?: Knex) => {
|
||||||
const kmsDoc = await kmsDAL.findByIdWithAssociatedKms(kmsId, tx);
|
const kmsDoc = await kmsDAL.findByIdWithAssociatedKms(kmsId, tx);
|
||||||
if (!kmsDoc) {
|
if (!kmsDoc) {
|
||||||
@@ -993,6 +1036,7 @@ export const kmsServiceFactory = ({
|
|||||||
loadProjectKeyBackup,
|
loadProjectKeyBackup,
|
||||||
getKmsById,
|
getKmsById,
|
||||||
createCipherPairWithDataKey,
|
createCipherPairWithDataKey,
|
||||||
getKeyMaterial
|
getKeyMaterial,
|
||||||
|
importKeyMaterial
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -64,3 +64,12 @@ export enum RootKeyEncryptionStrategy {
|
|||||||
export type TGetKeyMaterialDTO = {
|
export type TGetKeyMaterialDTO = {
|
||||||
kmsId: string;
|
kmsId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type TImportKeyMaterialDTO = {
|
||||||
|
key: Buffer;
|
||||||
|
algorithm: SymmetricEncryption;
|
||||||
|
name?: string;
|
||||||
|
isReserved: boolean;
|
||||||
|
projectId: string;
|
||||||
|
orgId: string;
|
||||||
|
};
|
||||||
|
|||||||
@@ -127,7 +127,12 @@ export const eventToNameMap: { [K in EventType]: string } = {
|
|||||||
[EventType.CREATE_KMIP_CLIENT_CERTIFICATE]: "Create KMIP client certificate",
|
[EventType.CREATE_KMIP_CLIENT_CERTIFICATE]: "Create KMIP client certificate",
|
||||||
[EventType.KMIP_OPERATION_CREATE]: "KMIP operation create",
|
[EventType.KMIP_OPERATION_CREATE]: "KMIP operation create",
|
||||||
[EventType.KMIP_OPERATION_GET]: "KMIP operation get",
|
[EventType.KMIP_OPERATION_GET]: "KMIP operation get",
|
||||||
[EventType.KMIP_OPERATION_DELETE]: "KMIP operation delete"
|
[EventType.KMIP_OPERATION_DELETE]: "KMIP operation delete",
|
||||||
|
[EventType.KMIP_OPERATION_GET_ATTRIBUTES]: "KMIP operation get attributes",
|
||||||
|
[EventType.KMIP_OPERATION_ACTIVATE]: "KMIP operation activate",
|
||||||
|
[EventType.KMIP_OPERATION_REVOKE]: "KMIP operation revoke",
|
||||||
|
[EventType.KMIP_OPERATION_LOCATE]: "KMIP operation locate",
|
||||||
|
[EventType.KMIP_OPERATION_REGISTER]: "KMIP operation register"
|
||||||
};
|
};
|
||||||
|
|
||||||
export const userAgentTTypeoNameMap: { [K in UserAgentType]: string } = {
|
export const userAgentTTypeoNameMap: { [K in UserAgentType]: string } = {
|
||||||
|
|||||||
@@ -139,5 +139,10 @@ export enum EventType {
|
|||||||
CREATE_KMIP_CLIENT_CERTIFICATE = "create-kmip-client-certificate",
|
CREATE_KMIP_CLIENT_CERTIFICATE = "create-kmip-client-certificate",
|
||||||
KMIP_OPERATION_CREATE = "kmip-operation-create",
|
KMIP_OPERATION_CREATE = "kmip-operation-create",
|
||||||
KMIP_OPERATION_GET = "kmip-operation-get",
|
KMIP_OPERATION_GET = "kmip-operation-get",
|
||||||
KMIP_OPERATION_DELETE = "kmip-operation-delete"
|
KMIP_OPERATION_DELETE = "kmip-operation-delete",
|
||||||
|
KMIP_OPERATION_GET_ATTRIBUTES = "kmip-operation-get-attributes",
|
||||||
|
KMIP_OPERATION_ACTIVATE = "kmip-operation-activate",
|
||||||
|
KMIP_OPERATION_REVOKE = "kmip-operation-revoke",
|
||||||
|
KMIP_OPERATION_LOCATE = "kmip-operation-locate",
|
||||||
|
KMIP_OPERATION_REGISTER = "kmip-operation-register"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,11 @@ export enum KmipPermission {
|
|||||||
Locate = "locate",
|
Locate = "locate",
|
||||||
Check = "check",
|
Check = "check",
|
||||||
Get = "get",
|
Get = "get",
|
||||||
Delete = "delete"
|
GetAttributes = "get-attributes",
|
||||||
|
Activate = "activate",
|
||||||
|
Revoke = "revoke",
|
||||||
|
Delete = "delete",
|
||||||
|
Register = "register"
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TKmipClient = {
|
export type TKmipClient = {
|
||||||
|
|||||||
@@ -22,7 +22,11 @@ const KMIP_PERMISSIONS_OPTIONS = [
|
|||||||
{ value: KmipPermission.Create, label: "Create" },
|
{ value: KmipPermission.Create, label: "Create" },
|
||||||
{ value: KmipPermission.Get, label: "Get" },
|
{ value: KmipPermission.Get, label: "Get" },
|
||||||
{ value: KmipPermission.Locate, label: "Locate" },
|
{ value: KmipPermission.Locate, label: "Locate" },
|
||||||
{ value: KmipPermission.Delete, label: "Delete" }
|
{ value: KmipPermission.Delete, label: "Delete" },
|
||||||
|
{ value: KmipPermission.Activate, label: "Activate" },
|
||||||
|
{ value: KmipPermission.Revoke, label: "Revoke" },
|
||||||
|
{ value: KmipPermission.GetAttributes, label: "Get Attributes" },
|
||||||
|
{ value: KmipPermission.Register, label: "Register" }
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
const formSchema = z.object({
|
const formSchema = z.object({
|
||||||
@@ -33,7 +37,11 @@ const formSchema = z.object({
|
|||||||
[KmipPermission.Create]: z.boolean().optional(),
|
[KmipPermission.Create]: z.boolean().optional(),
|
||||||
[KmipPermission.Get]: z.boolean().optional(),
|
[KmipPermission.Get]: z.boolean().optional(),
|
||||||
[KmipPermission.Locate]: z.boolean().optional(),
|
[KmipPermission.Locate]: z.boolean().optional(),
|
||||||
[KmipPermission.Delete]: z.boolean().optional()
|
[KmipPermission.Delete]: z.boolean().optional(),
|
||||||
|
[KmipPermission.Activate]: z.boolean().optional(),
|
||||||
|
[KmipPermission.GetAttributes]: z.boolean().optional(),
|
||||||
|
[KmipPermission.Revoke]: z.boolean().optional(),
|
||||||
|
[KmipPermission.Register]: z.boolean().optional()
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user