misc: added back old ca endpoints

This commit is contained in:
Sheen Capadngan
2025-11-28 22:47:31 +08:00
parent ec5c5728bf
commit 271fd912ef
13 changed files with 690 additions and 3 deletions

View File

@@ -0,0 +1,18 @@
import { AcmeCertificateAuthoritySchema } from "@app/services/certificate-authority/acme/acme-certificate-authority-schemas";
import {
CreateAcmeCertificateAuthoritySchema,
UpdateAcmeCertificateAuthoritySchema
} from "@app/services/certificate-authority/acme/deprecated-acme-certificate-authority-schemas";
import { CaType } from "@app/services/certificate-authority/certificate-authority-enums";
import { registerCertificateAuthorityEndpoints } from "./certificate-authority-endpoints";
export const registerAcmeCertificateAuthorityRouter = async (server: FastifyZodProvider) => {
registerCertificateAuthorityEndpoints({
caType: CaType.ACME,
server,
responseSchema: AcmeCertificateAuthoritySchema,
createSchema: CreateAcmeCertificateAuthoritySchema,
updateSchema: UpdateAcmeCertificateAuthoritySchema
});
};

View File

@@ -0,0 +1,78 @@
import { z } from "zod";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { readLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
import { AzureAdCsCertificateAuthoritySchema } from "@app/services/certificate-authority/azure-ad-cs/azure-ad-cs-certificate-authority-schemas";
import {
CreateAzureAdCsCertificateAuthoritySchema,
UpdateAzureAdCsCertificateAuthoritySchema
} from "@app/services/certificate-authority/azure-ad-cs/deprecated-azure-ad-cs-certificate-authority-schemas";
import { CaType } from "@app/services/certificate-authority/certificate-authority-enums";
import { registerCertificateAuthorityEndpoints } from "./certificate-authority-endpoints";
export const registerAzureAdCsCertificateAuthorityRouter = async (server: FastifyZodProvider) => {
registerCertificateAuthorityEndpoints({
caType: CaType.AZURE_AD_CS,
server,
responseSchema: AzureAdCsCertificateAuthoritySchema,
createSchema: CreateAzureAdCsCertificateAuthoritySchema,
updateSchema: UpdateAzureAdCsCertificateAuthoritySchema
});
server.route({
method: "GET",
url: "/:caId/templates",
config: {
rateLimit: readLimit
},
schema: {
hide: false,
description: "Get available certificate templates from Azure AD CS CA",
params: z.object({
caId: z.string().describe("Azure AD CS CA ID")
}),
querystring: z.object({
projectId: z.string().describe("Project ID")
}),
response: {
200: z.object({
templates: z.array(
z.object({
id: z.string().describe("Template identifier"),
name: z.string().describe("Template display name"),
description: z.string().optional().describe("Template description")
})
)
})
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const templates = await server.services.certificateAuthority.getAzureAdcsTemplates({
caId: req.params.caId,
projectId: req.query.projectId,
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId
});
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId: req.query.projectId,
event: {
type: EventType.GET_AZURE_AD_TEMPLATES,
metadata: {
caId: req.params.caId,
amount: templates.length
}
}
});
return { templates };
}
});
};

View File

@@ -0,0 +1,258 @@
import { z } from "zod";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { ApiDocsTags } from "@app/lib/api-docs";
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
import { CaStatus, CaType } from "@app/services/certificate-authority/certificate-authority-enums";
import {
TCertificateAuthority,
TCertificateAuthorityInput
} from "@app/services/certificate-authority/certificate-authority-types";
export const registerCertificateAuthorityEndpoints = <
T extends TCertificateAuthority,
I extends TCertificateAuthorityInput
>({
server,
caType,
createSchema,
updateSchema,
responseSchema
}: {
caType: CaType;
server: FastifyZodProvider;
createSchema: z.ZodType<{
name: string;
projectId: string;
status: CaStatus;
configuration: I["configuration"];
enableDirectIssuance: boolean;
}>;
updateSchema: z.ZodType<{
projectId: string;
name?: string;
status?: CaStatus;
configuration?: I["configuration"];
enableDirectIssuance?: boolean;
}>;
responseSchema: z.ZodTypeAny;
}) => {
server.route({
method: "GET",
url: `/`,
config: {
rateLimit: readLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.PkiCertificateAuthorities],
querystring: z.object({
projectId: z.string().trim().min(1, "Project ID required")
}),
response: {
200: responseSchema.array()
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const {
query: { projectId }
} = req;
const certificateAuthorities = (await server.services.certificateAuthority.listCertificateAuthoritiesByProjectId(
{ projectId, type: caType },
req.permission
)) as T[];
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId,
event: {
type: EventType.GET_CAS,
metadata: {
caIds: certificateAuthorities.map((ca) => ca.id)
}
}
});
return certificateAuthorities;
}
});
server.route({
method: "GET",
url: "/:caName",
config: {
rateLimit: readLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.PkiCertificateAuthorities],
params: z.object({
caName: z.string()
}),
querystring: z.object({
projectId: z.string().uuid()
}),
response: {
200: responseSchema
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const { caName } = req.params;
const { projectId } = req.query;
const certificateAuthority =
(await server.services.certificateAuthority.findCertificateAuthorityByNameAndProjectId(
{ caName, type: caType, projectId },
req.permission
)) as T;
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId: certificateAuthority.projectId,
event: {
type: EventType.GET_CA,
metadata: {
caId: certificateAuthority.id,
name: certificateAuthority.name
}
}
});
return certificateAuthority;
}
});
server.route({
method: "POST",
url: "/",
config: {
rateLimit: writeLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.PkiCertificateAuthorities],
body: createSchema,
response: {
200: responseSchema
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const certificateAuthority = (await server.services.certificateAuthority.createCertificateAuthority(
{ ...req.body, type: caType },
req.permission
)) as T;
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId: certificateAuthority.projectId,
event: {
type: EventType.CREATE_CA,
metadata: {
name: certificateAuthority.name,
caId: certificateAuthority.id
}
}
});
return certificateAuthority;
}
});
server.route({
method: "PATCH",
url: "/:caName",
config: {
rateLimit: writeLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.PkiCertificateAuthorities],
params: z.object({
caName: z.string()
}),
body: updateSchema,
response: {
200: responseSchema
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const { caName } = req.params;
const certificateAuthority = (await server.services.certificateAuthority.deprecatedUpdateCertificateAuthority(
{
...req.body,
type: caType,
caName
},
req.permission
)) as T;
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId: certificateAuthority.projectId,
event: {
type: EventType.UPDATE_CA,
metadata: {
name: certificateAuthority.name,
caId: certificateAuthority.id,
status: certificateAuthority.status
}
}
});
return certificateAuthority;
}
});
server.route({
method: "DELETE",
url: "/:caName",
config: {
rateLimit: writeLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.PkiCertificateAuthorities],
params: z.object({
caName: z.string()
}),
body: z.object({
projectId: z.string().uuid()
}),
response: {
200: responseSchema
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const { caName } = req.params;
const { projectId } = req.body;
const certificateAuthority = (await server.services.certificateAuthority.deprecatedDeleteCertificateAuthority(
{ caName, type: caType, projectId },
req.permission
)) as T;
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId: certificateAuthority.projectId,
event: {
type: EventType.DELETE_CA,
metadata: {
name: certificateAuthority.name,
caId: certificateAuthority.id
}
}
});
return certificateAuthority;
}
});
};

View File

@@ -0,0 +1,16 @@
import { CaType } from "@app/services/certificate-authority/certificate-authority-enums";
import { registerAcmeCertificateAuthorityRouter } from "./acme-certificate-authority-router";
import { registerAzureAdCsCertificateAuthorityRouter } from "./azure-ad-cs-certificate-authority-router";
import { registerInternalCertificateAuthorityRouter } from "./internal-certificate-authority-router";
export * from "./internal-certificate-authority-router";
export const DEPRECATED_CERTIFICATE_AUTHORITY_REGISTER_ROUTER_MAP: Record<
CaType,
(server: FastifyZodProvider) => Promise<void>
> = {
[CaType.INTERNAL]: registerInternalCertificateAuthorityRouter,
[CaType.ACME]: registerAcmeCertificateAuthorityRouter,
[CaType.AZURE_AD_CS]: registerAzureAdCsCertificateAuthorityRouter
};

View File

@@ -0,0 +1,18 @@
import { CaType } from "@app/services/certificate-authority/certificate-authority-enums";
import {
CreateInternalCertificateAuthoritySchema,
UpdateInternalCertificateAuthoritySchema
} from "@app/services/certificate-authority/internal/deprecated-internal-certificate-authority-schemas";
import { InternalCertificateAuthoritySchema } from "@app/services/certificate-authority/internal/internal-certificate-authority-schemas";
import { registerCertificateAuthorityEndpoints } from "./certificate-authority-endpoints";
export const registerInternalCertificateAuthorityRouter = async (server: FastifyZodProvider) => {
registerCertificateAuthorityEndpoints({
caType: CaType.INTERNAL,
server,
responseSchema: InternalCertificateAuthoritySchema,
createSchema: CreateInternalCertificateAuthoritySchema,
updateSchema: UpdateInternalCertificateAuthoritySchema
});
};

View File

@@ -15,6 +15,7 @@ import { registerGeneralCertificateAuthorityRouter } from "./certificate-authori
import { registerCertificateProfilesRouter } from "./certificate-profiles-router";
import { registerCertificateRouter } from "./certificate-router";
import { registerCertificateTemplateRouter } from "./certificate-template-router";
import { DEPRECATED_CERTIFICATE_AUTHORITY_REGISTER_ROUTER_MAP } from "./deprecated-certificate-authority-routers";
import { registerDeprecatedCertRouter } from "./deprecated-certificate-router";
import { registerDeprecatedCertificateTemplateRouter } from "./deprecated-certificate-template-router";
import { registerDeprecatedIdentityProjectMembershipRouter } from "./deprecated-identity-project-membership-router";
@@ -190,7 +191,7 @@ export const registerV1Routes = async (server: FastifyZodProvider) => {
await pkiRouter.register(registerCaRouter, { prefix: "/ca" });
await pkiRouter.register(
async (caRouter) => {
for await (const [caType, router] of Object.entries(CERTIFICATE_AUTHORITY_REGISTER_ROUTER_MAP)) {
for await (const [caType, router] of Object.entries(DEPRECATED_CERTIFICATE_AUTHORITY_REGISTER_ROUTER_MAP)) {
await caRouter.register(router, { prefix: `/${caType}` });
}
},

View File

@@ -0,0 +1,14 @@
import { CaType } from "../certificate-authority-enums";
import {
GenericCreateCertificateAuthorityFieldsSchema,
GenericUpdateCertificateAuthorityFieldsSchema
} from "../deprecated-certificate-authority-schemas";
import { AcmeCertificateAuthorityConfigurationSchema } from "./acme-certificate-authority-schemas";
export const CreateAcmeCertificateAuthoritySchema = GenericCreateCertificateAuthorityFieldsSchema(CaType.ACME).extend({
configuration: AcmeCertificateAuthorityConfigurationSchema
});
export const UpdateAcmeCertificateAuthoritySchema = GenericUpdateCertificateAuthorityFieldsSchema(CaType.ACME).extend({
configuration: AcmeCertificateAuthorityConfigurationSchema.optional()
});

View File

@@ -0,0 +1,18 @@
import { CaType } from "../certificate-authority-enums";
import {
GenericCreateCertificateAuthorityFieldsSchema,
GenericUpdateCertificateAuthorityFieldsSchema
} from "../deprecated-certificate-authority-schemas";
import { AzureAdCsCertificateAuthorityConfigurationSchema } from "./azure-ad-cs-certificate-authority-schemas";
export const CreateAzureAdCsCertificateAuthoritySchema = GenericCreateCertificateAuthorityFieldsSchema(
CaType.AZURE_AD_CS
).extend({
configuration: AzureAdCsCertificateAuthorityConfigurationSchema
});
export const UpdateAzureAdCsCertificateAuthoritySchema = GenericUpdateCertificateAuthorityFieldsSchema(
CaType.AZURE_AD_CS
).extend({
configuration: AzureAdCsCertificateAuthorityConfigurationSchema.optional()
});

View File

@@ -37,6 +37,7 @@ import { CaType } from "./certificate-authority-enums";
import {
TCertificateAuthority,
TCreateCertificateAuthorityDTO,
TDeprecatedUpdateCertificateAuthorityDTO,
TUpdateCertificateAuthorityDTO
} from "./certificate-authority-types";
import { TExternalCertificateAuthorityDALFactory } from "./external-certificate-authority-dal";
@@ -245,6 +246,69 @@ export const certificateAuthorityServiceFactory = ({
throw new BadRequestError({ message: "Invalid certificate authority type" });
};
const findCertificateAuthorityByNameAndProjectId = async (
{ caName, type, projectId }: { caName: string; type: CaType; projectId: string },
actor: OrgServiceActor
) => {
const certificateAuthority = await certificateAuthorityDAL.findByNameAndProjectIdWithAssociatedCa(
caName,
projectId
);
if (!certificateAuthority)
throw new NotFoundError({
message: `Could not find certificate authority with name "${caName}" in project "${projectId}"`
});
const { permission } = await permissionService.getProjectPermission({
actor: actor.type,
actorId: actor.id,
projectId: certificateAuthority.projectId,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.CertificateManager
});
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Read,
ProjectPermissionSub.CertificateAuthorities
);
if (type === CaType.INTERNAL) {
if (!certificateAuthority.internalCa?.id) {
throw new NotFoundError({
message: `Internal certificate authority with name "${caName}" in project "${projectId}" not found`
});
}
return {
id: certificateAuthority.id,
type,
enableDirectIssuance: certificateAuthority.enableDirectIssuance,
name: certificateAuthority.name,
projectId: certificateAuthority.projectId,
configuration: certificateAuthority.internalCa,
status: certificateAuthority.status
} as TCertificateAuthority;
}
if (certificateAuthority.externalCa?.type !== type) {
throw new NotFoundError({
message: `Could not find external certificate authority with name "${caName}" in project "${projectId}" and type "${type}"`
});
}
if (type === CaType.ACME) {
return castDbEntryToAcmeCertificateAuthority(certificateAuthority);
}
if (type === CaType.AZURE_AD_CS) {
return castDbEntryToAzureAdCsCertificateAuthority(certificateAuthority);
}
throw new BadRequestError({ message: "Invalid certificate authority type" });
};
const listCertificateAuthoritiesByProjectId = async (
{ projectId, type }: { projectId: string; type: CaType },
actor: OrgServiceActor
@@ -431,6 +495,153 @@ export const certificateAuthorityServiceFactory = ({
throw new BadRequestError({ message: "Invalid certificate authority type" });
};
const deprecatedUpdateCertificateAuthority = async (
{ caName, type, configuration, status, name, projectId }: TDeprecatedUpdateCertificateAuthorityDTO,
actor: OrgServiceActor
) => {
const certificateAuthority = await certificateAuthorityDAL.findByNameAndProjectIdWithAssociatedCa(
caName,
projectId
);
if (!certificateAuthority)
throw new NotFoundError({
message: `Could not find certificate authority with name "${caName}" in project "${projectId}"`
});
const { permission } = await permissionService.getProjectPermission({
actor: actor.type,
actorId: actor.id,
projectId: certificateAuthority.projectId,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.CertificateManager
});
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Edit,
ProjectPermissionSub.CertificateAuthorities
);
if (type === CaType.INTERNAL) {
if (!certificateAuthority.internalCa?.id) {
throw new NotFoundError({
message: `Internal certificate authority with name "${caName}" in project "${projectId}" not found`
});
}
const updatedCa = await internalCertificateAuthorityService.updateCaById({
isInternal: true,
caId: certificateAuthority.id,
status,
name
});
if (!updatedCa.internalCa) {
throw new BadRequestError({
message: "Failed to update internal certificate authority"
});
}
return {
id: updatedCa.id,
type,
enableDirectIssuance: updatedCa.enableDirectIssuance,
name: updatedCa.name,
projectId: updatedCa.projectId,
configuration: updatedCa.internalCa,
status: updatedCa.status
} as TCertificateAuthority;
}
if (type === CaType.ACME) {
return acmeFns.updateCertificateAuthority({
id: certificateAuthority.id,
configuration: configuration as TUpdateAcmeCertificateAuthorityDTO["configuration"],
actor,
status,
name
});
}
if (type === CaType.AZURE_AD_CS) {
return azureAdCsFns.updateCertificateAuthority({
id: certificateAuthority.id,
configuration: configuration as TUpdateAzureAdCsCertificateAuthorityDTO["configuration"],
actor,
status,
name
});
}
throw new BadRequestError({ message: "Invalid certificate authority type" });
};
const deprecatedDeleteCertificateAuthority = async (
{ caName, type, projectId }: { caName: string; type: CaType; projectId: string },
actor: OrgServiceActor
) => {
const certificateAuthority = await certificateAuthorityDAL.findByNameAndProjectIdWithAssociatedCa(
caName,
projectId
);
if (!certificateAuthority)
throw new NotFoundError({
message: `Could not find certificate authority with name "${caName}" in project "${projectId}"`
});
const { permission } = await permissionService.getProjectPermission({
actor: actor.type,
actorId: actor.id,
projectId: certificateAuthority.projectId,
actorAuthMethod: actor.authMethod,
actorOrgId: actor.orgId,
actionProjectType: ActionProjectType.CertificateManager
});
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Delete,
ProjectPermissionSub.CertificateAuthorities
);
if (!certificateAuthority.internalCa?.id && type === CaType.INTERNAL) {
throw new BadRequestError({
message: "Internal certificate authority cannot be deleted"
});
}
if (certificateAuthority.externalCa?.id && certificateAuthority.externalCa.type !== type) {
throw new BadRequestError({
message: "External certificate authority cannot be deleted"
});
}
await certificateAuthorityDAL.deleteById(certificateAuthority.id);
if (type === CaType.INTERNAL) {
return {
id: certificateAuthority.id,
type,
enableDirectIssuance: certificateAuthority.enableDirectIssuance,
name: certificateAuthority.name,
projectId: certificateAuthority.projectId,
configuration: certificateAuthority.internalCa,
status: certificateAuthority.status
} as TCertificateAuthority;
}
if (type === CaType.ACME) {
return castDbEntryToAcmeCertificateAuthority(certificateAuthority);
}
if (type === CaType.AZURE_AD_CS) {
return castDbEntryToAzureAdCsCertificateAuthority(certificateAuthority);
}
throw new BadRequestError({ message: "Invalid certificate authority type" });
};
const getAzureAdcsTemplates = async ({
caId,
projectId,
@@ -470,8 +681,11 @@ export const certificateAuthorityServiceFactory = ({
createCertificateAuthority,
findCertificateAuthorityById,
listCertificateAuthoritiesByProjectId,
findCertificateAuthorityByNameAndProjectId,
updateCertificateAuthority,
deleteCertificateAuthority,
getAzureAdcsTemplates
getAzureAdcsTemplates,
deprecatedUpdateCertificateAuthority,
deprecatedDeleteCertificateAuthority
};
};

View File

@@ -25,3 +25,9 @@ export type TUpdateCertificateAuthorityDTO = Partial<Omit<TCreateCertificateAuth
type: CaType;
id: string;
};
export type TDeprecatedUpdateCertificateAuthorityDTO = Partial<Omit<TCreateCertificateAuthorityDTO, "projectId">> & {
type: CaType;
caName: string;
projectId: string;
};

View File

@@ -0,0 +1,32 @@
import z from "zod";
import { CertificateAuthoritiesSchema } from "@app/db/schemas";
import { CertificateAuthorities } from "@app/lib/api-docs/constants";
import { slugSchema } from "@app/server/lib/schemas";
import { CaStatus, CaType } from "./certificate-authority-enums";
export const BaseCertificateAuthoritySchema = CertificateAuthoritiesSchema.pick({
projectId: true,
enableDirectIssuance: true,
name: true,
id: true
}).extend({
status: z.nativeEnum(CaStatus)
});
export const GenericCreateCertificateAuthorityFieldsSchema = (type: CaType) =>
z.object({
name: slugSchema({ field: "name" }).describe(CertificateAuthorities.CREATE(type).name),
projectId: z.string().uuid("Project ID must be valid").describe(CertificateAuthorities.CREATE(type).projectId),
enableDirectIssuance: z.boolean().describe(CertificateAuthorities.CREATE(type).enableDirectIssuance),
status: z.nativeEnum(CaStatus).describe(CertificateAuthorities.CREATE(type).status)
});
export const GenericUpdateCertificateAuthorityFieldsSchema = (type: CaType) =>
z.object({
name: slugSchema({ field: "name" }).optional().describe(CertificateAuthorities.UPDATE(type).name),
projectId: z.string().uuid("Project ID must be valid").describe(CertificateAuthorities.UPDATE(type).projectId),
enableDirectIssuance: z.boolean().optional().describe(CertificateAuthorities.UPDATE(type).enableDirectIssuance),
status: z.nativeEnum(CaStatus).optional().describe(CertificateAuthorities.UPDATE(type).status)
});

View File

@@ -0,0 +1,14 @@
import { CaType } from "../certificate-authority-enums";
import {
GenericCreateCertificateAuthorityFieldsSchema,
GenericUpdateCertificateAuthorityFieldsSchema
} from "../deprecated-certificate-authority-schemas";
import { InternalCertificateAuthorityConfigurationSchema } from "./internal-certificate-authority-schemas";
export const CreateInternalCertificateAuthoritySchema = GenericCreateCertificateAuthorityFieldsSchema(
CaType.INTERNAL
).extend({
configuration: InternalCertificateAuthorityConfigurationSchema
});
export const UpdateInternalCertificateAuthoritySchema = GenericUpdateCertificateAuthorityFieldsSchema(CaType.INTERNAL);

View File

@@ -11,7 +11,7 @@ import {
} from "../certificate-authority-schemas";
import { validateCaDateField } from "../certificate-authority-validators";
const InternalCertificateAuthorityConfigurationSchema = z
export const InternalCertificateAuthorityConfigurationSchema = z
.object({
type: z.nativeEnum(InternalCaType).describe(CertificateAuthorities.CONFIGURATIONS.INTERNAL.type),
friendlyName: z.string().optional().describe(CertificateAuthorities.CONFIGURATIONS.INTERNAL.friendlyName),