feat(azure-app-integration): label & reference support

This commit is contained in:
Daniel Hougaard
2024-12-10 03:30:19 +04:00
parent 64a982d5e0
commit 0366506213
5 changed files with 109 additions and 32 deletions

View File

@@ -1126,6 +1126,8 @@ export const INTEGRATION = {
shouldAutoRedeploy: "Used by Render to trigger auto deploy.",
secretGCPLabel: "The label for GCP secrets.",
secretAWSTag: "The tags for AWS secrets.",
azureUseLabels:
"If enabled, each secret will be given a label that represents which Infisical environment they belong to.",
githubVisibility:
"Define where the secrets from the Github Integration should be visible. Option 'selected' lets you directly define which repositories to sync secrets to.",
githubVisibilityRepoIds:

View File

@@ -299,6 +299,11 @@ const syncSecretsAzureAppConfig = async ({
value: string;
}
// Format: {\"uri\":\"https://SOME-KEY-VAULT.vault.azure.net/secrets/SOME-SECRET-KEY\"}
// Also works without the backslash escapes
const azureSecretReferenceUriRegex =
/^\{(\\"|")uri(\\"|"):(\\"|")https:\/\/[a-zA-Z0-9-]+\.vault\.azure\.net\/secrets\/[a-zA-Z0-9-]+\\?\2\}$/;
const getCompleteAzureAppConfigValues = async (url: string) => {
let result: AzureAppConfigKeyValue[] = [];
while (url) {
@@ -405,14 +410,24 @@ const syncSecretsAzureAppConfig = async ({
}
// create or update secrets on Azure App Config
for await (const key of Object.keys(secrets)) {
if (!(key in azureAppConfigSecrets) || secrets[key]?.value !== azureAppConfigSecrets[key]) {
await request.put(
`${integration.app}/kv/${key}?api-version=2023-11-01`,
{
value: secrets[key]?.value
value: secrets[key]?.value,
...(azureSecretReferenceUriRegex.test(secrets[key]?.value || "") && {
content_type: "application/vnd.microsoft.appconfig.keyvaultref+json;charset=utf-8"
})
},
{
...(metadata.azureUseLabels && {
params: {
label: integration.environment.slug
}
}),
headers: {
Authorization: `Bearer ${accessToken}`
},
@@ -432,6 +447,11 @@ const syncSecretsAzureAppConfig = async ({
headers: {
Authorization: `Bearer ${accessToken}`
},
...(metadata.azureUseLabels && {
params: {
label: integration.environment.slug
}
}),
// we force IPV4 because docker setup fails with ipv6
httpsAgent: new https.Agent({
family: 4

View File

@@ -35,6 +35,8 @@ export const IntegrationMetadataSchema = z.object({
.optional()
.describe(INTEGRATION.CREATE.metadata.secretAWSTag),
azureUseLabels: z.boolean().optional().describe(INTEGRATION.CREATE.metadata.azureUseLabels),
githubVisibility: z
.union([z.literal("selected"), z.literal("private"), z.literal("all")])
.optional()

View File

@@ -80,6 +80,7 @@ export const useCreateIntegration = () => {
key: string;
value: string;
}[];
azureUseLabels?: boolean;
githubVisibility?: string;
githubVisibilityRepoIds?: string[];
kmsKeyId?: string;

View File

@@ -4,7 +4,11 @@ import Head from "next/head";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-svg-icons";
import {
faArrowUpRightFromSquare,
faBookOpen,
faQuestionCircle
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { zodResolver } from "@hookform/resolvers/zod";
import queryString from "query-string";
@@ -21,7 +25,9 @@ import {
FormControl,
Input,
Select,
SelectItem
SelectItem,
Switch,
Tooltip
} from "../../../components/v2";
import { useGetIntegrationAuthById } from "../../../hooks/api/integrationAuth";
import { useGetWorkspaceById } from "../../../hooks/api/workspace";
@@ -39,7 +45,8 @@ const schema = z.object({
secretPath: z.string().trim().min(1, { message: "Secret path is required" }),
sourceEnvironment: z.string().trim().min(1, { message: "Source environment is required" }),
initialSyncBehavior: z.nativeEnum(IntegrationSyncBehavior),
secretPrefix: z.string().default("")
secretPrefix: z.string().default(""),
useLabels: z.boolean().default(false)
});
type TFormSchema = z.infer<typeof schema>;
@@ -60,6 +67,7 @@ export default function AzureAppConfigurationCreateIntegration() {
const router = useRouter();
const {
control,
watch,
setValue,
handleSubmit,
formState: { isSubmitting }
@@ -85,8 +93,11 @@ export default function AzureAppConfigurationCreateIntegration() {
}
}, [workspace]);
const sourceEnv = watch("sourceEnvironment");
const handleIntegrationSubmit = async ({
secretPath,
useLabels,
sourceEnvironment,
baseUrl,
initialSyncBehavior,
@@ -103,7 +114,8 @@ export default function AzureAppConfigurationCreateIntegration() {
secretPath,
metadata: {
initialSyncBehavior,
secretPrefix
secretPrefix,
azureUseLabels: useLabels
}
});
@@ -155,35 +167,75 @@ export default function AzureAppConfigurationCreateIntegration() {
</div>
</CardTitle>
<div className="px-6">
<Controller
control={control}
name="sourceEnvironment"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Project Environment"
errorText={error?.message}
isError={Boolean(error)}
>
<Select
className="w-full border border-mineshaft-500"
dropdownContainerClassName="max-w-full"
value={field.value}
onValueChange={(val) => {
field.onChange(val);
}}
<div className="mb-2 -space-y-2">
<Controller
control={control}
name="sourceEnvironment"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Project Environment"
errorText={error?.message}
isError={Boolean(error)}
>
{workspace?.environments.map((sourceEnvironment) => (
<SelectItem
value={sourceEnvironment.slug}
key={`source-environment-${sourceEnvironment.slug}`}
<Select
className="w-full border border-mineshaft-500"
dropdownContainerClassName="max-w-full"
value={field.value}
onValueChange={(val) => {
field.onChange(val);
}}
>
{workspace?.environments.map((sourceEnvironment) => (
<SelectItem
value={sourceEnvironment.slug}
key={`source-environment-${sourceEnvironment.slug}`}
>
{sourceEnvironment.name}
</SelectItem>
))}
</Select>
</FormControl>
)}
/>
<Controller
control={control}
name="useLabels"
render={({ field: { onChange, value } }) => (
<Switch
id="use-environment-labels"
onCheckedChange={(isChecked) => onChange(isChecked)}
isChecked={value}
>
<div className="flex items-center gap-1">
Use Environment Labels
<Tooltip
content={
<div>
<p>
Use the environment slug as the label on the secret keys created in
Azure App Configuration.
<br />
<br />
{sourceEnv && (
<p>
You have selected the{" "}
<span className="font-semibold">{sourceEnv}</span> environment,
therefore the label will be set to{" "}
<span className="font-semibold">{sourceEnv}</span>.
</p>
)}
</p>
</div>
}
>
{sourceEnvironment.name}
</SelectItem>
))}
</Select>
</FormControl>
)}
/>
<FontAwesomeIcon icon={faQuestionCircle} size="1x" />
</Tooltip>
</div>
</Switch>
)}
/>
</div>
<Controller
control={control}
name="secretPath"