Files
gcp-wif-test/vault_create_user.mjs
T

61 lines
1.9 KiB
JavaScript

#!/usr/bin/env node
import { createInterface } from "node:readline";
import { parseArgs } from "node:util";
const { values, positionals } = parseArgs({
allowPositionals: true,
options: {
policy: { type: "string", multiple: true, default: [] },
"token-ttl": { type: "string", default: "15m" },
"token-max-ttl": { type: "string", default: "1h" },
},
});
const [username] = positionals;
const policies = values.policy;
const address = process.env.VAULT_ADDR;
const token = process.env.VAULT_TOKEN;
if (!username || policies.length === 0 || !address || !token) {
console.error(
"Usage: VAULT_ADDR=... VAULT_TOKEN=... vault_create_user.mjs --policy POLICY [--policy POLICY...] [--token-ttl TTL] [--token-max-ttl TTL] USERNAME",
);
process.exit(1);
}
// Without an output stream readline does not echo the typed characters.
const rl = createInterface({ input: process.stdin, terminal: process.stdin.isTTY });
const lines = rl[Symbol.asyncIterator]();
const ask = async (prompt) => {
process.stdout.write(prompt);
const { value } = await lines.next();
process.stdout.write("\n");
return value ?? "";
};
const password = await ask("Password: ");
const confirmation = await ask("Repeat the password: ");
rl.close();
if (password === "" || password !== confirmation) {
console.error("The passwords are empty or do not match");
process.exit(1);
}
const response = await fetch(`${address}/v1/auth/userpass/users/${username}`, {
method: "POST",
headers: { "X-Vault-Token": token, "Content-Type": "application/json" },
body: JSON.stringify({
password,
token_policies: policies,
token_ttl: values["token-ttl"],
token_max_ttl: values["token-max-ttl"],
}),
});
if (!response.ok) {
console.error(`Vault returned ${response.status}: ${await response.text()}`);
process.exit(1);
}
console.log(`The user ${username} was created with the policies: ${policies.join(", ")}`);