UNPKG

hashi-vault-js

Version:

A node.js module to interact with the Hashicorp Vault API.

2,008 lines (1,847 loc) 107 kB
/* * The accompanying program is provided under the terms of the MIT license ("agreement"). * Written by Rod Anami <rod.anami@kyndryl.com>, June 2020. */ // Go to strict mode to be safer "use strict"; import { config } from './Config.js'; // I personally prefer request, but it's deprecated now import axios from 'axios'; //const _ = require('underscore'); import https from 'https'; import fs from 'fs'; import assert from 'assert'; // Internal function - create new https agent const getHttpsAgent = function(certificate, key, cacert) { const options = {} if(cacert) { // CA cert from Hashicorp Vault PKI options.ca = fs.readFileSync(cacert) } if(certificate || key) { // Client certificate options.cert = fs.readFileSync(certificate) options.key = fs.readFileSync(key) } return new https.Agent(options); } // Internal function - creates new axios instance const getAxiosInstance = function(baseurl, timeout, agent, proxy, namespace) { return axios.create({ baseURL: baseurl, timeout: timeout, headers: { 'X-Application-Name': config.appName, 'X-Vault-Namespace': namespace, }, httpsAgent: agent, proxy: proxy }); } // Internal function - parse axios response const parseAxiosResponse = function(response){ let message = {}; if (response.data.auth) { message = response.data.auth; } else if (response.data.data){ message = response.data.data; } else if (response.data) { message = response.data; } else { message['status']= response.status; message['statusText'] = response.statusText; } return message; } // Internal function - parse axios error const parseAxiosError = function(error){ let helpMessage = ""; // Fix the stack // passing parseAxiosError as the second param will leave this function out of the trace Error.captureStackTrace(error, parseAxiosError); // Verify if it's a Vault error // https://www.vaultproject.io/api-docs#error-response if (error.response && error.response.status) { error.isVaultError = true; switch(error.response.status){ case 400: helpMessage = "Invalid request, missing or invalid data."; break; case 403: helpMessage = "Forbidden, your authentication details are either incorrect, you don't have access to this feature, or - if CORS is enabled - you made a cross-origin request from an origin that is not allowed to make such requests."; break; case 404: helpMessage = "Invalid path. This can both mean that the path truly doesn't exist or that you don't have permission to view a specific path. We use 404 in some cases to avoid state leakage."; break; case 429: helpMessage = "Default return code for health status of standby nodes. This will likely change in the future."; break; case 473: helpMessage = "Default return code for health status of performance standby nodes."; break; case 500: helpMessage = "Internal server error. An internal error has occurred, try again later. If the error persists, report a bug."; break; case 502: helpMessage = "A request to Vault required Vault making a request to a third party; the third party responded with an error of some kind."; break; case 503: helpMessage = "Vault is down for maintenance or is currently sealed. Unseal it or Try again later."; break; default: helpMessage = "Unkown error code or helper is not implemented yet."; } error.vaultHelpMessage = helpMessage; } return error; } // main class constructor /** * @constructor * @param {boolean} [params.https=false] * @param {string} [params.cert] * @param {string} [params.key] * @param {string} [params.cacert] * @param {string} [params.baseUrl] * @param {string} [params.rootPath] * @param {number} [params.timeout=1000] * @param {boolean} [params.proxy=false] * @param {string} [params.namespace] */ export default class Vault { constructor(params) { /** @type {boolean} */ this.https = params.https || false; /** @type {string} */ this.cert = params.cert; /** @type {string} */ this.key = params.key; /** @type {string} */ this.cacert = params.cacert; /** @type {string} */ this.baseUrl = params.baseUrl || config.baseUrl; /** @type {string} */ this.rootPath = params.rootPath; /** @type {number} */ this.timeout = params.timeout || config.timeout; /** @type {Object} */ this.proxy = params.proxy || config.proxy; /** @type {string} */ this.namespace = params.namespace || config.namespace; try { if (this.https) { /** @type {Object | boolean} */ this.agent = getHttpsAgent(this.cert, this.key, this.cacert); } else { this.agent = false; } /** @type {Object} */ this.instance = getAxiosInstance(this.baseUrl, this.timeout, this.agent, this.proxy, this.namespace); } catch (error) { console.error('Error initiating Vault class:\n', error); } } // /sys API endpoints /** * @param {Object} [params] * @returns {PromiseLike<Object>} */ async healthCheck(params){ const Options = { url: config.sysHealth, method: 'get', params: params, headers: { "X-Vault-Namespace": '' // https://www.vaultproject.io/docs/enterprise/namespaces#root-only-api-paths } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @returns {PromiseLike<Object>} */ async sealStatus(){ const Options = { url: config.sysSealStatus, method: 'get' }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} sudoToken * @returns {PromiseLike<Object>} */ async sysHostInfo(sudoToken){ const Options = { url: config.sysHostInfo, method: 'get', headers: { "X-Vault-Token": sudoToken, "X-Vault-Namespace": '' // https://www.vaultproject.io/docs/enterprise/namespaces#root-only-api-paths } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} sudoToken * @param {string} token * @param {string[]} paths * @returns {PromiseLike<Object>} */ async sysCapabilities(sudoToken, token, paths){ const Options = { url: config.sysCapabilities, method: 'post', headers: { "X-Vault-Token": sudoToken }, data: { token: token, paths: paths } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} token * @param {string[]} paths * @returns {PromiseLike<Object>} */ async sysCapabilitiesSelf(token, paths){ const Options = { url: config.sysCapabilitiesSelf, method: 'post', headers: { "X-Vault-Token": token }, data: { paths: paths } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} sudoToken * @param {string} type * @returns {PromiseLike<Object>} */ async sysInternalCounters(sudoToken, type) { let message = {}; if (config.sysCounterTypes.includes(type)) { const Options = { url: `${config.sysInternalCounters}/${type}`, method: 'get', headers: { "X-Vault-Token": sudoToken } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } else { message['status']= 400; message['statusText'] = 'Bad request: Counter type error'; reject(new Error(message)); } } /** * @param {string} sudoToken * @param {string} [format] * @returns {PromiseLike<Object>} */ async sysMetrics(sudoToken, format){ const Options = { url: '', method: 'get', headers: { "X-Vault-Token": sudoToken, "X-Vault-Namespace": '' // https://www.vaultproject.io/docs/enterprise/namespaces#root-only-api-paths } }; if (config.sysMetricFormats.includes(format)) { Options.url= `${config.sysMetrics}?format=${format}`; } else { Options.url= `${config.sysMetrics}`; } const xvn = this.instance.defaults.headers['X-Vault-Namespace']; this.instance.defaults.headers['X-Vault-Namespace'] = ''; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } finally { this.instance.defaults.headers['X-Vault-Namespace'] = xvn; } } /** * @param {string} sudoToken * @returns {PromiseLike<Object>} */ async sysSeal(sudoToken){ const Options = { url: config.sysSeal, method: 'put', headers: { "X-Vault-Token": sudoToken } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} sudoToken * @param {string} key * @param {boolean} reset * @param {boolean} migrate * @returns {PromiseLike<Object>} */ async sysUnseal(sudoToken, key, reset, migrate){ const Options = { url: config.sysUnseal, method: 'put', headers: { "X-Vault-Token": sudoToken }, data: { "key": key, "reset": reset, "migrate": migrate } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } // // Token auth method API endpoints // The token method is built-in and automatically available at /auth/token. // /** * @param {string} vaultToken * @param {Object} [params] * @param {string} [params.id] * @param {string} [params.role_name] * @param {string} [params.policies] * @param {Object} [params.meta] * @param {boolean} [params.no_narent=false] * @param {boolean} [params.no_default_policy=false] * @param {boolean} [params.renewable=true] * @param {string} [params.ttl] * @param {string} [params.type=service] * @param {string} [params.explicit_max_ttl] * @param {string} [params.display_name] * @param {number} [params.num_uses] * @param {string} [params.period] * @param {string} [params.entity_alias] * @returns {PromiseLike<Object>} */ async createToken(vaultToken, params) { assert(vaultToken, 'createToken: required parameter missing: vaultToken'); // Defaults - most are probably already defaults from Vault itself params = { no_parent: false, no_default_policy: false, renewable: true, type: 'service', // display_name: '', ...params }; const { id, role_name, policies, meta, no_parent, no_default_policy, renewable, ttl, type, explicit_max_ttl, display_name, num_uses, period, entity_alias } = params; const url = role_name ? `${config.tokenCreate}/${role_name}` : config.tokenCreate; const Options = { url, method: 'post', headers: { "X-Vault-Token": vaultToken }, data: { id, policies, meta, no_parent, no_default_policy, renewable, ttl, type, explicit_max_ttl, display_name, num_uses, period, entity_alias } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} vaultToken * @param {string} clientToken * @returns {PromiseLike<Object>} */ async revokeToken(vaultToken, clientToken) { const Options = { url: config.tokenRevoke, method: 'post', headers: { "X-Vault-Token": vaultToken }, data: { token: clientToken } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} clientToken * @returns {PromiseLike<Object>} */ async revokeSelfToken(clientToken) { const Options = { url: config.tokenRevokeSelf, method: 'post', headers: { "X-Vault-Token": clientToken } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} vaultToken * @param {string} clientToken * @returns {PromiseLike<Object>} */ async lookupToken(vaultToken, clientToken) { const Options = { url: config.tokenLookup, method: 'post', headers: { "X-Vault-Token": vaultToken }, data: { token: clientToken } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} clientToken * @returns {PromiseLike<Object>} */ async lookupSelfToken(clientToken) { const Options = { url: config.tokenLookupSelf, method: 'get', headers: { "X-Vault-Token": clientToken } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} vaultToken * @param {string} clientToken * @param {string} increment * @returns {PromiseLike<Object>} */ async renewToken(vaultToken, clientToken, increment) { const Options = { url: config.tokenRenew, method: 'post', headers: { "X-Vault-Token": vaultToken }, data: { token: clientToken, increment: increment } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} clientToken * @param {string} increment * @returns {PromiseLike<Object>} */ async renewSelfToken(clientToken, increment) { const Options = { url: config.tokenRenewSelf, method: 'post', headers: { "X-Vault-Token": clientToken }, data: { increment: increment } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} sudoToken * @returns {PromiseLike<Object>} */ async listAccessors(sudoToken) { const Options = { url: config.tokenListAccessors, method: 'list', headers: { "X-Vault-Token": sudoToken } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} vaultToken * @param {string} accessor * @returns {PromiseLike<Object>} */ async lookupAccessor(vaultToken, accessor) { const Options = { url: config.tokenLookupAccessor, method: 'post', headers: { "X-Vault-Token": vaultToken }, data: { accessor: accessor } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} vaultToken * @param {string} accessor * @param {string} increment * @returns {PromiseLike<Object>} */ async renewAccessor(vaultToken, accessor, increment) { const Options = { url: config.tokenRenewAccessor, method: 'post', headers: { "X-Vault-Token": vaultToken }, data: { accessor: accessor, increment: increment || null } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} vaultToken * @param {string} accessor * @returns {PromiseLike<Object>} */ async revokeAccessor(vaultToken, accessor) { const Options = { url: config.tokenRevokeAccessor, method: 'post', headers: { "X-Vault-Token": vaultToken }, data: { accessor: accessor } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } // // ldap auth method API endpoints // /** * @param {string} username * @param {string} password * @param {string} [mount] * @returns {Object} */ async loginWithLdap(username, password, mount) { let rootPath= ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.ldapRootPath; } const Options = { url: `${rootPath}/${config.ldapLogin[0]}/${username}`, method: config.ldapLogin[1], data: { password: password } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} token * @param {string} username * @param {string[]} policies * @param {string} groups * @param {string} [mount] * @returns {PromiseLike<Object>} */ async createLdapUser(token, username, policies, groups, mount) { let rootPath= ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.ldapRootPath; } const Options = { url: `${rootPath}/${config.ldapCreateUser[0]}/${username}`, method: config.ldapCreateUser[1], headers: { "X-Vault-Token": token }, data: { policies: policies, groups: groups } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} token * @param {string} username * @param {string[]} policies * @param {string} groups * @param {string} [mount] * @returns {PromiseLike<Object>} */ async updateLdapUser(token, username, policies, groups, mount) { return await this.createLdapUser(token, username, policies, groups, mount); } /** * @param {string} token * @param {string} group * @param {string[]} policies * @param {string} [mount] * @returns {PromiseLike<Object>} */ async createLdapGroup(token, group, policies, mount) { let rootPath= ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.ldapRootPath; } const Options = { url: `${rootPath}/${config.ldapCreateGroup[0]}/${group}`, method: config.ldapCreateGroup[1], headers: { "X-Vault-Token": token }, data: { policies: policies } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} token * @param {string} group * @param {string[]} policies * @param {string} [mount] * @returns {PromiseLike<Object>} */ async updateLdapGroup(token, group, policies, mount) { return await this.createLdapGroup(token, group, policies, mount); } /** * @param {string} token * @param {string} group * @param {string} [mount] * @returns {PromiseLike<Object>} */ async readLdapGroup(token, group, mount) { let rootPath= ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.ldapRootPath; } const Options = { url: `${rootPath}/${config.ldapReadGroup[0]}/${group}`, method: config.ldapReadGroup[1], headers: { "X-Vault-Token": token } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} token * @param {string} username * @param {string} [mount] * @returns {PromiseLike<Object>} */ async readLdapUser(token, username, mount) { let rootPath= ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.ldapRootPath; } const Options = { url: `${rootPath}/${config.ldapReadUser[0]}/${username}`, method: config.ldapReadUser[1], headers: { "X-Vault-Token": token } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} token * @param {string} [mount] * @returns {PromiseLike<Object>} */ async listLdapUsers(token, mount) { let rootPath= ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.ldapRootPath; } const Options = { url: `${rootPath}/${config.ldapListUsers[0]}`, method: config.ldapListUsers[1], headers: { "X-Vault-Token": token } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} token * @param {string} [mount] * @returns {PromiseLike<Object>} */ async listLdapGroups(token, mount) { let rootPath= ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.ldapRootPath; } const Options = { url: `${rootPath}/${config.ldapListGroups[0]}`, method: config.ldapListGroups[1], headers: { "X-Vault-Token": token } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} token * @param {string} username * @param {string} [mount] * @returns {PromiseLike<Object>} */ async deleteLdapUser(token, username, mount) { let rootPath= ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.ldapRootPath; } const Options = { url: `${rootPath}/${config.ldapDeleteUser[0]}/${username}`, method: config.ldapDeleteUser[1], headers: { "X-Vault-Token": token } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} token * @param {string} group * @param {string} [mount] * @returns {PromiseLike<Object>} */ async deleteLdapGroup(token, group, mount) { let rootPath= ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.ldapRootPath; } const Options = { url: `${rootPath}/${config.ldapDeleteGroup[0]}/${group}`, method: config.ldapDeleteGroup[1], headers: { "X-Vault-Token": token } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} token * @param {string} [mount] * @returns {PromiseLike<Object>} */ async readLdapConfig(token, mount) { let rootPath= ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.ldapRootPath; } const Options = { url: `${rootPath}/${config.ldapReadConfig[0]}`, method: config.ldapReadConfig[1], headers: { "X-Vault-Token": token } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} token * @param {string} [mount] * @param {Object} [params] * @param {string} params.url * @param {boolean} params.case_sensitive_names * @param {number} params.request_timeout * @param {boolean} params.starttls * @param {string} params.tls_min_version * @param {string} params.tls_max_version * @param {boolean} params.insecure_tls * @param {string} params.certificate * @param {string} params.client_tls_cert * @param {string} params.client_tls_key * @param {string} params.binddn * @param {string} params.bindpass * @param {string} params.userdn * @param {string} params.userattr * @param {boolean} params.discoverdn * @param {boolean} params.deny_null_bind * @param {string} params.upndomain * @param {string} params.userfilter * @param {boolean} params.anonymous_group_search * @param {string} params.groupfilter * @param {string} params.groupdn * @param {string} params.groupattr * @param {boolean} params.username_as_alias * @param {number} params.token_ttl * @param {number} params.token_max_ttl * @param {string[]} params.token_policies * @param {string[]} params.token_bound_cidrs * @param {number} params.token_explicit_max_ttl * @param {boolean} params.token_no_default_policy * @param {number} params.token_num_uses * @param {number} params.token_period * @param {string} params.token_type * @returns {PromiseLike<Object>} */ async setLdapConfig(token, params, mount) { let rootPath= ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.ldapRootPath; } const Options = { url: `${rootPath}/${config.ldapSetConfig[0]}`, method: config.ldapSetConfig[1], headers: { "X-Vault-Token": token }, data: { url: params.url, case_sensitive_names: params.case_sensitive_names, request_timeout: params.request_timeout, starttls: params.starttls, tls_min_version: params.tls_min_version, tls_max_version: params.tls_max_version, insecure_tls: params.insecure_tls, certificate: params.certificate, client_tls_cert: params.client_tls_cert, client_tls_key: params.client_tls_key, binddn: params.binddn, bindpass: params.bindpass, userdn: params.userdn, userattr: params.userattr, discoverdn: params.discoverdn, deny_null_bind: params.deny_null_bind, upndomain: params.upndomain, userfilter: params.userfilter, anonymous_group_search: params.anonymous_group_search, groupfilter: params.groupfilter, groupdn: params.groupdn, groupattr: params.groupattr, username_as_alias: params.username_as_alias, token_ttl: params.token_ttl, token_max_ttl: params.token_max_ttl, token_policies: params.token_policies, token_bound_cidrs: params.token_bound_cidrs, token_explicit_max_ttl: params.token_explicit_max_ttl, token_no_default_policy: params.token_no_default_policy, token_num_uses: params.token_num_uses, token_period: params.token_period, token_type: params.token_type } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } // // TLS Certificate auth method API endpoints // /** * @param {string} [mount] * @param {string} certName * @returns {PromiseLike<Object>} */ async loginWithCert(certName, mount) { let rootPath= ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.certRootPath; } const Options = { url: `${rootPath}/${config.certLogin[0]}`, method: config.certLogin[1], data: { name: certName } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } // // Userpass auth method API endpoints // /** * @param {string} username * @param {string} password * @param {string} [mount] * @returns {PromiseLike<Object>} */ async loginWithUserpass(username, password, mount) { let rootPath= ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.userpassRootPath; } const Options = { url: `${rootPath}/${config.userpassLogin[0]}/${username}`, method: config.userpassLogin[1], data: { password: password } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} token * @param {string} username * @param {string} password * @param {string[]} policies * @param {string} [mount] * @returns {PromiseLike<Object>} */ async createUserpassUser(token, username, password, policies, mount) { let rootPath= ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.userpassRootPath; } const Options = { url: `${rootPath}/${config.userpassCreateUser[0]}/${username}`, method: config.userpassCreateUser[1], headers: { "X-Vault-Token": token }, data: { policies: policies, password: password } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} token * @param {string} username * @param {string} password * @param {string[]} policies * @param {string} [mount] * @returns {PromiseLike<Object>} */ async updateUserpassUser(token, username, password, policies, mount) { return await this.createUserpassUser(token, username, password, policies, mount); } /** * @param {string} token * @param {string} username * @param {string} [mount] * @returns {PromiseLike<Object>} */ async readUserpassUser(token, username, mount) { let rootPath= ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.userpassRootPath; } const Options = { url: `${rootPath}/${config.userpassReadUser[0]}/${username}`, method: config.userpassReadUser[1], headers: { "X-Vault-Token": token } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} token * @param {string} username * @param {string} [mount] * @returns {PromiseLike<Object>} */ async deleteUserpassUser(token, username, mount) { let rootPath= ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.userpassRootPath; } const Options = { url: `${rootPath}/${config.userpassDeleteUser[0]}/${username}`, method: config.userpassDeleteUser[1], headers: { "X-Vault-Token": token } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} token * @param {string} username * @param {string} password * @param {string} [mount] * @returns {PromiseLike<Object>} */ async updateUserpassPassword(token, username, password, mount) { let rootPath= ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.userpassRootPath; } const Options = { url: `${rootPath}/${config.userpassUpdatePass[0]}/${username}/password`, method: config.userpassUpdatePass[1], headers: { "X-Vault-Token": token }, data: { password: password } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} token * @param {string} username * @param {string[]} policies * @param {string} [mount] * @returns {PromiseLike<Object>} */ async updateUserpassPolicies(token, username, policies, mount) { let rootPath= ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.userpassRootPath; } const Options = { url: `${rootPath}/${config.userpassUpdatePolicies[0]}/${username}/policies`, method: config.userpassUpdatePolicies[1], headers: { "X-Vault-Token": token }, data: { policies: policies } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} token * @param {string} [mount] * @returns {PromiseLike<Object>} */ async listUserpassUsers(token, mount) { let rootPath= ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.userpassRootPath; } const Options = { url: `${rootPath}/${config.userpassListUsers[0]}`, method: config.userpassListUsers[1], headers: { "X-Vault-Token": token } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } // // Kubernetes auth method API endpoints // /** * @param {string} role * @param {string} jwt * @param {string} [mount] * @returns {Object} */ async loginWithK8s(role, jwt, mount) { assert(role, 'loginWithK8s: required parameter missing: role'); assert(jwt, 'loginWithK8s: required parameter missing: jwt'); let rootPath= ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.k8sRootPath; } const Options = { url: `${rootPath}/${config.k8sLogin[0]}`, method: config.k8sLogin[1], data: { role: role, jwt: jwt } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} token * @param {Object} params * @param {string} params.kubernetes_host * @param {string} params.kubernetes_ca_cert * @param {string} params.token_reviewer_jwt * @param {Object} [params.pem_keys] * @param {string} params.issuer * @param {boolean} params.disable_iss_validation * @param {boolean} params.disable_local_ca_jwt * @param {string} [mount] * @returns {PromiseLike<Object>} */ async updateK8sConfig(token, params, mount) { assert(token, 'updateK8sConfig: required parameter missing: vault token'); // Defaults - most are probably already defaults from Vault itself params = { disable_iss_validation: false, disable_local_ca_jwt: false, ...params }; const { kubernetes_host, kubernetes_ca_cert, token_reviewer_jwt, pem_keys, issuer, disable_iss_validation, disable_local_ca_jwt } = params; let rootPath= ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.k8sRootPath; } const Options = { url: `${rootPath}/${config.k8sUpdateConfig[0]}`, method: config.k8sUpdateConfig[1], headers: { "X-Vault-Token": token }, data: { kubernetes_host, kubernetes_ca_cert, token_reviewer_jwt, pem_keys, issuer, disable_iss_validation, disable_local_ca_jwt } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} token * @param {string} [mount] * @returns {Object} */ async readK8sConfig(token, mount) { assert(token, 'readK8sConfig: required parameter missing: Vault admin token'); let rootPath= ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.k8sRootPath; } const Options = { url: `${rootPath}/${config.k8sReadConfig[0]}`, method: config.k8sReadConfig[1], headers: { "X-Vault-Token": token } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} token * @param {string} role * @param {Object} params * @param {Object} [params.bound_service_account_names] * @param {Object} [params.bound_service_account_namespaces] * @param {string} params.audience * @param {number | string} params.token_ttl * @param {number | string} params.token_max_ttl * @param {Object} [params.token_policies] * @param {Object} [params.token_bound_cidrs] * @param {number | string} params.token_explicit_max_ttl * @param {boolean} params.token_no_default_policy * @param {number} params.token_num_uses * @param {number | string} params.token_period * @param {string} params.token_type * @param {string} [mount] * @returns {Object} */ async createK8sRole(token, role, params, mount) { assert(token, 'createK8sRole: required parameter missing: Vault admin token'); assert(role, 'createK8sRole: required parameter missing: role'); // Defaults - most are probably already defaults from Vault itself params = { token_no_default_policy: false, token_num_uses: 0, ...params }; const { bound_service_account_names, bound_service_account_namespaces, audience, token_ttl, token_max_ttl, token_policies, token_bound_cidrs, token_explicit_max_ttl, token_no_default_policy, token_num_uses, token_period, token_type } = params; let rootPath= ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.k8sRootPath; } const Options = { url: `${rootPath}/${config.k8sCreateRole[0]}/${role}`, method: config.k8sCreateRole[1], headers: { "X-Vault-Token": token }, data: { bound_service_account_names, bound_service_account_namespaces, audience, token_ttl, token_max_ttl, token_policies, token_bound_cidrs, token_explicit_max_ttl, token_no_default_policy, token_num_uses, token_period, token_type } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} token * @param {string} role * @param {string} [mount] * @returns {Object} */ async readK8sRole(token, role, mount) { assert(token, 'readK8sRole: required parameter missing: Vault admin token'); let rootPath= ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.k8sRootPath; } const Options = { url: `${rootPath}/${config.k8sReadRole[0]}/${role}`, method: config.k8sReadRole[1], headers: { "X-Vault-Token": token } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} token * @param {string} [mount] * @returns {Object} */ async listK8sRoles(token, mount) { assert(token, 'listK8sRoles: required parameter missing: Vault admin token'); let rootPath= ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.k8sRootPath; } const Options = { url: `${rootPath}/${config.k8sListRoles[0]}`, method: config.k8sListRoles[1], headers: { "X-Vault-Token": token } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} token * @param {string} role * @param {string} [mount] * @returns {Object} */ async deleteK8sRole(token, role, mount) { assert(token, 'deleteK8sRole: required parameter missing: Vault admin token'); let rootPath= ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.k8sRootPath; } const Options = { url: `${rootPath}/${config.k8sDeleteRole[0]}/${role}`, method: config.k8sDeleteRole[1], headers: { "X-Vault-Token": token } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } // // AppRole auth method API endpoints // /** * @param {string} roleId * @param {string} secretId * @param {string} [mount] * @returns {Object} */ async loginWithAppRole(roleId, secretId, mount) { let rootPath= ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.appRoleRootPath; } const Options = { url: `${rootPath}/${config.appRoleLogin[0]}`, method: config.appRoleLogin[1], data: { role_id: roleId, secret_id: secretId } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} token * @param {string} appRole * @param {string} [metadata] * @param {string} [mount] * @returns {PromiseLike<Object>} */ async generateAppRoleSecretId(token, appRole, metadata, mount) { let rootPath= ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.appRoleRootPath; } const Options = { url: `${rootPath}/${config.appRoleCreateSecret[0]}/${appRole}/${config.appRoleCreateSecret[1]}`, method: config.appRoleCreateSecret[2], headers: { "X-Vault-Token": token }, data: { metadata: metadata } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} token * @param {string} appRole * @param {string} secretId * @param {string} [mount] * @returns {PromiseLike<Object>} */ async readAppRoleSecretId(token, appRole, secretId, mount) { let rootPath= ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.appRoleRootPath; } const Options = { url: `${rootPath}/${config.appRoleReadSecret[0]}/${appRole}/${config.appRoleReadSecret[1]}`, method: config.appRoleReadSecret[2], headers: { "X-Vault-Token": token }, data: { secret_id: secretId } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} token * @param {string} appRole * @param {string} secretId * @param {string} [mount] * @returns {PromiseLike<Object>} */ async destroyAppRoleSecretId(token, appRole, secretId, mount) { let rootPath= ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.appRoleRootPath; } const Options = { url: `${rootPath}/${config.appRoleDestroySecret[0]}/${appRole}/${config.appRoleDestroySecret[1]}`, method: config.appRoleDestroySecret[2], headers: { "X-Vault-Token": token }, data: { secret_id: secretId } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } // // PKI secret engine API endpoints // /** * @param {string} format - certificate format either 'der' or 'pem' * @param {string} [mount] * @returns {PromiseLike<string>} */ async readCACertificate(format, mount) { let url = ""; let rootPath= ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.pkiRootPath; } if (format === 'pem') { url = `${rootPath}/${config.pkiReadCACert[0]}/pem`; } else { url = `${rootPath}/${config.pkiReadCACert[0]}`; } const Options = { url: url, method: config.pkiReadCACert[1] }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} format - certificate format either 'der' or 'pem' * @param {string} [mount] * @returns {PromiseLike<string>} */ async readPkiCrl(format, mount) { let url = ""; let rootPath = ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.pkiRootPath; } if (format === 'pem') { url = `${rootPath}/${config.pkiReadCrl[0]}/pem`; } else { url = config.pkiReadCrl[0]; } const Options = { url: url, method: config.pkiReadCrl[1] }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} [mount] * @returns {PromiseLike<string>} */ async readCAChain(mount) { let rootPath = ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.pkiRootPath; } const Options = { url: `${rootPath}/${config.pkiReadCAChain[0]}`, method: config.pkiReadCAChain[1] }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} serial * @param {string} [mount] * @returns {PromiseLike<Object>} */ async readCertificate(serial, mount) { let rootPath = ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.pkiRootPath; } const Options = { url: `${rootPath}/${config.pkiReadCert[0]}/${serial}`, method: config.pkiReadCert[1] }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} token * @param {string} [mount] * @returns {PromiseLike<Object>} */ async listCertificates(token, mount) { let rootPath = ""; if (mount) { rootPath = mount; } else if (this.rootPath) { rootPath = this.rootPath; } else { rootPath = config.pkiRootPath; } const Options = { url: `${rootPath}/${config.pkiListCerts[0]}`, method: config.pkiListCerts[1], headers: { "X-Vault-Token": token } }; try { const response = await this.instance(Options); return parseAxiosResponse(response); } catch(err) { throw parseAxiosError(err); } } /** * @param {string} token * @param {string} pemBundle * @param {string} [mount] * @returns {PromiseLike<Object>}