serverless-env-generator
Version:
A Serverless 1.x plugin to automatically create a .env file during deployment by merging environment variables from one or more YAML files. Variables can be securely encrypted with KMS. Multiple stages and profiles are supported.
82 lines (73 loc) • 2.78 kB
JavaScript
const kms = require('./kms')
const path = require('path')
const yaml = require('./yaml')
const ENCRYPT_PREFIX = 'encrypted:'
// Reads & pre-processes env-vars for the specified stage from a YAML-document
const collectEnvVars = (doc, stage) => {
var envVars = []
if (doc && stage in doc) {
Object.keys(doc[stage]).forEach(attribute => {
var value = doc[stage][attribute]
let encrypted = (typeof value === 'string' && value.indexOf(ENCRYPT_PREFIX) === 0)
if (encrypted) value = value.substr(ENCRYPT_PREFIX.length)
envVars.push({ attribute, value, encrypted })
})
}
return envVars
}
// Reads environment files and returns the env-vars for the specified stage
const readEnvYamlFiles = (filePaths, stage) => {
return Promise.all(filePaths.map(filePath => {
return yaml.read(filePath).then(doc => {
let file = path.basename(filePath)
let vars = collectEnvVars(doc, stage)
return { file, filePath, doc, vars }
})
}))
}
// Helper to filter env-vars by attribute
const filterEnvVars = (envFiles, attribute) => {
envFiles.forEach(envFile => {
envFile.vars = envFile.vars.filter(_ => _.attribute === attribute)
})
return envFiles.filter(_ => _.vars.length > 0)
}
// Helper to decrypt all env vars
const decryptEnvVars = (envFiles, config) => {
return Promise.all(envFiles.map(envFile => {
return Promise.all(envFile.vars.map(envVar =>
envVar.encrypted
? kms.decrypt(envVar.value, config).then(value => Object.assign({}, envVar, { value }))
: Promise.resolve(envVar)
)).then(vars =>
Object.assign({}, envFile, { vars })
)
}))
}
// Returns all env-files with the env-vars
// The optional attribute allows you to limit the returned env-vars to a single attribute
module.exports.getEnvVars = (attribute, decrypt, config) => {
return readEnvYamlFiles(config.yamlPaths, config.stage).then(
envFiles => (attribute) ? filterEnvVars(envFiles, attribute) : envFiles
).then(
envFiles => (decrypt) ? decryptEnvVars(envFiles, config) : envFiles
)
}
// Sets the env variable
module.exports.setEnvVar = (attribute, value, encrypt, config) => {
let filePath = config.yamlPaths[0]
if (!filePath) {
return Promise.reject(new Error('No environment files specified in serverless.yml'))
}
return Promise.all([
yaml.read(filePath).catch(error => error.code === 'ENOENT' ? {} : Promise.reject(error)),
(encrypt) ? kms.encrypt(value, config) : Promise.resolve(value)
]).then(args => {
let doc = Object.assign({}, args[0])
let value = args[1]
doc[config.stage] = Object.assign({}, doc[config.stage])
doc[config.stage][attribute] = (encrypt) ? `${ENCRYPT_PREFIX}${value}` : value
return yaml.write(filePath, doc)
})
}