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.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/index.js +81 -54
  3. 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/custom_metadata vars
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 {entity_id, identity : {metadata}} = await this._get_profile();
116
- if(!metadata)
117
- metadata = {};
118
- let key_name = `env_${k.toUpperCase()}`;
119
- metadata[key_name] = v;
120
- await this._update_identity(this.VAULT_TOKEN, entity_id, {metadata});
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._get_profile();
129
- return profile;
129
+ let {profile, database} = await this._vault_get_profile();
130
+ return {...database, ...profile};
130
131
  }
131
132
 
132
- async _get_profile() {
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
- for(let alias of identity.aliases) {
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
- async dotenv() {
152
- let {profile} = await this._get_profile();
147
+ return {entity_id, identity, profile, database};
148
+ }
153
149
 
154
- let env = {VAULT_TOKEN : this.VAULT_TOKEN, VAULT_ADDR : this.VAULT_ADDR}, secrets = {},
155
- {map = {}, paths, path : mount = "secrets"} = this.rc.env || {};
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
- if(paths) {
159
- for(let secret_path of paths) {
160
- console.error("reaching paths", secret_path);
161
- let data = await this._read(mount, secret_path);
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
- for(let [k, v] of Object.entries(map))
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
- for(let [k, v] of Object.entries(env)) {
170
- process.stdout.write(`${k}=${String(v)}\n`);
171
- process.stderr.write(`export ${k}=[redacted]\n`);
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._read(mount, secret_path);
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}, expect : 200};
220
+ let query = {...url.parse(remote_url), headers : {'x-vault-token' : this.VAULT_TOKEN}};
214
221
  let res = await request(query);
215
- return get(JSON.parse(String(await drain(res))), 'data.data');
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": "1.1.3",
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
  },