mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-14 07:30:20 +00:00
Merge pull request #4286 from Infisical/ENG-3376
feat(app-connections, PKI): Cloudflare as DNS provider
This commit is contained in:
@@ -3,14 +3,16 @@ import { useQuery, UseQueryOptions } from "@tanstack/react-query";
|
||||
import { apiRequest } from "@app/config/request";
|
||||
|
||||
import { appConnectionKeys } from "../queries";
|
||||
import { TCloudflarePagesProject, TCloudflareWorkersScript } from "./types";
|
||||
import { TCloudflarePagesProject, TCloudflareWorkersScript, TCloudflareZone } from "./types";
|
||||
|
||||
const cloudflareConnectionKeys = {
|
||||
all: [...appConnectionKeys.all, "cloudflare"] as const,
|
||||
listPagesProjects: (connectionId: string) =>
|
||||
[...cloudflareConnectionKeys.all, "pages-projects", connectionId] as const,
|
||||
listWorkersScripts: (connectionId: string) =>
|
||||
[...cloudflareConnectionKeys.all, "workers-scripts", connectionId] as const
|
||||
[...cloudflareConnectionKeys.all, "workers-scripts", connectionId] as const,
|
||||
listZones: (connectionId: string) =>
|
||||
[...cloudflareConnectionKeys.all, "zones", connectionId] as const
|
||||
};
|
||||
|
||||
export const useCloudflareConnectionListPagesProjects = (
|
||||
@@ -62,3 +64,28 @@ export const useCloudflareConnectionListWorkersScripts = (
|
||||
...options
|
||||
});
|
||||
};
|
||||
|
||||
export const useCloudflareConnectionListZones = (
|
||||
connectionId: string,
|
||||
options?: Omit<
|
||||
UseQueryOptions<
|
||||
TCloudflareZone[],
|
||||
unknown,
|
||||
TCloudflareZone[],
|
||||
ReturnType<typeof cloudflareConnectionKeys.listZones>
|
||||
>,
|
||||
"queryKey" | "queryFn"
|
||||
>
|
||||
) => {
|
||||
return useQuery({
|
||||
queryKey: cloudflareConnectionKeys.listZones(connectionId),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<TCloudflareZone[]>(
|
||||
`/api/v1/app-connections/cloudflare/${connectionId}/cloudflare-zones`
|
||||
);
|
||||
|
||||
return data;
|
||||
},
|
||||
...options
|
||||
});
|
||||
};
|
||||
|
||||
@@ -6,3 +6,8 @@ export type TCloudflarePagesProject = {
|
||||
export type TCloudflareWorkersScript = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
export type TCloudflareZone = {
|
||||
id: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { AppConnection } from "../appConnections/enums";
|
||||
import { SshCaStatus } from "../sshCa";
|
||||
import { SshCertTemplateStatus } from "../sshCertificateTemplates";
|
||||
import { CaStatus, InternalCaType } from "./enums";
|
||||
import { AcmeDnsProvider, CaStatus, InternalCaType } from "./enums";
|
||||
|
||||
export const caTypeToNameMap: { [K in InternalCaType]: string } = {
|
||||
[InternalCaType.ROOT]: "Root",
|
||||
@@ -13,6 +14,16 @@ export const caStatusToNameMap: { [K in CaStatus]: string } = {
|
||||
[CaStatus.PENDING_CERTIFICATE]: "Pending Certificate"
|
||||
};
|
||||
|
||||
export const ACME_DNS_PROVIDER_NAME_MAP: Record<AcmeDnsProvider, string> = {
|
||||
[AcmeDnsProvider.ROUTE53]: "Route53",
|
||||
[AcmeDnsProvider.Cloudflare]: "Cloudflare"
|
||||
};
|
||||
|
||||
export const ACME_DNS_PROVIDER_APP_CONNECTION_MAP: Record<AcmeDnsProvider, AppConnection> = {
|
||||
[AcmeDnsProvider.ROUTE53]: AppConnection.AWS,
|
||||
[AcmeDnsProvider.Cloudflare]: AppConnection.Cloudflare
|
||||
};
|
||||
|
||||
export const getCaStatusBadgeVariant = (status: CaStatus | SshCaStatus | SshCertTemplateStatus) => {
|
||||
switch (status) {
|
||||
case CaStatus.ACTIVE:
|
||||
|
||||
@@ -19,5 +19,6 @@ export enum CaRenewalType {
|
||||
}
|
||||
|
||||
export enum AcmeDnsProvider {
|
||||
ROUTE53 = "route53"
|
||||
ROUTE53 = "route53",
|
||||
Cloudflare = "cloudflare"
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ export type TAcmeCertificateAuthority = {
|
||||
configuration: {
|
||||
dnsAppConnectionId: string;
|
||||
dnsProviderConfig: {
|
||||
provider: AcmeDnsProvider.ROUTE53;
|
||||
provider: AcmeDnsProvider;
|
||||
hostedZoneId: string;
|
||||
};
|
||||
directoryUrl: string;
|
||||
|
||||
+87
-49
@@ -1,5 +1,6 @@
|
||||
import { useEffect } from "react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { SingleValue } from "react-select";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { z } from "zod";
|
||||
|
||||
@@ -16,7 +17,15 @@ import {
|
||||
Switch
|
||||
} from "@app/components/v2";
|
||||
import { useWorkspace } from "@app/context";
|
||||
import { useListAvailableAppConnections } from "@app/hooks/api/appConnections";
|
||||
import { APP_CONNECTION_MAP } from "@app/helpers/appConnections";
|
||||
import {
|
||||
TAvailableAppConnection,
|
||||
useListAvailableAppConnections
|
||||
} from "@app/hooks/api/appConnections";
|
||||
import {
|
||||
TCloudflareZone,
|
||||
useCloudflareConnectionListZones
|
||||
} from "@app/hooks/api/appConnections/cloudflare";
|
||||
import { AppConnection } from "@app/hooks/api/appConnections/enums";
|
||||
import {
|
||||
AcmeDnsProvider,
|
||||
@@ -26,6 +35,10 @@ import {
|
||||
useGetCa,
|
||||
useUpdateCa
|
||||
} from "@app/hooks/api/ca";
|
||||
import {
|
||||
ACME_DNS_PROVIDER_APP_CONNECTION_MAP,
|
||||
ACME_DNS_PROVIDER_NAME_MAP
|
||||
} from "@app/hooks/api/ca/constants";
|
||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||
import { slugSchema } from "@app/lib/schemas";
|
||||
|
||||
@@ -42,7 +55,7 @@ const schema = z
|
||||
id: z.string(),
|
||||
name: z.string()
|
||||
}),
|
||||
// currently specific to Route53 but can be extended to others by differentiating via the provider property
|
||||
// currently specific to Route53 & Cloudflare but can be extended to others by differentiating via the provider property
|
||||
dnsProviderConfig: z.object({
|
||||
provider: z.nativeEnum(AcmeDnsProvider),
|
||||
hostedZoneId: z.string()
|
||||
@@ -105,12 +118,29 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
const caType = watch("type");
|
||||
const dnsProvider = watch("configuration.dnsProviderConfig.provider");
|
||||
|
||||
const { data: availableConnections, isPending } = useListAvailableAppConnections(
|
||||
AppConnection.AWS,
|
||||
{
|
||||
enabled: dnsProvider === AcmeDnsProvider.ROUTE53
|
||||
}
|
||||
);
|
||||
const { data: availableRoute53Connections, isPending: isRoute53Pending } =
|
||||
useListAvailableAppConnections(AppConnection.AWS, {
|
||||
enabled: caType === CaType.ACME
|
||||
});
|
||||
|
||||
const { data: availableCloudflareConnections, isPending: isCloudflarePending } =
|
||||
useListAvailableAppConnections(AppConnection.Cloudflare, {
|
||||
enabled: caType === CaType.ACME
|
||||
});
|
||||
|
||||
const availableConnections: TAvailableAppConnection[] = [
|
||||
...(availableRoute53Connections || []),
|
||||
...(availableCloudflareConnections || [])
|
||||
];
|
||||
|
||||
const isPending = isRoute53Pending || isCloudflarePending;
|
||||
|
||||
const dnsAppConnection = watch("configuration.dnsAppConnection");
|
||||
|
||||
const { data: cloudflareZones = [], isPending: isZonesPending } =
|
||||
useCloudflareConnectionListZones(dnsAppConnection.id, {
|
||||
enabled: dnsProvider === AcmeDnsProvider.Cloudflare && !!dnsAppConnection.id
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (ca) {
|
||||
@@ -138,25 +168,6 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
reset({
|
||||
type: CaType.ACME,
|
||||
name: "",
|
||||
status: CaStatus.ACTIVE,
|
||||
enableDirectIssuance: true,
|
||||
configuration: {
|
||||
dnsAppConnection: {
|
||||
id: "",
|
||||
name: ""
|
||||
},
|
||||
dnsProviderConfig: {
|
||||
provider: AcmeDnsProvider.ROUTE53,
|
||||
hostedZoneId: ""
|
||||
},
|
||||
directoryUrl: "",
|
||||
accountEmail: ""
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [ca, availableConnections]);
|
||||
|
||||
@@ -284,12 +295,11 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
className="w-full"
|
||||
isDisabled={Boolean(ca)}
|
||||
>
|
||||
<SelectItem
|
||||
value={String(AcmeDnsProvider.ROUTE53)}
|
||||
key={AcmeDnsProvider.ROUTE53}
|
||||
>
|
||||
Route53
|
||||
</SelectItem>
|
||||
{Object.values(AcmeDnsProvider).map((provider) => (
|
||||
<SelectItem value={String(provider)} key={provider}>
|
||||
{ACME_DNS_PROVIDER_NAME_MAP[provider]}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
)}
|
||||
@@ -297,7 +307,7 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
<Controller
|
||||
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
tooltipText={`${dnsProvider === AcmeDnsProvider.ROUTE53 ? "Route53" : ""} requires an AWS App Connection. This can be created from the Organization Settings page.`}
|
||||
tooltipText={`${ACME_DNS_PROVIDER_NAME_MAP[dnsProvider]} uses the ${APP_CONNECTION_MAP[ACME_DNS_PROVIDER_APP_CONNECTION_MAP[dnsProvider]].name} App Connection. You can create one in the Organization Settings page.`}
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
label="DNS App Connection"
|
||||
@@ -318,21 +328,49 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
control={control}
|
||||
name="configuration.dnsAppConnection"
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
defaultValue=""
|
||||
name="configuration.dnsProviderConfig.hostedZoneId"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Hosted Zone ID"
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
isRequired
|
||||
>
|
||||
<Input {...field} placeholder="Z040441124N1GOOMCQYX1" />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
{dnsProvider === AcmeDnsProvider.ROUTE53 && (
|
||||
<Controller
|
||||
control={control}
|
||||
defaultValue=""
|
||||
name="configuration.dnsProviderConfig.hostedZoneId"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Hosted Zone ID"
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
isRequired
|
||||
>
|
||||
<Input {...field} placeholder="Z040441124N1GOOMCQYX1" />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{dnsProvider === AcmeDnsProvider.Cloudflare && (
|
||||
<Controller
|
||||
name="configuration.dnsProviderConfig.hostedZoneId"
|
||||
control={control}
|
||||
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error?.message)}
|
||||
label="Zone"
|
||||
>
|
||||
<FilterableSelect
|
||||
isLoading={isZonesPending && !!dnsAppConnection.id}
|
||||
isDisabled={!dnsAppConnection.id}
|
||||
value={cloudflareZones.find((zone) => zone.id === value)}
|
||||
onChange={(option) => {
|
||||
onChange((option as SingleValue<TCloudflareZone>)?.id ?? null);
|
||||
}}
|
||||
options={cloudflareZones}
|
||||
placeholder="Select a zone..."
|
||||
getOptionLabel={(option) => option.name}
|
||||
getOptionValue={(option) => option.id}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
<Controller
|
||||
control={control}
|
||||
defaultValue=""
|
||||
|
||||
+5
-1
@@ -82,7 +82,11 @@ export const SecretDetectionIgnoreValuesSection = () => {
|
||||
<div className="flex w-full items-center justify-between">
|
||||
<p className="text-xl font-semibold">Secret Detection</p>
|
||||
</div>
|
||||
<p className="mb-4 mt-2 max-w-2xl text-sm text-gray-400">Define secret values to ignore when scanning designated parameter folders. Add values here to prevent false positives or allow approved sensitive data. These ignored values will not trigger policy violation alerts.</p>
|
||||
<p className="mb-4 mt-2 max-w-2xl text-sm text-gray-400">
|
||||
Define secret values to ignore when scanning designated parameter folders. Add values here
|
||||
to prevent false positives or allow approved sensitive data. These ignored values will not
|
||||
trigger policy violation alerts.
|
||||
</p>
|
||||
|
||||
<form onSubmit={handleSubmit(handleIgnoreValuesSubmit)} autoComplete="off">
|
||||
<div className="mb-4">
|
||||
|
||||
Reference in New Issue
Block a user