@tooljet/vault-manager
v1.0.0
Published
Unified TypeScript client for AWS Secrets Manager, GCP Secret Manager, and Azure Key Vault
Readme
vault-manager
A unified TypeScript package for fetching secrets from AWS Secrets Manager, GCP Secret Manager, Azure Key Vault, and HashiCorp Vault. Returns all secrets as a flat Record<string, string> key-value map.
Installation
npm install vault-managerQuick Start
import { vaultManager, VaultProvider } from "vault-manager";
const secrets = await vaultManager(VaultProvider.AWS, {
region: "us-east-1",
secretIds: ["prod/database"],
});
console.log(secrets);
// { DB_HOST: "localhost", DB_PASS: "s3cr3t" }API
vaultManager(provider: VaultProvider, options: ProviderOptions): Promise<Record<string, string>>getProviderOptionsDetails(provider: VaultProvider): ProviderOptionDetail[]
getProviderOptionsDetails(): ProviderOptionsCatalogEntry[]VaultProvider enum
| Value | String |
| ------------------ | --------- |
| VaultProvider.AWS | "aws" |
| VaultProvider.GCP | "gcp" |
| VaultProvider.AZURE | "azure" |
| VaultProvider.HASHICORP | "hashicorp" |
Secret resolution
Each secret value is parsed as JSON when possible. If the value is a JSON object, its keys are merged into the result map directly. If it's a plain string, the secret name is used as the key.
All providers also support optional key filtering via keys: string[] in the provider options. When provided, only those keys are returned from the final merged map.
// Secret "prod/db" value: {"DB_HOST":"rds.aws.com","DB_PORT":"5432"}
// Result: { DB_HOST: "rds.aws.com", DB_PORT: "5432" }
// Secret "api-token" value: "sk-abc123"
// Result: { "api-token": "sk-abc123" }
// Optional filter
// options.keys = ["DB_HOST"]
// Final result: { DB_HOST: "rds.aws.com" }Provider option metadata (for frontend forms)
Use these helpers to get UI-ready option definitions (key, type, label, isRequired) for one provider or all providers.
import { getProviderOptionsDetails, VaultProvider } from "vault-manager";
// One provider
const awsOptions = getProviderOptionsDetails(VaultProvider.AWS);
// All providers at once
const allProviderOptions = getProviderOptionsDetails();Example response shape:
[
{
provider: "aws",
options: [
{ key: "region", type: "text", label: "AWS Region", isRequired: false },
{ key: "secretIds", type: "csv", label: "Secret IDs", isRequired: true },
{ key: "keys", type: "csv", label: "Filter Keys", isRequired: false },
],
},
]Compact option matrix:
| Provider | Key | Type | Required | Label |
| -------- | --- | ---- | -------- | ----- |
| aws | region | text | No | AWS Region |
| aws | accessKeyId | text | No | Access Key ID |
| aws | secretAccessKey | password | No | Secret Access Key |
| aws | sessionToken | password | No | Session Token |
| aws | secretIds | csv | Yes | Secret IDs |
| aws | keys | csv | No | Filter Keys |
| gcp | projectId | text | No | Project ID |
| gcp | keyFilename | text | No | Service Account Key File |
| gcp | secretNames | csv | Yes | Secret Names |
| gcp | keys | csv | No | Filter Keys |
| azure | vaultUrl | text | Yes | Vault URL |
| azure | tenantId | text | No | Tenant ID |
| azure | clientId | text | No | Client ID |
| azure | clientSecret | password | No | Client Secret |
| azure | secretNames | csv | Yes | Secret Names |
| azure | keys | csv | No | Filter Keys |
| hashicorp | vaultUrl | text | Yes | Vault URL |
| hashicorp | token | password | No | Vault Token |
| hashicorp | mountPath | text | No | Mount Path |
| hashicorp | secretPaths | csv | Yes | Secret Paths |
| hashicorp | keys | csv | No | Filter Keys |
Providers
AWS — VaultProvider.AWS
Uses AWS Secrets Manager.
import { vaultManager, VaultProvider } from "vault-manager";
const secrets = await vaultManager(VaultProvider.AWS, {
region: "us-east-1", // Optional — falls back to AWS_REGION env var
accessKeyId: "AKIA...", // Optional — falls back to env / IAM role
secretAccessKey: "...", // Optional — falls back to env / IAM role
sessionToken: "...", // Optional — for temporary credentials
secretIds: [ // Required — names or full ARNs
"prod/database",
"arn:aws:secretsmanager:us-east-1:123:secret:prod/api-keys",
],
});Credential resolution order: explicit options → environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY) → IAM instance role / ECS task role.
GCP — VaultProvider.GCP
Uses GCP Secret Manager.
import { vaultManager, VaultProvider } from "vault-manager";
const secrets = await vaultManager(VaultProvider.GCP, {
projectId: "my-gcp-project", // Optional — falls back to GOOGLE_CLOUD_PROJECT
keyFilename: "/path/to/sa.json", // Optional — falls back to ADC
secretNames: [ // Required — short secret names (not full paths)
"db-password",
"stripe-secret-key",
],
});Credential resolution order: keyFilename → Application Default Credentials (GOOGLE_APPLICATION_CREDENTIALS, gcloud CLI, metadata server).
Azure — VaultProvider.AZURE
Uses Azure Key Vault.
import { vaultManager, VaultProvider } from "vault-manager";
const secrets = await vaultManager(VaultProvider.AZURE, {
vaultUrl: "https://my-vault.vault.azure.net", // Required
tenantId: "...", // Optional — falls back to AZURE_TENANT_ID
clientId: "...", // Optional — falls back to AZURE_CLIENT_ID
clientSecret: "...", // Optional — falls back to AZURE_CLIENT_SECRET
secretNames: [ // Required
"DbPassword",
"StripeKey",
],
});Credential resolution order: explicit tenantId + clientId + clientSecret → DefaultAzureCredential (env vars → managed identity → Azure CLI → etc.).
HashiCorp Vault — VaultProvider.HASHICORP
Uses HashiCorp Vault HTTP API.
import { vaultManager, VaultProvider } from "vault-manager";
const secrets = await vaultManager(VaultProvider.HASHICORP, {
vaultUrl: "http://127.0.0.1:8200", // Required
token: "<vault-token>", // Optional - falls back to VAULT_TOKEN
mountPath: "secret", // Optional - defaults to "secret"
secretPaths: [ // Required - paths to list and read
"",
"prod",
],
});Equivalent LIST call for a root path:
curl \
-H "X-Vault-Token: <vault-token>" \
-X LIST \
http://127.0.0.1:8200/v1/secret/Behavior:
- For each path in
secretPaths, the library issues aLIST /v1/{mountPath}/{path}request. - For each listed key, it issues a
GET /v1/{mountPath}/{path}/{key}request. - Secret objects are flattened into the final result map.
API reference docs:
- https://developer.hashicorp.com/vault/api-docs
KV engine note:
- KV v1 and KV v2 use different API paths.
- KV v1 commonly uses paths like
/v1/secret/<path>. - KV v2 commonly uses
/v1/<mount>/metadata/<path>for LIST and/v1/<mount>/data/<path>for reads. - If your Vault mount is KV v2, ensure the configured mount/path convention matches your server setup before using
secretPaths.
Credential resolution order: explicit token → VAULT_TOKEN environment variable.
Error Handling
All errors are thrown as VaultManagerError which includes the provider name and the original cause:
import { vaultManager, VaultProvider, VaultManagerError } from "vault-manager";
try {
const secrets = await vaultManager(VaultProvider.AWS, {
region: "us-east-1",
secretIds: ["prod/database"],
});
} catch (err) {
if (err instanceof VaultManagerError) {
console.error(`[${err.provider}] ${err.message}`);
console.error("Caused by:", err.cause);
}
}Build
npm run build # compile TypeScript → dist/
npm run build:watch # watch mode
npm run clean # remove dist/License
MIT
