mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-09 08:28:22 +00:00
Add PKI collection to issue cert modal
This commit is contained in:
@@ -1088,6 +1088,7 @@ export const CERTIFICATE_AUTHORITIES = {
|
|||||||
},
|
},
|
||||||
ISSUE_CERT: {
|
ISSUE_CERT: {
|
||||||
caId: "The ID of the CA to issue the certificate from",
|
caId: "The ID of the CA to issue the certificate from",
|
||||||
|
pkiCollectionId: "The ID of the PKI collection to add the certificate to",
|
||||||
friendlyName: "A friendly name for the certificate",
|
friendlyName: "A friendly name for the certificate",
|
||||||
commonName: "The common name (CN) for the certificate",
|
commonName: "The common name (CN) for the certificate",
|
||||||
altNames:
|
altNames:
|
||||||
@@ -1103,6 +1104,7 @@ export const CERTIFICATE_AUTHORITIES = {
|
|||||||
},
|
},
|
||||||
SIGN_CERT: {
|
SIGN_CERT: {
|
||||||
caId: "The ID of the CA to issue the certificate from",
|
caId: "The ID of the CA to issue the certificate from",
|
||||||
|
pkiCollectionId: "The ID of the PKI collection to add the certificate to",
|
||||||
csr: "The pem-encoded CSR to sign with the CA to be used for certificate issuance",
|
csr: "The pem-encoded CSR to sign with the CA to be used for certificate issuance",
|
||||||
friendlyName: "A friendly name for the certificate",
|
friendlyName: "A friendly name for the certificate",
|
||||||
commonName: "The common name (CN) for the certificate",
|
commonName: "The common name (CN) for the certificate",
|
||||||
|
|||||||
@@ -622,6 +622,8 @@ export const registerRoutes = async (
|
|||||||
certificateAuthorityQueue,
|
certificateAuthorityQueue,
|
||||||
certificateDAL,
|
certificateDAL,
|
||||||
certificateBodyDAL,
|
certificateBodyDAL,
|
||||||
|
pkiCollectionDAL,
|
||||||
|
pkiCollectionItemDAL,
|
||||||
projectDAL,
|
projectDAL,
|
||||||
kmsService,
|
kmsService,
|
||||||
permissionService
|
permissionService
|
||||||
|
|||||||
@@ -556,6 +556,7 @@ export const registerCaRouter = async (server: FastifyZodProvider) => {
|
|||||||
}),
|
}),
|
||||||
body: z
|
body: z
|
||||||
.object({
|
.object({
|
||||||
|
pkiCollectionId: z.string().trim().optional().describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.pkiCollectionId),
|
||||||
friendlyName: z.string().trim().optional().describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.friendlyName),
|
friendlyName: z.string().trim().optional().describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.friendlyName),
|
||||||
commonName: z.string().trim().min(1).describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.commonName),
|
commonName: z.string().trim().min(1).describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.commonName),
|
||||||
altNames: validateAltNamesField.describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.altNames),
|
altNames: validateAltNamesField.describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.altNames),
|
||||||
@@ -635,6 +636,7 @@ export const registerCaRouter = async (server: FastifyZodProvider) => {
|
|||||||
body: z
|
body: z
|
||||||
.object({
|
.object({
|
||||||
csr: z.string().trim().min(1).describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.csr),
|
csr: z.string().trim().min(1).describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.csr),
|
||||||
|
pkiCollectionId: z.string().trim().optional().describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.pkiCollectionId),
|
||||||
friendlyName: z.string().trim().optional().describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.friendlyName),
|
friendlyName: z.string().trim().optional().describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.friendlyName),
|
||||||
commonName: z.string().trim().min(1).optional().describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.commonName),
|
commonName: z.string().trim().min(1).optional().describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.commonName),
|
||||||
altNames: validateAltNamesField.describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.altNames),
|
altNames: validateAltNamesField.describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.altNames),
|
||||||
|
|||||||
@@ -7,10 +7,12 @@ import { z } from "zod";
|
|||||||
|
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
||||||
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
||||||
import { BadRequestError } from "@app/lib/errors";
|
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
||||||
import { TCertificateBodyDALFactory } from "@app/services/certificate/certificate-body-dal";
|
import { TCertificateBodyDALFactory } from "@app/services/certificate/certificate-body-dal";
|
||||||
import { TCertificateDALFactory } from "@app/services/certificate/certificate-dal";
|
import { TCertificateDALFactory } from "@app/services/certificate/certificate-dal";
|
||||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||||
|
import { TPkiCollectionDALFactory } from "@app/services/pki-collection/pki-collection-dal";
|
||||||
|
import { TPkiCollectionItemDALFactory } from "@app/services/pki-collection/pki-collection-item-dal";
|
||||||
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
||||||
import { getProjectKmsCertificateKeyId } from "@app/services/project/project-fns";
|
import { getProjectKmsCertificateKeyId } from "@app/services/project/project-fns";
|
||||||
|
|
||||||
@@ -60,6 +62,8 @@ type TCertificateAuthorityServiceFactoryDep = {
|
|||||||
certificateAuthorityQueue: TCertificateAuthorityQueueFactory; // TODO: Pick
|
certificateAuthorityQueue: TCertificateAuthorityQueueFactory; // TODO: Pick
|
||||||
certificateDAL: Pick<TCertificateDALFactory, "transaction" | "create" | "find">;
|
certificateDAL: Pick<TCertificateDALFactory, "transaction" | "create" | "find">;
|
||||||
certificateBodyDAL: Pick<TCertificateBodyDALFactory, "create">;
|
certificateBodyDAL: Pick<TCertificateBodyDALFactory, "create">;
|
||||||
|
pkiCollectionDAL: Pick<TPkiCollectionDALFactory, "findById">;
|
||||||
|
pkiCollectionItemDAL: Pick<TPkiCollectionItemDALFactory, "create">;
|
||||||
projectDAL: Pick<TProjectDALFactory, "findProjectBySlug" | "findOne" | "updateById" | "findById" | "transaction">;
|
projectDAL: Pick<TProjectDALFactory, "findProjectBySlug" | "findOne" | "updateById" | "findById" | "transaction">;
|
||||||
kmsService: Pick<TKmsServiceFactory, "generateKmsKey" | "encryptWithKmsKey" | "decryptWithKmsKey">;
|
kmsService: Pick<TKmsServiceFactory, "generateKmsKey" | "encryptWithKmsKey" | "decryptWithKmsKey">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
||||||
@@ -74,6 +78,8 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
certificateAuthorityCrlDAL,
|
certificateAuthorityCrlDAL,
|
||||||
certificateDAL,
|
certificateDAL,
|
||||||
certificateBodyDAL,
|
certificateBodyDAL,
|
||||||
|
pkiCollectionDAL,
|
||||||
|
pkiCollectionItemDAL,
|
||||||
projectDAL,
|
projectDAL,
|
||||||
kmsService,
|
kmsService,
|
||||||
permissionService
|
permissionService
|
||||||
@@ -1007,6 +1013,7 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
*/
|
*/
|
||||||
const issueCertFromCa = async ({
|
const issueCertFromCa = async ({
|
||||||
caId,
|
caId,
|
||||||
|
pkiCollectionId,
|
||||||
friendlyName,
|
friendlyName,
|
||||||
commonName,
|
commonName,
|
||||||
altNames,
|
altNames,
|
||||||
@@ -1039,6 +1046,13 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
throw new BadRequestError({ message: "CA is expired" });
|
throw new BadRequestError({ message: "CA is expired" });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check PKI collection
|
||||||
|
if (pkiCollectionId) {
|
||||||
|
const pkiCollection = await pkiCollectionDAL.findById(pkiCollectionId);
|
||||||
|
if (!pkiCollection) throw new NotFoundError({ message: "PKI collection not found" });
|
||||||
|
if (pkiCollection.projectId !== ca.projectId) throw new BadRequestError({ message: "Invalid PKI collection" });
|
||||||
|
}
|
||||||
|
|
||||||
const certificateManagerKmsId = await getProjectKmsCertificateKeyId({
|
const certificateManagerKmsId = await getProjectKmsCertificateKeyId({
|
||||||
projectId: ca.projectId,
|
projectId: ca.projectId,
|
||||||
projectDAL,
|
projectDAL,
|
||||||
@@ -1186,6 +1200,16 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (pkiCollectionId) {
|
||||||
|
await pkiCollectionItemDAL.create(
|
||||||
|
{
|
||||||
|
pkiCollectionId,
|
||||||
|
certId: cert.id
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return cert;
|
return cert;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1214,6 +1238,7 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
const signCertFromCa = async ({
|
const signCertFromCa = async ({
|
||||||
caId,
|
caId,
|
||||||
csr,
|
csr,
|
||||||
|
pkiCollectionId,
|
||||||
friendlyName,
|
friendlyName,
|
||||||
commonName,
|
commonName,
|
||||||
altNames,
|
altNames,
|
||||||
@@ -1247,6 +1272,13 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
throw new BadRequestError({ message: "CA is expired" });
|
throw new BadRequestError({ message: "CA is expired" });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check PKI collection
|
||||||
|
if (pkiCollectionId) {
|
||||||
|
const pkiCollection = await pkiCollectionDAL.findById(pkiCollectionId);
|
||||||
|
if (!pkiCollection) throw new NotFoundError({ message: "PKI collection not found" });
|
||||||
|
if (pkiCollection.projectId !== ca.projectId) throw new BadRequestError({ message: "Invalid PKI collection" });
|
||||||
|
}
|
||||||
|
|
||||||
const certificateManagerKmsId = await getProjectKmsCertificateKeyId({
|
const certificateManagerKmsId = await getProjectKmsCertificateKeyId({
|
||||||
projectId: ca.projectId,
|
projectId: ca.projectId,
|
||||||
projectDAL,
|
projectDAL,
|
||||||
@@ -1390,6 +1422,16 @@ export const certificateAuthorityServiceFactory = ({
|
|||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (pkiCollectionId) {
|
||||||
|
await pkiCollectionItemDAL.create(
|
||||||
|
{
|
||||||
|
pkiCollectionId,
|
||||||
|
certId: cert.id
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return cert;
|
return cert;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ export type TImportCertToCaDTO = {
|
|||||||
|
|
||||||
export type TIssueCertFromCaDTO = {
|
export type TIssueCertFromCaDTO = {
|
||||||
caId: string;
|
caId: string;
|
||||||
|
pkiCollectionId?: string;
|
||||||
friendlyName?: string;
|
friendlyName?: string;
|
||||||
commonName: string;
|
commonName: string;
|
||||||
altNames: string;
|
altNames: string;
|
||||||
@@ -98,6 +99,7 @@ export type TIssueCertFromCaDTO = {
|
|||||||
export type TSignCertFromCaDTO = {
|
export type TSignCertFromCaDTO = {
|
||||||
caId: string;
|
caId: string;
|
||||||
csr: string;
|
csr: string;
|
||||||
|
pkiCollectionId?: string;
|
||||||
friendlyName?: string;
|
friendlyName?: string;
|
||||||
commonName?: string;
|
commonName?: string;
|
||||||
altNames: string;
|
altNames: string;
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ export type TImportCaCertificateResponse = {
|
|||||||
export type TCreateCertificateDTO = {
|
export type TCreateCertificateDTO = {
|
||||||
projectSlug: string;
|
projectSlug: string;
|
||||||
caId: string;
|
caId: string;
|
||||||
|
pkiCollectionId?: string;
|
||||||
friendlyName?: string;
|
friendlyName?: string;
|
||||||
commonName: string;
|
commonName: string;
|
||||||
altNames: string; // sans
|
altNames: string; // sans
|
||||||
|
|||||||
+47
-2
@@ -14,7 +14,13 @@ import {
|
|||||||
SelectItem
|
SelectItem
|
||||||
} from "@app/components/v2";
|
} from "@app/components/v2";
|
||||||
import { useWorkspace } from "@app/context";
|
import { useWorkspace } from "@app/context";
|
||||||
import { CaStatus, useCreateCertificate, useGetCert, useListWorkspaceCas } from "@app/hooks/api";
|
import {
|
||||||
|
CaStatus,
|
||||||
|
useCreateCertificate,
|
||||||
|
useGetCert,
|
||||||
|
useListWorkspaceCas,
|
||||||
|
useListWorkspacePkiCollections
|
||||||
|
} from "@app/hooks/api";
|
||||||
import { caTypeToNameMap } from "@app/hooks/api/ca/constants";
|
import { caTypeToNameMap } from "@app/hooks/api/ca/constants";
|
||||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||||
|
|
||||||
@@ -22,6 +28,7 @@ import { CertificateContent } from "./CertificateContent";
|
|||||||
|
|
||||||
const schema = z.object({
|
const schema = z.object({
|
||||||
caId: z.string(),
|
caId: z.string(),
|
||||||
|
collectionId: z.string().optional(),
|
||||||
friendlyName: z.string(),
|
friendlyName: z.string(),
|
||||||
commonName: z.string().trim().min(1),
|
commonName: z.string().trim().min(1),
|
||||||
altNames: z.string(),
|
altNames: z.string(),
|
||||||
@@ -54,6 +61,10 @@ export const CertificateModal = ({ popUp, handlePopUpToggle }: Props) => {
|
|||||||
status: CaStatus.ACTIVE
|
status: CaStatus.ACTIVE
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { data } = useListWorkspacePkiCollections({
|
||||||
|
workspaceId: currentWorkspace?.id || ""
|
||||||
|
});
|
||||||
|
|
||||||
const { mutateAsync: createCertificate } = useCreateCertificate();
|
const { mutateAsync: createCertificate } = useCreateCertificate();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -86,13 +97,21 @@ export const CertificateModal = ({ popUp, handlePopUpToggle }: Props) => {
|
|||||||
}
|
}
|
||||||
}, [cert]);
|
}, [cert]);
|
||||||
|
|
||||||
const onFormSubmit = async ({ caId, friendlyName, commonName, altNames, ttl }: FormData) => {
|
const onFormSubmit = async ({
|
||||||
|
caId,
|
||||||
|
collectionId,
|
||||||
|
friendlyName,
|
||||||
|
commonName,
|
||||||
|
altNames,
|
||||||
|
ttl
|
||||||
|
}: FormData) => {
|
||||||
try {
|
try {
|
||||||
if (!currentWorkspace?.slug) return;
|
if (!currentWorkspace?.slug) return;
|
||||||
|
|
||||||
const { serialNumber, certificate, certificateChain, privateKey } = await createCertificate({
|
const { serialNumber, certificate, certificateChain, privateKey } = await createCertificate({
|
||||||
projectSlug: currentWorkspace.slug,
|
projectSlug: currentWorkspace.slug,
|
||||||
caId,
|
caId,
|
||||||
|
pkiCollectionId: collectionId,
|
||||||
friendlyName,
|
friendlyName,
|
||||||
commonName,
|
commonName,
|
||||||
altNames,
|
altNames,
|
||||||
@@ -167,6 +186,32 @@ export const CertificateModal = ({ popUp, handlePopUpToggle }: Props) => {
|
|||||||
</FormControl>
|
</FormControl>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="collectionId"
|
||||||
|
render={({ field: { onChange, ...field }, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
label="Certificate Collection (Optional)"
|
||||||
|
errorText={error?.message}
|
||||||
|
isError={Boolean(error)}
|
||||||
|
className="mt-4"
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
defaultValue={field.value}
|
||||||
|
{...field}
|
||||||
|
onValueChange={(e) => onChange(e)}
|
||||||
|
className="w-full"
|
||||||
|
isDisabled={Boolean(cert)}
|
||||||
|
>
|
||||||
|
{(data?.collections || []).map(({ id, name }) => (
|
||||||
|
<SelectItem value={id} key={`pki-collection-${id}`}>
|
||||||
|
{name}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
defaultValue=""
|
defaultValue=""
|
||||||
|
|||||||
Reference in New Issue
Block a user