Configuration

In addition to the Runway Config File, there are two files that can be used for configuration:

Changed in version 1.5.0: Stacker is no longer used for handling CloudFormation/Troposphere. It has been replaced with an internal CloudFormation engin (CFNgin).

runway.yml

Example

deployments:
  - modules:
      - path: sampleapp.cfn
        type: cloudformation  # not required; implied from ".cfn" directory extension
        environments:
          dev: true
        parameters:
          namespace: example-${env DEPLOY_ENVIRONMENT}
          cfngin_bucket: example-${env DEPLOY_ENVIRONMENT}-${env AWS_REGION}
    regions:
      - us-east-1

Options

CloudFormation modules do not have any module-specific options.

Parameters

Runway can pass Parameters to a CloudFormation module in place of or in addition to values in an environment file. When Parameters are passed to the module, the data type is retained (e.g. array, boolean, mapping).

A typical usage pattern would be to use Runway Lookups in combination with Parameters to pass deploy environment and/or region specific values to the module from the Runway Config File.

Example

deployments:
  - modules:
      - sampleapp-01.cfn
      - path: sampleapp-02.cfn
        parameters:
          instance_count: ${var instance_count.${env DEPLOY_ENVIRONMENT}}
    parameters:
      image_id: ${var image_id.%{env AWS_REGION}}

Common Parameters

Runway automatically makes the following commonly used Parameters available to CloudFormation modules.

Note

If these parameters are already being explicitly defined in deployment.parameters/module.parameters the value provided will be used instead of what would be automatically added.

environment: str

Taken from the DEPLOY_ENVIRONMENT environment variable. This will the be current deploy environment.

region: str

Taken from the AWS_REGION environment variable. This will be the current region being processed.


CFNgin Config File

The CFNgin config file has full support for YAML features like anchors & references for a DRY config file (See YAML anchors & references for details).

Top-Level Fields

class cfngin.config

Runway’s CFNgin makes use of a YAML formatted config file to define the different CloudFormation stacks that make up a given environment.

cfngin_bucket: Optional[str] = None

By default, CloudFormation templates are pushed into an S3 bucket and CloudFormation is pointed to the template in that bucket when launching or updating stacks. By default it uses a bucket named cfngin-${namespace}-${region}, where the namespace is namespace and region is the current AWS region.

To change this, define a value for this field.

If the bucket does not exists, CFNgin will try to create it in the same region that the stacks will be launched in. The bucket will be created by deploying a CloudFormation stack named ${namespace}-cfngin-bucket where the namespace is namespace. If there is a stack named cfngin-bucket found defined in the stacks field, it will be used in place of default stack & Blueprint (runway.cfngin.blueprints.cfngin_bucket.CfnginBucket) provided by CFNgin. When using a custom stack, it is the user’s responsibility to ensure that a bucket with the correct name is created by this stack.

If you want CFNgin to upload templates directly to CloudFormation instead of first uploading to S3, you can set this field to an empty string. However, the template size is greatly limited when uploading directly. See the CloudFormation Limits Reference.

Tip

Defining a stack that uses the Blueprint provided by CFNgin allows for easy customization of stack fields such as tags. It also allows the stack to be deleted as part of the normal deletion process. If it is not defined as a stack, CFNgin won’t delete the stack or bucket.

namespace: ${namespace}
cfngin_bucket: cfngin-${namespace}-${region}

stacks:
  - name: cfngin-bucket
    class_path: runway.cfngin.blueprints.cfngin_bucket.CfnginBucket
    variables:
      BucketName: cfngin-${namespace}-${region}

pre_destroy:
  - path: runway.cfngin.hooks.cleanup_s3.purge_bucket
    args:
      bucket_name: cfngin-${namespace}-${region}

Example

cfngin_bucket: example-${region}

Changed in version 2.0.0: The format of the default value is now cfngin-${namespace}-${region}.

cfngin_bucket_region: Optional[str] = None

AWS Region where cfngin_bucket is located. This can be different than the region currently being deployed to but, ensure to account for all AWS limitations before manually setting this value.

If not provided, the current region is used.

Example

cfngin_bucket_region: us-east-1
cfngin_cache_dir: Optional[str] = ./.runway/

Path to a local directory that CFNgin will use for local caching.

If provided, the cache location is relative to the CFNgin configuration file.

If NOT provided, the cache location is relative to the runway.yaml/runway.yml file and is shared between all Runway modules.

Example

cfngin_cache_dir: ./.runway
log_formats: Optional[Dict[str, str]] = {}

Customize log message formatting by log level.

Any of the standard Python logging module format attributes can be used when writing a new log format string.

Example

log_formats:
  info: "[%(asctime)s] %(message)s"
  debug: "[%(asctime)s] %(levelname)s %(threadName)s %(name)s:%(lineno)d(%(funcName)s): %(message)s"
lookups: Optional[Dict[str, str]] = {}

Lookups allow you to create custom methods which take a value and are resolved at runtime time. The resolved values are passed to the Blueprint before it is rendered. For more information, see the Lookups documentation.

CFNgin provides some common Lookups, but it is sometimes useful to have your own custom lookup that doesn’t get shipped with Runway. You can register your own lookups here.

The key of each item in the mapping will be used as the name of the lookup type when registering the lookup. The value should be the path to a valid lookup handler.

Example

lookups:
  custom: path.to.lookup.handler

conf_value: ${custom query}
mappings: Optional[Dict[str, Dict[str, Dict[str, Any]]]] = {}

Mappings are dictionaries that are provided as Mappings to each CloudFormation stack that CFNgin produces.

These can be useful for providing things like different AMIs for different instance types in different regions.

These can be used in each Blueprint/template as usual.

Example

mappings:
  AmiMap:
    us-east-1:
      NAT: ami-ad227cc4
      ubuntu1404: ami-74e27e1c
      bastion: ami-74e27e1c
    us-west-2:
      NAT: ami-290f4119
      ubuntu1404: ami-5189a661
      bastion: ami-5189a661
namespace: str

A namespace to create all stacks within. The value will be used as a prefix for the name of any stack that is created.

In addition, this value can be used to create an S3 bucket that will be used to upload and store all CloudFormation templates. See cfngin_bucket for more detailed information.

In general, this is paired with the concept of deploy environments to create a namespace per environment.

Example

namespace: ${namespace}-${environment}
namespace_delimiter: Optional[str] = "-"

By default, - will be used as a delimiter between the namespace and the declared stack name to deploy the actual CloudFormation stack name that gets created.

If you prefer to not use a delimiter, an empty string can be used as the value of this field.

See the CloudFormation API Reference for allowed stack name characters

Example

namespace_delimiter: ""
package_sources: Optional[cfngin.package_sources] = {}

See Remote Sources for detailed information.

package_sources:
  git:
    ...
  local:
    ...
  s3:
    ...
persistent_graph_key: Optional[str] = None

Used to track the state of stacks defined in configuration file. This can result in stacks being destroyed when they are removed from the configuration file removing the need to manually delete the stacks.

See Persistent Graph for detailed information.

Example

persistent_graph_key: unique-key.json
post_deploy: Optional[List[cfngin.hook]] = []

Python functions/methods that are executed after processing the stacks in the config while using the deploy command.

See Hooks for more detailed information.

Example

post_deploy:
  - path: do.something

Changed in version 2.0.0: post_build renamed to post_deploy.

Changed in version 2.2.0: The CFNgin bucket is now created using a CloudFormation stack.

post_destroy: Optional[List[cfngin.hook]] = []

Python functions/methods that are executed after processing the stacks in the config while using the destroy command.

See Hooks for more detailed information.

Example

post_destroy:
  - path: do.something
pre_deploy: Optional[List[cfngin.hook]] = []

Python functions/methods that are executed before processing the stacks in the config while using the deploy command.

See Hooks for more detailed information.

Example

pre_deploy:
  - path: do.something

Changed in version 2.0.0: pre_build renamed to pre_deploy.

pre_destroy: Optional[List[cfngin.hook]] = []

Python functions/methods that are executed before processing the stacks in the config while using the destroy command.

See Hooks for more detailed information.

Example

pre_destroy:
  - path: do.something
service_role: Optional[str] = None

By default CFNgin doesn’t specify a service role when executing changes to CloudFormation stacks. If you would prefer that it do so, you define the IAM Role ARN that CFNgin should use when executing CloudFormation changes.

This is the equivalent of setting RoleARN on a call to the following CloudFormation API calls: CreateStack, UpdateStack, CreateChangeSet.

See the AWS CloudFormation service role for more information.

Example

service_role: arn:aws:iam::123456789012:role/name
stacks: Optional[List[cfngin.stack]] = []

This is the core part of the config where the CloudFormations stacks that will be deployed in the environment are defined.

See Stack for more information.

sys_path: Optional[str] = None

A path to be added to $PATH while processing the configuration file. This will allow modules from the provided path location to be used.

When setting class_path for a Blueprint or path for a hook , it is sometimes desirable to load modules from outside the default $PATH (e.g. to include modules inside the same repo as config files).

Example

sys_path: ./  # most common value to use
tags: Optional[Dict[str, str]] = {"cfngin_namespace": namespace}

A dictionary of tags to add to all stacks. These tags are propagated to all resources that AWS CloudFormation supports. See CloudFormation - Resource Tag for more information.

If this field is undefined, a cfngin_namespace tag is applied to your stack with the value of namespace as the tag-value. Alternatively, this field can be set to a value of {} (an empty dictionary) to disable the default tag.

Example

tags:
  namespace: ${namespace}
  example: value
disable default tag
tags: {}
template_indent: Optional[int] = 4

Number of spaces per indentation level to use when rendering/outputting CloudFormation templates.

Example

template_indent: 2

Stack

class cfngin.stack

Defines a CloudFormation stack.

Lookup Support

The following fields support lookups:

Example

stacks:
  - name: vpc-example
    class_path: blueprints.vpc.VPC
    variables:
      InstanceType: t2.small
      SshKeyName: default
      ImageName: NAT
      AZCount: 2
      PublicSubnets:
        - 10.128.0.0/24
        - 10.128.1.0/24
        - 10.128.2.0/24
        - 10.128.3.0/24
      PrivateSubnets:
        - 10.128.8.0/22
        - 10.128.12.0/22
        - 10.128.16.0/22
        - 10.128.20.0/22
      CidrBlock: 10.128.0.0/16
class_path: Optional[str] = None

A python importable path to the Blueprint class to be used.

Exactly one of class_path or template_path must be defined.

Example

stacks:
  - name: example-stack
    class_path: example.BlueprintClass
description: Optional[str] = None

A short description to apply to the stack. This overwrites any description defined in the Blueprint. See Cloudformation - Template Description for more information.

Example

stacks:
  - name: example-stack
    description: An Example Stack
enabled: Optional[bool] = True

Whether to deploy/update the stack. This enables the ability to disable stacks in different environments.

Important

This field is ignored when destroying stacks.

Example

stacks:
  - name: example-stack
    enabled: false
  - name: another-stack
    enabled: ${enable_another_stack}
in_progress_behavior: Optional[Literal['wait']] = None

Specifies the behavior for when a stack is in CREATE_IN_PROGRESS or UPDATE_IN_PROGRESS. By default, CFNgin will raise an exception if the stack is in an IN_PROGRESS state when processing begins.

If the value of this field is wait, CFNgin will wait for the previous update to complete before attempting to update the stack instead of raising an exception.

Example

stacks:
  - name: example-stack
    in_progress_behavior: wait
locked: Optional[bool] = False

Whether the stack should be updated after initial deployment. This is useful for risky stacks that you don’t want to take the risk of allowing CloudFormation to update but still want to deploy it using CFNgin.

Example

stacks:
  - name: example-stack
    locked: true
  - name: another-stack
    locked: ${locked_another_stack}
name: str

Name of the CFNgin Stack. The value of this field is used by CFNgin when referring to a Stack. It will also be used as the name of the Stack when created in CloudFormation unless overridden by stack_name.

Note

namespace will be appended to this value when used as the name of the CloudFormation Stack.

Example

stacks:
  - name: example-stack
protected: Optional[bool] = False

Whether to force all updates to be performed interactively.

When true and running in non-interactive mode, CFNgin will switch to interactive mode for this stack to require manual review and approval of any changes.

Example

stacks:
  - name: example-stack
    protected: true
  - name: another-stack
    protected: ${protected_another_stack}
required_by: Optional[List[str]] = []

A list of other stacks that require this stack. All stacks must be defined in the same configuration file.

Inverse of requires.

Example

stacks:
  - name: example-stack:  # deployed first
    required_by:
      - another-stack
  - name: another-stack:  # deployed after example-stack
    ...
requires: Optional[List[str]] = []

A list of other stacks that this stack requires. All stacks must be defined in the same configuration file.

Inverse of required_by.

Example

stacks:
  - name: example-stack# deployed after another-stack
    requires:
      - another-stack
  - name: another-stack  # deployed first
    ...
stack_name: Optional[str] = None

The name used when creating the CloudFormation stack. If not provided, name will be used.

Note

namespace will be appended to this value.

Example

stacks:
  - name: example-stack
    stack_name: another-name
stack_policy_path: Optional[str] = None

Path to a JSON formatted stack policy that will be applied when the CloudFormation stack is created and/or updated.

See CloudFormation - Prevent updates to stack resources for examples and more information.

Example

stacks:
  - name: example-stack
    stack_policy_path: ./stack_policies/example-stack.json
tags: Optional[Dict[str, str]] = {}

A dictionary of tags to add to the Stack. These tags are propagated to all resources that AWS CloudFormation supports. See CloudFormation - Resource Tag for more information.

This will be combined with the global tags. Values defined here take precedence over those defined globally.

Example

stacks:
  - name: example-stack
    tags:
      namespace: ${namespace}
      example: value
template_path: Optional[str]

Path to a raw CloudFormation template (JSON or YAML). Can be relative to the working directory (e.g. templates stored alongside the configuration file), or relative to a directory in the $PATH (i.e. for loading templates retrieved via package_sources).

Exactly one of class_path or template_path must be provided.

Example

stacks:
  - name: example-stack
    template_path: ./templates/example-stack.yml
  - name: another-stack
    template_path: remote/path/templates/another-stack.json
termination_protection: Optional[bool] = False

Whether the stack will be protected from termination by CloudFormation.

Any attempts to destroy the stack (using Runway, the AWS console, AWS API, etc) will be prevented unless manually disabled.

When updating a stack and the value has been changed, termination protection on the CloudFormation stack sill also change. This is useful when needing to destroy a stack by first changing the value in the configuration file, updating the stack, then proceeding to destroy it.

Example

stacks:
  - name: example-stack
    termination_protection: true
  - name: another-stack
    termination_protection: ${termination_protection_another_stack}
timeout: Optional[int] = None

Specifies the amount of time, in minutes, that CloudFormation should allot before timing out stack creation operations. If CloudFormation can’t create the entire stack in the time allotted, it fails the stack creation due to timeout and rolls back the stack.

By default, there is no timeout for stack creation. However, individual resources may have their own timeouts based on the nature of the service they implement. For example, if an individual resource in your stack times out, stack creation also times out even if the timeout you specified for stack creation hasn’t yet been reached.

Example

stacks:
  - name: example-stack
    timeout: 120
variables: Optional[Dict[str, Any]] = {}

A dictionary of Variables to pass to the Blueprint when rendering the CloudFormation template. Can be any valid YAML data structure.

When using a raw CloudFormation template, these are the values provided for it’s Parameters.

Example

stacks:
  - name: example-stack
    variables:
      StackVariable: value

Variables

Variables are values that will be passed into a Blueprint before it is rendered. Variables can be any valid YAML data structure and can leverage Lookups to expand values at runtime.

YAML anchors & references

If you have a common set of variables that you need to pass around in many places, it can be annoying to have to copy and paste them in multiple places. Instead, using a feature of YAML known as anchors & references, you can define common values in a single place and then refer to them with a simple syntax.

For example, say you pass a common domain name to each of your stacks, each of them taking it as a Variable. Rather than having to enter the domain into each stack you could do the following to have an anchor called domain that you can use in place of any value in the config to provide the value mydomain.com.

stacks:
- name: example-stack
  class_path: blueprints.Example
  variables:
    DomainName: &domain mydomain.com
  - name: vpc
    class_path: blueprints.VPC
    variables:
      DomainName: *domain

Even more powerful is the ability to anchor entire dictionaries, and then reference them in another dictionary, effectively providing it with default values. Now, rather than having to provide each of those variables to every stack that could use them, you can just do this instead.

stacks:
  - name: example-stack
    class_path: blueprints.Example
    variables: &variables
      DomainName: mydomain.com
      InstanceType: m3.medium
      AMI: ami-12345abc
  - name: vpc
    class_path: blueprints.VPC
    variables:
      << : *variables
      InstanceType: c4.xlarge # override the InstanceType in this stack

Using Outputs as Variables

Since CFNgin encourages the breaking up of your CloudFormation stacks into entirely separate stacks, sometimes you’ll need to pass values from one stack to another. The way this is handled in CFNgin is by having one stack provide Outputs for all the values that another stack may need, and then using those as the inputs for another stack’s variables. CFNgin makes this easier for you by providing a syntax for variables that will cause CFNgin to automatically look up the values of Outputs from another stack in its config.

To do so, use the output in the variables on the target stack.

MyParameter: ${output OtherStack.OutputName}

For more information see Lookups.

In this example config, when deploying things inside a VPC, you will need to pass the VpcId of the VPC that you want the resources to be located in. If the vpc stack provides an Output called VpcId, you can reference it easily.

domain_name: my_domain &domain

stacks:
  - name: vpc
    class_path: blueprints.vpc.VPC
    variables:
      DomainName: *domain
  - name: webservers
    class_path: blueprints.asg.AutoscalingGroup
    variables:
      DomainName: *domain
      VpcId: ${output vpc.VpcId} # gets the VpcId Output from the vpc stack

Doing this creates an implicit dependency from the webservers stack to the vpc stack, which will cause CFNgin to submit the vpc stack, and then wait until it is complete until it submits the webservers stack. This would be the same as adding vpc to the requires field of the webservers stack.


Environment File

When using CFNgin, you can optionally provide an “environment” file. The CFNgin config file will be interpolated as a string.Template using the key-value pairs from the environment file as parameters. The format of the file is a single key-value per line, separated by a colon (:).

File Naming

Environment files must follow a specific naming format in order to be recognized by Runway. The files must also be stored at the root of the module’s directory.

${DEPLOY_ENVIRONMENT}-${AWS_REGION}.env

The typical naming format that will be used for these files specifies the name of the DEPLOY_ENVIRONMENT and AWS_REGION in which to use the file.

${DEPLOY_ENVIRONMENT}.env

The region can optionally be omitted to apply a single file to all regions.

Files following both naming schemes may be used. The file with the most specific name takes precedence. Values passed in as parameters from the Runway Config File take precedence over those provided in an environment file.

Usage

A pretty common use case is to have separate environments that you want to look mostly the same, though with some slight modifications. For example, you might want a production and a staging environment.

The production environment likely needs more instances, and often those instances will be of a larger instance type. The parameters defined in an environment file, deployment.parameters, and/or module.parameters allow you to use your existing CFNgin config, but provide different values based on the current deploy environment.

Example

vpcID: vpc-12345678

Provided the key-value pair above, you will now be able to use this in your configs for a deploy environment. They act as keys that can be used in your config file, providing a sort of templating ability. This allows you to change the values of your config based on the current deploy environment.

For example, if you have a webserver stack, and you need to provide it a variable for the instance size it should use, you would have something like this in your config file.

stacks:
  - name: webservers
    class_path: blueprints.asg.AutoscalingGroup
    variables:
      InstanceType: m3.medium

But what if you needed more CPU in your production environment, but not in your staging? Without parameters, you’d need a separate config for each. With parameters, you can simply define two different values for InstanceType in an an environment file, deployment.parameters, and/or module.parameters then use the parameter’s name to reference the value in a config file.

sampleapp.cfn/cfngin.yml
# in your config file:
stacks:
  - name: webservers:
    class_path: blueprints.asg.AutoscalingGroup
    variables:
      InstanceType: ${web_instance_type}

Using Environment Files

Both files would be required.

sampleapp.cfn/stage.env
web_instance_type: m5.medium
sampleapp.cfn/prod.env
web_instance_type: c5.xlarge

Using Runway

This option would not required the use of environment files to define the values.

runway.yaml
deployments:
  - modules:
    - name: Sample Application
      path: sampleapp.cfn
      parameters:
        web_instance_type: ${var web_instance_type.${env DEPLOY_ENVIRONMENT}}

variables:
  web_instance_type:
    stage: m5.medium
    prod: c5.xlarge