requested changes

This commit is contained in:
Daniel Hougaard
2025-02-07 23:41:07 +04:00
parent 1b5b937db5
commit 8d52011173
27 changed files with 173 additions and 35 deletions

View File

@@ -28,6 +28,7 @@ import { githubConnectionService } from "@app/services/app-connection/github/git
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
import { TAppConnectionDALFactory } from "./app-connection-dal";
import { ValidateAzureAppConfigurationConnectionCredentialsSchema } from "./azure-app-configuration";
import { ValidateAzureKeyVaultConnectionCredentialsSchema } from "./azure-key-vault";
import { ValidateGcpConnectionCredentialsSchema } from "./gcp";
import { gcpConnectionService } from "./gcp/gcp-connection-service";
@@ -45,7 +46,7 @@ const VALIDATE_APP_CONNECTION_CREDENTIALS_MAP: Record<AppConnection, TValidateAp
[AppConnection.GitHub]: ValidateGitHubConnectionCredentialsSchema,
[AppConnection.GCP]: ValidateGcpConnectionCredentialsSchema,
[AppConnection.AzureKeyVault]: ValidateAzureKeyVaultConnectionCredentialsSchema,
[AppConnection.AzureAppConfiguration]: ValidateAzureKeyVaultConnectionCredentialsSchema
[AppConnection.AzureAppConfiguration]: ValidateAzureAppConfigurationConnectionCredentialsSchema
};
export const appConnectionServiceFactory = ({

View File

@@ -63,7 +63,6 @@ export const SanitizedAzureAppConfigurationConnectionSchema = z.discriminatedUni
BaseAzureAppConfigurationConnectionSchema.extend({
method: z.literal(AzureAppConfigurationConnectionMethod.OAuth),
credentials: AzureAppConfigurationConnectionOAuthOutputCredentialsSchema.pick({
resource: true,
tenantId: true
})
})

View File

@@ -63,7 +63,6 @@ export const SanitizedAzureKeyVaultConnectionSchema = z.discriminatedUnion("meth
BaseAzureKeyVaultConnectionSchema.extend({
method: z.literal(AzureKeyVaultConnectionMethod.OAuth),
credentials: AzureKeyVaultConnectionOAuthOutputCredentialsSchema.pick({
resource: true,
tenantId: true
})
})

View File

@@ -19,6 +19,7 @@ type TAzureAppConfigurationSecretSyncFactoryDeps = {
interface AzureAppConfigKeyValue {
key: string;
value: string;
label?: string;
}
export const azureAppConfigurationSecretSyncFactory = ({
@@ -78,7 +79,9 @@ export const azureAppConfigurationSecretSyncFactory = ({
secretSync.destinationConfig.label ? `&label=${secretSync.destinationConfig.label}` : "&label=%00"
}`;
const azureAppConfigSecrets = Object.fromEntries(
const azureAppConfigValuesUrlAllSecrets = `/kv?api-version=2023-11-01`;
const azureAppConfigSecretsLabeled = Object.fromEntries(
(
await $getCompleteAzureAppConfigValues(
accessToken,
@@ -88,9 +91,25 @@ export const azureAppConfigurationSecretSyncFactory = ({
).map((entry) => [entry.key, entry.value])
);
const azureAppConfigSecrets = Object.fromEntries(
(
await $getCompleteAzureAppConfigValues(
accessToken,
secretSync.destinationConfig.configurationUrl,
azureAppConfigValuesUrlAllSecrets
)
).map((entry) => [
entry.key,
{
value: entry.value,
label: entry.label
}
])
);
// add the secrets to azure app config, that are in infisical
for await (const key of Object.keys(secretMap)) {
if (!(key in azureAppConfigSecrets) || secretMap[key]?.value !== azureAppConfigSecrets[key]) {
if (!(key in azureAppConfigSecretsLabeled) || secretMap[key]?.value !== azureAppConfigSecretsLabeled[key]) {
await request.put(
`${secretSync.destinationConfig.configurationUrl}/kv/${key}?api-version=2023-11-01`,
{
@@ -117,14 +136,14 @@ export const azureAppConfigurationSecretSyncFactory = ({
}
}
// delete the secrets that are in azure app config, but not in infisical
for await (const key of Object.keys(azureAppConfigSecrets)) {
if (!(key in secretMap) || secretMap[key] === null) {
const azureSecret = azureAppConfigSecrets[key];
if (!(key in secretMap) || secretMap[key] === null || azureSecret.label !== secretSync.destinationConfig.label) {
await $deleteAzureSecret(
accessToken,
secretSync.destinationConfig.configurationUrl,
key,
secretSync.destinationConfig.label
azureSecret.label // use the secret's actual label for deletion
);
}
}

View File

@@ -7,6 +7,7 @@ import { getAzureConnectionAccessToken } from "@app/services/app-connection/azur
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
import { TSecretMap } from "@app/services/secret-sync/secret-sync-types";
import { SecretSyncError } from "../secret-sync-errors";
import { GetAzureKeyVaultSecret, TAzureKeyVaultSyncWithCredentials } from "./azure-key-vault-sync-types";
type TAzureKeyVaultSecretSyncFactoryDeps = {
@@ -127,6 +128,7 @@ export const azureKeyVaultSecretSyncFactory = ({
const setSecretAzureKeyVault = async ({ key, value }: { key: string; value: string }) => {
let isSecretSet = false;
let syncError: Error | null = null;
let maxTries = 6;
if (disabledAzureKeyVaultSecretKeys.includes(key)) return;
@@ -147,6 +149,7 @@ export const azureKeyVaultSecretSyncFactory = ({
isSecretSet = true;
} catch (err) {
syncError = err as Error;
if (err instanceof AxiosError) {
// eslint-disable-next-line
if (err.response?.data?.error?.innererror?.code === "ObjectIsDeletedButRecoverable") {
@@ -174,7 +177,10 @@ export const azureKeyVaultSecretSyncFactory = ({
}
if (!isSecretSet) {
throw new Error(`Failed to set secret ${key}`);
throw new SecretSyncError({
error: syncError,
secretKey: key
});
}
};

View File

@@ -0,0 +1,4 @@
---
title: "Available"
openapi: "GET /api/v1/app-connections/azure-app-configuration/available"
---

View File

@@ -0,0 +1,10 @@
---
title: "Create"
openapi: "POST /api/v1/app-connections/azure-app-configuration"
---
<Note>
Azure App Configuration Connections must be created through the Infisical UI.
Check out the configuration docs for [Azure App Configuration Connections](/integrations/app-connections/azure-app-configuration) for a step-by-step
guide.
</Note>

View File

@@ -0,0 +1,4 @@
---
title: "Delete"
openapi: "DELETE /api/v1/app-connections/azure-app-configuration/{connectionId}"
---

View File

@@ -0,0 +1,4 @@
---
title: "Get by ID"
openapi: "GET /api/v1/app-connections/azure-app-configuration/{connectionId}"
---

View File

@@ -0,0 +1,4 @@
---
title: "Get by Name"
openapi: "GET /api/v1/app-connections/azure-app-configuration/connection-name/{connectionName}"
---

View File

@@ -0,0 +1,4 @@
---
title: "List"
openapi: "GET /api/v1/app-connections/azure-app-configuration"
---

View File

@@ -0,0 +1,10 @@
---
title: "Update"
openapi: "PATCH /api/v1/app-connections/azure-app-configuration/{connectionId}"
---
<Note>
Azure App Configuration Connections must be updated through the Infisical UI.
Check out the configuration docs for [Azure App Configuration Connections](/integrations/app-connections/azure-app-configuration) for a step-by-step
guide.
</Note>

View File

@@ -0,0 +1,4 @@
---
title: "Available"
openapi: "GET /api/v1/app-connections/azure-key-vault/available"
---

View File

@@ -0,0 +1,10 @@
---
title: "Create"
openapi: "POST /api/v1/app-connections/azure-key-vault"
---
<Note>
Azure Key Vault Connections must be created through the Infisical UI.
Check out the configuration docs for [Azure Key Vault Connections](/integrations/app-connections/azure-key-vault) for a step-by-step
guide.
</Note>

View File

@@ -0,0 +1,4 @@
---
title: "Delete"
openapi: "DELETE /api/v1/app-connections/azure-key-vault/{connectionId}"
---

View File

@@ -0,0 +1,4 @@
---
title: "Get by ID"
openapi: "GET /api/v1/app-connections/azure-key-vault/{connectionId}"
---

View File

@@ -0,0 +1,4 @@
---
title: "Get by Name"
openapi: "GET /api/v1/app-connections/azure-key-vault/connection-name/{connectionName}"
---

View File

@@ -0,0 +1,4 @@
---
title: "List"
openapi: "GET /api/v1/app-connections/azure-key-vault"
---

View File

@@ -0,0 +1,10 @@
---
title: "Update"
openapi: "PATCH /api/v1/app-connections/azure-key-vault/{connectionId}"
---
<Note>
Azure Key Vault Connections must be updated through the Infisical UI.
Check out the configuration docs for [Azure Key Vault Connections](/integrations/app-connections/azure-key-vault) for a step-by-step
guide.
</Note>

View File

@@ -80,7 +80,7 @@ Infisical currently only supports one method for connecting to Azure, which is O
</Step>
<Step title="Grant Access">
You will then be redirected to Azure to grant Infisical access to your Azure account (organization and repo privileges). Once granted,
You will then be redirected to Azure to grant Infisical access to your Azure account. Once granted,
you will redirect you back to Infisical's App Connections page. ![Azure App Configuration
Authorization](/images/app-connections/azure/grant-access.png)
</Step>

View File

@@ -32,7 +32,7 @@ Infisical currently only supports one method for connecting to Azure, which is O
</Step>
<Step title="Assign API permissions to the application">
For the Azure Connection to work with both Key Vault, you need to assign multiple permissions to the application.
For the Azure Connection to work with Key Vault, you need to assign multiple permissions to the application.
#### Azure Key Vault permissions
@@ -79,7 +79,7 @@ Infisical currently only supports one method for connecting to Azure, which is O
</Step>
<Step title="Grant Access">
You will then be redirected to Azure to grant Infisical access to your Azure account (organization and repo privileges). Once granted,
You will then be redirected to Azure to grant Infisical access to your Azure account. Once granted,
you will redirect you back to Infisical's App Connections page. ![Azure Key Vault
Authorization](/images/app-connections/azure/grant-access.png)
</Step>

View File

@@ -12,8 +12,7 @@ description: "Learn how to configure an Azure App Configuration Sync for Infisic
The Azure App Configuration Secret Sync requires the following permissions to be set on the user / service principal
for Infisical to sync secrets to Azure App Configuration: `Read Key-Value`, `Write Key-Value`, `Delete Key-Value`.
Any role with these permissions would work such as the **App Configuration Data Owner** role. Alternatively, you can use the
**App Configuration Data Reader** role for read-only access or **App Configuration Data Contributor** role for read/write access.
Any role with these permissions would work such as the **App Configuration Data Owner** role. Alternatively, you can use the **App Configuration Data Contributor** role for read/write access.
</Note>
<Tabs>
@@ -44,11 +43,12 @@ description: "Learn how to configure an Azure App Configuration Sync for Infisic
5. Configure the **Sync Options** to specify how secrets should be synced, then click **Next**.
![Configure Options](/images/secret-syncs/azure-app-configuration/app-config-options.png)
- **Initial Sync Behavior**: Determines how Infisical should resolve the initial sync.
- **Overwrite Destination Secrets**: Removes any secrets at the destination endpoint not present in Infisical.
<Note>
Azure App Configuration does not support importing secrets.
</Note>
- **Import Secrets (Prioritize Infisical)**: Imports secrets from the destination endpoint before syncing, prioritizing values from Infisical over Secrets Manager when keys conflict.
- **Import Secrets (Prioritize Azure App Configuration)**: Imports secrets from the destination endpoint before syncing, prioritizing values from Secrets Manager over Infisical when keys conflict.
- **Auto-Sync Enabled**: If enabled, secrets will automatically be synced from the source location when changes occur. Disable to enforce manual syncing only.
6. Configure the **Details** of your Azure App Configuration Sync, then click **Next**.

View File

@@ -49,9 +49,8 @@ description: "Learn how to configure a Azure Key Vault Sync for Infisical."
- **Initial Sync Behavior**: Determines how Infisical should resolve the initial sync.
- **Overwrite Destination Secrets**: Removes any secrets at the destination endpoint not present in Infisical.
<Note>
Azure Key Vault does not support importing secrets.
</Note>
- **Import Secrets (Prioritize Infisical)**: Imports secrets from the destination endpoint before syncing, prioritizing values from Infisical over Secrets Manager when keys conflict.
- **Import Secrets (Prioritize Azure Key Vault)**: Imports secrets from the destination endpoint before syncing, prioritizing values from Secrets Manager over Infisical when keys conflict.
- **Auto-Sync Enabled**: If enabled, secrets will automatically be synced from the source location when changes occur. Disable to enforce manual syncing only.
6. Configure the **Details** of your Azure Key Vault Sync, then click **Next**.

View File

@@ -1,6 +1,6 @@
{
"name": "Infisical",
"openapi": "https://2eb781d275f5.ngrok.app/api/docs/json",
"openapi": "https://app.infisical.com/api/docs/json",
"logo": {
"dark": "/logo/dark.svg",
"light": "/logo/light.svg",
@@ -847,6 +847,30 @@
"api-reference/endpoints/app-connections/gcp/update",
"api-reference/endpoints/app-connections/gcp/delete"
]
},
{
"group": "Azure Key Vault",
"pages": [
"api-reference/endpoints/app-connections/azure-key-vault/list",
"api-reference/endpoints/app-connections/azure-key-vault/available",
"api-reference/endpoints/app-connections/azure-key-vault/get-by-id",
"api-reference/endpoints/app-connections/azure-key-vault/get-by-name",
"api-reference/endpoints/app-connections/azure-key-vault/create",
"api-reference/endpoints/app-connections/azure-key-vault/update",
"api-reference/endpoints/app-connections/azure-key-vault/delete"
]
},
{
"group": "Azure App Configuration",
"pages": [
"api-reference/endpoints/app-connections/azure-app-configuration/list",
"api-reference/endpoints/app-connections/azure-app-configuration/available",
"api-reference/endpoints/app-connections/azure-app-configuration/get-by-id",
"api-reference/endpoints/app-connections/azure-app-configuration/get-by-name",
"api-reference/endpoints/app-connections/azure-app-configuration/create",
"api-reference/endpoints/app-connections/azure-app-configuration/update",
"api-reference/endpoints/app-connections/azure-app-configuration/delete"
]
}
]
},

View File

@@ -8,6 +8,7 @@ import {
AzureAppConfigurationConnectionMethod,
AzureKeyVaultConnectionMethod,
GitHubConnectionMethod,
TAzureAppConfigurationConnection,
TAzureKeyVaultConnection,
TGitHubConnection,
useCreateAppConnection,
@@ -15,20 +16,25 @@ import {
} from "@app/hooks/api/appConnections";
import { AppConnection } from "@app/hooks/api/appConnections/enums";
type GithubFormData = Pick<TGitHubConnection, "name" | "method" | "description"> & {
type BaseFormData = {
returnUrl?: string;
connectionId?: string;
};
type AzureFormData = Pick<TGitHubConnection, "name" | "method" | "description"> & {
returnUrl?: string;
connectionId?: string;
} & Pick<TAzureKeyVaultConnection["credentials"], "tenantId">;
type GithubFormData = BaseFormData & Pick<TGitHubConnection, "name" | "method" | "description">;
type AzureKeyVaultFormData = BaseFormData &
Pick<TAzureKeyVaultConnection, "name" | "method" | "description"> &
Pick<TAzureKeyVaultConnection["credentials"], "tenantId">;
type AzureAppConfigurationFormData = BaseFormData &
Pick<TAzureAppConfigurationConnection, "name" | "method" | "description"> &
Pick<TAzureAppConfigurationConnection["credentials"], "tenantId">;
type FormDataMap = {
[AppConnection.GitHub]: GithubFormData & { app: AppConnection.GitHub };
[AppConnection.AzureKeyVault]: AzureFormData & { app: AppConnection.AzureKeyVault };
[AppConnection.AzureAppConfiguration]: AzureFormData & {
[AppConnection.AzureKeyVault]: AzureKeyVaultFormData & { app: AppConnection.AzureKeyVault };
[AppConnection.AzureAppConfiguration]: AzureAppConfigurationFormData & {
app: AppConnection.AzureAppConfiguration;
};
};
@@ -105,7 +111,8 @@ export const OAuthCallbackPage = () => {
app: AppConnection.AzureKeyVault,
connectionId,
credentials: {
code: code as string
code: code as string,
tenantId: formData.tenantId
}
});
} else {
@@ -122,7 +129,7 @@ export const OAuthCallbackPage = () => {
}
} catch (err: any) {
createNotification({
title: `Failed to ${connectionId ? "update" : "add"} Azure Connection`,
title: `Failed to ${connectionId ? "update" : "add"} Azure Key Vault Connection`,
text: err?.message,
type: "error"
});
@@ -152,7 +159,8 @@ export const OAuthCallbackPage = () => {
app: AppConnection.AzureAppConfiguration,
connectionId,
credentials: {
code: code as string
code: code as string,
tenantId: formData.tenantId
}
});
} else {
@@ -162,13 +170,14 @@ export const OAuthCallbackPage = () => {
description,
method: AzureAppConfigurationConnectionMethod.OAuth,
credentials: {
code: code as string
code: code as string,
tenantId: formData.tenantId
}
});
}
} catch (err: any) {
createNotification({
title: `Failed to ${connectionId ? "update" : "add"} Azure Connection`,
title: `Failed to ${connectionId ? "update" : "add"} Azure App Configuration Connection`,
text: err?.message,
type: "error"
});

View File

@@ -45,7 +45,8 @@ export const AzureAppConfigurationConnectionForm = ({ appConnection }: Props) =>
resolver: zodResolver(formSchema),
defaultValues: appConnection
? {
...appConnection
...appConnection,
tenantId: appConnection.credentials.tenantId
}
: {
app: AppConnection.AzureAppConfiguration,

View File

@@ -45,7 +45,8 @@ export const AzureKeyVaultConnectionForm = ({ appConnection }: Props) => {
resolver: zodResolver(formSchema),
defaultValues: appConnection
? {
...appConnection
...appConnection,
tenantId: appConnection.credentials.tenantId
}
: {
app: AppConnection.AzureKeyVault,