@varius.io/framework 13.11.4 → 13.12.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/bin/vatom-vault-env.mjs +137 -0
- package/package.json +7 -3
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { spawn } from "child_process";
|
|
4
|
+
import fsp from "node:fs/promises";
|
|
5
|
+
import { format } from "node:util";
|
|
6
|
+
|
|
7
|
+
const vaultApiBase = process.env.VAULT_ENV_VAULT_API_BASE;
|
|
8
|
+
|
|
9
|
+
async function getKubernetesServiceAccountToken() {
|
|
10
|
+
const buffer = await fsp.readFile("/var/run/secrets/kubernetes.io/serviceaccount/token");
|
|
11
|
+
return buffer.toString("utf8");
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async function fetchVaultTokenViaKubernetesAuth(role) {
|
|
15
|
+
const jwt = await getKubernetesServiceAccountToken();
|
|
16
|
+
|
|
17
|
+
const res = await fetch(`${vaultApiBase}/v1/auth/kubernetes/login`, {
|
|
18
|
+
method: "POST",
|
|
19
|
+
headers: { "content-type": "application/json" },
|
|
20
|
+
body: JSON.stringify({ role, jwt }),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
if (!res.ok) {
|
|
24
|
+
throw new Error(
|
|
25
|
+
format(
|
|
26
|
+
`Error fetching vault token via kubernetes auth, role=%j, httpStatusCode=%j`,
|
|
27
|
+
role,
|
|
28
|
+
res.status
|
|
29
|
+
)
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const resBody = await res.json();
|
|
34
|
+
return resBody.auth.client_token;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function getVaultToken() {
|
|
38
|
+
const envToken = process.env.VAULT_ENV_VAULT_TOKEN;
|
|
39
|
+
const envRole = process.env.VAULT_ENV_ROLE;
|
|
40
|
+
|
|
41
|
+
if (envToken) {
|
|
42
|
+
return envToken;
|
|
43
|
+
} else if (envRole) {
|
|
44
|
+
return await fetchVaultTokenViaKubernetesAuth(envRole);
|
|
45
|
+
} else {
|
|
46
|
+
throw new Error("No available vault auth mechanism.");
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async function fetchSecret(secretPath) {
|
|
51
|
+
const res = await fetch(`${vaultApiBase}/v1/${secretPath}`, {
|
|
52
|
+
headers: { "X-Vault-Token": await getVaultToken() },
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
if (!res.ok) {
|
|
56
|
+
throw new Error(
|
|
57
|
+
format(`Failed to fetch secret, secretPath=%j, httpStatusCode=%j`, secretPath, res.status)
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const resBody = await res.json();
|
|
62
|
+
return resBody.data;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const resolvedSecrets = new Map();
|
|
66
|
+
|
|
67
|
+
export async function resolveEnv() {
|
|
68
|
+
const newEnv = {};
|
|
69
|
+
const secretEnvVars = [];
|
|
70
|
+
|
|
71
|
+
for (const [envKey, envValue] of Object.entries(process.env)) {
|
|
72
|
+
if (envValue.startsWith("vault:")) {
|
|
73
|
+
const [secretPath, secretPropertyName] = envValue.split("vault:")[1].split("#");
|
|
74
|
+
secretEnvVars.push({ envKey, secretPath, secretPropertyName });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async function getSecret(secretPath) {
|
|
79
|
+
resolvedSecrets.set(secretPath, await fetchSecret(secretPath));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const secretPaths = Array.from(new Set(secretEnvVars.map(envVar => envVar.secretPath)));
|
|
83
|
+
await Promise.all(secretPaths.map(getSecret));
|
|
84
|
+
|
|
85
|
+
for (const envVar of secretEnvVars) {
|
|
86
|
+
const secret = resolvedSecrets.get(envVar.secretPath);
|
|
87
|
+
const secretPropertyValue = secret.data[envVar.secretPropertyName];
|
|
88
|
+
newEnv[envVar.envKey] = secretPropertyValue;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return newEnv;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function spawnChildProcess() {
|
|
95
|
+
// remove this script's args (before "--" separator)
|
|
96
|
+
while (process.argv[0] !== "--") {
|
|
97
|
+
process.argv.shift();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// remove "--" separator
|
|
101
|
+
process.argv.shift();
|
|
102
|
+
|
|
103
|
+
const childCommand = process.argv.shift();
|
|
104
|
+
|
|
105
|
+
const child = spawn(childCommand, process.argv, {
|
|
106
|
+
cwd: process.cwd(),
|
|
107
|
+
env: process.env,
|
|
108
|
+
stdio: "inherit",
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
child.on("error", function(e) {
|
|
112
|
+
console.error(e);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async function main() {
|
|
117
|
+
// need to temporarily allow self-signed certs
|
|
118
|
+
const oldRejectUnauthorized = process.env.NODE_TLS_REJECT_UNAUTHORIZED;
|
|
119
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
|
120
|
+
|
|
121
|
+
const newEnv = await setupEnv();
|
|
122
|
+
|
|
123
|
+
// reset self-signed cert permission, for the child process
|
|
124
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = oldRejectUnauthorized;
|
|
125
|
+
|
|
126
|
+
process.env = { ...process.env, ...newEnv };
|
|
127
|
+
|
|
128
|
+
for (const key of Object.keys(process.env)) {
|
|
129
|
+
if (key.startsWith("VAULT_ENV")) {
|
|
130
|
+
delete process.env[key];
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
spawnChildProcess();
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
main();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@varius.io/framework",
|
|
3
|
-
"version": "13.
|
|
3
|
+
"version": "13.12.0",
|
|
4
4
|
"main": "./build/index.js",
|
|
5
5
|
"type": "./build/index.d.ts",
|
|
6
6
|
"scripts": {
|
|
@@ -79,6 +79,10 @@
|
|
|
79
79
|
},
|
|
80
80
|
"homepage": "https://github.com/VariusIO/framework#readme",
|
|
81
81
|
"files": [
|
|
82
|
-
"build"
|
|
83
|
-
|
|
82
|
+
"build",
|
|
83
|
+
"bin"
|
|
84
|
+
],
|
|
85
|
+
"bin": {
|
|
86
|
+
"vatom-vault-env": "bin/vatom-vault-env.mjs"
|
|
87
|
+
}
|
|
84
88
|
}
|