Stack-Assembly is a command line tool to configure and deploy AWS Cloudformation stacks in a safe way. The safety aspect is enabled by utilizing Cloudformation Changesets and letting the user to view and confirm changes to be deployed.
Contents
- No dependencies (NodeJS, Python interpreter, aws cli etc.) - Stack-Assembly is a single statically linked binary
- Configuration powered by Golang Templates
- Interactive interface which enables user to view, diff and confirm changes to be deployed
- Colorized terminal output
- Documentation
- Test coverage
The pre-compiled binaries can be downloaded from the release page. The following OSs are supported:
- Windows amd64/386
- Linux amd64/386
- Darwin amd64/386
This requires go 1.11 to be installed
$ git clone git@github.com:molecule-man/stack-assembly.git
$ cd stack-assembly
$ make build
This will build binary inside bin
folder.
For demonstration purposes it is assumed that there exists file
./path/to/cf-tpls/sqs.yaml
containing cloudformation template you
want to deploy. For example:
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
QueueName:
Type: String
VisibilityTimeout:
Type: Number
Resources:
MyQueue:
Type: AWS::SQS::Queue
Properties:
QueueName: !Ref QueueName
VisibilityTimeout: !Ref VisibilityTimeout
Then create Stack-Assembly configuration file in the root folder of your project
stack-assembly.yaml
:
# In this simple example two stacks are configured. Both stacks use the same
# cloudformation template
stacks:
# tpl1 is the id of the stack. This id has meaning only inside this
# config. You can use this id to deploy a particular stack instead of
# deploying all stacks as it's done by default. You can do it by running
# `stas sync tpl1`
tpl1:
name: demo-tpl1
path: path/to/cf-tpls/sqs.yaml
# parameters is a key-value map where values are strings. Numeric
# parameters have to be defined as strings as you can see in the example
# of VisibilityTimeout parameter
parameters:
QueueName: demo1
VisibilityTimeout: "10"
tpl2:
name: demo-tpl2
path: path/to/cf-tpls/sqs.yaml
parameters:
QueueName: demo2
VisibilityTimeout: "20"
Assuming you have configured AWS credentials then you can deploy your stacks by running:
$ stas sync
By default Stack-Assembly is executed in interactive mode. During the deployment it shows the changes that are about to be deployed and asks user's confirmation to proceed with deployment.
$ stas help sync Creates or updates stacks specified in the config file(s). By default sync command deploys all the stacks described in the config file(s). To deploy a particular stack, ID argument has to be provided. ID is an identifier of a stack within the config file. For example, ID is tpl1 in the following yaml config: stacks: tpl1: # <--- this is ID name: mystack path: path/to/tpl.json The config can be nested: stacks: parent_tpl: name: my-parent-stack path: path/to/tpl.json stacks: child_tpl: # <--- this is ID of the stack we want to deploy name: my-child-stack path: path/to/tpl.json In this case specifying ID of only wanted stack is not enough all the parent IDs have to be specified as well: stas sync parent_tpl child_tpl Usage: stas sync [<ID> [<ID> ...]] [flags] Aliases: sync, deploy Flags: -h, --help help for sync Global Flags: -c, --configs strings Alternative config file(s). Default: stack-assembly.yaml -n, --no-interaction Do not ask any interactive questions --nocolor Disables color output -p, --profile string AWS named profile (default "default") -r, --region string AWS region -v, --var -v myParam=someValue Additional variables to use as parameters in config. Example: -v myParam=someValue
You can supply multiple -c
configuration files. When you supply multiple
files, Stack-Assembly combines them into a single configuration. Subsequent
files override and add to their predecessors.
For example, consider this command line:
$ stas sync -c stack-assembly.yml -c stack-assembly.staging.yml
The stack-assembly.yml
file might look like this:
stacks:
ec2machine:
name: ec2machine-dev
path: cf-tpls/ec2machine.yml
parameters:
Size: t2.micro
ImageID: ami-rt34fu
And the stack-assembly.staging.yml
file might look like this:
stacks:
ec2machine:
name: ec2machine-staging
parameters:
Size: t2.medium
tags:
ENV: staging
Stack-Assembly will apply configuration from stack-assembly.staging.yml
on
top of stack-assembly.yml
and the result configuration will look like this:
stacks:
ec2machine:
name: ec2machine-staging
path: cf-tpls/ec2machine.yml
parameters:
Size: t2.medium
ImageID: ami-rt34fu
tags:
ENV: staging
Stack-Assembly uses simple yet powerful config file that can be in one of these
three formats: yaml
, toml
, json
. The next sections will use yaml
as a format.
Stack-Assembly will firstly try to use file stack-assembly.yaml
in your
project directory. If it's not found then Stack-Assembly will try to use
stack-assembly.yml
, stack-assembly.toml
, stack-assembly.json
.
Example of Stack-Assembly config file:
settings:
aws:
# aws named profile. See the following link for more information
# https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html
# This configuration option can be overriden by env variable AWS_PROFILE.
# Or by command line parameter `--profile`
profile: default
# aws region. This configuration option can be overriden by env variable
# AWS_REGION. Or by command line parameter `--region`
region: us-west-2
# cloudformation parameters that are global for all stacks
parameters:
Env: dev
ServiceName: myservice
stacks:
db:
# cloudformation stack's name. It's possible to use golang templating
# inside `name`
name: "{{ .Params.DbName }}"
# path to cloudformation template.
# Either `path` or `body` has to be provided
path: cf-tpls/rds.yml
# cloudformation stack's parameters
parameters:
Type: db.t2.medium
# it's possible to use golang templating inside parameter value
DbName: "{{ .Params.ServiceName }}-{{ .Params.Env }}"
# cloudformation stack's tags. It's also possible to use golang
# templating inside tag value
tags:
ENV: "{{ .Params.Env }}"
# it's possible to create a stack policy that will disallow to `update`
# or `delete` certain stack resources. In this case the policy will be
# applied to stack resource with `LogicalResourceId` equal to
# `DbInstance`. See the following link for more information:
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/protect-stack-resources.html
blocked:
- DbInstance
ec2app:
name: "{{ .Params.ServiceName }}-{{ .Params.Env }}-ec2app"
parameters:
Type: t2.micro
# `path` is not the only way to specify cloudformation template. It's
# possible to specify the whole template body inside the config. It
# might be especially useful when template generating tool (as e.g.
# troposphere) is used.
# In this example, given that `Env` is equal to "dev", body will have
# contents of the output produced by executing
# `python terraform_tpls/ec2.py dev`
body: |
{{ .Params.Env | Exec "python" "terraform_tpls/ec2.py" }}
# dependsOn instruction tells Stack-Assembly that this stack should be
# deployed after `db` stack is deployed
dependsOn:
- db
# In some cases, you must explicity acknowledge that your stack template
# contains certain capabilities in order for AWS CloudFormation to
# create the stack. For more information, see
# https://docs.aws.amazon.com/AWSCloudFormation/latest/APIReference/API_CreateStack.html
capabilities:
- CAPABILITY_IAM
# Rollback triggers enable you to have AWS CloudFormation monitor the
# state of your application during stack creation and updating, and to
# roll back that operation if the application breaches the threshold of
# any of the alarms you've specified.
# For more information, see
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-rollback-triggers.html
rollbackConfiguration:
monitoringTimeInMinutes: 1
rollbackTriggers:
- arn: arn:aws:cloudwatch:{{ .AWS.Region }}:{{ .AWS.AccountID }}:alarm:{{ .Params.ServiceName }}-errors
type: AWS::CloudWatch::Alarm
Every stack in stack-assembly config can contain nested stacks. This enables possibility to deploy subgroup (subtree) of stacks.
stacks:
staging:
# settings, as well as parameters, are propagated down the tree.
# All the child stacks of `staging` inherit settings and parameters
# defined at `staging` level
settings:
aws:
region: eu-west-1
parameters:
Env: staging
stacks:
db:
name: "db-staging"
path: cf-tpls/rds.yml
app:
name: "app-staging"
path: cf-tpls/app.yml
production:
settings:
aws:
region: us-east-1
parameters:
Env: production
stacks:
db:
name: "db-production"
path: cf-tpls/rds.yml
app:
name: "app-production"
path: cf-tpls/app.yml
Having this config one can deploy all the stacks under production
by
running:
stas sync production
Or, if one needs to deploy db
stack under staging
, one can use the
following command:
stas sync staging db
When writing complex config, it's almost inevitable to have duplication in the config. This section describes how stack-assembly helps to avoid copying-and-pasting.
Let's say we have a stack we want to deploy multiple times in different
environments. Each environment is different from each other only by handful of
parameters. Then we put the reused stack under the definitions
in the root
of the config. And then we can (re)use this stack in the config by referencing
this stack with $basedOn
field in the config:
stacks:
staging:
"$basedOn": reused_stack
parameters:
Env: staging
production:
"$basedOn": reused_stack
parameters:
Env: production
definitions:
reused_stack:
name: "reused-stack-{{ .Params.Env }}"
path: cf-tpls/stack.yml
If you've ever used awscli or similar tool you probably already know about aws
credentials file. Stack-Assembly also uses this file to read credentials. The
default location of this file is $HOME/.aws/credentials
. You can find more
information in AWS documentation.
For the sake of example let's consider that you have configured aws credentials and now have this files in your home folder:
~/.aws/credentials
[default] aws_access_key_id=AKIAIOSFODNN7EXAMPLE aws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
~/.aws/config
[default] region=us-west-2
Now you have couple of options:
- Specify profile and region in the config file. See Config file structure:
settings:
aws:
profile: default
region: eu-west-1
- Use environmental variables:
$ export AWS_PROFILE=default
$ export AWS_REGION=eu-west-1
$ stas sync
- Use command line flags:
$ stas sync --profile default --region eu-west-1
Apart from sync command there are also couple of handy other commands you can use:
$ stas help
Usage:
stas [command]
Available Commands:
delete Deletes deployed stacks
diff Show diff of the stacks to be deployed
dump-config Dump loaded config into stdout
help Help about any command
info Show info about the stack
sync Synchronize (deploy) stacks
Stack-assembly provides a possibility to enhance aws-cli by replacing create-stack, update-stack and deploy commands with improved versions of those commands. More info can be found here
- Enable user to unblock the blocked resource (interactively).
- Github support.
- Add possibility to introspect aws resources??