node-vault-client 1.0.2 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +201 -17
- package/package.json +30 -10
- package/src/VaultApiClient.js +58 -19
- package/src/VaultClient.js +32 -7
- package/src/VaultNodeConfig.js +3 -4
- package/src/auth/AuthToken.js +57 -10
- package/src/auth/VaultAppRoleAuth.js +2 -0
- package/src/auth/VaultBaseAuth.js +26 -4
- package/src/auth/VaultIAMAuth.js +30 -5
- package/src/auth/VaultKubernetesAuth.js +1 -0
- package/src/auth/VaultTokenAuth.js +5 -4
- package/src/errors.js +2 -2
package/README.md
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
# Node.js Vault Client
|
|
2
2
|
|
|
3
|
-
](https://github.com/namecheap/node-vault-client/actions/workflows/pipeline.yaml)
|
|
4
|
+
[](https://www.npmjs.com/package/node-vault-client)
|
|
5
|
+
[](https://www.npmjs.com/package/node-vault-client)
|
|
6
|
+
[](https://github.com/namecheap/node-vault-client/blob/master/LICENSE.txt)
|
|
7
|
+
[](https://libraries.io/npm/node-vault-client/)
|
|
5
8
|
|
|
6
9
|
A Vault Client implemented in pure javascript for [HashiCorp Vault](https://github.com/hashicorp/vault).
|
|
7
10
|
It supports variety of Auth Backends and performs lease renewal for issued auth token.
|
|
@@ -11,6 +14,10 @@ It supports variety of Auth Backends and performs lease renewal for issued auth
|
|
|
11
14
|
npm install --save node-vault-client
|
|
12
15
|
```
|
|
13
16
|
|
|
17
|
+
### Requirements
|
|
18
|
+
|
|
19
|
+
Node.js >= 18 — the client uses the native `fetch` API.
|
|
20
|
+
|
|
14
21
|
## Example
|
|
15
22
|
|
|
16
23
|
```javascript
|
|
@@ -19,21 +26,102 @@ const VaultClient = require('node-vault-client');
|
|
|
19
26
|
const vaultClient = VaultClient.boot('main', {
|
|
20
27
|
api: { url: 'https://vault.example.com:8200/' },
|
|
21
28
|
auth: {
|
|
22
|
-
type: 'appRole', //
|
|
29
|
+
type: 'appRole', // one of: 'appRole' | 'token' | 'iam' | 'kubernetes'
|
|
23
30
|
config: { role_id: '637c065f-c644-5e12-d3d1-e9fa4363af61' }
|
|
24
31
|
},
|
|
25
32
|
});
|
|
26
33
|
|
|
27
|
-
vaultClient.read('secret/tst').then(
|
|
28
|
-
console.log(
|
|
34
|
+
vaultClient.read('secret/tst').then(lease => {
|
|
35
|
+
console.log(lease.getData()); // read() resolves to a Lease; use getData()/getValue(key)
|
|
29
36
|
}).catch(e => console.error(e));
|
|
30
37
|
```
|
|
31
38
|
|
|
32
39
|
## Supported Auth Backends
|
|
33
40
|
|
|
34
|
-
* [AWS IAM](https://
|
|
35
|
-
* [AppRole](https://
|
|
36
|
-
* [Token](https://
|
|
41
|
+
* [AWS IAM](https://developer.hashicorp.com/vault/docs/auth/aws)
|
|
42
|
+
* [AppRole](https://developer.hashicorp.com/vault/docs/auth/approle)
|
|
43
|
+
* [Token](https://developer.hashicorp.com/vault/docs/auth/token)
|
|
44
|
+
* [Kubernetes](https://developer.hashicorp.com/vault/docs/auth/kubernetes)
|
|
45
|
+
|
|
46
|
+
### AWS IAM auth
|
|
47
|
+
|
|
48
|
+
```javascript
|
|
49
|
+
const vaultClient = VaultClient.boot('main', {
|
|
50
|
+
api: { url: 'https://vault.example.com:8200/' },
|
|
51
|
+
auth: {
|
|
52
|
+
type: 'iam',
|
|
53
|
+
mount: 'aws', // Optional. Vault AWS auth mount point ("aws" by default)
|
|
54
|
+
config: {
|
|
55
|
+
role: 'my_iam_role',
|
|
56
|
+
iam_server_id_header_value: 'https://vault.example.com:8200/', // Optional. X-Vault-AWS-IAM-Server-ID header
|
|
57
|
+
namespace: 'some_namespace', // Optional. X-Vault-Namespace header
|
|
58
|
+
region: 'eu-central-1', // Optional. AWS STS region (see below)
|
|
59
|
+
credentials: { // Optional. Resolved from the AWS provider chain when omitted
|
|
60
|
+
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
|
|
61
|
+
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
#### `region`
|
|
69
|
+
|
|
70
|
+
By default the signed `GetCallerIdentity` request targets the global STS endpoint
|
|
71
|
+
`sts.amazonaws.com` and the SigV4 credential scope is bound to `us-east-1`. Set
|
|
72
|
+
`config.region` to sign against a regional STS endpoint instead — the request is then sent to
|
|
73
|
+
`sts.<region>.amazonaws.com` and the signature scope is bound to that region. This is required
|
|
74
|
+
when Vault's `sts_region` / `sts_endpoint` is configured for a non-`us-east-1` region (e.g.
|
|
75
|
+
`eu-central-1`); otherwise STS rejects the replayed request with
|
|
76
|
+
`SignatureDoesNotMatch — Credential should be scoped to a valid region`. Omitting `region`
|
|
77
|
+
preserves the previous (global-endpoint) behavior.
|
|
78
|
+
|
|
79
|
+
### AppRole auth
|
|
80
|
+
|
|
81
|
+
```javascript
|
|
82
|
+
const vaultClient = VaultClient.boot('main', {
|
|
83
|
+
api: { url: 'https://vault.example.com:8200/' },
|
|
84
|
+
auth: {
|
|
85
|
+
type: 'appRole',
|
|
86
|
+
mount: 'approle', // Optional. Vault AppRole auth mount point ("approle" by default)
|
|
87
|
+
config: {
|
|
88
|
+
role_id: '637c065f-c644-5e12-d3d1-e9fa4363af61', // Required. RoleID of the AppRole
|
|
89
|
+
secret_id: '...', // Optional. Required when bind_secret_id is enabled
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Token auth
|
|
96
|
+
|
|
97
|
+
```javascript
|
|
98
|
+
const vaultClient = VaultClient.boot('main', {
|
|
99
|
+
api: { url: 'https://vault.example.com:8200/' },
|
|
100
|
+
auth: {
|
|
101
|
+
type: 'token',
|
|
102
|
+
mount: 'token', // Optional. Vault token auth mount point ("token" by default)
|
|
103
|
+
config: {
|
|
104
|
+
token: 's.xxxxxxxxxxxxxxxxxxxxxxxx', // Required. Vault token
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Kubernetes auth
|
|
111
|
+
|
|
112
|
+
```javascript
|
|
113
|
+
const vaultClient = VaultClient.boot('main', {
|
|
114
|
+
api: { url: 'https://vault.example.com:8200/' },
|
|
115
|
+
auth: {
|
|
116
|
+
type: 'kubernetes',
|
|
117
|
+
mount: 'kubernetes', // Optional. Vault Kubernetes auth mount point ("kubernetes" by default)
|
|
118
|
+
config: {
|
|
119
|
+
role: 'my_k8s_role', // Required. Role configured in the Vault Kubernetes auth backend
|
|
120
|
+
tokenPath: '/var/run/secrets/kubernetes.io/serviceaccount/token', // Optional. Defaults to the in-pod service-account token path
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
```
|
|
37
125
|
|
|
38
126
|
## API
|
|
39
127
|
|
|
@@ -47,11 +135,13 @@ vaultClient.read('secret/tst').then(v => {
|
|
|
47
135
|
* [.fillNodeConfig()](#VaultClient+fillNodeConfig)
|
|
48
136
|
* [.read(path)](#VaultClient+read) ⇒ <code>Promise.<Lease></code>
|
|
49
137
|
* [.list(path)](#VaultClient+list) ⇒ <code>Promise.<Lease></code>
|
|
50
|
-
* [.write(path, data)](#VaultClient+write) ⇒ <code>Promise.<
|
|
138
|
+
* [.write(path, data)](#VaultClient+write) ⇒ <code>Promise.<Object></code>
|
|
139
|
+
* [.close()](#VaultClient+close)
|
|
51
140
|
* _static_
|
|
52
|
-
* [.boot(name, [options])](#VaultClient.boot) ⇒
|
|
53
|
-
* [.get(name)](#VaultClient.get) ⇒
|
|
141
|
+
* [.boot(name, [options])](#VaultClient.boot) ⇒ <code>VaultClient</code>
|
|
142
|
+
* [.get(name)](#VaultClient.get) ⇒ <code>VaultClient</code>
|
|
54
143
|
* [.clear([name])](#VaultClient.clear)
|
|
144
|
+
* [Lease](#Lease)
|
|
55
145
|
|
|
56
146
|
<a name="new_VaultClient_new"></a>
|
|
57
147
|
|
|
@@ -65,14 +155,52 @@ Client constructor function.
|
|
|
65
155
|
| options.api | <code>Object</code> | | |
|
|
66
156
|
| options.api.url | <code>String</code> | | the url of the vault server |
|
|
67
157
|
| [options.api.apiVersion] | <code>String</code> | `v1` | |
|
|
158
|
+
| [options.api.requestOptions] | <code>Object</code> | | extra options merged into every HTTP request (see [Custom transport](#custom-transport-proxy--self-signed-tls)) |
|
|
68
159
|
| options.auth | <code>Object</code> | | |
|
|
69
160
|
| options.auth.type | <code>String</code> | | |
|
|
161
|
+
| [options.auth.mount] | <code>String</code> | | Vault auth backend mount point; default varies per method (e.g. "aws" for iam, "approle", "token", "kubernetes") |
|
|
70
162
|
| options.auth.config | <code>Object</code> | | auth configuration variables |
|
|
163
|
+
| [options.auth.config.namespace] | <code>String</code> | | Optional. Vault namespace, sent as the `X-Vault-Namespace` header on all secret read/list/write requests. Applies to every auth type, not just IAM. |
|
|
71
164
|
| options.logger | <code>Object</code> | `false` | | Logger that supports "error", "info", "warn", "trace", "debug" methods. Uses `console` by default. Pass `false` to disable logging. |
|
|
72
165
|
|
|
73
|
-
|
|
166
|
+
##### Custom transport (proxy / self-signed TLS)
|
|
167
|
+
|
|
168
|
+
`options.api.requestOptions` is shallow-merged into every underlying `fetch()` call, so you
|
|
169
|
+
can route traffic through a proxy/SOCKS agent or trust a self-signed / internal-CA Vault.
|
|
170
|
+
Pass an [undici](https://undici.nodejs.org/) `dispatcher` (request semantics like `method`
|
|
171
|
+
and `body` always win; `headers` are merged with per-request headers taking precedence):
|
|
172
|
+
|
|
173
|
+
```javascript
|
|
174
|
+
const { Agent, ProxyAgent } = require('undici');
|
|
175
|
+
|
|
176
|
+
// Trust an internal/self-signed CA (preferred over disabling verification)
|
|
177
|
+
const vaultClient = VaultClient.boot('main', {
|
|
178
|
+
api: {
|
|
179
|
+
url: 'https://vault.internal:8200/',
|
|
180
|
+
requestOptions: {
|
|
181
|
+
dispatcher: new Agent({ connect: { ca: require('fs').readFileSync('/etc/ssl/internal-ca.pem') } }),
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
auth: { type: 'token', config: { token: '...' } },
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
// Route through an HTTP proxy / SOCKS agent
|
|
188
|
+
const proxied = VaultClient.boot('proxied', {
|
|
189
|
+
api: { url: 'https://vault.example.com:8200/', requestOptions: { dispatcher: new ProxyAgent('http://proxy:8080') } },
|
|
190
|
+
auth: { type: 'token', config: { token: '...' } },
|
|
191
|
+
});
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
For the self-signed-CA case you can also use the process-wide `NODE_EXTRA_CA_CERTS=/path/ca.pem`
|
|
195
|
+
env var with no code change. Only disable verification
|
|
196
|
+
(`new Agent({ connect: { rejectUnauthorized: false } })`) in throwaway/dev setups — it removes
|
|
197
|
+
MITM protection.
|
|
198
|
+
|
|
199
|
+
#### vaultClient.fillNodeConfig() ⇒ <code>Promise</code>
|
|
74
200
|
Populates Vault's values to NPM "config" module
|
|
75
201
|
|
|
202
|
+
Resolves once the npm `config` module has been populated from Vault.
|
|
203
|
+
|
|
76
204
|
**Kind**: instance method of [<code>VaultClient</code>](#VaultClient)
|
|
77
205
|
<a name="VaultClient+read"></a>
|
|
78
206
|
|
|
@@ -98,9 +226,12 @@ Retrieves secrets list
|
|
|
98
226
|
|
|
99
227
|
<a name="VaultClient+write"></a>
|
|
100
228
|
|
|
101
|
-
#### vaultClient.write(path, data) ⇒ <code>Promise.<
|
|
229
|
+
#### vaultClient.write(path, data) ⇒ <code>Promise.<Object></code>
|
|
102
230
|
Writes data to Vault
|
|
103
231
|
|
|
232
|
+
Resolves to the raw parsed Vault response body, which may be empty/undefined for
|
|
233
|
+
`204 No Content` responses.
|
|
234
|
+
|
|
104
235
|
**Kind**: instance method of [<code>VaultClient</code>](#VaultClient)
|
|
105
236
|
|
|
106
237
|
| Param | Type | Description |
|
|
@@ -108,16 +239,48 @@ Writes data to Vault
|
|
|
108
239
|
| path | | path used to write data |
|
|
109
240
|
| data | <code>object</code> | data to write |
|
|
110
241
|
|
|
242
|
+
<a name="VaultClient+close"></a>
|
|
243
|
+
|
|
244
|
+
#### vaultClient.close()
|
|
245
|
+
Release resources held by this client.
|
|
246
|
+
|
|
247
|
+
This client performs lease renewal for renewable auth tokens by arming a background timer.
|
|
248
|
+
That timer keeps the Node.js event loop alive, so a short-lived script (e.g. a one-off
|
|
249
|
+
`read`) never exits on its own. Call `close()` once you are done with the client to cancel
|
|
250
|
+
the timer and let the process exit. It is null-safe and safe to call multiple times. The
|
|
251
|
+
client may still be used afterwards — the next operation that fetches a renewable token
|
|
252
|
+
will arm a new refresh timer.
|
|
253
|
+
|
|
254
|
+
```javascript
|
|
255
|
+
const vaultClient = VaultClient.boot('main', { /* ... */ });
|
|
256
|
+
const secret = await vaultClient.read('secret/tst');
|
|
257
|
+
console.log(secret);
|
|
258
|
+
vaultClient.close(); // process can now exit
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
**Kind**: instance method of [<code>VaultClient</code>](#VaultClient)
|
|
262
|
+
|
|
263
|
+
<a name="Lease"></a>
|
|
264
|
+
|
|
265
|
+
### Lease
|
|
266
|
+
|
|
267
|
+
The object returned by `read()` and `list()` (they resolve to `Promise<Lease>`). Use its
|
|
268
|
+
accessors to extract the secret data:
|
|
269
|
+
|
|
270
|
+
* `getValue(key)` ⇒ <code>String</code> — value for a single key. Throws `Requested key does not exist` when the key is absent.
|
|
271
|
+
* `getData()` ⇒ <code>Object</code> — a deep-cloned copy of the whole secret data object.
|
|
272
|
+
* `isRenewable()` ⇒ <code>boolean</code> — whether the underlying lease is renewable.
|
|
273
|
+
|
|
111
274
|
<a name="VaultClient.boot"></a>
|
|
112
275
|
|
|
113
|
-
#### VaultClient.boot(name, [options]) ⇒
|
|
276
|
+
#### VaultClient.boot(name, [options]) ⇒ <code>VaultClient</code>
|
|
114
277
|
Boot an instance of Vault
|
|
115
278
|
|
|
116
279
|
The instance will be stored in a local hash. Calling Vault.boot multiple
|
|
117
280
|
times with the same name will return the same instance.
|
|
118
281
|
|
|
119
282
|
**Kind**: static method of [<code>VaultClient</code>](#VaultClient)
|
|
120
|
-
**Returns**:
|
|
283
|
+
**Returns**: <code>VaultClient</code>
|
|
121
284
|
|
|
122
285
|
| Param | Type | Description |
|
|
123
286
|
| --- | --- | --- |
|
|
@@ -126,14 +289,14 @@ times with the same name will return the same instance.
|
|
|
126
289
|
|
|
127
290
|
<a name="VaultClient.get"></a>
|
|
128
291
|
|
|
129
|
-
#### VaultClient.get(name) ⇒
|
|
292
|
+
#### VaultClient.get(name) ⇒ <code>VaultClient</code>
|
|
130
293
|
Get an instance of Vault
|
|
131
294
|
|
|
132
295
|
The instance will be stored in a local hash. Calling Vault.pop multiple
|
|
133
296
|
times with the same name will return the same instance.
|
|
134
297
|
|
|
135
298
|
**Kind**: static method of [<code>VaultClient</code>](#VaultClient)
|
|
136
|
-
**Returns**:
|
|
299
|
+
**Returns**: <code>VaultClient</code>
|
|
137
300
|
|
|
138
301
|
| Param | Type | Description |
|
|
139
302
|
| --- | --- | --- |
|
|
@@ -151,3 +314,24 @@ If no name passed all named instances will be cleared.
|
|
|
151
314
|
| Param | Type | Description |
|
|
152
315
|
| --- | --- | --- |
|
|
153
316
|
| [name] | <code>String</code> | Vault instance name, all instances will be cleared if no name were passed |
|
|
317
|
+
|
|
318
|
+
## Contributing
|
|
319
|
+
|
|
320
|
+
Contributions are welcome! Please read the [contributing guide](CONTRIBUTING.md) to get started,
|
|
321
|
+
and note that this project requires a [DCO sign-off](CONTRIBUTING.md#dco-sign-off) on every commit.
|
|
322
|
+
|
|
323
|
+
## Getting help
|
|
324
|
+
|
|
325
|
+
Not sure where to start? See [SUPPORT.md](SUPPORT.md).
|
|
326
|
+
|
|
327
|
+
## Code of Conduct
|
|
328
|
+
|
|
329
|
+
This project adheres to the [Contributor Covenant Code of Conduct](CODE_OF_CONDUCT.md).
|
|
330
|
+
|
|
331
|
+
## Security
|
|
332
|
+
|
|
333
|
+
To report a security vulnerability, please follow our [Security Policy](SECURITY.md).
|
|
334
|
+
|
|
335
|
+
## License
|
|
336
|
+
|
|
337
|
+
Licensed under the [Apache License 2.0](LICENSE.txt).
|
package/package.json
CHANGED
|
@@ -1,21 +1,35 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-vault-client",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "A Vault Client implemented in pure javascript for HashiCorp Vault. It supports variety of Auth Backends and performs lease renewal for issued auth token.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"url": "git+https://github.com/namecheap/node-vault-client.git"
|
|
7
7
|
},
|
|
8
8
|
"engines": {
|
|
9
|
-
"node": ">=
|
|
9
|
+
"node": ">=18.0.0"
|
|
10
10
|
},
|
|
11
11
|
"main": "src/VaultClient.js",
|
|
12
12
|
"files": [
|
|
13
13
|
"src"
|
|
14
14
|
],
|
|
15
15
|
"scripts": {
|
|
16
|
-
"test": "mocha test/**/*.test.
|
|
16
|
+
"test": "mocha --exit \"test/**/*.test.mjs\"",
|
|
17
|
+
"test:unit": "mocha \"test/*.test.mjs\"",
|
|
18
|
+
"coverage": "c8 npm run test:unit",
|
|
19
|
+
"lint": "eslint src/",
|
|
17
20
|
"version": "git add -A ."
|
|
18
21
|
},
|
|
22
|
+
"c8": {
|
|
23
|
+
"include": [
|
|
24
|
+
"src/**/*.js"
|
|
25
|
+
],
|
|
26
|
+
"reporter": [
|
|
27
|
+
"text",
|
|
28
|
+
"html",
|
|
29
|
+
"lcov"
|
|
30
|
+
],
|
|
31
|
+
"all": true
|
|
32
|
+
},
|
|
19
33
|
"author": "Namecheap <opensource@namecheap.com>",
|
|
20
34
|
"license": "Apache-2.0",
|
|
21
35
|
"dependencies": {
|
|
@@ -26,19 +40,25 @@
|
|
|
26
40
|
"lodash": "^4.17.15",
|
|
27
41
|
"long-timeout": "^0.1.1",
|
|
28
42
|
"pretty-ms": "^2.1.0",
|
|
29
|
-
"request": "^2.88.0",
|
|
30
|
-
"request-promise": "^4.2.4",
|
|
31
43
|
"url-join": "^2.0.5"
|
|
32
44
|
},
|
|
33
45
|
"peerDependencies": {
|
|
34
46
|
"config": ">=1 <4"
|
|
35
47
|
},
|
|
48
|
+
"overrides": {
|
|
49
|
+
"serialize-javascript": "^7.0.5",
|
|
50
|
+
"glob": "^13.0.0",
|
|
51
|
+
"diff": "^8.0.3"
|
|
52
|
+
},
|
|
36
53
|
"devDependencies": {
|
|
37
|
-
"
|
|
38
|
-
"
|
|
54
|
+
"@eslint/js": "^9.0.0",
|
|
55
|
+
"c8": "^11.0.0",
|
|
56
|
+
"chai": "^6.0.0",
|
|
39
57
|
"deep-freeze": "^0.0.1",
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
58
|
+
"eslint": "^9.0.0",
|
|
59
|
+
"globals": "^16.0.0",
|
|
60
|
+
"mocha": "^11.7.6",
|
|
61
|
+
"sinon": "^22.0.0",
|
|
62
|
+
"sinon-chai": "^4.0.0"
|
|
43
63
|
}
|
|
44
64
|
}
|
package/src/VaultApiClient.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const rp = require('request-promise');
|
|
4
3
|
const urljoin = require('url-join');
|
|
5
4
|
const _ = require('lodash');
|
|
6
5
|
|
|
@@ -10,13 +9,25 @@ class VaultApiClient {
|
|
|
10
9
|
* @param {Object} config
|
|
11
10
|
* @param {String} config.url - the url of the vault server
|
|
12
11
|
* @param {String} [config.apiVersion='v1']
|
|
12
|
+
* @param {Object} [config.requestOptions] - extra options shallow-merged into every
|
|
13
|
+
* `fetch()` call. Use it to inject an undici `dispatcher` for a proxy/SOCKS agent
|
|
14
|
+
* or for custom TLS trust (self-signed / internal CA). Request-specific fields
|
|
15
|
+
* (`method`, `body`) always take precedence; `headers` are merged with the
|
|
16
|
+
* per-request headers winning. Stored by reference (not deep-cloned) so live
|
|
17
|
+
* objects such as a Dispatcher keep their prototype and remain usable.
|
|
13
18
|
* @param {Object} logger
|
|
14
19
|
*/
|
|
15
20
|
constructor(config, logger) {
|
|
16
|
-
|
|
21
|
+
const requestOptions = config && config.requestOptions;
|
|
22
|
+
|
|
23
|
+
this.__config = _.defaultsDeep(_.cloneDeep(_.omit(config, ['requestOptions'])), {
|
|
17
24
|
apiVersion: 'v1',
|
|
18
25
|
});
|
|
19
26
|
|
|
27
|
+
if (requestOptions !== undefined) {
|
|
28
|
+
this.__config.requestOptions = requestOptions;
|
|
29
|
+
}
|
|
30
|
+
|
|
20
31
|
this._logger = logger;
|
|
21
32
|
}
|
|
22
33
|
|
|
@@ -24,31 +35,59 @@ class VaultApiClient {
|
|
|
24
35
|
data = data === undefined ? null : data;
|
|
25
36
|
headers = headers === undefined ? {} : headers;
|
|
26
37
|
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
38
|
+
const uri = urljoin(this.__config.url, this.__config.apiVersion, path);
|
|
39
|
+
|
|
40
|
+
const requestOptions = this.__config.requestOptions || {};
|
|
41
|
+
|
|
42
|
+
const options = Object.assign(
|
|
43
|
+
{ redirect: 'follow' },
|
|
44
|
+
requestOptions,
|
|
45
|
+
{
|
|
46
|
+
method: method,
|
|
47
|
+
headers: Object.assign(
|
|
48
|
+
{ Accept: 'application/json' },
|
|
49
|
+
requestOptions.headers,
|
|
50
|
+
headers
|
|
51
|
+
),
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
if (data !== null) {
|
|
55
|
+
options.body = JSON.stringify(data);
|
|
56
|
+
options.headers['Content-Type'] = 'application/json';
|
|
57
|
+
}
|
|
36
58
|
|
|
37
59
|
this._logger.debug(
|
|
38
60
|
'making request: %s %s',
|
|
39
|
-
|
|
40
|
-
|
|
61
|
+
method,
|
|
62
|
+
uri
|
|
41
63
|
);
|
|
42
64
|
|
|
43
|
-
return
|
|
44
|
-
.then((
|
|
65
|
+
return fetch(uri, options).then((response) => {
|
|
66
|
+
return response.text().then((text) => {
|
|
67
|
+
let body;
|
|
68
|
+
if (text) {
|
|
69
|
+
try {
|
|
70
|
+
body = JSON.parse(text);
|
|
71
|
+
} catch {
|
|
72
|
+
body = text;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (!response.ok) {
|
|
77
|
+
const error = new Error(`${response.status} - ${text}`);
|
|
78
|
+
error.statusCode = response.status;
|
|
79
|
+
error.error = body;
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
|
|
45
83
|
this._logger.debug('%s %s response body:\n%s',
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
JSON.stringify(
|
|
84
|
+
method,
|
|
85
|
+
uri,
|
|
86
|
+
JSON.stringify(body, null, ' ')
|
|
49
87
|
);
|
|
50
|
-
return
|
|
88
|
+
return body;
|
|
51
89
|
});
|
|
90
|
+
});
|
|
52
91
|
}
|
|
53
92
|
}
|
|
54
93
|
|
package/src/VaultClient.js
CHANGED
|
@@ -20,6 +20,9 @@ class VaultClient {
|
|
|
20
20
|
* @param {Object} options.api
|
|
21
21
|
* @param {String} options.api.url - the url of the vault server
|
|
22
22
|
* @param {String} [options.api.apiVersion='v1']
|
|
23
|
+
* @param {Object} [options.api.requestOptions] - extra options merged into every HTTP
|
|
24
|
+
* request (e.g. an undici `dispatcher` for a proxy/SOCKS agent or custom TLS/CA trust).
|
|
25
|
+
* See {@link VaultApiClient#constructor}.
|
|
23
26
|
* @param {Object} options.auth
|
|
24
27
|
* @param {String} options.auth.type
|
|
25
28
|
* @param {Object} options.auth.config - auth configuration variables
|
|
@@ -52,8 +55,8 @@ class VaultClient {
|
|
|
52
55
|
* times with the same name will return the same instance.
|
|
53
56
|
*
|
|
54
57
|
* @param {String} name - Vault instance name
|
|
55
|
-
* @param {Object} [options] - options for {@link
|
|
56
|
-
* @return
|
|
58
|
+
* @param {Object} [options] - options for {@link VaultClient#constructor}.
|
|
59
|
+
* @return {VaultClient}
|
|
57
60
|
*/
|
|
58
61
|
static boot(name, options) {
|
|
59
62
|
if (options === undefined) {
|
|
@@ -74,7 +77,7 @@ class VaultClient {
|
|
|
74
77
|
* times with the same name will return the same instance.
|
|
75
78
|
*
|
|
76
79
|
* @param {String} name - Vault instance name
|
|
77
|
-
* @return
|
|
80
|
+
* @return {VaultClient}
|
|
78
81
|
*/
|
|
79
82
|
static get(name) {
|
|
80
83
|
let instance = vaultInstances[name];
|
|
@@ -95,16 +98,38 @@ class VaultClient {
|
|
|
95
98
|
*/
|
|
96
99
|
static clear(name) {
|
|
97
100
|
if (typeof name === 'string') {
|
|
98
|
-
|
|
101
|
+
const instance = vaultInstances[name];
|
|
102
|
+
if (instance !== undefined) {
|
|
103
|
+
instance.close();
|
|
104
|
+
delete vaultInstances[name];
|
|
105
|
+
}
|
|
99
106
|
} else {
|
|
100
107
|
for (let k in vaultInstances) {
|
|
101
|
-
if (
|
|
108
|
+
if (Object.hasOwn(vaultInstances, k)) {
|
|
109
|
+
vaultInstances[k].close();
|
|
102
110
|
delete vaultInstances[k];
|
|
103
111
|
}
|
|
104
112
|
}
|
|
105
113
|
}
|
|
106
114
|
}
|
|
107
115
|
|
|
116
|
+
/**
|
|
117
|
+
* Release resources held by this client.
|
|
118
|
+
*
|
|
119
|
+
* Cancels the background auth-token refresh timer that keeps the Node.js event loop
|
|
120
|
+
* alive for renewable tokens. Call this once you are done with the client so a
|
|
121
|
+
* short-lived script can exit on its own. Safe to call when no timer is armed and
|
|
122
|
+
* safe to call multiple times. After calling `close()` the client may still be used;
|
|
123
|
+
* the next operation that fetches a renewable token will arm a new refresh timer.
|
|
124
|
+
*
|
|
125
|
+
* @returns {void}
|
|
126
|
+
*/
|
|
127
|
+
close() {
|
|
128
|
+
if (this.__auth && typeof this.__auth.cancelTokenRefresh === 'function') {
|
|
129
|
+
this.__auth.cancelTokenRefresh();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
108
133
|
/**
|
|
109
134
|
* @protected
|
|
110
135
|
*
|
|
@@ -215,9 +240,9 @@ class VaultClient {
|
|
|
215
240
|
/**
|
|
216
241
|
* Writes data to Vault
|
|
217
242
|
*
|
|
218
|
-
* @param path - path used to write data
|
|
243
|
+
* @param {string} path - path used to write data
|
|
219
244
|
* @param {object} data - data to write
|
|
220
|
-
* @returns {Promise<
|
|
245
|
+
* @returns {Promise<Object>} the parsed Vault response body
|
|
221
246
|
*/
|
|
222
247
|
write(path, data) {
|
|
223
248
|
this.__log.debug('write secret %s', path);
|
package/src/VaultNodeConfig.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const path = require('path');
|
|
4
|
-
const fs = require('fs');
|
|
5
4
|
const Bluebird = require('bluebird');
|
|
6
5
|
const _ = require('lodash');
|
|
7
6
|
const assignDeep = require('assign-deep');
|
|
@@ -15,7 +14,7 @@ class VaultNodeConfig {
|
|
|
15
14
|
|
|
16
15
|
try {
|
|
17
16
|
require.resolve('config');
|
|
18
|
-
} catch
|
|
17
|
+
} catch {
|
|
19
18
|
throw new errors.VaultError(`NPM package "config" isn't installed`);
|
|
20
19
|
}
|
|
21
20
|
|
|
@@ -73,7 +72,7 @@ class VaultNodeConfig {
|
|
|
73
72
|
let fileContent;
|
|
74
73
|
try {
|
|
75
74
|
fileContent = require(fullFilename);
|
|
76
|
-
} catch
|
|
75
|
+
} catch {
|
|
77
76
|
throw new errors.VaultError('Config file ' + fullFilename + ' cannot be read');
|
|
78
77
|
}
|
|
79
78
|
|
|
@@ -86,7 +85,7 @@ class VaultNodeConfig {
|
|
|
86
85
|
|
|
87
86
|
__traverse(o, func) {
|
|
88
87
|
for (let i in o) {
|
|
89
|
-
if (!
|
|
88
|
+
if (!Object.hasOwn(o, i)) {
|
|
90
89
|
continue;
|
|
91
90
|
}
|
|
92
91
|
|
package/src/auth/AuthToken.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const _ = require('lodash');
|
|
4
3
|
|
|
5
4
|
class AuthToken {
|
|
6
5
|
|
|
@@ -35,25 +34,73 @@ class AuthToken {
|
|
|
35
34
|
static fromResponse(response) {
|
|
36
35
|
const data = response.data;
|
|
37
36
|
|
|
38
|
-
let expiresAt = null;
|
|
39
|
-
if (data.ttl !== 0) {
|
|
40
|
-
const creationTime = parseInt(data.last_renewal_time !== undefined ? data.last_renewal_time : data.creation_time, 10);
|
|
41
|
-
const networkLatency = 60;
|
|
42
|
-
const ttl = parseInt(data.ttl > networkLatency ? data.ttl - networkLatency : data.ttl);
|
|
43
|
-
expiresAt = creationTime + ttl;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
37
|
return new AuthToken(
|
|
47
38
|
data.id,
|
|
48
39
|
data.accessor,
|
|
49
40
|
data.creation_time,
|
|
50
|
-
|
|
41
|
+
AuthToken.__resolveExpiresAt(data),
|
|
51
42
|
data.explicit_max_ttl,
|
|
52
43
|
data.num_uses,
|
|
53
44
|
data.renewable !== undefined ? data.renewable : false
|
|
54
45
|
);
|
|
55
46
|
}
|
|
56
47
|
|
|
48
|
+
/**
|
|
49
|
+
* Resolve the UNIX timestamp (seconds) at which the client should treat the token
|
|
50
|
+
* as expired, shifted earlier by a network-latency safety margin so renewal happens
|
|
51
|
+
* before the real expiry.
|
|
52
|
+
*
|
|
53
|
+
* Prefers Vault's authoritative `expire_time` (RFC3339), which is the documented
|
|
54
|
+
* absolute expiry. Falls back to `(last_renewal_time || creation_time) + ttl` for
|
|
55
|
+
* responses that don't carry `expire_time` — note `ttl` is the *remaining* lifetime,
|
|
56
|
+
* so that sum is only accurate when the lookup happens right after issuance/renewal.
|
|
57
|
+
*
|
|
58
|
+
* @private
|
|
59
|
+
* @param {Object} data - the `data` object of a token lookup response
|
|
60
|
+
* @returns {int|null} null when the token never expires (ttl === 0)
|
|
61
|
+
*/
|
|
62
|
+
static __resolveExpiresAt(data) {
|
|
63
|
+
if (data.ttl === 0) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const networkLatency = 60;
|
|
68
|
+
const margin = data.ttl > networkLatency ? networkLatency : 0;
|
|
69
|
+
|
|
70
|
+
const expireTime = AuthToken.__parseRfc3339Seconds(data.expire_time);
|
|
71
|
+
if (expireTime !== null) {
|
|
72
|
+
return expireTime - margin;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Fallback for responses without a usable `expire_time`.
|
|
76
|
+
const creationTime = parseInt(data.last_renewal_time !== undefined ? data.last_renewal_time : data.creation_time, 10);
|
|
77
|
+
const ttl = data.ttl > networkLatency ? data.ttl - networkLatency : data.ttl;
|
|
78
|
+
return creationTime + parseInt(ttl, 10);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Parse an RFC3339 timestamp (as returned by Vault, up to nanosecond precision with
|
|
83
|
+
* a timezone offset) into whole UNIX seconds. Returns null for missing, empty,
|
|
84
|
+
* unparseable, or non-positive (e.g. Vault's "0001-01-01T00:00:00Z" zero value) input.
|
|
85
|
+
*
|
|
86
|
+
* @private
|
|
87
|
+
* @param {String} value
|
|
88
|
+
* @returns {int|null}
|
|
89
|
+
*/
|
|
90
|
+
static __parseRfc3339Seconds(value) {
|
|
91
|
+
if (typeof value !== 'string' || value === '') {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const ms = Date.parse(value);
|
|
96
|
+
if (isNaN(ms)) {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const seconds = Math.floor(ms / 1000);
|
|
101
|
+
return seconds > 0 ? seconds : null;
|
|
102
|
+
}
|
|
103
|
+
|
|
57
104
|
/**
|
|
58
105
|
* @returns {string}
|
|
59
106
|
*/
|
|
@@ -6,9 +6,11 @@ class VaultAppRoleAuth extends VaultBaseAuth {
|
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* @param {VaultApiClient} apiClient - see {@link VaultBaseAuth#constructor}
|
|
9
|
+
* @param {Object} logger
|
|
9
10
|
* @param {Object} config
|
|
10
11
|
* @param {String} config.role_id - RoleID of the AppRole.
|
|
11
12
|
* @param {String} [config.secret_id] - required when bind_secret_id is enabled SecretID belonging to AppRole.
|
|
13
|
+
* @param {String} [config.namespace] - Optional. Vault namespace, sent as the X-Vault-Namespace header.
|
|
12
14
|
* @param {String} mount - Vault's mount point ("approle" by default)
|
|
13
15
|
*/
|
|
14
16
|
constructor(apiClient, logger, config, mount) {
|
|
@@ -32,11 +32,15 @@ class VaultBaseAuth {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
getAuthToken() {
|
|
35
|
-
|
|
36
|
-
if (this.__authToken !== null && this.__authToken.isExpired() && !this._reauthenticationAllowed()) {
|
|
37
|
-
throw new errors.AuthTokenExpiredError('Auth token has expired & cannot be refreshed since auth method doesn\'t support this.');
|
|
38
|
-
}
|
|
35
|
+
const tokenExpired = this.__authToken instanceof AuthToken && this.__authToken.isExpired();
|
|
39
36
|
|
|
37
|
+
if (tokenExpired && !this._reauthenticationAllowed()) {
|
|
38
|
+
return Promise.reject(new errors.AuthTokenExpiredError(
|
|
39
|
+
'Auth token has expired & cannot be refreshed since auth method doesn\'t support this.'
|
|
40
|
+
));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (this.__authToken === null || tokenExpired) {
|
|
40
44
|
this._log.info('getting auth token (mount=%s)', this._mount);
|
|
41
45
|
|
|
42
46
|
const tokenPromise = this._authenticate().then(authToken => {
|
|
@@ -64,6 +68,24 @@ class VaultBaseAuth {
|
|
|
64
68
|
return Promise.resolve(this.__authToken);
|
|
65
69
|
}
|
|
66
70
|
|
|
71
|
+
/**
|
|
72
|
+
* Cancel any pending token-refresh timer.
|
|
73
|
+
*
|
|
74
|
+
* When a renewable token is fetched the client arms a `long-timeout` timer to renew it
|
|
75
|
+
* before it expires. That timer keeps the Node.js event loop alive, so a short-lived
|
|
76
|
+
* script never exits on its own. Call this (or {@link VaultClient#close}) once you are
|
|
77
|
+
* done with the client to release the event loop. Safe to call when no timer is armed
|
|
78
|
+
* and safe to call multiple times.
|
|
79
|
+
*
|
|
80
|
+
* @returns {void}
|
|
81
|
+
*/
|
|
82
|
+
cancelTokenRefresh() {
|
|
83
|
+
if (this.__refreshTimeout !== null) {
|
|
84
|
+
lt.clearTimeout(this.__refreshTimeout);
|
|
85
|
+
this.__refreshTimeout = null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
67
89
|
/**
|
|
68
90
|
* @protected
|
|
69
91
|
* @returns {Promise<AuthToken>}
|
package/src/auth/VaultIAMAuth.js
CHANGED
|
@@ -29,6 +29,7 @@ const errors = require('../errors');
|
|
|
29
29
|
* role: 'my_iam_role',
|
|
30
30
|
* iam_server_id_header_value: VAULT_ADDR, // Optional
|
|
31
31
|
* namespace: 'some_namespace', // Optional
|
|
32
|
+
* region: 'eu-central-1', // Optional. AWS STS region.
|
|
32
33
|
* credentials: { // Optional
|
|
33
34
|
* accessKeyId: AWS_ACCESS_KEY,
|
|
34
35
|
* secretAccessKey: AWS_SECRET_KEY,
|
|
@@ -47,8 +48,14 @@ class VaultIAMAuth extends VaultBaseAuth {
|
|
|
47
48
|
*
|
|
48
49
|
* @typedef {Object} VaultIAMAuthConfig
|
|
49
50
|
* @property {String} role - Role name of the auth/{mount}/role/{name} backend.
|
|
50
|
-
* @property
|
|
51
|
+
* @property {AWSCredentials} [credentials] - Optional. AWS Credentials
|
|
52
|
+
* @property {String} [namespace] - Optional. Vault namespace, sent as the X-Vault-Namespace header.
|
|
51
53
|
* @property {String} [iam_server_id_header_value] - Optional. Header's value X-Vault-AWS-IAM-Server-ID.
|
|
54
|
+
* @property {String} [region] - Optional. AWS region used to sign the STS GetCallerIdentity
|
|
55
|
+
* request. When set, the request is signed against the regional STS endpoint
|
|
56
|
+
* (`sts.<region>.amazonaws.com`) and the SigV4 credential scope is bound to that region.
|
|
57
|
+
* When omitted, the global endpoint (`sts.amazonaws.com`, scope `us-east-1`) is used,
|
|
58
|
+
* preserving the previous default behavior.
|
|
52
59
|
*
|
|
53
60
|
* @param {VaultApiClient} api - see {@link VaultBaseAuth#constructor}
|
|
54
61
|
* @param {Object} logger
|
|
@@ -61,6 +68,7 @@ class VaultIAMAuth extends VaultBaseAuth {
|
|
|
61
68
|
this.__role = config.role;
|
|
62
69
|
this.__iam_server_id_header_value = config.iam_server_id_header_value;
|
|
63
70
|
this.__namespace = config.namespace;
|
|
71
|
+
this.__region = config.region;
|
|
64
72
|
|
|
65
73
|
|
|
66
74
|
const { credentials } = config;
|
|
@@ -130,7 +138,11 @@ class VaultIAMAuth extends VaultBaseAuth {
|
|
|
130
138
|
JSON.stringify(this.__headersLikeGolangStyle(stsRequest.headers))
|
|
131
139
|
),
|
|
132
140
|
iam_request_body: this.__base64encode(stsRequest.body),
|
|
133
|
-
|
|
141
|
+
// `aws4` populates `hostname` for the default (global) endpoint, but
|
|
142
|
+
// `host` when an explicit host is supplied (regional endpoint). Use
|
|
143
|
+
// whichever is present so the URL sent to Vault matches the signed
|
|
144
|
+
// Host header.
|
|
145
|
+
iam_request_url: this.__base64encode(`https://${stsRequest.host || stsRequest.hostname}${stsRequest.path}`),
|
|
134
146
|
role: this.__role
|
|
135
147
|
}
|
|
136
148
|
}
|
|
@@ -142,14 +154,27 @@ class VaultIAMAuth extends VaultBaseAuth {
|
|
|
142
154
|
* @private
|
|
143
155
|
*/
|
|
144
156
|
__getStsRequest(credentials) {
|
|
145
|
-
|
|
157
|
+
const request = {
|
|
146
158
|
service: 'sts',
|
|
147
159
|
method: 'POST',
|
|
148
160
|
body: 'Action=GetCallerIdentity&Version=2011-06-15',
|
|
149
161
|
headers: this.__iam_server_id_header_value ? {
|
|
150
162
|
'X-Vault-AWS-IAM-Server-ID': this.__iam_server_id_header_value,
|
|
151
163
|
} : {}
|
|
152
|
-
}
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
// When a region is configured, sign the request against the regional STS
|
|
167
|
+
// endpoint. Both the SigV4 credential scope (via `region`) and the signed
|
|
168
|
+
// Host header / request URL (via `host`) must reference the same region,
|
|
169
|
+
// otherwise Vault's STS replay fails with `SignatureDoesNotMatch`.
|
|
170
|
+
// When omitted, `aws4` defaults to the global endpoint (`sts.amazonaws.com`,
|
|
171
|
+
// scope `us-east-1`), preserving the previous behavior.
|
|
172
|
+
if (this.__region) {
|
|
173
|
+
request.region = this.__region;
|
|
174
|
+
request.host = `sts.${this.__region}.amazonaws.com`;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return aws4.sign(request, credentials);
|
|
153
178
|
}
|
|
154
179
|
|
|
155
180
|
/**
|
|
@@ -157,7 +182,7 @@ class VaultIAMAuth extends VaultBaseAuth {
|
|
|
157
182
|
* @private
|
|
158
183
|
*/
|
|
159
184
|
__base64encode(string) {
|
|
160
|
-
return
|
|
185
|
+
return Buffer.from(string).toString('base64')
|
|
161
186
|
}
|
|
162
187
|
|
|
163
188
|
/**
|
|
@@ -4,6 +4,7 @@ const VaultBaseAuth = require('./VaultBaseAuth');
|
|
|
4
4
|
class VaultKubernetesAuth extends VaultBaseAuth {
|
|
5
5
|
/**
|
|
6
6
|
* @param {VaultApiClient} apiClient - see {@link VaultBaseAuth#constructor}
|
|
7
|
+
* @param {Object} logger
|
|
7
8
|
* @param {Object} config
|
|
8
9
|
* @param {String} config.role - Role configured in Vault Kubernetes Auth backend under which we want to issue Vault token.
|
|
9
10
|
* @param {String} [config.tokenPath] - Path to the Kube JWT token. If omitted - default will be used.
|
|
@@ -6,13 +6,14 @@ const errors = require('../errors');
|
|
|
6
6
|
class VaultTokenAuth extends VaultBaseAuth {
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* @param {
|
|
9
|
+
* @param {VaultApiClient} apiClient - see {@link VaultBaseAuth#constructor}
|
|
10
|
+
* @param {Object} logger
|
|
10
11
|
* @param {Object} config
|
|
11
12
|
* @param {String} config.token
|
|
12
|
-
* @param {String} mount - Vault's
|
|
13
|
+
* @param {String} mount - Vault's mount point ("token" by default)
|
|
13
14
|
*/
|
|
14
|
-
constructor(
|
|
15
|
-
super(
|
|
15
|
+
constructor(apiClient, logger, config, mount) {
|
|
16
|
+
super(apiClient, logger, mount || 'token');
|
|
16
17
|
|
|
17
18
|
if (!config.token) {
|
|
18
19
|
throw new errors.InvalidArgumentsError('Auth token should be provided for VaultTokenAuth');
|
package/src/errors.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
class VaultError extends Error {
|
|
4
|
-
constructor(message
|
|
4
|
+
constructor(message) {
|
|
5
5
|
super(message);
|
|
6
6
|
this.name = this.constructor.name;
|
|
7
7
|
this.message = message;
|
|
8
8
|
|
|
9
|
-
Error.captureStackTrace(this, this.constructor
|
|
9
|
+
Error.captureStackTrace(this, this.constructor);
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
class InvalidArgumentsError extends VaultError {}
|