misc: continued migration to new ca structure

This commit is contained in:
Sheen Capadngan
2025-05-14 04:08:57 +08:00
parent b0e25a8bd1
commit 6b95bb0ceb
17 changed files with 291 additions and 2047 deletions

View File

@@ -7,6 +7,7 @@ import { TPermissionServiceFactory } from "@app/ee/services/permission/permissio
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
import { NotFoundError } from "@app/lib/errors";
import { TCertificateAuthorityDALFactory } from "@app/services/certificate-authority/certificate-authority-dal";
import { expandInternalCa } from "@app/services/certificate-authority/certificate-authority-fns";
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
import { TProjectDALFactory } from "@app/services/project/project-dal";
import { getProjectKmsCertificateKeyId } from "@app/services/project/project-fns";
@@ -14,7 +15,7 @@ import { getProjectKmsCertificateKeyId } from "@app/services/project/project-fns
import { TGetCaCrlsDTO, TGetCrlById } from "./certificate-authority-crl-types";
type TCertificateAuthorityCrlServiceFactoryDep = {
certificateAuthorityDAL: Pick<TCertificateAuthorityDALFactory, "findById">;
certificateAuthorityDAL: Pick<TCertificateAuthorityDALFactory, "findByIdWithAssociatedCa">;
certificateAuthorityCrlDAL: Pick<TCertificateAuthorityCrlDALFactory, "find" | "findById">;
projectDAL: Pick<TProjectDALFactory, "findOne" | "updateById" | "transaction">;
kmsService: Pick<TKmsServiceFactory, "decryptWithKmsKey" | "generateKmsKey">;
@@ -37,7 +38,8 @@ export const certificateAuthorityCrlServiceFactory = ({
const caCrl = await certificateAuthorityCrlDAL.findById(crlId);
if (!caCrl) throw new NotFoundError({ message: `CRL with ID '${crlId}' not found` });
const ca = await certificateAuthorityDAL.findById(caCrl.caId);
const ca = await certificateAuthorityDAL.findByIdWithAssociatedCa(caCrl.caId);
if (!ca?.internalCa) throw new NotFoundError({ message: `CA with ID '${caCrl.caId}' not found` });
const keyId = await getProjectKmsCertificateKeyId({
projectId: ca.projectId,
@@ -54,7 +56,7 @@ export const certificateAuthorityCrlServiceFactory = ({
const crl = new x509.X509Crl(decryptedCrl);
return {
ca,
ca: expandInternalCa(ca),
caCrl,
crl: crl.rawData
};
@@ -64,8 +66,8 @@ export const certificateAuthorityCrlServiceFactory = ({
* Returns a list of CRL ids for CA with id [caId]
*/
const getCaCrls = async ({ caId, actorId, actorAuthMethod, actor, actorOrgId }: TGetCaCrlsDTO) => {
const ca = await certificateAuthorityDAL.findById(caId);
if (!ca) throw new NotFoundError({ message: `CA with ID '${caId}' not found` });
const ca = await certificateAuthorityDAL.findByIdWithAssociatedCa(caId);
if (!ca?.internalCa) throw new NotFoundError({ message: `CA with ID '${caId}' not found` });
const { permission } = await permissionService.getProjectPermission({
actor,
@@ -108,7 +110,7 @@ export const certificateAuthorityCrlServiceFactory = ({
);
return {
ca,
ca: expandInternalCa(ca),
crls: decryptedCrls
};
};

View File

@@ -6,7 +6,7 @@ import { isCertChainValid } from "@app/services/certificate/certificate-fns";
import { TCertificateAuthorityCertDALFactory } from "@app/services/certificate-authority/certificate-authority-cert-dal";
import { TCertificateAuthorityDALFactory } from "@app/services/certificate-authority/certificate-authority-dal";
import { getCaCertChain, getCaCertChains } from "@app/services/certificate-authority/certificate-authority-fns";
import { TCertificateAuthorityServiceFactory } from "@app/services/certificate-authority/certificate-authority-service";
import { TInternalCertificateAuthorityServiceFactory } from "@app/services/certificate-authority/internal-certificate-authority-service";
import { TCertificateTemplateDALFactory } from "@app/services/certificate-template/certificate-template-dal";
import { TCertificateTemplateServiceFactory } from "@app/services/certificate-template/certificate-template-service";
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
@@ -16,10 +16,10 @@ import { TLicenseServiceFactory } from "../license/license-service";
import { convertRawCertsToPkcs7 } from "./certificate-est-fns";
type TCertificateEstServiceFactoryDep = {
certificateAuthorityService: Pick<TCertificateAuthorityServiceFactory, "signCertFromCa">;
internalCertificateAuthorityService: Pick<TInternalCertificateAuthorityServiceFactory, "signCertFromCa">;
certificateTemplateService: Pick<TCertificateTemplateServiceFactory, "getEstConfiguration">;
certificateTemplateDAL: Pick<TCertificateTemplateDALFactory, "findById">;
certificateAuthorityDAL: Pick<TCertificateAuthorityDALFactory, "findById">;
certificateAuthorityDAL: Pick<TCertificateAuthorityDALFactory, "findById" | "findByIdWithAssociatedCa">;
certificateAuthorityCertDAL: Pick<TCertificateAuthorityCertDALFactory, "find" | "findById">;
projectDAL: Pick<TProjectDALFactory, "findOne" | "updateById" | "transaction">;
kmsService: Pick<TKmsServiceFactory, "decryptWithKmsKey" | "generateKmsKey">;
@@ -29,7 +29,7 @@ type TCertificateEstServiceFactoryDep = {
export type TCertificateEstServiceFactory = ReturnType<typeof certificateEstServiceFactory>;
export const certificateEstServiceFactory = ({
certificateAuthorityService,
internalCertificateAuthorityService,
certificateTemplateService,
certificateTemplateDAL,
certificateAuthorityCertDAL,
@@ -127,7 +127,7 @@ export const certificateEstServiceFactory = ({
});
}
const { certificate } = await certificateAuthorityService.signCertFromCa({
const { certificate } = await internalCertificateAuthorityService.signCertFromCa({
isInternal: true,
certificateTemplateId,
csr
@@ -188,7 +188,7 @@ export const certificateEstServiceFactory = ({
}
}
const { certificate } = await certificateAuthorityService.signCertFromCa({
const { certificate } = await internalCertificateAuthorityService.signCertFromCa({
isInternal: true,
certificateTemplateId,
csr
@@ -227,15 +227,15 @@ export const certificateEstServiceFactory = ({
});
}
const ca = await certificateAuthorityDAL.findById(certTemplate.caId);
if (!ca) {
const ca = await certificateAuthorityDAL.findByIdWithAssociatedCa(certTemplate.caId);
if (!ca?.internalCa) {
throw new NotFoundError({
message: `Certificate Authority with ID '${certTemplate.caId}' not found`
});
}
const { caCert, caCertChain } = await getCaCertChain({
caCertId: ca.activeCaCertId as string,
caCertId: ca.internalCa.activeCaCertId as string,
certificateAuthorityDAL,
certificateAuthorityCertDAL,
projectDAL,

View File

@@ -959,7 +959,7 @@ export const registerRoutes = async (
});
const certificateEstService = certificateEstServiceFactory({
certificateAuthorityService,
internalCertificateAuthorityService,
certificateTemplateService,
certificateTemplateDAL,
certificateAuthorityCertDAL,

View File

@@ -1,9 +1,11 @@
import { z } from "zod";
import {
CertificateAuthoritiesSchema,
DynamicSecretsSchema,
IdentityProjectAdditionalPrivilegeSchema,
IntegrationAuthsSchema,
InternalCertificateAuthoritiesSchema,
ProjectRolesSchema,
ProjectsSchema,
SecretApprovalPoliciesSchema,
@@ -271,3 +273,7 @@ export const SanitizedTagSchema = SecretTagsSchema.pick({
}).extend({
name: z.string()
});
export const InternalCertificateAuthorityResponseSchema = CertificateAuthoritiesSchema.merge(
InternalCertificateAuthoritiesSchema
);

View File

@@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-floating-promises */
import { z } from "zod";
import { CertificateAuthoritiesSchema, CertificateTemplatesSchema } from "@app/db/schemas";
import { CertificateTemplatesSchema } from "@app/db/schemas";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { ApiDocsTags, CERTIFICATE_AUTHORITIES } from "@app/lib/api-docs";
import { ms } from "@app/lib/ms";
@@ -17,6 +17,8 @@ import {
} from "@app/services/certificate-authority/certificate-authority-validators";
import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types";
import { InternalCertificateAuthorityResponseSchema } from "../sanitizedSchemas";
export const registerCaRouter = async (server: FastifyZodProvider) => {
server.route({
method: "POST",
@@ -68,7 +70,7 @@ export const registerCaRouter = async (server: FastifyZodProvider) => {
),
response: {
200: z.object({
ca: CertificateAuthoritiesSchema
ca: InternalCertificateAuthorityResponseSchema
})
}
},
@@ -115,7 +117,7 @@ export const registerCaRouter = async (server: FastifyZodProvider) => {
}),
response: {
200: z.object({
ca: CertificateAuthoritiesSchema
ca: InternalCertificateAuthorityResponseSchema
})
}
},
@@ -198,7 +200,7 @@ export const registerCaRouter = async (server: FastifyZodProvider) => {
}),
response: {
200: z.object({
ca: CertificateAuthoritiesSchema
ca: InternalCertificateAuthorityResponseSchema
})
}
},
@@ -247,7 +249,7 @@ export const registerCaRouter = async (server: FastifyZodProvider) => {
}),
response: {
200: z.object({
ca: CertificateAuthoritiesSchema
ca: InternalCertificateAuthorityResponseSchema
})
}
},

View File

@@ -242,7 +242,7 @@ export const registerCertRouter = async (server: FastifyZodProvider) => {
},
handler: async (req) => {
const { certificate, certificateChain, issuingCaCertificate, privateKey, serialNumber, ca } =
await server.services.certificateAuthority.issueCertFromCa({
await server.services.internalCertificateAuthority.issueCertFromCa({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
@@ -355,7 +355,7 @@ export const registerCertRouter = async (server: FastifyZodProvider) => {
},
handler: async (req) => {
const { certificate, certificateChain, issuingCaCertificate, serialNumber, ca, commonName } =
await server.services.certificateAuthority.signCertFromCa({
await server.services.internalCertificateAuthority.signCertFromCa({
isInternal: false,
actor: req.permission.type,
actorId: req.permission.id,

View File

@@ -1,7 +1,6 @@
import { z } from "zod";
import {
CertificateAuthoritiesSchema,
CertificatesSchema,
PkiAlertsSchema,
PkiCollectionsSchema,
@@ -28,7 +27,7 @@ import { sanitizedPkiSubscriber } from "@app/services/pki-subscriber/pki-subscri
import { ProjectFilterType } from "@app/services/project/project-types";
import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types";
import { SanitizedProjectSchema } from "../sanitizedSchemas";
import { InternalCertificateAuthorityResponseSchema, SanitizedProjectSchema } from "../sanitizedSchemas";
const projectWithEnv = SanitizedProjectSchema.extend({
_id: z.string(),
@@ -366,7 +365,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
}),
response: {
200: z.object({
cas: z.array(CertificateAuthoritiesSchema)
cas: z.array(InternalCertificateAuthorityResponseSchema)
})
}
},

View File

@@ -1,12 +1,16 @@
import { Knex } from "knex";
import { TDbClient } from "@app/db";
import { CertificateAuthoritiesSchema, TableName } from "@app/db/schemas";
import { CertificateAuthoritiesSchema, TableName, TCertificateAuthorities } from "@app/db/schemas";
import { DatabaseError } from "@app/lib/errors";
import { ormify, selectAllTableCols } from "@app/lib/knex";
import { ormify, selectAllTableCols, TFindOpt } from "@app/lib/knex";
export type TCertificateAuthorityDALFactory = ReturnType<typeof certificateAuthorityDALFactory>;
export type TCertificateAuthorityWithAssociatedCa = Awaited<
ReturnType<TCertificateAuthorityDALFactory["findByIdWithAssociatedCa"]>
>;
export const certificateAuthorityDALFactory = (db: TDbClient) => {
const caOrm = ormify(db, TableName.CertificateAuthority);
@@ -109,8 +113,91 @@ export const certificateAuthorityDALFactory = (db: TDbClient) => {
}
};
const findWithAssociatedCa = async (
filter: Parameters<(typeof caOrm)["find"]>[0] & { dn?: string },
{ offset, limit, sort = [["createdAt", "desc"]] }: TFindOpt<TCertificateAuthorities> = {},
tx?: Knex
) => {
try {
const query = (tx || db.replicaNode())(TableName.CertificateAuthority)
.leftJoin(
TableName.InternalCertificateAuthority,
`${TableName.CertificateAuthority}.id`,
`${TableName.InternalCertificateAuthority}.certificateAuthorityId`
)
.where(filter)
.select(selectAllTableCols(TableName.CertificateAuthority))
.select(
db.ref("id").withSchema(TableName.InternalCertificateAuthority).as("internalCaId"),
db.ref("parentCaId").withSchema(TableName.InternalCertificateAuthority).as("internalParentCaId"),
db.ref("type").withSchema(TableName.InternalCertificateAuthority).as("internalType"),
db.ref("status").withSchema(TableName.InternalCertificateAuthority).as("internalStatus"),
db.ref("friendlyName").withSchema(TableName.InternalCertificateAuthority).as("internalFriendlyName"),
db.ref("organization").withSchema(TableName.InternalCertificateAuthority).as("internalOrganization"),
db.ref("ou").withSchema(TableName.InternalCertificateAuthority).as("internalOu"),
db.ref("country").withSchema(TableName.InternalCertificateAuthority).as("internalCountry"),
db.ref("province").withSchema(TableName.InternalCertificateAuthority).as("internalProvince"),
db.ref("locality").withSchema(TableName.InternalCertificateAuthority).as("internalLocality"),
db.ref("commonName").withSchema(TableName.InternalCertificateAuthority).as("internalCommonName"),
db.ref("dn").withSchema(TableName.InternalCertificateAuthority).as("internalDn"),
db.ref("serialNumber").withSchema(TableName.InternalCertificateAuthority).as("internalSerialNumber"),
db.ref("maxPathLength").withSchema(TableName.InternalCertificateAuthority).as("internalMaxPathLength"),
db.ref("keyAlgorithm").withSchema(TableName.InternalCertificateAuthority).as("internalKeyAlgorithm"),
db.ref("notBefore").withSchema(TableName.InternalCertificateAuthority).as("internalNotBefore"),
db.ref("notAfter").withSchema(TableName.InternalCertificateAuthority).as("internalNotAfter"),
db.ref("activeCaCertId").withSchema(TableName.InternalCertificateAuthority).as("internalActiveCaCertId"),
db
.ref("certificateAuthorityId")
.withSchema(TableName.InternalCertificateAuthority)
.as("internalCertificateAuthorityId")
);
if (limit) void query.limit(limit);
if (offset) void query.offset(offset);
if (sort) {
void query.orderBy(
sort.map(([column, order, nulls]) => ({
column,
order,
nulls
}))
);
}
return (await query).map((ca) => ({
...CertificateAuthoritiesSchema.parse(ca),
internalCa: ca
? {
id: ca.internalCaId,
parentCaId: ca.internalParentCaId,
type: ca.internalType,
status: ca.internalStatus,
friendlyName: ca.internalFriendlyName,
organization: ca.internalOrganization,
ou: ca.internalOu,
country: ca.internalCountry,
province: ca.internalProvince,
locality: ca.internalLocality,
commonName: ca.internalCommonName,
dn: ca.internalDn,
serialNumber: ca.internalSerialNumber,
maxPathLength: ca.internalMaxPathLength,
keyAlgorithm: ca.internalKeyAlgorithm,
notBefore: ca.internalNotBefore,
notAfter: ca.internalNotAfter,
activeCaCertId: ca.internalActiveCaCertId,
certificateAuthorityId: ca.internalCertificateAuthorityId
}
: undefined
}));
} catch (error) {
throw new DatabaseError({ error, name: "Find - Certificate Authority" });
}
};
return {
...caOrm,
findWithAssociatedCa,
buildCertificateChain,
findByIdWithAssociatedCa
};

View File

@@ -113,8 +113,8 @@ export const getCaCredentials = async ({
projectDAL,
kmsService
}: TGetCaCredentialsDTO) => {
const ca = await certificateAuthorityDAL.findById(caId);
if (!ca) throw new NotFoundError({ message: `CA with ID '${caId}' not found` });
const ca = await certificateAuthorityDAL.findByIdWithAssociatedCa(caId);
if (!ca?.internalCa) throw new NotFoundError({ message: `CA with ID '${caId}' not found` });
const caSecret = await certificateAuthoritySecretDAL.findOne({ caId });
if (!caSecret) throw new NotFoundError({ message: `CA secret for CA with ID '${caId}' not found` });
@@ -132,7 +132,7 @@ export const getCaCredentials = async ({
cipherTextBlob: caSecret.encryptedPrivateKey
});
const alg = keyAlgorithmToAlgCfg(ca.keyAlgorithm as CertKeyAlgorithm);
const alg = keyAlgorithmToAlgCfg(ca.internalCa.keyAlgorithm as CertKeyAlgorithm);
const skObj = crypto.createPrivateKey({ key: decryptedPrivateKey, format: "der", type: "pkcs8" });
const caPrivateKey = await crypto.subtle.importKey(
"pkcs8",
@@ -256,12 +256,12 @@ export const rebuildCaCrl = async ({
certificateDAL,
kmsService
}: TRebuildCaCrlDTO) => {
const ca = await certificateAuthorityDAL.findById(caId);
if (!ca) throw new NotFoundError({ message: `CA with ID '${caId}' not found` });
const ca = await certificateAuthorityDAL.findByIdWithAssociatedCa(caId);
if (!ca?.internalCa) throw new NotFoundError({ message: `CA with ID '${caId}' not found` });
const caSecret = await certificateAuthoritySecretDAL.findOne({ caId: ca.id });
const alg = keyAlgorithmToAlgCfg(ca.keyAlgorithm as CertKeyAlgorithm);
const alg = keyAlgorithmToAlgCfg(ca.internalCa.keyAlgorithm as CertKeyAlgorithm);
const keyId = await getProjectKmsCertificateKeyId({
projectId: ca.projectId,
@@ -288,7 +288,7 @@ export const rebuildCaCrl = async ({
});
const crl = await x509.X509CrlGenerator.create({
issuer: ca.dn,
issuer: ca.internalCa.dn,
thisUpdate: new Date(),
nextUpdate: new Date("2025/12/12"),
entries: revokedCerts.map((revokedCert) => {
@@ -322,7 +322,12 @@ export const rebuildCaCrl = async ({
export const expandInternalCa = (
ca: Awaited<ReturnType<TCertificateAuthorityDALFactory["findByIdWithAssociatedCa"]>>
) => ({
...ca,
...ca.internalCa
});
) => {
if (!ca.internalCa) {
throw new Error("Internal CA must be defined");
}
return {
...ca.internalCa,
...ca
} as const;
};

View File

@@ -75,12 +75,12 @@ export const certificateAuthorityQueueFactory = ({
const { caId } = job.data;
logger.info(`secretReminderQueue.process: [secretDocument=${caId}]`);
const ca = await certificateAuthorityDAL.findById(caId);
if (!ca) throw new NotFoundError({ message: `CA with ID '${caId}' not found` });
const ca = await certificateAuthorityDAL.findByIdWithAssociatedCa(caId);
if (!ca.internalCa) throw new NotFoundError({ message: `CA with ID '${caId}' not found` });
const caSecret = await certificateAuthoritySecretDAL.findOne({ caId: ca.id });
const alg = keyAlgorithmToAlgCfg(ca.keyAlgorithm as CertKeyAlgorithm);
const alg = keyAlgorithmToAlgCfg(ca.internalCa.keyAlgorithm as CertKeyAlgorithm);
const keyId = await getProjectKmsCertificateKeyId({
projectId: ca.projectId,
@@ -106,7 +106,7 @@ export const certificateAuthorityQueueFactory = ({
});
const crl = await x509.X509CrlGenerator.create({
issuer: ca.dn,
issuer: ca.internalCa.dn,
thisUpdate: new Date(),
nextUpdate: new Date("2025/12/12"), // TODO: depends on configured rebuild interval
entries: revokedCerts.map((revokedCert) => {
@@ -115,7 +115,7 @@ export const certificateAuthorityQueueFactory = ({
revocationDate: new Date(revokedCert.revokedAt as Date),
reason: revokedCert.revocationReason as number,
invalidity: new Date("2022/01/01"),
issuer: ca.dn
issuer: ca.internalCa?.dn
};
}),
signingAlgorithm: alg,

View File

@@ -148,7 +148,7 @@ export type TDNParts = {
export type TGetCaCredentialsDTO = {
caId: string;
certificateAuthorityDAL: Pick<TCertificateAuthorityDALFactory, "findById">;
certificateAuthorityDAL: Pick<TCertificateAuthorityDALFactory, "findByIdWithAssociatedCa">;
certificateAuthoritySecretDAL: Pick<TCertificateAuthoritySecretDALFactory, "findOne">;
projectDAL: Pick<TProjectDALFactory, "findOne" | "updateById" | "transaction">;
kmsService: Pick<TKmsServiceFactory, "decryptWithKmsKey" | "generateKmsKey">;
@@ -172,7 +172,7 @@ export type TGetCaCertChainDTO = {
export type TRebuildCaCrlDTO = {
caId: string;
certificateAuthorityDAL: Pick<TCertificateAuthorityDALFactory, "findById">;
certificateAuthorityDAL: Pick<TCertificateAuthorityDALFactory, "findByIdWithAssociatedCa">;
certificateAuthorityCrlDAL: Pick<TCertificateAuthorityCrlDALFactory, "update">;
certificateAuthoritySecretDAL: Pick<TCertificateAuthoritySecretDALFactory, "findOne">;
projectDAL: Pick<TProjectDALFactory, "findOne" | "updateById" | "transaction">;

View File

@@ -4,7 +4,13 @@ import * as x509 from "@peculiar/x509";
import crypto, { KeyObject } from "crypto";
import { z } from "zod";
import { ActionProjectType, ProjectType, TCertificateAuthorities, TCertificateTemplates } from "@app/db/schemas";
import {
ActionProjectType,
ProjectType,
TableName,
TCertificateAuthorities,
TCertificateTemplates
} from "@app/db/schemas";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
import {
ProjectPermissionActions,
@@ -36,7 +42,7 @@ import {
import { TCertificateTemplateDALFactory } from "../certificate-template/certificate-template-dal";
import { validateCertificateDetailsAgainstTemplate } from "../certificate-template/certificate-template-fns";
import { TCertificateAuthorityCertDALFactory } from "./certificate-authority-cert-dal";
import { TCertificateAuthorityDALFactory } from "./certificate-authority-dal";
import { TCertificateAuthorityDALFactory, TCertificateAuthorityWithAssociatedCa } from "./certificate-authority-dal";
import {
createDistinguishedName,
createSerialNumber,
@@ -71,7 +77,14 @@ import { TInternalCertificateAuthorityDALFactory } from "./internal-certificate-
type TInternalCertificateAuthorityServiceFactoryDep = {
certificateAuthorityDAL: Pick<
TCertificateAuthorityDALFactory,
"transaction" | "create" | "findById" | "updateById" | "deleteById" | "findOne" | "findByIdWithAssociatedCa"
| "transaction"
| "create"
| "findById"
| "updateById"
| "deleteById"
| "findOne"
| "findByIdWithAssociatedCa"
| "findWithAssociatedCa"
>;
internalCertificateAuthorityDAL: Pick<
TInternalCertificateAuthorityDALFactory,
@@ -371,8 +384,19 @@ export const internalCertificateAuthorityServiceFactory = ({
);
const updatedCa = await certificateAuthorityDAL.transaction(async (tx) => {
await internalCertificateAuthorityDAL.updateById(caId, { status }, tx);
await certificateAuthorityDAL.updateById(ca.id, { disableDirectIssuance: requireTemplateForIssuance }, tx);
if (status) {
await internalCertificateAuthorityDAL.update(
{
certificateAuthorityId: ca.id
},
{ status },
tx
);
}
if (requireTemplateForIssuance) {
await certificateAuthorityDAL.updateById(ca.id, { disableDirectIssuance: requireTemplateForIssuance }, tx);
}
return certificateAuthorityDAL.findByIdWithAssociatedCa(caId, tx);
});
@@ -401,15 +425,9 @@ export const internalCertificateAuthorityServiceFactory = ({
ProjectPermissionSub.CertificateAuthorities
);
return certificateAuthorityDAL.transaction(async (tx) => {
const deletedInternalCa = await internalCertificateAuthorityDAL.deleteById(caId, tx);
const deletedCa = await certificateAuthorityDAL.deleteById(ca.id, tx);
await certificateAuthorityDAL.deleteById(ca.id);
return {
...deletedCa,
...deletedInternalCa
};
});
return expandInternalCa(ca);
};
/**
@@ -466,7 +484,7 @@ export const internalCertificateAuthorityServiceFactory = ({
return {
csr: csrObj.toString("pem"),
ca
ca: expandInternalCa(ca)
};
};
@@ -884,8 +902,8 @@ export const internalCertificateAuthorityServiceFactory = ({
maxPathLength
}: TSignIntermediateDTO) => {
const appCfg = getConfig();
const ca = await certificateAuthorityDAL.findById(caId);
if (!ca) throw new NotFoundError({ message: "CA not found" });
const ca = await certificateAuthorityDAL.findByIdWithAssociatedCa(caId);
if (!ca.internalCa) throw new NotFoundError({ message: "CA not found" });
const { permission } = await permissionService.getProjectPermission({
actor,
@@ -901,16 +919,17 @@ export const internalCertificateAuthorityServiceFactory = ({
ProjectPermissionSub.CertificateAuthorities
);
if (ca.status === CaStatus.DISABLED) throw new BadRequestError({ message: "CA is disabled" });
if (!ca.activeCaCertId) throw new BadRequestError({ message: "CA does not have a certificate installed" });
if (ca.internalCa.status === CaStatus.DISABLED) throw new BadRequestError({ message: "CA is disabled" });
if (!ca.internalCa.activeCaCertId)
throw new BadRequestError({ message: "CA does not have a certificate installed" });
const caCert = await certificateAuthorityCertDAL.findById(ca.activeCaCertId);
const caCert = await certificateAuthorityCertDAL.findById(ca.internalCa.activeCaCertId);
if (ca.notAfter && new Date() > new Date(ca.notAfter)) {
if (ca.internalCa.notAfter && new Date() > new Date(ca.internalCa.notAfter)) {
throw new BadRequestError({ message: "CA is expired" });
}
const alg = keyAlgorithmToAlgCfg(ca.keyAlgorithm as CertKeyAlgorithm);
const alg = keyAlgorithmToAlgCfg(ca.internalCa.keyAlgorithm as CertKeyAlgorithm);
const certificateManagerKmsId = await getProjectKmsCertificateKeyId({
projectId: ca.projectId,
@@ -1001,7 +1020,7 @@ export const internalCertificateAuthorityServiceFactory = ({
});
const { caCert: issuingCaCertificate, caCertChain } = await getCaCertChain({
caCertId: ca.activeCaCertId,
caCertId: ca.internalCa.activeCaCertId,
certificateAuthorityDAL,
certificateAuthorityCertDAL,
projectDAL,
@@ -1013,7 +1032,7 @@ export const internalCertificateAuthorityServiceFactory = ({
issuingCaCertificate,
certificateChain: `${issuingCaCertificate}\n${caCertChain}`.trim(),
serialNumber: intermediateCert.serialNumber,
ca
ca: expandInternalCa(ca)
};
};
@@ -1031,8 +1050,8 @@ export const internalCertificateAuthorityServiceFactory = ({
certificate,
certificateChain
}: TImportCertToCaDTO) => {
const ca = await certificateAuthorityDAL.findById(caId);
if (!ca) throw new NotFoundError({ message: `CA with ID '${caId}' not found` });
const ca = await certificateAuthorityDAL.findByIdWithAssociatedCa(caId);
if (!ca.internalCa) throw new NotFoundError({ message: `CA with ID '${caId}' not found` });
const { permission } = await permissionService.getProjectPermission({
actor,
@@ -1048,7 +1067,7 @@ export const internalCertificateAuthorityServiceFactory = ({
ProjectPermissionSub.CertificateAuthorities
);
if (ca.parentCaId) {
if (ca.internalCa.parentCaId) {
/**
* re-evaluate in the future if we should allow users to import a new CA certificate for an intermediate
* CA chained to an internal parent CA. Doing so would allow users to re-chain the CA to a different
@@ -1059,7 +1078,9 @@ export const internalCertificateAuthorityServiceFactory = ({
});
}
const caCert = ca.activeCaCertId ? await certificateAuthorityCertDAL.findById(ca.activeCaCertId) : undefined;
const caCert = ca.internalCa.activeCaCertId
? await certificateAuthorityCertDAL.findById(ca.internalCa.activeCaCertId)
: undefined;
const certObj = new x509.X509Certificate(certificate);
const maxPathLength = certObj.getExtension(x509.BasicConstraintsExtension)?.pathLength;
@@ -1082,9 +1103,9 @@ export const internalCertificateAuthorityServiceFactory = ({
const parentCertObj = chainItems[1];
const parentCertSubject = parentCertObj.subject;
const parentCa = await certificateAuthorityDAL.findOne({
projectId: ca.projectId,
dn: parentCertSubject
const [parentCa] = await certificateAuthorityDAL.findWithAssociatedCa({
[`${TableName.CertificateAuthority}.projectId` as "projectId"]: ca.projectId,
[`${TableName.InternalCertificateAuthority}.dn` as "dn"]: parentCertSubject
});
const certificateManagerKmsId = await getProjectKmsCertificateKeyId({
@@ -1134,8 +1155,10 @@ export const internalCertificateAuthorityServiceFactory = ({
tx
);
await certificateAuthorityDAL.updateById(
ca.id,
await internalCertificateAuthorityDAL.update(
{
certificateAuthorityId: ca.id
},
{
status: CaStatus.ACTIVE,
maxPathLength: maxPathLength === undefined ? -1 : maxPathLength,
@@ -1149,7 +1172,7 @@ export const internalCertificateAuthorityServiceFactory = ({
);
});
return { ca };
return { ca: expandInternalCa(ca) };
};
/**
@@ -1173,12 +1196,12 @@ export const internalCertificateAuthorityServiceFactory = ({
keyUsages,
extendedKeyUsages
}: TIssueCertFromCaDTO) => {
let ca: TCertificateAuthorities | undefined;
let ca: TCertificateAuthorityWithAssociatedCa | undefined;
let certificateTemplate: TCertificateTemplates | undefined;
let collectionId = pkiCollectionId;
if (caId) {
ca = await certificateAuthorityDAL.findById(caId);
ca = await certificateAuthorityDAL.findByIdWithAssociatedCa(caId);
} else if (certificateTemplateId) {
certificateTemplate = await certificateTemplateDAL.getById(certificateTemplateId);
if (!certificateTemplate) {
@@ -1188,10 +1211,10 @@ export const internalCertificateAuthorityServiceFactory = ({
}
collectionId = certificateTemplate.pkiCollectionId as string;
ca = await certificateAuthorityDAL.findById(certificateTemplate.caId);
ca = await certificateAuthorityDAL.findByIdWithAssociatedCa(certificateTemplate.caId);
}
if (!ca) {
if (!ca?.internalCa) {
throw new NotFoundError({ message: `CA with ID '${caId}' not found` });
}
@@ -1209,14 +1232,16 @@ export const internalCertificateAuthorityServiceFactory = ({
ProjectPermissionSub.Certificates
);
if (ca.status !== CaStatus.ACTIVE) throw new BadRequestError({ message: "CA is not active" });
if (!ca.activeCaCertId) throw new BadRequestError({ message: "CA does not have a certificate installed" });
if (ca.requireTemplateForIssuance && !certificateTemplate) {
if (ca.internalCa.status !== CaStatus.ACTIVE) throw new BadRequestError({ message: "CA is not active" });
if (!ca.internalCa.activeCaCertId)
throw new BadRequestError({ message: "CA does not have a certificate installed" });
if (ca.disableDirectIssuance && !certificateTemplate) {
throw new BadRequestError({ message: "Certificate template is required for issuance" });
}
const caCert = await certificateAuthorityCertDAL.findById(ca.activeCaCertId);
if (ca.notAfter && new Date() > new Date(ca.notAfter)) {
const caCert = await certificateAuthorityCertDAL.findById(ca.internalCa.activeCaCertId);
if (ca.internalCa.notAfter && new Date() > new Date(ca.internalCa.notAfter)) {
throw new BadRequestError({ message: "CA is expired" });
}
@@ -1266,7 +1291,7 @@ export const internalCertificateAuthorityServiceFactory = ({
throw new BadRequestError({ message: "notAfter date is after CA certificate's notAfter date" });
}
const alg = keyAlgorithmToAlgCfg(ca.keyAlgorithm as CertKeyAlgorithm);
const alg = keyAlgorithmToAlgCfg(ca.internalCa.keyAlgorithm as CertKeyAlgorithm);
const leafKeys = await crypto.subtle.generateKey(alg, true, ["sign", "verify"]);
const csrObj = await x509.Pkcs10CertificateRequestGenerator.create({
@@ -1496,7 +1521,7 @@ export const internalCertificateAuthorityServiceFactory = ({
issuingCaCertificate,
privateKey: skLeaf,
serialNumber,
ca
ca: expandInternalCa(ca)
};
};
@@ -1506,7 +1531,7 @@ export const internalCertificateAuthorityServiceFactory = ({
*/
const signCertFromCa = async (dto: TSignCertFromCaDTO) => {
const appCfg = getConfig();
let ca: TCertificateAuthorities | undefined;
let ca: TCertificateAuthorityWithAssociatedCa | undefined;
let certificateTemplate: TCertificateTemplates | undefined;
const {
@@ -1527,7 +1552,7 @@ export const internalCertificateAuthorityServiceFactory = ({
let collectionId = pkiCollectionId;
if (caId) {
ca = await certificateAuthorityDAL.findById(caId);
ca = await certificateAuthorityDAL.findByIdWithAssociatedCa(caId);
} else if (certificateTemplateId) {
certificateTemplate = await certificateTemplateDAL.getById(certificateTemplateId);
if (!certificateTemplate) {
@@ -1537,10 +1562,10 @@ export const internalCertificateAuthorityServiceFactory = ({
}
collectionId = certificateTemplate.pkiCollectionId as string;
ca = await certificateAuthorityDAL.findById(certificateTemplate.caId);
ca = await certificateAuthorityDAL.findByIdWithAssociatedCa(certificateTemplate.caId);
}
if (!ca) {
if (!ca?.internalCa) {
throw new NotFoundError({ message: `CA with ID '${caId}' not found` });
}
@@ -1560,15 +1585,16 @@ export const internalCertificateAuthorityServiceFactory = ({
);
}
if (ca.status !== CaStatus.ACTIVE) throw new BadRequestError({ message: "CA is not active" });
if (!ca.activeCaCertId) throw new BadRequestError({ message: "CA does not have a certificate installed" });
if (ca.requireTemplateForIssuance && !certificateTemplate) {
if (ca.internalCa.status !== CaStatus.ACTIVE) throw new BadRequestError({ message: "CA is not active" });
if (!ca.internalCa.activeCaCertId)
throw new BadRequestError({ message: "CA does not have a certificate installed" });
if (ca.disableDirectIssuance && !certificateTemplate) {
throw new BadRequestError({ message: "Certificate template is required for issuance" });
}
const caCert = await certificateAuthorityCertDAL.findById(ca.activeCaCertId);
const caCert = await certificateAuthorityCertDAL.findById(ca.internalCa.activeCaCertId);
if (ca.notAfter && new Date() > new Date(ca.notAfter)) {
if (ca.internalCa.notAfter && new Date() > new Date(ca.internalCa.notAfter)) {
throw new BadRequestError({ message: "CA is expired" });
}
@@ -1621,7 +1647,7 @@ export const internalCertificateAuthorityServiceFactory = ({
throw new BadRequestError({ message: "notAfter date is after CA certificate's notAfter date" });
}
const alg = keyAlgorithmToAlgCfg(ca.keyAlgorithm as CertKeyAlgorithm);
const alg = keyAlgorithmToAlgCfg(ca.internalCa.keyAlgorithm as CertKeyAlgorithm);
const csrObj = new x509.Pkcs10CertificateRequest(csr);
@@ -1874,7 +1900,7 @@ export const internalCertificateAuthorityServiceFactory = ({
});
const { caCert: issuingCaCertificate, caCertChain } = await getCaCertChain({
caCertId: ca.activeCaCertId,
caCertId: ca.internalCa.activeCaCertId,
certificateAuthorityDAL,
certificateAuthorityCertDAL,
projectDAL,
@@ -1886,7 +1912,7 @@ export const internalCertificateAuthorityServiceFactory = ({
certificateChain: `${issuingCaCertificate}\n${caCertChain}`.trim(),
issuingCaCertificate,
serialNumber,
ca,
ca: expandInternalCa(ca),
commonName: cn
};
};
@@ -1901,8 +1927,8 @@ export const internalCertificateAuthorityServiceFactory = ({
actor,
actorOrgId
}: TGetCaCertificateTemplatesDTO) => {
const ca = await certificateAuthorityDAL.findById(caId);
if (!ca) throw new NotFoundError({ message: `CA with ID '${caId}' not found` });
const ca = await certificateAuthorityDAL.findByIdWithAssociatedCa(caId);
if (!ca?.internalCa) throw new NotFoundError({ message: `CA with ID '${caId}' not found` });
const { permission } = await permissionService.getProjectPermission({
actor,
@@ -1922,7 +1948,7 @@ export const internalCertificateAuthorityServiceFactory = ({
return {
certificateTemplates,
ca
ca: expandInternalCa(ca)
};
};

View File

@@ -19,10 +19,15 @@ export const certificateTemplateDALFactory = (db: TDbClient) => {
`${TableName.CertificateAuthority}.id`,
`${TableName.CertificateTemplate}.caId`
)
.join(
TableName.InternalCertificateAuthority,
`${TableName.InternalCertificateAuthority}.certificateAuthorityId`,
`${TableName.CertificateAuthority}.id`
)
.where(`${TableName.CertificateAuthority}.projectId`, "=", projectId)
.select(selectAllTableCols(TableName.CertificateTemplate))
.select(
db.ref("friendlyName").as("caName").withSchema(TableName.CertificateAuthority),
db.ref("friendlyName").as("caName").withSchema(TableName.InternalCertificateAuthority),
db.ref("projectId").withSchema(TableName.CertificateAuthority)
);
@@ -41,11 +46,16 @@ export const certificateTemplateDALFactory = (db: TDbClient) => {
`${TableName.CertificateTemplate}.caId`
)
.join(TableName.Project, `${TableName.Project}.id`, `${TableName.CertificateAuthority}.projectId`)
.join(
TableName.InternalCertificateAuthority,
`${TableName.InternalCertificateAuthority}.certificateAuthorityId`,
`${TableName.CertificateAuthority}.id`
)
.where(`${TableName.CertificateTemplate}.id`, "=", id)
.select(selectAllTableCols(TableName.CertificateTemplate))
.select(
db.ref("projectId").withSchema(TableName.CertificateAuthority),
db.ref("friendlyName").as("caName").withSchema(TableName.CertificateAuthority),
db.ref("friendlyName").as("caName").withSchema(TableName.InternalCertificateAuthority),
db.ref("orgId").withSchema(TableName.Project)
)
.first();

View File

@@ -17,7 +17,7 @@ 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 { getCaCertChain, rebuildCaCrl } from "../certificate-authority/certificate-authority-fns";
import { expandInternalCa, getCaCertChain, rebuildCaCrl } from "../certificate-authority/certificate-authority-fns";
import { buildCertificateChain, getCertificateCredentials, revocationReasonToCrlCode } from "./certificate-fns";
import { TCertificateSecretDALFactory } from "./certificate-secret-dal";
import {
@@ -34,7 +34,7 @@ type TCertificateServiceFactoryDep = {
certificateDAL: Pick<TCertificateDALFactory, "findOne" | "deleteById" | "update" | "find">;
certificateSecretDAL: Pick<TCertificateSecretDALFactory, "findOne">;
certificateBodyDAL: Pick<TCertificateBodyDALFactory, "findOne">;
certificateAuthorityDAL: Pick<TCertificateAuthorityDALFactory, "findById">;
certificateAuthorityDAL: Pick<TCertificateAuthorityDALFactory, "findById" | "findByIdWithAssociatedCa">;
certificateAuthorityCertDAL: Pick<TCertificateAuthorityCertDALFactory, "findById">;
certificateAuthorityCrlDAL: Pick<TCertificateAuthorityCrlDALFactory, "update">;
certificateAuthoritySecretDAL: Pick<TCertificateAuthoritySecretDALFactory, "findOne">;
@@ -62,7 +62,7 @@ export const certificateServiceFactory = ({
*/
const getCert = async ({ serialNumber, actorId, actorAuthMethod, actor, actorOrgId }: TGetCertDTO) => {
const cert = await certificateDAL.findOne({ serialNumber });
const ca = await certificateAuthorityDAL.findById(cert.caId);
const ca = await certificateAuthorityDAL.findByIdWithAssociatedCa(cert.caId);
const { permission } = await permissionService.getProjectPermission({
actor,
@@ -80,7 +80,7 @@ export const certificateServiceFactory = ({
return {
cert,
ca
ca: expandInternalCa(ca)
};
};
@@ -95,7 +95,7 @@ export const certificateServiceFactory = ({
actorOrgId
}: TGetCertPrivateKeyDTO) => {
const cert = await certificateDAL.findOne({ serialNumber });
const ca = await certificateAuthorityDAL.findById(cert.caId);
const ca = await certificateAuthorityDAL.findByIdWithAssociatedCa(cert.caId);
const { permission } = await permissionService.getProjectPermission({
actor,
@@ -120,7 +120,7 @@ export const certificateServiceFactory = ({
});
return {
ca,
ca: expandInternalCa(ca),
cert,
certPrivateKey
};
@@ -131,7 +131,7 @@ export const certificateServiceFactory = ({
*/
const deleteCert = async ({ serialNumber, actorId, actorAuthMethod, actor, actorOrgId }: TDeleteCertDTO) => {
const cert = await certificateDAL.findOne({ serialNumber });
const ca = await certificateAuthorityDAL.findById(cert.caId);
const ca = await certificateAuthorityDAL.findByIdWithAssociatedCa(cert.caId);
const { permission } = await permissionService.getProjectPermission({
actor,
@@ -151,7 +151,7 @@ export const certificateServiceFactory = ({
return {
deletedCert,
ca
ca: expandInternalCa(ca)
};
};
@@ -169,7 +169,7 @@ export const certificateServiceFactory = ({
actorOrgId
}: TRevokeCertDTO) => {
const cert = await certificateDAL.findOne({ serialNumber });
const ca = await certificateAuthorityDAL.findById(cert.caId);
const ca = await certificateAuthorityDAL.findByIdWithAssociatedCa(cert.caId);
const { permission } = await permissionService.getProjectPermission({
actor,
@@ -210,7 +210,7 @@ export const certificateServiceFactory = ({
kmsService
});
return { revokedAt, cert, ca };
return { revokedAt, cert, ca: expandInternalCa(ca) };
};
/**
@@ -219,7 +219,7 @@ export const certificateServiceFactory = ({
*/
const getCertBody = async ({ serialNumber, actorId, actorAuthMethod, actor, actorOrgId }: TGetCertBodyDTO) => {
const cert = await certificateDAL.findOne({ serialNumber });
const ca = await certificateAuthorityDAL.findById(cert.caId);
const ca = await certificateAuthorityDAL.findByIdWithAssociatedCa(cert.caId);
const { permission } = await permissionService.getProjectPermission({
actor,
@@ -273,7 +273,7 @@ export const certificateServiceFactory = ({
certificateChain,
serialNumber: certObj.serialNumber,
cert,
ca
ca: expandInternalCa(ca)
};
};
@@ -283,7 +283,7 @@ export const certificateServiceFactory = ({
*/
const getCertBundle = async ({ serialNumber, actorId, actorAuthMethod, actor, actorOrgId }: TGetCertBundleDTO) => {
const cert = await certificateDAL.findOne({ serialNumber });
const ca = await certificateAuthorityDAL.findById(cert.caId);
const ca = await certificateAuthorityDAL.findByIdWithAssociatedCa(cert.caId);
const { permission } = await permissionService.getProjectPermission({
actor,
@@ -351,7 +351,7 @@ export const certificateServiceFactory = ({
privateKey: certPrivateKey,
serialNumber,
cert,
ca
ca: expandInternalCa(ca)
};
};

View File

@@ -29,6 +29,7 @@ import { TCertificateAuthorityCertDALFactory } from "@app/services/certificate-a
import { TCertificateAuthorityDALFactory } from "@app/services/certificate-authority/certificate-authority-dal";
import {
createSerialNumber,
expandInternalCa,
getCaCertChain,
getCaCredentials,
keyAlgorithmToAlgCfg,
@@ -57,7 +58,7 @@ type TPkiSubscriberServiceFactoryDep = {
TPkiSubscriberDALFactory,
"create" | "findById" | "updateById" | "deleteById" | "transaction" | "find" | "findOne"
>;
certificateAuthorityDAL: Pick<TCertificateAuthorityDALFactory, "findById">;
certificateAuthorityDAL: Pick<TCertificateAuthorityDALFactory, "findByIdWithAssociatedCa" | "findById">;
certificateAuthorityCertDAL: Pick<TCertificateAuthorityCertDALFactory, "findById">;
certificateAuthoritySecretDAL: Pick<TCertificateAuthoritySecretDALFactory, "findOne">;
certificateAuthorityCrlDAL: Pick<TCertificateAuthorityCrlDALFactory, "findOne">;
@@ -266,8 +267,8 @@ export const pkiSubscriberServiceFactory = ({
if (!subscriber) throw new NotFoundError({ message: `PKI subscriber named '${subscriberName}' not found` });
if (!subscriber.caId) throw new BadRequestError({ message: "Subscriber does not have an assigned issuing CA" });
const ca = await certificateAuthorityDAL.findById(subscriber.caId);
if (!ca) throw new NotFoundError({ message: `CA with ID '${subscriber.caId}' not found` });
const ca = await certificateAuthorityDAL.findByIdWithAssociatedCa(subscriber.caId);
if (!ca?.internalCa) throw new NotFoundError({ message: `CA with ID '${subscriber.caId}' not found` });
const { permission } = await permissionService.getProjectPermission({
actor,
@@ -287,12 +288,13 @@ export const pkiSubscriberServiceFactory = ({
if (subscriber.status !== PkiSubscriberStatus.ACTIVE)
throw new BadRequestError({ message: "Subscriber is not active" });
if (ca.status !== CaStatus.ACTIVE) throw new BadRequestError({ message: "CA is not active" });
if (!ca.activeCaCertId) throw new BadRequestError({ message: "CA does not have a certificate installed" });
if (ca.requireTemplateForIssuance) {
if (ca.internalCa?.status !== CaStatus.ACTIVE) throw new BadRequestError({ message: "CA is not active" });
if (!ca.internalCa?.activeCaCertId)
throw new BadRequestError({ message: "CA does not have a certificate installed" });
if (ca.disableDirectIssuance) {
throw new BadRequestError({ message: "Certificate template is required for issuance" });
}
const caCert = await certificateAuthorityCertDAL.findById(ca.activeCaCertId);
const caCert = await certificateAuthorityCertDAL.findById(ca.internalCa.activeCaCertId);
const certificateManagerKmsId = await getProjectKmsCertificateKeyId({
projectId: ca.projectId,
@@ -323,7 +325,7 @@ export const pkiSubscriberServiceFactory = ({
throw new BadRequestError({ message: "notAfter date is after CA certificate's notAfter date" });
}
const alg = keyAlgorithmToAlgCfg(ca.keyAlgorithm as CertKeyAlgorithm);
const alg = keyAlgorithmToAlgCfg(ca.internalCa.keyAlgorithm as CertKeyAlgorithm);
const leafKeys = await crypto.subtle.generateKey(alg, true, ["sign", "verify"]);
const csrObj = await x509.Pkcs10CertificateRequestGenerator.create({
@@ -500,8 +502,8 @@ export const pkiSubscriberServiceFactory = ({
if (!subscriber) throw new NotFoundError({ message: `PKI subscriber named '${subscriberName}' not found` });
if (!subscriber.caId) throw new BadRequestError({ message: "Subscriber does not have an assigned issuing CA" });
const ca = await certificateAuthorityDAL.findById(subscriber.caId);
if (!ca) throw new NotFoundError({ message: `CA with ID '${subscriber.caId}' not found` });
const ca = await certificateAuthorityDAL.findByIdWithAssociatedCa(subscriber.caId);
if (!ca?.internalCa) throw new NotFoundError({ message: `CA with ID '${subscriber.caId}' not found` });
const { permission } = await permissionService.getProjectPermission({
actor,
@@ -521,12 +523,13 @@ export const pkiSubscriberServiceFactory = ({
if (subscriber.status !== PkiSubscriberStatus.ACTIVE)
throw new BadRequestError({ message: "Subscriber is not active" });
if (ca.status !== CaStatus.ACTIVE) throw new BadRequestError({ message: "CA is not active" });
if (!ca.activeCaCertId) throw new BadRequestError({ message: "CA does not have a certificate installed" });
if (ca.requireTemplateForIssuance) {
if (ca.internalCa?.status !== CaStatus.ACTIVE) throw new BadRequestError({ message: "CA is not active" });
if (!ca.internalCa?.activeCaCertId)
throw new BadRequestError({ message: "CA does not have a certificate installed" });
if (ca.disableDirectIssuance) {
throw new BadRequestError({ message: "Certificate template is required for issuance" });
}
const caCert = await certificateAuthorityCertDAL.findById(ca.activeCaCertId);
const caCert = await certificateAuthorityCertDAL.findById(ca.internalCa.activeCaCertId);
const certificateManagerKmsId = await getProjectKmsCertificateKeyId({
projectId: ca.projectId,
@@ -557,7 +560,7 @@ export const pkiSubscriberServiceFactory = ({
throw new BadRequestError({ message: "notAfter date is after CA certificate's notAfter date" });
}
const alg = keyAlgorithmToAlgCfg(ca.keyAlgorithm as CertKeyAlgorithm);
const alg = keyAlgorithmToAlgCfg(ca.internalCa.keyAlgorithm as CertKeyAlgorithm);
const csrObj = new x509.Pkcs10CertificateRequest(csr);
@@ -691,7 +694,7 @@ export const pkiSubscriberServiceFactory = ({
});
const { caCert: issuingCaCertificate, caCertChain } = await getCaCertChain({
caCertId: ca.activeCaCertId,
caCertId: ca.internalCa.activeCaCertId,
certificateAuthorityDAL,
certificateAuthorityCertDAL,
projectDAL,
@@ -740,7 +743,7 @@ export const pkiSubscriberServiceFactory = ({
certificateChain: `${issuingCaCertificate}\n${caCertChain}`.trim(),
issuingCaCertificate,
serialNumber,
ca,
ca: expandInternalCa(ca),
commonName: subscriber.commonName,
subscriber
};

View File

@@ -6,6 +6,7 @@ import {
ProjectMembershipRole,
ProjectType,
ProjectVersion,
TableName,
TProjectEnvironments
} from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
@@ -41,6 +42,7 @@ import { TPkiSubscriberDALFactory } from "@app/services/pki-subscriber/pki-subsc
import { ActorType } from "../auth/auth-type";
import { TCertificateDALFactory } from "../certificate/certificate-dal";
import { TCertificateAuthorityDALFactory } from "../certificate-authority/certificate-authority-dal";
import { expandInternalCa } from "../certificate-authority/certificate-authority-fns";
import { TCertificateTemplateDALFactory } from "../certificate-template/certificate-template-dal";
import { TGroupProjectDALFactory } from "../group-project/group-project-dal";
import { TIdentityOrgDALFactory } from "../identity/identity-org-dal";
@@ -149,7 +151,7 @@ type TProjectServiceFactoryDep = {
>;
projectUserMembershipRoleDAL: Pick<TProjectUserMembershipRoleDALFactory, "create">;
pkiSubscriberDAL: Pick<TPkiSubscriberDALFactory, "find">;
certificateAuthorityDAL: Pick<TCertificateAuthorityDALFactory, "find">;
certificateAuthorityDAL: Pick<TCertificateAuthorityDALFactory, "find" | "findWithAssociatedCa">;
certificateDAL: Pick<TCertificateDALFactory, "find" | "countCertificatesInProject">;
certificateTemplateDAL: Pick<TCertificateTemplateDALFactory, "getCertTemplatesByProjectId">;
pkiAlertDAL: Pick<TPkiAlertDALFactory, "find">;
@@ -913,17 +915,19 @@ export const projectServiceFactory = ({
ProjectPermissionSub.CertificateAuthorities
);
const cas = await certificateAuthorityDAL.find(
const cas = await certificateAuthorityDAL.findWithAssociatedCa(
{
projectId,
...(status && { status }),
...(friendlyName && { friendlyName }),
...(commonName && { commonName })
[`${TableName.CertificateAuthority}.projectId` as "projectId"]: projectId,
...(status && { [`${TableName.InternalCertificateAuthority}.status` as "status"]: status }),
...(friendlyName && {
[`${TableName.InternalCertificateAuthority}.friendlyName` as "friendlyName"]: friendlyName
}),
...(commonName && { [`${TableName.InternalCertificateAuthority}.commonName` as "commonName"]: commonName })
},
{ offset, limit, sort: [["updatedAt", "desc"]] }
);
return cas;
return cas.map((ca) => expandInternalCa(ca));
};
/**