Merge pull request #4436 from Infisical/ENG-3536

feat(PKI): External CA EAB Support + DigiCert Docs
This commit is contained in:
x032205
2025-08-29 18:03:57 -04:00
committed by GitHub
7 changed files with 145 additions and 29 deletions
+2
View File
@@ -16,6 +16,8 @@ export type TAcmeCertificateAuthority = {
};
directoryUrl: string;
accountEmail: string;
eabKid?: string;
eabHmacKey?: string;
};
};
@@ -42,6 +42,17 @@ import {
import { UsePopUpState } from "@app/hooks/usePopUp";
import { slugSchema } from "@app/lib/schemas";
const REQUIRED_EAB_DIRECTORIES = [
"https://acme.digicert.com/v2/acme/directory",
"https://acme.zerossl.com/v2/DV90",
"https://acme.ssl.com/sslcom-dv-rsa",
"https://acme.ssl.com/sslcom-dv-ecc",
"https://dv.acme-v02.api.pki.goog/directory",
"https://acme.sectigo.com/v2/OV",
"https://acme.sectigo.com/v2/EV",
"https://acme.cisco.com/ACMEv2/directory"
];
const baseSchema = z.object({
type: z.nativeEnum(CaType),
name: slugSchema({
@@ -51,18 +62,39 @@ const baseSchema = z.object({
status: z.nativeEnum(CaStatus)
});
const acmeConfigurationSchema = z.object({
dnsAppConnection: z.object({
id: z.string(),
name: z.string()
}),
dnsProviderConfig: z.object({
provider: z.nativeEnum(AcmeDnsProvider),
hostedZoneId: z.string()
}),
directoryUrl: z.string(),
accountEmail: z.string()
});
const acmeConfigurationSchema = z
.object({
dnsAppConnection: z.object({
id: z.string(),
name: z.string()
}),
dnsProviderConfig: z.object({
provider: z.nativeEnum(AcmeDnsProvider),
hostedZoneId: z.string()
}),
directoryUrl: z.string(),
accountEmail: z.string(),
eabKid: z.string().optional(),
eabHmacKey: z.string().optional()
})
.superRefine((data, ctx) => {
if (REQUIRED_EAB_DIRECTORIES.includes(data.directoryUrl)) {
if (!data.eabKid || data.eabKid.trim() === "") {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "EAB Key Identifier (KID) is required for this directory URL",
path: ["eabKid"]
});
}
if (!data.eabHmacKey || data.eabHmacKey.trim() === "") {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "EAB HMAC Key is required for this directory URL",
path: ["eabHmacKey"]
});
}
}
});
const azureAdCsConfigurationSchema = z.object({
azureAdcsConnection: z.object({
@@ -122,6 +154,10 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => {
caType === CaType.ACME && configuration && "dnsProviderConfig" in configuration
? configuration.dnsProviderConfig.provider
: undefined;
const directoryUrl =
caType === CaType.ACME && configuration && "directoryUrl" in configuration
? configuration.directoryUrl
: undefined;
useEffect(() => {
const initialType = (popUp?.ca?.data as { type: CaType })?.type;
@@ -155,7 +191,9 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => {
hostedZoneId: ""
},
directoryUrl: "",
accountEmail: ""
accountEmail: "",
eabKid: "",
eabHmacKey: ""
}
});
}
@@ -178,13 +216,10 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => {
});
const availableConnections: TAvailableAppConnection[] = useMemo(() => {
if (caType === CaType.ACME) {
return [...(availableRoute53Connections || []), ...(availableCloudflareConnections || [])];
}
if (caType === CaType.AZURE_AD_CS) {
return availableAzureConnections || [];
}
return [];
return [...(availableRoute53Connections || []), ...(availableCloudflareConnections || [])];
}, [
caType,
availableRoute53Connections,
@@ -192,7 +227,8 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => {
availableAzureConnections
]);
const isPending = isRoute53Pending || isCloudflarePending || isAzurePending;
const isPending =
isRoute53Pending || isCloudflarePending || (isAzurePending && caType === CaType.AZURE_AD_CS);
const dnsAppConnection =
caType === CaType.ACME && configuration && "dnsAppConnection" in configuration
@@ -227,7 +263,9 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => {
hostedZoneId: ca.configuration.dnsProviderConfig.hostedZoneId
},
directoryUrl: ca.configuration.directoryUrl,
accountEmail: ca.configuration.accountEmail
accountEmail: ca.configuration.accountEmail,
eabKid: ca.configuration.eabKid,
eabHmacKey: ca.configuration.eabHmacKey
}
});
} else if (ca.type === CaType.AZURE_AD_CS && availableConnections?.length) {
@@ -268,7 +306,9 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => {
dnsProviderConfig: formConfiguration.dnsProviderConfig,
directoryUrl: formConfiguration.directoryUrl,
accountEmail: formConfiguration.accountEmail,
dnsAppConnectionId: formConfiguration.dnsAppConnection.id
dnsAppConnectionId: formConfiguration.dnsAppConnection.id,
eabKid: formConfiguration.eabKid,
eabHmacKey: formConfiguration.eabHmacKey
};
} else if (type === CaType.AZURE_AD_CS && "azureAdcsConnection" in formConfiguration) {
configPayload = {
@@ -499,6 +539,44 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => {
</FormControl>
)}
/>
<Controller
control={control}
defaultValue=""
name="configuration.eabKid"
render={({ field, fieldState: { error } }) => (
<FormControl
label="EAB Key Identifier (KID)"
isError={Boolean(error)}
errorText={error?.message}
isOptional={!REQUIRED_EAB_DIRECTORIES.includes(directoryUrl || "")}
isRequired={REQUIRED_EAB_DIRECTORIES.includes(directoryUrl || "")}
>
<Input
{...field}
placeholder="abc123def456ghi789jkl012mno345pqr678stu901vwx234yz"
/>
</FormControl>
)}
/>
<Controller
control={control}
defaultValue=""
name="configuration.eabHmacKey"
render={({ field, fieldState: { error } }) => (
<FormControl
label="EAB HMAC Key"
isError={Boolean(error)}
errorText={error?.message}
isOptional={!REQUIRED_EAB_DIRECTORIES.includes(directoryUrl || "")}
isRequired={REQUIRED_EAB_DIRECTORIES.includes(directoryUrl || "")}
>
<Input
{...field}
placeholder="dGhpc2lzYW5leGFtcGxlaG1hY2tleWZvcmRpZ2ljZXJ0YWNtZXRlc3RpbmcxMjM0NTY3ODkw"
/>
</FormControl>
)}
/>
</>
)}
{caType === CaType.AZURE_AD_CS && (