node-vault-client 1.0.1 → 1.0.3
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/LICENSE.txt +200 -200
- package/README.md +264 -154
- package/package.json +44 -44
- package/src/Lease.js +70 -57
- package/src/MountResolver.js +167 -0
- package/src/VaultApiClient.js +55 -55
- package/src/VaultClient.js +366 -263
- package/src/VaultNodeConfig.js +105 -105
- package/src/auth/AuthToken.js +94 -94
- package/src/auth/VaultAppRoleAuth.js +47 -40
- package/src/auth/VaultBaseAuth.js +140 -140
- package/src/auth/VaultIAMAuth.js +187 -187
- package/src/auth/VaultKubernetesAuth.js +48 -48
- package/src/auth/VaultTokenAuth.js +34 -34
- package/src/errors.js +21 -21
- package/src/kvTransform.js +90 -0
|
@@ -1,48 +1,48 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const VaultBaseAuth = require('./VaultBaseAuth');
|
|
3
|
-
|
|
4
|
-
class VaultKubernetesAuth extends VaultBaseAuth {
|
|
5
|
-
/**
|
|
6
|
-
* @param {VaultApiClient} apiClient - see {@link VaultBaseAuth#constructor}
|
|
7
|
-
* @param {Object} config
|
|
8
|
-
* @param {String} config.role - Role configured in Vault Kubernetes Auth backend under which we want to issue Vault token.
|
|
9
|
-
* @param {String} [config.tokenPath] - Path to the Kube JWT token. If omitted - default will be used.
|
|
10
|
-
* @param {String} mount - Vault's mount point ("kubernetes" by default)
|
|
11
|
-
*/
|
|
12
|
-
constructor(apiClient, logger, config, mount) {
|
|
13
|
-
super(apiClient, logger, mount || 'kubernetes');
|
|
14
|
-
|
|
15
|
-
this.__role = config.role;
|
|
16
|
-
this.__tokenPath = '/var/run/secrets/kubernetes.io/serviceaccount/token';
|
|
17
|
-
if (config.tokenPath !== undefined) {
|
|
18
|
-
this.__tokenPath = config.tokenPath;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
_authenticate() {
|
|
23
|
-
this._log.info(
|
|
24
|
-
'making authentication request: Vault role: "%s"; K8s token path: "%s"',
|
|
25
|
-
this.__role, this.__tokenPath
|
|
26
|
-
);
|
|
27
|
-
|
|
28
|
-
const k8sJwtToken = fs.readFileSync(this.__tokenPath).toString();
|
|
29
|
-
this._log.debug(
|
|
30
|
-
'receive K8s token: %s',
|
|
31
|
-
k8sJwtToken
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
return this.__apiClient.makeRequest('POST', `/auth/${this._mount}/login`, {
|
|
35
|
-
role: this.__role,
|
|
36
|
-
jwt: k8sJwtToken,
|
|
37
|
-
}).then((res) => {
|
|
38
|
-
this._log.debug(
|
|
39
|
-
'receive token: %s',
|
|
40
|
-
res.auth.client_token
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
return this._getTokenEntity(res.auth.client_token);
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
module.exports = VaultKubernetesAuth;
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const VaultBaseAuth = require('./VaultBaseAuth');
|
|
3
|
+
|
|
4
|
+
class VaultKubernetesAuth extends VaultBaseAuth {
|
|
5
|
+
/**
|
|
6
|
+
* @param {VaultApiClient} apiClient - see {@link VaultBaseAuth#constructor}
|
|
7
|
+
* @param {Object} config
|
|
8
|
+
* @param {String} config.role - Role configured in Vault Kubernetes Auth backend under which we want to issue Vault token.
|
|
9
|
+
* @param {String} [config.tokenPath] - Path to the Kube JWT token. If omitted - default will be used.
|
|
10
|
+
* @param {String} mount - Vault's mount point ("kubernetes" by default)
|
|
11
|
+
*/
|
|
12
|
+
constructor(apiClient, logger, config, mount) {
|
|
13
|
+
super(apiClient, logger, mount || 'kubernetes');
|
|
14
|
+
|
|
15
|
+
this.__role = config.role;
|
|
16
|
+
this.__tokenPath = '/var/run/secrets/kubernetes.io/serviceaccount/token';
|
|
17
|
+
if (config.tokenPath !== undefined) {
|
|
18
|
+
this.__tokenPath = config.tokenPath;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
_authenticate() {
|
|
23
|
+
this._log.info(
|
|
24
|
+
'making authentication request: Vault role: "%s"; K8s token path: "%s"',
|
|
25
|
+
this.__role, this.__tokenPath
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
const k8sJwtToken = fs.readFileSync(this.__tokenPath).toString();
|
|
29
|
+
this._log.debug(
|
|
30
|
+
'receive K8s token: %s',
|
|
31
|
+
k8sJwtToken
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
return this.__apiClient.makeRequest('POST', `/auth/${this._mount}/login`, {
|
|
35
|
+
role: this.__role,
|
|
36
|
+
jwt: k8sJwtToken,
|
|
37
|
+
}).then((res) => {
|
|
38
|
+
this._log.debug(
|
|
39
|
+
'receive token: %s',
|
|
40
|
+
res.auth.client_token
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
return this._getTokenEntity(res.auth.client_token);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
module.exports = VaultKubernetesAuth;
|
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const VaultBaseAuth = require('./VaultBaseAuth');
|
|
4
|
-
const errors = require('../errors');
|
|
5
|
-
|
|
6
|
-
class VaultTokenAuth extends VaultBaseAuth {
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* @param {Object} connConfig - see {@link VaultBaseAuth#constructor}
|
|
10
|
-
* @param {Object} config
|
|
11
|
-
* @param {String} config.token
|
|
12
|
-
* @param {String} mount - Vault's mount point ("token" by default)
|
|
13
|
-
*/
|
|
14
|
-
constructor(connConfig, logger, config, mount) {
|
|
15
|
-
super(connConfig, logger, mount || 'token');
|
|
16
|
-
|
|
17
|
-
if (!config.token) {
|
|
18
|
-
throw new errors.InvalidArgumentsError('Auth token should be provided for VaultTokenAuth');
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
this.__token = config.token;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
_authenticate() {
|
|
25
|
-
return this._getTokenEntity(this.__token);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
_reauthenticationAllowed() {
|
|
29
|
-
return false;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
module.exports = VaultTokenAuth;
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const VaultBaseAuth = require('./VaultBaseAuth');
|
|
4
|
+
const errors = require('../errors');
|
|
5
|
+
|
|
6
|
+
class VaultTokenAuth extends VaultBaseAuth {
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @param {Object} connConfig - see {@link VaultBaseAuth#constructor}
|
|
10
|
+
* @param {Object} config
|
|
11
|
+
* @param {String} config.token
|
|
12
|
+
* @param {String} mount - Vault's mount point ("token" by default)
|
|
13
|
+
*/
|
|
14
|
+
constructor(connConfig, logger, config, mount) {
|
|
15
|
+
super(connConfig, logger, mount || 'token');
|
|
16
|
+
|
|
17
|
+
if (!config.token) {
|
|
18
|
+
throw new errors.InvalidArgumentsError('Auth token should be provided for VaultTokenAuth');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
this.__token = config.token;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
_authenticate() {
|
|
25
|
+
return this._getTokenEntity(this.__token);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
_reauthenticationAllowed() {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
module.exports = VaultTokenAuth;
|
package/src/errors.js
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
class VaultError extends Error {
|
|
4
|
-
constructor(message, error) {
|
|
5
|
-
super(message);
|
|
6
|
-
this.name = this.constructor.name;
|
|
7
|
-
this.message = message;
|
|
8
|
-
|
|
9
|
-
Error.captureStackTrace(this, this.constructor.name);
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
class InvalidArgumentsError extends VaultError {}
|
|
13
|
-
class InvalidAWSCredentialsError extends InvalidArgumentsError {}
|
|
14
|
-
class AuthTokenExpiredError extends VaultError {}
|
|
15
|
-
|
|
16
|
-
module.exports = {
|
|
17
|
-
VaultError,
|
|
18
|
-
InvalidArgumentsError,
|
|
19
|
-
InvalidAWSCredentialsError,
|
|
20
|
-
AuthTokenExpiredError,
|
|
21
|
-
};
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
class VaultError extends Error {
|
|
4
|
+
constructor(message, error) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = this.constructor.name;
|
|
7
|
+
this.message = message;
|
|
8
|
+
|
|
9
|
+
Error.captureStackTrace(this, this.constructor.name);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
class InvalidArgumentsError extends VaultError {}
|
|
13
|
+
class InvalidAWSCredentialsError extends InvalidArgumentsError {}
|
|
14
|
+
class AuthTokenExpiredError extends VaultError {}
|
|
15
|
+
|
|
16
|
+
module.exports = {
|
|
17
|
+
VaultError,
|
|
18
|
+
InvalidArgumentsError,
|
|
19
|
+
InvalidAWSCredentialsError,
|
|
20
|
+
AuthTokenExpiredError,
|
|
21
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Pure KV path-rewriting and response-normalizing helpers.
|
|
5
|
+
* No I/O; fully testable in isolation.
|
|
6
|
+
*
|
|
7
|
+
* rewritePath(version, op, mount, logicalPath) -> apiPath
|
|
8
|
+
* normalizeResponse(version, op, body) -> normalized body
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// Map of op -> v2 path segment inserted between mount and logical path.
|
|
12
|
+
const V2_SEGMENT = {
|
|
13
|
+
read: 'data',
|
|
14
|
+
write: 'data',
|
|
15
|
+
delete: 'data',
|
|
16
|
+
update: 'data',
|
|
17
|
+
list: 'metadata',
|
|
18
|
+
readMetadata: 'metadata',
|
|
19
|
+
deleteMetadata: 'metadata',
|
|
20
|
+
deleteVersions: 'delete',
|
|
21
|
+
undeleteVersions:'undelete',
|
|
22
|
+
destroyVersions: 'destroy',
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Rewrite a logical path to the correct API path for the given engine version.
|
|
27
|
+
*
|
|
28
|
+
* @param {number} version - Engine version (2 = KV v2; anything else = passthrough)
|
|
29
|
+
* @param {string} op - Operation name (read, write, list, delete, update, …)
|
|
30
|
+
* @param {string} mount - Mount point (e.g. "secret" or "secret/")
|
|
31
|
+
* @param {string} logicalPath - Path relative to the mount (e.g. "team/svc")
|
|
32
|
+
* @returns {string}
|
|
33
|
+
*/
|
|
34
|
+
function rewritePath(version, op, mount, logicalPath) {
|
|
35
|
+
// Normalise trailing slash on mount
|
|
36
|
+
const m = mount.replace(/\/+$/, '');
|
|
37
|
+
|
|
38
|
+
if (version !== 2) {
|
|
39
|
+
// v1 / non-kv: simple concatenation
|
|
40
|
+
return logicalPath ? `${m}/${logicalPath}` : m;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const segment = V2_SEGMENT[op] || 'data';
|
|
44
|
+
return `${m}/${segment}/${logicalPath}`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Normalise a Vault API response body for the given engine version and operation.
|
|
49
|
+
*
|
|
50
|
+
* For v1 / non-kv the body is always returned as-is.
|
|
51
|
+
* For v2:
|
|
52
|
+
* - read: body.data is replaced with body.data.data; body.metadata is set to body.data.metadata
|
|
53
|
+
* - readMetadata: body.data is replaced with the original body.data (unwrapped one level)
|
|
54
|
+
* - write/delete/update/…: body returned as-is
|
|
55
|
+
*
|
|
56
|
+
* @param {number} version
|
|
57
|
+
* @param {string} op
|
|
58
|
+
* @param {*} body
|
|
59
|
+
* @returns {*}
|
|
60
|
+
*/
|
|
61
|
+
function normalizeResponse(version, op, body) {
|
|
62
|
+
if (version !== 2) {
|
|
63
|
+
return body;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (op === 'read') {
|
|
67
|
+
if (!body || !body.data) {
|
|
68
|
+
return body;
|
|
69
|
+
}
|
|
70
|
+
// Promote inner data/metadata to top-level response fields
|
|
71
|
+
const result = Object.assign({}, body);
|
|
72
|
+
result.metadata = body.data.metadata;
|
|
73
|
+
result.data = body.data.data;
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (op === 'readMetadata') {
|
|
78
|
+
if (!body || !body.data) {
|
|
79
|
+
return body;
|
|
80
|
+
}
|
|
81
|
+
const result = Object.assign({}, body);
|
|
82
|
+
result.data = body.data;
|
|
83
|
+
return result;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// All other v2 ops (write, list, delete, update, deleteVersions, …): passthrough
|
|
87
|
+
return body;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
module.exports = { rewritePath, normalizeResponse };
|