mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-15 15:41:27 +00:00
478 lines
12 KiB
TypeScript
478 lines
12 KiB
TypeScript
import z from "zod";
|
|
|
|
import { KmsKeysSchema } from "@app/db/schemas";
|
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
|
import { SymmetricEncryption } from "@app/lib/crypto/cipher";
|
|
import { ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
|
|
import { writeLimit } from "@app/server/config/rateLimiter";
|
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
|
import { ActorType, AuthMode } from "@app/services/auth/auth-type";
|
|
|
|
export const registerKmipSpecRouter = async (server: FastifyZodProvider) => {
|
|
server.decorateRequest("kmipUser", null);
|
|
|
|
server.addHook("onRequest", async (req) => {
|
|
const clientId = req.headers["x-kmip-client-id"] as string;
|
|
const projectId = req.headers["x-kmip-project-id"] as string;
|
|
const clientCertSerialNumber = req.headers["x-kmip-client-certificate-serial-number"] as string;
|
|
const serverCertSerialNumber = req.headers["x-kmip-server-certificate-serial-number"] as string;
|
|
|
|
if (!serverCertSerialNumber) {
|
|
throw new ForbiddenRequestError({
|
|
message: "Missing server certificate serial number from request"
|
|
});
|
|
}
|
|
|
|
if (!clientCertSerialNumber) {
|
|
throw new ForbiddenRequestError({
|
|
message: "Missing client certificate serial number from request"
|
|
});
|
|
}
|
|
|
|
if (!clientId) {
|
|
throw new ForbiddenRequestError({
|
|
message: "Missing client ID from request"
|
|
});
|
|
}
|
|
|
|
if (!projectId) {
|
|
throw new ForbiddenRequestError({
|
|
message: "Missing project ID from request"
|
|
});
|
|
}
|
|
|
|
// TODO: assert that server certificate used is not revoked
|
|
// TODO: assert that client certificate used is not revoked
|
|
|
|
const kmipClient = await server.store.kmipClient.findByProjectAndClientId(projectId, clientId);
|
|
|
|
if (!kmipClient) {
|
|
throw new NotFoundError({
|
|
message: "KMIP client cannot be found."
|
|
});
|
|
}
|
|
|
|
if (kmipClient.orgId !== req.permission.orgId) {
|
|
throw new ForbiddenRequestError({
|
|
message: "Client specified in the request does not belong in the organization"
|
|
});
|
|
}
|
|
|
|
req.kmipUser = {
|
|
projectId,
|
|
clientId,
|
|
name: kmipClient.name
|
|
};
|
|
});
|
|
|
|
server.route({
|
|
method: "POST",
|
|
url: "/create",
|
|
config: {
|
|
rateLimit: writeLimit
|
|
},
|
|
schema: {
|
|
description: "KMIP endpoint for creating managed objects",
|
|
body: z.object({
|
|
algorithm: z.nativeEnum(SymmetricEncryption)
|
|
}),
|
|
response: {
|
|
200: KmsKeysSchema
|
|
}
|
|
},
|
|
onRequest: verifyAuth([AuthMode.IDENTITY_ACCESS_TOKEN]),
|
|
handler: async (req) => {
|
|
const object = await server.services.kmipOperation.create({
|
|
...req.kmipUser,
|
|
actor: req.permission.type,
|
|
actorId: req.permission.id,
|
|
actorAuthMethod: req.permission.authMethod,
|
|
actorOrgId: req.permission.orgId,
|
|
algorithm: req.body.algorithm
|
|
});
|
|
|
|
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_CREATE,
|
|
metadata: {
|
|
id: object.id,
|
|
algorithm: req.body.algorithm
|
|
}
|
|
}
|
|
});
|
|
|
|
return object;
|
|
}
|
|
});
|
|
|
|
server.route({
|
|
method: "POST",
|
|
url: "/get",
|
|
config: {
|
|
rateLimit: writeLimit
|
|
},
|
|
schema: {
|
|
description: "KMIP endpoint for getting managed objects",
|
|
body: z.object({
|
|
id: z.string()
|
|
}),
|
|
response: {
|
|
200: z.object({
|
|
id: z.string(),
|
|
value: z.string(),
|
|
algorithm: z.string()
|
|
})
|
|
}
|
|
},
|
|
onRequest: verifyAuth([AuthMode.IDENTITY_ACCESS_TOKEN]),
|
|
handler: async (req) => {
|
|
const object = await server.services.kmipOperation.get({
|
|
...req.kmipUser,
|
|
actor: req.permission.type,
|
|
actorId: req.permission.id,
|
|
actorAuthMethod: req.permission.authMethod,
|
|
actorOrgId: req.permission.orgId,
|
|
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,
|
|
metadata: {
|
|
id: object.id
|
|
}
|
|
}
|
|
});
|
|
|
|
return object;
|
|
}
|
|
});
|
|
|
|
server.route({
|
|
method: "POST",
|
|
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()
|
|
})
|
|
}
|
|
},
|
|
onRequest: verifyAuth([AuthMode.IDENTITY_ACCESS_TOKEN]),
|
|
handler: async (req) => {
|
|
const object = await server.services.kmipOperation.getAttributes({
|
|
...req.kmipUser,
|
|
actor: req.permission.type,
|
|
actorId: req.permission.id,
|
|
actorAuthMethod: req.permission.authMethod,
|
|
actorOrgId: req.permission.orgId,
|
|
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: {
|
|
rateLimit: writeLimit
|
|
},
|
|
schema: {
|
|
description: "KMIP endpoint for destroying managed objects",
|
|
body: z.object({
|
|
id: z.string()
|
|
}),
|
|
response: {
|
|
200: z.object({
|
|
id: z.string()
|
|
})
|
|
}
|
|
},
|
|
onRequest: verifyAuth([AuthMode.IDENTITY_ACCESS_TOKEN]),
|
|
handler: async (req) => {
|
|
const object = await server.services.kmipOperation.destroy({
|
|
...req.kmipUser,
|
|
actor: req.permission.type,
|
|
actorId: req.permission.id,
|
|
actorAuthMethod: req.permission.authMethod,
|
|
actorOrgId: req.permission.orgId,
|
|
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_DESTROY,
|
|
metadata: {
|
|
id: object.id
|
|
}
|
|
}
|
|
});
|
|
|
|
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()
|
|
})
|
|
}
|
|
},
|
|
onRequest: verifyAuth([AuthMode.IDENTITY_ACCESS_TOKEN]),
|
|
handler: async (req) => {
|
|
const object = await server.services.kmipOperation.activate({
|
|
...req.kmipUser,
|
|
actor: req.permission.type,
|
|
actorId: req.permission.id,
|
|
actorAuthMethod: req.permission.authMethod,
|
|
actorOrgId: req.permission.orgId,
|
|
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()
|
|
})
|
|
}
|
|
},
|
|
onRequest: verifyAuth([AuthMode.IDENTITY_ACCESS_TOKEN]),
|
|
handler: async (req) => {
|
|
const object = await server.services.kmipOperation.revoke({
|
|
...req.kmipUser,
|
|
actor: req.permission.type,
|
|
actorId: req.permission.id,
|
|
actorAuthMethod: req.permission.authMethod,
|
|
actorOrgId: req.permission.orgId,
|
|
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()
|
|
})
|
|
}
|
|
},
|
|
onRequest: verifyAuth([AuthMode.IDENTITY_ACCESS_TOKEN]),
|
|
handler: async (req) => {
|
|
const objects = await server.services.kmipOperation.locate({
|
|
...req.kmipUser,
|
|
actor: req.permission.type,
|
|
actorId: req.permission.id,
|
|
actorAuthMethod: req.permission.authMethod,
|
|
actorOrgId: req.permission.orgId
|
|
});
|
|
|
|
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()
|
|
})
|
|
}
|
|
},
|
|
onRequest: verifyAuth([AuthMode.IDENTITY_ACCESS_TOKEN]),
|
|
handler: async (req) => {
|
|
const object = await server.services.kmipOperation.register({
|
|
...req.kmipUser,
|
|
...req.body,
|
|
actor: req.permission.type,
|
|
actorId: req.permission.id,
|
|
actorAuthMethod: req.permission.authMethod,
|
|
actorOrgId: req.permission.orgId
|
|
});
|
|
|
|
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;
|
|
}
|
|
});
|
|
};
|