aws-lager
Version:
AWS Lambda / API Gateway / Endpoint Router
147 lines (133 loc) • 4.6 kB
JavaScript
'use strict';
var _ = require('lodash');
var AWS = require('aws-sdk');
var Promise = require('bluebird');
var fs = require('fs');
var nameGenerator = require('./name_generator');
var policyHelperFn = require('./policy_helper');
AWS.config.apiVersions = {
iam: '2010-05-08'
};
/**
* Constructor function
* @param Object options
*/
var policyBuilder = function(options) {
this.environment = options.environment;
this.pathPrefix = '/' + (this.environment ? this.environment + '/' : '');
this.iam = new AWS.IAM();
this.policyHelper = policyHelperFn(this.iam);
};
/* istanbul ignore next */
/**
* Deploy all policies in a directory
* @param String path
* @return Promise
*/
policyBuilder.prototype.deployAll = function(path) {
// Retrieve policy configuration directories
var policyPaths = _.map(fs.readdirSync(path), function(dirName) {
return path + '/' + dirName;
});
// Run the functions in serie
return Promise.mapSeries(policyPaths, this.deploy.bind(this));
};
/* istanbul ignore next */
/**
* Deploy a policy configuration
* @param String pathToPolicy
* @return Promise
*/
policyBuilder.prototype.deploy = function(pathToPolicy) {
var policyName = nameGenerator(pathToPolicy, this.environment);
var policyDocument = fs.readFileSync(pathToPolicy).toString();
console.log(' * Deploying policy ' + policyName);
var params = {
PathPrefix: this.pathPrefix,
OnlyAttached: false,
Scope: 'Local'
};
return this.policyHelper.getPolicyByName(policyName, params)
.then(function(currentPolicy) {
if (!currentPolicy) {
// If the policy could not be found, create it
console.log(' * The policy does not exist yet');
var params = {
PolicyDocument: policyDocument,
PolicyName: policyName,
Description: 'Policy generated by LAGER',
Path: this.pathPrefix
};
return Promise.promisify(this.iam.createPolicy.bind(this.iam))(params);
} else {
// If the policy already exists, we update it if necessary
console.log(' * The policy already exists');
var params = {
PolicyArn: currentPolicy.Arn,
VersionId: currentPolicy.DefaultVersionId
};
return Promise.promisify(this.iam.getPolicyVersion.bind(this.iam))(params)
.then(function(data) {
if (unescape(data.PolicyVersion.Document) === policyDocument) {
console.log(' * The policy is already up-to-date');
return Promise.resolve(currentPolicy);
} else {
console.log(' * The policy must be updated');
return this.updatePolicy(currentPolicy.Arn, policyDocument);
}
});
}
}.bind(this));
};
/**
* Update a policy taking car of the limit of 5 versions
* Deletes the version that has the smallest ID and is not set as default
* @param String policyArn
* @param String policyDocument
* @return Promise
*/
policyBuilder.prototype.updatePolicy = function(policyArn, policyDocument) {
return Promise.promisify(this.iam.listPolicyVersions.bind(this.iam))({ PolicyArn: policyArn })
.then(function(data) {
if (data.Versions.length < 5) {
// If the policy has less than 5 versions, we can create a new version
return this.createPolicyVersion(policyArn, policyDocument);
} else {
// If the policy already has 5 versions, we have to delete the oldest one
// Look for the smallest version number
console.log(' * 5 versions exist already');
var minVersion = _.reduce(data.Versions, function(result, value, key) {
if (value.IsDefaultVersion || value.VersionId > result) {
return result;
}
return value.VersionId;
}, Infinity);
console.log(' * Deleting version ' + minVersion);
var params = {
PolicyArn: policyArn,
VersionId: minVersion
};
return Promise.promisify(this.iam.deletePolicyVersion.bind(this.iam))(params)
.then(function() {
return this.createPolicyVersion(policyArn, policyDocument);
});
}
});
};
/**
* Create a policy version
* @param String policyArn
* @param String policyDocument
* @return Promise
*/
policyBuilder.prototype.createPolicyVersion = function(policyArn, policyDocument) {
// @TODO We should SetAsDefault only once the deployment is performed
console.log(' * Creating a new version');
var params = {
PolicyArn: policyArn,
PolicyDocument: policyDocument,
SetAsDefault: true
};
return Promise.promisify(this.iam.createPolicyVersion.bind(this.iam))(params);
};
module.exports = policyBuilder;