vvauth 1.2.1 → 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 +1 -1
- package/index.js +49 -25
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ vauth configuration file is a simple yaml file with a specific macro expansion s
|
|
|
18
18
|
The configuration file should abide the following schema
|
|
19
19
|
|
|
20
20
|
### configuration macro expansion set
|
|
21
|
-
* $${profile.XXX} expand to vault entity metadata
|
|
21
|
+
* $${profile.XXX} expand to vault entity metadata and user `.vauth_database` vars
|
|
22
22
|
* $${env.XXX} expand to local environement vars
|
|
23
23
|
* $${secrets.XXX} expand to remote scrapped secrets (see the env.paths)
|
|
24
24
|
|
package/index.js
CHANGED
|
@@ -7,6 +7,7 @@ const path = require('path');
|
|
|
7
7
|
const url = require('url');
|
|
8
8
|
const {spawn} = require('child_process');
|
|
9
9
|
const passthru = require('nyks/child_process/passthru');
|
|
10
|
+
const wait = require('nyks/child_process/wait');
|
|
10
11
|
|
|
11
12
|
const {parse} = require('yaml');
|
|
12
13
|
const semver = require('semver');
|
|
@@ -112,12 +113,12 @@ class vvauth {
|
|
|
112
113
|
|
|
113
114
|
|
|
114
115
|
async set(k, v) {
|
|
115
|
-
let {
|
|
116
|
-
if(!
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
await this.
|
|
116
|
+
let {profile, database} = await this._vault_get_profile();
|
|
117
|
+
if(!profile.VAUTH_USER_LOGIN)
|
|
118
|
+
throw "Could not resolve VAUTH_USER_LOGIN from vault identity";
|
|
119
|
+
|
|
120
|
+
database[k.toUpperCase()] = v;
|
|
121
|
+
await this._vault_write(`private/${profile.VAUTH_USER_LOGIN}`, '.vauth_database', database);
|
|
121
122
|
}
|
|
122
123
|
|
|
123
124
|
async unset(k) {
|
|
@@ -125,8 +126,8 @@ class vvauth {
|
|
|
125
126
|
}
|
|
126
127
|
|
|
127
128
|
async show() {
|
|
128
|
-
let {profile} = await this._vault_get_profile();
|
|
129
|
-
return profile;
|
|
129
|
+
let {profile, database} = await this._vault_get_profile();
|
|
130
|
+
return {...database, ...profile};
|
|
130
131
|
}
|
|
131
132
|
|
|
132
133
|
async _vault_get_profile() {
|
|
@@ -137,22 +138,18 @@ class vvauth {
|
|
|
137
138
|
|
|
138
139
|
let {entity_id} = await this._lookup_token(this.VAULT_TOKEN);
|
|
139
140
|
let identity = await this._lookup_identity(this.VAULT_TOKEN, entity_id);
|
|
140
|
-
let profile = {};
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
for(let [k, v] of Object.entries(identity.metadata || {})) {
|
|
148
|
-
if(k.startsWith('env_'))
|
|
149
|
-
profile[k.substr(4)] = v;
|
|
150
|
-
}
|
|
151
|
-
return {entity_id, identity, profile};
|
|
141
|
+
let profile = {...(identity.metadata || {})};
|
|
142
|
+
let database = {};
|
|
143
|
+
|
|
144
|
+
if(profile.VAUTH_USER_LOGIN)
|
|
145
|
+
database = await this._vault_read(`private/${profile.VAUTH_USER_LOGIN}`, '.vauth_database', true);
|
|
146
|
+
|
|
147
|
+
return {entity_id, identity, profile, database};
|
|
152
148
|
}
|
|
153
149
|
|
|
154
150
|
async _get_env() {
|
|
155
|
-
let {profile} = await this._vault_get_profile();
|
|
151
|
+
let {profile, database} = await this._vault_get_profile();
|
|
152
|
+
profile = {...database, ...profile};
|
|
156
153
|
|
|
157
154
|
let env = {VAULT_TOKEN : this.VAULT_TOKEN, VAULT_ADDR : this.VAULT_ADDR}, secrets = {},
|
|
158
155
|
{git, map = {}, paths, path : mount = "secrets"} = this.rc.env || {};
|
|
@@ -163,7 +160,14 @@ class vvauth {
|
|
|
163
160
|
let child = spawn('ssh-agent-crypt', ["-decrypt", identity]);
|
|
164
161
|
|
|
165
162
|
child.stdin.end(fs.readFileSync(path));
|
|
166
|
-
|
|
163
|
+
child.stderr.pipe(process.stderr);
|
|
164
|
+
|
|
165
|
+
const [exit, body] = await Promise.all([wait(child, false), drain(child.stdout)]);
|
|
166
|
+
if(exit !== 0) {
|
|
167
|
+
console.error("Could not expand armored %s using %s", path, identity);
|
|
168
|
+
process.exit();
|
|
169
|
+
}
|
|
170
|
+
const result = JSON.parse(body);
|
|
167
171
|
secrets = {...secrets, ...result};
|
|
168
172
|
}
|
|
169
173
|
|
|
@@ -211,11 +215,31 @@ class vvauth {
|
|
|
211
215
|
return env;
|
|
212
216
|
}
|
|
213
217
|
|
|
214
|
-
async _vault_read(mount, secret_path) {
|
|
218
|
+
async _vault_read(mount, secret_path, optional = false) {
|
|
215
219
|
let remote_url = `${trim(this.VAULT_ADDR, '/')}/v1/${mount}/data/${trim(secret_path, '/')}`;
|
|
216
|
-
let query = {...url.parse(remote_url), headers : {'x-vault-token' : this.VAULT_TOKEN}
|
|
220
|
+
let query = {...url.parse(remote_url), headers : {'x-vault-token' : this.VAULT_TOKEN}};
|
|
217
221
|
let res = await request(query);
|
|
218
|
-
|
|
222
|
+
let body = String(await drain(res));
|
|
223
|
+
|
|
224
|
+
if(optional && res.statusCode == 404)
|
|
225
|
+
return {};
|
|
226
|
+
|
|
227
|
+
if(res.statusCode != 200)
|
|
228
|
+
throw `Could not read vault secret '${mount}/${trim(secret_path, '/')}' : ${body}`;
|
|
229
|
+
|
|
230
|
+
return get(JSON.parse(body), 'data.data');
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
async _vault_write(mount, secret_path, data) {
|
|
234
|
+
let remote_url = `${trim(this.VAULT_ADDR, '/')}/v1/${mount}/data/${trim(secret_path, '/')}`;
|
|
235
|
+
let query = {...url.parse(remote_url), headers : {'x-vault-token' : this.VAULT_TOKEN}, json : true};
|
|
236
|
+
let res = await request(query, {data});
|
|
237
|
+
let body = String(await drain(res));
|
|
238
|
+
|
|
239
|
+
if(res.statusCode != 200)
|
|
240
|
+
throw `Could not write vault secret '${mount}/${trim(secret_path, '/')}' : ${body}`;
|
|
241
|
+
|
|
242
|
+
return body ? JSON.parse(body) : {};
|
|
219
243
|
}
|
|
220
244
|
|
|
221
245
|
|