mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-05 20:26:44 +00:00
Link cert mgmt to kms
This commit is contained in:
Vendored
+7
-7
@@ -41,9 +41,9 @@ import {
|
|||||||
TCertificateAuthorityCrl,
|
TCertificateAuthorityCrl,
|
||||||
TCertificateAuthorityCrlInsert,
|
TCertificateAuthorityCrlInsert,
|
||||||
TCertificateAuthorityCrlUpdate,
|
TCertificateAuthorityCrlUpdate,
|
||||||
TCertificateAuthoritySk,
|
TCertificateAuthoritySecret,
|
||||||
TCertificateAuthoritySkInsert,
|
TCertificateAuthoritySecretInsert,
|
||||||
TCertificateAuthoritySkUpdate,
|
TCertificateAuthoritySecretUpdate,
|
||||||
TCertificateCerts,
|
TCertificateCerts,
|
||||||
TCertificateCertsInsert,
|
TCertificateCertsInsert,
|
||||||
TCertificateCertsUpdate,
|
TCertificateCertsUpdate,
|
||||||
@@ -288,10 +288,10 @@ declare module "knex/types/tables" {
|
|||||||
TCertificateAuthorityCertsInsert,
|
TCertificateAuthorityCertsInsert,
|
||||||
TCertificateAuthorityCertsUpdate
|
TCertificateAuthorityCertsUpdate
|
||||||
>;
|
>;
|
||||||
[TableName.CertificateAuthoritySk]: Knex.CompositeTableType<
|
[TableName.CertificateAuthoritySecret]: Knex.CompositeTableType<
|
||||||
TCertificateAuthoritySk,
|
TCertificateAuthoritySecret,
|
||||||
TCertificateAuthoritySkInsert,
|
TCertificateAuthoritySecretInsert,
|
||||||
TCertificateAuthoritySkUpdate
|
TCertificateAuthoritySecretUpdate
|
||||||
>;
|
>;
|
||||||
[TableName.CertificateAuthorityCrl]: Knex.CompositeTableType<
|
[TableName.CertificateAuthorityCrl]: Knex.CompositeTableType<
|
||||||
TCertificateAuthorityCrl,
|
TCertificateAuthorityCrl,
|
||||||
|
|||||||
+29
-13
@@ -4,6 +4,16 @@ import { TableName } from "../schemas";
|
|||||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
export async function up(knex: Knex): Promise<void> {
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (await knex.schema.hasTable(TableName.Project)) {
|
||||||
|
const doesProjectCertificateKeyIdExist = await knex.schema.hasColumn(TableName.Project, "kmsCertificateKeyId");
|
||||||
|
await knex.schema.alterTable(TableName.Project, (t) => {
|
||||||
|
if (!doesProjectCertificateKeyIdExist) {
|
||||||
|
t.uuid("kmsCertificateKeyId").nullable();
|
||||||
|
t.foreign("kmsCertificateKeyId").references("id").inTable(TableName.KmsKey);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (!(await knex.schema.hasTable(TableName.CertificateAuthority))) {
|
if (!(await knex.schema.hasTable(TableName.CertificateAuthority))) {
|
||||||
await knex.schema.createTable(TableName.CertificateAuthority, (t) => {
|
await knex.schema.createTable(TableName.CertificateAuthority, (t) => {
|
||||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
@@ -35,22 +45,20 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
await knex.schema.createTable(TableName.CertificateAuthorityCert, (t) => {
|
await knex.schema.createTable(TableName.CertificateAuthorityCert, (t) => {
|
||||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
t.timestamps(true, true, true);
|
t.timestamps(true, true, true);
|
||||||
t.uuid("caId").notNullable().unique(); // TODO: consider that cert can be rotated so may be multiple / non-unique
|
t.uuid("caId").notNullable().unique();
|
||||||
t.foreign("caId").references("id").inTable(TableName.CertificateAuthority).onDelete("CASCADE");
|
t.foreign("caId").references("id").inTable(TableName.CertificateAuthority).onDelete("CASCADE");
|
||||||
t.text("certificate").notNullable(); // TODO: encrypt
|
t.binary("encryptedCertificate").notNullable();
|
||||||
t.text("certificateChain").notNullable(); // TODO: encrypt
|
t.binary("encryptedCertificateChain").notNullable();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: consider renaming this to CertificateAuthoritySecret
|
if (!(await knex.schema.hasTable(TableName.CertificateAuthoritySecret))) {
|
||||||
if (!(await knex.schema.hasTable(TableName.CertificateAuthoritySk))) {
|
await knex.schema.createTable(TableName.CertificateAuthoritySecret, (t) => {
|
||||||
await knex.schema.createTable(TableName.CertificateAuthoritySk, (t) => {
|
|
||||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
t.timestamps(true, true, true);
|
t.timestamps(true, true, true);
|
||||||
t.uuid("caId").notNullable().unique();
|
t.uuid("caId").notNullable().unique();
|
||||||
t.foreign("caId").references("id").inTable(TableName.CertificateAuthority).onDelete("CASCADE");
|
t.foreign("caId").references("id").inTable(TableName.CertificateAuthority).onDelete("CASCADE");
|
||||||
t.text("pk").notNullable(); // TODO: encrypt
|
t.binary("encryptedPrivateKey").notNullable();
|
||||||
t.text("sk").notNullable(); // TODO: encrypt
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,19 +97,27 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
t.timestamps(true, true, true);
|
t.timestamps(true, true, true);
|
||||||
t.uuid("certId").notNullable().unique();
|
t.uuid("certId").notNullable().unique();
|
||||||
t.foreign("certId").references("id").inTable(TableName.Certificate).onDelete("CASCADE");
|
t.foreign("certId").references("id").inTable(TableName.Certificate).onDelete("CASCADE");
|
||||||
t.text("certificate").notNullable(); // TODO: encrypt
|
t.binary("encryptedCertificate").notNullable();
|
||||||
t.text("certificateChain").notNullable(); // TODO: encrypt
|
t.binary("encryptedCertificateChain").notNullable();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
await createOnUpdateTrigger(knex, TableName.CertificateAuthority);
|
await createOnUpdateTrigger(knex, TableName.CertificateAuthority);
|
||||||
await createOnUpdateTrigger(knex, TableName.CertificateAuthorityCert);
|
await createOnUpdateTrigger(knex, TableName.CertificateAuthorityCert);
|
||||||
await createOnUpdateTrigger(knex, TableName.CertificateAuthoritySk);
|
await createOnUpdateTrigger(knex, TableName.CertificateAuthoritySecret);
|
||||||
await createOnUpdateTrigger(knex, TableName.Certificate);
|
await createOnUpdateTrigger(knex, TableName.Certificate);
|
||||||
await createOnUpdateTrigger(knex, TableName.CertificateCert);
|
await createOnUpdateTrigger(knex, TableName.CertificateCert);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function down(knex: Knex): Promise<void> {
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
// project
|
||||||
|
if (await knex.schema.hasTable(TableName.Project)) {
|
||||||
|
const doesProjectCertificateKeyIdExist = await knex.schema.hasColumn(TableName.Project, "kmsCertificateKeyId");
|
||||||
|
await knex.schema.alterTable(TableName.Project, (t) => {
|
||||||
|
if (doesProjectCertificateKeyIdExist) t.dropColumn("kmsCertificateKeyId");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// certificates
|
// certificates
|
||||||
await knex.schema.dropTableIfExists(TableName.CertificateCert);
|
await knex.schema.dropTableIfExists(TableName.CertificateCert);
|
||||||
await dropOnUpdateTrigger(knex, TableName.CertificateCert);
|
await dropOnUpdateTrigger(knex, TableName.CertificateCert);
|
||||||
@@ -110,8 +126,8 @@ export async function down(knex: Knex): Promise<void> {
|
|||||||
await dropOnUpdateTrigger(knex, TableName.Certificate);
|
await dropOnUpdateTrigger(knex, TableName.Certificate);
|
||||||
|
|
||||||
// certificate authorities
|
// certificate authorities
|
||||||
await knex.schema.dropTableIfExists(TableName.CertificateAuthoritySk);
|
await knex.schema.dropTableIfExists(TableName.CertificateAuthoritySecret);
|
||||||
await dropOnUpdateTrigger(knex, TableName.CertificateAuthoritySk);
|
await dropOnUpdateTrigger(knex, TableName.CertificateAuthoritySecret);
|
||||||
|
|
||||||
await knex.schema.dropTableIfExists(TableName.CertificateAuthorityCrl);
|
await knex.schema.dropTableIfExists(TableName.CertificateAuthorityCrl);
|
||||||
await dropOnUpdateTrigger(knex, TableName.CertificateAuthorityCrl);
|
await dropOnUpdateTrigger(knex, TableName.CertificateAuthorityCrl);
|
||||||
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { zodBuffer } from "@app/lib/zod";
|
||||||
|
|
||||||
import { TImmutableDBKeys } from "./models";
|
import { TImmutableDBKeys } from "./models";
|
||||||
|
|
||||||
export const CertificateAuthorityCertsSchema = z.object({
|
export const CertificateAuthorityCertsSchema = z.object({
|
||||||
@@ -12,8 +14,8 @@ export const CertificateAuthorityCertsSchema = z.object({
|
|||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
caId: z.string().uuid(),
|
caId: z.string().uuid(),
|
||||||
certificate: z.string(),
|
encryptedCertificate: zodBuffer,
|
||||||
certificateChain: z.string()
|
encryptedCertificateChain: zodBuffer
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TCertificateAuthorityCerts = z.infer<typeof CertificateAuthorityCertsSchema>;
|
export type TCertificateAuthorityCerts = z.infer<typeof CertificateAuthorityCertsSchema>;
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
// Code generated by automation script, DO NOT EDIT.
|
||||||
|
// Automated by pulling database and generating zod schema
|
||||||
|
// To update. Just run npm run generate:schema
|
||||||
|
// Written by akhilmhdh.
|
||||||
|
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { zodBuffer } from "@app/lib/zod";
|
||||||
|
|
||||||
|
import { TImmutableDBKeys } from "./models";
|
||||||
|
|
||||||
|
export const CertificateAuthoritySecretSchema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date(),
|
||||||
|
caId: z.string().uuid(),
|
||||||
|
encryptedPrivateKey: zodBuffer
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TCertificateAuthoritySecret = z.infer<typeof CertificateAuthoritySecretSchema>;
|
||||||
|
export type TCertificateAuthoritySecretInsert = Omit<
|
||||||
|
z.input<typeof CertificateAuthoritySecretSchema>,
|
||||||
|
TImmutableDBKeys
|
||||||
|
>;
|
||||||
|
export type TCertificateAuthoritySecretUpdate = Partial<
|
||||||
|
Omit<z.input<typeof CertificateAuthoritySecretSchema>, TImmutableDBKeys>
|
||||||
|
>;
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
// Code generated by automation script, DO NOT EDIT.
|
|
||||||
// Automated by pulling database and generating zod schema
|
|
||||||
// To update. Just run npm run generate:schema
|
|
||||||
// Written by akhilmhdh.
|
|
||||||
|
|
||||||
import { z } from "zod";
|
|
||||||
|
|
||||||
import { TImmutableDBKeys } from "./models";
|
|
||||||
|
|
||||||
export const CertificateAuthoritySkSchema = z.object({
|
|
||||||
id: z.string().uuid(),
|
|
||||||
createdAt: z.date(),
|
|
||||||
updatedAt: z.date(),
|
|
||||||
caId: z.string().uuid(),
|
|
||||||
pk: z.string(),
|
|
||||||
sk: z.string()
|
|
||||||
});
|
|
||||||
|
|
||||||
export type TCertificateAuthoritySk = z.infer<typeof CertificateAuthoritySkSchema>;
|
|
||||||
export type TCertificateAuthoritySkInsert = Omit<z.input<typeof CertificateAuthoritySkSchema>, TImmutableDBKeys>;
|
|
||||||
export type TCertificateAuthoritySkUpdate = Partial<
|
|
||||||
Omit<z.input<typeof CertificateAuthoritySkSchema>, TImmutableDBKeys>
|
|
||||||
>;
|
|
||||||
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { zodBuffer } from "@app/lib/zod";
|
||||||
|
|
||||||
import { TImmutableDBKeys } from "./models";
|
import { TImmutableDBKeys } from "./models";
|
||||||
|
|
||||||
export const CertificateCertsSchema = z.object({
|
export const CertificateCertsSchema = z.object({
|
||||||
@@ -12,8 +14,8 @@ export const CertificateCertsSchema = z.object({
|
|||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
certId: z.string().uuid(),
|
certId: z.string().uuid(),
|
||||||
certificate: z.string(),
|
encryptedCertificate: zodBuffer,
|
||||||
certificateChain: z.string()
|
encryptedCertificateChain: zodBuffer
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TCertificateCerts = z.infer<typeof CertificateCertsSchema>;
|
export type TCertificateCerts = z.infer<typeof CertificateCertsSchema>;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export * from "./backup-private-key";
|
|||||||
export * from "./certificate-authorities";
|
export * from "./certificate-authorities";
|
||||||
export * from "./certificate-authority-certs";
|
export * from "./certificate-authority-certs";
|
||||||
export * from "./certificate-authority-crl";
|
export * from "./certificate-authority-crl";
|
||||||
export * from "./certificate-authority-sk";
|
export * from "./certificate-authority-secret";
|
||||||
export * from "./certificate-certs";
|
export * from "./certificate-certs";
|
||||||
export * from "./certificate-secrets";
|
export * from "./certificate-secrets";
|
||||||
export * from "./certificates";
|
export * from "./certificates";
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ export enum TableName {
|
|||||||
Users = "users",
|
Users = "users",
|
||||||
CertificateAuthority = "certificate_authorities",
|
CertificateAuthority = "certificate_authorities",
|
||||||
CertificateAuthorityCert = "certificate_authority_certs",
|
CertificateAuthorityCert = "certificate_authority_certs",
|
||||||
CertificateAuthoritySk = "certificate_authority_sk",
|
CertificateAuthoritySecret = "certificate_authority_secret",
|
||||||
CertificateAuthorityCrl = "certificate_authority_crl",
|
CertificateAuthorityCrl = "certificate_authority_crl",
|
||||||
Certificate = "certificates",
|
Certificate = "certificates",
|
||||||
CertificateCert = "certificate_certs",
|
CertificateCert = "certificate_certs",
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ export const ProjectsSchema = z.object({
|
|||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
version: z.number().default(1),
|
version: z.number().default(1),
|
||||||
upgradeStatus: z.string().nullable().optional()
|
upgradeStatus: z.string().nullable().optional(),
|
||||||
|
kmsCertificateKeyId: z.string().uuid().nullable().optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TProjects = z.infer<typeof ProjectsSchema>;
|
export type TProjects = z.infer<typeof ProjectsSchema>;
|
||||||
|
|||||||
@@ -78,8 +78,8 @@ import { certificateAuthorityCertDALFactory } from "@app/services/certificate-au
|
|||||||
import { certificateAuthorityCrlDALFactory } from "@app/services/certificate-authority/certificate-authority-crl-dal";
|
import { certificateAuthorityCrlDALFactory } from "@app/services/certificate-authority/certificate-authority-crl-dal";
|
||||||
import { certificateAuthorityDALFactory } from "@app/services/certificate-authority/certificate-authority-dal";
|
import { certificateAuthorityDALFactory } from "@app/services/certificate-authority/certificate-authority-dal";
|
||||||
import { certificateAuthorityQueueFactory } from "@app/services/certificate-authority/certificate-authority-queue";
|
import { certificateAuthorityQueueFactory } from "@app/services/certificate-authority/certificate-authority-queue";
|
||||||
|
import { certificateAuthoritySecretDALFactory } from "@app/services/certificate-authority/certificate-authority-secret-dal";
|
||||||
import { certificateAuthorityServiceFactory } from "@app/services/certificate-authority/certificate-authority-service";
|
import { certificateAuthorityServiceFactory } from "@app/services/certificate-authority/certificate-authority-service";
|
||||||
import { certificateAuthoritySkDALFactory } from "@app/services/certificate-authority/certificate-authority-sk-dal";
|
|
||||||
import { groupProjectDALFactory } from "@app/services/group-project/group-project-dal";
|
import { groupProjectDALFactory } from "@app/services/group-project/group-project-dal";
|
||||||
import { groupProjectMembershipRoleDALFactory } from "@app/services/group-project/group-project-membership-role-dal";
|
import { groupProjectMembershipRoleDALFactory } from "@app/services/group-project/group-project-membership-role-dal";
|
||||||
import { groupProjectServiceFactory } from "@app/services/group-project/group-project-service";
|
import { groupProjectServiceFactory } from "@app/services/group-project/group-project-service";
|
||||||
@@ -517,7 +517,7 @@ export const registerRoutes = async (
|
|||||||
|
|
||||||
const certificateAuthorityDAL = certificateAuthorityDALFactory(db);
|
const certificateAuthorityDAL = certificateAuthorityDALFactory(db);
|
||||||
const certificateAuthorityCertDAL = certificateAuthorityCertDALFactory(db);
|
const certificateAuthorityCertDAL = certificateAuthorityCertDALFactory(db);
|
||||||
const certificateAuthoritySkDAL = certificateAuthoritySkDALFactory(db);
|
const certificateAuthoritySecretDAL = certificateAuthoritySecretDALFactory(db);
|
||||||
const certificateAuthorityCrlDAL = certificateAuthorityCrlDALFactory(db);
|
const certificateAuthorityCrlDAL = certificateAuthorityCrlDALFactory(db);
|
||||||
|
|
||||||
const certificateDAL = certificateDALFactory(db);
|
const certificateDAL = certificateDALFactory(db);
|
||||||
@@ -527,13 +527,15 @@ export const registerRoutes = async (
|
|||||||
certificateDAL,
|
certificateDAL,
|
||||||
certificateCertDAL,
|
certificateCertDAL,
|
||||||
certificateAuthorityDAL,
|
certificateAuthorityDAL,
|
||||||
|
projectDAL,
|
||||||
|
kmsService,
|
||||||
permissionService
|
permissionService
|
||||||
});
|
});
|
||||||
|
|
||||||
const certificateAuthorityQueue = certificateAuthorityQueueFactory({
|
const certificateAuthorityQueue = certificateAuthorityQueueFactory({
|
||||||
certificateAuthorityCrlDAL,
|
certificateAuthorityCrlDAL,
|
||||||
certificateAuthorityDAL,
|
certificateAuthorityDAL,
|
||||||
certificateAuthoritySkDAL,
|
certificateAuthoritySecretDAL,
|
||||||
certificateDAL,
|
certificateDAL,
|
||||||
queueService
|
queueService
|
||||||
});
|
});
|
||||||
@@ -541,12 +543,13 @@ export const registerRoutes = async (
|
|||||||
const certificateAuthorityService = certificateAuthorityServiceFactory({
|
const certificateAuthorityService = certificateAuthorityServiceFactory({
|
||||||
certificateAuthorityDAL,
|
certificateAuthorityDAL,
|
||||||
certificateAuthorityCertDAL,
|
certificateAuthorityCertDAL,
|
||||||
certificateAuthoritySkDAL,
|
certificateAuthoritySecretDAL,
|
||||||
certificateAuthorityCrlDAL,
|
certificateAuthorityCrlDAL,
|
||||||
certificateAuthorityQueue,
|
certificateAuthorityQueue,
|
||||||
certificateDAL,
|
certificateDAL,
|
||||||
certificateCertDAL,
|
certificateCertDAL,
|
||||||
projectDAL,
|
projectDAL,
|
||||||
|
kmsService,
|
||||||
permissionService
|
permissionService
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export const certificateAuthorityDALFactory = (db: TDbClient) => {
|
|||||||
const result: {
|
const result: {
|
||||||
caId: string;
|
caId: string;
|
||||||
parentCaId?: string;
|
parentCaId?: string;
|
||||||
certificate: string;
|
certificate: Buffer;
|
||||||
}[] = await db
|
}[] = await db
|
||||||
.withRecursive("cte", (cte) => {
|
.withRecursive("cte", (cte) => {
|
||||||
void cte
|
void cte
|
||||||
@@ -33,7 +33,7 @@ export const certificateAuthorityDALFactory = (db: TDbClient) => {
|
|||||||
.from("cte");
|
.from("cte");
|
||||||
|
|
||||||
// Extract certificates and reverse the order to have the root CA at the end
|
// Extract certificates and reverse the order to have the root CA at the end
|
||||||
const certChain: string[] = result.map((row) => row.certificate);
|
const certChain: Buffer[] = result.map((row) => row.certificate);
|
||||||
return certChain;
|
return certChain;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "BuildCertificateChain" });
|
throw new DatabaseError({ error, name: "BuildCertificateChain" });
|
||||||
|
|||||||
@@ -1,35 +1,35 @@
|
|||||||
import * as x509 from "@peculiar/x509";
|
// import * as x509 from "@peculiar/x509";
|
||||||
import crypto from "crypto";
|
// import crypto from "crypto";
|
||||||
|
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { daysToMillisecond, secondsToMillis } from "@app/lib/dates";
|
import { daysToMillisecond, secondsToMillis } from "@app/lib/dates";
|
||||||
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 { QueueJobs, QueueName, TQueueServiceFactory } from "@app/queue";
|
import { QueueJobs, QueueName, TQueueServiceFactory } from "@app/queue";
|
||||||
import { TCertificateDALFactory } from "@app/services/certificate/certificate-dal";
|
import { TCertificateDALFactory } from "@app/services/certificate/certificate-dal";
|
||||||
import { CertKeyAlgorithm, CertStatus } from "@app/services/certificate/certificate-types";
|
|
||||||
|
|
||||||
|
// import { CertKeyAlgorithm, CertStatus } from "@app/services/certificate/certificate-types";
|
||||||
import { TCertificateAuthorityCrlDALFactory } from "./certificate-authority-crl-dal";
|
import { TCertificateAuthorityCrlDALFactory } from "./certificate-authority-crl-dal";
|
||||||
import { TCertificateAuthorityDALFactory } from "./certificate-authority-dal";
|
import { TCertificateAuthorityDALFactory } from "./certificate-authority-dal";
|
||||||
import { keyAlgorithmToAlgCfg } from "./certificate-authority-fns";
|
// import { keyAlgorithmToAlgCfg } from "./certificate-authority-fns";
|
||||||
import { TCertificateAuthoritySkDALFactory } from "./certificate-authority-sk-dal";
|
import { TCertificateAuthoritySecretDALFactory } from "./certificate-authority-secret-dal";
|
||||||
import { TRotateCaCrlTriggerDTO } from "./certificate-authority-types";
|
import { TRotateCaCrlTriggerDTO } from "./certificate-authority-types";
|
||||||
|
|
||||||
type TCertificateAuthorityQueueFactoryDep = {
|
type TCertificateAuthorityQueueFactoryDep = {
|
||||||
// TODO: Pick
|
// TODO: Pick
|
||||||
certificateAuthorityDAL: TCertificateAuthorityDALFactory;
|
certificateAuthorityDAL: TCertificateAuthorityDALFactory;
|
||||||
certificateAuthorityCrlDAL: TCertificateAuthorityCrlDALFactory;
|
certificateAuthorityCrlDAL: TCertificateAuthorityCrlDALFactory;
|
||||||
certificateAuthoritySkDAL: TCertificateAuthoritySkDALFactory;
|
certificateAuthoritySecretDAL: TCertificateAuthoritySecretDALFactory;
|
||||||
certificateDAL: TCertificateDALFactory;
|
certificateDAL: TCertificateDALFactory;
|
||||||
queueService: TQueueServiceFactory;
|
queueService: TQueueServiceFactory;
|
||||||
};
|
};
|
||||||
export type TCertificateAuthorityQueueFactory = ReturnType<typeof certificateAuthorityQueueFactory>;
|
export type TCertificateAuthorityQueueFactory = ReturnType<typeof certificateAuthorityQueueFactory>;
|
||||||
|
|
||||||
export const certificateAuthorityQueueFactory = ({
|
export const certificateAuthorityQueueFactory = ({
|
||||||
certificateAuthorityCrlDAL,
|
// certificateAuthorityCrlDAL,
|
||||||
certificateAuthorityDAL,
|
// certificateAuthorityDAL,
|
||||||
certificateAuthoritySkDAL,
|
// certificateAuthoritySecretDAL,
|
||||||
certificateDAL,
|
// certificateDAL,
|
||||||
queueService
|
queueService
|
||||||
}: TCertificateAuthorityQueueFactoryDep) => {
|
}: TCertificateAuthorityQueueFactoryDep) => {
|
||||||
// TODO 1: auto-periodic rotation
|
// TODO 1: auto-periodic rotation
|
||||||
@@ -64,55 +64,55 @@ export const certificateAuthorityQueueFactory = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
queueService.start(QueueName.CaCrlRotation, async (job) => {
|
// queueService.start(QueueName.CaCrlRotation, async (job) => {
|
||||||
const { caId } = job.data;
|
// const { caId } = job.data;
|
||||||
logger.info(`secretReminderQueue.process: [secretDocument=${caId}]`);
|
// logger.info(`secretReminderQueue.process: [secretDocument=${caId}]`);
|
||||||
|
|
||||||
const ca = await certificateAuthorityDAL.findById(caId);
|
// const ca = await certificateAuthorityDAL.findById(caId);
|
||||||
if (!ca) throw new BadRequestError({ message: "CA not found" });
|
// if (!ca) throw new BadRequestError({ message: "CA not found" });
|
||||||
|
|
||||||
const caKeys = await certificateAuthoritySkDAL.findOne({ caId: ca.id });
|
// const caKeys = await certificateAuthoritySecretDAL.findOne({ caId: ca.id });
|
||||||
|
|
||||||
const alg = keyAlgorithmToAlgCfg(ca.keyAlgorithm as CertKeyAlgorithm);
|
// const alg = keyAlgorithmToAlgCfg(ca.keyAlgorithm as CertKeyAlgorithm);
|
||||||
const skObj = crypto.createPrivateKey({ key: caKeys.sk, format: "pem", type: "pkcs8" });
|
// const skObj = crypto.createPrivateKey({ key: caKeys.sk, format: "pem", type: "pkcs8" });
|
||||||
const sk = await crypto.subtle.importKey("pkcs8", skObj.export({ format: "der", type: "pkcs8" }), alg, true, [
|
// const sk = await crypto.subtle.importKey("pkcs8", skObj.export({ format: "der", type: "pkcs8" }), alg, true, [
|
||||||
"sign"
|
// "sign"
|
||||||
]);
|
// ]);
|
||||||
|
|
||||||
const revokedCerts = await certificateDAL.find({
|
// const revokedCerts = await certificateDAL.find({
|
||||||
caId: ca.id,
|
// caId: ca.id,
|
||||||
status: CertStatus.REVOKED
|
// status: CertStatus.REVOKED
|
||||||
});
|
// });
|
||||||
|
|
||||||
const crl = await x509.X509CrlGenerator.create({
|
// const crl = await x509.X509CrlGenerator.create({
|
||||||
issuer: ca.dn,
|
// issuer: ca.dn,
|
||||||
thisUpdate: new Date(),
|
// thisUpdate: new Date(),
|
||||||
nextUpdate: new Date("2025/12/12"), // TODO: depends on configured rebuild interval
|
// nextUpdate: new Date("2025/12/12"), // TODO: depends on configured rebuild interval
|
||||||
entries: revokedCerts.map((revokedCert) => {
|
// entries: revokedCerts.map((revokedCert) => {
|
||||||
return {
|
// return {
|
||||||
serialNumber: revokedCert.serialNumber,
|
// serialNumber: revokedCert.serialNumber,
|
||||||
revocationDate: new Date(revokedCert.revokedAt as Date),
|
// revocationDate: new Date(revokedCert.revokedAt as Date),
|
||||||
reason: revokedCert.revocationReason as number,
|
// reason: revokedCert.revocationReason as number,
|
||||||
invalidity: new Date("2022/01/01"),
|
// invalidity: new Date("2022/01/01"),
|
||||||
issuer: ca.dn
|
// issuer: ca.dn
|
||||||
};
|
// };
|
||||||
}),
|
// }),
|
||||||
signingAlgorithm: alg,
|
// signingAlgorithm: alg,
|
||||||
signingKey: sk
|
// signingKey: sk
|
||||||
});
|
// });
|
||||||
|
|
||||||
const base64crl = crl.toString("base64");
|
// const base64crl = crl.toString("base64");
|
||||||
const crlPem = `-----BEGIN X509 CRL-----\n${base64crl.match(/.{1,64}/g)?.join("\n")}\n-----END X509 CRL-----`;
|
// const crlPem = `-----BEGIN X509 CRL-----\n${base64crl.match(/.{1,64}/g)?.join("\n")}\n-----END X509 CRL-----`;
|
||||||
|
|
||||||
await certificateAuthorityCrlDAL.update(
|
// await certificateAuthorityCrlDAL.update(
|
||||||
{
|
// {
|
||||||
caId: ca.id
|
// caId: ca.id
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
crl: crlPem // TODO: encrypt
|
// crl: crlPem // TODO: encrypt
|
||||||
}
|
// }
|
||||||
);
|
// );
|
||||||
});
|
// });
|
||||||
|
|
||||||
queueService.listen(QueueName.CaCrlRotation, "failed", (job, err) => {
|
queueService.listen(QueueName.CaCrlRotation, "failed", (job, err) => {
|
||||||
logger.error(err, "Failed to rotate CA CRL %s", job?.id);
|
logger.error(err, "Failed to rotate CA CRL %s", job?.id);
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { TDbClient } from "@app/db";
|
||||||
|
import { TableName } from "@app/db/schemas";
|
||||||
|
import { ormify } from "@app/lib/knex";
|
||||||
|
|
||||||
|
export type TCertificateAuthoritySecretDALFactory = ReturnType<typeof certificateAuthoritySecretDALFactory>;
|
||||||
|
|
||||||
|
export const certificateAuthoritySecretDALFactory = (db: TDbClient) => {
|
||||||
|
const caSecretOrm = ormify(db, TableName.CertificateAuthoritySecret);
|
||||||
|
return caSecretOrm;
|
||||||
|
};
|
||||||
@@ -8,7 +8,9 @@ import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services
|
|||||||
import { BadRequestError } from "@app/lib/errors";
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
import { TCertificateCertDALFactory } from "@app/services/certificate/certificate-cert-dal";
|
import { TCertificateCertDALFactory } from "@app/services/certificate/certificate-cert-dal";
|
||||||
import { TCertificateDALFactory } from "@app/services/certificate/certificate-dal";
|
import { TCertificateDALFactory } from "@app/services/certificate/certificate-dal";
|
||||||
|
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||||
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
||||||
|
import { getProjectKmsCertificateKeyId } from "@app/services/project/project-fns";
|
||||||
|
|
||||||
import { CertKeyAlgorithm, CertStatus } from "../certificate/certificate-types";
|
import { CertKeyAlgorithm, CertStatus } from "../certificate/certificate-types";
|
||||||
import { TCertificateAuthorityCertDALFactory } from "./certificate-authority-cert-dal";
|
import { TCertificateAuthorityCertDALFactory } from "./certificate-authority-cert-dal";
|
||||||
@@ -16,7 +18,7 @@ import { TCertificateAuthorityCrlDALFactory } from "./certificate-authority-crl-
|
|||||||
import { TCertificateAuthorityDALFactory } from "./certificate-authority-dal";
|
import { TCertificateAuthorityDALFactory } from "./certificate-authority-dal";
|
||||||
import { createDistinguishedName, keyAlgorithmToAlgCfg } from "./certificate-authority-fns";
|
import { createDistinguishedName, keyAlgorithmToAlgCfg } from "./certificate-authority-fns";
|
||||||
import { TCertificateAuthorityQueueFactory } from "./certificate-authority-queue";
|
import { TCertificateAuthorityQueueFactory } from "./certificate-authority-queue";
|
||||||
import { TCertificateAuthoritySkDALFactory } from "./certificate-authority-sk-dal";
|
import { TCertificateAuthoritySecretDALFactory } from "./certificate-authority-secret-dal";
|
||||||
import {
|
import {
|
||||||
CaStatus,
|
CaStatus,
|
||||||
CaType,
|
CaType,
|
||||||
@@ -39,25 +41,29 @@ type TCertificateAuthorityServiceFactoryDep = {
|
|||||||
"transaction" | "create" | "findById" | "updateById" | "deleteById" | "findOne" | "buildCertificateChain"
|
"transaction" | "create" | "findById" | "updateById" | "deleteById" | "findOne" | "buildCertificateChain"
|
||||||
>;
|
>;
|
||||||
certificateAuthorityCertDAL: Pick<TCertificateAuthorityCertDALFactory, "create" | "findOne" | "transaction">;
|
certificateAuthorityCertDAL: Pick<TCertificateAuthorityCertDALFactory, "create" | "findOne" | "transaction">;
|
||||||
certificateAuthoritySkDAL: Pick<TCertificateAuthoritySkDALFactory, "create" | "findOne">;
|
certificateAuthoritySecretDAL: Pick<TCertificateAuthoritySecretDALFactory, "create" | "findOne">;
|
||||||
certificateAuthorityCrlDAL: Pick<TCertificateAuthorityCrlDALFactory, "create" | "findOne" | "update">;
|
certificateAuthorityCrlDAL: Pick<TCertificateAuthorityCrlDALFactory, "create" | "findOne" | "update">;
|
||||||
certificateAuthorityQueue: TCertificateAuthorityQueueFactory; // TODO: Pick
|
certificateAuthorityQueue: TCertificateAuthorityQueueFactory; // TODO: Pick
|
||||||
certificateDAL: Pick<TCertificateDALFactory, "transaction" | "create" | "find">;
|
certificateDAL: Pick<TCertificateDALFactory, "transaction" | "create" | "find">;
|
||||||
certificateCertDAL: Pick<TCertificateCertDALFactory, "create">;
|
certificateCertDAL: Pick<TCertificateCertDALFactory, "create">;
|
||||||
projectDAL: Pick<TProjectDALFactory, "findProjectBySlug">;
|
projectDAL: Pick<TProjectDALFactory, "findProjectBySlug" | "findOne" | "updateById" | "findById" | "transaction">;
|
||||||
|
kmsService: Pick<TKmsServiceFactory, "generateKmsKey" | "encrypt" | "decrypt">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TCertificateAuthorityServiceFactory = ReturnType<typeof certificateAuthorityServiceFactory>;
|
export type TCertificateAuthorityServiceFactory = ReturnType<typeof certificateAuthorityServiceFactory>;
|
||||||
|
|
||||||
|
// TODO: reconsider build cert chain due to imported chains
|
||||||
|
|
||||||
export const certificateAuthorityServiceFactory = ({
|
export const certificateAuthorityServiceFactory = ({
|
||||||
certificateAuthorityDAL,
|
certificateAuthorityDAL,
|
||||||
certificateAuthorityCertDAL,
|
certificateAuthorityCertDAL,
|
||||||
certificateAuthoritySkDAL,
|
certificateAuthoritySecretDAL,
|
||||||
certificateAuthorityCrlDAL,
|
certificateAuthorityCrlDAL,
|
||||||
certificateDAL,
|
certificateDAL,
|
||||||
certificateCertDAL,
|
certificateCertDAL,
|
||||||
projectDAL,
|
projectDAL,
|
||||||
|
kmsService,
|
||||||
permissionService
|
permissionService
|
||||||
}: TCertificateAuthorityServiceFactoryDep) => {
|
}: TCertificateAuthorityServiceFactoryDep) => {
|
||||||
/**
|
/**
|
||||||
@@ -109,12 +115,6 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
const alg = keyAlgorithmToAlgCfg(keyAlgorithm);
|
const alg = keyAlgorithmToAlgCfg(keyAlgorithm);
|
||||||
const keys = await crypto.subtle.generateKey(alg, true, ["sign", "verify"]);
|
const keys = await crypto.subtle.generateKey(alg, true, ["sign", "verify"]);
|
||||||
|
|
||||||
// https://nodejs.org/api/crypto.html#static-method-keyobjectfromkey
|
|
||||||
const skObj = KeyObject.from(keys.privateKey);
|
|
||||||
const sk = skObj.export({ format: "pem", type: "pkcs8" }) as string;
|
|
||||||
const pkObj = KeyObject.from(keys.publicKey);
|
|
||||||
const pk = pkObj.export({ format: "pem", type: "spki" }) as string;
|
|
||||||
|
|
||||||
const newCa = await certificateAuthorityDAL.transaction(async (tx) => {
|
const newCa = await certificateAuthorityDAL.transaction(async (tx) => {
|
||||||
const notBeforeDate = notBefore ? new Date(notBefore) : new Date();
|
const notBeforeDate = notBefore ? new Date(notBefore) : new Date();
|
||||||
|
|
||||||
@@ -149,6 +149,12 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
|
|
||||||
// TODO: create CRL
|
// TODO: create CRL
|
||||||
|
|
||||||
|
const keyId = await getProjectKmsCertificateKeyId({
|
||||||
|
projectId: project.id,
|
||||||
|
projectDAL,
|
||||||
|
kmsService
|
||||||
|
});
|
||||||
|
|
||||||
if (type === CaType.ROOT) {
|
if (type === CaType.ROOT) {
|
||||||
// note: self-signed cert only applicable for root CA
|
// note: self-signed cert only applicable for root CA
|
||||||
|
|
||||||
@@ -167,12 +173,22 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
await x509.SubjectKeyIdentifierExtension.create(keys.publicKey)
|
await x509.SubjectKeyIdentifierExtension.create(keys.publicKey)
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
const certificate = cert.toString("pem");
|
|
||||||
|
const { cipherTextBlob: encryptedCertificate } = await kmsService.encrypt({
|
||||||
|
kmsId: keyId,
|
||||||
|
plainText: Buffer.from(new Uint8Array(cert.rawData))
|
||||||
|
});
|
||||||
|
|
||||||
|
const { cipherTextBlob: encryptedCertificateChain } = await kmsService.encrypt({
|
||||||
|
kmsId: keyId,
|
||||||
|
plainText: Buffer.alloc(0)
|
||||||
|
});
|
||||||
|
|
||||||
await certificateAuthorityCertDAL.create(
|
await certificateAuthorityCertDAL.create(
|
||||||
{
|
{
|
||||||
caId: ca.id,
|
caId: ca.id,
|
||||||
certificate, // TODO: encrypt
|
encryptedCertificate,
|
||||||
certificateChain: "" // TODO: encrypt
|
encryptedCertificateChain
|
||||||
},
|
},
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
@@ -187,11 +203,21 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
await certificateAuthoritySkDAL.create(
|
// https://nodejs.org/api/crypto.html#static-method-keyobjectfromkey
|
||||||
|
const skObj = KeyObject.from(keys.privateKey);
|
||||||
|
|
||||||
|
const { cipherTextBlob: encryptedPrivateKey } = await kmsService.encrypt({
|
||||||
|
kmsId: keyId,
|
||||||
|
plainText: skObj.export({
|
||||||
|
type: "pkcs8",
|
||||||
|
format: "der"
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
await certificateAuthoritySecretDAL.create(
|
||||||
{
|
{
|
||||||
caId: ca.id,
|
caId: ca.id,
|
||||||
pk, // TODO: encrypt
|
encryptedPrivateKey
|
||||||
sk // TODO: encrypt
|
|
||||||
},
|
},
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
@@ -290,16 +316,27 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
const caCert = await certificateAuthorityCertDAL.findOne({ caId: ca.id });
|
const caCert = await certificateAuthorityCertDAL.findOne({ caId: ca.id });
|
||||||
if (caCert) throw new BadRequestError({ message: "CA already has a certificate installed" });
|
if (caCert) throw new BadRequestError({ message: "CA already has a certificate installed" });
|
||||||
|
|
||||||
const caKeys = await certificateAuthoritySkDAL.findOne({ caId: ca.id });
|
const caKeys = await certificateAuthoritySecretDAL.findOne({ caId: ca.id });
|
||||||
|
|
||||||
const alg = keyAlgorithmToAlgCfg(ca.keyAlgorithm as CertKeyAlgorithm);
|
const alg = keyAlgorithmToAlgCfg(ca.keyAlgorithm as CertKeyAlgorithm);
|
||||||
|
|
||||||
const skObj = crypto.createPrivateKey({ key: caKeys.sk, format: "pem", type: "pkcs8" });
|
const keyId = await getProjectKmsCertificateKeyId({
|
||||||
const pkObj = crypto.createPublicKey({ key: caKeys.pk, format: "pem", type: "spki" });
|
projectId: ca.projectId,
|
||||||
|
projectDAL,
|
||||||
|
kmsService
|
||||||
|
});
|
||||||
|
|
||||||
|
const privateKey = await kmsService.decrypt({
|
||||||
|
kmsId: keyId,
|
||||||
|
cipherTextBlob: caKeys.encryptedPrivateKey
|
||||||
|
});
|
||||||
|
|
||||||
|
const skObj = crypto.createPrivateKey({ key: privateKey, format: "der", type: "pkcs8" });
|
||||||
const sk = await crypto.subtle.importKey("pkcs8", skObj.export({ format: "der", type: "pkcs8" }), alg, true, [
|
const sk = await crypto.subtle.importKey("pkcs8", skObj.export({ format: "der", type: "pkcs8" }), alg, true, [
|
||||||
"sign"
|
"sign"
|
||||||
]);
|
]);
|
||||||
|
const pkObj = crypto.createPublicKey(skObj);
|
||||||
|
|
||||||
const pk = await crypto.subtle.importKey("spki", pkObj.export({ format: "der", type: "spki" }), alg, true, [
|
const pk = await crypto.subtle.importKey("spki", pkObj.export({ format: "der", type: "spki" }), alg, true, [
|
||||||
"verify"
|
"verify"
|
||||||
]);
|
]);
|
||||||
@@ -344,11 +381,28 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const caCert = await certificateAuthorityCertDAL.findOne({ caId: ca.id });
|
const caCert = await certificateAuthorityCertDAL.findOne({ caId: ca.id });
|
||||||
const certObj = new x509.X509Certificate(caCert.certificate);
|
|
||||||
|
const keyId = await getProjectKmsCertificateKeyId({
|
||||||
|
projectId: ca.projectId,
|
||||||
|
projectDAL,
|
||||||
|
kmsService
|
||||||
|
});
|
||||||
|
|
||||||
|
const decryptedCaCert = await kmsService.decrypt({
|
||||||
|
kmsId: keyId,
|
||||||
|
cipherTextBlob: caCert.encryptedCertificate
|
||||||
|
});
|
||||||
|
|
||||||
|
const certObj = new x509.X509Certificate(decryptedCaCert);
|
||||||
|
|
||||||
|
const decryptedChain = await kmsService.decrypt({
|
||||||
|
kmsId: keyId,
|
||||||
|
cipherTextBlob: caCert.encryptedCertificateChain
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
certificate: caCert.certificate,
|
certificate: certObj.toString("pem"),
|
||||||
certificateChain: caCert.certificateChain,
|
certificateChain: decryptedChain.toString("utf-8"),
|
||||||
serialNumber: certObj.serialNumber
|
serialNumber: certObj.serialNumber
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -388,15 +442,31 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
|
|
||||||
const alg = keyAlgorithmToAlgCfg(ca.keyAlgorithm as CertKeyAlgorithm);
|
const alg = keyAlgorithmToAlgCfg(ca.keyAlgorithm as CertKeyAlgorithm);
|
||||||
|
|
||||||
const caCert = await certificateAuthorityCertDAL.findOne({ caId: ca.id });
|
const keyId = await getProjectKmsCertificateKeyId({
|
||||||
const caKeys = await certificateAuthoritySkDAL.findOne({ caId: ca.id });
|
projectId: ca.projectId,
|
||||||
|
projectDAL,
|
||||||
|
kmsService
|
||||||
|
});
|
||||||
|
|
||||||
const skObj = crypto.createPrivateKey({ key: caKeys.sk, format: "pem", type: "pkcs8" });
|
const caCert = await certificateAuthorityCertDAL.findOne({ caId: ca.id });
|
||||||
|
const caKeys = await certificateAuthoritySecretDAL.findOne({ caId: ca.id });
|
||||||
|
|
||||||
|
const privateKey = await kmsService.decrypt({
|
||||||
|
kmsId: keyId,
|
||||||
|
cipherTextBlob: caKeys.encryptedPrivateKey
|
||||||
|
});
|
||||||
|
|
||||||
|
const skObj = crypto.createPrivateKey({ key: privateKey, format: "der", type: "pkcs8" });
|
||||||
const sk = await crypto.subtle.importKey("pkcs8", skObj.export({ format: "der", type: "pkcs8" }), alg, true, [
|
const sk = await crypto.subtle.importKey("pkcs8", skObj.export({ format: "der", type: "pkcs8" }), alg, true, [
|
||||||
"sign"
|
"sign"
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const certObj = new x509.X509Certificate(caCert.certificate);
|
const decryptedCaCert = await kmsService.decrypt({
|
||||||
|
kmsId: keyId,
|
||||||
|
cipherTextBlob: caCert.encryptedCertificate
|
||||||
|
});
|
||||||
|
|
||||||
|
const certObj = new x509.X509Certificate(decryptedCaCert);
|
||||||
const csrObj = new x509.Pkcs10CertificateRequest(csr);
|
const csrObj = new x509.Pkcs10CertificateRequest(csr);
|
||||||
|
|
||||||
// check path length constraint
|
// check path length constraint
|
||||||
@@ -455,11 +525,22 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const chain = await certificateAuthorityDAL.buildCertificateChain(caId);
|
const chain = await certificateAuthorityDAL.buildCertificateChain(caId);
|
||||||
|
const decryptedChain = await Promise.all(
|
||||||
|
chain.map(async (c) => {
|
||||||
|
const decryptedCaChainCert = await kmsService.decrypt({
|
||||||
|
kmsId: keyId,
|
||||||
|
cipherTextBlob: c
|
||||||
|
});
|
||||||
|
|
||||||
|
const chainCertObj = new x509.X509Certificate(decryptedCaChainCert);
|
||||||
|
return chainCertObj.toString("pem");
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
certificate: intermediateCert.toString("pem"),
|
certificate: intermediateCert.toString("pem"),
|
||||||
issuingCaCertificate: caCert.certificate,
|
issuingCaCertificate: certObj.toString("pem"),
|
||||||
certificateChain: chain.join("\n"),
|
certificateChain: decryptedChain.join("\n"),
|
||||||
serialNumber: intermediateCert.serialNumber
|
serialNumber: intermediateCert.serialNumber
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -520,12 +601,28 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
dn: parentCertSubject
|
dn: parentCertSubject
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const keyId = await getProjectKmsCertificateKeyId({
|
||||||
|
projectId: ca.projectId,
|
||||||
|
projectDAL,
|
||||||
|
kmsService
|
||||||
|
});
|
||||||
|
|
||||||
|
const { cipherTextBlob: encryptedCertificate } = await kmsService.encrypt({
|
||||||
|
kmsId: keyId,
|
||||||
|
plainText: Buffer.from(new Uint8Array(certObj.rawData))
|
||||||
|
});
|
||||||
|
|
||||||
|
const { cipherTextBlob: encryptedCertificateChain } = await kmsService.encrypt({
|
||||||
|
kmsId: keyId,
|
||||||
|
plainText: Buffer.from(certificateChain)
|
||||||
|
});
|
||||||
|
|
||||||
await certificateAuthorityCertDAL.transaction(async (tx) => {
|
await certificateAuthorityCertDAL.transaction(async (tx) => {
|
||||||
await certificateAuthorityCertDAL.create(
|
await certificateAuthorityCertDAL.create(
|
||||||
{
|
{
|
||||||
caId: ca.id,
|
caId: ca.id,
|
||||||
certificate, // TODO: encrypt
|
encryptedCertificate,
|
||||||
certificateChain // TODO: encrypt
|
encryptedCertificateChain
|
||||||
},
|
},
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
@@ -569,18 +666,34 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Certificates);
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Certificates);
|
||||||
|
|
||||||
|
if (ca.status === CaStatus.DISABLED) throw new BadRequestError({ message: "CA is disabled" });
|
||||||
|
|
||||||
const caCert = await certificateAuthorityCertDAL.findOne({ caId: ca.id });
|
const caCert = await certificateAuthorityCertDAL.findOne({ caId: ca.id });
|
||||||
if (!caCert) throw new BadRequestError({ message: "CA does not have a certificate installed" });
|
if (!caCert) throw new BadRequestError({ message: "CA does not have a certificate installed" });
|
||||||
|
|
||||||
if (ca.status === CaStatus.DISABLED) throw new BadRequestError({ message: "CA is disabled" });
|
const keyId = await getProjectKmsCertificateKeyId({
|
||||||
|
projectId: ca.projectId,
|
||||||
|
projectDAL,
|
||||||
|
kmsService
|
||||||
|
});
|
||||||
|
|
||||||
const caCertObj = new x509.X509Certificate(caCert.certificate);
|
const decryptedCaCert = await kmsService.decrypt({
|
||||||
|
kmsId: keyId,
|
||||||
|
cipherTextBlob: caCert.encryptedCertificate
|
||||||
|
});
|
||||||
|
|
||||||
|
const caCertObj = new x509.X509Certificate(decryptedCaCert);
|
||||||
|
|
||||||
const alg = keyAlgorithmToAlgCfg(ca.keyAlgorithm as CertKeyAlgorithm);
|
const alg = keyAlgorithmToAlgCfg(ca.keyAlgorithm as CertKeyAlgorithm);
|
||||||
|
|
||||||
const caKeys = await certificateAuthoritySkDAL.findOne({ caId: ca.id });
|
const caKeys = await certificateAuthoritySecretDAL.findOne({ caId: ca.id });
|
||||||
|
|
||||||
const caSkObj = crypto.createPrivateKey({ key: caKeys.sk, format: "pem", type: "pkcs8" });
|
const privateKey = await kmsService.decrypt({
|
||||||
|
kmsId: keyId,
|
||||||
|
cipherTextBlob: caKeys.encryptedPrivateKey
|
||||||
|
});
|
||||||
|
|
||||||
|
const caSkObj = crypto.createPrivateKey({ key: privateKey, format: "der", type: "pkcs8" });
|
||||||
const caSk = await crypto.subtle.importKey("pkcs8", caSkObj.export({ format: "der", type: "pkcs8" }), alg, true, [
|
const caSk = await crypto.subtle.importKey("pkcs8", caSkObj.export({ format: "der", type: "pkcs8" }), alg, true, [
|
||||||
"sign"
|
"sign"
|
||||||
]);
|
]);
|
||||||
@@ -646,6 +759,28 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
|
|
||||||
const chain = await certificateAuthorityDAL.buildCertificateChain(caId);
|
const chain = await certificateAuthorityDAL.buildCertificateChain(caId);
|
||||||
|
|
||||||
|
const { cipherTextBlob: encryptedCertificate } = await kmsService.encrypt({
|
||||||
|
kmsId: keyId,
|
||||||
|
plainText: Buffer.from(new Uint8Array(leafCert.rawData))
|
||||||
|
});
|
||||||
|
|
||||||
|
const decryptedChain = await Promise.all(
|
||||||
|
chain.map(async (c) => {
|
||||||
|
const decryptedCaChainCert = await kmsService.decrypt({
|
||||||
|
kmsId: keyId,
|
||||||
|
cipherTextBlob: c
|
||||||
|
});
|
||||||
|
|
||||||
|
const certObj = new x509.X509Certificate(decryptedCaChainCert);
|
||||||
|
return certObj.toString("pem");
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const { cipherTextBlob: encryptedCertificateChain } = await kmsService.encrypt({
|
||||||
|
kmsId: keyId,
|
||||||
|
plainText: Buffer.from(decryptedChain.join("\n"))
|
||||||
|
});
|
||||||
|
|
||||||
await certificateDAL.transaction(async (tx) => {
|
await certificateDAL.transaction(async (tx) => {
|
||||||
const cert = await certificateDAL.create(
|
const cert = await certificateDAL.create(
|
||||||
{
|
{
|
||||||
@@ -662,8 +797,8 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
await certificateCertDAL.create(
|
await certificateCertDAL.create(
|
||||||
{
|
{
|
||||||
certId: cert.id,
|
certId: cert.id,
|
||||||
certificate: leafCert.toString("pem"), // TODO: encrypt
|
encryptedCertificate,
|
||||||
certificateChain: chain.join("\n") // TODO: encrypt
|
encryptedCertificateChain
|
||||||
},
|
},
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
@@ -673,8 +808,8 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
certificate: leafCert.toString("pem"),
|
certificate: leafCert.toString("pem"),
|
||||||
certificateChain: chain.join("\n"),
|
certificateChain: decryptedChain.join("\n"),
|
||||||
issuingCaCertificate: caCert.certificate,
|
issuingCaCertificate: caCertObj.toString("pem"),
|
||||||
privateKey: skLeaf,
|
privateKey: skLeaf,
|
||||||
serialNumber
|
serialNumber
|
||||||
};
|
};
|
||||||
@@ -700,10 +835,22 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
ProjectPermissionSub.CertificateAuthorities
|
ProjectPermissionSub.CertificateAuthorities
|
||||||
);
|
);
|
||||||
|
|
||||||
const caKeys = await certificateAuthoritySkDAL.findOne({ caId: ca.id });
|
const caKeys = await certificateAuthoritySecretDAL.findOne({ caId: ca.id });
|
||||||
|
|
||||||
const alg = keyAlgorithmToAlgCfg(ca.keyAlgorithm as CertKeyAlgorithm);
|
const alg = keyAlgorithmToAlgCfg(ca.keyAlgorithm as CertKeyAlgorithm);
|
||||||
const skObj = crypto.createPrivateKey({ key: caKeys.sk, format: "pem", type: "pkcs8" });
|
|
||||||
|
const keyId = await getProjectKmsCertificateKeyId({
|
||||||
|
projectId: ca.projectId,
|
||||||
|
projectDAL,
|
||||||
|
kmsService
|
||||||
|
});
|
||||||
|
|
||||||
|
const privateKey = await kmsService.decrypt({
|
||||||
|
kmsId: keyId,
|
||||||
|
cipherTextBlob: caKeys.encryptedPrivateKey
|
||||||
|
});
|
||||||
|
|
||||||
|
const skObj = crypto.createPrivateKey({ key: privateKey, format: "der", type: "pkcs8" });
|
||||||
const sk = await crypto.subtle.importKey("pkcs8", skObj.export({ format: "der", type: "pkcs8" }), alg, true, [
|
const sk = await crypto.subtle.importKey("pkcs8", skObj.export({ format: "der", type: "pkcs8" }), alg, true, [
|
||||||
"sign"
|
"sign"
|
||||||
]);
|
]);
|
||||||
@@ -755,10 +902,22 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
ProjectPermissionSub.CertificateAuthorities
|
ProjectPermissionSub.CertificateAuthorities
|
||||||
);
|
);
|
||||||
|
|
||||||
const caKeys = await certificateAuthoritySkDAL.findOne({ caId: ca.id });
|
const caKeys = await certificateAuthoritySecretDAL.findOne({ caId: ca.id });
|
||||||
|
|
||||||
const alg = keyAlgorithmToAlgCfg(ca.keyAlgorithm as CertKeyAlgorithm);
|
const alg = keyAlgorithmToAlgCfg(ca.keyAlgorithm as CertKeyAlgorithm);
|
||||||
const skObj = crypto.createPrivateKey({ key: caKeys.sk, format: "pem", type: "pkcs8" });
|
|
||||||
|
const keyId = await getProjectKmsCertificateKeyId({
|
||||||
|
projectId: ca.projectId,
|
||||||
|
projectDAL,
|
||||||
|
kmsService
|
||||||
|
});
|
||||||
|
|
||||||
|
const privateKey = await kmsService.decrypt({
|
||||||
|
kmsId: keyId,
|
||||||
|
cipherTextBlob: caKeys.encryptedPrivateKey
|
||||||
|
});
|
||||||
|
|
||||||
|
const skObj = crypto.createPrivateKey({ key: privateKey, format: "der", type: "pkcs8" });
|
||||||
const sk = await crypto.subtle.importKey("pkcs8", skObj.export({ format: "der", type: "pkcs8" }), alg, true, [
|
const sk = await crypto.subtle.importKey("pkcs8", skObj.export({ format: "der", type: "pkcs8" }), alg, true, [
|
||||||
"sign"
|
"sign"
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
import { TDbClient } from "@app/db";
|
|
||||||
import { TableName } from "@app/db/schemas";
|
|
||||||
import { ormify } from "@app/lib/knex";
|
|
||||||
|
|
||||||
export type TCertificateAuthoritySkDALFactory = ReturnType<typeof certificateAuthoritySkDALFactory>;
|
|
||||||
|
|
||||||
export const certificateAuthoritySkDALFactory = (db: TDbClient) => {
|
|
||||||
const caSkOrm = ormify(db, TableName.CertificateAuthoritySk);
|
|
||||||
return caSkOrm;
|
|
||||||
};
|
|
||||||
@@ -6,6 +6,9 @@ import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services
|
|||||||
import { TCertificateCertDALFactory } from "@app/services/certificate/certificate-cert-dal";
|
import { TCertificateCertDALFactory } from "@app/services/certificate/certificate-cert-dal";
|
||||||
import { TCertificateDALFactory } from "@app/services/certificate/certificate-dal";
|
import { TCertificateDALFactory } from "@app/services/certificate/certificate-dal";
|
||||||
import { TCertificateAuthorityDALFactory } from "@app/services/certificate-authority/certificate-authority-dal";
|
import { TCertificateAuthorityDALFactory } from "@app/services/certificate-authority/certificate-authority-dal";
|
||||||
|
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||||
|
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
||||||
|
import { getProjectKmsCertificateKeyId } from "@app/services/project/project-fns";
|
||||||
|
|
||||||
import { revocationReasonToCrlCode } from "./certificate-fns";
|
import { revocationReasonToCrlCode } from "./certificate-fns";
|
||||||
import { CertStatus, TDeleteCertDTO, TGetCertCertDTO, TGetCertDTO, TRevokeCertDTO } from "./certificate-types";
|
import { CertStatus, TDeleteCertDTO, TGetCertCertDTO, TGetCertDTO, TRevokeCertDTO } from "./certificate-types";
|
||||||
@@ -14,6 +17,8 @@ type TCertificateServiceFactoryDep = {
|
|||||||
certificateDAL: Pick<TCertificateDALFactory, "findOne" | "deleteById" | "update">;
|
certificateDAL: Pick<TCertificateDALFactory, "findOne" | "deleteById" | "update">;
|
||||||
certificateCertDAL: Pick<TCertificateCertDALFactory, "findOne">;
|
certificateCertDAL: Pick<TCertificateCertDALFactory, "findOne">;
|
||||||
certificateAuthorityDAL: Pick<TCertificateAuthorityDALFactory, "findById">;
|
certificateAuthorityDAL: Pick<TCertificateAuthorityDALFactory, "findById">;
|
||||||
|
projectDAL: Pick<TProjectDALFactory, "findOne" | "updateById" | "findById" | "transaction">;
|
||||||
|
kmsService: Pick<TKmsServiceFactory, "generateKmsKey" | "encrypt" | "decrypt">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -23,6 +28,8 @@ export const certificateServiceFactory = ({
|
|||||||
certificateDAL,
|
certificateDAL,
|
||||||
certificateCertDAL,
|
certificateCertDAL,
|
||||||
certificateAuthorityDAL,
|
certificateAuthorityDAL,
|
||||||
|
projectDAL,
|
||||||
|
kmsService,
|
||||||
permissionService
|
permissionService
|
||||||
}: TCertificateServiceFactoryDep) => {
|
}: TCertificateServiceFactoryDep) => {
|
||||||
const getCert = async ({ serialNumber, actorId, actorAuthMethod, actor, actorOrgId }: TGetCertDTO) => {
|
const getCert = async ({ serialNumber, actorId, actorAuthMethod, actor, actorOrgId }: TGetCertDTO) => {
|
||||||
@@ -113,11 +120,28 @@ export const certificateServiceFactory = ({
|
|||||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Certificates);
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Certificates);
|
||||||
|
|
||||||
const certCert = await certificateCertDAL.findOne({ certId: cert.id });
|
const certCert = await certificateCertDAL.findOne({ certId: cert.id });
|
||||||
const certObj = new x509.X509Certificate(certCert.certificate);
|
|
||||||
|
const keyId = await getProjectKmsCertificateKeyId({
|
||||||
|
projectId: ca.projectId,
|
||||||
|
projectDAL,
|
||||||
|
kmsService
|
||||||
|
});
|
||||||
|
|
||||||
|
const decryptedCert = await kmsService.decrypt({
|
||||||
|
kmsId: keyId,
|
||||||
|
cipherTextBlob: certCert.encryptedCertificate
|
||||||
|
});
|
||||||
|
|
||||||
|
const decryptedChain = await kmsService.decrypt({
|
||||||
|
kmsId: keyId,
|
||||||
|
cipherTextBlob: certCert.encryptedCertificateChain
|
||||||
|
});
|
||||||
|
|
||||||
|
const certObj = new x509.X509Certificate(decryptedCert);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
certificate: certCert.certificate,
|
certificate: certObj.toString("pem"),
|
||||||
certificateChain: certCert.certificateChain,
|
certificateChain: decryptedChain.toString("utf-8"),
|
||||||
serialNumber: certObj.serialNumber
|
serialNumber: certObj.serialNumber
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -29,19 +29,22 @@ export const kmsServiceFactory = ({ kmsDAL, kmsRootConfigDAL, keyStore }: TKmsSe
|
|||||||
let ROOT_ENCRYPTION_KEY = Buffer.alloc(0);
|
let ROOT_ENCRYPTION_KEY = Buffer.alloc(0);
|
||||||
|
|
||||||
// this is used symmetric encryption
|
// this is used symmetric encryption
|
||||||
const generateKmsKey = async ({ scopeId, scopeType, isReserved = true }: TGenerateKMSDTO) => {
|
const generateKmsKey = async ({ scopeId, scopeType, isReserved = true, tx }: TGenerateKMSDTO) => {
|
||||||
const cipher = symmetricCipherService(SymmetricEncryption.AES_GCM_256);
|
const cipher = symmetricCipherService(SymmetricEncryption.AES_GCM_256);
|
||||||
const kmsKeyMaterial = randomSecureBytes(32);
|
const kmsKeyMaterial = randomSecureBytes(32);
|
||||||
const encryptedKeyMaterial = cipher.encrypt(kmsKeyMaterial, ROOT_ENCRYPTION_KEY);
|
const encryptedKeyMaterial = cipher.encrypt(kmsKeyMaterial, ROOT_ENCRYPTION_KEY);
|
||||||
|
|
||||||
const { encryptedKey, ...doc } = await kmsDAL.create({
|
const { encryptedKey, ...doc } = await kmsDAL.create(
|
||||||
version: 1,
|
{
|
||||||
encryptedKey: encryptedKeyMaterial,
|
version: 1,
|
||||||
encryptionAlgorithm: SymmetricEncryption.AES_GCM_256,
|
encryptedKey: encryptedKeyMaterial,
|
||||||
isReserved,
|
encryptionAlgorithm: SymmetricEncryption.AES_GCM_256,
|
||||||
orgId: scopeType === "org" ? scopeId : undefined,
|
isReserved,
|
||||||
projectId: scopeType === "project" ? scopeId : undefined
|
orgId: scopeType === "org" ? scopeId : undefined,
|
||||||
});
|
projectId: scopeType === "project" ? scopeId : undefined
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
return doc;
|
return doc;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
export type TGenerateKMSDTO = {
|
export type TGenerateKMSDTO = {
|
||||||
scopeType: "project" | "org";
|
scopeType: "project" | "org";
|
||||||
scopeId: string;
|
scopeId: string;
|
||||||
isReserved?: boolean;
|
isReserved?: boolean;
|
||||||
|
tx?: Knex;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TEncryptWithKmsDTO = {
|
export type TEncryptWithKmsDTO = {
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import crypto from "crypto";
|
import crypto from "crypto";
|
||||||
|
|
||||||
import { decryptAsymmetric, encryptAsymmetric } from "@app/lib/crypto";
|
import { decryptAsymmetric, encryptAsymmetric } from "@app/lib/crypto";
|
||||||
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
|
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||||
|
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
||||||
|
|
||||||
import { AddUserToWsDTO } from "./project-types";
|
import { AddUserToWsDTO } from "./project-types";
|
||||||
|
|
||||||
@@ -49,3 +52,44 @@ export const createProjectKey = ({ publicKey, privateKey, plainProjectKey }: TCr
|
|||||||
|
|
||||||
return { key: encryptedProjectKey, iv: encryptedProjectKeyIv };
|
return { key: encryptedProjectKey, iv: encryptedProjectKeyIv };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getProjectKmsCertificateKeyId = async ({
|
||||||
|
projectId,
|
||||||
|
projectDAL,
|
||||||
|
kmsService
|
||||||
|
}: {
|
||||||
|
projectId: string;
|
||||||
|
projectDAL: Pick<TProjectDALFactory, "findOne" | "updateById" | "findById" | "transaction">;
|
||||||
|
kmsService: Pick<TKmsServiceFactory, "generateKmsKey">;
|
||||||
|
}) => {
|
||||||
|
const keyId = await projectDAL.transaction(async (tx) => {
|
||||||
|
const project = await projectDAL.findOne({ id: projectId }, tx);
|
||||||
|
if (!project) {
|
||||||
|
throw new BadRequestError({ message: "Project not found" });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!project.kmsCertificateKeyId) {
|
||||||
|
// create default kms key for certificate service
|
||||||
|
const key = await kmsService.generateKmsKey({
|
||||||
|
scopeId: projectId,
|
||||||
|
scopeType: "project",
|
||||||
|
isReserved: true,
|
||||||
|
tx
|
||||||
|
});
|
||||||
|
|
||||||
|
await projectDAL.updateById(
|
||||||
|
projectId,
|
||||||
|
{
|
||||||
|
kmsCertificateKeyId: key.id
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
|
||||||
|
return key.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return project.kmsCertificateKeyId;
|
||||||
|
});
|
||||||
|
|
||||||
|
return keyId;
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user