briareus
Version:
Briareus assists with Feature Branch deploys to ECS
79 lines (68 loc) • 2.76 kB
JavaScript
const async = require('async');
const _ = require('lodash');
const AWS = require('aws-sdk');
const crypto = require('crypto');
const config = require('../config');
const utils = require('../../utilities');
const deleteSsmParameters = require('./destroy-ssm-parameters').deleteSsmParameters;
let action = module.exports = function (pipeline, payload, cb) {
const ssm = new AWS.SSM();
const kms = new AWS.KMS();
function putSecret(name, value, cb) {
kms.decrypt({ CiphertextBlob: Buffer.from(value, 'base64') }, (err, data) => {
if (err) return cb(err);
let params = {
Name: name,
Type: 'SecureString',
Value: data.Plaintext.toString(),
Description: `Secret for Briareus Variant ${payload.id}`,
KeyId: payload.kmsKeyArn,
Overwrite: true,
};
utils.awsRetry((done) => ssm.putParameter(params, done), cb);
});
}
function putSecrets(secrets, cb) {
async.mapLimit(secrets, 3, (secret, next) => {
let paramPath = `${payload.ssmParameterScopePrefix}/${secret.id}`;
putSecret(paramPath, secret.value, (err, data) => {
if (err) return next(err);
// Hash `id` to avoid `/` in asset path. Otherwise JSON Patch will try
// to set values on undefined objects. eg if `id` is `web/API_KEY` then JSON patch
// will try to set `API_KEY` on object `web` (which won't exist). But we should
// track SSM Parameters via `id` since this is a PUT operation. ie we override
// existing parameters if the `id` is the same.
let hashedId = crypto.createHash('md5').update(secret.id).digest("hex");
// Small timeout to help avoid API request throttling.
setTimeout(() => {
next(null, {
op: 'add',
path: `/assets/ssmParameters/${hashedId}`,
value: {
id: secret.id,
hashedId: hashedId,
arn: `arn:aws:ssm:${config.get('aws.region')}:${payload.awsAccountId}:parameter${paramPath}`,
path: paramPath,
name: secret.name,
container: secret.container
}
});
}, 200);
});
}, cb);
}
const secretIds = _.map(payload.secrets, 'id');
const removedParameters = _.filter(_.values(payload.assets.ssmParameters), (ssmParam) => {
return secretIds.indexOf(ssmParam.id) === -1
});
async.waterfall([
(done) => putSecrets(payload.secrets, done),
(ops, done) => deleteSsmParameters(removedParameters, (err, ops2) => {
if (err) return done(err);
done(null, [].concat(ops, ops2));
})
], cb);
}
action.waiting = 'Syncing SSM Parameter Secrets';
action.done = 'SSM Parameter Secrets have been synchronized';