node-vault

repository·master·Indexed 19 days ago

https://github.com/nodevault/node-vault

A Node.js client for the HashiCorp Vault HTTP API (version 0.12.0) that provides a programmatic way to manage secrets, authentication, and Vault server lifecycle operations such as initialization and unsealing. It supports standard CRUD operations for secrets, Transit secrets engine for encryption/decryption, and authentication methods including Kubernetes and AppRole. The client includes TypeScript definitions and supports custom API command registration via generateFunction.

Tokens
6K
Snippets
15
Records
21
Agent score
69%

What's inside node-vault

  1. Initialize and unseal a Vault server

    master

    Use init() to initialize a new Vault server and unseal() to make it operational.

    When initializing, you specify secret_shares and secret_threshold. The init result contains the keys needed for unsealing and a root_token for authentication. After initialization, you should set the client's token to the root_token to perform subsequent operations.

    const vault = require('node-vault')({
      apiVersion: 'v1',
      endpoint: 'http://127.0.0.1:8200',
      token: 'MY_TOKEN',
    });
    
    // init vault server
    vault.init({ secret_shares: 1, secret_threshold: 1 })
      .then((result) => {
        const keys = result.keys;
        // set token for all following requests
        vault.token = result.root_token;
        // unseal vault server
        return vault.unseal({ secret_shares: 1, key: keys[0] });
      })
      .catch(console.error);
  2. Unseal an existing Vault server

    master

    If a Vault server is sealed (e.g., after a restart), you must call unseal() with the required keys. If the vault was initialized with a secret_threshold > 1, you must call unseal() multiple times with different keys until the threshold is met. The result of unseal() contains a sealed boolean and progress (current keys / threshold).

    const vault = require('node-vault')({
      apiVersion: 'v1',
      endpoint: 'http://127.0.0.1:8200',
    });
    
    // unseal vault server with a single key
    vault.unseal({ key: 'my-unseal-key' })
      .then(console.log)
      .catch(console.error);
  3. Install node-vault

    master

    Install the node-vault client via npm.

    Prerequisites:

    • Node.js >= 18.0.0

    Note: If you are using an older version of Node.js (>= 6.x), you must use node-vault <= v0.10.0. However, be aware that versions <= v0.10.0 contain known vulnerabilities.

    TypeScript definitions are included in the package.

    npm install -S node-vault
  4. Configure SSL/TLS and SOCKS proxies

    master

    You can customize the underlying HTTP/HTTPS agents via requestOptions during client initialization or per-call.

    SOCKS Proxy: To connect through a bastion host, use socks-proxy-agent and pass it to httpAgent and httpsAgent within requestOptions.

    Custom SSL/TLS Options: To resolve SSL errors (like EPROTO on Node 18+), pass agentOptions containing securityOptions (e.g., SSL_OP_LEGACY_SERVER_CONNECT).

    Supported requestOptions keys include: ca, cert, key, passphrase, agentOptions, strictSSL, timeout, httpsAgent, and httpAgent.

    // SOCKS Proxy Example
    const { SocksProxyAgent } = require('socks-proxy-agent');
    const agent = new SocksProxyAgent(`socks://127.0.0.1:${socksPort}`);
    
    const vault = require('node-vault')({
      apiVersion: 'v1',
      requestOptions: {
        httpsAgent: agent,
        httpAgent: agent,
      },
    });
    
    // Custom SSL/TLS per-call
    vault.read('secret/hello', {
      agentOptions: {
        securityOptions: 'SSL_OP_LEGACY_SERVER_CONNECT',
      },
    });
  5. Configure the node-vault client

    master

    Initialize the Vault client by passing an options object. The client also supports configuration via environment variables.

    Client Options:

    • apiVersion: API version (default: 'v1')
    • endpoint: Vault server URL (default: 'http://127.0.0.1:8200'). Trailing slashes are automatically stripped.
    • token: Vault token for authentication.
    • pathPrefix: Optional prefix for all request paths.
    • namespace: Vault Enterprise namespace.
    • noCustomHTTPVerbs: If true, uses GET with ?list=1 instead of the LIST HTTP method.
    • requestOptions: Custom axios request options applied to all requests (e.g., headers, timeout, httpsAgent).

    Environment Variables (Defaults):

    • VAULT_ADDR: Vault server URL (overridden by endpoint)
    • VAULT_TOKEN: Vault token (overridden by token)
    • VAULT_NAMESPACE: Vault Enterprise namespace (overridden by namespace)
    • VAULT_PREFIX: Request path prefix (overridden by pathPrefix)
    • VAULT_SKIP_VERIFY: Disables SSL certificate verification when set.
    const vault = require('node-vault')({
      apiVersion: 'v1',
      endpoint: 'http://127.0.0.1:8200',
      token: 'MY_TOKEN',
      pathPrefix: '',
      namespace: 'my-namespace',
      noCustomHTTPVerbs: false,
      requestOptions: {},
    });
  6. Handle Vault API errors

    master

    When a Vault API request fails (non-200/204 status code), the client throws an ApiResponseError.

    An ApiResponseError contains:

    • message: The error message extracted from the Vault response (e.g., from response.body.errors[0]).
    • response.statusCode: The HTTP status code returned by Vault.
    • response.body: The full JSON body returned by Vault.

    Note: Requests to sys/health are treated as successful even if they return non-200 status codes, to allow for health checking logic.

    try {
      await client.read('secret/invalid-path');
    } catch (err) {
      if (err.name === 'ApiResponseError') {
        console.error(`Vault Error: ${err.message}`);
        console.error(`Status: ${err.response.statusCode}`);
        console.error(`Body:`, err.response.body);
      } else {
        console.error('Generic Error:', err);
      }
    }
  7. Run HashiCorp Vault with PostgreSQL via Docker Compose

    master

    This docker-compose.yml file provides a local development environment for running HashiCorp Vault (v1.13.3) with a PostgreSQL backend (v15.3).

    Service Details

    • vault: The main Vault service. It uses the IPC_LOCK capability to prevent memory from being swapped to disk. It is configured to use a configuration file located at /tmp/example/config.hcl inside the container. The host directory $PWD/example is mounted to /tmp/example to provide this configuration.
    • postgres: A PostgreSQL database used as a storage backend. It is exposed on host port 5433 (mapping to container port 5432).

    Environment Variables for PostgreSQL

    When using this setup, the PostgreSQL service is initialized with the following credentials:

    • POSTGRES_USER: root
    • POSTGRES_PASSWORD: test
    version: '2'
    services:
      vault:
        container_name: vault
        image: vault:1.13.3
        volumes:
          - $PWD/example:/tmp/example
          - $PWD/logs/:/tmp/logs
        cap_add:
          - IPC_LOCK
        command: server -config /tmp/example/config.hcl
        ports:
          - "8200:8200"
        depends_on:
          - postgres
        networks:
          - vault-network
    
    postgres:
        image: postgres:15.3
        ports:
          - "5433:5432"
        environment:
          POSTGRES_USER: root
          POSTGRES_PASSWORD: test
        networks:
          - vault-network
    
    networks:
      vault-network:
        name: vault-network
        driver: bridge
  8. Initialize the Vault client

    master

    To use node-vault, call the exported function with a configuration object. The client is an EventEmitter that provides methods to interact with the HashiCorp Vault API.

    By default, the client uses the following values if not provided in the config:

    • apiVersion: 'v1'
    • endpoint: process.env.VAULT_ADDR or 'http://127.0.0.1:8200'
    • pathPrefix: process.env.VAULT_PREFIX or ''
    • token: process.env.VAULT_TOKEN
    • namespace: process.env.VAULT_NAMESPACE

    You can also provide requestOptions to configure TLS settings (like ca, cert, key, passphrase, pfx) or strictSSL (defaults to true unless process.env.VAULT_SKIP_VERIFY is set).

    const Vault = require('node-vault');
    
    const client = Vault({
      apiVersion: 'v1',
      endpoint: 'https://your-vault-url:8200',
      token: 'your-vault-token',
      namespace: 'your-namespace'
    });
  9. Authenticate using Kubernetes or AppRole

    master

    The client supports various authentication methods:

    Kubernetes Auth: Requires a JWT (typically from a service account token) and a role. You must also specify the mount_point where the Kubernetes auth method is enabled.

    AppRole Auth: Requires a role_id and a secret_id. Upon successful login, the client automatically sets the token property on the client instance.

    // Kubernetes Auth
    const fs = require('fs');
    const jwt = fs.readFileSync('/var/run/secrets/kubernetes.io/serviceaccount/token', { encoding: 'utf8' });
    
    vault.kubernetesLogin({
      role: 'example-role',
      jwt: jwt,
      mount_point: 'example-cluster',
    }).catch(console.error);
    
    // AppRole Auth
    vault.approleLogin({
      role_id: 'my-role-id',
      secret_id: 'my-secret-id',
    }).then((result) => {
      console.log(result.auth.client_token);
    }).catch(console.error);
  10. Manage Vault policies and mounts

    master

    Control access control policies and filesystem-like mounts within Vault:

    Policies

    • vault.policies: List all policies (GET /sys/policy).
    • vault.addPolicy: Create or update a policy (PUT /sys/policy/{{name}}).
    • vault.getPolicy: Retrieve a policy (GET /sys/policy/{{name}}).
    • vault.removePolicy: Delete a policy (DELETE /sys/policy/{{name}}).

    Mounts

    • vault.mounts: List all active mounts (GET /sys/mounts).
    • vault.mount: Mount a new secrets engine (POST /sys/mounts/{{mount_point}}).
    • vault.unmount: Unmount a secrets engine (DELETE /sys/mounts/{{mount_point}}).
    • vault.remount: Remount a secrets engine (POST /sys/remount).
  11. Register custom API commands with `generateFunction`

    master

    If you need to access a Vault API endpoint not explicitly implemented in the client, use generateFunction. This creates a new method on the vault instance.

    Arguments for generateFunction(name, options):

    • name: The name of the new method to be added to the client.
    • options: An object containing method (HTTP verb) and path (the endpoint path, supporting {{key}} placeholders).
    vault.generateFunction('myCustomEndpoint', {
      method: 'GET',
      path: '/my-custom/endpoint/{{id}}',
    });
    
    // Use the generated function
    vault.myCustomEndpoint({ id: 'abc123' })
      .then(console.log)
      .catch(console.error);
  12. Manage Token lifecycle and accessors

    master

    Perform advanced token management operations:

    • vault.tokenCreate: Create a new token (POST /auth/token/create).
    • vault.tokenCreateOrphan: Create an orphan token (POST /auth/token/create-orphan).
    • vault.tokenCreateRole: Create a token with a specific role (POST /auth/token/create/{{role_name}}).
    • vault.tokenLookup: Look up token information (POST /auth/token/lookup).
    • vault.tokenLookupSelf: Look up information about the current token (GET /auth/token/lookup-self).
    • vault.tokenRenew: Renew a token (POST /auth/token/renew).
    • vault.tokenRenewSelf: Renew the current token (POST /auth/token/renew-self).
    • vault.tokenRevoke: Revoke a token (POST /auth/token/revoke).
    • vault.tokenRevokeSelf: Revoke the current token (POST /auth/token/revoke-self).
    • vault.tokenAccessors: List token accessors (LIST /auth/token/accessors).