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.
- package/index.js +100 -27
- 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('
|
|
26
|
-
info : debug('
|
|
27
|
-
error : debug('
|
|
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
|
-
|
|
42
|
-
|
|
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
|
-
|
|
48
|
-
|
|
49
|
+
this.vault_addr = this.rc.vault_addr;
|
|
50
|
+
|
|
51
|
+
if(!this.vault_addr)
|
|
49
52
|
throw `Invalid vault remote`;
|
|
50
|
-
|
|
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
|
|
54
|
-
let {
|
|
58
|
+
async connect() {
|
|
59
|
+
let {VAULT_TOKEN, rc : {ssh_auth, jwt_auth}} = this;
|
|
55
60
|
|
|
56
|
-
|
|
57
|
-
|
|
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(!
|
|
64
|
+
if(!VAULT_TOKEN && jwt_auth && jwt_auth.jwt) {
|
|
61
65
|
let {path, jwt, role} = jwt_auth, payload = {jwt, role};
|
|
62
|
-
|
|
66
|
+
VAULT_TOKEN = await this._login_vault(path, payload);
|
|
63
67
|
}
|
|
64
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
|
141
|
-
let remote_url = `${trim(vault_addr, '/')}/v1/auth
|
|
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
|
}
|