UNPKG

@lumigo/serverless-crossaccount-ssm

Version:

Serverless framework plugin to access the system and secrets managers at isolated account

101 lines (85 loc) 2.75 kB
const _ = require("lodash"); const AWS = require("aws-sdk"); const util = require("util"); const PromiseAny = require("promise.any"); class CrossaccountSSM { constructor(serverless, options) { this.serverless = serverless; this.options = options; this.log = msg => this.serverless.cli.log(`crossaccount-ssm: ${msg}`); this.verboseLog = msg => { if (process.env.SLS_DEBUG) { this.log(msg); } }; // NOTE: config load is deferred to resolver due to the late embedded variables evaluation this.config = null; this.ssmResolver = serverless.variables.variableResolvers.find( ({ serviceName }) => serviceName === "SSM" ); if (this.ssmResolver) { this.ssmResolver.resolver = this.resolver.bind(this); this.verboseLog( "Default SSM resolver was replaced with the crossaccount one" ); } } async resolver(name) { const [, , key] = name.match(this.ssmResolver.regex) || []; if (!key) return Promise.resolve(); this.verboseLog(`Resolving ${key}`); if (!this.config) this.config = this.getConfig(); const validTrues = new Set(["True", "true", "Yes", "yes", true]); const enabled = validTrues.has(_.get(this.config, "enable", true)); // NOTE: the reason it exists is that I currently cant understand the evaluation order // FIXME: this N/A-workaround should be wiped-up const nonAvailableMarker = "NA"; if (key.includes(nonAvailableMarker)) { this.verboseLog( `Resolving skipped due to the resolution disabled (secret name contains '${nonAvailableMarker}' marker: ${key})` ); return key; } if (enabled) { AWS.config.credentials = new AWS.SharedIniFileCredentials({ profile: this.config.profile }); const secretParam = { Name: key, WithDecryption: true }; let replicas = _.chain(this.config.regions).map(r => new AWS.SSM({ region: r }) .getParameter(secretParam) .promise() .then(s => s.Parameter.Value) ); return PromiseAny(replicas.value()).catch(error => { this.log( "multi-regional failure (all the regions requested were rejected)" ); throw error; }); } else { this.verboseLog( `Resolving skipped due to the resolution disabled (enable: ${enabled})` ); return key; } } getConfig() { const configKey = "custom.crossaccount-ssm"; const currentConfig = _.get(this.serverless.service, configKey, null); const defaultConfig = { profile: "default", regions: ["us-east-1"] }; if (!currentConfig) { this.verboseLog( `config wasn't found. Defaulted to: ${util.inspect(defaultConfig)}` ); return defaultConfig; } else { this.verboseLog(`config found: ${util.inspect(currentConfig)}`); return currentConfig; } } } module.exports = CrossaccountSSM;