node-vault-client 0.5.7 → 0.6.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/LICENSE.txt +200 -200
- package/README.md +153 -153
- package/package.json +43 -43
- package/src/Lease.js +57 -57
- package/src/VaultApiClient.js +55 -55
- package/src/VaultClient.js +266 -253
- package/src/VaultNodeConfig.js +105 -105
- package/src/auth/AuthToken.js +94 -94
- package/src/auth/VaultAppRoleAuth.js +40 -40
- package/src/auth/VaultBaseAuth.js +140 -140
- package/src/auth/VaultIAMAuth.js +181 -169
- package/src/auth/VaultKubernetesAuth.js +48 -48
- package/src/auth/VaultTokenAuth.js +34 -34
- package/src/errors.js +21 -21
package/src/VaultNodeConfig.js
CHANGED
|
@@ -1,105 +1,105 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const path = require('path');
|
|
4
|
-
const fs = require('fs');
|
|
5
|
-
const Bluebird = require('bluebird');
|
|
6
|
-
const _ = require('lodash');
|
|
7
|
-
const assignDeep = require('assign-deep');
|
|
8
|
-
|
|
9
|
-
const errors = require('./errors');
|
|
10
|
-
|
|
11
|
-
class VaultNodeConfig {
|
|
12
|
-
|
|
13
|
-
constructor(vault) {
|
|
14
|
-
this.__vault = vault;
|
|
15
|
-
|
|
16
|
-
try {
|
|
17
|
-
require.resolve('config');
|
|
18
|
-
} catch(e) {
|
|
19
|
-
throw new errors.VaultError(`NPM package "config" isn't installed`);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
this.__nodeConfig = require('config');
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Populates Vault's values to "node-config"
|
|
27
|
-
*/
|
|
28
|
-
populate() {
|
|
29
|
-
const substitutionMap = this.__getSubstitutionMap();
|
|
30
|
-
let requiredData = {};
|
|
31
|
-
|
|
32
|
-
this.__traverse(substitutionMap, (key, val) => {
|
|
33
|
-
const splitRes = val.split('#');
|
|
34
|
-
const path = splitRes[0], value = splitRes[1];
|
|
35
|
-
if (path === undefined || value === undefined) {
|
|
36
|
-
throw new errors.InvalidArgumentsError('Invalid format of substitution value');
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
requiredData[path] = null;
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
let promises = _.mapValues(requiredData, (value, path) => this.__vault.read(path));
|
|
43
|
-
|
|
44
|
-
return Bluebird.props(promises).then(results => {
|
|
45
|
-
requiredData = _.mapValues(requiredData, (value, path) => results[path].getData());
|
|
46
|
-
|
|
47
|
-
this.__traverse(substitutionMap, (key, val, obj) => {
|
|
48
|
-
const splitRes = val.split('#');
|
|
49
|
-
const path = splitRes[0], value = splitRes[1];
|
|
50
|
-
const res = requiredData[path][value];
|
|
51
|
-
if (res === undefined) {
|
|
52
|
-
throw new errors.VaultError(`Can't find substitution for "${val}"`);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
obj[key] = requiredData[path][value];
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
return assignDeep(this.__nodeConfig, substitutionMap);
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* @private
|
|
64
|
-
*/
|
|
65
|
-
__getSubstitutionMap() {
|
|
66
|
-
let config_dir = this.__nodeConfig.util.initParam('NODE_CONFIG_DIR', path.join( process.cwd(), 'config') );
|
|
67
|
-
if (config_dir.indexOf('.') === 0) {
|
|
68
|
-
config_dir = path.join(process.cwd() , config_dir);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const fullFilename = path.join(config_dir, 'custom-vault-variables.js');
|
|
72
|
-
|
|
73
|
-
let fileContent;
|
|
74
|
-
try {
|
|
75
|
-
fileContent = require(fullFilename);
|
|
76
|
-
} catch (e) {
|
|
77
|
-
throw new errors.VaultError('Config file ' + fullFilename + ' cannot be read');
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if (!_.isPlainObject(fileContent)) {
|
|
81
|
-
throw new errors.VaultError('Config file ' + fullFilename + ' should return plain object');
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
return _.cloneDeep(fileContent);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
__traverse(o, func) {
|
|
88
|
-
for (let i in o) {
|
|
89
|
-
if (!o.hasOwnProperty(i)) {
|
|
90
|
-
continue;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (o[i] !== null && typeof(o[i]) === "object") {
|
|
94
|
-
//going one step down in the object tree!!
|
|
95
|
-
this.__traverse(o[i], func);
|
|
96
|
-
} else if (typeof o[i] === 'string') {
|
|
97
|
-
func(i, o[i], o);
|
|
98
|
-
} else {
|
|
99
|
-
throw new errors.InvalidArgumentsError('Illegal key type for substitution map');
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
module.exports = VaultNodeConfig;
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const Bluebird = require('bluebird');
|
|
6
|
+
const _ = require('lodash');
|
|
7
|
+
const assignDeep = require('assign-deep');
|
|
8
|
+
|
|
9
|
+
const errors = require('./errors');
|
|
10
|
+
|
|
11
|
+
class VaultNodeConfig {
|
|
12
|
+
|
|
13
|
+
constructor(vault) {
|
|
14
|
+
this.__vault = vault;
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
require.resolve('config');
|
|
18
|
+
} catch(e) {
|
|
19
|
+
throw new errors.VaultError(`NPM package "config" isn't installed`);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
this.__nodeConfig = require('config');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Populates Vault's values to "node-config"
|
|
27
|
+
*/
|
|
28
|
+
populate() {
|
|
29
|
+
const substitutionMap = this.__getSubstitutionMap();
|
|
30
|
+
let requiredData = {};
|
|
31
|
+
|
|
32
|
+
this.__traverse(substitutionMap, (key, val) => {
|
|
33
|
+
const splitRes = val.split('#');
|
|
34
|
+
const path = splitRes[0], value = splitRes[1];
|
|
35
|
+
if (path === undefined || value === undefined) {
|
|
36
|
+
throw new errors.InvalidArgumentsError('Invalid format of substitution value');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
requiredData[path] = null;
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
let promises = _.mapValues(requiredData, (value, path) => this.__vault.read(path));
|
|
43
|
+
|
|
44
|
+
return Bluebird.props(promises).then(results => {
|
|
45
|
+
requiredData = _.mapValues(requiredData, (value, path) => results[path].getData());
|
|
46
|
+
|
|
47
|
+
this.__traverse(substitutionMap, (key, val, obj) => {
|
|
48
|
+
const splitRes = val.split('#');
|
|
49
|
+
const path = splitRes[0], value = splitRes[1];
|
|
50
|
+
const res = requiredData[path][value];
|
|
51
|
+
if (res === undefined) {
|
|
52
|
+
throw new errors.VaultError(`Can't find substitution for "${val}"`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
obj[key] = requiredData[path][value];
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
return assignDeep(this.__nodeConfig, substitutionMap);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @private
|
|
64
|
+
*/
|
|
65
|
+
__getSubstitutionMap() {
|
|
66
|
+
let config_dir = this.__nodeConfig.util.initParam('NODE_CONFIG_DIR', path.join( process.cwd(), 'config') );
|
|
67
|
+
if (config_dir.indexOf('.') === 0) {
|
|
68
|
+
config_dir = path.join(process.cwd() , config_dir);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const fullFilename = path.join(config_dir, 'custom-vault-variables.js');
|
|
72
|
+
|
|
73
|
+
let fileContent;
|
|
74
|
+
try {
|
|
75
|
+
fileContent = require(fullFilename);
|
|
76
|
+
} catch (e) {
|
|
77
|
+
throw new errors.VaultError('Config file ' + fullFilename + ' cannot be read');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (!_.isPlainObject(fileContent)) {
|
|
81
|
+
throw new errors.VaultError('Config file ' + fullFilename + ' should return plain object');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return _.cloneDeep(fileContent);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
__traverse(o, func) {
|
|
88
|
+
for (let i in o) {
|
|
89
|
+
if (!o.hasOwnProperty(i)) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (o[i] !== null && typeof(o[i]) === "object") {
|
|
94
|
+
//going one step down in the object tree!!
|
|
95
|
+
this.__traverse(o[i], func);
|
|
96
|
+
} else if (typeof o[i] === 'string') {
|
|
97
|
+
func(i, o[i], o);
|
|
98
|
+
} else {
|
|
99
|
+
throw new errors.InvalidArgumentsError('Illegal key type for substitution map');
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
module.exports = VaultNodeConfig;
|
package/src/auth/AuthToken.js
CHANGED
|
@@ -1,94 +1,94 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const _ = require('lodash');
|
|
4
|
-
|
|
5
|
-
class AuthToken {
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
*
|
|
9
|
-
* @param {string} id
|
|
10
|
-
* @param {string} accessor
|
|
11
|
-
* @param {int} createdAt - UNIX timestamp
|
|
12
|
-
* @param {int|null} expiresAt - UNIX timestamp
|
|
13
|
-
* @param {int} explicitMaxTtl - in seconds
|
|
14
|
-
* @param {int} numUses
|
|
15
|
-
* @param {boolean} isRenewable
|
|
16
|
-
*/
|
|
17
|
-
constructor(
|
|
18
|
-
id,
|
|
19
|
-
accessor,
|
|
20
|
-
createdAt,
|
|
21
|
-
expiresAt,
|
|
22
|
-
explicitMaxTtl,
|
|
23
|
-
numUses,
|
|
24
|
-
isRenewable
|
|
25
|
-
) {
|
|
26
|
-
this.__id = id;
|
|
27
|
-
this.__accessor = accessor;
|
|
28
|
-
this.__createdAt = createdAt;
|
|
29
|
-
this.__expiresAt = expiresAt;
|
|
30
|
-
this.__explicitMaxTtl = explicitMaxTtl;
|
|
31
|
-
this.__numUses = numUses;
|
|
32
|
-
this.__isRenewable = isRenewable;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
static fromResponse(response) {
|
|
36
|
-
const data = response.data;
|
|
37
|
-
|
|
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
|
-
return new AuthToken(
|
|
47
|
-
data.id,
|
|
48
|
-
data.accessor,
|
|
49
|
-
data.creation_time,
|
|
50
|
-
expiresAt,
|
|
51
|
-
data.explicit_max_ttl,
|
|
52
|
-
data.num_uses,
|
|
53
|
-
data.renewable !== undefined ? data.renewable : false
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* @returns {string}
|
|
59
|
-
*/
|
|
60
|
-
getId() {
|
|
61
|
-
return this.__id;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
getAccessor() {
|
|
65
|
-
return this.__accessor;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* @returns {boolean}
|
|
70
|
-
*/
|
|
71
|
-
isExpired() {
|
|
72
|
-
if (this.__expiresAt === null) {
|
|
73
|
-
return false;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
return Math.floor(Date.now() / 1000) > this.__expiresAt;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* @returns {boolean}
|
|
81
|
-
*/
|
|
82
|
-
isRenewable() {
|
|
83
|
-
return this.__isRenewable && this.getExpiresAt() !== null;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* @returns {int|null} UNIX timestamp
|
|
88
|
-
*/
|
|
89
|
-
getExpiresAt() {
|
|
90
|
-
return this.__expiresAt;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
module.exports = AuthToken;
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
|
|
5
|
+
class AuthToken {
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
*
|
|
9
|
+
* @param {string} id
|
|
10
|
+
* @param {string} accessor
|
|
11
|
+
* @param {int} createdAt - UNIX timestamp
|
|
12
|
+
* @param {int|null} expiresAt - UNIX timestamp
|
|
13
|
+
* @param {int} explicitMaxTtl - in seconds
|
|
14
|
+
* @param {int} numUses
|
|
15
|
+
* @param {boolean} isRenewable
|
|
16
|
+
*/
|
|
17
|
+
constructor(
|
|
18
|
+
id,
|
|
19
|
+
accessor,
|
|
20
|
+
createdAt,
|
|
21
|
+
expiresAt,
|
|
22
|
+
explicitMaxTtl,
|
|
23
|
+
numUses,
|
|
24
|
+
isRenewable
|
|
25
|
+
) {
|
|
26
|
+
this.__id = id;
|
|
27
|
+
this.__accessor = accessor;
|
|
28
|
+
this.__createdAt = createdAt;
|
|
29
|
+
this.__expiresAt = expiresAt;
|
|
30
|
+
this.__explicitMaxTtl = explicitMaxTtl;
|
|
31
|
+
this.__numUses = numUses;
|
|
32
|
+
this.__isRenewable = isRenewable;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
static fromResponse(response) {
|
|
36
|
+
const data = response.data;
|
|
37
|
+
|
|
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
|
+
return new AuthToken(
|
|
47
|
+
data.id,
|
|
48
|
+
data.accessor,
|
|
49
|
+
data.creation_time,
|
|
50
|
+
expiresAt,
|
|
51
|
+
data.explicit_max_ttl,
|
|
52
|
+
data.num_uses,
|
|
53
|
+
data.renewable !== undefined ? data.renewable : false
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @returns {string}
|
|
59
|
+
*/
|
|
60
|
+
getId() {
|
|
61
|
+
return this.__id;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
getAccessor() {
|
|
65
|
+
return this.__accessor;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* @returns {boolean}
|
|
70
|
+
*/
|
|
71
|
+
isExpired() {
|
|
72
|
+
if (this.__expiresAt === null) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return Math.floor(Date.now() / 1000) > this.__expiresAt;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @returns {boolean}
|
|
81
|
+
*/
|
|
82
|
+
isRenewable() {
|
|
83
|
+
return this.__isRenewable && this.getExpiresAt() !== null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* @returns {int|null} UNIX timestamp
|
|
88
|
+
*/
|
|
89
|
+
getExpiresAt() {
|
|
90
|
+
return this.__expiresAt;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
module.exports = AuthToken;
|
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const VaultBaseAuth = require('./VaultBaseAuth');
|
|
4
|
-
|
|
5
|
-
class VaultAppRoleAuth extends VaultBaseAuth {
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* @param {VaultApiClient} apiClient - see {@link VaultBaseAuth#constructor}
|
|
9
|
-
* @param {Object} config
|
|
10
|
-
* @param {String} config.role_id - RoleID of the AppRole.
|
|
11
|
-
* @param {String} [config.secret_id] - required when bind_secret_id is enabled SecretID belonging to AppRole.
|
|
12
|
-
* @param {String} mount - Vault's mount point ("approle" by default)
|
|
13
|
-
*/
|
|
14
|
-
constructor(apiClient, logger, config, mount) {
|
|
15
|
-
super(apiClient, logger, mount || 'approle');
|
|
16
|
-
|
|
17
|
-
this.__roleId = config.role_id;
|
|
18
|
-
this.__secretId = config.secret_id;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
_authenticate() {
|
|
22
|
-
this._log.info(
|
|
23
|
-
'making authentication request: role_id=%s',
|
|
24
|
-
this.__roleId
|
|
25
|
-
);
|
|
26
|
-
return this.__apiClient.makeRequest('POST', `/auth/${this._mount}/login`, {
|
|
27
|
-
role_id: this.__roleId,
|
|
28
|
-
secret_id: this.__secretId,
|
|
29
|
-
}).then(res => {
|
|
30
|
-
this._log.debug(
|
|
31
|
-
'receive token: %s',
|
|
32
|
-
res.auth.client_token
|
|
33
|
-
);
|
|
34
|
-
return this._getTokenEntity(res.auth.client_token);
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
module.exports = VaultAppRoleAuth;
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const VaultBaseAuth = require('./VaultBaseAuth');
|
|
4
|
+
|
|
5
|
+
class VaultAppRoleAuth extends VaultBaseAuth {
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @param {VaultApiClient} apiClient - see {@link VaultBaseAuth#constructor}
|
|
9
|
+
* @param {Object} config
|
|
10
|
+
* @param {String} config.role_id - RoleID of the AppRole.
|
|
11
|
+
* @param {String} [config.secret_id] - required when bind_secret_id is enabled SecretID belonging to AppRole.
|
|
12
|
+
* @param {String} mount - Vault's mount point ("approle" by default)
|
|
13
|
+
*/
|
|
14
|
+
constructor(apiClient, logger, config, mount) {
|
|
15
|
+
super(apiClient, logger, mount || 'approle');
|
|
16
|
+
|
|
17
|
+
this.__roleId = config.role_id;
|
|
18
|
+
this.__secretId = config.secret_id;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
_authenticate() {
|
|
22
|
+
this._log.info(
|
|
23
|
+
'making authentication request: role_id=%s',
|
|
24
|
+
this.__roleId
|
|
25
|
+
);
|
|
26
|
+
return this.__apiClient.makeRequest('POST', `/auth/${this._mount}/login`, {
|
|
27
|
+
role_id: this.__roleId,
|
|
28
|
+
secret_id: this.__secretId,
|
|
29
|
+
}).then(res => {
|
|
30
|
+
this._log.debug(
|
|
31
|
+
'receive token: %s',
|
|
32
|
+
res.auth.client_token
|
|
33
|
+
);
|
|
34
|
+
return this._getTokenEntity(res.auth.client_token);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
module.exports = VaultAppRoleAuth;
|