vvauth 0.1.4 → 0.2.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 (2) hide show
  1. package/index.js +100 -27
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -22,57 +22,59 @@ const replaceEnv = require('nyks/string/replaceEnv');
22
22
  const debug = require('debug');
23
23
 
24
24
  const logger = {
25
- debug : debug('dspp:secrets:debug'),
26
- info : debug('dspp:secrets:info'),
27
- error : debug('dspp:secrets:error'),
25
+ debug : debug('vvauth:debug'),
26
+ info : debug('vvauth:info'),
27
+ error : debug('vvauth:error'),
28
28
  };
29
29
 
30
30
 
31
- const VAUTH_RC = ".vauthrc";
31
+ const VAUTH_RC = [process.env.VAUTHRC, path.join(process.cwd(), ".vauthrc"), path.join(os.homedir(), ".vauthrc")];
32
32
  const FUNCTION_NAME = "vauth";
33
33
  const FUNCTION_DECL = "function vauth() { source <(/usr/bin/env vvauth --ir://raw --source --ir://run=$1 \"${@:2}\"); }";
34
34
 
35
35
  class vvauth {
36
36
  constructor(rc = null) {
37
+
37
38
  this.rc = {};
38
39
  if(rc) {
39
40
  this.rc = rc;
40
41
  } else {
41
- if(fs.existsSync(VAUTH_RC)) {
42
- let body = fs.readFileSync(VAUTH_RC, 'utf8');
42
+ let vauth_rc = VAUTH_RC.filter(path => path && fs.existsSync(path))[0];
43
+ if(vauth_rc) {
44
+ let body = fs.readFileSync(vauth_rc, 'utf8');
43
45
  this.rc = walk(parse(body), v => replaceEnv(v, { env : process.env}));
44
46
  }
45
47
  }
46
48
 
47
- let {vault_addr} = this.rc;
48
- if(!vault_addr)
49
+ this.vault_addr = this.rc.vault_addr;
50
+
51
+ if(!this.vault_addr)
49
52
  throw `Invalid vault remote`;
50
- console.error("vauth bound to '%s'", vault_addr);
53
+
54
+ this.VAULT_TOKEN = process.env.VAULT_TOKEN;
55
+ console.error("vauth bound to '%s'", this.vault_addr);
51
56
  }
52
57
 
53
- async _get_token() {
54
- let {vault_addr, ssh_auth, jwt_auth} = this.rc;
58
+ async connect() {
59
+ let {VAULT_TOKEN, rc : {ssh_auth, jwt_auth}} = this;
55
60
 
56
- let token = this.rc.VAULT_TOKEN;
57
- if(!token && ssh_auth && process.env.SSH_AUTH_SOCK)
58
- token = await this._login_vault_ssh({...ssh_auth, vault_addr});
61
+ if(!VAULT_TOKEN && ssh_auth && process.env.SSH_AUTH_SOCK)
62
+ VAULT_TOKEN = await this._login_vault_ssh({...ssh_auth});
59
63
 
60
- if(!token && jwt_auth && jwt_auth.jwt) {
64
+ if(!VAULT_TOKEN && jwt_auth && jwt_auth.jwt) {
61
65
  let {path, jwt, role} = jwt_auth, payload = {jwt, role};
62
- token = await this._login_vault(vault_addr, path, payload);
66
+ VAULT_TOKEN = await this._login_vault(path, payload);
63
67
  }
64
- return token;
68
+ this.VAULT_TOKEN = VAULT_TOKEN;
65
69
  }
66
70
 
67
71
  async login(source = false) {
68
-
69
- let VAULT_TOKEN = await this._get_token();
72
+ await this.connect();
70
73
  if(source) {
71
- let env = {VAULT_TOKEN};
74
+ let env = {VAULT_TOKEN : this.VAULT_TOKEN};
72
75
  this._publish_env(env);
73
76
  process.exit();
74
77
  }
75
- return VAULT_TOKEN;
76
78
  }
77
79
 
78
80
  _publish_env(env) {
@@ -84,7 +86,55 @@ class vvauth {
84
86
  process.stdout.write(cmds.join("\n") + "\n");
85
87
  }
86
88
 
87
- async _login_vault_ssh({vault_addr, path = 'ssh', role}) {
89
+
90
+ async set(k, v) {
91
+ let {entity_id, identity : {metadata}} = await this._get_profile();
92
+ if(!metadata)
93
+ metadata = {};
94
+ let key_name = `env_${k.toUpperCase()}`;
95
+ metadata[key_name] = v;
96
+ await this._update_identity(this.VAULT_TOKEN, entity_id, {metadata});
97
+ }
98
+
99
+ async unset(k) {
100
+ await this.set(k, undefined);
101
+ }
102
+
103
+ async show() {
104
+ let {profile} = await this._get_profile();
105
+ return profile;
106
+ }
107
+
108
+ async _get_profile() {
109
+ await this.connect();
110
+ let {entity_id} = await this._lookup_token(this.VAULT_TOKEN);
111
+ let identity = await this._lookup_identity(this.VAULT_TOKEN, entity_id);
112
+ let profile = {};
113
+ for(let alias of identity.aliases)
114
+ {for(let [k, v] of Object.entries(alias.custom_metadata || {}))
115
+ {if(k.startsWith('env_'))
116
+ profile[k.substr(4)] = v;}}
117
+ for(let [k, v] of Object.entries(identity.metadata || {}))
118
+ {if(k.startsWith('env_'))
119
+ profile[k.substr(4)] = v;}
120
+ return {entity_id, identity, profile};
121
+ }
122
+
123
+ async env(source = false) {
124
+ let {profile} = await this._get_profile();
125
+
126
+ let env = {VAULT_TOKEN : this.VAULT_TOKEN};
127
+ for(let [k, v] of Object.entries(this.rc.env || {}))
128
+ env[k] = profile[v];
129
+
130
+ if(source) {
131
+ this._publish_env(env);
132
+ process.exit();
133
+ }
134
+ }
135
+
136
+ async _login_vault_ssh({path = 'ssh', role}) {
137
+ logger.info("Trying to auth as '%s'", role);
88
138
  let sock;
89
139
  await new Promise(resolve => (sock = net.connect(process.env.SSH_AUTH_SOCK, resolve)));
90
140
  let agent = new SSHAgent(sock);
@@ -95,7 +145,7 @@ class vvauth {
95
145
  if(token)
96
146
  return;
97
147
 
98
- let remote_url = `${trim(vault_addr, '/')}/v1/auth/${path}/nonce`;
148
+ let remote_url = `${trim(this.vault_addr, '/')}/v1/auth/${path}/nonce`;
99
149
  let query = {...url.parse(remote_url), json : true};
100
150
  let res = await request(query);
101
151
  let {data : {nonce}} = JSON.parse(String(await drain(res)));
@@ -105,7 +155,7 @@ class vvauth {
105
155
 
106
156
  const payload = {public_key, role, nonce : Buffer.from(nonce).toString('base64'), signature};
107
157
  try {
108
- token = await this._login_vault(vault_addr, path, payload);
158
+ token = await this._login_vault(path, payload);
109
159
  } catch(err) {
110
160
  logger.debug("ssh : invalid challenge for public key", comment);
111
161
  }
@@ -137,8 +187,32 @@ class vvauth {
137
187
  console.error(`Installation ok, please \nsource ${bashrc_path}`);
138
188
  }
139
189
 
140
- async _login_vault(vault_addr, path, payload) {
141
- let remote_url = `${trim(vault_addr, '/')}/v1/auth/${path}/login`;
190
+ async _lookup_token(token) {
191
+ let remote_url = `${trim(this.vault_addr, '/')}/v1/auth/token/lookup-self`;
192
+ let query = {...url.parse(remote_url), headers : {'x-vault-token' : token}, expect : 200};
193
+ let res = await request(query);
194
+ let response = JSON.parse(await drain(res)).data;
195
+ return response;
196
+ }
197
+
198
+ async _lookup_identity(token, id) {
199
+ let remote_url = `${trim(this.vault_addr, '/')}/v1/identity/entity/id/${id}`;
200
+ let query = {...url.parse(remote_url), headers : {'x-vault-token' : token}, expect : 200};
201
+ let res = await request(query);
202
+ return JSON.parse(String(await drain(res))).data;
203
+ }
204
+
205
+ async _update_identity(token, id, payload) {
206
+ let remote_url = `${trim(this.vault_addr, '/')}/v1/identity/entity/id/${id}`;
207
+ let query = {...url.parse(remote_url), headers : {'x-vault-token' : token}, expect : 204, json : true};
208
+ await request(query, payload);
209
+ return payload;
210
+ }
211
+
212
+
213
+
214
+ async _login_vault(path, payload) {
215
+ let remote_url = `${trim(this.vault_addr, '/')}/v1/auth/${path}/login`;
142
216
  let query = {...url.parse(remote_url), json : true};
143
217
  let res = await request(query, payload);
144
218
  let response = String(await drain(res));
@@ -147,7 +221,6 @@ class vvauth {
147
221
  throw `Could not login to vault : ${response}`;
148
222
 
149
223
  response = JSON.parse(response);
150
- //console.log(response);
151
224
  let token = get(response, 'auth.client_token');
152
225
  return token;
153
226
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vvauth",
3
- "version": "0.1.4",
3
+ "version": "0.2.0",
4
4
  "description": "Vault Auth helper",
5
5
  "main": "index.js",
6
6
  "bin": {