Merge pull request #2345 from Infisical/misc/finalize-certificate-template-and-est

finalized certificate template and EST
This commit is contained in:
Sheen
2024-08-29 12:47:13 +08:00
committed by GitHub
13 changed files with 155 additions and 63 deletions
+1 -1
View File
@@ -7,6 +7,7 @@ import { TAuditLogServiceFactory } from "@app/ee/services/audit-log/audit-log-se
import { TCreateAuditLogDTO } from "@app/ee/services/audit-log/audit-log-types"; import { TCreateAuditLogDTO } from "@app/ee/services/audit-log/audit-log-types";
import { TAuditLogStreamServiceFactory } from "@app/ee/services/audit-log-stream/audit-log-stream-service"; import { TAuditLogStreamServiceFactory } from "@app/ee/services/audit-log-stream/audit-log-stream-service";
import { TCertificateAuthorityCrlServiceFactory } from "@app/ee/services/certificate-authority-crl/certificate-authority-crl-service"; import { TCertificateAuthorityCrlServiceFactory } from "@app/ee/services/certificate-authority-crl/certificate-authority-crl-service";
import { TCertificateEstServiceFactory } from "@app/ee/services/certificate-est/certificate-est-service";
import { TDynamicSecretServiceFactory } from "@app/ee/services/dynamic-secret/dynamic-secret-service"; import { TDynamicSecretServiceFactory } from "@app/ee/services/dynamic-secret/dynamic-secret-service";
import { TDynamicSecretLeaseServiceFactory } from "@app/ee/services/dynamic-secret-lease/dynamic-secret-lease-service"; import { TDynamicSecretLeaseServiceFactory } from "@app/ee/services/dynamic-secret-lease/dynamic-secret-lease-service";
import { TExternalKmsServiceFactory } from "@app/ee/services/external-kms/external-kms-service"; import { TExternalKmsServiceFactory } from "@app/ee/services/external-kms/external-kms-service";
@@ -36,7 +37,6 @@ import { ActorAuthMethod, ActorType } from "@app/services/auth/auth-type";
import { TAuthTokenServiceFactory } from "@app/services/auth-token/auth-token-service"; import { TAuthTokenServiceFactory } from "@app/services/auth-token/auth-token-service";
import { TCertificateServiceFactory } from "@app/services/certificate/certificate-service"; import { TCertificateServiceFactory } from "@app/services/certificate/certificate-service";
import { TCertificateAuthorityServiceFactory } from "@app/services/certificate-authority/certificate-authority-service"; import { TCertificateAuthorityServiceFactory } from "@app/services/certificate-authority/certificate-authority-service";
import { TCertificateEstServiceFactory } from "@app/services/certificate-est/certificate-est-service";
import { TCertificateTemplateServiceFactory } from "@app/services/certificate-template/certificate-template-service"; import { TCertificateTemplateServiceFactory } from "@app/services/certificate-template/certificate-template-service";
import { TGroupProjectServiceFactory } from "@app/services/group-project/group-project-service"; import { TGroupProjectServiceFactory } from "@app/services/group-project/group-project-service";
import { TIdentityServiceFactory } from "@app/services/identity/identity-service"; import { TIdentityServiceFactory } from "@app/services/identity/identity-service";
@@ -1,16 +1,17 @@
import * as x509 from "@peculiar/x509"; import * as x509 from "@peculiar/x509";
import { BadRequestError, NotFoundError, UnauthorizedError } from "@app/lib/errors"; import { BadRequestError, NotFoundError, UnauthorizedError } from "@app/lib/errors";
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 { 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";
import { TProjectDALFactory } from "@app/services/project/project-dal";
import { isCertChainValid } from "../certificate/certificate-fns"; import { TLicenseServiceFactory } from "../license/license-service";
import { TCertificateAuthorityCertDALFactory } from "../certificate-authority/certificate-authority-cert-dal";
import { TCertificateAuthorityDALFactory } from "../certificate-authority/certificate-authority-dal";
import { getCaCertChain, getCaCertChains } from "../certificate-authority/certificate-authority-fns";
import { TCertificateAuthorityServiceFactory } from "../certificate-authority/certificate-authority-service";
import { TCertificateTemplateDALFactory } from "../certificate-template/certificate-template-dal";
import { TCertificateTemplateServiceFactory } from "../certificate-template/certificate-template-service";
import { TKmsServiceFactory } from "../kms/kms-service";
import { TProjectDALFactory } from "../project/project-dal";
import { convertRawCertsToPkcs7 } from "./certificate-est-fns"; import { convertRawCertsToPkcs7 } from "./certificate-est-fns";
type TCertificateEstServiceFactoryDep = { type TCertificateEstServiceFactoryDep = {
@@ -21,6 +22,7 @@ type TCertificateEstServiceFactoryDep = {
certificateAuthorityCertDAL: Pick<TCertificateAuthorityCertDALFactory, "find" | "findById">; certificateAuthorityCertDAL: Pick<TCertificateAuthorityCertDALFactory, "find" | "findById">;
projectDAL: Pick<TProjectDALFactory, "findOne" | "updateById" | "transaction">; projectDAL: Pick<TProjectDALFactory, "findOne" | "updateById" | "transaction">;
kmsService: Pick<TKmsServiceFactory, "decryptWithKmsKey" | "generateKmsKey">; kmsService: Pick<TKmsServiceFactory, "decryptWithKmsKey" | "generateKmsKey">;
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
}; };
export type TCertificateEstServiceFactory = ReturnType<typeof certificateEstServiceFactory>; export type TCertificateEstServiceFactory = ReturnType<typeof certificateEstServiceFactory>;
@@ -32,7 +34,8 @@ export const certificateEstServiceFactory = ({
certificateAuthorityCertDAL, certificateAuthorityCertDAL,
certificateAuthorityDAL, certificateAuthorityDAL,
projectDAL, projectDAL,
kmsService kmsService,
licenseService
}: TCertificateEstServiceFactoryDep) => { }: TCertificateEstServiceFactoryDep) => {
const simpleReenroll = async ({ const simpleReenroll = async ({
csr, csr,
@@ -48,6 +51,14 @@ export const certificateEstServiceFactory = ({
certificateTemplateId certificateTemplateId
}); });
const plan = await licenseService.getPlan(estConfig.orgId);
if (!plan.pkiEst) {
throw new BadRequestError({
message:
"Failed to perform EST operation - simpleReenroll due to plan restriction. Upgrade to the Enterprise plan."
});
}
if (!estConfig.isEnabled) { if (!estConfig.isEnabled) {
throw new BadRequestError({ throw new BadRequestError({
message: "EST is disabled" message: "EST is disabled"
@@ -146,6 +157,14 @@ export const certificateEstServiceFactory = ({
certificateTemplateId certificateTemplateId
}); });
const plan = await licenseService.getPlan(estConfig.orgId);
if (!plan.pkiEst) {
throw new BadRequestError({
message:
"Failed to perform EST operation - simpleEnroll due to plan restriction. Upgrade to the Enterprise plan."
});
}
if (!estConfig.isEnabled) { if (!estConfig.isEnabled) {
throw new BadRequestError({ throw new BadRequestError({
message: "EST is disabled" message: "EST is disabled"
@@ -196,6 +215,24 @@ export const certificateEstServiceFactory = ({
}); });
} }
const estConfig = await certificateTemplateService.getEstConfiguration({
isInternal: true,
certificateTemplateId
});
const plan = await licenseService.getPlan(estConfig.orgId);
if (!plan.pkiEst) {
throw new BadRequestError({
message: "Failed to perform EST operation - caCerts due to plan restriction. Upgrade to the Enterprise plan."
});
}
if (!estConfig.isEnabled) {
throw new BadRequestError({
message: "EST is disabled"
});
}
const ca = await certificateAuthorityDAL.findById(certTemplate.caId); const ca = await certificateAuthorityDAL.findById(certTemplate.caId);
if (!ca) { if (!ca) {
throw new NotFoundError({ throw new NotFoundError({
@@ -45,7 +45,8 @@ export const getDefaultOnPremFeatures = (): TFeatureSet => ({
readLimit: 60, readLimit: 60,
writeLimit: 200, writeLimit: 200,
secretsLimit: 40 secretsLimit: 40
} },
pkiEst: false
}); });
export const setupLicenceRequestWithStore = (baseURL: string, refreshUrl: string, licenseKey: string) => { export const setupLicenceRequestWithStore = (baseURL: string, refreshUrl: string, licenseKey: string) => {
@@ -63,6 +63,7 @@ export type TFeatureSet = {
writeLimit: number; writeLimit: number;
secretsLimit: number; secretsLimit: number;
}; };
pkiEst: boolean;
}; };
export type TOrgPlansTableDTO = { export type TOrgPlansTableDTO = {
+6 -4
View File
@@ -3,6 +3,7 @@ import { Redis } from "ioredis";
import { Knex } from "knex"; import { Knex } from "knex";
import { z } from "zod"; import { z } from "zod";
import { registerCertificateEstRouter } from "@app/ee/routes/est/certificate-est-router";
import { registerV1EERoutes } from "@app/ee/routes/v1"; import { registerV1EERoutes } from "@app/ee/routes/v1";
import { accessApprovalPolicyApproverDALFactory } from "@app/ee/services/access-approval-policy/access-approval-policy-approver-dal"; import { accessApprovalPolicyApproverDALFactory } from "@app/ee/services/access-approval-policy/access-approval-policy-approver-dal";
import { accessApprovalPolicyDALFactory } from "@app/ee/services/access-approval-policy/access-approval-policy-dal"; import { accessApprovalPolicyDALFactory } from "@app/ee/services/access-approval-policy/access-approval-policy-dal";
@@ -17,6 +18,7 @@ import { auditLogStreamDALFactory } from "@app/ee/services/audit-log-stream/audi
import { auditLogStreamServiceFactory } from "@app/ee/services/audit-log-stream/audit-log-stream-service"; import { auditLogStreamServiceFactory } from "@app/ee/services/audit-log-stream/audit-log-stream-service";
import { certificateAuthorityCrlDALFactory } from "@app/ee/services/certificate-authority-crl/certificate-authority-crl-dal"; import { certificateAuthorityCrlDALFactory } from "@app/ee/services/certificate-authority-crl/certificate-authority-crl-dal";
import { certificateAuthorityCrlServiceFactory } from "@app/ee/services/certificate-authority-crl/certificate-authority-crl-service"; import { certificateAuthorityCrlServiceFactory } from "@app/ee/services/certificate-authority-crl/certificate-authority-crl-service";
import { certificateEstServiceFactory } from "@app/ee/services/certificate-est/certificate-est-service";
import { dynamicSecretDALFactory } from "@app/ee/services/dynamic-secret/dynamic-secret-dal"; import { dynamicSecretDALFactory } from "@app/ee/services/dynamic-secret/dynamic-secret-dal";
import { dynamicSecretServiceFactory } from "@app/ee/services/dynamic-secret/dynamic-secret-service"; import { dynamicSecretServiceFactory } from "@app/ee/services/dynamic-secret/dynamic-secret-service";
import { buildDynamicSecretProviders } from "@app/ee/services/dynamic-secret/providers"; import { buildDynamicSecretProviders } from "@app/ee/services/dynamic-secret/providers";
@@ -92,7 +94,6 @@ import { certificateAuthorityDALFactory } from "@app/services/certificate-author
import { certificateAuthorityQueueFactory } from "@app/services/certificate-authority/certificate-authority-queue"; import { certificateAuthorityQueueFactory } from "@app/services/certificate-authority/certificate-authority-queue";
import { certificateAuthoritySecretDALFactory } from "@app/services/certificate-authority/certificate-authority-secret-dal"; import { certificateAuthoritySecretDALFactory } from "@app/services/certificate-authority/certificate-authority-secret-dal";
import { certificateAuthorityServiceFactory } from "@app/services/certificate-authority/certificate-authority-service"; import { certificateAuthorityServiceFactory } from "@app/services/certificate-authority/certificate-authority-service";
import { certificateEstServiceFactory } from "@app/services/certificate-est/certificate-est-service";
import { certificateTemplateDALFactory } from "@app/services/certificate-template/certificate-template-dal"; import { certificateTemplateDALFactory } from "@app/services/certificate-template/certificate-template-dal";
import { certificateTemplateEstConfigDALFactory } from "@app/services/certificate-template/certificate-template-est-config-dal"; import { certificateTemplateEstConfigDALFactory } from "@app/services/certificate-template/certificate-template-est-config-dal";
import { certificateTemplateServiceFactory } from "@app/services/certificate-template/certificate-template-service"; import { certificateTemplateServiceFactory } from "@app/services/certificate-template/certificate-template-service";
@@ -199,7 +200,6 @@ import { injectIdentity } from "../plugins/auth/inject-identity";
import { injectPermission } from "../plugins/auth/inject-permission"; import { injectPermission } from "../plugins/auth/inject-permission";
import { injectRateLimits } from "../plugins/inject-rate-limits"; import { injectRateLimits } from "../plugins/inject-rate-limits";
import { registerSecretScannerGhApp } from "../plugins/secret-scanner"; import { registerSecretScannerGhApp } from "../plugins/secret-scanner";
import { registerCertificateEstRouter } from "./est/certificate-est-router";
import { registerV1Routes } from "./v1"; import { registerV1Routes } from "./v1";
import { registerV2Routes } from "./v2"; import { registerV2Routes } from "./v2";
import { registerV3Routes } from "./v3"; import { registerV3Routes } from "./v3";
@@ -667,7 +667,8 @@ export const registerRoutes = async (
certificateAuthorityDAL, certificateAuthorityDAL,
permissionService, permissionService,
kmsService, kmsService,
projectDAL projectDAL,
licenseService
}); });
const certificateEstService = certificateEstServiceFactory({ const certificateEstService = certificateEstServiceFactory({
@@ -677,7 +678,8 @@ export const registerRoutes = async (
certificateAuthorityCertDAL, certificateAuthorityCertDAL,
certificateAuthorityDAL, certificateAuthorityDAL,
projectDAL, projectDAL,
kmsService kmsService,
licenseService
}); });
const pkiAlertService = pkiAlertServiceFactory({ const pkiAlertService = pkiAlertServiceFactory({
@@ -1,3 +1,5 @@
import { Knex } from "knex";
import { TDbClient } from "@app/db"; import { TDbClient } from "@app/db";
import { TableName } from "@app/db/schemas"; import { TableName } from "@app/db/schemas";
import { DatabaseError } from "@app/lib/errors"; import { DatabaseError } from "@app/lib/errors";
@@ -30,20 +32,21 @@ export const certificateTemplateDALFactory = (db: TDbClient) => {
} }
}; };
const getById = async (id: string) => { const getById = async (id: string, tx?: Knex) => {
try { try {
const certTemplate = await db const certTemplate = await (tx || db.replicaNode())(TableName.CertificateTemplate)
.replicaNode()(TableName.CertificateTemplate)
.join( .join(
TableName.CertificateAuthority, TableName.CertificateAuthority,
`${TableName.CertificateAuthority}.id`, `${TableName.CertificateAuthority}.id`,
`${TableName.CertificateTemplate}.caId` `${TableName.CertificateTemplate}.caId`
) )
.join(TableName.Project, `${TableName.Project}.id`, `${TableName.CertificateAuthority}.projectId`)
.where(`${TableName.CertificateTemplate}.id`, "=", id) .where(`${TableName.CertificateTemplate}.id`, "=", id)
.select(selectAllTableCols(TableName.CertificateTemplate)) .select(selectAllTableCols(TableName.CertificateTemplate))
.select( .select(
db.ref("projectId").withSchema(TableName.CertificateAuthority), db.ref("projectId").withSchema(TableName.CertificateAuthority),
db.ref("friendlyName").as("caName").withSchema(TableName.CertificateAuthority) db.ref("friendlyName").as("caName").withSchema(TableName.CertificateAuthority),
db.ref("orgId").withSchema(TableName.Project)
) )
.first(); .first();
@@ -3,6 +3,7 @@ import * as x509 from "@peculiar/x509";
import bcrypt from "bcrypt"; import bcrypt from "bcrypt";
import { TCertificateTemplateEstConfigsUpdate } from "@app/db/schemas"; import { TCertificateTemplateEstConfigsUpdate } from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
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 { getConfig } from "@app/lib/config/env"; import { getConfig } from "@app/lib/config/env";
@@ -32,6 +33,7 @@ type TCertificateTemplateServiceFactoryDep = {
kmsService: Pick<TKmsServiceFactory, "generateKmsKey" | "encryptWithKmsKey" | "decryptWithKmsKey">; kmsService: Pick<TKmsServiceFactory, "generateKmsKey" | "encryptWithKmsKey" | "decryptWithKmsKey">;
certificateAuthorityDAL: Pick<TCertificateAuthorityDALFactory, "findById">; certificateAuthorityDAL: Pick<TCertificateAuthorityDALFactory, "findById">;
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">; permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
}; };
export type TCertificateTemplateServiceFactory = ReturnType<typeof certificateTemplateServiceFactory>; export type TCertificateTemplateServiceFactory = ReturnType<typeof certificateTemplateServiceFactory>;
@@ -42,7 +44,8 @@ export const certificateTemplateServiceFactory = ({
certificateAuthorityDAL, certificateAuthorityDAL,
permissionService, permissionService,
kmsService, kmsService,
projectDAL projectDAL,
licenseService
}: TCertificateTemplateServiceFactoryDep) => { }: TCertificateTemplateServiceFactoryDep) => {
const createCertTemplate = async ({ const createCertTemplate = async ({
caId, caId,
@@ -75,16 +78,20 @@ export const certificateTemplateServiceFactory = ({
ProjectPermissionSub.CertificateTemplates ProjectPermissionSub.CertificateTemplates
); );
const { id } = await certificateTemplateDAL.create({ return certificateTemplateDAL.transaction(async (tx) => {
const { id } = await certificateTemplateDAL.create(
{
caId, caId,
pkiCollectionId, pkiCollectionId,
name, name,
commonName, commonName,
subjectAlternativeName, subjectAlternativeName,
ttl ttl
}); },
tx
);
const certificateTemplate = await certificateTemplateDAL.getById(id); const certificateTemplate = await certificateTemplateDAL.getById(id, tx);
if (!certificateTemplate) { if (!certificateTemplate) {
throw new NotFoundError({ throw new NotFoundError({
message: "Certificate template not found" message: "Certificate template not found"
@@ -92,6 +99,7 @@ export const certificateTemplateServiceFactory = ({
} }
return certificateTemplate; return certificateTemplate;
});
}; };
const updateCertTemplate = async ({ const updateCertTemplate = async ({
@@ -136,16 +144,21 @@ export const certificateTemplateServiceFactory = ({
} }
} }
await certificateTemplateDAL.updateById(certTemplate.id, { return certificateTemplateDAL.transaction(async (tx) => {
await certificateTemplateDAL.updateById(
certTemplate.id,
{
caId, caId,
pkiCollectionId, pkiCollectionId,
commonName, commonName,
subjectAlternativeName, subjectAlternativeName,
name, name,
ttl ttl
}); },
tx
);
const updatedTemplate = await certificateTemplateDAL.getById(id); const updatedTemplate = await certificateTemplateDAL.getById(id, tx);
if (!updatedTemplate) { if (!updatedTemplate) {
throw new NotFoundError({ throw new NotFoundError({
message: "Certificate template not found" message: "Certificate template not found"
@@ -153,6 +166,7 @@ export const certificateTemplateServiceFactory = ({
} }
return updatedTemplate; return updatedTemplate;
});
}; };
const deleteCertTemplate = async ({ id, actorId, actorAuthMethod, actor, actorOrgId }: TDeleteCertTemplateDTO) => { const deleteCertTemplate = async ({ id, actorId, actorAuthMethod, actor, actorOrgId }: TDeleteCertTemplateDTO) => {
@@ -215,6 +229,13 @@ export const certificateTemplateServiceFactory = ({
actor, actor,
actorOrgId actorOrgId
}: TCreateEstConfigurationDTO) => { }: TCreateEstConfigurationDTO) => {
const plan = await licenseService.getPlan(actorOrgId);
if (!plan.pkiEst) {
throw new BadRequestError({
message: "Failed to create EST configuration due to plan restriction. Upgrade to the Enterprise plan."
});
}
const certTemplate = await certificateTemplateDAL.getById(certificateTemplateId); const certTemplate = await certificateTemplateDAL.getById(certificateTemplateId);
if (!certTemplate) { if (!certTemplate) {
throw new NotFoundError({ throw new NotFoundError({
@@ -285,6 +306,13 @@ export const certificateTemplateServiceFactory = ({
actor, actor,
actorOrgId actorOrgId
}: TUpdateEstConfigurationDTO) => { }: TUpdateEstConfigurationDTO) => {
const plan = await licenseService.getPlan(actorOrgId);
if (!plan.pkiEst) {
throw new BadRequestError({
message: "Failed to update EST configuration due to plan restriction. Upgrade to the Enterprise plan."
});
}
const certTemplate = await certificateTemplateDAL.getById(certificateTemplateId); const certTemplate = await certificateTemplateDAL.getById(certificateTemplateId);
if (!certTemplate) { if (!certTemplate) {
throw new NotFoundError({ throw new NotFoundError({
@@ -416,7 +444,8 @@ export const certificateTemplateServiceFactory = ({
isEnabled: estConfig.isEnabled, isEnabled: estConfig.isEnabled,
caChain: decryptedCaChain.toString(), caChain: decryptedCaChain.toString(),
hashedPassphrase: estConfig.hashedPassphrase, hashedPassphrase: estConfig.hashedPassphrase,
projectId: certTemplate.projectId projectId: certTemplate.projectId,
orgId: certTemplate.orgId
}; };
}; };
+3 -2
View File
@@ -21,7 +21,8 @@ These endpoints are exposed on port 8443 under the .well-known/est path e.g.
- You need to have an existing [CA hierarchy](/documentation/platform/pki/private-ca). - You need to have an existing [CA hierarchy](/documentation/platform/pki/private-ca).
- The client devices need to have a bootstrap/pre-installed certificate. - The client devices need to have a bootstrap/pre-installed certificate.
- The client devices must trust the server certificates used by Infisical's EST server. If the devices are new or lack existing trust configurations, you need to manually establish trust for the appropriate certificates. When using Infisical Cloud, this means establishing trust for certificates issued by AWS. - The client devices must trust the server certificates used by Infisical's EST server. If the devices are new or lack existing trust configurations, you need to manually establish trust for the appropriate certificates.
- For Infisical Cloud users, the devices must be configured to trust the [Amazon root CA certificates](https://www.amazontrust.com/repository).
## Guide to configuring EST ## Guide to configuring EST
@@ -42,7 +43,7 @@ These endpoints are exposed on port 8443 under the .well-known/est path e.g.
4. Once the configuration of enrollment options is completed, a new **EST Label** field appears in the enrollment settings. This is the value to use as label in the URL when configuring the connection of EST clients to Infisical. 4. Once the configuration of enrollment options is completed, a new **EST Label** field appears in the enrollment settings. This is the value to use as label in the URL when configuring the connection of EST clients to Infisical.
![est enrollment modal create](/images/platform/pki/est/template-enrollment-est-label.png) ![est enrollment modal create](/images/platform/pki/est/template-enrollment-est-label.png)
For demonstration, the complete URL of the supported EST endpoints will look like the following: The complete URL of the supported EST endpoints will look like the following:
- https://app.infisical.com:8443/.well-known/est/f110f308-9888-40ab-b228-237b12de8b96/cacerts - https://app.infisical.com:8443/.well-known/est/f110f308-9888-40ab-b228-237b12de8b96/cacerts
- https://app.infisical.com:8443/.well-known/est/f110f308-9888-40ab-b228-237b12de8b96/simpleenroll - https://app.infisical.com:8443/.well-known/est/f110f308-9888-40ab-b228-237b12de8b96/simpleenroll
@@ -41,4 +41,5 @@ export type SubscriptionPlan = {
caCrl: boolean; caCrl: boolean;
instanceUserManagement: boolean; instanceUserManagement: boolean;
externalKms: boolean; externalKms: boolean;
pkiEst: boolean;
}; };
@@ -3,7 +3,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { createNotification } from "@app/components/notifications"; import { createNotification } from "@app/components/notifications";
import { ProjectPermissionCan } from "@app/components/permissions"; import { ProjectPermissionCan } from "@app/components/permissions";
import { Button, DeleteActionModal } from "@app/components/v2"; import { Button, DeleteActionModal, UpgradePlanModal } from "@app/components/v2";
import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context";
import { usePopUp } from "@app/hooks"; import { usePopUp } from "@app/hooks";
import { useDeleteCertTemplate } from "@app/hooks/api"; import { useDeleteCertTemplate } from "@app/hooks/api";
@@ -16,7 +16,8 @@ export const CertificateTemplatesSection = () => {
const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([ const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([
"certificateTemplate", "certificateTemplate",
"deleteCertificateTemplate", "deleteCertificateTemplate",
"enrollmentOptions" "enrollmentOptions",
"upgradePlan"
] as const); ] as const);
const { currentWorkspace } = useWorkspace(); const { currentWorkspace } = useWorkspace();
@@ -85,6 +86,11 @@ export const CertificateTemplatesSection = () => {
) )
} }
/> />
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
text="Managing template enrollment options for EST is only available on Infisical's Enterprise plan."
/>
</div> </div>
); );
}; };
@@ -19,14 +19,19 @@ import {
Tooltip, Tooltip,
Tr Tr
} from "@app/components/v2"; } from "@app/components/v2";
import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; import {
ProjectPermissionActions,
ProjectPermissionSub,
useSubscription,
useWorkspace
} from "@app/context";
import { useListWorkspaceCertificateTemplates } from "@app/hooks/api"; import { useListWorkspaceCertificateTemplates } from "@app/hooks/api";
import { UsePopUpState } from "@app/hooks/usePopUp"; import { UsePopUpState } from "@app/hooks/usePopUp";
type Props = { type Props = {
handlePopUpOpen: ( handlePopUpOpen: (
popUpName: keyof UsePopUpState< popUpName: keyof UsePopUpState<
["certificateTemplate", "deleteCertificateTemplate", "enrollmentOptions"] ["certificateTemplate", "deleteCertificateTemplate", "enrollmentOptions", "upgradePlan"]
>, >,
data?: { data?: {
id?: string; id?: string;
@@ -37,6 +42,7 @@ type Props = {
export const CertificateTemplatesTable = ({ handlePopUpOpen }: Props) => { export const CertificateTemplatesTable = ({ handlePopUpOpen }: Props) => {
const { currentWorkspace } = useWorkspace(); const { currentWorkspace } = useWorkspace();
const { subscription } = useSubscription();
const { data, isLoading } = useListWorkspaceCertificateTemplates({ const { data, isLoading } = useListWorkspaceCertificateTemplates({
workspaceId: currentWorkspace?.id ?? "" workspaceId: currentWorkspace?.id ?? ""
}); });
@@ -86,11 +92,16 @@ export const CertificateTemplatesTable = ({ handlePopUpOpen }: Props) => {
> >
{(isAllowed) => ( {(isAllowed) => (
<DropdownMenuItem <DropdownMenuItem
onClick={() => onClick={() => {
if (!subscription?.pkiEst) {
handlePopUpOpen("upgradePlan");
return;
}
handlePopUpOpen("enrollmentOptions", { handlePopUpOpen("enrollmentOptions", {
id: certificateTemplate.id id: certificateTemplate.id
}) });
} }}
className={twMerge( className={twMerge(
!isAllowed && "pointer-events-none cursor-not-allowed opacity-50" !isAllowed && "pointer-events-none cursor-not-allowed opacity-50"
)} )}