vvauth 1.1.3 → 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 +81 -54
- package/package.json +2 -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,62 +126,51 @@ class vvauth {
|
|
|
125
126
|
}
|
|
126
127
|
|
|
127
128
|
async show() {
|
|
128
|
-
let {profile} = await this.
|
|
129
|
-
return profile;
|
|
129
|
+
let {profile, database} = await this._vault_get_profile();
|
|
130
|
+
return {...database, ...profile};
|
|
130
131
|
}
|
|
131
132
|
|
|
132
|
-
async
|
|
133
|
+
async _vault_get_profile() {
|
|
133
134
|
await this.connect();
|
|
135
|
+
|
|
136
|
+
if(!this.VAULT_TOKEN)
|
|
137
|
+
return {};
|
|
138
|
+
|
|
134
139
|
let {entity_id} = await this._lookup_token(this.VAULT_TOKEN);
|
|
135
140
|
let identity = await this._lookup_identity(this.VAULT_TOKEN, entity_id);
|
|
136
|
-
let profile = {};
|
|
137
|
-
|
|
138
|
-
for(let [k, v] of Object.entries(alias.custom_metadata || {})) {
|
|
139
|
-
if(k.startsWith('env_'))
|
|
140
|
-
profile[k.substr(4)] = v;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
for(let [k, v] of Object.entries(identity.metadata || {})) {
|
|
144
|
-
if(k.startsWith('env_'))
|
|
145
|
-
profile[k.substr(4)] = v;
|
|
146
|
-
}
|
|
147
|
-
return {entity_id, identity, profile};
|
|
148
|
-
}
|
|
141
|
+
let profile = {...(identity.metadata || {})};
|
|
142
|
+
let database = {};
|
|
149
143
|
|
|
144
|
+
if(profile.VAUTH_USER_LOGIN)
|
|
145
|
+
database = await this._vault_read(`private/${profile.VAUTH_USER_LOGIN}`, '.vauth_database', true);
|
|
150
146
|
|
|
151
|
-
|
|
152
|
-
|
|
147
|
+
return {entity_id, identity, profile, database};
|
|
148
|
+
}
|
|
153
149
|
|
|
154
|
-
|
|
155
|
-
|
|
150
|
+
async _get_env() {
|
|
151
|
+
let {profile, database} = await this._vault_get_profile();
|
|
152
|
+
profile = {...database, ...profile};
|
|
156
153
|
|
|
154
|
+
let env = {VAULT_TOKEN : this.VAULT_TOKEN, VAULT_ADDR : this.VAULT_ADDR}, secrets = {},
|
|
155
|
+
{git, map = {}, paths, path : mount = "secrets"} = this.rc.env || {};
|
|
157
156
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
secrets = {...secrets, ...data};
|
|
163
|
-
}
|
|
157
|
+
let {'ssh-agent-crypt' : agent } = this.rc;
|
|
158
|
+
if(agent) {
|
|
159
|
+
const {path, identity} = agent;
|
|
160
|
+
let child = spawn('ssh-agent-crypt', ["-decrypt", identity]);
|
|
164
161
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
env[k] = replaceEnv(v, {env : process.env, profile, secrets});
|
|
162
|
+
child.stdin.end(fs.readFileSync(path));
|
|
163
|
+
child.stderr.pipe(process.stderr);
|
|
168
164
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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);
|
|
171
|
+
secrets = {...secrets, ...result};
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
-
process.exit();
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
async env(source = false) {
|
|
179
|
-
let {profile} = await this._get_profile();
|
|
180
|
-
|
|
181
|
-
let env = {VAULT_TOKEN : this.VAULT_TOKEN, VAULT_ADDR : this.VAULT_ADDR}, secrets = {},
|
|
182
|
-
{git, map = {}, paths, path : mount = "secrets"} = this.rc.env || {};
|
|
183
|
-
|
|
184
174
|
if(git) {
|
|
185
175
|
map = {...map,
|
|
186
176
|
"GIT_COMMITTER_NAME" : profile.VAUTH_USER_NAME,
|
|
@@ -193,32 +183,69 @@ class vvauth {
|
|
|
193
183
|
if(paths) {
|
|
194
184
|
for(let secret_path of paths) {
|
|
195
185
|
console.error("reaching paths", secret_path);
|
|
196
|
-
let data = await this.
|
|
186
|
+
let data = await this._vault_read(mount, secret_path);
|
|
197
187
|
secrets = {...secrets, ...data};
|
|
198
188
|
}
|
|
199
189
|
}
|
|
200
190
|
for(let [k, v] of Object.entries(map))
|
|
201
191
|
env[k] = replaceEnv(v, {env : process.env, profile, secrets});
|
|
202
192
|
|
|
193
|
+
return env;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
async dotenv() {
|
|
197
|
+
const env = await this._get_env();
|
|
198
|
+
|
|
199
|
+
for(let [k, v] of Object.entries(env)) {
|
|
200
|
+
process.stdout.write(`${k}=${String(v)}\n`);
|
|
201
|
+
process.stderr.write(`export ${k}=[redacted]\n`);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
process.exit();
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
async env(source = false) {
|
|
208
|
+
const env = await this._get_env();
|
|
209
|
+
|
|
203
210
|
if(source) {
|
|
204
211
|
this._publish_env(env);
|
|
205
212
|
process.exit();
|
|
206
213
|
}
|
|
214
|
+
|
|
207
215
|
return env;
|
|
208
216
|
}
|
|
209
217
|
|
|
210
|
-
|
|
211
|
-
async _read(mount, secret_path) {
|
|
218
|
+
async _vault_read(mount, secret_path, optional = false) {
|
|
212
219
|
let remote_url = `${trim(this.VAULT_ADDR, '/')}/v1/${mount}/data/${trim(secret_path, '/')}`;
|
|
213
|
-
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}};
|
|
214
221
|
let res = await request(query);
|
|
215
|
-
|
|
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');
|
|
216
231
|
}
|
|
217
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) : {};
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
|
|
218
246
|
async _login_vault_ssh({path = 'ssh', role}) {
|
|
219
247
|
logger.info("Trying to auth as '%s'", role);
|
|
220
248
|
|
|
221
|
-
|
|
222
249
|
let agent = new OpenSSHAgent(process.env.SSH_AUTH_SOCK);
|
|
223
250
|
let keys = await promiser(chain => agent.getIdentities(chain));
|
|
224
251
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vvauth",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Vault Auth helper",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"mout": "^1.2.4",
|
|
18
18
|
"nyks": "^6.15.0",
|
|
19
19
|
"semver": "^7.5.4",
|
|
20
|
+
"ssh-agent-crypt": "^1.0.1",
|
|
20
21
|
"ssh2": "^1.16.0",
|
|
21
22
|
"yaml": "^2.6.1"
|
|
22
23
|
},
|