mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-15 19:16:22 +00:00
Address PR comment for terraform sync integration
This commit is contained in:
@@ -9,7 +9,8 @@ export enum AppConnection {
|
||||
TerraformCloud = "terraform-cloud",
|
||||
Vercel = "vercel",
|
||||
Postgres = "postgres",
|
||||
MsSql = "mssql"
|
||||
MsSql = "mssql",
|
||||
Camunda = "camunda"
|
||||
}
|
||||
|
||||
export enum AWSRegion {
|
||||
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
getAzureKeyVaultConnectionListItem,
|
||||
validateAzureKeyVaultConnectionCredentials
|
||||
} from "./azure-key-vault";
|
||||
import { CamundaConnectionMethod, getCamundaConnectionListItem, validateCamundaConnectionCredentials } from "./camunda";
|
||||
import {
|
||||
DatabricksConnectionMethod,
|
||||
getDatabricksConnectionListItem,
|
||||
@@ -61,7 +62,8 @@ export const listAppConnectionOptions = () => {
|
||||
getTerraformCloudConnectionListItem(),
|
||||
getVercelConnectionListItem(),
|
||||
getPostgresConnectionListItem(),
|
||||
getMsSqlConnectionListItem()
|
||||
getMsSqlConnectionListItem(),
|
||||
getCamundaConnectionListItem()
|
||||
].sort((a, b) => a.name.localeCompare(b.name));
|
||||
};
|
||||
|
||||
@@ -119,6 +121,7 @@ const VALIDATE_APP_CONNECTION_CREDENTIALS_MAP: Record<AppConnection, TAppConnect
|
||||
[AppConnection.Postgres]: validateSqlConnectionCredentials as TAppConnectionCredentialsValidator,
|
||||
[AppConnection.MsSql]: validateSqlConnectionCredentials as TAppConnectionCredentialsValidator,
|
||||
[AppConnection.TerraformCloud]: validateTerraformCloudConnectionCredentials as TAppConnectionCredentialsValidator,
|
||||
[AppConnection.Camunda]: validateCamundaConnectionCredentials as TAppConnectionCredentialsValidator,
|
||||
[AppConnection.Vercel]: validateVercelConnectionCredentials as TAppConnectionCredentialsValidator
|
||||
};
|
||||
|
||||
@@ -142,6 +145,8 @@ export const getAppConnectionMethodName = (method: TAppConnection["method"]) =>
|
||||
return "Service Account Impersonation";
|
||||
case DatabricksConnectionMethod.ServicePrincipal:
|
||||
return "Service Principal";
|
||||
case CamundaConnectionMethod.ClientCredentials:
|
||||
return "Client Credentials";
|
||||
case HumanitecConnectionMethod.ApiToken:
|
||||
case TerraformCloudConnectionMethod.ApiToken:
|
||||
case VercelConnectionMethod.ApiToken:
|
||||
@@ -190,5 +195,6 @@ export const TRANSITION_CONNECTION_CREDENTIALS_TO_PLATFORM: Record<
|
||||
[AppConnection.Postgres]: transferSqlConnectionCredentialsToPlatform as TAppConnectionTransitionCredentialsToPlatform,
|
||||
[AppConnection.MsSql]: transferSqlConnectionCredentialsToPlatform as TAppConnectionTransitionCredentialsToPlatform,
|
||||
[AppConnection.TerraformCloud]: platformManagedCredentialsNotSupported,
|
||||
[AppConnection.Camunda]: platformManagedCredentialsNotSupported,
|
||||
[AppConnection.Vercel]: platformManagedCredentialsNotSupported
|
||||
};
|
||||
|
||||
@@ -11,5 +11,6 @@ export const APP_CONNECTION_NAME_MAP: Record<AppConnection, string> = {
|
||||
[AppConnection.TerraformCloud]: "Terraform Cloud",
|
||||
[AppConnection.Vercel]: "Vercel",
|
||||
[AppConnection.Postgres]: "PostgreSQL",
|
||||
[AppConnection.MsSql]: "Microsoft SQL Server"
|
||||
[AppConnection.MsSql]: "Microsoft SQL Server",
|
||||
[AppConnection.Camunda]: "Camunda"
|
||||
};
|
||||
|
||||
@@ -31,6 +31,8 @@ import { ValidateAwsConnectionCredentialsSchema } from "./aws";
|
||||
import { awsConnectionService } from "./aws/aws-connection-service";
|
||||
import { ValidateAzureAppConfigurationConnectionCredentialsSchema } from "./azure-app-configuration";
|
||||
import { ValidateAzureKeyVaultConnectionCredentialsSchema } from "./azure-key-vault";
|
||||
import { ValidateCamundaConnectionCredentialsSchema } from "./camunda";
|
||||
import { camundaConnectionService } from "./camunda/camunda-connection-service";
|
||||
import { ValidateDatabricksConnectionCredentialsSchema } from "./databricks";
|
||||
import { databricksConnectionService } from "./databricks/databricks-connection-service";
|
||||
import { ValidateGcpConnectionCredentialsSchema } from "./gcp";
|
||||
@@ -65,7 +67,8 @@ const VALIDATE_APP_CONNECTION_CREDENTIALS_MAP: Record<AppConnection, TValidateAp
|
||||
[AppConnection.TerraformCloud]: ValidateTerraformCloudConnectionCredentialsSchema,
|
||||
[AppConnection.Vercel]: ValidateVercelConnectionCredentialsSchema,
|
||||
[AppConnection.Postgres]: ValidatePostgresConnectionCredentialsSchema,
|
||||
[AppConnection.MsSql]: ValidateMsSqlConnectionCredentialsSchema
|
||||
[AppConnection.MsSql]: ValidateMsSqlConnectionCredentialsSchema,
|
||||
[AppConnection.Camunda]: ValidateCamundaConnectionCredentialsSchema
|
||||
};
|
||||
|
||||
export const appConnectionServiceFactory = ({
|
||||
@@ -438,6 +441,7 @@ export const appConnectionServiceFactory = ({
|
||||
aws: awsConnectionService(connectAppConnectionById),
|
||||
humanitec: humanitecConnectionService(connectAppConnectionById),
|
||||
terraformCloud: terraformCloudConnectionService(connectAppConnectionById),
|
||||
camunda: camundaConnectionService(connectAppConnectionById, appConnectionDAL, kmsService),
|
||||
vercel: vercelConnectionService(connectAppConnectionById)
|
||||
};
|
||||
};
|
||||
|
||||
@@ -21,6 +21,12 @@ import {
|
||||
TAzureKeyVaultConnectionInput,
|
||||
TValidateAzureKeyVaultConnectionCredentialsSchema
|
||||
} from "./azure-key-vault";
|
||||
import {
|
||||
TCamundaConnection,
|
||||
TCamundaConnectionConfig,
|
||||
TCamundaConnectionInput,
|
||||
TValidateCamundaConnectionCredentialsSchema
|
||||
} from "./camunda";
|
||||
import {
|
||||
TDatabricksConnection,
|
||||
TDatabricksConnectionConfig,
|
||||
@@ -76,6 +82,7 @@ export type TAppConnection = { id: string } & (
|
||||
| TVercelConnection
|
||||
| TPostgresConnection
|
||||
| TMsSqlConnection
|
||||
| TCamundaConnection
|
||||
);
|
||||
|
||||
export type TAppConnectionRaw = NonNullable<Awaited<ReturnType<TAppConnectionDALFactory["findById"]>>>;
|
||||
@@ -94,6 +101,7 @@ export type TAppConnectionInput = { id: string } & (
|
||||
| TVercelConnectionInput
|
||||
| TPostgresConnectionInput
|
||||
| TMsSqlConnectionInput
|
||||
| TCamundaConnectionInput
|
||||
);
|
||||
|
||||
export type TSqlConnectionInput = TPostgresConnectionInput | TMsSqlConnectionInput;
|
||||
@@ -117,7 +125,8 @@ export type TAppConnectionConfig =
|
||||
| THumanitecConnectionConfig
|
||||
| TTerraformCloudConnectionConfig
|
||||
| TVercelConnectionConfig
|
||||
| TSqlConnectionConfig;
|
||||
| TSqlConnectionConfig
|
||||
| TCamundaConnectionConfig;
|
||||
|
||||
export type TValidateAppConnectionCredentialsSchema =
|
||||
| TValidateAwsConnectionCredentialsSchema
|
||||
@@ -130,6 +139,7 @@ export type TValidateAppConnectionCredentialsSchema =
|
||||
| TValidatePostgresConnectionCredentialsSchema
|
||||
| TValidateMsSqlConnectionCredentialsSchema
|
||||
| TValidateTerraformCloudConnectionCredentialsSchema
|
||||
| TValidateCamundaConnectionCredentialsSchema
|
||||
| TValidateVercelConnectionCredentialsSchema;
|
||||
|
||||
export type TListAwsConnectionKmsKeys = {
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export enum CamundaConnectionMethod {
|
||||
ClientCredentials = "client-credentials"
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
import { request } from "@app/lib/config/request";
|
||||
import { BadRequestError } from "@app/lib/errors";
|
||||
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||
import { encryptAppConnectionCredentials } from "@app/services/app-connection/app-connection-fns";
|
||||
import { IntegrationUrls } from "@app/services/integration-auth/integration-list";
|
||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||
|
||||
import { TAppConnectionDALFactory } from "../app-connection-dal";
|
||||
import { CamundaConnectionMethod } from "./camunda-connection-enums";
|
||||
import { TAuthorizeCamundaConnection, TCamundaConnection, TCamundaConnectionConfig } from "./camunda-connection-types";
|
||||
|
||||
export const getCamundaConnectionListItem = () => {
|
||||
return {
|
||||
name: "Camunda" as const,
|
||||
app: AppConnection.Camunda as const,
|
||||
methods: Object.values(CamundaConnectionMethod) as [CamundaConnectionMethod.ClientCredentials]
|
||||
};
|
||||
};
|
||||
|
||||
const authorizeCamundaConnection = async ({
|
||||
clientId,
|
||||
clientSecret
|
||||
}: Pick<TCamundaConnection["credentials"], "clientId" | "clientSecret">) => {
|
||||
const { data } = await request.post<TAuthorizeCamundaConnection>(
|
||||
IntegrationUrls.CAMUNDA_TOKEN_URL,
|
||||
{
|
||||
grant_type: "client_credentials",
|
||||
client_id: clientId,
|
||||
client_secret: clientSecret,
|
||||
audience: "api.cloud.camunda.io"
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return { accessToken: data.access_token, expiresAt: data.expires_in * 1000 + Date.now() };
|
||||
};
|
||||
|
||||
export const getCamundaConnectionAccessToken = async (
|
||||
{ id, orgId, credentials }: TCamundaConnection,
|
||||
appConnectionDAL: Pick<TAppConnectionDALFactory, "updateById">,
|
||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">
|
||||
) => {
|
||||
const { clientSecret, clientId, accessToken, expiresAt } = credentials;
|
||||
|
||||
// get new token if less than 30 seconds from expiry
|
||||
if (Date.now() < expiresAt - 30_000) {
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
const authData = await authorizeCamundaConnection({ clientId, clientSecret });
|
||||
|
||||
const updatedCredentials: TCamundaConnection["credentials"] = {
|
||||
...credentials,
|
||||
...authData
|
||||
};
|
||||
|
||||
const encryptedCredentials = await encryptAppConnectionCredentials({
|
||||
credentials: updatedCredentials,
|
||||
orgId,
|
||||
kmsService
|
||||
});
|
||||
|
||||
await appConnectionDAL.updateById(id, { encryptedCredentials });
|
||||
|
||||
return authData.accessToken;
|
||||
};
|
||||
|
||||
export const validateCamundaConnectionCredentials = async (appConnection: TCamundaConnectionConfig) => {
|
||||
const { credentials } = appConnection;
|
||||
|
||||
try {
|
||||
const { accessToken, expiresAt } = await authorizeCamundaConnection(appConnection.credentials);
|
||||
|
||||
return {
|
||||
...credentials,
|
||||
accessToken,
|
||||
expiresAt
|
||||
};
|
||||
} catch (e: unknown) {
|
||||
throw new BadRequestError({
|
||||
message: `Unable to validate connection: verify credentials`
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,77 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { AppConnections } from "@app/lib/api-docs";
|
||||
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||
import {
|
||||
BaseAppConnectionSchema,
|
||||
GenericCreateAppConnectionFieldsSchema,
|
||||
GenericUpdateAppConnectionFieldsSchema
|
||||
} from "@app/services/app-connection/app-connection-schemas";
|
||||
|
||||
import { CamundaConnectionMethod } from "./camunda-connection-enums";
|
||||
|
||||
const BaseCamundaConnectionSchema = BaseAppConnectionSchema.extend({ app: z.literal(AppConnection.Camunda) });
|
||||
|
||||
export const CamundaConnectionClientCredentialsInputCredentialsSchema = z.object({
|
||||
clientId: z.string().trim().min(1, "Client ID required").describe(AppConnections.CREDENTIALS.CAMUNDA.clientId),
|
||||
clientSecret: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, "Client Secret required")
|
||||
.describe(AppConnections.CREDENTIALS.CAMUNDA.clientSecret)
|
||||
});
|
||||
|
||||
export const CamundaConnectionClientCredentialsOutputCredentialsSchema = z
|
||||
.object({
|
||||
accessToken: z.string(),
|
||||
expiresAt: z.number()
|
||||
})
|
||||
.merge(CamundaConnectionClientCredentialsInputCredentialsSchema);
|
||||
|
||||
export const CamundaConnectionSchema = z.intersection(
|
||||
BaseCamundaConnectionSchema,
|
||||
z.discriminatedUnion("method", [
|
||||
z.object({
|
||||
method: z.literal(CamundaConnectionMethod.ClientCredentials),
|
||||
credentials: CamundaConnectionClientCredentialsOutputCredentialsSchema
|
||||
})
|
||||
])
|
||||
);
|
||||
|
||||
export const SanitizedCamundaConnectionSchema = z.discriminatedUnion("method", [
|
||||
BaseCamundaConnectionSchema.extend({
|
||||
method: z.literal(CamundaConnectionMethod.ClientCredentials),
|
||||
credentials: CamundaConnectionClientCredentialsOutputCredentialsSchema.pick({
|
||||
clientId: true
|
||||
})
|
||||
})
|
||||
]);
|
||||
|
||||
export const ValidateCamundaConnectionCredentialsSchema = z.discriminatedUnion("method", [
|
||||
z.object({
|
||||
method: z
|
||||
.literal(CamundaConnectionMethod.ClientCredentials)
|
||||
.describe(AppConnections.CREATE(AppConnection.Camunda).method),
|
||||
credentials: CamundaConnectionClientCredentialsInputCredentialsSchema.describe(
|
||||
AppConnections.CREATE(AppConnection.Camunda).credentials
|
||||
)
|
||||
})
|
||||
]);
|
||||
|
||||
export const CreateCamundaConnectionSchema = ValidateCamundaConnectionCredentialsSchema.and(
|
||||
GenericCreateAppConnectionFieldsSchema(AppConnection.Camunda)
|
||||
);
|
||||
|
||||
export const UpdateCamundaConnectionSchema = z
|
||||
.object({
|
||||
credentials: CamundaConnectionClientCredentialsInputCredentialsSchema.optional().describe(
|
||||
AppConnections.UPDATE(AppConnection.Camunda).credentials
|
||||
)
|
||||
})
|
||||
.and(GenericUpdateAppConnectionFieldsSchema(AppConnection.Camunda));
|
||||
|
||||
export const CamundaConnectionListItemSchema = z.object({
|
||||
name: z.literal("Camunda"),
|
||||
app: z.literal(AppConnection.Camunda),
|
||||
methods: z.nativeEnum(CamundaConnectionMethod).array()
|
||||
});
|
||||
@@ -0,0 +1,50 @@
|
||||
import { request } from "@app/lib/config/request";
|
||||
import { OrgServiceActor } from "@app/lib/types";
|
||||
import { TAppConnectionDALFactory } from "@app/services/app-connection/app-connection-dal";
|
||||
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||
import { IntegrationUrls } from "@app/services/integration-auth/integration-list";
|
||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||
|
||||
import { getCamundaConnectionAccessToken } from "./camunda-connection-fns";
|
||||
import { TCamundaConnection, TCamundaListClustersResponse } from "./camunda-connection-types";
|
||||
|
||||
type TGetAppConnectionFunc = (
|
||||
app: AppConnection,
|
||||
connectionId: string,
|
||||
actor: OrgServiceActor
|
||||
) => Promise<TCamundaConnection>;
|
||||
|
||||
const listCamundaClusters = async (
|
||||
appConnection: TCamundaConnection,
|
||||
appConnectionDAL: Pick<TAppConnectionDALFactory, "updateById">,
|
||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">
|
||||
) => {
|
||||
const accessToken = await getCamundaConnectionAccessToken(appConnection, appConnectionDAL, kmsService);
|
||||
|
||||
const { data } = await request.get<TCamundaListClustersResponse>(`${IntegrationUrls.CAMUNDA_API_URL}/clusters`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
"Accept-Encoding": "application/json"
|
||||
}
|
||||
});
|
||||
|
||||
return data ?? [];
|
||||
};
|
||||
|
||||
export const camundaConnectionService = (
|
||||
getAppConnection: TGetAppConnectionFunc,
|
||||
appConnectionDAL: Pick<TAppConnectionDALFactory, "updateById">,
|
||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">
|
||||
) => {
|
||||
const listClusters = async (connectionId: string, actor: OrgServiceActor) => {
|
||||
const appConnection = await getAppConnection(AppConnection.Camunda, connectionId, actor);
|
||||
|
||||
const clusters = await listCamundaClusters(appConnection, appConnectionDAL, kmsService);
|
||||
|
||||
return clusters;
|
||||
};
|
||||
|
||||
return {
|
||||
listClusters
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { DiscriminativePick } from "@app/lib/types";
|
||||
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||
|
||||
import {
|
||||
CamundaConnectionSchema,
|
||||
CreateCamundaConnectionSchema,
|
||||
ValidateCamundaConnectionCredentialsSchema
|
||||
} from "./camunda-connection-schema";
|
||||
|
||||
export type TCamundaConnection = z.infer<typeof CamundaConnectionSchema>;
|
||||
|
||||
export type TCamundaConnectionInput = z.infer<typeof CreateCamundaConnectionSchema> & {
|
||||
app: AppConnection.Camunda;
|
||||
};
|
||||
|
||||
export type TValidateCamundaConnectionCredentialsSchema = typeof ValidateCamundaConnectionCredentialsSchema;
|
||||
|
||||
export type TCamundaConnectionConfig = DiscriminativePick<TCamundaConnectionInput, "method" | "app" | "credentials"> & {
|
||||
orgId: string;
|
||||
};
|
||||
|
||||
export type TAuthorizeCamundaConnection = {
|
||||
access_token: string;
|
||||
scope: string;
|
||||
token_type: string;
|
||||
expires_in: number;
|
||||
};
|
||||
|
||||
export type TCamundaListClustersResponse = { uuid: string; name: string }[];
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from "./camunda-connection-enums";
|
||||
export * from "./camunda-connection-fns";
|
||||
export * from "./camunda-connection-schema";
|
||||
export * from "./camunda-connection-types";
|
||||
Reference in New Issue
Block a user