https://github.com/cludden/vault-client
a node client for HashiCorp's Vault
https://github.com/cludden/vault-client
Last synced: 5 months ago
JSON representation
a node client for HashiCorp's Vault
- Host: GitHub
- URL: https://github.com/cludden/vault-client
- Owner: cludden
- License: mit
- Created: 2016-05-30T22:40:24.000Z (about 10 years ago)
- Default Branch: master
- Last Pushed: 2016-10-10T03:44:52.000Z (almost 10 years ago)
- Last Synced: 2024-03-23T15:46:41.747Z (over 2 years ago)
- Language: JavaScript
- Size: 55.7 KB
- Stars: 5
- Watchers: 5
- Forks: 5
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
Awesome Lists containing this project
README
# vault-client
A node client for HashiCorp's [vault](https://www.vaultproject.io/). In addition
to supporting basic http interaction with a vault api, it will also manage:
- authentication & reauthentication based on token `lease_duration`
- including the current access token on every request as the `X-Vault-Token` header
- caching & renewing secrets based on `lease_duration`
- notifying subscribers of secret renewals
## Installing
```bash
npm install --save vault-client
```
## Getting Started
```javascript
const Vault = require('vault-client');
const client = new Vault({
url: 'https://vault.example.com'
});
async.series([
// first, we need to authenticate with vault
function login(next) {
vault.login({
backend: 'userpass',
options: {
username: 'bob',
password: 'password1'
}
}, next);
},
// let's add some secrets
function addSecrets(next) {
const secrets = [{
path: '/secret/foo',
data: {
foo: 'bar'
}
},{
path: '/secret/bar',
data: {
bar: 'baz'
}
}];
async.each(secrets, function(secret, done) {
vault.post(secret.path, secret.data, done);
}, next);
},
// next, we can fetch a single secret from vault
function get(next) {
vault.get('/secret/foo', function(err, data) {
console.log(data);
// {
// "data": {
// "foo": "bar"
// },
// "lease_duration": 2592000,
// "renewable": false
// }
next(err);
});
},
// or, we can choose to watch a single secret. the vault client
// will cache the fetched secret locally, and will handle renewing
// the secret if a lease_duration is included in the response metadata
function(next) {
vault.watch({
address: 'foo', // store the secret in the cache at path "foo"
path: '/secret/foo'
}, function(err, data) {
const foo = vault.secret('foo');
console.log(JSON.stringify(foo));
// { "foo": "bar" }
next(err, data);
});
// we can listen for secret renewals at the "foo" address by attaching
// a listener to the "secret:
" event
vault.on('secret:foo', function(data) {
console.log(JSON.stringify(data))
// { "foo": "goo" }
});
},
// we can also choose to watch multiple secrets. again, the vault client
// will handle renewing each secret based on its lease_duration.
function(next) {
vault.watch([{
address: '.', // the root address, secret will be merged into the root
path: '/secret/foo'
}, {
address: 'bar',
path: '/secret/bar'
}], function(err, data) {
console.log(JSON.stringify(vault.secret()))
// { "bar": { "bar": "baz" }, "foo": "bar" }
});
}
]);
```
## API
### Vault(options)
Creates a new `vault` client.
###### Params
| param | type | description |
| :--- | :---: | :--- |
| options* | `{Object}` | options |
| options.url* | `{String}` | the base url of the vault server |
| options.retry | `{Object}` | global retry settings for failed network requests. see [node-retry](https://github.com/tim-kos/node-retry) for more info
###### Example
```javascript
const Vault = require('vault-client');
const vault = new Vault({
url: 'https://localhost:8200/v1'
});
```
### vault.secret([address])
Fetch a copy of a partial branch of secret cache. If no address is specified, a copy of the entire cache will be returned.
###### Params
| param | type | description |
| :--- | :---: | :--- |
| address | `{String}` | an path of the cache to retrieve |
###### Example
```javascript
const secrets = vault.secret();
console.log(JSON.stringify(secrets));
// returns a copy of the internal store
// {
// "foo": "bar",
// "bar": { "bar": "baz" },
// "super": { "nested": { "secret": "s3cr3t" }}
// }
const nested = vault.secret('some.nested.secret');
console.log(nested)
// returns a copy of a branch of the store
// "s3cr3t"
```
### vault.watch(secrets, [options], [cb])
Fetches one or more secrets from vault and caches them internally. If a secret includes a `lease_duration` greater than 0, this method will handle renewing them periodically. Failed attempts will be automatically retried using [node-retry](https://github.com/tim-kos/node-retry) |
###### Params
| param | type | description |
| :--- | :---: | :--- |
| secrets* | `{Object,Object[]}` | |
| secrets.$.address* | `{String}` | the caching address to use for the fetched secret's data |
| secrets.$.path* | `{String}` | the relative url of the secret in vault |
| options | `{Object}` | |
| options.retry | `{Object}` | optional [node-retry](https://github.com/tim-kos/node-retry) settings for retrying failed attempts |
| cb | `{Function}` | node style callback |
###### Example
```javascript
const secrets = [
{ address: '.', path: '/secret/foo' },
{ address: 'bar', path: '/secret/bar' },
{ address: 'super', path: '/secret/super' }
];
vault.watch(secrets, function(err, data) {
// do something once all secrets have been successfully retrieved.
});
vault.on('secret:foo', function(secret) {
// execute when secret is first retrieved and every time secret is renewed
});
```
### vault.delete(url, [config], [cb])
Issues a DELETE request to vault. If the client is authenticated, the request will include the current client_token via the `X-VAULT-TOKEN` header.
###### Params
| param | type | description |
| :--- | :---: | :--- |
| url* | `{String}` | relative url |
| config | `{Object}` | [axios](https://github.com/mzabriskie/axios) configuration object |
| cb | `{Function}` | node style callback |
### vault.head(url, [config], [cb])
Issues a HEAD request to vault. If the client is authenticated, the request will include the current client_token via the `X-VAULT-TOKEN` header.
###### Params
| param | type | description |
| :--- | :---: | :--- |
| url* | `{String}` | relative url |
| config | `{Object}` | [axios](https://github.com/mzabriskie/axios) configuration object |
| cb | `{Function}` | node style callback |
### vault.get(url, [config], [cb])
Issues a GET request to vault. If the client is authenticated, the request will include the current client_token via the `X-VAULT-TOKEN` header.
###### Params
| param | type | description |
| :--- | :---: | :--- |
| url* | `{String}` | relative url |
| config | `{Object}` | [axios](https://github.com/mzabriskie/axios) configuration object |
| cb | `{Function}` | node style callback |
###### Example
```javascript
// node style
vault.get('/secrets/foo', {
timeout: 1000
}, function(err, results) {
console.log(results);
})
// promise style
vault.get('/secrets/foo', {
timeout: 1000
}).then(function(res) {
// res is an axios res object
}).catch(function(err) {
// catch any errors
});
```
### vault.login(options, [callback])
Create a new session with vault server and periodically refresh it.
*currently the 'userpass' backend is the only supported backend*
###### Params
| param | type | description |
| :--- | :---: | :--- |
| options* | `{Object} | login options |
| options.backend* | `{String}` | the backend to use. currently supported backends: userpass |
| options.options* | `{Object}` | backend specific options |
| options.retry | `{Object}` | in the event of network errors, the client will continue attempting the login using [node-retry](https://github.com/tim-kos/node-retry) |
### vault.patch(url, [data], [config], [cb])
Issues a PATCH request to vault. If the client is authenticated, the request will include the current client_token via the `X-VAULT-TOKEN` header.
###### Params
| param | type | description |
| :--- | :---: | :--- |
| url* | `{String}` | relative url |
| data | `{Object}` | request data |
| config | `{Object}` | [axios](https://github.com/mzabriskie/axios) configuration object |
| cb | `{Function}` | node style callback |
### vault.post(url, [data], [config], [cb])
Issues a POST request to vault. If the client is authenticated, the request will include the current client_token via the `X-VAULT-TOKEN` header.
###### Params
| param | type | description |
| :--- | :---: | :--- |
| url* | `{String}` | relative url |
| data | `{Object}` | request data |
| config | `{Object}` | [axios](https://github.com/mzabriskie/axios) configuration object |
| cb | `{Function}` | node style callback |
### vault.put(url, [data], [config], [cb])
Issues a PUT request to vault. If the client is authenticated, the request will include the current client_token via the `X-VAULT-TOKEN` header.
###### Params
| param | type | description |
| :--- | :---: | :--- |
| url* | `{String}` | relative url |
| data | `{Object}` | request data |
| config | `{Object}` | [axios](https://github.com/mzabriskie/axios) configuration object |
| cb | `{Function}` | node style callback |
## Events
| name | callback | description |
| :--- | :--- | :--- |
| error | `function(err)` | all errors will bubble to here |
| error:login | `function(err)` | login errors |
## Auth Backends
Following are backend specific login options
### userpass
```js
{
backend: 'userpass',
options: {
username: '',
password: ''
}
}
```
## Todo
- [ ] add support for additional auth backends
## Testing
run the test suite (*requires docker-compose v1.7+*)
```bash
docker-compose up
```
run coverage
```bash
docker-compose run client npm run coverage
```
## Contributing
1. [Fork it](https://github.com/cludden/vault-client/fork)
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request
## License
Copyright (c) 2016 Chris Ludden
Licensed under the [MIT License](LICENSE.md);