vvauth 0.3.2 → 0.3.4

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 (2) hide show
  1. package/index.js +26 -23
  2. package/package.json +3 -3
package/index.js CHANGED
@@ -5,12 +5,10 @@ const os = require('os');
5
5
  const fs = require('fs');
6
6
  const path = require('path');
7
7
  const url = require('url');
8
- const net = require('net');
9
8
  const {spawn} = require('child_process');
10
9
 
11
10
  const {parse} = require('yaml');
12
11
  const semver = require('semver');
13
- const SSHAgent = require('ssh-agent-js/client');
14
12
  const trim = require('mout/string/trim');
15
13
  const get = require('mout/object/get');
16
14
  const eachLimit = require('nyks/async/eachLimit');
@@ -19,7 +17,9 @@ const walk = require('nyks/object/walk');
19
17
  const request = require('nyks/http/request');
20
18
  const drain = require('nyks/stream/drain');
21
19
  const replaceEnv = require('nyks/string/replaceEnv');
20
+ const promiser = require('nyks/function/promiser');
22
21
 
22
+ const {OpenSSHAgent} = require('ssh2/lib/agent');
23
23
  const debug = require('debug');
24
24
 
25
25
  const logger = {
@@ -56,13 +56,13 @@ class vvauth {
56
56
  }
57
57
  }
58
58
 
59
- this.vault_addr = this.rc.vault_addr;
59
+ this.VAULT_ADDR = this.rc.vault_addr;
60
60
 
61
- if(!this.vault_addr)
61
+ if(!this.VAULT_ADDR)
62
62
  throw `Invalid vault remote`;
63
63
 
64
64
  this.VAULT_TOKEN = process.env.VAULT_TOKEN;
65
- console.error("vauth bound to '%s'", this.vault_addr);
65
+ console.error("vauth bound to '%s'", this.VAULT_ADDR);
66
66
  }
67
67
 
68
68
  async connect() {
@@ -90,7 +90,7 @@ class vvauth {
90
90
  _publish_env(env) {
91
91
  let cmds = [];
92
92
  for(let [k, v] of Object.entries(env)) {
93
- cmds.push(`export ${k}="${v}"`);
93
+ cmds.push(`export ${k}=${shellEscape(v)}`);
94
94
  cmds.push(`echo export ${k}=[redacted] >&2`);
95
95
  }
96
96
  process.stdout.write(cmds.join("\n") + "\n");
@@ -136,7 +136,7 @@ class vvauth {
136
136
  async env(source = false) {
137
137
  let {profile} = await this._get_profile();
138
138
 
139
- let env = {VAULT_TOKEN : this.VAULT_TOKEN}, secrets = {},
139
+ let env = {VAULT_TOKEN : this.VAULT_TOKEN, VAULT_ADDR : this.VAULT_ADDR}, secrets = {},
140
140
  {git, map = {}, paths, path : mount = "secrets"} = this.rc.env || {};
141
141
 
142
142
  if(git) {
@@ -166,7 +166,7 @@ class vvauth {
166
166
 
167
167
 
168
168
  async _read(mount, secret_path) {
169
- let remote_url = `${trim(this.vault_addr, '/')}/v1/${mount}/data/${trim(secret_path, '/')}`;
169
+ let remote_url = `${trim(this.VAULT_ADDR, '/')}/v1/${mount}/data/${trim(secret_path, '/')}`;
170
170
  let query = {...url.parse(remote_url), headers : {'x-vault-token' : this.VAULT_TOKEN}, expect : 200};
171
171
  let res = await request(query);
172
172
  return get(JSON.parse(String(await drain(res))), 'data.data');
@@ -174,33 +174,32 @@ class vvauth {
174
174
 
175
175
  async _login_vault_ssh({path = 'ssh', role}) {
176
176
  logger.info("Trying to auth as '%s'", role);
177
- let sock;
178
- await new Promise(resolve => (sock = net.connect(process.env.SSH_AUTH_SOCK, resolve)));
179
- let agent = new SSHAgent(sock);
180
- let keys = Object.values(await agent.list_keys());
177
+
178
+
179
+ let agent = new OpenSSHAgent(process.env.SSH_AUTH_SOCK);
180
+ let keys = await promiser(chain => agent.getIdentities(chain));
181
+
181
182
 
182
183
  let token;
183
- await eachLimit(keys, 1, async ({type, ssh_key, fingerprint, comment}) => {
184
+ await eachLimit(keys, 1, async (pubKey) => {
184
185
  if(token)
185
186
  return;
186
187
 
187
- let remote_url = `${trim(this.vault_addr, '/')}/v1/auth/${path}/nonce`;
188
+ let remote_url = `${trim(this.VAULT_ADDR, '/')}/v1/auth/${path}/nonce`;
188
189
  let query = {...url.parse(remote_url), json : true};
189
190
  let res = await request(query);
190
191
  let {data : {nonce}} = JSON.parse(String(await drain(res)));
191
192
 
192
- const public_key = `${type} ${ssh_key}`;
193
- const {signature} = await agent.sign(fingerprint, Buffer.from(nonce));
194
-
193
+ const signature = (await promiser(chain => agent.sign(pubKey, Buffer.from(nonce), {}, chain))).toString('base64');
194
+ const public_key = pubKey.type + ' ' + pubKey.getPublicSSH().toString('base64');
195
195
  const payload = {public_key, role, nonce : Buffer.from(nonce).toString('base64'), signature};
196
196
  try {
197
197
  token = await this._login_vault(path, payload);
198
198
  } catch(err) {
199
- logger.debug("ssh : invalid challenge for public key", comment);
199
+ logger.debug("ssh : invalid challenge for public key", pubKey.comment);
200
200
  }
201
201
  });
202
202
 
203
- sock.destroy();
204
203
 
205
204
  if(!token)
206
205
  throw `Could not login to vault`;
@@ -227,7 +226,7 @@ class vvauth {
227
226
  }
228
227
 
229
228
  async _lookup_token(token) {
230
- let remote_url = `${trim(this.vault_addr, '/')}/v1/auth/token/lookup-self`;
229
+ let remote_url = `${trim(this.VAULT_ADDR, '/')}/v1/auth/token/lookup-self`;
231
230
  let query = {...url.parse(remote_url), headers : {'x-vault-token' : token}, expect : 200};
232
231
  let res = await request(query);
233
232
  let response = JSON.parse(await drain(res)).data;
@@ -235,14 +234,14 @@ class vvauth {
235
234
  }
236
235
 
237
236
  async _lookup_identity(token, id) {
238
- let remote_url = `${trim(this.vault_addr, '/')}/v1/identity/entity/id/${id}`;
237
+ let remote_url = `${trim(this.VAULT_ADDR, '/')}/v1/identity/entity/id/${id}`;
239
238
  let query = {...url.parse(remote_url), headers : {'x-vault-token' : token}, expect : 200};
240
239
  let res = await request(query);
241
240
  return JSON.parse(String(await drain(res))).data;
242
241
  }
243
242
 
244
243
  async _update_identity(token, id, payload) {
245
- let remote_url = `${trim(this.vault_addr, '/')}/v1/identity/entity/id/${id}`;
244
+ let remote_url = `${trim(this.VAULT_ADDR, '/')}/v1/identity/entity/id/${id}`;
246
245
  let query = {...url.parse(remote_url), headers : {'x-vault-token' : token}, expect : 204, json : true};
247
246
  await request(query, payload);
248
247
  return payload;
@@ -251,7 +250,7 @@ class vvauth {
251
250
 
252
251
 
253
252
  async _login_vault(path, payload) {
254
- let remote_url = `${trim(this.vault_addr, '/')}/v1/auth/${path}/login`;
253
+ let remote_url = `${trim(this.VAULT_ADDR, '/')}/v1/auth/${path}/login`;
255
254
  let query = {...url.parse(remote_url), json : true};
256
255
  let res = await request(query, payload);
257
256
  let response = String(await drain(res));
@@ -266,6 +265,10 @@ class vvauth {
266
265
 
267
266
  }
268
267
 
268
+ const shellEscape = (arg) => {
269
+ return arg.replace(/([$!'"();`*?{}[\]<>&%#~@\\ ])/g, '\\$1');
270
+ };
271
+
269
272
  //ensure module is called directly, i.e. not required
270
273
  if(module.parent === null)
271
274
  require('cnyks/lib/bundle')(vvauth);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vvauth",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "description": "Vault Auth helper",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -15,9 +15,9 @@
15
15
  "cnyks": "^3.0.6",
16
16
  "debug": "^4.3.4",
17
17
  "mout": "^1.0.0",
18
- "nyks": "^6.9.1",
18
+ "nyks": "^6.15.0",
19
19
  "semver": "^7.5.4",
20
- "ssh-agent-js": "^2.0.4",
20
+ "ssh2": "^1.16.0",
21
21
  "yaml": "^2.6.1"
22
22
  },
23
23
  "devDependencies": {