Support for namespaces (for HCP)

This commit is contained in:
x
2025-04-28 18:34:33 -04:00
parent b6566943c6
commit e30d400afa
10 changed files with 72 additions and 11 deletions
+1
View File
@@ -1860,6 +1860,7 @@ export const AppConnections = {
},
HC_VAULT: {
instanceUrl: "The Hashicrop Vault instance URL to connect with.",
namespace: "The Hashicrop Vault namespace to connect with.",
accessToken: "The access token used to connect with Hashicorp Vault.",
roleId: "The Role ID used to connect with Hashicorp Vault.",
secretId: "The Secret ID used to connect with Hashicorp Vault."
@@ -49,7 +49,12 @@ export const getHCVaultAccessToken = async (connection: TValidateHCVaultConnecti
const tokenResp = await request.post<TokenRespData>(
`${removeTrailingSlash(instanceUrl)}/v1/auth/approle/login`,
{ role_id: roleId, secret_id: secretId },
{ headers: { "Content-Type": "application/json" } }
{
headers: {
"Content-Type": "application/json",
...(connection.credentials.namespace ? { "X-Vault-Namespace": connection.credentials.namespace } : {})
}
}
);
if (tokenResp.status !== 200) {
@@ -95,7 +100,10 @@ export const listHCVaultMounts = async (appConnection: THCVaultConnection) => {
const accessToken = await getHCVaultAccessToken(appConnection);
const { data } = await request.get<THCVaultMountResponse>(`${instanceUrl}/v1/sys/mounts`, {
headers: { "X-Vault-Token": accessToken }
headers: {
"X-Vault-Token": accessToken,
...(appConnection.credentials.namespace ? { "X-Vault-Namespace": appConnection.credentials.namespace } : {})
}
});
const mounts: string[] = [];
@@ -17,8 +17,11 @@ const InstanceUrlSchema = z
.url("Invalid Instance URL")
.describe(AppConnections.CREDENTIALS.HC_VAULT.instanceUrl);
const NamespaceSchema = z.string().trim().optional().describe(AppConnections.CREDENTIALS.HC_VAULT.namespace);
export const HCVaultConnectionAccessTokenCredentialsSchema = z.object({
instanceUrl: InstanceUrlSchema,
namespace: NamespaceSchema,
accessToken: z
.string()
.trim()
@@ -28,6 +31,7 @@ export const HCVaultConnectionAccessTokenCredentialsSchema = z.object({
export const HCVaultConnectionAppRoleCredentialsSchema = z.object({
instanceUrl: InstanceUrlSchema,
namespace: NamespaceSchema,
roleId: z.string().trim().min(1, "Role ID required").describe(AppConnections.CREDENTIALS.HC_VAULT.roleId),
secretId: z.string().trim().min(1, "Secret ID required").describe(AppConnections.CREDENTIALS.HC_VAULT.secretId)
});
@@ -10,12 +10,13 @@ import {
import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
import { TSecretMap } from "@app/services/secret-sync/secret-sync-types";
const listHCVaultVariables = async ({ instanceUrl, mount, accessToken, path }: THCVaultListVariables) => {
const listHCVaultVariables = async ({ instanceUrl, namespace, mount, accessToken, path }: THCVaultListVariables) => {
const { data } = await request.get<THCVaultListVariablesResponse>(
`${instanceUrl}/v1/${removeTrailingSlash(mount)}/data/${path}`,
{
headers: {
"X-Vault-Token": accessToken
"X-Vault-Token": accessToken,
...(namespace ? { "X-Vault-Namespace": namespace } : {})
}
}
);
@@ -24,7 +25,14 @@ const listHCVaultVariables = async ({ instanceUrl, mount, accessToken, path }: T
};
// Hashicorp Vault updates all variables in one batch. This is to respect their versioning
const updateHCVaultVariables = async ({ path, instanceUrl, accessToken, mount, data }: TPostHCVaultVariable) =>
const updateHCVaultVariables = async ({
path,
instanceUrl,
namespace,
accessToken,
mount,
data
}: TPostHCVaultVariable) =>
request.post(
`${instanceUrl}/v1/${removeTrailingSlash(mount)}/data/${path}`,
{
@@ -33,6 +41,7 @@ const updateHCVaultVariables = async ({ path, instanceUrl, accessToken, mount, d
{
headers: {
"X-Vault-Token": accessToken,
...(namespace ? { "X-Vault-Namespace": namespace } : {}),
"Content-Type": "application/json"
}
}
@@ -46,10 +55,17 @@ export const HCVaultSyncFns = {
syncOptions: { disableSecretDeletion }
} = secretSync;
const { namespace } = connection.credentials;
const accessToken = await getHCVaultAccessToken(connection);
const instanceUrl = await getHCVaultInstanceUrl(connection);
const variables = await listHCVaultVariables({ instanceUrl, accessToken, mount, path });
const variables = await listHCVaultVariables({
instanceUrl,
accessToken,
namespace,
mount,
path
});
let tainted = false;
for (const entry of Object.entries(secretMap)) {
@@ -73,7 +89,7 @@ export const HCVaultSyncFns = {
if (!tainted) return;
try {
await updateHCVaultVariables({ accessToken, instanceUrl, mount, path, data: variables });
await updateHCVaultVariables({ accessToken, instanceUrl, namespace, mount, path, data: variables });
} catch (error) {
throw new SecretSyncError({
error
@@ -86,10 +102,11 @@ export const HCVaultSyncFns = {
destinationConfig: { mount, path }
} = secretSync;
const { namespace } = connection.credentials;
const accessToken = await getHCVaultAccessToken(connection);
const instanceUrl = await getHCVaultInstanceUrl(connection);
const variables = await listHCVaultVariables({ instanceUrl, accessToken, mount, path });
const variables = await listHCVaultVariables({ instanceUrl, namespace, accessToken, mount, path });
for await (const [key] of Object.entries(variables)) {
if (key in secretMap) {
@@ -98,7 +115,7 @@ export const HCVaultSyncFns = {
}
try {
await updateHCVaultVariables({ accessToken, instanceUrl, mount, path, data: variables });
await updateHCVaultVariables({ accessToken, instanceUrl, namespace, mount, path, data: variables });
} catch (error) {
throw new SecretSyncError({
error
@@ -111,11 +128,13 @@ export const HCVaultSyncFns = {
destinationConfig: { mount, path }
} = secretSync;
const { namespace } = connection.credentials;
const accessToken = await getHCVaultAccessToken(connection);
const instanceUrl = await getHCVaultInstanceUrl(connection);
const variables = await listHCVaultVariables({
instanceUrl,
namespace,
accessToken,
mount,
path
@@ -25,6 +25,7 @@ export type THCVaultListVariablesResponse = {
export type THCVaultListVariables = {
accessToken: string;
instanceUrl: string;
namespace?: string;
mount: string;
path: string;
};