node-vault
A client for the HTTP API of HashiCorp's [Vault] written for Node.js.
Install
Prerequisites:
- Node.js >=
18.0.0
npm install -S node-vault
Note: If you need to use an older version of Node.js (>= 6.x), use
node-vault Please be aware thatnode-vault Note: Trailing slashes in theendpointURL (e.g.http://127.0.0.1:8200/) are automatically stripped to prevent malformed request URIs.
Environment Variables
The client reads the following environment variables as defaults:
| Variable | Description |
|---|---|
VAULT_ADDR |
Vault server URL (overridden by endpoint option) |
VAULT_TOKEN |
Vault token (overridden by token option) |
VAULT_NAMESPACE |
Vault Enterprise namespace (overridden by namespace option) |
VAULT_PREFIX |
Request path prefix (overridden by pathPrefix option) |
VAULT_SKIP_VERIFY |
When set, disables SSL certificate verification |
Usage
Init and unseal
const vault = require('node-vault')({
apiVersion: 'v1',
endpoint: 'http://127.0.0.1:8200',
token: 'MY_TOKEN', // optional; can be set after initialization
});
// 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);
Unseal a vault that is already initialized
If the vault server has been restarted or sealed, you can unseal it using
the unseal keys from the original initialization. If the vault was initialized
with secret_threshold > 1, you must call unseal multiple times with
different keys until the threshold is met.
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);
When the vault requires multiple unseal keys (threshold > 1):
vault.unseal({ key: 'first-unseal-key' })
.then((result) => {
// result.sealed will be true until enough keys are provided
console.log('Sealed:', result.sealed);
console.log('Progress:', result.progress + '/' + result.t);
return vault.unseal({ key: 'second-unseal-key' });
})
.then((result) => {
// once the threshold is met, sealed will be false
console.log('Sealed:', result.sealed);
})
.catch(console.error);
See example/unseal.js for a working example.
Write, read, update and delete secrets
vault.write('secret/hello', { value: 'world', lease: '1s' })
.then(() => vault.read('secret/hello'))
.then(() => vault.delete('secret/hello'))
.catch(console.error);
The update method sends a PATCH request with application/merge-patch+json content type:
vault.update('secret/data/hello', { data: { value: 'new-world' } })
.catch(console.error);
List secrets
vault.list('secret/metadata/')
.then((result) => console.log(result.data.keys))
.catch(console.error);
Kubernetes Auth Example
const fs = require('fs');
// Read service account token from default mount path
const jwt = fs.readFileSync('/var/run/secrets/kubernetes.io/serviceaccount/token', { encoding: 'utf8' });
// If the Vault Kubernetes auth endpoint is /auth/example-cluster/login and the role is example-role
vault.kubernetesLogin({
role: 'example-role',
jwt: jwt,
mount_point: 'example-cluster',
}).catch(console.error);
AppRole Auth Example
const vault = require('node-vault')();
vault.approleLogin({
role_id: 'my-role-id',
secret_id: 'my-secret-id',
})
.then((result) => {
// client token is automatically set on successful login
console.log(result.auth.client_token);
})
.catch(console.error);
Error Handling
The client exposes two error types accessible from the module:
VaultError— Base error class for all vault-related errors.ApiResponseError— Thrown on non-200/204 responses. Contains aresponseproperty withstatusCodeandbody.
vault.read('secret/missing')
.catch((err) => {
console.error(err.message); // Error message from Vault
if (err.response) {
console.error(err.response.statusCode); // e.g. 404
console.error(err.response.body); // Response body from Vault
}
});
Custom Commands
You can register custom API commands using generateFunction:
vault.generateFunction('myCustomEndpoint', {
method: 'GET',
path: '/my-custom/endpoint/{{id}}',
});
// Use the generated function
vault.myCustomEndpoint({ id: 'abc123' })
.then(console.log)
.catch(console.error);
Docs
Generate [docco] docs via:
npm run docs
Examples
Please have a look at the [examples] and the generated [feature list] to see all supported Vault API endpoints.
Instead of installing all the dependencies like vault itself and postgres, you can use [docker] and [docker-compose] to link and run multiple docker containers with all of their dependencies.
git clone [email protected]:nodevault/node-vault.git
cd node-vault
docker-compose up vault
Now you can run the examples from another terminal window.
First of all you should initialize and unseal the vault:
node example/init.js
You should see root_token: followed by a long key in the response.
Please copy that long key and export it as an environment variable:
export VAULT_TOKEN=<insert long key here>
Now you are able to run all of the other [examples]:
node example/policies.js
Connecting to Vault Through a Bastion Host
To connect to a vault server in a private network through a bastion host, first open a SOCKS proxy connection:
ssh -D <socksPort> bastion.example.com
Then configure the client with a SOCKS proxy agent:
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 Configuration
If you encounter SSL errors after upgrading to Node 18+ (e.g., EPROTO errors related to
unsafe legacy renegotiation disabled), you can pass SSL/TLS options via requestOptions
or rpDefaults when initializing the client:
const vault = require('node-vault')({
apiVersion: 'v1',
endpoint: 'https://vault.example.com:8200',
token: 'MY_TOKEN',
requestOptions: {
agentOptions: {
securityOptions: 'SSL_OP_LEGACY_SERVER_CONNECT',
},
},
});
The requestOptions object supports TLS/SSL options (ca, cert, key, passphrase,
agentOptions, strictSSL) as well as timeout, httpsAgent, and httpAgent. TLS options
are mapped to an https.Agent and applied to every request. You can also pa