Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

aws-cfm-utils

Package Overview
Dependencies
Maintainers
1
Versions
22
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

aws-cfm-utils - npm Package Compare versions

Comparing version 1.0.0 to 1.1.0

helpers/cfm_create_stack.js

271

index.js

@@ -6,227 +6,49 @@ #!/usr/bin/env node

const { version } = require(__dirname + '/package.json');
const { cliopts } = require('./lib/cli_options.js');
const { processopts } = require('./lib/process_cli_options.js');
const deletion_timeout = 1800000; //30 mins
const create_timeout = 3600000; //60 mins
const update_timeout = 3600000; //60 mins
const { describestack } = require('./helpers/cfm_describe_stack.js'); //describestack(cfm, stackname)
const { deletestack } = require('./helpers/cfm_delete_stack.js'); //deletestack(cfm, stackname)
const { createstack } = require('./helpers/cfm_create_stack.js'); //createstack(cfm, args)
const { updatestack } = require('./helpers/cfm_update_stack.js'); //updatestack(cfm, args)
const sleep = require('util').promisify(setTimeout);
AWS.config.update({
region: 'eu-west-1'
});
const cfm = new AWS.CloudFormation();
const readjsonfile = (filename) => {
const file_dir = __dirname + '/' + filename;
const file_content = fs.readFileSync(file_dir, 'utf8'); //JSON.parse(fs.readFileSync(file_dir, 'utf8'));
return file_content;
};
//Function: describe cfm stack status
const describestack = async (stackname) => {
let data;
try {
data = await cfm.describeStacks({ StackName: stackname }).promise();
return data.Stacks[0].StackStatus;
}
catch (err) {
return err.statusCode;
}
};
//Function: change stackprotection on the stack
const stackprotection = async (stackname, termination) => {
console.log('Changing termination protection on stack: ' + stackname);
const params = {
EnableTerminationProtection: termination,
StackName: stackname
const cfmclient = (region, profile) => {
const options = {
apiVersion: '2010-05-15',
region: region,
};
try {
await cfm.updateTerminationProtection(params).promise();
}
catch (err) {
console.error('Exiting with error: ' + err.stack);
process.exit(2);
if (profile !== undefined) {
options.credentials = new AWS.SharedIniFileCredentials({profile: profile});
}
console.log('Termination Protection set to ' + termination + ' on stack: ' + stackname + '\n');
return new AWS.CloudFormation(options);
};
//Function: createstack
const createstack = async (cfm, stackname, template, policy) => {
console.log('Creating stack: ' + stackname);
const main = async (cfm, args) => {
const stack_status = await describestack(cfm, args.stackName);
console.log('status: ' + stack_status);
let data;
let count = 0;
let stack_status = await describestack(stackname);
const params = {
StackName: stackname,
Capabilities: [ 'CAPABILITY_NAMED_IAM' ],
EnableTerminationProtection: true,
StackPolicyBody: policy,
TemplateBody: template
};
try {
data = await cfm.createStack(params).promise();
console.log(data);
}
catch (err) {
console.error('Exiting with error: ' + err.stack);
process.exit(2);
}
while (stack_status == 'CREATE_IN_PROGRESS' || stack_status == 400) {
count = count++;
stack_status = await describestack(stackname);
console.log('CFM stack status: ', stack_status);
if (count > create_timeout * 60 / 10) {
console.log('Aborting - Timeout while creating!');
process.exit(1);
}
else {
console.log('Waiting...');
await sleep(15000); //15 secs
}
}
if (stack_status != 'CREATE_COMPLETE') {
console.log('Failure - Stack creation unsuccessful!');
process.exit(1);
}
console.log('Success - Stack Creation successful!');
process.exit(0);
};
//Function: updatestack
const updatestack = async (cfm, stackname, template, policy) => {
console.log('Updating stack: ' + stackname);
const params = {
StackName: stackname,
Capabilities: [ 'CAPABILITY_NAMED_IAM' ],
StackPolicyBody: policy,
TemplateBody: template
};
let data;
try {
data = await cfm.updateStack(params).promise();
console.log(data);
}
catch (err) {
if (err == 'ValidationError: No updates are to be performed.') {
console.log('Update not required. No changes to the cfm stack! ' + err + '\n');
process.exit(0);
}
console.error('Exiting with error type: ' + err.stack);
process.exit(2);
}
let stack_status = await describestack(stackname);
let count = 0;
//Wait for stack update
while (stack_status == 'UPDATE_IN_PROGRESS' || stack_status == 'CREATE_COMPLETE' || stack_status == 'UPDATE_COMPLETE_CLEANUP_IN_PROGRESS') {
count = count++;
stack_status = await describestack(stackname);
console.log('CFM stack status: ', stack_status);
if (count > update_timeout * 60 / 10) {
console.log('Aborting - Timeout while updating');
process.exit(1);
} else {
console.log('Waiting...');
await sleep(15000); //15 sec
}
}
if (stack_status != 'UPDATE_COMPLETE') {
console.log('Failure - Stack update unsuccessful');
process.exit(1);
}
console.log('Success - Stack Updated successfully! \n');
process.exit(0);
};
//Function: deletestack
const deletestack = async (cfm, stackname) => {
console.log('Deleting stack: ' + stackname);
const params = {
StackName: stackname
};
let data;
try {
data = await cfm.deleteStack(params).promise();
console.log(data);
}
catch (err) {
if (err == 'ValidationError: Stack [' + stackname + '] cannot be deleted while TerminationProtection is enabled') {
console.log('Termination Protection is enabled on the stack! \n');
console.log('Disabling Termination Protection on ' + stackname + '\n');
await stackprotection(stackname, false);
console.log('Trigger deployment of the stack again. Exiting...\n');
process.exit(0);
}
console.error('Exiting with error: ' + err.stack);
process.exit(2);
}
let stack_status = await describestack(stackname);
let count = 0;
//Wait for stack delete
while (stack_status != 400) {
count = count++;
stack_status = await describestack(stackname);
console.log('CFM stack status: ', stack_status);
if (count > deletion_timeout * 60 / 5) {
console.log('Aborting - Timeout while deleting');
process.exit(1);
}
else {
console.log('Waiting...');
await sleep(15000); //15 secs
}
}
console.log('Success - Stack Deleted successfully!');
};
const main = async (cfm, stackname, template, policy) => {
const stack_status = await describestack(stackname);
if (stack_status != 400) {
try {
console.log('Stack: ' + stackname + ' exists! Status: ' + stack_status);
console.log('Stack: ' + args.stackName + ' exists! Status: ' + stack_status);
switch (stack_status) {
case 'CREATE_COMPLETE':
await updatestack(cfm, stackname, template, policy);
await updatestack(cfm, args);
break;
case 'UPDATE_COMPLETE':
await updatestack(cfm, stackname, template, policy);
await updatestack(cfm, args);
break;
case 'ROLLBACK_COMPLETE':
await updatestack(cfm, stackname, template, policy);
await updatestack(cfm, args);
break;
case 'UPDATE_ROLLBACK_COMPLETE':
await updatestack(cfm, stackname, template, policy);
await updatestack(cfm, args);
break;
case 'UPDATE_ROLLBACK_FAILED':
await updatestack(cfm, stackname, template, policy);
await updatestack(cfm, args);
break;
case 'CREATE_FAILED':
await deletestack(cfm, stackname);
await createstack(cfm, stackname, template, policy);
await deletestack(cfm, args.stackName);
await createstack(cfm, args);
break;

@@ -244,4 +66,4 @@ default:

try {
console.log('Stack: ' + stackname + ' does not exist, creating new one!');
await createstack(cfm, stackname, template, policy);
console.log('Stack: ' + args.stackName + ' does not exist, creating new one!');
await createstack(cfm, args);
}

@@ -255,37 +77,10 @@ catch (err) {

//Parse command line options
const argv = require('yargs') // eslint-disable-line
.usage('Usage: $0 [options]')
.example('$0 -n stackname -t cfmtemplate -p stackpolicy','Create/update stack using AWS default credentials')
.example('$0 -n stackname -t cfmtemplate -p stackpolicy -k accesskeyid -s secretkey','Create/update stack using provided credentials')
.example('$0 --name stackname --template cfmtemplate --stackpolicy stackpolicy')
.example('$0 --name stackname --template cfmtemplate --stackpolicy stackpolicy --accesskeyid accesskeyid --secretkey secretkey')
.alias('n', 'name')
.nargs('n', 1)
.describe('n', 'AWS stack name')
.alias('t', 'template')
.nargs('t', 1)
.describe('t', 'CFM template file name')
.alias('p', 'stackpolicy')
.nargs('p', 1)
.describe('p', 'Stack policy file name')
.demandOption(['n', 't', 'p'])
.string(['n', 't', 'p'])
.describe('k', 'Your AWS access key')
.alias('k', 'accesskeyid')
.describe('s', 'Your AWS secret key')
.alias('s', 'secretkey')
.string(['k', 's'])
.implies('k', 's')
.version(version)
.alias('v', 'version')
.help('h')
.alias('h', 'help')
.showHelpOnFail(false, 'Something went wrong! run with --help or -h')
.argv;
// Collect and transform input options
const input_args = process.argv;
const args = processopts(cliopts(input_args));
const stackname = argv.name;
const template = readjsonfile(argv.template);
const policy = readjsonfile(argv.stackpolicy);
// Create AWS.CloudFormation client for specified region/profile
cfm = cfmclient(args.region, args.profile);
main(cfm, stackname, template, policy);
// Create/Update cloudformation stack using input args and cfm client
main(cfm, args);
{
"name": "aws-cfm-utils",
"version": "1.0.0",
"version": "1.1.0",
"description": "AWS utils to deploy cloudformation stack/templates",

@@ -16,3 +16,4 @@ "main": "index.js",

"eslint": "eslint .",
"eslint-fix": "eslint --fix ."
"eslint-fix": "eslint --fix .",
"test": "make mocha"
},

@@ -24,2 +25,3 @@ "author": "Marcin Cuber",

"fs": "0.0.1-security",
"path": "^0.12.7",
"util": "^0.10.3",

@@ -35,4 +37,5 @@ "yargs": "^11.0.0"

"eslint-plugin-standard": "^3.1.0",
"rimraf": "^2.6.2"
"rimraf": "^2.6.2",
"mocha": "^5.1.1"
}
}

@@ -19,15 +19,67 @@ # AWS CLOUDFORMATION UTILS

Options:
-n, --name AWS stack name [string] [required]
-t, --template CFM template file name [string] [required]
-p, --stackpolicy Stack policy file name [string] [required]
-k, --accesskeyid Your AWS access key [string]
-s, --secretkey Your AWS secret key [string]
-h, --help Show help [boolean]
-v, --version Show version number [boolean]
Options:
--stack-name [string] [required]
--template-body CFM template file name [string]
--stack-policy-body Stack policy file name [string]
--accesskeyid AWS access key [string]
--secretkey AWS secret key [string]
-h, --help Show help [boolean]
--parameters CFM Parameters [array]
--tags CFM Tags [array]
--region [string] [default: "eu-west-1"]
--capabilities [array] [choices: "CAPABILITY_NAMED_IAM", "CAPABILITY_IAM"]
--profile [string]
--role-arn [string]
--resource-types [array]
--disable-rollback [boolean]
--template-url [string]
--stack-policy-url [string]
--notification-arns [array]
--timeout-in-minutes [number]
--on-failure [string] [choices: "DO_NOTHING", "ROLLBACK", "DELETE"]
--use-previous-template [boolean]
--stack-policy-during-update-body [string]
--stack-policy-during-update-url [string]
--wait [boolean]
--enable-termination-protection [boolean]
--version Show version number [boolean]
Examples:
aws-cfm-utils -n stackname -t cfmtemplate -p stackpolicy
aws-cfm-utils --name stackname --template cfmtemplate --stackpolicy stackpolicy
1. aws-cfm-utils --stack-name stackname --template-body cfmtemplate --stack-policy-body stackpolicy --region eu-west-1 --enable-termination-protection true
2. aws-cfm-utils --stack-name mynewstack --template-body test/fixtures/template.json --stack-policy-body test/fixtures/stackpolicy.json --enable-termination-protection true --region eu-west-1 --parameters test/fixtures/parameters.json --tags Key=TestTag,Value=TestTagValue Key=TestTag2,Value=TestTagValue2 Key=TestTag3,Value=TestTagValue4
3. aws-cfm-utils --stack-name mynewstack --template-body test/fixtures/template.json --stack-policy-body test/fixtures/stackpolicy.json --enable-termination-protection true --region eu-west-1 --parameters test/fixtures/parameters.json --tags test/fixtures/tags.json
4. aws-cfm-utils --stack-name mynewstack --template-body test/template.json --stack-policy-body test/stackpolicy.json --enable-termination-protection true --region eu-west-1 --parameters ParameterKey=TestName,ParameterValue=TestKey ParameterKey=TestName2,ParameterValue=TestKey2
### Global parameters ([AWS CLI Docs](http://docs.aws.amazon.com/cli/latest/topic/config-vars.html#general-options)):
```
--profile //optional
--region //optional, defaults to Ireland region eu-west-1
```
### Used during creation of the stack, otherwise ignored ([create-stack](http://docs.aws.amazon.com/cli/latest/reference/cloudformation/create-stack.html)):
```
--enable-termination-protection | --no-enable-termination-protection
--disable-rollback | --no-disable-rollback
--timeout-in-minutes
--on-failure
```
### Used during update of the stack, otherwise ignored ([update-stack](http://docs.aws.amazon.com/cli/latest/reference/cloudformation/update-stack.html)):
```
--use-previous-template | --no-use-previous-template]
--stack-policy-during-update-body
--stack-policy-during-update-url
```
## Unit Tests
```
npm run test
```
## Requirements and Dependencies

@@ -34,0 +86,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc