mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-14 21:51:56 +00:00
feat: added camunda secret sync
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
|
||||
import { TSecretSyncListItem } from "@app/services/secret-sync/secret-sync-types";
|
||||
|
||||
export const CAMUNDA_SYNC_LIST_OPTION: TSecretSyncListItem = {
|
||||
name: "Camunda",
|
||||
destination: SecretSync.Camunda,
|
||||
connection: AppConnection.Camunda,
|
||||
canImportSecrets: true
|
||||
};
|
||||
@@ -0,0 +1,161 @@
|
||||
import { request } from "@app/lib/config/request";
|
||||
import { TAppConnectionDALFactory } from "@app/services/app-connection/app-connection-dal";
|
||||
import { getCamundaConnectionAccessToken } from "@app/services/app-connection/camunda";
|
||||
import { IntegrationUrls } from "@app/services/integration-auth/integration-list";
|
||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||
import {
|
||||
TCamundaCreateSecret,
|
||||
TCamundaDeleteSecret,
|
||||
TCamundaListSecrets,
|
||||
TCamundaListSecretsResponse,
|
||||
TCamundaPutSecret,
|
||||
TCamundaSyncWithCredentials
|
||||
} from "@app/services/secret-sync/camunda/camunda-sync-types";
|
||||
import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
|
||||
|
||||
import { TSecretMap } from "../secret-sync-types";
|
||||
|
||||
type TCamundaSecretSyncFactoryDeps = {
|
||||
appConnectionDAL: Pick<TAppConnectionDALFactory, "updateById">;
|
||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
||||
};
|
||||
|
||||
const getCamundaSecrets = async ({ accessToken, clusterUUID }: TCamundaListSecrets) => {
|
||||
const { data } = await request.get<TCamundaListSecretsResponse>(
|
||||
`${IntegrationUrls.CAMUNDA_API_URL}/clusters/${clusterUUID}/secrets`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
"Accept-Encoding": "application/json"
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
const createCamundaSecret = async ({ accessToken, clusterUUID, key, value }: TCamundaCreateSecret) =>
|
||||
request.post(
|
||||
`${IntegrationUrls.CAMUNDA_API_URL}/clusters/${clusterUUID}/secrets`,
|
||||
{
|
||||
secretName: key,
|
||||
secretValue: value
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
"Accept-Encoding": "application/json"
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const deleteCamundaSecret = async ({ accessToken, clusterUUID, key }: TCamundaDeleteSecret) =>
|
||||
request.delete(`${IntegrationUrls.CAMUNDA_API_URL}/clusters/${clusterUUID}/secrets/${key}`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
"Accept-Encoding": "application/json"
|
||||
}
|
||||
});
|
||||
|
||||
const updateCamundaSecret = async ({ accessToken, clusterUUID, key, value }: TCamundaPutSecret) =>
|
||||
request.put(
|
||||
`${IntegrationUrls.CAMUNDA_API_URL}/clusters/${clusterUUID}/secrets/${key}`,
|
||||
{
|
||||
secretValue: value
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
"Accept-Encoding": "application/json"
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const camundaSyncFactory = ({ kmsService, appConnectionDAL }: TCamundaSecretSyncFactoryDeps) => {
|
||||
const syncSecrets = async (secretSync: TCamundaSyncWithCredentials, secretMap: TSecretMap) => {
|
||||
const {
|
||||
destinationConfig: { clusterUUID },
|
||||
connection
|
||||
} = secretSync;
|
||||
|
||||
const accessToken = await getCamundaConnectionAccessToken(connection, appConnectionDAL, kmsService);
|
||||
const camundaSecrets = await getCamundaSecrets({ accessToken, clusterUUID });
|
||||
|
||||
for await (const entry of Object.entries(secretMap)) {
|
||||
const [key, { value }] = entry;
|
||||
|
||||
try {
|
||||
if (camundaSecrets[key] === undefined) {
|
||||
await createCamundaSecret({
|
||||
key,
|
||||
value,
|
||||
clusterUUID,
|
||||
accessToken
|
||||
});
|
||||
} else if (camundaSecrets[key] !== value) {
|
||||
await updateCamundaSecret({
|
||||
key,
|
||||
value,
|
||||
clusterUUID,
|
||||
accessToken
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
throw new SecretSyncError({
|
||||
error,
|
||||
secretKey: key
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (secretSync.syncOptions.disableSecretDeletion) return;
|
||||
|
||||
for await (const secret of Object.keys(camundaSecrets)) {
|
||||
if (!(secret in secretMap)) {
|
||||
await deleteCamundaSecret({
|
||||
key: secret,
|
||||
clusterUUID,
|
||||
accessToken
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const removeSecrets = async (secretSync: TCamundaSyncWithCredentials, secretMap: TSecretMap) => {
|
||||
const {
|
||||
destinationConfig: { clusterUUID },
|
||||
connection
|
||||
} = secretSync;
|
||||
|
||||
const accessToken = await getCamundaConnectionAccessToken(connection, appConnectionDAL, kmsService);
|
||||
const camundaSecrets = await getCamundaSecrets({ accessToken, clusterUUID });
|
||||
|
||||
for await (const secret of Object.keys(camundaSecrets)) {
|
||||
if (!(secret in secretMap)) {
|
||||
await deleteCamundaSecret({
|
||||
key: secret,
|
||||
clusterUUID,
|
||||
accessToken
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const getSecrets = async (secretSync: TCamundaSyncWithCredentials) => {
|
||||
const {
|
||||
destinationConfig: { clusterUUID },
|
||||
connection
|
||||
} = secretSync;
|
||||
|
||||
const accessToken = await getCamundaConnectionAccessToken(connection, appConnectionDAL, kmsService);
|
||||
const camundaSecrets = await getCamundaSecrets({ accessToken, clusterUUID });
|
||||
|
||||
return Object.fromEntries(Object.entries(camundaSecrets).map(([key, value]) => [key, { value }]));
|
||||
};
|
||||
|
||||
return {
|
||||
syncSecrets,
|
||||
removeSecrets,
|
||||
getSecrets
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,47 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { SecretSyncs } from "@app/lib/api-docs";
|
||||
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
|
||||
import {
|
||||
BaseSecretSyncSchema,
|
||||
GenericCreateSecretSyncFieldsSchema,
|
||||
GenericUpdateSecretSyncFieldsSchema
|
||||
} from "@app/services/secret-sync/secret-sync-schemas";
|
||||
import { TSyncOptionsConfig } from "@app/services/secret-sync/secret-sync-types";
|
||||
|
||||
const CamundaSyncDestinationConfigSchema = z.object({
|
||||
scope: z.string().trim().min(1, "Camunda scope required").describe(SecretSyncs.DESTINATION_CONFIG.CAMUNDA.scope),
|
||||
clusterUUID: z
|
||||
.string()
|
||||
.min(1, "Camunda cluster UUID is required")
|
||||
.describe(SecretSyncs.DESTINATION_CONFIG.CAMUNDA.clusterUUID)
|
||||
});
|
||||
|
||||
const CamundaSyncOptionsConfig: TSyncOptionsConfig = { canImportSecrets: true };
|
||||
|
||||
export const CamundaSyncSchema = BaseSecretSyncSchema(SecretSync.Camunda, CamundaSyncOptionsConfig).extend({
|
||||
destination: z.literal(SecretSync.Camunda),
|
||||
destinationConfig: CamundaSyncDestinationConfigSchema
|
||||
});
|
||||
|
||||
export const CreateCamundaSyncSchema = GenericCreateSecretSyncFieldsSchema(
|
||||
SecretSync.Camunda,
|
||||
CamundaSyncOptionsConfig
|
||||
).extend({
|
||||
destinationConfig: CamundaSyncDestinationConfigSchema
|
||||
});
|
||||
|
||||
export const UpdateCamundaSyncSchema = GenericUpdateSecretSyncFieldsSchema(
|
||||
SecretSync.Camunda,
|
||||
CamundaSyncOptionsConfig
|
||||
).extend({
|
||||
destinationConfig: CamundaSyncDestinationConfigSchema.optional()
|
||||
});
|
||||
|
||||
export const CamundaSyncListItemSchema = z.object({
|
||||
name: z.literal("Camunda"),
|
||||
connection: z.literal(AppConnection.Camunda),
|
||||
destination: z.literal(SecretSync.Camunda),
|
||||
canImportSecrets: z.literal(true)
|
||||
});
|
||||
@@ -0,0 +1,38 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { TCamundaConnection } from "@app/services/app-connection/camunda";
|
||||
|
||||
import { CamundaSyncListItemSchema, CamundaSyncSchema, CreateCamundaSyncSchema } from "./camunda-sync-schemas";
|
||||
|
||||
export type TCamundaSync = z.infer<typeof CamundaSyncSchema>;
|
||||
|
||||
export type TCamundaSyncInput = z.infer<typeof CreateCamundaSyncSchema>;
|
||||
|
||||
export type TCamundaSyncListItem = z.infer<typeof CamundaSyncListItemSchema>;
|
||||
|
||||
export type TCamundaSyncWithCredentials = TCamundaSync & {
|
||||
connection: TCamundaConnection;
|
||||
};
|
||||
|
||||
export type TCamundaListSecretsResponse = { [key: string]: string };
|
||||
|
||||
type TBaseCamundaSecretRequest = {
|
||||
accessToken: string;
|
||||
clusterUUID: string;
|
||||
};
|
||||
|
||||
export type TCamundaListSecrets = TBaseCamundaSecretRequest;
|
||||
|
||||
export type TCamundaCreateSecret = {
|
||||
key: string;
|
||||
value?: string;
|
||||
} & TBaseCamundaSecretRequest;
|
||||
|
||||
export type TCamundaPutSecret = {
|
||||
key: string;
|
||||
value?: string;
|
||||
} & TBaseCamundaSecretRequest;
|
||||
|
||||
export type TCamundaDeleteSecret = {
|
||||
key: string;
|
||||
} & TBaseCamundaSecretRequest;
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from "./camunda-sync-constants";
|
||||
export * from "./camunda-sync-fns";
|
||||
export * from "./camunda-sync-schemas";
|
||||
export * from "./camunda-sync-types";
|
||||
@@ -6,7 +6,8 @@ export enum SecretSync {
|
||||
AzureKeyVault = "azure-key-vault",
|
||||
AzureAppConfiguration = "azure-app-configuration",
|
||||
Databricks = "databricks",
|
||||
Humanitec = "humanitec"
|
||||
Humanitec = "humanitec",
|
||||
Camunda = "camunda"
|
||||
}
|
||||
|
||||
export enum SecretSyncInitialSyncBehavior {
|
||||
|
||||
@@ -22,6 +22,7 @@ import { TAppConnectionDALFactory } from "../app-connection/app-connection-dal";
|
||||
import { TKmsServiceFactory } from "../kms/kms-service";
|
||||
import { AZURE_APP_CONFIGURATION_SYNC_LIST_OPTION, azureAppConfigurationSyncFactory } from "./azure-app-configuration";
|
||||
import { AZURE_KEY_VAULT_SYNC_LIST_OPTION, azureKeyVaultSyncFactory } from "./azure-key-vault";
|
||||
import { CAMUNDA_SYNC_LIST_OPTION, camundaSyncFactory } from "./camunda";
|
||||
import { GCP_SYNC_LIST_OPTION } from "./gcp";
|
||||
import { GcpSyncFns } from "./gcp/gcp-sync-fns";
|
||||
import { HUMANITEC_SYNC_LIST_OPTION } from "./humanitec";
|
||||
@@ -35,7 +36,8 @@ const SECRET_SYNC_LIST_OPTIONS: Record<SecretSync, TSecretSyncListItem> = {
|
||||
[SecretSync.AzureKeyVault]: AZURE_KEY_VAULT_SYNC_LIST_OPTION,
|
||||
[SecretSync.AzureAppConfiguration]: AZURE_APP_CONFIGURATION_SYNC_LIST_OPTION,
|
||||
[SecretSync.Databricks]: DATABRICKS_SYNC_LIST_OPTION,
|
||||
[SecretSync.Humanitec]: HUMANITEC_SYNC_LIST_OPTION
|
||||
[SecretSync.Humanitec]: HUMANITEC_SYNC_LIST_OPTION,
|
||||
[SecretSync.Camunda]: CAMUNDA_SYNC_LIST_OPTION
|
||||
};
|
||||
|
||||
export const listSecretSyncOptions = () => {
|
||||
@@ -121,6 +123,11 @@ export const SecretSyncFns = {
|
||||
}).syncSecrets(secretSync, secretMap);
|
||||
case SecretSync.Humanitec:
|
||||
return HumanitecSyncFns.syncSecrets(secretSync, secretMap);
|
||||
case SecretSync.Camunda:
|
||||
return camundaSyncFactory({
|
||||
appConnectionDAL,
|
||||
kmsService
|
||||
}).syncSecrets(secretSync, secretMap);
|
||||
default:
|
||||
throw new Error(
|
||||
`Unhandled sync destination for sync secrets fns: ${(secretSync as TSecretSyncWithCredentials).destination}`
|
||||
@@ -165,6 +172,12 @@ export const SecretSyncFns = {
|
||||
case SecretSync.Humanitec:
|
||||
secretMap = await HumanitecSyncFns.getSecrets(secretSync);
|
||||
break;
|
||||
case SecretSync.Camunda:
|
||||
secretMap = await camundaSyncFactory({
|
||||
appConnectionDAL,
|
||||
kmsService
|
||||
}).getSecrets(secretSync);
|
||||
break;
|
||||
default:
|
||||
throw new Error(
|
||||
`Unhandled sync destination for get secrets fns: ${(secretSync as TSecretSyncWithCredentials).destination}`
|
||||
@@ -207,6 +220,11 @@ export const SecretSyncFns = {
|
||||
}).removeSecrets(secretSync, secretMap);
|
||||
case SecretSync.Humanitec:
|
||||
return HumanitecSyncFns.removeSecrets(secretSync, secretMap);
|
||||
case SecretSync.Camunda:
|
||||
return camundaSyncFactory({
|
||||
appConnectionDAL,
|
||||
kmsService
|
||||
}).removeSecrets(secretSync, secretMap);
|
||||
default:
|
||||
throw new Error(
|
||||
`Unhandled sync destination for remove secrets fns: ${(secretSync as TSecretSyncWithCredentials).destination}`
|
||||
|
||||
@@ -9,7 +9,8 @@ export const SECRET_SYNC_NAME_MAP: Record<SecretSync, string> = {
|
||||
[SecretSync.AzureKeyVault]: "Azure Key Vault",
|
||||
[SecretSync.AzureAppConfiguration]: "Azure App Configuration",
|
||||
[SecretSync.Databricks]: "Databricks",
|
||||
[SecretSync.Humanitec]: "Humanitec"
|
||||
[SecretSync.Humanitec]: "Humanitec",
|
||||
[SecretSync.Camunda]: "Camunda"
|
||||
};
|
||||
|
||||
export const SECRET_SYNC_CONNECTION_MAP: Record<SecretSync, AppConnection> = {
|
||||
@@ -20,5 +21,6 @@ export const SECRET_SYNC_CONNECTION_MAP: Record<SecretSync, AppConnection> = {
|
||||
[SecretSync.AzureKeyVault]: AppConnection.AzureKeyVault,
|
||||
[SecretSync.AzureAppConfiguration]: AppConnection.AzureAppConfiguration,
|
||||
[SecretSync.Databricks]: AppConnection.Databricks,
|
||||
[SecretSync.Humanitec]: AppConnection.Humanitec
|
||||
[SecretSync.Humanitec]: AppConnection.Humanitec,
|
||||
[SecretSync.Camunda]: AppConnection.Camunda
|
||||
};
|
||||
|
||||
@@ -9,6 +9,12 @@ import {
|
||||
TAwsSecretsManagerSyncListItem,
|
||||
TAwsSecretsManagerSyncWithCredentials
|
||||
} from "@app/services/secret-sync/aws-secrets-manager";
|
||||
import {
|
||||
TCamundaSync,
|
||||
TCamundaSyncInput,
|
||||
TCamundaSyncListItem,
|
||||
TCamundaSyncWithCredentials
|
||||
} from "@app/services/secret-sync/camunda";
|
||||
import {
|
||||
TDatabricksSync,
|
||||
TDatabricksSyncInput,
|
||||
@@ -58,7 +64,8 @@ export type TSecretSync =
|
||||
| TAzureKeyVaultSync
|
||||
| TAzureAppConfigurationSync
|
||||
| TDatabricksSync
|
||||
| THumanitecSync;
|
||||
| THumanitecSync
|
||||
| TCamundaSync;
|
||||
|
||||
export type TSecretSyncWithCredentials =
|
||||
| TAwsParameterStoreSyncWithCredentials
|
||||
@@ -68,7 +75,8 @@ export type TSecretSyncWithCredentials =
|
||||
| TAzureKeyVaultSyncWithCredentials
|
||||
| TAzureAppConfigurationSyncWithCredentials
|
||||
| TDatabricksSyncWithCredentials
|
||||
| THumanitecSyncWithCredentials;
|
||||
| THumanitecSyncWithCredentials
|
||||
| TCamundaSyncWithCredentials;
|
||||
|
||||
export type TSecretSyncInput =
|
||||
| TAwsParameterStoreSyncInput
|
||||
@@ -78,7 +86,8 @@ export type TSecretSyncInput =
|
||||
| TAzureKeyVaultSyncInput
|
||||
| TAzureAppConfigurationSyncInput
|
||||
| TDatabricksSyncInput
|
||||
| THumanitecSyncInput;
|
||||
| THumanitecSyncInput
|
||||
| TCamundaSyncInput;
|
||||
|
||||
export type TSecretSyncListItem =
|
||||
| TAwsParameterStoreSyncListItem
|
||||
@@ -88,7 +97,8 @@ export type TSecretSyncListItem =
|
||||
| TAzureKeyVaultSyncListItem
|
||||
| TAzureAppConfigurationSyncListItem
|
||||
| TDatabricksSyncListItem
|
||||
| THumanitecSyncListItem;
|
||||
| THumanitecSyncListItem
|
||||
| TCamundaSyncListItem;
|
||||
|
||||
export type TSyncOptionsConfig = {
|
||||
canImportSecrets: boolean;
|
||||
|
||||
Reference in New Issue
Block a user