Start moving CRL generation to queue

This commit is contained in:
Tuan Dang
2024-06-03 16:16:05 -07:00
parent 31de0755a2
commit 7ee440fa3f
13 changed files with 346 additions and 6 deletions

View File

@@ -38,6 +38,9 @@ import {
TCertificateAuthorityCerts, TCertificateAuthorityCerts,
TCertificateAuthorityCertsInsert, TCertificateAuthorityCertsInsert,
TCertificateAuthorityCertsUpdate, TCertificateAuthorityCertsUpdate,
TCertificateAuthorityCrl,
TCertificateAuthorityCrlInsert,
TCertificateAuthorityCrlUpdate,
TCertificateAuthoritySk, TCertificateAuthoritySk,
TCertificateAuthoritySkInsert, TCertificateAuthoritySkInsert,
TCertificateAuthoritySkUpdate, TCertificateAuthoritySkUpdate,
@@ -279,6 +282,11 @@ declare module "knex/types/tables" {
TCertificateAuthoritySkInsert, TCertificateAuthoritySkInsert,
TCertificateAuthoritySkUpdate TCertificateAuthoritySkUpdate
>; >;
[TableName.CertificateAuthorityCrl]: Knex.CompositeTableType<
TCertificateAuthorityCrl,
TCertificateAuthorityCrlInsert,
TCertificateAuthorityCrlUpdate
>;
[TableName.Certificate]: Knex.CompositeTableType<TCertificates, TCertificatesInsert, TCertificatesUpdate>; [TableName.Certificate]: Knex.CompositeTableType<TCertificates, TCertificatesInsert, TCertificatesUpdate>;
[TableName.CertificateCert]: Knex.CompositeTableType< [TableName.CertificateCert]: Knex.CompositeTableType<
TCertificateCerts, TCertificateCerts,

View File

@@ -54,6 +54,19 @@ export async function up(knex: Knex): Promise<void> {
}); });
} }
if (!(await knex.schema.hasTable(TableName.CertificateAuthorityCrl))) {
await knex.schema.createTable(TableName.CertificateAuthorityCrl, (t) => {
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
t.timestamps(true, true, true);
t.uuid("caId").notNullable().unique();
t.foreign("caId").references("id").inTable(TableName.CertificateAuthority).onDelete("CASCADE");
t.text("crl").notNullable(); // TODO: encrypt
t.integer("ttl").notNullable(); // in minutes
// TODO: consider type (crl or delta)
// TODO: rebuild interval
});
}
if (!(await knex.schema.hasTable(TableName.Certificate))) { if (!(await knex.schema.hasTable(TableName.Certificate))) {
await knex.schema.createTable(TableName.Certificate, (t) => { await knex.schema.createTable(TableName.Certificate, (t) => {
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid()); t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
@@ -100,6 +113,9 @@ export async function down(knex: Knex): Promise<void> {
await knex.schema.dropTableIfExists(TableName.CertificateAuthoritySk); await knex.schema.dropTableIfExists(TableName.CertificateAuthoritySk);
await dropOnUpdateTrigger(knex, TableName.CertificateAuthoritySk); await dropOnUpdateTrigger(knex, TableName.CertificateAuthoritySk);
await knex.schema.dropTableIfExists(TableName.CertificateAuthorityCrl);
await dropOnUpdateTrigger(knex, TableName.CertificateAuthorityCrl);
await knex.schema.dropTableIfExists(TableName.CertificateAuthorityCert); await knex.schema.dropTableIfExists(TableName.CertificateAuthorityCert);
await dropOnUpdateTrigger(knex, TableName.CertificateAuthorityCert); await dropOnUpdateTrigger(knex, TableName.CertificateAuthorityCert);

View File

@@ -0,0 +1,23 @@
// 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 CertificateAuthorityCrlSchema = z.object({
id: z.string().uuid(),
createdAt: z.date(),
updatedAt: z.date(),
caId: z.string().uuid(),
crl: z.string(),
ttl: z.number()
});
export type TCertificateAuthorityCrl = z.infer<typeof CertificateAuthorityCrlSchema>;
export type TCertificateAuthorityCrlInsert = Omit<z.input<typeof CertificateAuthorityCrlSchema>, TImmutableDBKeys>;
export type TCertificateAuthorityCrlUpdate = Partial<
Omit<z.input<typeof CertificateAuthorityCrlSchema>, TImmutableDBKeys>
>;

View File

@@ -10,6 +10,7 @@ export * from "./auth-tokens";
export * from "./backup-private-key"; 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-sk"; export * from "./certificate-authority-sk";
export * from "./certificate-certs"; export * from "./certificate-certs";
export * from "./certificate-secrets"; export * from "./certificate-secrets";

View File

@@ -5,6 +5,7 @@ export enum TableName {
CertificateAuthority = "certificate_authorities", CertificateAuthority = "certificate_authorities",
CertificateAuthorityCert = "certificate_authority_certs", CertificateAuthorityCert = "certificate_authority_certs",
CertificateAuthoritySk = "certificate_authority_sk", CertificateAuthoritySk = "certificate_authority_sk",
CertificateAuthorityCrl = "certificate_authority_crl",
Certificate = "certificates", Certificate = "certificates",
CertificateCert = "certificate_certs", CertificateCert = "certificate_certs",
CertificateSecret = "certificate_secrets", CertificateSecret = "certificate_secrets",

View File

@@ -21,7 +21,8 @@ export enum QueueName {
SecretFullRepoScan = "secret-full-repo-scan", SecretFullRepoScan = "secret-full-repo-scan",
SecretPushEventScan = "secret-push-event-scan", SecretPushEventScan = "secret-push-event-scan",
UpgradeProjectToGhost = "upgrade-project-to-ghost", UpgradeProjectToGhost = "upgrade-project-to-ghost",
DynamicSecretRevocation = "dynamic-secret-revocation" DynamicSecretRevocation = "dynamic-secret-revocation",
CaCrlRotation = "ca-crl-rotation"
} }
export enum QueueJobs { export enum QueueJobs {
@@ -37,7 +38,8 @@ export enum QueueJobs {
SecretScan = "secret-scan", SecretScan = "secret-scan",
UpgradeProjectToGhost = "upgrade-project-to-ghost-job", UpgradeProjectToGhost = "upgrade-project-to-ghost-job",
DynamicSecretRevocation = "dynamic-secret-revocation", DynamicSecretRevocation = "dynamic-secret-revocation",
DynamicSecretPruning = "dynamic-secret-pruning" DynamicSecretPruning = "dynamic-secret-pruning",
CaCrlRotation = "ca-crl-rotation-job"
} }
export type TQueueJobTypes = { export type TQueueJobTypes = {
@@ -50,7 +52,6 @@ export type TQueueJobTypes = {
}; };
name: QueueJobs.SecretReminder; name: QueueJobs.SecretReminder;
}; };
[QueueName.SecretRotation]: { [QueueName.SecretRotation]: {
payload: { rotationId: string }; payload: { rotationId: string };
name: QueueJobs.SecretRotation; name: QueueJobs.SecretRotation;
@@ -116,6 +117,12 @@ export type TQueueJobTypes = {
dynamicSecretCfgId: string; dynamicSecretCfgId: string;
}; };
}; };
[QueueName.CaCrlRotation]: {
name: QueueJobs.CaCrlRotation;
payload: {
caId: string;
};
};
}; };
export type TQueueServiceFactory = ReturnType<typeof queueServiceFactory>; export type TQueueServiceFactory = ReturnType<typeof queueServiceFactory>;

View File

@@ -74,7 +74,9 @@ import { certificateCertDALFactory } from "@app/services/certificate/certificate
import { certificateDALFactory } from "@app/services/certificate/certificate-dal"; import { certificateDALFactory } from "@app/services/certificate/certificate-dal";
import { certificateServiceFactory } from "@app/services/certificate/certificate-service"; import { certificateServiceFactory } from "@app/services/certificate/certificate-service";
import { certificateAuthorityCertDALFactory } from "@app/services/certificate-authority/certificate-authority-cert-dal"; import { certificateAuthorityCertDALFactory } from "@app/services/certificate-authority/certificate-authority-cert-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 { 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 { 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";
@@ -503,6 +505,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 certificateAuthoritySkDAL = certificateAuthoritySkDALFactory(db);
const certificateAuthorityCrlDAL = certificateAuthorityCrlDALFactory(db);
const certificateDAL = certificateDALFactory(db); const certificateDAL = certificateDALFactory(db);
const certificateCertDAL = certificateCertDALFactory(db); const certificateCertDAL = certificateCertDALFactory(db);
@@ -514,10 +517,20 @@ export const registerRoutes = async (
permissionService permissionService
}); });
const certificateAuthorityQueue = certificateAuthorityQueueFactory({
certificateAuthorityCrlDAL,
certificateAuthorityDAL,
certificateAuthoritySkDAL,
certificateDAL,
queueService
});
const certificateAuthorityService = certificateAuthorityServiceFactory({ const certificateAuthorityService = certificateAuthorityServiceFactory({
certificateAuthorityDAL, certificateAuthorityDAL,
certificateAuthorityCertDAL, certificateAuthorityCertDAL,
certificateAuthoritySkDAL, certificateAuthoritySkDAL,
certificateAuthorityCrlDAL,
certificateAuthorityQueue,
certificateDAL, certificateDAL,
certificateCertDAL, certificateCertDAL,
projectDAL, projectDAL,

View File

@@ -419,4 +419,36 @@ export const registerCaRouter = async (server: FastifyZodProvider) => {
}; };
} }
}); });
server.route({
method: "GET",
url: "/:caId/crl/rotate",
config: {
rateLimit: writeLimit
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "Rotate CRL of the CA",
params: z.object({
caId: z.string().trim()
}),
response: {
200: z.object({
message: z.string()
})
}
},
handler: async (req) => {
await server.services.certificateAuthority.rotateCaCrl({
caId: req.params.caId,
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId
});
return {
message: "Successfully rotated CA CRL"
};
}
});
}; };

View File

@@ -0,0 +1,10 @@
import { TDbClient } from "@app/db";
import { TableName } from "@app/db/schemas";
import { ormify } from "@app/lib/knex";
export type TCertificateAuthorityCrlDALFactory = ReturnType<typeof certificateAuthorityCrlDALFactory>;
export const certificateAuthorityCrlDALFactory = (db: TDbClient) => {
const caCrlOrm = ormify(db, TableName.CertificateAuthorityCrl);
return caCrlOrm;
};

View File

@@ -0,0 +1,124 @@
import * as x509 from "@peculiar/x509";
import crypto from "crypto";
import { getConfig } from "@app/lib/config/env";
import { daysToMillisecond, secondsToMillis } from "@app/lib/dates";
import { BadRequestError } from "@app/lib/errors";
import { logger } from "@app/lib/logger";
import { QueueJobs, QueueName, TQueueServiceFactory } from "@app/queue";
import { TCertificateDALFactory } from "@app/services/certificate/certificate-dal";
import { CertKeyAlgorithm, CertStatus } from "@app/services/certificate/certificate-types";
import { TCertificateAuthorityCrlDALFactory } from "./certificate-authority-crl-dal";
import { TCertificateAuthorityDALFactory } from "./certificate-authority-dal";
import { keyAlgorithmToAlgCfg } from "./certificate-authority-fns";
import { TCertificateAuthoritySkDALFactory } from "./certificate-authority-sk-dal";
import { TRotateCaCrlTriggerDTO } from "./certificate-authority-types";
type TCertificateAuthorityQueueFactoryDep = {
// TODO: Pick
certificateAuthorityDAL: TCertificateAuthorityDALFactory;
certificateAuthorityCrlDAL: TCertificateAuthorityCrlDALFactory;
certificateAuthoritySkDAL: TCertificateAuthoritySkDALFactory;
certificateDAL: TCertificateDALFactory;
queueService: TQueueServiceFactory;
};
export type TCertificateAuthorityQueueFactory = ReturnType<typeof certificateAuthorityQueueFactory>;
export const certificateAuthorityQueueFactory = ({
certificateAuthorityCrlDAL,
certificateAuthorityDAL,
certificateAuthoritySkDAL,
certificateDAL,
queueService
}: TCertificateAuthorityQueueFactoryDep) => {
// TODO 1: auto-periodic rotation
// TODO 2: manual rotation
const setCaCrlRotationInterval = async ({ caId, rotationIntervalDays }: TRotateCaCrlTriggerDTO) => {
const appCfg = getConfig();
// query for config
// const caCrl = await certificateAuthorityCrlDAL.findOne({
// caId
// });
await queueService.queue(
// TODO: clarify queue + job naming
QueueName.CaCrlRotation,
QueueJobs.CaCrlRotation,
{
caId
},
{
jobId: `ca-crl-rotation-${caId}`,
repeat: {
// on prod it this will be in days, in development this will be second
every:
appCfg.NODE_ENV === "development"
? secondsToMillis(rotationIntervalDays)
: daysToMillisecond(rotationIntervalDays),
immediately: true
}
}
);
};
queueService.start(QueueName.CaCrlRotation, async (job) => {
const { caId } = job.data;
logger.info(`secretReminderQueue.process: [secretDocument=${caId}]`);
const ca = await certificateAuthorityDAL.findById(caId);
if (!ca) throw new BadRequestError({ message: "CA not found" });
const caKeys = await certificateAuthoritySkDAL.findOne({ caId: ca.id });
const alg = keyAlgorithmToAlgCfg(ca.keyAlgorithm as CertKeyAlgorithm);
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, [
"sign"
]);
const revokedCerts = await certificateDAL.find({
caId: ca.id,
status: CertStatus.REVOKED
});
const crl = await x509.X509CrlGenerator.create({
issuer: ca.dn,
thisUpdate: new Date(),
nextUpdate: new Date("2025/12/12"), // TODO: depends on configured rebuild interval
entries: revokedCerts.map((revokedCert) => {
return {
serialNumber: revokedCert.serialNumber,
revocationDate: new Date(revokedCert.revokedAt as Date),
reason: revokedCert.revocationReason as number,
invalidity: new Date("2022/01/01"),
issuer: ca.dn
};
}),
signingAlgorithm: alg,
signingKey: sk
});
const base64crl = crl.toString("base64");
const crlPem = `-----BEGIN X509 CRL-----\n${base64crl.match(/.{1,64}/g)?.join("\n")}\n-----END X509 CRL-----`;
await certificateAuthorityCrlDAL.update(
{
caId: ca.id
},
{
crl: crlPem // TODO: encrypt
}
);
});
queueService.listen(QueueName.CaCrlRotation, "failed", (job, err) => {
logger.error(err, "Failed to rotate CA CRL %s", job?.id);
});
return {
setCaCrlRotationInterval
};
};

View File

@@ -12,8 +12,10 @@ import { TProjectDALFactory } from "@app/services/project/project-dal";
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";
import { TCertificateAuthorityCrlDALFactory } from "./certificate-authority-crl-dal";
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 { TCertificateAuthoritySkDALFactory } from "./certificate-authority-sk-dal"; import { TCertificateAuthoritySkDALFactory } from "./certificate-authority-sk-dal";
import { import {
CaStatus, CaStatus,
@@ -26,6 +28,7 @@ import {
TGetCrl, TGetCrl,
TImportCertToCaDTO, TImportCertToCaDTO,
TIssueCertFromCaDTO, TIssueCertFromCaDTO,
TRotateCrlDTO,
TSignIntermediateDTO, TSignIntermediateDTO,
TUpdateCaDTO TUpdateCaDTO
} from "./certificate-authority-types"; } from "./certificate-authority-types";
@@ -37,6 +40,8 @@ type TCertificateAuthorityServiceFactoryDep = {
>; >;
certificateAuthorityCertDAL: Pick<TCertificateAuthorityCertDALFactory, "create" | "findOne" | "transaction">; certificateAuthorityCertDAL: Pick<TCertificateAuthorityCertDALFactory, "create" | "findOne" | "transaction">;
certificateAuthoritySkDAL: Pick<TCertificateAuthoritySkDALFactory, "create" | "findOne">; certificateAuthoritySkDAL: Pick<TCertificateAuthoritySkDALFactory, "create" | "findOne">;
certificateAuthorityCrlDAL: Pick<TCertificateAuthorityCrlDALFactory, "create" | "findOne" | "update">;
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">;
@@ -49,6 +54,7 @@ export const certificateAuthorityServiceFactory = ({
certificateAuthorityDAL, certificateAuthorityDAL,
certificateAuthorityCertDAL, certificateAuthorityCertDAL,
certificateAuthoritySkDAL, certificateAuthoritySkDAL,
certificateAuthorityCrlDAL,
certificateDAL, certificateDAL,
certificateCertDAL, certificateCertDAL,
projectDAL, projectDAL,
@@ -141,6 +147,8 @@ export const certificateAuthorityServiceFactory = ({
tx tx
); );
// TODO: create CRL
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
@@ -168,6 +176,15 @@ export const certificateAuthorityServiceFactory = ({
}, },
tx tx
); );
await certificateAuthorityCrlDAL.create(
{
caId: ca.id,
crl: "", // TODO: encrypt
ttl: 60 // in minutes
},
tx
);
} }
await certificateAuthoritySkDAL.create( await certificateAuthoritySkDAL.create(
@@ -721,6 +738,70 @@ export const certificateAuthorityServiceFactory = ({
}; };
}; };
const rotateCaCrl = async ({ caId, actorId, actorAuthMethod, actor, actorOrgId }: TRotateCrlDTO) => {
const ca = await certificateAuthorityDAL.findById(caId);
if (!ca) throw new BadRequestError({ message: "CA not found" });
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
ca.projectId,
actorAuthMethod,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Read,
ProjectPermissionSub.CertificateAuthorities
);
const caKeys = await certificateAuthoritySkDAL.findOne({ caId: ca.id });
const alg = keyAlgorithmToAlgCfg(ca.keyAlgorithm as CertKeyAlgorithm);
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, [
"sign"
]);
const revokedCerts = await certificateDAL.find({
caId: ca.id,
status: CertStatus.REVOKED
});
const crl = await x509.X509CrlGenerator.create({
issuer: ca.dn,
thisUpdate: new Date(),
nextUpdate: new Date("2025/12/12"),
entries: revokedCerts.map((revokedCert) => {
return {
serialNumber: revokedCert.serialNumber,
revocationDate: new Date(revokedCert.revokedAt as Date),
reason: revokedCert.revocationReason as number,
invalidity: new Date("2022/01/01"),
issuer: ca.dn
};
}),
signingAlgorithm: alg,
signingKey: sk
});
const base64crl = crl.toString("base64");
const crlPem = `-----BEGIN X509 CRL-----\n${base64crl.match(/.{1,64}/g)?.join("\n")}\n-----END X509 CRL-----`;
await certificateAuthorityCrlDAL.update(
{
caId: ca.id
},
{
crl: crlPem // TODO: encrypt
}
);
return {
crl: crlPem
};
};
return { return {
createCa, createCa,
getCaById, getCaById,
@@ -731,6 +812,7 @@ export const certificateAuthorityServiceFactory = ({
signIntermediate, signIntermediate,
importCertToCa, importCertToCa,
issueCertFromCa, issueCertFromCa,
getCaCrl getCaCrl,
rotateCaCrl
}; };
}; };

View File

@@ -75,6 +75,10 @@ export type TGetCrl = {
caId: string; caId: string;
} & Omit<TProjectPermission, "projectId">; } & Omit<TProjectPermission, "projectId">;
export type TRotateCrlDTO = {
caId: string;
} & Omit<TProjectPermission, "projectId">;
export type TDNParts = { export type TDNParts = {
commonName?: string; commonName?: string;
organization?: string; organization?: string;
@@ -83,3 +87,8 @@ export type TDNParts = {
province?: string; province?: string;
locality?: string; locality?: string;
}; };
export type TRotateCaCrlTriggerDTO = {
caId: string;
rotationIntervalDays: number;
};

View File

@@ -2,7 +2,7 @@ import { useEffect } from "react";
import { faCheck, faCopy, faDownload } from "@fortawesome/free-solid-svg-icons"; import { faCheck, faCopy, faDownload } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { IconButton,Modal, ModalContent } from "@app/components/v2"; import { IconButton, Modal, ModalContent } from "@app/components/v2";
import { useToggle } from "@app/hooks"; import { useToggle } from "@app/hooks";
import { useGetCaCrl } from "@app/hooks/api"; import { useGetCaCrl } from "@app/hooks/api";
import { UsePopUpState } from "@app/hooks/usePopUp"; import { UsePopUpState } from "@app/hooks/usePopUp";
@@ -48,8 +48,22 @@ export const CaCrlModal = ({ popUp, handlePopUpToggle }: Props) => {
<div> <div>
{crl && ( {crl && (
<> <>
{/* <div className="mb-4 flex items-center justify-between">
<h2>Manual CRL Rotation</h2>
<Button
// isLoading={isLoading}
// isDisabled={!isAllowed}
colorSchema="primary"
variant="outline_bg"
type="submit"
// onClick={() => handleAssignment(username, !isPartOfGroup)}
onClick={() => {}}
>
Rotate
</Button>
</div> */}
<div className="mb-4 flex items-center justify-between"> <div className="mb-4 flex items-center justify-between">
<h2>CA CRL</h2> <h2>Certificate Revocation List</h2>
<div className="flex"> <div className="flex">
<IconButton <IconButton
ariaLabel="copy icon" ariaLabel="copy icon"