feat(secret-sync): HC Vault Secret Sync Gateway Support

This commit is contained in:
x032205
2025-09-01 23:22:59 -04:00
parent 4f1cd69bcc
commit b40bb72643

View File

@@ -1,10 +1,13 @@
import { isAxiosError } from "axios"; import { isAxiosError } from "axios";
import { TGatewayServiceFactory } from "@app/ee/services/gateway/gateway-service"; import { TGatewayServiceFactory } from "@app/ee/services/gateway/gateway-service";
import { request } from "@app/lib/config/request";
import { removeTrailingSlash } from "@app/lib/fn"; import { removeTrailingSlash } from "@app/lib/fn";
import { blockLocalAndPrivateIpAddresses } from "@app/lib/validator"; import {
import { getHCVaultAccessToken, getHCVaultInstanceUrl } from "@app/services/app-connection/hc-vault"; getHCVaultAccessToken,
getHCVaultInstanceUrl,
requestWithHCVaultGateway,
THCVaultConnection
} from "@app/services/app-connection/hc-vault";
import { import {
THCVaultListVariables, THCVaultListVariables,
THCVaultListVariablesResponse, THCVaultListVariablesResponse,
@@ -15,19 +18,20 @@ import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
import { matchesSchema } from "@app/services/secret-sync/secret-sync-fns"; import { matchesSchema } from "@app/services/secret-sync/secret-sync-fns";
import { TSecretMap } from "@app/services/secret-sync/secret-sync-types"; import { TSecretMap } from "@app/services/secret-sync/secret-sync-types";
const listHCVaultVariables = async ({ instanceUrl, namespace, mount, accessToken, path }: THCVaultListVariables) => { const listHCVaultVariables = async (
await blockLocalAndPrivateIpAddresses(instanceUrl); { instanceUrl, namespace, mount, accessToken, path }: THCVaultListVariables,
connection: THCVaultConnection,
gatewayService: Pick<TGatewayServiceFactory, "fnGetGatewayClientTlsByGatewayId">
) => {
try { try {
const { data } = await request.get<THCVaultListVariablesResponse>( const { data } = await requestWithHCVaultGateway<THCVaultListVariablesResponse>(connection, gatewayService, {
`${instanceUrl}/v1/${removeTrailingSlash(mount)}/data/${path}`, url: `${instanceUrl}/v1/${removeTrailingSlash(mount)}/data/${path}`,
{ method: "GET",
headers: { headers: {
"X-Vault-Token": accessToken, "X-Vault-Token": accessToken,
...(namespace ? { "X-Vault-Namespace": namespace } : {}) ...(namespace ? { "X-Vault-Namespace": namespace } : {})
}
} }
); });
return data.data.data; return data.data.data;
} catch (error: unknown) { } catch (error: unknown) {
@@ -40,29 +44,21 @@ const listHCVaultVariables = async ({ instanceUrl, namespace, mount, accessToken
}; };
// Hashicorp Vault updates all variables in one batch. This is to respect their versioning // Hashicorp Vault updates all variables in one batch. This is to respect their versioning
const updateHCVaultVariables = async ({ const updateHCVaultVariables = async (
path, { path, instanceUrl, namespace, accessToken, mount, data }: TPostHCVaultVariable,
instanceUrl, connection: THCVaultConnection,
namespace, gatewayService: Pick<TGatewayServiceFactory, "fnGetGatewayClientTlsByGatewayId">
accessToken, ) => {
mount, return requestWithHCVaultGateway(connection, gatewayService, {
data url: `${instanceUrl}/v1/${removeTrailingSlash(mount)}/data/${path}`,
}: TPostHCVaultVariable) => { method: "POST",
await blockLocalAndPrivateIpAddresses(instanceUrl); headers: {
"X-Vault-Token": accessToken,
return request.post( ...(namespace ? { "X-Vault-Namespace": namespace } : {}),
`${instanceUrl}/v1/${removeTrailingSlash(mount)}/data/${path}`, "Content-Type": "application/json"
{
data
}, },
{ data: { data }
headers: { });
"X-Vault-Token": accessToken,
...(namespace ? { "X-Vault-Namespace": namespace } : {}),
"Content-Type": "application/json"
}
}
);
}; };
export const HCVaultSyncFns = { export const HCVaultSyncFns = {
@@ -82,13 +78,17 @@ export const HCVaultSyncFns = {
const accessToken = await getHCVaultAccessToken(connection, gatewayService); const accessToken = await getHCVaultAccessToken(connection, gatewayService);
const instanceUrl = await getHCVaultInstanceUrl(connection); const instanceUrl = await getHCVaultInstanceUrl(connection);
const variables = await listHCVaultVariables({ const variables = await listHCVaultVariables(
instanceUrl, {
accessToken, instanceUrl,
namespace, accessToken,
mount, namespace,
path mount,
}); path
},
connection,
gatewayService
);
let tainted = false; let tainted = false;
for (const entry of Object.entries(secretMap)) { for (const entry of Object.entries(secretMap)) {
@@ -115,7 +115,11 @@ export const HCVaultSyncFns = {
if (!tainted) return; if (!tainted) return;
try { try {
await updateHCVaultVariables({ accessToken, instanceUrl, namespace, mount, path, data: variables }); await updateHCVaultVariables(
{ accessToken, instanceUrl, namespace, mount, path, data: variables },
connection,
gatewayService
);
} catch (error) { } catch (error) {
throw new SecretSyncError({ throw new SecretSyncError({
error error
@@ -136,7 +140,11 @@ export const HCVaultSyncFns = {
const accessToken = await getHCVaultAccessToken(connection, gatewayService); const accessToken = await getHCVaultAccessToken(connection, gatewayService);
const instanceUrl = await getHCVaultInstanceUrl(connection); const instanceUrl = await getHCVaultInstanceUrl(connection);
const variables = await listHCVaultVariables({ instanceUrl, namespace, accessToken, mount, path }); const variables = await listHCVaultVariables(
{ instanceUrl, namespace, accessToken, mount, path },
connection,
gatewayService
);
for await (const [key] of Object.entries(variables)) { for await (const [key] of Object.entries(variables)) {
if (key in secretMap) { if (key in secretMap) {
@@ -145,7 +153,11 @@ export const HCVaultSyncFns = {
} }
try { try {
await updateHCVaultVariables({ accessToken, instanceUrl, namespace, mount, path, data: variables }); await updateHCVaultVariables(
{ accessToken, instanceUrl, namespace, mount, path, data: variables },
connection,
gatewayService
);
} catch (error) { } catch (error) {
throw new SecretSyncError({ throw new SecretSyncError({
error error
@@ -165,13 +177,17 @@ export const HCVaultSyncFns = {
const accessToken = await getHCVaultAccessToken(connection, gatewayService); const accessToken = await getHCVaultAccessToken(connection, gatewayService);
const instanceUrl = await getHCVaultInstanceUrl(connection); const instanceUrl = await getHCVaultInstanceUrl(connection);
const variables = await listHCVaultVariables({ const variables = await listHCVaultVariables(
instanceUrl, {
namespace, instanceUrl,
accessToken, namespace,
mount, accessToken,
path mount,
}); path
},
connection,
gatewayService
);
return Object.fromEntries(Object.entries(variables).map(([key, value]) => [key, { value }])); return Object.fromEntries(Object.entries(variables).map(([key, value]) => [key, { value }]));
} }