diff --git a/backend/src/services/certificate-authority/certificate-authority-service.ts b/backend/src/services/certificate-authority/certificate-authority-service.ts
index 32dbc8fd0..b2ee04c4c 100644
--- a/backend/src/services/certificate-authority/certificate-authority-service.ts
+++ b/backend/src/services/certificate-authority/certificate-authority-service.ts
@@ -368,7 +368,6 @@ export const certificateAuthorityServiceFactory = ({
);
if (ca.type === CaType.ROOT) throw new BadRequestError({ message: "Root CA cannot generate CSR" });
- if (ca.activeCaCertId) throw new BadRequestError({ message: "CA already has a certificate installed" });
const { caPrivateKey, caPublicKey } = await getCaCredentials({
caId,
@@ -407,7 +406,8 @@ export const certificateAuthorityServiceFactory = ({
/**
* Renew certificate for CA with id [caId]
- * Note: Currently implements CA renewal with same key-pair only
+ * Note 1: This CA renewal method is only applicable to CAs with internal parent CAs
+ * Note 2: Currently implements CA renewal with same key-pair only
*/
const renewCaCert = async ({ caId, notAfter, actorId, actorAuthMethod, actor, actorOrgId }: TRenewCaCertDTO) => {
const ca = await certificateAuthorityDAL.findById(caId);
@@ -888,9 +888,9 @@ export const certificateAuthorityServiceFactory = ({
};
/**
- * Import certificate for (un-installed) CA with id [caId].
+ * Import certificate for CA with id [caId].
* Note: Can be used to import an external certificate and certificate chain
- * to be installed into the CA.
+ * to be into an installed or uninstalled CA.
*/
const importCertToCa = async ({
caId,
@@ -917,7 +917,18 @@ export const certificateAuthorityServiceFactory = ({
ProjectPermissionSub.CertificateAuthorities
);
- if (ca.activeCaCertId) throw new BadRequestError({ message: "CA has already imported a certificate" });
+ if (ca.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
+ * internal CA.
+ */
+ throw new BadRequestError({
+ message: "Cannot import certificate to intermediate CA chained to internal parent CA"
+ });
+ }
+
+ const caCert = ca.activeCaCertId ? await certificateAuthorityCertDAL.findById(ca.activeCaCertId) : undefined;
const certObj = new x509.X509Certificate(certificate);
const maxPathLength = certObj.getExtension(x509.BasicConstraintsExtension)?.pathLength;
@@ -988,7 +999,7 @@ export const certificateAuthorityServiceFactory = ({
caId: ca.id,
encryptedCertificate,
encryptedCertificateChain,
- version: 1,
+ version: caCert ? caCert.version + 1 : 1,
caSecretId: caSecret.id
},
tx
diff --git a/docs/documentation/platform/pki/private-ca.mdx b/docs/documentation/platform/pki/private-ca.mdx
index 3a7191a1d..aff6fae05 100644
--- a/docs/documentation/platform/pki/private-ca.mdx
+++ b/docs/documentation/platform/pki/private-ca.mdx
@@ -24,8 +24,8 @@ graph TD
A typical workflow for setting up a Private CA hierarchy consists of the following steps:
-1. Configuring a root CA with details like name, validity period, and path length.
-2. Configuring and chaining intermediate CA(s) with details like name, validity period, path length, and imported certificate.
+1. Configuring an Infisical root CA with details like name, validity period, and path length — This step is optional if you wish to use an external root CA.
+2. Configuring and chaining intermediate CA(s) with details like name, validity period, path length, and imported certificate to your Root CA.
3. Managing the CA lifecycle events such as CA succession.
@@ -39,19 +39,21 @@ A typical workflow for setting up a Private CA hierarchy consists of the followi
## Guide to Creating a CA Hierarchy
In the following steps, we explore how to create a simple Private CA hierarchy
-consisting of a root CA and an intermediate CA.
+consisting of an (optional) root CA and an intermediate CA.
+ If you wish to use an external root CA, you can skip this step and head to step 2 to create an intermediate CA.
+
To create a root CA, head to your Project > Internal PKI > Certificate Authorities and press **Create CA**.
- 
+ 
Here, set the **CA Type** to **Root** and fill out details for the root CA.
- 
+ 
Here's some guidance on each field:
@@ -71,17 +73,19 @@ consisting of a root CA and an intermediate CA.
- 1.1. To create an intermediate CA, press **Create CA** again but this time specifying the **CA Type** to be **Intermediate**. Fill out the details for the intermediate CA.
+ 2.1. To create an intermediate CA, press **Create CA** again but this time specifying the **CA Type** to be **Intermediate**. Fill out the details for the intermediate CA.
- 
+ 
- 1.2. Next, press the **Install Certificate** option on the intermediate CA from step 1.1.
+ 2.2. Next, press the **Install Certificate** option on the intermediate CA from step 1.1.
- 
+ 
- Here, set the **Parent CA** to the root CA created in step 1 and configure the intended **Valid Until** and **Path Length** fields on the intermediate CA; feel free to use the prefilled values.
+ 2.3a. If you created a root CA in step 1, select **Infisical CA** for the **Parent CA Type** field.
- 
+ Next, set the **Parent CA** to the root CA created in step 1 and configure the intended **Valid Until** and **Path Length** fields on the intermediate CA; feel free to use the prefilled values.
+
+ 
Here's some guidance on each field:
@@ -91,17 +95,30 @@ consisting of a root CA and an intermediate CA.
Finally, press **Install** to chain the intermediate CA to the root CA; this creates a Certificate Signing Request (CSR) for the intermediate CA, creates an intermediate certificate using the root CA private key and CSR, and imports the signed certificate back to the intermediate CA.
- 
+ 
Great! You've successfully created a Private CA hierarchy with a root CA and an intermediate CA.
Now check out the [Certificates](/documentation/platform/pki/certificates) page to learn more about how to issue X.509 certificates using the intermediate CA.
+ 2.3b. If you have an external root CA, select **External CA** for the **Parent CA Type** field.
+
+ Next, use the provided intermediate CSR to generate a certificate from your external root CA and paste the PEM-encoded certificate back into the **Certificate Body** field; the PEM-encoded external root CA certificate should be pasted under the **Certificate Chain** field.
+
+ 
+
+ Finally, press **Install** to import the certificate and certificate chain as part of the installation step for the intermediate CA
+
+ Great! You've successfully created a Private CA hierarchy with an intermediate CA chained to an external root CA.
+ Now check out the [Certificates](/documentation/platform/pki/certificates) page to learn more about how to issue X.509 certificates using the intermediate CA.
+
+ If you wish to use an external root CA, you can skip this step and head to step 2 to create an intermediate CA.
+
To create a root CA, make an API request to the [Create CA](/api-reference/endpoints/certificate-authorities/create) API endpoint, specifying the `type` as `root`.
### Sample request
@@ -181,6 +198,8 @@ consisting of a root CA and an intermediate CA.
}
```
+ If using an external root CA, then use the CSR to generate a certificate for the intermediate CA using your external root CA and skip to step 2.4.
+
2.3. Next, create an intermediate certificate by making an API request to the [Sign Intermediate](/api-reference/endpoints/certificate-authorities/sign-intermediate) API endpoint
containing the CSR from step 2.2, referencing the root CA created in step 1.
@@ -212,6 +231,8 @@ consisting of a root CA and an intermediate CA.
2.4. Finally, import the intermediate certificate and certificate chain from step 2.3 back to the intermediate CA by making an API request to the [Import Certificate](/api-reference/endpoints/certificate-authorities/import-cert) API endpoint.
+ If using an external root CA, then import the generated certificate and root CA certificate under certificate chain back into the intermediate CA.
+
### Sample request
```bash Request
@@ -242,7 +263,17 @@ consisting of a root CA and an intermediate CA.
## Guide to CA Renewal
-In the following steps, we explore how to renew a CA certificate via same key pair.
+In the following steps, we explore how to renew a CA certificate.
+
+
+ If renewing an intermediate CA chained to an Infisical CA, then Infisical will
+ automate the process of generating a new certificate for the intermediate CA for you.
+
+If renewing an intermediate CA chained to an external parent CA, you'll be
+required to generate a new certificate from the external parent CA and manually import
+the certificate back to the intermediate CA.
+
+
@@ -296,4 +327,10 @@ In the following steps, we explore how to renew a CA certificate via same key pa
At the moment, Infisical only supports CA renewal via same key pair. We
anticipate supporting CA renewal via new key pair in the coming month.
+
+ Yes. You may obtain a CSR from the Intermediate CA and use it to generate a
+ certificate from your external Root CA. The certificate, along with the Root
+ CA certificate, can be imported back to the Intermediate CA as part of the
+ CA installation step.
+
diff --git a/docs/images/platform/pki/ca-create-intermediate.png b/docs/images/platform/pki/ca-create-intermediate.png
deleted file mode 100644
index e52e5735c..000000000
Binary files a/docs/images/platform/pki/ca-create-intermediate.png and /dev/null differ
diff --git a/docs/images/platform/pki/ca-create-root.png b/docs/images/platform/pki/ca-create-root.png
deleted file mode 100644
index 3c954b833..000000000
Binary files a/docs/images/platform/pki/ca-create-root.png and /dev/null differ
diff --git a/docs/images/platform/pki/ca-create.png b/docs/images/platform/pki/ca-create.png
deleted file mode 100644
index 35096c721..000000000
Binary files a/docs/images/platform/pki/ca-create.png and /dev/null differ
diff --git a/docs/images/platform/pki/ca-install-intermediate-opt.png b/docs/images/platform/pki/ca-install-intermediate-opt.png
deleted file mode 100644
index 2bdcbf306..000000000
Binary files a/docs/images/platform/pki/ca-install-intermediate-opt.png and /dev/null differ
diff --git a/docs/images/platform/pki/ca-install-intermediate.png b/docs/images/platform/pki/ca-install-intermediate.png
deleted file mode 100644
index ca30ad6ff..000000000
Binary files a/docs/images/platform/pki/ca-install-intermediate.png and /dev/null differ
diff --git a/docs/images/platform/pki/ca/ca-create-intermediate.png b/docs/images/platform/pki/ca/ca-create-intermediate.png
new file mode 100644
index 000000000..ac83db3e9
Binary files /dev/null and b/docs/images/platform/pki/ca/ca-create-intermediate.png differ
diff --git a/docs/images/platform/pki/ca/ca-create-root.png b/docs/images/platform/pki/ca/ca-create-root.png
new file mode 100644
index 000000000..a8bf936a3
Binary files /dev/null and b/docs/images/platform/pki/ca/ca-create-root.png differ
diff --git a/docs/images/platform/pki/ca/ca-create.png b/docs/images/platform/pki/ca/ca-create.png
new file mode 100644
index 000000000..915ed684c
Binary files /dev/null and b/docs/images/platform/pki/ca/ca-create.png differ
diff --git a/docs/images/platform/pki/ca/ca-install-intermediate-csr.png b/docs/images/platform/pki/ca/ca-install-intermediate-csr.png
new file mode 100644
index 000000000..77c7df0b9
Binary files /dev/null and b/docs/images/platform/pki/ca/ca-install-intermediate-csr.png differ
diff --git a/docs/images/platform/pki/ca/ca-install-intermediate-opt.png b/docs/images/platform/pki/ca/ca-install-intermediate-opt.png
new file mode 100644
index 000000000..16afd2f0b
Binary files /dev/null and b/docs/images/platform/pki/ca/ca-install-intermediate-opt.png differ
diff --git a/docs/images/platform/pki/ca/ca-install-intermediate.png b/docs/images/platform/pki/ca/ca-install-intermediate.png
new file mode 100644
index 000000000..10c9424ff
Binary files /dev/null and b/docs/images/platform/pki/ca/ca-install-intermediate.png differ
diff --git a/docs/images/platform/pki/ca/cas.png b/docs/images/platform/pki/ca/cas.png
new file mode 100644
index 000000000..d3189fd1a
Binary files /dev/null and b/docs/images/platform/pki/ca/cas.png differ
diff --git a/docs/images/platform/pki/cas.png b/docs/images/platform/pki/cas.png
deleted file mode 100644
index b532768e2..000000000
Binary files a/docs/images/platform/pki/cas.png and /dev/null differ
diff --git a/frontend/src/components/v2/TextArea/TextArea.tsx b/frontend/src/components/v2/TextArea/TextArea.tsx
index 3f75f5a43..a1e71edd2 100644
--- a/frontend/src/components/v2/TextArea/TextArea.tsx
+++ b/frontend/src/components/v2/TextArea/TextArea.tsx
@@ -11,7 +11,7 @@ type Props = {
};
const textAreaVariants = cva(
- "textarea w-full p-2 focus:ring-2 ring-primary-800 outline-none border border-solid text-gray-400 font-inter placeholder-gray-500 placeholder-opacity-50",
+ "textarea w-full p-2 focus:ring-2 ring-primary-800 outline-none border text-gray-400 font-inter placeholder-gray-500 placeholder-opacity-50",
{
variants: {
size: {
@@ -25,13 +25,13 @@ const textAreaVariants = cva(
false: ""
},
variant: {
- filled: ["bg-bunker-800", "text-gray-400"],
+ filled: ["bg-mineshaft-900", "text-gray-400"],
outline: ["bg-transparent"],
plain: "bg-transparent outline-none"
},
isError: {
true: "focus:ring-red/50 placeholder-red-300 border-red",
- false: "focus:ring-primary/50 border-mineshaft-400"
+ false: "focus:ring-primary-400/50 focus:ring-1 border-mineshaft-500"
}
},
compoundVariants: [
diff --git a/frontend/src/views/Project/CaPage/CaPage.tsx b/frontend/src/views/Project/CaPage/CaPage.tsx
index 7edc99af9..e0bdaeb64 100644
--- a/frontend/src/views/Project/CaPage/CaPage.tsx
+++ b/frontend/src/views/Project/CaPage/CaPage.tsx
@@ -22,7 +22,6 @@ import { usePopUp } from "@app/hooks/usePopUp";
import { CaModal } from "@app/views/Project/CertificatesPage/components/CaTab/components/CaModal";
import { CaInstallCertModal } from "../CertificatesPage/components/CaTab/components/CaInstallCertModal";
-import { TabSections } from "../Types";
import { CaCertificatesSection, CaDetailsSection, CaRenewalModal } from "./components";
export const CaPage = withProjectPermission(
diff --git a/frontend/src/views/Project/CaPage/components/CaDetailsSection.tsx b/frontend/src/views/Project/CaPage/components/CaDetailsSection.tsx
index eb8ccf86f..94eae3e6b 100644
--- a/frontend/src/views/Project/CaPage/components/CaDetailsSection.tsx
+++ b/frontend/src/views/Project/CaPage/components/CaDetailsSection.tsx
@@ -6,7 +6,7 @@ import { ProjectPermissionCan } from "@app/components/permissions";
import { Button, IconButton, Tooltip } from "@app/components/v2";
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/context";
import { useTimedReset } from "@app/hooks";
-import { CaStatus, useGetCaById } from "@app/hooks/api";
+import { CaStatus, CaType, useGetCaById } from "@app/hooks/api";
import { caStatusToNameMap, caTypeToNameMap } from "@app/hooks/api/ca/constants";
import { certKeyAlgorithmToNameMap } from "@app/hooks/api/certificates/constants";
import { UsePopUpState } from "@app/hooks/usePopUp";
@@ -35,6 +35,10 @@ export const CaDetailsSection = ({ caId, handlePopUpOpen }: Props) => {