From b40bb726433cf8c19652f4fca98125c5f62a60de Mon Sep 17 00:00:00 2001 From: x032205 Date: Mon, 1 Sep 2025 23:22:59 -0400 Subject: [PATCH] feat(secret-sync): HC Vault Secret Sync Gateway Support --- .../secret-sync/hc-vault/hc-vault-sync-fns.ts | 122 ++++++++++-------- 1 file changed, 69 insertions(+), 53 deletions(-) diff --git a/backend/src/services/secret-sync/hc-vault/hc-vault-sync-fns.ts b/backend/src/services/secret-sync/hc-vault/hc-vault-sync-fns.ts index 73c3a0699..9168c96a6 100644 --- a/backend/src/services/secret-sync/hc-vault/hc-vault-sync-fns.ts +++ b/backend/src/services/secret-sync/hc-vault/hc-vault-sync-fns.ts @@ -1,10 +1,13 @@ import { isAxiosError } from "axios"; import { TGatewayServiceFactory } from "@app/ee/services/gateway/gateway-service"; -import { request } from "@app/lib/config/request"; import { removeTrailingSlash } from "@app/lib/fn"; -import { blockLocalAndPrivateIpAddresses } from "@app/lib/validator"; -import { getHCVaultAccessToken, getHCVaultInstanceUrl } from "@app/services/app-connection/hc-vault"; +import { + getHCVaultAccessToken, + getHCVaultInstanceUrl, + requestWithHCVaultGateway, + THCVaultConnection +} from "@app/services/app-connection/hc-vault"; import { THCVaultListVariables, 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 { TSecretMap } from "@app/services/secret-sync/secret-sync-types"; -const listHCVaultVariables = async ({ instanceUrl, namespace, mount, accessToken, path }: THCVaultListVariables) => { - await blockLocalAndPrivateIpAddresses(instanceUrl); - +const listHCVaultVariables = async ( + { instanceUrl, namespace, mount, accessToken, path }: THCVaultListVariables, + connection: THCVaultConnection, + gatewayService: Pick +) => { try { - const { data } = await request.get( - `${instanceUrl}/v1/${removeTrailingSlash(mount)}/data/${path}`, - { - headers: { - "X-Vault-Token": accessToken, - ...(namespace ? { "X-Vault-Namespace": namespace } : {}) - } + const { data } = await requestWithHCVaultGateway(connection, gatewayService, { + url: `${instanceUrl}/v1/${removeTrailingSlash(mount)}/data/${path}`, + method: "GET", + headers: { + "X-Vault-Token": accessToken, + ...(namespace ? { "X-Vault-Namespace": namespace } : {}) } - ); + }); return data.data.data; } 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 -const updateHCVaultVariables = async ({ - path, - instanceUrl, - namespace, - accessToken, - mount, - data -}: TPostHCVaultVariable) => { - await blockLocalAndPrivateIpAddresses(instanceUrl); - - return request.post( - `${instanceUrl}/v1/${removeTrailingSlash(mount)}/data/${path}`, - { - data +const updateHCVaultVariables = async ( + { path, instanceUrl, namespace, accessToken, mount, data }: TPostHCVaultVariable, + connection: THCVaultConnection, + gatewayService: Pick +) => { + return requestWithHCVaultGateway(connection, gatewayService, { + url: `${instanceUrl}/v1/${removeTrailingSlash(mount)}/data/${path}`, + method: "POST", + headers: { + "X-Vault-Token": accessToken, + ...(namespace ? { "X-Vault-Namespace": namespace } : {}), + "Content-Type": "application/json" }, - { - headers: { - "X-Vault-Token": accessToken, - ...(namespace ? { "X-Vault-Namespace": namespace } : {}), - "Content-Type": "application/json" - } - } - ); + data: { data } + }); }; export const HCVaultSyncFns = { @@ -82,13 +78,17 @@ export const HCVaultSyncFns = { const accessToken = await getHCVaultAccessToken(connection, gatewayService); const instanceUrl = await getHCVaultInstanceUrl(connection); - const variables = await listHCVaultVariables({ - instanceUrl, - accessToken, - namespace, - mount, - path - }); + const variables = await listHCVaultVariables( + { + instanceUrl, + accessToken, + namespace, + mount, + path + }, + connection, + gatewayService + ); let tainted = false; for (const entry of Object.entries(secretMap)) { @@ -115,7 +115,11 @@ export const HCVaultSyncFns = { if (!tainted) return; try { - await updateHCVaultVariables({ accessToken, instanceUrl, namespace, mount, path, data: variables }); + await updateHCVaultVariables( + { accessToken, instanceUrl, namespace, mount, path, data: variables }, + connection, + gatewayService + ); } catch (error) { throw new SecretSyncError({ error @@ -136,7 +140,11 @@ export const HCVaultSyncFns = { const accessToken = await getHCVaultAccessToken(connection, gatewayService); 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)) { if (key in secretMap) { @@ -145,7 +153,11 @@ export const HCVaultSyncFns = { } try { - await updateHCVaultVariables({ accessToken, instanceUrl, namespace, mount, path, data: variables }); + await updateHCVaultVariables( + { accessToken, instanceUrl, namespace, mount, path, data: variables }, + connection, + gatewayService + ); } catch (error) { throw new SecretSyncError({ error @@ -165,13 +177,17 @@ export const HCVaultSyncFns = { const accessToken = await getHCVaultAccessToken(connection, gatewayService); 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 + ); return Object.fromEntries(Object.entries(variables).map(([key, value]) => [key, { value }])); }