Only this pageAll pages
Powered by GitBook
1 of 69

Takomo

Loading...

Getting started

Loading...

Loading...

Loading...

Configuration

Loading...

Loading...

Loading...

Loading...

Stack properties

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Variables and templating

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Parameter resolvers

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Hooks

Loading...

Loading...

Loading...

Validation schemas

Loading...

Command-line usage

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Support

Loading...

Loading...

Development

Loading...

Installation

System requirements

Sorry to say this, but currently, Takomo doesn't work on Windows, so you need to have Linux or Mac. Takomo is built with Node.js and requires Node.js v14.4.0 or later.

Install as a project dependency

The recommended way to install Takomo is to add it as a development dependency in your project's package.json.

Initialize a new project if needed:

npm init -y

Add Takomo as a development dependency:

npm install -D takomo 

Verify installation:

npx tkm --version

Global installation

You can, of course, use global installation, too.

npm install -g takomo

Verify installation:

tkm --version

Directory structure

Takomo project's directory structure looks like this.

.
├─ stacks
├─ templates
├─ helpers
├─ partials
├─ resolvers
├─ hooks
├─ schemas
├─ deployment
├─ config-sets
└─ organization

There are two mandatory directories: stacks and templates. The stacks directory will contain all configuration files for your stacks, and the templates directory is where you'll place template files for the stacks.

You can find the purpose of each directory from the table below.

Directory

Description

stacks

Configuration files for stacks. You can create subdirectories to organize stacks and to provide common configuration. Takomo treats each subdirectory as a stack group, You can provide configuration for a stack group by placing a config.yml file into its directory.

templates

CloudFormation template files that can be referenced from the stack configuration files. You can use subdirectories to organize template files.

helpers

Custom Handlebars helpers. You can use helpers in stack configuration and template files.

partials

Handlebars partial files. You can include partial files in stack configuration and template files.

resolvers

Custom resolvers.

hooks

Custom hooks.

schemas

Custom Joi schemas.

deployment

organization

config-sets

Config sets

Configuration for .

Configuration for .

deployment targets
AWS organization management

Name

Each CloudFormation stack must have a name that is unique within the stack's region. Takomo uses stack names to match stacks found from the local configuration with the target accounts' stacks.

You can give a name for a stack using the name property.

Example

Specifying a name:

name: vpc

Default value

If you omit the name, Takomo will generate the name using the following logic:

  1. Take the stack path and remove the leading forward slash

  2. Remove the region specifier from the end of the stack path

  3. Replace the remaining forward slashes with hyphens

  4. If the project property is specified, prepend it to the name

For example, if your stack's path is /dev/eu-west-1/vpc.yml/eu-west-1, its generated name will be dev-eu-west-1-vpc.

Where to define

The name property can be defined only in stack configuration files.

Requirements

The name property must satisfy these requirements:

  • Must be a string

  • Must match regex ^[a-zA-Z0-9][-a-zA-Z0-9]*$

  • Have a minimum length of 1

  • Have a maximum length 128

Renaming stacks

You can't rename stacks. If you change the name of an existing stack, Takomo will use the new name to find a corresponding stack from the target account. As Takomo does not keep track of the stacks it has deployed, it can't know that the stack still exists with the old name.

Stacks and stack groups

You create a configuration file in the stacks directory for each stack you want to manage with Takomo. Configuration files are in YAML format and should contain the configuration needed to deploy the corresponding stacks.

Takomo uses .yml file extension with YAML files.

Stack groups for common configuration

You can create more directories under the stacks directory to group stacks by application environment, region, or another criterion. Takomo treats these directories as stack groups. You can use them to provide common configurations for stacks that belong to the stack groups by placing a config.yml file into the stack group's directory. Individual stacks can override parts or all of the configurations they inherit from their stack group.

You can also nest stack groups to create a tree-like hierarchy where child stack groups inherit configuration from their parent. Like the stacks, they can override the configuration they inherit.

The stacks directory itself is the root stack group, and the configuration defined in its config.yml file gets inherited for all other stack groups and every stack in the project.

Identifying stacks and stack groups

You identify stack groups and stacks by their path, which is basically like a file path in Linux filesystem where the stacks directory is the filesystem root.

We learned earlier the stacks directory is the root stack group. Its path is /. Other stack groups' path is the absolute file path to the stack group's directory from the stacks directory.

The stack paths follow this same logic with one important difference. A stack's path is the absolute file path to its configuration file from the stacks directory, appended with a region specifier that is a forward slash followed by the stack's region. You may omit the region specifier if the stack has only one region.

A stack can have one or more regions. The regions are defined in the stack's configuration file, which means more than one CloudFormation stack can be created from a single stack configuration file.

Command path

A common name for both stack and stack group paths is the command path. The command path is used in many places in Takomo's configuration files and is accepted as input arguments by many CLI commands. Wherever a command path is required, you can always use either a stack or stack group path.

Example project

Here is an example of how a Takomo project could look like.

.
├─ stacks
│  ├─ config.yml
│  ├─ dev
│  │  ├─ config.yml
│  │  ├─ application.yml
│  │  └─ vpc.yml
│  └─ prod
│     ├─ application.yml
│     └─ vpc.yml
└─ templates
   ├─ application-template.yml
   └─ vpc-template.yml

In the stacks directory, there is a config.yml file that contains configurations shared with all stack groups and stacks.

There are two stack groups for application environments: dev and prod. Each environment consists of two stacks: application.yml and vpc.yml. The dev environment also has its own config.yml file with configurations shared only with its stacks.

Let's say that in the root config.yml file, we specify that we want to use region eu-west-1, and that we override this for the dev environment by setting a different region, us-east-1, in its config.yml file.

The templates directory contains CloudFormation template files for the stacks.

This table shows the paths for each stack and stack group found from the example project.

File

Path

the stacks directory

/

dev

/dev

dev/application.yml

/dev/application.yml/us-east-1

dev/vpc.yml

/dev/vpc.yml/us-east-1

prod

/prod

prod/application.yml

/prod/application.yml/eu-west-1

prod/vpc.yml

/prod/vpc.yml/eu-west-1

Template

You put CloudFormation template files for stacks in the templates directory or its subdirectories.

For each stack, you specify the template file to use with the template property. It accepts a relative file path to the template file in the templates directory.

If you don't specify the template, Takomo looks for a template file using the relative file path to the current stack configuration file from the stacks directory.

Takomo supports both of the standard CloudFormation template file formats, i.e., JSON and YAML.

Example

Say, we have the following project.

.
├─ stacks
│  └─ application.yml
└─ templates
   └─ application-template.yml

In application.yml stack configuration file you can define the template property like so:

stacks/application.yml
template: application-template.yml

If you would omit the template property, Takomo would fallback to the default behaviour and look for a template file by name application.yml from the templates directory.

Inline template body

You can also inline the template body in a stack configuration file.

Example

template:
  inline: |
    Resources:
      VPC:
        Type: AWS::EC2::VPC
        Properties:
          CidrBlock: 10.0.0.0/16
  

Disabling dynamic template

By default, Takomo processes each template file with Handlebars templating engine. You can turn off this dynamic template processing by providing the template configuration with an object with two properties: filename and dynamic. The former specifies the relative file path to the template file in the templates directory., and the latter is an optional boolean to enable or disable dynamic processing.

Example

Use the object notation to disable dynamic template:

template:
  filename: networking.yml
  dynamic: false

Where to define

The template property can be defined only in stack configuration files.

Requirements

The template property must satisfy these requirements:

  • Must be a string or an object

Regions

You specify the regions where to deploy a stack using the regions property. You can give a single region or a list of regions. Each stack must have at least one region.

Examples

Specifying a single region:

regions: eu-west-1

Specifying multiple regions:

regions:
  - eu-central-1
  - eu-north-1
  - us-east-1

Where to define

The regions property can be defined in stack and stack group configuration files. If specified in a stack group, the stack group's children and stacks inherit the value. Stack groups and stacks can override the value they have inherited from their parent.

Requirements

The regions property must satisfy these requirements:

  • Must be a string or a list of strings

  • Must be valid region

Changing the regions

You can't change the stack's region. If you change the region of an existing stack, Takomo will look for a corresponding stack from the new region. As Takomo does not keep track of the stacks it has deployed, it can't know that the stack still exists in the old region.

You can always add new regions for a stack.

Template bucket

By default, the maximum size for a CloudFormation template file is 51,200 bytes. Using larger template files, up to 460,800 bytes, requires that you upload them to an S3 bucket before deployment.

You use the templateBucket property to instruct Takomo to upload template files to a specific S3 bucket before the deployment. The bucket must exist.

The templateBucket property is an object with two properties: name and keyPrefix. The former is required and used to specify the bucket's name, and the latter is optional and specifies the object key prefix under which Takomo uploads the templates files.

Examples

Specifying a template bucket with a key prefix:

templateBucket:
  name: my-bucket
  keyPrefix: template-files/

Specifying a template bucket with just a name:

templateBucket:
  name: hello-bucket

Where to define

The templateBucket property can be defined in stack and stack group configuration files. If specified in a stack group, the stack group's children and stacks inherit the value. Stack groups and stacks can override the value they have inherited from their parent.

Requirements

The templateBucket property must satisfy these requirements:

  • Name must be a valid S3 bucket name

  • Key prefix must be a valid S3 object key prefix

Command role

When you execute a Takomo command, the AWS credentials present in the current terminal session dictate the target AWS account. We call these credentials the default credentials.

Should you want to target a different account, you can specify an IAM role that Takomo should assume using the default credentials and then use it to execute the commands to the account where the role is bound. We call this role the command role, and you can specify it with the commandRole property, which accepts an IAM role ARN.

The command role must not require MFA authentication.

Example

Specify a command role:

Where to define

The capabilities property can be defined in stack and stack group configuration files. If specified in a stack group, the stack group's children and stacks inherit the value. Stack groups and stacks can override the value they have inherited from their parent.

Requirements

The commandRole property must satisfy these requirements:

  • Must be a valid IAM role ARN

arn:aws:iam::123456789012:role/deployer-role

What is Takomo?

Takomo helps you organize, parameterize and deploy CloudFormation stacks across multiple regions and accounts. It works equally well with smaller deployments consisting of just a few stacks and larger multi-account environments.

Takomo was inspired by Cloudreach’s excellent Sceptre, a CloudFormation wrapper tool built with Python, and Terraform created by Hashicorp.

Motivation

AWS CloudFormation is a great tool to manage AWS infrastructure, but as a low-level tool, it's not sufficient alone to manage deployments spanning multiple regions and accounts. Many tools do a good job generating and deploying CloudFormation templates but lack crucial features to handle large-scale deployments.

Takomo was created to overcome challenges that arise when managing a complex AWS infrastructure with inter-stack dependencies across multiple accounts and regions.

How Takomo works?

You specify the stacks you want to manage with Takomo in configuration files. Each file contains information about the stack, including stack name, regions, values for parameters and tags, and which template file to use.

When you run a command, Takomo starts by reading the configuration files and building a plan showing the changes it is about to execute. Once you have reviewed the plan, you can decide to cancel or proceed with the deployment. During the operation, Takomo prints stack events so you can see what is happening. Once the operation completes, Takomo presents you with a summary of changes and possible errors.

Takomo doesn't store the infrastructure's state or operations it has executed anywhere. It relies solely on the configuration files' information to match locally defined stacks with the ones found in the target accounts.

Features

Here are Takomo's key features.

Stack configuration

Provide configuration to your CloudFormation stacks including, input parameters, tags, region, timeouts and more. Use outputs from other stacks as input parameters to your stacks, even if the source stacks reside in different accounts or regions.

Stack deployment

Quickly deploy all of your stacks at once or choose to deploy only a subset. Takomo understands inter-stack dependencies and deploys stacks in the correct order and parallel when possible.

Generate IAM policies

Takomo helps you follow the principle of least privilege by providing you with a command to generate IAM policies based on actions performed during your previous deployments.

Resolve parameter values at deployment time

Avoid hard coding of parameter values to configuration files by using parameter resolvers that provide parameter values at deployment time.

Takomo comes with these built-in resolvers that resolve parameter values from:

  • Stack outputs - use outputs from other stacks

  • File contents - read contents of a file

  • Shell command output - execute a shell command and use its output

  • Hook output - use value exposed by a lifecycle hook

  • SSM parameter - read value from an SSM parameter

It's really easy to implement your own custom resolvers, too!

Dynamic templates files

Take advantage of dynamic Handlebars templating and avoid repetitive configuration and copy-pasting in CloudFormation templates.

Safe

Avoid mistakes by reviewing changes to the configuration before deployment. Take advantage of safety features that prevent deployments to the wrong environments and accounts:

  • Enable stack termination protection

  • Ensure stacks are deployed only to allowed accounts

Extensible

Plug in your own JavaScript code to extend the core features. You can implement your own:

  • Parameter resolvers to resolve stack parameter values at deployment time

  • Hooks to run code at different deployment stages

  • Joi validation schemas to validate your configuration

  • Handlebars helpers to run custom code when processing configuration

Continuous Integration

Easily integrate Takomo to your CI pipeline.

AWS organization management

Manage organizational units, member accounts, and policies of your AWS organization. You can also easily configure and deploy CloudFormation stacks to all of your accounts or choose to deploy to accounts that belong to a specified organizational unit.

  • Go to Takomo's organization management documentation

Quick start

This quick start guide will show you how to install and configure Takomo and deploy some basic infrastructure.

AWS credentials

During this tutorial, you'll deploy some stacks, so you need an AWS account where you can safely try things out.

Create an IAM user with administrator permissions.

Next, create access keys for the IAM user and configure them to your ~/.aws/credentials file. Let's name our profile as takomo-quick-start.

Project initialization

We'll start by creating a new directory for your Takomo project:

From now on, we'll call the takomo-quick-start directory as project's root directory.

Change to the root directory and initialize a new NPM project:

Add Takomo as a development dependency:

Initialize a new Takomo project:

From the command output you can see what directories and files were created. You might want to take a look at the files, there isn't much to see =).

Deploy stacks

Now that you have the project initialized, it's time to deploy the stacks. Go ahead and run the following command:

Takomo will present you a deployment plan. Review it and continue when you are ready. Once the deployment completes, you can see a summary of what just happened.

Clean up

You can remove the created stacks by running the following command:

You'll see a plan showing what will happen next. Review the plan and proceed. After the operation you'll see a summary.

Account ids

Working simultaneously with multiple accounts usually requires switching between many credentials or IAM roles. This poses a real risk of accidentally deploying infrastructure to the wrong account.

You can mitigate this risk with the accountIds property, which lets you define a list of allowed accounts to deploy a stack. It accepts a single account id or a list of account ids.

Examples

A single allowed account:

A list of allowed accounts:

Where to define

The accountIds property can be defined in stack and stack group configuration files. If specified in a stack group, the stack group's children and stacks inherit the value. Stack groups and stacks can override the value they have inherited from their parent.

Requirements

The accountIds property must satisfy these requirements:

  • Must be a string or a list of strings

  • Account ids must be valid AWS account ids

[takomo-quick-start]
aws_access_key_id = ENTER_YOUR_ACCESS_KEY_ID_HERE
aws_secret_access_key = ENTER_YOUR_SECRET_ACCESS_KEY_HERE
mkdir takomo-quick-start
cd takomo-quick-start
npm init -y
npm install -D takomo 
npx tkm init --create-samples --project quick-start --regions eu-west-1
npx tkm stacks deploy --profile takomo-quick-start
npx tkm stacks undeploy --profile takomo-quick-start
accountIds: "123456789012"
accountIds:
  - "876272828282"
  - "763273627326"

Depends

It’s a good practice to split the infrastructure into multiple stacks that group related resources together. Naturally, there will be dependencies between the stacks.

For example, one stack creates a VPC with subnets, and another stack creates some resources into those subnets. The stacks need to be created and updated in a certain order to ensure that the dependencies can be satisfied. For example, you need to have the subnets ready before you can create other resources into them.

You specify the stacks that a stack depends on by using the depends property which accepts a single stack path or a list of stack paths.

Examples

A single dependency:

depends: /dev/vpc.yml

A single dependency with region:

depends: /dev/vpc.yml/eu-west-1

Multiple dependencies:

depends:
  - /dev/vpc.yml
  - /dev/security-groups.yml

Using a relative stack path:

depends: ../../common/logs.yml

Where to define

The depends property can be defined only in stack configuration files.

Requirements

The depends property must satisfy these requirements:

  • Must be a string or a list of strings

  • Must contain valid stack paths

Tags

You specify stack tags with the tags property. CloudFormation automatically adds the tags to each resource in the stack that supports tagging.

Examples

Setting tags:

tags:
  foo: bar
  code: 123
  backups: true

Where to define

The tags property can be defined in stack and stack group configuration files. If specified in a stack group, the stack group's children and stacks inherit the value. Stack groups and stacks can add new tags and overwrite individual tags they inherited from their parent by specifying a new value with the same key.

Requirements

The tags property must satisfy these requirements:

  • Each tag key must be a string

  • Each tag value must be a string, a number or a boolean

AWS credentials

Using profile

The easiest way to provide credentials when running Takomo on your local computer is to configure a profile in the ~/.aws/credentials file and then either export the profile name in AWS_PROFILE environment variable or pass it on with the --profile command-line option.

Example

Configure a profile in the ~/.aws/credentials file:

You can then provide the profile in an environment variable:

Or, you can use the --profile command line option:

Assuming roles

If you have an IAM user in one account that you use to assume roles from the same or other accounts, you can configure the access keys for the user in the credentials file and then create separate profiles for each of the roles.

Example

Configure a profile and roles in the credentials file.

Now, when you run a command with account-a-admin profile, AWS SDK uses the access keys you have configured for the manager profile to assume the arn:aws:iam::123456789012:role/admin IAM role referenced by the account-a-admin profile.

Assuming roles that require MFA

You can specify in an IAM role's trust policy that the user must provide an MFA token to assume it. Then, to assume the role, you need to configure your IAM user's MFA device with mfa_serial property in the role's profile like so:

When you run a command, Takomo will ask you the MFA code.

To do anything with Takomo, you need to have valid AWS credentials configured. Under the hood, Takomo uses AWS JavaScript SDK to acquire the credentials. Take a look at to learn the ways you can configure credentials.

~/.aws/credentials
[my-profile]
aws_access_key_id=<YOUR ACCESS KEY ID>
aws_secret_access_key=<YOUR SECRET ACCESS KEY>
AWS_PROFILE=my-profile tkm stacks deploy
tkm stacks deploy --profile my-profile
~/.aws/credentials
[manager]
aws_access_key_id=<YOUR ACCESS KEY ID>
aws_secret_access_key=<YOUR SECRET ACCESS KEY>

[account-a-admin]
role_arn=arn:aws:iam::123456789012:role/admin
source_profile=manager

[account-b-readonly]
role_arn=arn:aws:iam::210987654321:role/readonly
source_profile=manager
tkm stacks deploy --profile account-a-admin
~/.aws/credentials
[manager]
aws_access_key_id=<YOUR ACCESS KEY ID>
aws_secret_access_key=<YOUR SECRET ACCESS KEY>

[account-a-admin]
role_arn=arn:aws:iam::123456789012:role/admin
source_profile=manager
mfa_serial=arn:aws:iam::224466880011:mfa/username
tkm stacks deploy --profile account-admin
the SDK's documentation

Tutorial

Now that we have the introduction out of the way, it's time to learn how to use Takomo. The best way to learn is by doing, so let's get our hands dirty and deploy some stacks.

What are we going to build?

Let's do something more interesting than just a trivial single stack example. Let's create a setup where we have a DynamoDB table, a VPC without internet access, a lambda function inside the VPC, and a VPC endpoint to DynamoDB to make it possible for the lambda function to access the DynamoDB table.

To make our configuration resemble a real-life use case, we'll create two separate environments: dev and prod.

Finally, we choose to deploy our stacks to the eu-west-1 region.

AWS credentials

During this tutorial, you'll deploy some stacks, so you need an AWS account where you can safely try things out.

Create an IAM user with administrator permissions.

Next, create access keys for the IAM user and configure them to your ~/.aws/credentials file. Let's name our profile as takomo-tutorial.

~/.aws/credentials
[takomo-tutorial]
aws_access_key_id = ENTER_YOUR_ACCESS_KEY_ID_HERE
aws_secret_access_key = ENTER_YOUR_SECRET_ACCESS_KEY_HERE

Project initialization

We'll start by creating a new directory for your Takomo project:

mkdir takomo-tutorial

From now on, we'll call the takomo-tutorial directory as project's root directory.

Change to the root directory and initialize a new NPM project:

cd takomo-tutorial
npm init -y

Add Takomo as a development dependency:

npm install -D takomo 

Project file structure

Make sure you are in the project root directory and create two other directories under it:

mkdir stacks
mkdir templates

The stacks directory will contain all configuration files for your stacks, and the templates directory is where you'll place template files for the stacks.

Stack groups

Takomo lets you organize stacks into directories under the stacks directory to group them by the environment, region, or other criteria. These directories are called stack groups. You can use them to provide configuration shared by the stacks that belong under the same stack group.

You can also nest stack groups to build tree-like hierarchies. You identify stack groups by their path, which is the file path to the stack group's directory from the stacks directory.

Let's group our stacks first by the environment and then by region. To do that, create directories under the stacks directory like so:

mkdir -p stacks/dev/eu-west-1
mkdir -p stacks/prod/eu-west-1

Now, you should have the following files in place:

.
├─ stacks
│  ├─ dev
│  │  └─ eu-west-1
│  └─ prod
│     └─ eu-west-1
├─ templates
└─ package.json

DynamoDB stack

It's time to start adding configuration for our stacks. We begin by creating a template file for the DynamoDB table. Go ahead and create a new file for it:

touch templates/dynamodb.yml

Add the following contents to it:

templates/dynamodb.yml
Parameters:
  Environment:
    Type: String
    Description: Application environment
    AllowedValues:
      - dev
      - prod

Resources:
  Table:
    Type: AWS::DynamoDB::Table
    Properties:
      TableName: !Sub my-table-${Environment}
      BillingMode: PAY_PER_REQUEST
      AttributeDefinitions:
        - AttributeName: id
          AttributeType: S
      KeySchema:
        - AttributeName: id
          KeyType: HASH

Outputs:
  TableName:
    Value: !Ref Table
  TableArn:
    Value: !GetAtt Table.Arn  

The template is simple; it has a single parameter for the environment used as a suffix of the DynamoDB table name.

Let's then add configuration for the dev environment's DynamoDB stack.

touch stacks/dev/eu-west-1/dynamodb.yml

Add the following contents to it:

stacks/dev/eu-west-1/dynamodb.yml
regions: eu-west-1
template: dynamodb.yml
parameters:
  Environment: dev

In the stack configuration file, you can find three important properties.

We instruct Takomo to deploy the stack to the eu-west-1 region using the regions property. It's in plural form because you can deploy a single stack to multiple regions, and therefore the regions property accepts a single region or a list of regions.

The template property takes a file path relative to the templates directory and specifies which template file Takomo uses when it deploys the stack.

Finally, we provide values for the stack parameters using the parameters property.

You should now have the following files in place:

.
├─ stacks
│  ├─ dev
│  │  └─ eu-west-1
│  │     └─ dynamodb.yml
│  └─ prod
│     └─ eu-west-1
├─ templates
│  └─ dynamodb.yml
└─ package.json

First deploy

Alright then, we are now ready to deploy our first stack. Make sure you are in the project's root directory and run the following command:

npx tkm stacks deploy --profile takomo-tutorial

You should see the deployment plan, and from it that you're about to deploy the DynamoDB stack.

The line printed in green displays the stack's path, which should be /dev/eu-west-1/dynamodb.yml/eu-west-1. The stack path is sort-of a file path to the stack's configuration file under the stacks directory and is used to identify stacks.

From the deployment plan, you can also see the stack's name, which is dev-eu-west-1-dynamodb. We can specify the stack name ourselves by using the name property, but as we didn't do that, Takomo generated the name for us from the stack path.

Choose "continue, but let me review changes to each stack"

You should see a stack-specific deployment plan showing changes about to be performed to the DynamoDB stack.

Choose "continue to deploy the stack, then let me review the remaining stacks"

The deployment should take a few seconds, and after it, you should see a deployment summary.

VPC stack

Let's proceed to the VPC stack. Create a template for it:

touch templates/vpc.yml

Add the following contents to it:

templates/vpc.yml
Parameters:
  Environment:
    Type: String
    Description: Application environment
    AllowedValues:
      - dev
      - prod
  VpcCidr:
    Type: String
    Description: VPC CIDR block

Resources:
  Vpc:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VpcCidr
  Subnet:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: !Ref VpcCidr
      VpcId: !Ref Vpc
  RouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref Vpc
  RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref Subnet
      RouteTableId: !Ref RouteTable

Outputs:
  VpcId:
    Value: !Ref Vpc
  RouteTableIds:
    Value: !Ref RouteTable
  SubnetIds:
    Value: !Ref Subnet

Then, create the stack configuration file:

touch stacks/dev/eu-west-1/vpc.yml

Add the following contents to it:

stacks/dev/eu-west-1/vpc.yml
regions: eu-west-1
template: vpc.yml
parameters:
  Environment: dev
  VpcCidr: 10.0.0.0/26

You should now have the following files in place:

.
├─ stacks
│  ├─ dev
│  │  └─ eu-west-1
│  │     ├─ dynamodb.yml
│  │     └─ vpc.yml
│  └─ prod
│     └─ eu-west-1
├─ templates
│  ├─ dynamodb.yml
│  └─ vpc.yml
└─ package.json

Listing stacks

Let's quickly check what stacks we have configured and what's their current status:

npx tkm stacks list --profile takomo-tutorial

You should see two stacks: the DynamoDB stack we already deployed and the VPC stack that is still waiting for deployment.

Second deploy

Rerun the deploy command to get also the VPC stack deployed:

npx tkm stacks deploy --profile takomo-tutorial

This time the deployment plan shows you both of the stacks. The DynamoDB stack already exists, and it is about to be updated. The VPC stack, on the other hand, doesn't exist yet, so Takomo needs to create it.

Choose "continue, but let me review changes to each stack"

The DynamoDB stack contains no changes and you don't need to confirm its deployment. Instead, you'll see the plan for the VPC stack.

Review the changes and choose "continue to deploy the stack, then let me review the remaining stacks".

Like earlier, the deployment takes just a short amount of time, and you'll see the summary once it completes.

Shared configuration

At this point, we notice that we have specified the same properties in multiple configuration files. Both of our stacks belong to the dev environment and reside in the eu-west-1 region.

Earlier, we learned that we can use stack groups to provide common configuration for multiple stacks. You provide configuration for a stack group by placing a config.yml file in its directory. Stacks that belong to the stack group inherit the stack group's configuration.

Let's start by creating configuration for the /dev stack group.

Create the configuration file:

touch stacks/dev/config.yml

Add the following contents to it:

stacks/dev/config.yml
data:
  environment: dev

We specified the environment under the data property. It's an object that can contain arbitrary values.

Then, create another file for the /dev/eu-west-1 stack group:

touch stacks/dev/eu-west-1/config.yml

Add the following contents to it:

stacks/dev/eu-west-1/config.yml
regions: eu-west-1

We can now remove the regions properties from our stack configuration files. We also need to modify the way we give value for the Environment parameter.

Update the stack configuration files to look like this:

stacks/dev/eu-west-1/dynamodb.yml
template: dynamodb.yml
parameters:
  Environment: {{ stackGroup.data.environment }}
stacks/dev/eu-west-1/vpc.yml
template: vpc.yml
parameters:
  Environment: {{ stackGroup.data.environment }}
  VpcCidr: 10.0.0.0/26

Notice how we refer to the values specified in the stack group.

You should now have the following files in place,:

.
├─ stacks
│  ├─ dev
│  │  ├─ config.yml
│  │  └─ eu-west-1
│  │     ├─ config.yml
│  │     ├─ dynamodb.yml
│  │     └─ vpc.yml
│  └─ prod
│     └─ eu-west-1
├─ templates
│  ├─ dynamodb.yml
│  └─ vpc.yml
└─ package.json

Our little configuration restructuring didn't actually change configurations of the stacks. We can verify that by deploying the stacks again. There shouldn't be any updates to the stacks.

npx tkm stacks deploy --profile takomo-tutorial

VPC endpoints stack

Next, we'll add a stack for the VPC endpoint that makes it possible to use DynamoDB from the VPC without Internet access.

Create a new template file:

touch templates/vpc-endpoints.yml

Add the following contents to it:

templates/vpc-endpoints.yml
Parameters:
  Environment:
    Type: String
    Description: Application environment
    AllowedValues:
      - dev
      - prod
  VpcId:
    Type: AWS::EC2::VPC::Id
    Description: Id of the VPC where the endpoints should be created
  RouteTableIds:
    Type: CommaDelimitedList
    Description: Ids of the route tables where the endpoints should be attached

Resources:
  DynamoDbVpcEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      RouteTableIds: !Ref RouteTableIds
      ServiceName: !Sub com.amazonaws.${AWS::Region}.dynamodb
      VpcEndpointType: Gateway
      VpcId: !Ref VpcId

Then, create the stack configuration file:

touch stacks/dev/eu-west-1/vpc-endpoints.yml

Add the following contents to it:

stacks/dev/eu-west-1/vpc-endpoints.yml
template: vpc-endpoints.yml
parameters:
  Environment: {{ stackGroup.data.environment }}
  VpcId:
    resolver: stack-output
    stack: vpc.yml
    output: VpcId
  RouteTableIds:
    resolver: stack-output
    stack: vpc.yml
    output: RouteTableIds

The parameters in this stack use a new kind of syntax. Previously, we have used static values for our parameters, but here we are using parameter resolvers that resolve the parameter values at deployment time.

Resolver of type stack-output reads the value for a parameter from another stack's outputs. In this case, we read values from the VPC stack's outputs.

You should now have the following files in place:

.
├─ stacks
│  ├─ dev
│  │  ├─ config.yml
│  │  └─ eu-west-1
│  │     ├─ config.yml
│  │     ├─ dynamodb.yml
│  │     ├─ vpc.yml
│  │     └─ vpc-endpoints.yml
│  └─ prod
│     └─ eu-west-1
├─ templates
│  ├─ dynamodb.yml
│  ├─ vpc.yml
│  └─ vpc-endpoints.yml
└─ package.json

It's again time to deploy our changes, but this time, let's do something different. Instead of deploying all stacks, let's deploy just the VPC endpoints stack. To achieve that, you need to give the path of the stack you want to deploy to the deploy stacks command:

npx tkm stacks deploy \
  /dev/eu-west-1/vpc-endpoints.yml \
  --profile takomo-tutorial

When you review the deployment plan, you notice something that you might find unexpected. You chose to deploy only the VPC endpoints stack, but the deployment plan indicates that Takomo will deploy the VPC stack as well.

This is because the VPC endpoints stack uses the VPC stack's outputs as inputs to its parameters, making the VPC endpoint stack dependent on the VPC stack. When building the deployment plan, Takomo takes relations between the stacks into account and ensures that it deploys the stacks in the correct order.

Lambda function stack

The infrastructure for the dev environment is almost complete. We still need to add the Lambda function that accesses the DynamoDB table through the VPC endpoint.

Let's start by creating a file that holds the Lambda function body:

mkdir partials
touch partials/lambda.js

Add the following contents to it:

partials/lambda.js
const AWS = require("aws-sdk")
const dynamo = new AWS.DynamoDB.DocumentClient()

exports.handler = async (event, context) => {
  console.log("EVENT: \n" + JSON.stringify(event, null, 2))
  await dynamo.put({
    TableName: process.env.TABLE_NAME,
    Item: {
      id: Date.now().toString()
    }  
  }).promise()
  
  const { Count } = await dynamo.scan({ TableName: process.env.TABLE_NAME }).promise()
  return Count
}

Create a new template file:

touch templates/lambda.yml

Add the following contents to it:

templates/lambda.yml
Parameters:
  Environment:
    Type: String
    Description: Application environment
    AllowedValues:
      - dev
      - prod
  VpcId:
    Type: AWS::EC2::VPC::Id
    Description: Id of the VPC where the endpoints should be created
  SubnetIds:
    Type: CommaDelimitedList
    Description: Ids of the subnets where the function should be created
  TableName:
    Type: String
    Description: Name of the DynamoDB table
  TableArn:
    Type: String
    Description: ARN of the DynamoDB table

Resources:
  FunctionSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: !Sub tutorial-function-${Environment}
      VpcId: !Ref VpcId
      
  FunctionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole     
      Policies:
        - PolicyName: DynamoDB
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - dynamodb:PutItem
                  - dynamodb:Scan
                Resource: !Ref TableArn
                      
  Function:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: !Sub tutorial-function-${Environment}
      Handler: index.handler
      MemorySize: 128
      Role: !GetAtt FunctionRole.Arn
      Runtime: nodejs12.x
      Timeout: 10
      Environment:
        Variables:
          TABLE_NAME: !Ref TableName
      VpcConfig:
        SecurityGroupIds:
          - !Ref FunctionSecurityGroup
        SubnetIds: !Ref SubnetIds
      Code:
        ZipFile: |
          {{> lambda.js }}

Notice how the lambda code is included in the template file (line 69).

Then, create the stack configuration file:

touch stacks/dev/eu-west-1/lambda.yml

Add the following contents to it:

stacks/dev/eu-west-1/lambda.yml
template: lambda.yml
parameters:
  Environment: {{ stackGroup.data.environment }}
  VpcId:
    resolver: stack-output
    stack: vpc.yml
    output: VpcId
  SubnetIds:
    resolver: stack-output
    stack: vpc.yml
    output: SubnetIds
  TableName:
    resolver: stack-output
    stack: dynamodb.yml
    output: TableName
  TableArn:
    resolver: stack-output
    stack: dynamodb.yml
    output: TableArn

You should now have the following files in place:

.
├─ stacks
│  ├─ dev
│  │  ├─ config.yml
│  │  └─ eu-west-1
│  │     ├─ config.yml
│  │     ├─ dynamodb.yml
│  │     ├─ lambda.yml
│  │     ├─ vpc.yml
│  │     └─ vpc-endpoints.yml
│  └─ prod
│     └─ eu-west-1
├─ templates
│  ├─ dynamodb.yml
│  ├─ vpc.yml
│  └─ vpc-endpoints.yml
└─ package.json

It's time to deploy the stacks again to get the lambda function stack created.

npx tkm stacks deploy --profile takomo-tutorial

Testing

We now have everything ready for the development environment, and it's time to test the lambda function.

If you have the AWS CLI installed, you can test the function from command-line:

aws lambda invoke \
  --region eu-west-1 \
  --function-name tutorial-function-dev \
  --profile takomo-tutorial \
  response.txt

The lambda returns the number of items in the DynamoDB table, so each invocation should increase the number in response.txt by one.

You can also invoke the function from AWS management console.

Production environment

Now that we have the dev environment ready, it's time to set up the prod environment.

Create shared configuration for the prod environment.

touch stacks/prod/config.yml

Add the following contents to it:

stacks/prod/config.yml
data:
  environment: prod

Then, create configuration shared by all stacks located in the eu-west-1 region.

touch stacks/prod/eu-west-1/config.yml

Add the following contents to it:

stacks/prod/eu-west-1/config.yml
regions: eu-west-1

Next, create configuration files for the stacks.

touch stacks/prod/eu-west-1/dynamodb.yml
touch stacks/prod/eu-west-1/lambda.yml
touch stacks/prod/eu-west-1/vpc.yml
touch stacks/prod/eu-west-1/vpc-endpoints.yml

Then, add the following contents to them:

stacks/prod/eu-west-1/dynamodb.yml
template: dynamodb.yml
parameters:
  Environment: {{ stackGroup.data.environment }}
stacks/prod/eu-west-1/lambda.yml
template: lambda.yml
parameters:
  Environment: {{ stackGroup.data.environment }}
  VpcId:
    resolver: stack-output
    stack: vpc.yml
    output: VpcId
  SubnetIds:
    resolver: stack-output
    stack: vpc.yml
    output: SubnetIds
  TableName:
    resolver: stack-output
    stack: dynamodb.yml
    output: TableName
  TableArn:
    resolver: stack-output
    stack: dynamodb.yml
    output: TableArn
stacks/prod/eu-west-1/vpc.yml
template: vpc.yml
parameters:
  Environment: {{ stackGroup.data.environment }}
  VpcCidr: 10.0.0.64/26
stacks/prod/eu-west-1/vpc-endpoints.yml
template: vpc-endpoints.yml
parameters:
  Environment: {{ stackGroup.data.environment }}
  VpcId:
    resolver: stack-output
    stack: vpc.yml
    output: VpcId
  RouteTableIds:
    resolver: stack-output
    stack: vpc.yml
    output: RouteTableIds

Your file structure should now look like this:

.
├─ stacks
│  ├─ dev
│  │  ├─ config.yml
│  │  └─ eu-west-1
│  │     ├─ config.yml
│  │     ├─ dynamodb.yml
│  │     ├─ lambda.yml
│  │     ├─ vpc.yml
│  │     └─ vpc-endpoints.yml
│  └─ prod
│     ├─ config.yml
│     └─ eu-west-1
│        ├─ config.yml
│        ├─ dynamodb.yml
│        ├─ lambda.yml
│        ├─ vpc.yml
│        └─ vpc-endpoints.yml
├─ templates
│  ├─ dynamodb.yml
│  ├─ vpc.yml
│  └─ vpc-endpoints.yml
└─ package.json

Let's quickly check how our stacks look like now:

npx tkm stacks list --profile takomo-tutorial

You should see four more stacks in addition to the existing dev stacks.

Deploy the stacks like earlier but this time use -y option to skip the plan review and confirm step.

npx tkm stacks deploy --profile takomo-tutorial -y

Clean up

You have reached the end of this tutorial. Hopefully, you now have a better understanding of how to configure and deploy CloudFormation stacks with Takomo.

To remove the stacks you have created, run the next command:

npx tkm stacks undeploy --profile takomo-tutorial

Parameters

You use the parameter property to define input parameters for a stack. It's an object of key-value pairs where the keys are parameter names, and the values are configuration for the corresponding parameter values.

The value configuration can be a single static value, an object, or a list of the two types mentioned above. You must use the object configuration when the parameter requires additional configuration, or you want Takomo to resolve its value at deployment time.

Simple static parameters

The simplest way to specify the value for a parameter is to hard code the value to the stack configuration file.

Examples

A single static value for a parameter named VpcId:

A list of values for a parameter named CidrBlocks:

Static parameters with object notation

You can provide configuration for static parameters using the object notation which allows you to use additional properties in the configuration. When using the object notation you give the parameter value in value property:

Example

A single static parameter using the object notation:

Immutable parameters

You can mark parameters as immutable if you want to make sure their values are not updated. Many CloudFormation resources have properties that don't support updating after creation, and making them immutable in stack configuration helps prevent failures during deployment.

A parameter can't be marked as immutable if it has NoEcho set to true in the CloudFormation template file. There is no way to find out the current value for NoEcho parameters and therefore Takomo can't detect if their value is about to be changed.

Example

A static immutable value for a parameter named VpcId:

Dynamic parameters

In many cases, it's not wise or even possible to hard code all parameter values. When you need to assign parameter values dynamically at deployment time, you can use parameter resolvers. There are a few built-in parameter resolvers, and you can also implement your own.

You use the resolver property to specify which parameter resolver to use to resolve the value for a parameter.

Examples

If you have two stacks configured within the same Takomo project, you can use the stack-output resolver to read the first stack's output value and use it as a parameter value in the second stack.

If the stacks are not configured within the same Takomo project, you need to use the external-stack-output resolver.

Where to define

The parameters property can be defined only in stack configuration files.

Requirements

The parameters property must satisfy these requirements:

  • Parameter name must be a string

  • Parameter name must match regex ^[a-zA-Z0-9]*$

See also

Project configuration

You can configure project-wide settings in a takomo.yml file that you place in the project root directory.

Required Takomo version

Example

Require Takomo version 3.4.0 or above:

Allowed regions

By default, the supported regions are hardcoded in Takomo's codebase. A new Takomo version is released whenever AWS launches new regions.

In case you need to use an older Takomo version that does not include some regions launched after its release, you may specify the missing regions yourself using this property.

You can also use this property to list only the regions you intend to use to prevent deploys to any other region.

Example

Allow only these four regions:

Feature flags

You can enable and disable certain Takomo features by specifying feature flags under the features property. Here are the available feature flags

Example

Disable undeploy deployment targets command:

Extending project configuration

You can make a Takomo project configuration file to inherit configuration from another file. Inheriting configuration becomes useful, for example, when you have a monorepo containing multiple Takomo projects, each having its own configuration and sharing some common properties with others. You can place the common properties in a parent file that others then inherit.

You use the extends property to make a project configuration file inherit configuration from another file:

Below, you can find some examples of built-in parameter resolvers. You can read more about parameter resolvers from .

You specify the required Takomo version with the requiredVersion property. It accepts a NPM compatible version range.

parameters:
  VpcId: vpc-06e4ab6c6c
parameters:
  CidrBlocks:
    - 10.0.0.0/26
    - 10.0.0.64/26
parameters:
  VpcId:
    value: vpc-06e4ab6c6c
parameters:
  VpcId:
    value: vpc-06e4ab6c6c
    immutable: true
parameters:
  VpcId:
    resolver: stack-output
    stack: /vpc.yml
    output: vpcId
parameters:
  VpcId:
    resolver: external-stack-output
    stack: vpc-stack
    output: vpcId
    region: eu-west-1
    commandRole: arn:aws:iam::123456789012:role/deployer
takomo.yml
requiredVersion: ">=3.4.0"
takomo.yml
regions:
  - us-east-1
  - eu-west-1
  - eu-central-1
  - eu-north-1 

Feature flag

Description

deploymentTargetsUndeploy

Set false to disable undeploy deployment targets command.

You might want to disable this command to add an extra confirmation step to prevent removing targets unintentionally.

You can override this setting by giving --feature deploymentTargetsUndeploy=true option from command-line when executing undeploy deployment targets command.

deploymentTargetsTearDown

Set false to disable tear down deployment targets command.

You might want to disable this command to add an extra confirmation step to prevent removing targets unintentionally.

You can override this setting by giving --feature deploymentTargetsTearDown=true option from command-line when executing tear down deployment targets command.

takomo.yml
features:
  deploymentTargetsUndeploy: false
takomo.yml
extends: ../my-parent-config.yml
here
Built-in parameter resolvers
Implementing custom parameter resolvers
semver

Stack policy

You specify a stack policy with the stackPolicy property. It accepts a string or an object.

Examples

Setting a stack policy as a string:

stackPolicy: |
  {
    "Statement": [
      {
        "Effect": "Allow",
        "NotAction": "Update:Delete",
        "Principal": "*",
        "Resource": "*"
      }
    ]
  }

Setting a stack policy as an object:

stackPolicy:
  Statement:
    - Effect: Allow
      NotAction: Update:Delete
      Principal: "*"
      Resource: "*"

Stack policy during update

You specify a stack policy to use during stack update with the stackPolicyDuringUpdate property. It works the same way as the stackPolicy property.

Examples

Setting a stack policy to use during the stack update as an object:

stackPolicyDuringUpdate:
  Statement:
    - Effect: Allow
      Action: Update:*
      Principal: "*"
      Resource: "*"

Deleting stack policy

CloudFormation doesn't support removing of a stack policy once it has been created. As a workaround, when you remove the stack policy from the stack configuration, Takomo updates the policy with the allow all policy shown below, which is essentially equivalent to not having a stack policy attached at all.

allow all stack policy
{
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "Update:*",
      "Principal": "*",
      "Resource": "*"
    }
  ]
}

Where to define

The stackPolicy and stackPolicyDuringUpdate properties can be defined in stack and stack group configuration files. If specified in a stack group, the stack group's children and stacks inherit the value. Stack groups and stacks can overwrite the policies they inherited from their parent.

Requirements

The stackPolicy property must satisfy these requirements:

  • Must be a valid JSON document

Timeout

You specify a timeout in seconds for stack create and update operations by using the timeout property. Takomo cancels the operation if it takes longer than what you have specified in the timeout property. You can't set a timeout for the delete operation. Use 0 to disable the timeout.

You set the timeout for both create and update operations by specifying a single integer. You can also set a separate timeout for create and update operations by using an object with create and update properties.

Examples

Timeout of 180 seconds for both create and update:

timeout: 180

Timeout of 300 seconds for create and no timeout for update:

timeout:
  create: 300

Separate timeouts for create and update:

timeout:
  create: 300
  update: 120

Where to define

The timeout property can be defined in stack and stack group configuration files. If specified in a stack group, the stack group's children and stacks inherit the value. Stack groups and stacks can override the value they have inherited from their parent.

Requirements

The timeout property must satisfy these requirements:

  • Must be an integer greater or equal to 0

Termination protection

You can enable termination protection for a stack with the terminationProtection property.

Example

Enabling termination protection:

terminationProtection: true

Default value

Termination protection is not enabled by default.

Where to define

The terminationProtection property can be defined in stack and stack group configuration files. If specified in a stack group, the stack group's children and stacks inherit the value. Stack groups and stacks can override the value they have inherited from their parent.

Requirements

The terminationProtection property must satisfy these requirements:

  • Must be a boolean

Capabilities

You specify stack capabilities with the capabilities property.

Examples

A single capability:

capabilities: CAPABILITY_IAM

A list of capabilities

capabilities:
  - CAPABILITY_IAM
  - CAPABILITY_NAMED_IAM

Disable all capabilities:

capabilities: []

Default value

By default, all capabilities are enabled.

Where to define

The capabilities property can be defined in stack and stack group configuration files. If specified in a stack group, the stack group's children and stacks inherit the value. Stack groups and stacks can override the value they have inherited from their parent.

Requirements

The capabilities property must satisfy these requirements:

  • Must be a string or a list of strings

  • Allowed values are:

    • CAPABILITY_IAM

    • CAPABILITY_NAMED_IAM

    • CAPABILITY_AUTO_EXPAND

Ignore

You can exclude stacks and stack groups from the configuration with the ignore property.

Examples

Setting the ignore property:

Where to define

The ignore property can be defined in stack and stack group configuration files. If specified in a stack group, the stack group's children and stacks inherit the value. If you set a stack group as ignored, its children or stacks can't set the ignore property back to false.

Requirements

The ignore property must satisfy these requirements:

  • Must be a boolean

ignore: true

Inherit tags

By default, stacks and stack groups inherit tags from their parent stack group. You can disable this behaviour by setting inheritTags to false.

Examples

Disable inheriting of tags.

inheritTags: false

Where to define

The inheritTags property can be defined in stack and stack group configuration files. Disabling tag inheritance in a stack group configuration affects only to the stack group itself and not stacks and stack groups that belong under it.

Requirements

The inheritTags property must satisfy these requirements:

  • Must be a boolean

Introduction

Sometimes static configuration files and templates are not enough to solve the real-life problems we might face. To help overcome those trickier challenges and avoid tedious and error-prone manual work, Takomo supports dynamic templating with Handlebars.

All standard Handlebars features are available, which means you can use loops, if-conditions, partial includes, helpers, and variables to streamline your configuration.

By default, Takomo processes all stack configuration, stack group configuration, and stack template files using Handlebars.

You can turn off dynamic processing of stack template files by setting dynamic to false under the stack's template property.

Understanding dynamic templating

It's essential to understand how dynamic templating works with Takomo. Takomo processes configuration files with Handlebars before parsing their content. The output produced by the processing needs to be a valid YAML document.

The YAML standard has some gotchas which may cause unexpected behaviour especially if you generate configuration files dynamically using Handlebars. It's helpful to set the logging level to trace when troubleshooting YAML-related problems.

Schemas

You can use custom Joi validation schemas to validate the following parts of stack configuration:

  • stack data

  • stack tags

  • stack parameters

  • stack name

You use the schemas property to specify which schemas Takomo should use for validation.

Example

In this example we have specified to use myDataSchema schema to validate data configuration. For tags, we have two schemas: commonTags and environmentTag.

schemas:
  data: myDataSchema
  tags:
    - commonTags
    - name: environmentTag
      allowedValues:
        - dev
        - test
        - prod

The implementation of myDataSchema schema provider could look like this:

schemas/data.js

module.exports = {
  name: "myDataSchema",
  init: ({ joi }) => joi.object({
    owner: joi.string().email(),
    costCenter: joi.number().required()
  }) 
}

The file exports an object with two properties name and init. The former specifies the schema's name used to refer to it from configuration files and the latter is a function that initializes the schema object.

Read more about custom validation schemas from here.

The implementation of commonTags schema provider could look like this:

schemas/common-tags.js
module.exports = {
  name: "commonTags",
  init: ({ joi }) => joi.object({
    project: joi.string().required()
  })
}

Finally, we have the implementation of environmentTag schema provider:

schemas/environment-tag.js
module.exports = {
  name: "environmentTag",
  init: ({ joi, props }) => {
    return joi.object({
      environment: joi.string().valid(...props.allowedValues)
    })
  }
}

Unlike the other schema providers, its init function uses properties from the stack configuration file that are passed via the props argument.

Where to define

The schemas property can be defined in stack and stack group configuration files. If specified in a stack group, the stack group's children and stacks inherit the value. The schemas defined by stack groups and stacks are appended to the list of schemas they inherit from their parent.

Requirements

The schemas property must satisfy these requirements:

  • Must be an object with the following optional properties: data, tags, parameters and name.

Hooks

You use the hooks property to specify actions Takomo should execute at different stages of deploy and undeploy commands. The hooks property accepts a list of hook configuration objects. A hook configuration object has the following properties:

  • name - Name of the hook

  • type - Type of the hook

  • operation - Operations during which the hook should be executed

    • Supported operations are:

      • create

      • update

      • delete

    • Accepts a single operation or a list of operations

    • By default, a hook is executed on every operation

  • stage - Stages during which the hook should be executed

    • Supported values are:

      • before

      • after

    • Accepts a single stage or a list of stages

    • By default, a hook is executed on every stage

  • status - Statuses during which the hook should be executed

    • Available on when stage is after

    • Supported values are:

      • success - The operation succeeded

      • failed - The operation failed

      • cancelled - The operation was cancelled

    • By default, a hook is executed on every status

Takomo executes hooks in the order that you have defined them in the configuration files. If one hook fails, the whole stack operation with any remaining hooks is aborted and deemed a failure.

Examples

A cmd hook that is executed after a successful stack creation:

A cmd hook that is executed after all create and update operations:

Where to define

The hooks property can be defined in stack and stack group configuration files. If specified in a stack group, the stack group's children and stacks inherit the value. The hooks defined by stack groups and stacks are appended to the list of hooks they inherit from their parent.

Requirements

The hooks property must satisfy these requirements:

  • Must be a list of objects

See also

hooks:
  - name: executed-after-successful-create
    type: cmd
    operation: create
    stage: after
    status: success
    command: echo 'success'
hooks:
  - name: my-hook
    type: cmd
    operation:
      - create
      - update
    stage: after
    command: echo 'hello'
Built-in hooks
Implementing custom hooks

Handlebars syntax

Here's a short guide to Handlebars syntax. For more information, consult the official Handlebars documentation.

Variables

You refer to variables like this:

{{ variable_name }}

If the variable is an object with properties of its own, you can refer to them like so:

{{ person.firstName }}

This is how you refer to a specific index of an array:

{{ people.[0] }}

Comments

You can use Handlebars comments in your files. Commented out sections won't show up in the final rendered output.

{{! This comment will not show up in the output}}

If the content you want to comment out contains }} or other Handlebars tokens, you need to use different comment style:

{{!-- This comment may contain mustaches like }} --}}

If-conditions

Here's an example of if-condition:

{{#if some_variable}}
  this will be included in the output
{{/if}}

Iterating over collections

This is how you iterate over a collection of items:

{{#each securityGroupIds}}
  - {{this}}
{{/each}}

Obsolete

You can exclude stacks from configuration by marking them as obsolete with the obsolete property. Obsolete stacks can be removed with prune stacks command.

Obsolete stacks can't have dependents that are not obsolete themselves.

Examples

Setting the obsolete property:

obsolete: true

Where to define

The obsolete property can be defined in stack and stack group configuration files. If specified in a stack group, the stack group's children and stacks inherit the value but can also override it.

Requirements

The obsolete property must satisfy these requirements:

  • Must be a boolean

Data

You can define custom properties by using the data property. The properties specified in a stack group configuration are available in its children's and stack's configuration files and stack templates files.

Example

If you specify data in a stack configuration file like this:

data:
  subnets:
    - subnet-ccbbb18ac981dc554e
    - subnet-969b3de3fa0a275d9b
    - subnet-7609598000b229fcb3
  environment:
    name: dev
    code: 123

Then, you can refer to the properties in the stack template file like so:

Resources:
  Bucket:
    Type: AWS::S3::Bucket
    Properties:
      Tags:
        - Key: Environment
          Value: {{ stack.data.environment.name }}
        - Key: Code
          Value: {{ stack.data.environment.code }}

Where to define

The data property can be defined in stack and stack group configuration files. If specified in a stack group, the stack group's children and stacks inherit the value. Takomo merges the properties defined by stack groups and stacks to the properties they inherit from their parents.

Requirements

The data property must satisfy these requirements:

  • Must be an object

Helpers

Environment variables

System environment variables are exposed via the env variable.

Example

Here's an example how to print the HOME environment variable:

Home dir is {{ env.HOME }}

Partials

Each file in the partials directory or its subdirectory can be used as Handlebars partial.

Example

If the partials directory contains a file named my-partial.hbs, you can include it as a partial in a configuration file like so:

{{> my-partial.hbs }}

External stack output resolver

The external stack output resolver reads the parameter value from a stack output of a stack. The source stack does not have to belong to the same Takomo project as the target stack.

Properties

Here are the properties of the external stack output resolver:

Key
Required
Type
Description

resolver

yes

string

Resolver name, this must be external-stack-output.

stack

yes

string

Name of the source stack.

output

yes

string

Name of the stack output whose value is read.

region

no

string

Region of the source stack. Region is optional. By default, the region of the target stack is used.

commandRole

no

string

IAM role used to access the stack output. Command role is optional. By default, credentials associated with the target stack are used.

confidential

no

boolean

Conceal the resolved parameter value from logs, defaults to false

immutable

no

boolean

Mark the parameter as immutable, defaults to false

Example

Say, we have two accounts: 123456789012 and 888888888888.

The account 123456789012 has one stack: src-bucket. It is located in the us-east-1 region and exposes the name of an application source bucket in a stack output named SrcBucketName. The 123456789012 account also has a read-only role that the 888888888888 account can assume.

The 888888888888 account has two stacks: assets-bucket and build-infra. The stacks are located in the us-east-1 and eu-west-1 regions, respectively. The assets-bucket stack exposes the name of an assets bucket in a stack output named AssetsBucket.

Only the build-infra stack is managed in our Takomo project. The two other stacks are configured elsewhere. The build-infra stack has two parameters: SrcBucket and AssetsBucket. To get the values for them, we use the external-stack-output resolver to read the two other stacks' outputs.

The directory structure looks like this:

.
├─ stacks
│  └─ build-infra.yml
└─ templates
   └─ build-infra.yml

The configuration of build-infra stack looks like this:

stacks/build-infra.yml
regions: us-east-1
parameters:
  SrcBucket:
    resolver: external-stack-output
    stack: src-bucket
    output: SrcBucketName
    commandRole: arn:aws:iam::123456789012:role/read-only
  AssetsBucket:
    resolver: external-stack-output
    stack: assets-bucket
    output: AssetsBucketName
    region: eu-west-1

For the SrcBucket parameter, we need to specify the commandRole property because the source stack is located in a different account. We don't need to specify the region because both stacks are located in the same region.

For the AssetsBucket parameter, we must specify the region but not the commandRole because the stacks are located in the same account but different regions.

Available variables

You can use variables in stack and stack group configuration files and stack template files. Each of them has a different set of variables available.

Stack group configuration files

Here are variables available in stack group configuration files:

Stack configuration files

Here are variables available in stack configuration files:

Stack template files

Here are variables available in stack template files:

Key

Type

Description

env

object

Environment variables.

context

object

An object containing context variables.

context.projectDir

string

Current project directory.

stackGroup

object

An object representing the current stack group.

stackGroup.name

string

Name of the stack group.

stackGroup.path

string

Path of the stack group.

stackGroup.pathSegments

string[]

Path of the stack group split into an array using / as a separator.

parent

object

An object representing the parent stack group where the stack group belongs to.

parent.accountIds

string[]

Account ids of the parent stack group.

parent.capabilities

string[]

Capabilities of the parent stack group.

parent.commandRole

string

Command role of the parent stack group.

parent.data

object

Data object of the parent stack group.

parent.isRoot

boolean

Is the parent stack group the root.

parent.name

string

Name of the parent stack group.

parent.path

string

Path of the parent stack group.

parent.pathSegments

string[]

Path of the parent stack group split into an array using / as a separator.

parent.project

string

Project of the parent stack group.

parent.regions

string

Regions of the parent stack group.

parent.tags

object[]

Stack tags of the parent stack group.

parent.tags[].key

string

Tag key.

parent.tags[].value

string

Tag value.

parent.templateBucket

object

Template bucket configuration of the parent stack group.

parent.templateBucket.name

string

Name of the template bucket.

parent.templateBucket.keyPrefix

string

Key prefix of the template bucket.

parent.timeout

object

Timeout configuration of the parent stack group.

parent.timeout.create

number

Create timeout in seconds.

parent.timeout.update

number

Update timeout in seconds.

var

object

Variables from the command line.

Key

Type

Description

context

object

An object containing context variables.

context.projectDir

string

Current project directory.

env

object

Environment variables.

stackGroup

object

An object representing the stack group where the stack belongs to.

stackGroup.accountIds

string[]

Account ids of the stack group.

stackGroup.capabilities

string[]

Capabilities of the stack group.

stackGroup.commandRole

string

Command role of the stack group.

stackGroup.data

object

Data object of the stack group.

stackGroup.isRoot

boolean

Is the stack group the root.

stackGroup.name

string

Name of the stack group.

stackGroup.path

string

Path of the stack group.

stackGroup.pathSegments

string[]

Path of the stack group split into an array using / as a separator.

stackGroup.project

string

Project of the stack group.

stackGroup.regions

string

Regions of the stack group.

stackGroup.tags

object[]

Stack tags of the stack group.

stackGroup.tags[].key

string

Tag key.

stackGroup.tags[].value

string

Tag value.

stackGroup.templateBucket

object

Template bucket configuration of the stack group.

stackGroup.templateBucket.name

string

Name of the template bucket.

stackGroup.templateBucket.keyPrefix

string

Key prefix of the template bucket.

stackGroup.timeout

object

Timeout configuration of the stack group.

stackGroup.timeout.create

number

Create timeout in seconds.

stackGroup.timeout.update

number

Update timeout in seconds.

stack

object

An object representing the stack.

stack.configFile

object

An object representing configuration file of the stack.

stack.configFile.basename

string

Name of the stack configuration file including the file extension

stack.configFile.dirPath

string

File path to the directory containing the stack configuration file relative to stack directory.

stack.configFile.filePath

string

File path of the stack configuration file relative to stack directory.

stack.configFile.name

string

Name of the stack configuration file without the file extension.

stack.path

string

Path of the stack without the region specified.

stack.pathSegments

string[]

Path of the stack without the region specified split into an array using / as a separator.

var

object

Variables from the command line.

Key

Type

Description

context

object

An object containing context variables.

context.projectDir

string

Current project directory.

env

object

Environment variables.

hooks

object

An object containing values returned by hooks

stack

object

An object representing the current stack

stack.accountIds

string[]

Account ids of the stack.

stack.commandRole

string

Command role of the stack.

stack.configFile

object

An object representing configuration file of the stack.

stack.configFile.basename

string

Name of the stack configuration file including the file extension

stack.configFile.dirPath

string

File path to the directory containing the stack configuration file relative to stack directory.

stack.configFile.filePath

string

File path of the stack configuration file relative to stack directory.

stack.configFile.name

string

Name of the stack configuration file without the file extension.

stack.data

object

Data object of the stack.

stack.depends

string[]

Dependencies of the stack.

stack.name

string

Name of the stack.

stack.path

string

Path of the stack.

stack.pathSegments

string[]

Path of the stack split into an array using / as a separator.

stack.parameters

object[]

Parameters of the stack

stack.parameters[].key

string

Parameters key

stack.parameters[].value

string

Parameters value

stack.parametersMap

object

Stack parameters in an object where each key is a parameter key and value is the corresponding parameter value.

stack.project

string

Project of the stack.

stack.region

string

Region of the stack.

stack.tags

object[]

Stack tags of the stack.

stack.tags[].key

string

Tag key.

stack.tags[].value

string

Tag value.

stack.template

string

Template of the stack.

stack.templateBucket

object

Template bucket configuration of the stack.

stack.templateBucket.name

string

Name of the template bucket.

stack.templateBucket.keyPrefix

string

Key prefix of the template bucket.

stack.timeout

object

Timeout configuration of the stack.

stack.timeout.create

number

Create timeout in seconds.

stack.timeout.update

number

Update timeout in seconds.

var

object

Variables from the command line.

Built-in parameter resolvers

You can use parameter resolvers to resolve values for stack parameters at deployment time. Takomo has a few built-in parameter resolvers, and you can also implement your own.

In a stack configuration, you choose which resolver to use by providing value to the resolver property. In addition to the resolver property, each resolver may have its own set of additional properties.

Here are the built-in parameter resolvers:

  • Stack output resolver

  • External stack output resolver

  • Command resolver

  • File contents resolver

  • Hook output resolver

  • SSM parameter resolver

  • Secret resolver

See also

  • Configuring parameter resolvers in stack configuration

  • Implementing custom parameter resolvers

Command-line variables

You can pass variables from command line using --var and --var-file options. Both options can be used multiple times. Variables are exposed via var variable.

Named variables

Use --var option to pass a single named variable from the command line.

Example

Provide a single variable named myVariable with value hello:

--var myVariable=hello

You can refer to the variable in configuration files like so:

Resources:
  LogGroup:
    Type: AWS::Logs::LogGroup
    LogGroupName: {{ var.myVariable }}

Variables from files

Use --var-file option to load variables from a file. If the file extension is .json or .yml, the file is first parsed into an object which is then stored to a variable. If the file extension is something else, the contents are just read into a variable.

The variable name can be omitted for .yml and .json files as long as the file contents can be deserialized to an object. The deserialized object is then stored to the top-level of variables.

Example - Read file contents to a variable

If the project directory contains a file named commit.txt, you can read its contents into a variable named commitHash like so:

--var-file commitHash=commit.txt

Example - Deserialize file contents to a variable

Here's an example how you would deserialize file contents to a variable. Suppose you have a file /home/variables.yml with valid YAML contents:

/home/variables.yml
name: James
age: 55
permissions:
  - create
  - delete
  - update

You can deserialize its contents to a variable named myVariable like so:

--var-file person=/home/variables.yml

And then use the variable in the configuration like so:

parameters:
  UserName: {{ var.person.name }}
  UserAge: {{ var.person.age }}

Example - Deserialize file contents to top-level variables

Say, you have a file properties.json with valid JSON contents:

properties.json
{
  "color: "red",
  "foo": {
    "bar": true
  }
}

You can deserialize its contents to top-level of variables:

--var-file person=/home/variables.yml

And then use the variables in the configuration like so:

parameters:
  Color: {{ var.color }}
  FooBarEnabled: {{ var.foo.bar }}

Loading order and merging of variables

Variables from files are loaded first in the order they are defined, and then the named variables also in the definition order. Variables defined later will override previously loaded variables with the same name. Complex variables are merged recursively.

Example

Say, you have a JSON file that defines some basic settings:

base.json
{
  "color": "blue",
  "width": 100,
  "settings": {
    "debug": true
  }
}

You also have another file that contains environment-specific settings:

prod.json
{
  "settings": {
    "debug": false
  }
}

You can load both settings files and also override and extend the loaded configuration using named variables:

--var-file base.json \
  --var-file prod.json \
  --var color=yellow \
  --var height=200

The final merged variables object would look like this:

{
  "color": "yellow",
  "width": 100,
  "height": 200,
  "settings": {
    "debug": false
  }
}

File contents resolver

The file contents resolver reads a file and uses the file contents as a parameter value.

Properties

Here are the properties of the file contents resolver:

Examples

Use contents of the /tmp/commit.txt file as parameter value:

Use a relative file path:

Secret resolver

The secret parameter resolver reads parameter values from secrets stored in Secrets Manager.

Properties

Here are the properties of the secret parameter resolver:

Examples

Read the parameter value from a secret with id "my-secret-password":

Read the parameter value from a secret in a different region:

Read the parameter value from a different account

SSM parameter resolver

The SSM parameter resolver reads parameter values from SSM parameter store. The parameter can be encrypted.

Properties

Here are the properties of the SSM parameter resolver:

Examples

Read value from an SSM parameter /database/password that resides in the same region as the current stack:

Read value from an SSM parameter /database/username that resides in eu-north-1 region:

Read value from an SSM parameter using custom IAM role:

Custom parameter resolvers

You can provide custom parameter resolvers by placing plain JavaScript files, with .js file extension, into the resolvers directory. Each file must export a parameter resolver provider object. Takomo uses the provider to initialize the actual parameter resolver.

You can use all language features available in Node 14.4.0.

Parameter Resolver Provider

  • name

    • Name of the resolver used to refer to the resolver from stack configuration files.

    • Must be either a string or a synchronous function that returns a string.

    • Required.

  • init

    • A function that initializes the resolver with properties given in a stack configuration file.

    • Can be either synchronous or asynchronous.

    • Required.

  • schema

    • It takes one argument that is an object with the following properties:

      • joi - Joi instance to create new validation constraints

    • You can return the pre-initialized schema from the schema function or use the Joi instance to create an entirely new schema. In most cases you should modify the base schema object as needed and then return it.

Parameter Resolver

  • resolve

    • A function that resolves the actual parameter value. The resolved value can be of any type and is converted to a string before it is passed to CloudFormation. If the value is an array, it is converted to a string by joining its values with a comma.

      • listParameterIndex - If the parameter whose value is being resolved is of type list, this will hold the index of the value in the list. The index begins from 0. This will be 0 if the parameter being resolved os not list.

      • parameterName - Name of the parameter whose value is being resolved.

  • confidential

    • A boolean or a synchronous function that returns a boolean value determining if the resolved parameter value should be concealed from log messages. The confidential property in a stack configuration file takes precedence over this value.

    • Optional, defaults to false.

  • dependencies

    • A list of stack paths or a synchronous function that returns a list of stack paths of the stacks that the resolver depends on.

    • Optional, defaults to an empty list.

  • iamRoleArns

    • A list of IAM role ARNs or a synchronous function that returns a list of IAM role ARNs needed to resolve the value.

    • Optional, defaults to an empty list.

Examples

Simple custom resolver

Here's an example of a simple custom parameter resolver that converts the value given in the parameter resolver configuration to uppercase. The parameter resolver schema requires that in the stack configuration file where the resolver is used, the resolver configuration must contain a value property of type string, and that its value must not have more than 50 characters.

Our file structure looks like this:

The parameter resolver provider defined in resolvers/uppercase.js looks like this:

Our custom parameter resolver is used in the stack configuration like so:

When the stack is deployed, the value for MyParameter parameter is resolved using the uppercase custom parameter resolver. The actual value that is assigned to the parameter will be "HELLO".

Publishing resolvers to NPM

Example

Here's an example of how to publish a simple custom resolver that returns the current timestamp. The project file structure looks like this:

The index.js file contains the parameter resolver provider:

The package.json file contains minimum configuration that is needed to publish the resolver to NPM:

Using resolvers from NPM

To use custom resolvers published to NPM, you need to install the resolver's NPM package to your project and then register the resolver in your project's takomo.yml file.

Example

Let's see how we would include the timestamp resolver from the previous example to our own project.

First of all, we need to install and save the resolver package to our project's dependencies.:

Then, we need to register the resolver to our Takomo project by modifying the takomo.yml file. There are three ways to register a resolver:

When registering the resolver using option 1 or 2, Takomo registers the resolver using the name exposed by the resolver provider object - in this case that is timestamp.

It's possible that our project already has a resolver registered with the same name. Takomo requires that all resolver names are unique and will throw an error if more that one resolver has the same name. To work around this problem, you can use the third way to register a resolver, which let's you specify a new name for it. In our example, we have set the resolver name to be special-timestamp.

Command resolver

The command resolver executes a specified shell command and uses the command output as a parameter value.

Properties

Here are the properties of the command resolver:

Environment variables available in the shell command

The following environment variables are available in the shell command:

Example

Use contents of the /home/password.txt file as parameter value:

Built-in hooks

You can use hooks to execute actions at specific stages of stack deploy and undeploy operations. Takomo has two built-in hooks, and you can also implement your own.

In a stack configuration, you choose which type of hook to use by providing value to the type property. You also need to give a name for each hook. In addition to these two mandatory properties, each hook type may have its own set of additional properties.

Command hook

The command hook executes the specified shell command.

Properties

Here are the properties of the Command hook:

Environment variables available in the shell command

The following environment variables are available in the shell command:

Any output the hook prints to the stdout is captured and exposed to other hooks.

Examples

A command hook that runs a simple shell command:

A command hook that exposes the current stack's AWS credentials to the shell command:

Checksum hook

The checksum hook calculates a checksum from a specified directory. The checksum is calculated recursively, i.e. all files and directories under the specified directory are included in the checksum.

Properties

Here are the properties of the Checksum hook:

Examples

Calculate a checksum from a directory lambda/scripts located in the project directory.

The same as above but using the hex encoding.

See also

Stack output resolver

Stack output resolver reads the parameter value from a stack output of another stack configured within the same Takomo project. The source stack automatically becomes the target stack's dependency. Takomo reads the output value using the credentials associated with the source stack.

Properties

Here are the properties of the stack output resolver:

Example

Say, we have two stacks: vpc.yml and security-groups.yml. The former creates a VPC and exposes its id in the stack outputs with a name VpcId, and the latter uses the VPC id to create some security groups.

The directory structure looks like this:

In security-groups.yml stack configuration we use the stack-output resolver to read the value for the VpcId parameter like so:

Hook output resolver

The hook output resolver reads parameter values from hook outputs.

Properties

Here are the properties of the hook output resolver:

Examples

This stack configuration has a hook named my-hook, which runs before stack operations. It is a command hook and will store the output from the shell command to hook outputs from where the subsequent hooks and parameter resolvers can access it.

A hook output resolver reads the output of my-hook and sets it as the value of the Greeting parameter.

Key
Required
Type
Description
Key
Required
Type
Description
Key
Required
Type
Description

The parameter resolver provider must implement the which has the following properties:

Must return an instantiated object.

An optional function that returns a schema that is used to validate configuration provided for the resolver from stack configuration files.

ctx - object that provides access to project configuration

base - A pre-initialized that you can modify to provide your resolver's validation schema

The parameter resolver must implement the which consists of the following properties:

The resolve function is invoked with a single argument of type that contains the following properties:

ctx - object that provides access to project configuration

logger - instance.

stack - The where the parameter whose value is being resolved belongs to.

variables - A mutable copy of the current command during the stack operation.

You can share your custom resolvers with others by publishing them to NPM. The published NPM package must export a object.

Refer to official for more information about publishing NPM packages.

Once the resolver is registered, you can use it like any resolver. For more information, see the related .

Key
Required
Type
Description

If you need to read outputs of stacks that are not configured in the same Takomo project, you can use the .

Key
Required
Type
Description
Key
Required
Type
Description

resolver

yes

string

Resolver name, this must be file-contents.

file

yes

string

Path to file. Can be an absolute path or a path relative to the project directory.

confidential

no

boolean

Conceal the resolved parameter value from logs, defaults to false

immutable

no

boolean

Mark the parameter as immutable, defaults to false

parameters:
  CommitHash:
    resolver: file-contents
    file: /tmp/commit.txt
parameters:
  Code:
    resolver: file-contents
    file: code.txt

resolver

yes

string

Resolver name, this must be secret.

secretId

yes

string

Secret id.

versionId

no

string

Secret version id.

versionStage

no

string

Secret version stage.

commandRole

no

string

IAM role used to access the secret from Secrets Manager. Command role is optional. By default, credentials associated with the current stack are used.

region

no

string

Region where the secret resides. By default, Takomo uses the region of the stack where the parameter resolver is used.

confidential

no

boolean

Conceal the resolved parameter value from logs, defaults to false

immutable

no

boolean

Mark the parameter as immutable, defaults to false

parameters:
  Password:
    resolver: secret
    secretId: my-secret-password
parameters:
  MyParam:
    resolver: secret
    secretId: my-secret-password
    region: eu-west-1
parameters:
  MyParam:
    resolver: secret
    secretId: arn:aws:secretsmanager:us-west-2:123456789012:secret:MySecret
    commandRole: arn:aws:iam::123456789012:role/SecretReader

resolver

yes

string

Resolver name, this must be ssm.

name

yes

string

Name of the SSM parameter.

region

no

string

Region where the SSM parameter resides. By default, Takomo uses the region of the stack where the parameter resolver is used.

commandRole

no

string

IAM role used to access the SSM parameter. Command role is optional. By default, credentials associated with the current stack are used.

confidential

no

boolean

Conceal the resolved parameter value from logs, defaults to false

immutable

no

boolean

Mark the parameter as immutable, defaults to false

parameters:
  Password:
    resolver: ssm
    name: /database/password
parameters:
  Username:
    resolver: ssm
    region: eu-north-1
    name: /database/username
parameters:
  Password:
    resolver: ssm
    commandRole: arn:aws:iam::123456789012:role/read-only
    name: MyParam
.
├─ stacks
│  └─ my-stack.yml
├─ resolvers
│  └─ uppercase.js
└─ templates
   └─ my-stack.yml
resolvers/uppercase.js
module.exports = {
  name: "uppercase",
  schema: ({joi, base}) => {
    return base.keys({
      value: joi.string().max(50).required()
    })
  },
  init: (props) => {
    return {
      confidential: true,
      dependencies: () => [],
      iamRoleArns: [],
      resolve: (input) => {
        input.logger.debug("Execute uppercase!");
        input.logger.debug(`Resolve value for parameter '${input.parameterName}'`);
        return props.value.toUpperCase();
      }
    }
  }
}
stacks/my-stack.yml
parameters:
  MyParameter:
    resolver: uppercase
    value: hello
.
├─ index.js
└─ package.json
index.js
module.exports = {
  name: "timestamp",
  init: () => Date.now(),
}
package.json
{
  "name": "takomo-timestamp-resolver",
  "version": "0.0.1",
  "description": "My custom timestamp resolver",
  "files": [
    "index.js"
  ],
  "main": "index.js",
  "license": "MIT",
  "publishConfig": {
    "access": "public",
    "registry": "https://registry.npmjs.org/"
  }
}
npm install takomo-timestamp-resolver@0.0.1 --save-dev 
takomo.yml
# Add resolvers section
resolvers:

  # 1) Use just the package name
  - takomo-timestamp-resolver

  # 2) Give the package name with 'package' property
  - package: takomo-timestamp-resolver

  # 3) Give the package name with 'package' property and
  #    override the resolver name with 'name' property.    
  - package: takomo-timestamp-resolver
    name: special-timestamp

resolver

yes

string

Resolver name, this must be cmd.

command

yes

string

Shell command to execute.

confidential

no

boolean

Conceal the resolved parameter value from logs, defaults to false

immutable

no

boolean

Mark the parameter as immutable, defaults to false

exposeStackCredentials

no

boolean

Make the current stack's AWS credentials available for the shell command. Defaults to false. Added in Takomo v3.11.0.

exposeStackRegion

no

boolean

Make the current stack's region available for the shell command. Defaults to false. Added in Takomo v3.11.0.

capture

no

string

Controls how to capture the output of the executed shell command. By default, all output is captured. To capture only the last line, set this to last-line. Added in Takomo v3.11.0.

Name

Description

AWS_ACCESS_KEY_ID

If exposeStackCredentials is true, this will hold the access key id of credentials of the current stack.

AWS_SECRET_ACCESS_KEY

If exposeStackCredentials is true, this will hold the secret access key of credentials of the current stack.

AWS_SESSION_TOKEN

If exposeStackCredentials is true, this will hold the session token of credentials of the current stack.

AWS_SECURITY_TOKEN

If exposeStackCredentials is true, this will hold the session token of credentials of the current stack.

AWS_DEFAULT_REGION

IF exposeStackRegion is true, this will hold the region of the current stack.

parameters:
  Password:
    resolver: cmd
    command: cat /home/password.txt

Key

Required

Type

Description

type

yes

string

Type of the hook, this must be cmd.

name

yes

string

Name of the hook.

command

yes

string

Shell command to execute.

cwd

no

string

Path to the working directory from where the shell command is executed. Relative to the current project directory.

exposeStackCredentials

no

boolean

Make the current stack's AWS credentials available for the shell command. Defaults to false.

exposeStackRegion

no

boolean

Make the current stack's region available for the shell command. Defaults to false.

capture

no

string

Controls how to capture the output of the executed shell command. By default, all output is captured. To capture only the last line, set this to last-line.

Name

Description

TKM_COMMAND_STAGE

The current stack operation stage.

TKM_COMMAND_OPERATION

The current stack operation.

TKM_COMMAND_STATUS

The current stack operation status, not present in before stage

AWS_ACCESS_KEY_ID

If exposeStackCredentials is true, this will hold the access key id of credentials of the current stack.

AWS_SECRET_ACCESS_KEY

If exposeStackCredentials is true, this will hold the secret access key of credentials of the current stack.

AWS_SESSION_TOKEN

If exposeStackCredentials is true, this will hold the session token of credentials of the current stack.

AWS_SECURITY_TOKEN

If exposeStackCredentials is true, this will hold the session token of credentials of the current stack.

AWS_DEFAULT_REGION

If exposeStackRegion is true, this will hold the region of the current stack.

TKM_HOOK_{hook-name}

Values returned from previous hooks are exposed in environment variables where the {hook-name} placeholder is replaced with the hook's name. Hooks whose name has unsafe characters not compatible with a pattern /^[a-zA-Z_]+[a-zA-Z0-9_]*$/ are not exposed and a warning is logged instead.

- name: my-hook
  type: cmd
  command: echo 'hello world'
- name: my-another-hook
  type: cmd
  exposeStackCredentials: true
  command: aws sts get-caller-identity

Key

Required

Type

Description

type

yes

string

Type of the hook, this must be checksum

name

yes

string

Name of the hook

dir

yes

string

Path to the directory from where the checksum should be calculated. The path can be absolute or relative to the project directory.

encoding

no

string

Encoding used to encode the calculated checksum. Supported values are base64 (default) and hex.

- name: my-checksum
  type: checksum
  dir: lambda/scripts
- name: my-hex-checksum
  type: checksum
  dir: lambda/scripts
  encoding: hex

resolver

yes

string

Resolver name, this must be stack-output.

stack

yes

string

Stack path of the source stack. Can be an absolute or a relative stack path.

output

yes

string

Name of the stack output whose value is read.

confidential

no

boolean

Conceal the resolved parameter value from logs, defaults to false

immutable

no

boolean

Mark the parameter as immutable, defaults to false

.
├─ stacks
│  ├─ vpc.yml
│  └─ security-groups.yml
└─ templates
   ├─ vpc.yml
   └─ security-groups.yml
stacks/security-groups.yml
parameters:
  VpcId:
    resolver: stack-output
    stack: /vpc.yml
    output: MyVpcId

resolver

yes

string

Resolver name, this must be hook-output.

hook

yes

string

Name of the hook whose output should be read.

confidential

no

boolean

Conceal the resolved parameter value from logs, defaults to false

immutable

no

boolean

Mark the parameter as immutable, defaults to false

parameters:
  Greeting:
    resolver: hook-output
    hook: my-hook
hooks:
  - name: my-hook
    type: cmd
    stage: before
    command: echo 'hello world'
ResolverProvider interface
parameter resolver
Joi
CommandContext
Joi object schema
Resolver interface
ResolverInput
CommandContext
Logger
stack
variables
parameter resolver provider
NPM documentation
documentation
Configuring hooks in stack configuration
external stack output resolver

Sharing data between hooks

Hooks can expose values to other hooks by returning a hook output object. Takomo stores the returned value with a hook's name in a mutable variables object that it then passes to the subsequent hooks. Takomo discards the mutable variables object after the stack operation completes, which means the exposed data is not visible to hooks executed in other stacks.

Example

This example shows how you can share data between hooks.

Our file structure looks like this:

.
├─ stacks
│  └─ my-stack.yml
├─ hooks
│  ├─ first.js 
│  └─ second.js
└─ templates
   └─ my-stack.yml

There are two custom hooks located in the hooks dir.

hooks/first.js
module.exports = {
  type: "first",
  init: (props) => {
    return {
      execute: (input) => {
        return {
          message: "OK",
          success: true,
          value: "My greeting to the next hook"
        }
      }
    }
  }
}

The first hook returns a hook output object that contains a greeting to other hooks in the value property.

hooks/second.js
module.exports = {
  type: "second",
  init: (props) => {
    return {
      execute: (input) => {
        const greeting = input.variables.hooks.firstHook
        // Do something with the greeting here...
        return true
      }
    }
  }
}

The second hook reads the greeting from the input argument.

And this is how you glue everything together in a stack configuration file:

template: my-stack.yml
regions: eu-west-1
hooks:
  - name: firstHook
    type: first
  - name: secondHook
    type: second  

The hooks property defines two hooks, one of each type. Takomo executes the hooks in order they are defined.

Undeploy stacks

Undeploy (remove) stacks within the given command path.

Takomo also removes stacks that depend on the stacks within the command path, even if they are outside the given command path. Takomo arranges the stacks in removal order by stack dependencies, ensuring that it removes the stacks in the correct order and in parallel when possible.

Usage

tkm stacks undeploy [command-path] \
  [--ignore-dependencies] \
  [--interactive|-i] \
  [--output <format>]

Positional arguments

  • command-path

    • Command path to select which stacks to undeploy.

    • Optional, by default, Takomo undeploys all stacks.

Options

In addition to the common options, this command has the following options.

  • --ignore-dependencies

    • Ignore stack dependencies. By default, when a stack is removed, its dependants are removed first, and then the stack itself. In some exceptional cases, you might want to remove just one stack and skip its dependants.

    • Bear in mind that this option is supported only when exactly one stack is removed. Ignoring dependants may lead into unexpected results, so you should use this option only in exceptional circumstances.

  • --interactive, -i

    • Choose the command path using autocompleting search.

  • --output <format>

    • Print the command result using this format

    • Supported values: text, json, yaml

IAM permissions

These are the minimum IAM permissions required to run this command.

# Minimum permissions. Additional permissions are needed to actually 
# remove the resources defined in CloudFormation templates.
Statement: 
  - Sid: Stacks
    Effect: Allow
    Action:
      - cloudformation:DescribeStackEvents
      - cloudformation:DeleteStack
      - cloudformation:DescribeStacks
    Resource: "*"

  # IAM permissions needed only if command roles are used  
  # Specify resource to restrict access to specific roles.  
  - Sid: IAM
    Effect: Allow
    Action:
      - sts:AssumeRole
    Resource: "*" 

Examples

Undeploy all stacks:

tkm stacks undeploy

Undeploy stacks within the given command path:

tkm stacks undeploy /dev

Undeploy only /dev/vpc.yml stack and its dependants:

tkm stacks undeploy /dev/vpc.yml

The region part must be specified if the stack has more than one region and you want to undeploy it from only one region.

tkm stacks undeploy /dev/vpc.yml/eu-west-1

Undeploy exactly one stack and skip its dependants:

tkm stacks undeploy /cloudtrail.yml --ignore-dependencies

Custom validation schemas

You can use custom Joi validation schemas to validate your configuration.

Please read more about Joi from its official documentation.

You provide custom validation schemas by placing plain JavaScript files, with .js file extension, into the schemas directory or its subdirectories. Each file must export a schema provider object. Takomo uses the provider to initialize the actual schema.

You can use all language features available in Node 14.4.0.

Schema provider

Schema provider initializes a Joi validation schema. It has the following properties:

  • name

    • Name of the resolver used to refer to the schema from configuration files. It can be either a string or a function that returns a string. The function must not be asynchronous.

    • Required.

  • init

    • A function that initializes the Joi schema object with properties given in a configuration file that uses to the schema.

    • The function can be either synchronous or asynchronous, and must return an instantiated Joi schema.

    • It takes one argument that is an object with the following properties:

      • ctx - CommandContext object that provides access to project configuration

      • joi - Joi instance to create new validation constraints

      • props - Properties from the configuration file

    • Required.

  • schema

    • A function that return a Joi schema object used to validate the properties given to the init function.

    • It takes one argument that is an object with the following properties:

      • ctx - CommandContext object that provides access to project configuration

      • joi - Joi instance to create new validation constraints

      • base - A pre-initialized Joi object schema that you can modify to provide your resolver's validation schema

    • You can return the pre-initialized schema from the schema function or use the Joi instance to create an entirely new schema. In most cases you should modify the base schema object as needed and then return it.

    • Optional.

You can find more information from the API documentation.

Examples

Here are a few examples of custom schemas.

Validation schema for stack tags

You can use the schemas property to specify validation schemas for stack tag configuration. Tag configuration is an object whose keys are tag keys and values are value for the corresponding tags. Therefore you need to use Joi's object schema to validate your tag configurations.

First, you need to implement a schema provider. We name our tag schema as my-tags and specify two required properties: environment and costCenter. In other words, we require that every stack must always have these two tags.

schemas/my-tags.js
module.exports = {
  name: "my-tags",
  init: ({ joi }) => joi.object({
    environment: joi.string().valid("dev", "test", "prod").required(),
    costCenter: joi.number().required()
  }).unknown(false)
} 

In stack configuration we specify that we want to validate stack tags using our custom schema like so:

schemas:
  tags: my-tags
  
tags:
  environment: dev
  costCenter: 1234  

Custom hooks

You can provide custom hooks by placing plain JavaScript files, with .js file extension, into the hooks directory. Each file must export a hook provider object. Takomo uses the provider to initialize the actual hook.

You can use all language features available in Node 14.4.0.

Hook provider

Hook provider has the following properties:

Key

Required

Type

Description

type

yes

string

Type of the hook

init

yes

function

Hook

Hook has the following properties:

Key

Required

Type

Description

execute

yes

function

Hook Input

A hook input is an object that is passed to hook's execute function. It has the following properties:

Key

Required

Type

Description

stage

yes

string

Current stack operation stage. Possible values are: before, after

operation

yes

string

Current stack operation. Possible values are: create, update, delete

status

yes

string

Current stack operation status. Possible values are: success, failed, cancelled This is defined only when the stage is after.

variables

yes

object

Mutable variables object containing command line and environment variables. The hook can modify existing variables and add new ones. After the hook is completed, the same variables object is passed to the subsequent hooks which can then access its contents. The variables are available also in the stack's template file.

ctx

yes

object

Command context object

Hook Output

A hook output is a value returned from hook's execute function. It is used to determine if the hook execution was successful and to share data between hooks. It can be either a boolean, an Error which is always considered as failure, or a detailed object with the following properties:

Key

Required

Type

Description

success

yes

boolean

A boolean determining if the hook execution was successful.

message

no

string

An informative message about the hook execution outcome.

value

no

any

A value to be exposed to other hooks.

skip

no

boolean

A boolean determining if all the remaining hooks of the current stack and the stack operation itself should be skipped.

Example

This example hook prints some debug information to the console.

Our file structure looks like this:

.
├─ stacks
│  └─ my-stack.yml
├─ hooks
│  └─ debug.js
└─ templates
   └─ my-stack.yml

The hook provider defined in hooks/debug.js looks like this:

hooks/debug.js
module.exports = {
  type: "debug",
  init: (props) => {
    console.log("Initialize debug hook")
    return {
      execute: (input) => {
        console.log("Execute debug hook!")
        console.log(`Stage:     ${input.stage}`)
        console.log(`Operation: ${input.operation}`)
        console.log(`Status:    ${input.status}`)
        console.log(JSON.stringify(props, null, 2))
        
        return {
          message: "OK",
          success: true,
          value: "Did some debugging"
        }
      }
    }
  }
}

Our custom hook is used in the stack configuration like so:

stacks/my-stack.yml
hooks:
  - name: my-hook
    type: debug

When executed, the hook exposes string "Did some debugging" in the mutable variables object.

Prune stacks

Undeploy (remove) stacks marked as obsolete within the given command path.

Takomo also removes obsolete stacks that depend on the obsolete stacks within the command path, even if they are outside the given command path. Takomo arranges the stacks in removal order by stack dependencies, ensuring that it removes the stacks in the correct order and in parallel when possible.

Obsolete stacks can't have dependent stacks that are not obsolete themselves.

Usage

Positional arguments

  • command-path

    • Command path to select which stacks to prune.

    • Optional, by default, Takomo prunes all stacks.

Options

  • --ignore-dependencies

    • Ignore stack dependencies. By default, when a stack is removed, its dependants are removed first, and then the stack itself. In some exceptional cases, you might want to remove just one stack and skip its dependants.

    • Bear in mind that this option is supported only when exactly one stack is removed. Ignoring dependants may lead into unexpected results, so you should use this option only in exceptional circumstances.

  • --interactive, -i

    • Choose the command path using autocompleting search.

  • --output <format>

    • Print the command result using this format

    • Supported values: text, json, yaml

IAM permissions

These are the minimum IAM permissions required to run this command.

Examples

Prune all stacks:

Prune stacks within the given command path:

Prune only /dev/vpc.yml stack and its dependants:

The region part must be specified if the stack has more than one region and you want to prune it from only one region.

Prune exactly one stack and skip its dependants:

Common options

Here are the options available for all commands (unless stated otherwise).

Assume yes to all questions

Pass --yes or -y option to answer yes to all questions.

Display help

Pass --help option to display help. Command specific helps include also the minimum IAM permissions needed to run the command.

Display Takomo version

Pass --version option to print version information.

Enable confidential information logging

By default, environment variables and confidential parameter values are concealed from logs. Override this default by passing --log-confidential-info.

Enable statistics

Use --stats option to print statistics information of the executed command.

Feature flags

You can use --feature <feature>=<boolean value> option to enable and disable certain Takomo features.

Available feature flags:

Load AWS SDK config

Use --load-aws-sdk-config to prefer loading credentials from configuration file over the credentials file. Passing this option will enable loading the profile from ~/.aws/config file.

Load environment variables from a file

Use --env-file <path-to-environment-variables-file> to load environment variables from a file. The loaded variables override existing variables with the same name. This option can be used multiple times.

Set logging level

Use --log <level> option to choose the logging level.

Supported values are:

  • trace

  • debug

  • info (default)

  • warn

  • error

  • none (suppress all logging)

Set project dir

Use --dir <directory> or -d <directory> option to define the directory from where Takomo loads configuration.

Set variables

Pass --var and --var-file options to provide variables that can be used in stack group and stack configuration files and stack templates. Both options can be used multiple times.

Show command to generate IAM policies

Use --show-generate-iam-policies option to print instructions how to generate IAM policies needed to run the command.

Suppress all but the final output

Use --quiet or -q to suppress all logging and all but the final output. Useful when you want to write the command output to a file.

Use AWS profile

Use --profile <profile> option to choose which AWS profile to use.

Deploy stacks

Deploy stacks within the given command path.

Takomo also deploys stacks that the stacks within the command path depend on, even if they are outside the given command path. Takomo arranges the stacks in deployment order by stack dependencies, ensuring that it deploys the stacks in the correct order and in parallel when possible.

Takomo deletes stacks whose creation have failed earlier and then recreates them. Such failed stacks can't be updated, and deleting them is the only possible operation.

Usage

Positional arguments

  • command-path

    • Command path to select which stacks to deploy.

    • Optional, by default, Takomo deploys all stacks.

Options

  • --ignore-dependencies

    • Ignore stack dependencies. By default, when a stack is deployed, its dependencies are deployed first, and then the stack itself. In some exceptional cases, you might want to deploy just one stack and skip its dependencies.

    • Bear in mind that this option is supported only when exactly one stack is deployed. Ignoring dependencies may lead into unexpected results, so you should use this option only in exceptional circumstances.

  • --interactive, -i

    • Choose the command path using autocompleting search.

  • --expect-no-changes

    • Fail the deployment if at least one stack has changes.

  • --output <format>

    • Print the command result using this format

    • Supported values: text, json, yaml

IAM permissions

These are the minimum IAM permissions required to run this command.

Examples

Deploy all stacks:

Deploy stacks within the given command path:

Deploy only /dev/vpc.yml stack and its dependencies:

The region part must be specified if the stack has more than one region and you want to deploy it to only one region.

Deploy exactly one stack and skip its dependencies:

A function that initializes the hook with properties given in a stack group or stack configuration file. The function can be either synchronous or asynchronous, and must return an instantiated .

A function that is invoked with when the hook is executed. The function can be synchronous or asynchronous and must return .

In addition to the , this command has the following options.

deploymentTargetsUndeploy - Set false to disable command

deploymentTargetsTearDown - Set false to disable command

The environment variables must be defined in a format accepted by , like so:

For more information, see .

For more information, see .

In addition to the , this command has the following options.

tkm stacks prune [command-path] \
  [--ignore-dependencies] \
  [--interactive|-i] \
  [--output <format>]
# Minimum permissions. Additional permissions are needed to actually 
# remove the resources defined in CloudFormation templates.
Statement: 
  - Sid: Stacks
    Effect: Allow
    Action:
      - cloudformation:DescribeStackEvents
      - cloudformation:DeleteStack
      - cloudformation:DescribeStacks
    Resource: "*"

  # IAM permissions needed only if command roles are used  
  # Specify resource to restrict access to specific roles.  
  - Sid: IAM
    Effect: Allow
    Action:
      - sts:AssumeRole
    Resource: "*" 
tkm stacks prune
tkm stacks prune /dev
tkm stacks prune /dev/vpc.yml
tkm stacks prune /dev/vpc.yml/eu-west-1
tkm stacks prune /cloudtrail.yml --ignore-dependencies
DB_HOST=localhost
DB_USER=root
DB_PASS=s1mpl3
tkm stacks deploy [command-path] \
  [--ignore-dependencies] \
  [--interactive|-i] \
  [--expect-no-changes] \
  [--output <format>]
# Minimum permissions. Additional permissions are needed to actually 
# modify resources defined in the CloudFormation templates.
Statement: 
  - Sid: CloudFormation
    Effect: Allow
    Action:
      - cloudformation:CancelUpdateStack
      - cloudformation:DescribeStackEvents
      - cloudformation:CreateStack
      - cloudformation:GetTemplate
      - cloudformation:DeleteStack
      - cloudformation:UpdateStack
      - cloudformation:CreateChangeSet
      - cloudformation:DescribeChangeSet
      - cloudformation:DeleteChangeSet
      - cloudformation:ValidateTemplate
      - cloudformation:DescribeStacks
      - cloudformation:GetTemplateSummary
      - cloudformation:UpdateTerminationProtection
    Resource: "*"
  
  # S3 permissions needed only if a template bucket is used.
  # Specify resource to restrict access to specific buckets.  
  - Sid: S3
    Effect: Allow
    Action:
      - s3:PutObject
    Resource: "*"
  
  # IAM permissions needed only if command roles are used  
  # Specify resource to restrict access to specific roles.  
  - Sid: IAM
    Effect: Allow
    Action:
      - sts:AssumeRole
    Resource: "*"
tkm stacks deploy
tkm stacks deploy /prod
tkm stacks deploy /dev/vpc.yml
tkm stacks deploy /dev/vpc.yml/eu-west-1
tkm stacks deploy /cloudtrail.yml --ignore-dependencies
hook object
an hook input object
a hook output
common options
Assume yes to all questions
Display help
Display Takomo version
Enable confidential information logging
Enable statistics
Feature flags
Load AWS SDK config
Load environment variables from a file
Set logging level
Set project dir
Set variables
Show command to generate IAM policies
Suppress all but the final output
Use AWS profile
undeploy deployment targets
tear down deployment targets
dotenv
command-line variables
AWS credentials
common options

List stacks

List stacks within the given command path.

Usage

tkm stacks list [command-path] [--output <format>]

Positional arguments

  • command-path

    • Command path to select which stacks to list.

    • Optional, by default, Takomo lists all stacks.

Options

In addition to the common options, this command has the following options.

  • --output <format>

    • Print the command result using this format

    • Supported values: text, json, yaml

IAM permissions

These are the minimum IAM permissions required to run this command.

Statement: 
  - Sid: Stacks
    Effect: Allow
    Action: cloudformation:DescribeStacks
    Resource: "*"

  # IAM permissions needed only if command roles are used.  
  # Specify Resource to restrict access to specific roles.  
  - Sid: IAM
    Effect: Allow
    Action: sts:AssumeRole
    Resource: "*" 

Examples

List all stacks:

tkm stacks list

List stacks within the given command path:

tkm stacks list /prod

Detect drift

Detect drift of stacks within the given command path.

Usage

tkm stacks detect-drift [command-path]

Positional arguments

  • command-path

    • Command path to select from which stacks to detect drift.

    • Optional, by default, Takomo detects drift from all stacks.

Options

In addition to the common options, this command has no command-specific options.

IAM permissions

These are the minimum IAM permissions required to run this command.

Statement: 
  - Sid: Stacks
    Effect: Allow
    Action:
      - cloudformation:DescribeStacks
      - cloudformation:DetectStackDrift
      - cloudformation:DescribeStackDriftDetectionStatus
    Resource: "*"

  # IAM permissions needed only if command roles are used  
  # Specify resource to restrict access to specific roles.  
  - Sid: IAM
    Effect: Allow
    Action:
      - sts:AssumeRole
    Resource: "*"  

Examples

Detect drift from all stacks:

tkm stacks detect-drift

Detect drift from stacks within the given command path:

tkm stacks detect-drift /prod

Getting help

Questions and assistance

If you need help or have general questions concerning Takomo, feel free to contact us at Gitter or start a GitHub discussion.

Bug reports and feature requests

Bug reports and feature requests are welcome via GitHub issues.

Inspect stack configuration

Show stack configuration within the given command path.

Usage

tkm stacks inspect configuration [command-path] \
  [--interactive|-i] \
  [--output <format>]

Positional arguments

  • command-path

    • Command path to select which stacks to include.

    • Optional, by default, Takomo lists all stacks.

Options

In addition to the common options, this command has the following options.

  • --interactive, -i

    • Choose the command path using autocompleting search.

  • --output <format>

    • Print the result from the command using this format

    • Supported values: text, json, yaml

Examples

Show configuration of all stacks:

tkm stacks inspect configuration

Show configuration of stacks within the given command path:

tkm stacks inspect configuration /prod

Inspect stack dependencies

Inspect dependencies between stacks within the given command path. Prints the dependency graph in a DOT format which can be rendered using various tools like this one.

Usage

tkm stacks inspect dependency-graph [command-path]

Positional arguments

  • command-path

    • Command path to select which stacks to include.

    • Optional, by default, Takomo lists all stacks.

Options

In addition to the common options, this command has no command-specific options.

Examples

Inspect dependencies from all stacks:

tkm stacks inspect dependency-graph

Inspect dependencies within the given command path:

tkm stacks inspect dependency-graph /prod

Generate IAM policies

Generate IAM policies based on CloudTrail events occurred between the given start and end time, in the given regions, by the given identities.

Important

The IAM policies generated by this command are based on events found from CloudTrail at the time the command is executed. There are a few things to keep in mind when generating policies.

  • You need to have CloudTrail enabled, preferably in all regions.

  • The IAM policies generated by this command can contain invalid IAM actions because not all events logged in CloudTrail can be mapped directly to valid IAM actions. You should use the generated policies as a starting point for your own handcrafted and fine-tuned policies.

  • Typically, the performed actions become visible in CloudTrail within 15 minutes. You should wait at least that time before running the command shown above to ensure the generated policies contain all actions. If you suspect that not all actions were included in the generated policy, you should 5 minutes more and then rerun the command.

Usage

tkm iam generate-policies \
  --start-time <start-time> \
  --end-time <end-time> \
  --identity <identity>... \
  --region <region>... \ 
  [--role-name <role-name>]
  

This command is intended to be run with option values generated after running some other command with --show-generate-iam-policies option. For example, to get the IAM policies needed to deploy a stack, you first need to run the deploy stack command with --show-generate-iam-policies option, and then run this command using instructions shown after the deploy stack command.

Here's a typical workflow to generate IAM policies needed to deploy some stacks:

  1. Run the deploy stacks command with --show-generate-iam-policies option and full admin permissions (to ensure the operation doesn't fail due to insufficient permissions). This step should be executed on a non-production environment.

  2. Copy the command to generate IAM policies shown in the deploy stacks command's output.

  3. Wait at least 15 minutes to ensure all events from the previous command are found from CloudTrail.

  4. Run the command you copied in step 2 with a role or user that is allowed to look up events from CloudTrail (see minimum IAM policy for this command).

  5. The command prints the generated policies that you can use to craft the final policies.

Positional arguments

This command has no positional arguments.

Options

In addition to the common options, this command has the following options.

  • --start-time <start time>

    • Include events from CloudTrail after this time.

    • Must be in ISO 8601 format, e.g. 2021-10-05T14:48:00.000Z.

    • Required.

  • --end-time <end time>

    • Include events from CloudTrail before this time.

    • Must be in ISO 8601 format, e.g. 2021-10-05T16:48:00.000Z.

    • Required.

  • --identity <identity>

    • Include events from CloudTrail by this identity.

    • You can use this option multiple times to specify more identities.

    • Must be a valid IAM identity ARN.

    • Optional.

  • --region <region>

    • Include events from CloudTrail from this region.

    • You can use this option multiple times to specify more regions.

    • Optional.

  • --role-name <role>

    • If you are generating policies from actions executed against multiple accounts, you need to provide a name of the IAM role for Takomo to assume from each account to collect the CloudTrail events.

    • Optional.

IAM permissions

These are the minimum IAM permissions required to run this command.

Statement: 
  - Sid: CloudTrail
    Effect: Allow
    Action: cloudtrail:LookupEvents
    Resource: "*"

  # IAM permissions needed only if policies are generated 
  # from multiple accounts. Specify the Resource to restrict 
  # access to specific roles.  
  - Sid: IAM
    Effect: Allow
    Action: sts:AssumeRole
    Resource: "*" 

Examples

Generate policies for IAM user john@example.com based on actions executed in eu-west-1 and us-east-1 regions:

tkm iam generate-policies \
  --start-time 2021-05-02T16:45:54.169Z \
  --end-time 2021-05-02T16:45:54.462Z \
  --identity arn:aws:iam::123456789012:user/john@example.com \
  --region eu-west-1 \
  --region us-east-1

Troubleshooting

Here are some tips to help you troubleshoot problems.

Logging level

By setting the logging level to debug or trace, you will see lots of useful information that might help you spot the problem. Logging level is set with --log <level> option which is available for all commands,

Example

This is how you set logging level to trace:

tkm stacks deploy --log trace

Statistics

To understand how Takomo interacts with AWS APIs you can use --stats option to instruct Takomo to print various statistics after executing a command.

Example

This is how you enable statistics:

tkm <your command here> --stats

Change log

v3.39.1

Released on 2021/12/12, (GitHub)

Bug fixes

  • Fix a bug that caused stacks marked as obsolete to be included in undeploy stacks operation if they depended on stacks chosen to be included in the undeploy operation.

v3.39.0

Released on 2021/12/11, (GitHub)

Features

Prune obsolete stacks

It's now easier to remove stacks that are no longer needed by marking them as obsolete and then executing the new prune stacks command (#327).

Improvements

  • Reviewing stacks to be deployed or undeployed now shows only the direct dependencies of the effected stacks. Previously, also transitive dependencies where shown, which caused the dependency list to become very long in larger projects with complex dependency graphs.

v3.38.1

Released on 2021/11/20, (GitHub)

This release includes only code refactoring and more tests.

v3.38.0

Released on 2021/11/05, (GitHub)

Features

Secret parameter resolver

With the new secret parameter resolver, you can use secrets stored in Secrets Manager as inputs for your CloudFormation stacks (#317).

This is an example of how you could use the secret parameter resolver in a stack configuration file:

parameters:
  DatabasePassword:
    resolver: secret
    secretId: my-password-secret

Read more from the docs.

v3.37.1

Released on 2021/11/03, (GitHub)

This release includes only code refactoring and more tests.

v3.37.0

Released on 2021/10/14, (GitHub)

Features

Extending Takomo project configuration files

It's now possible to make a Takomo project configuration file (takomo.yml) to inherit configuration from another file. Inheriting configuration becomes useful, for example, when you have a monorepo containing multiple Takomo projects, each having its own configuration and sharing some common properties with others. You can place the common properties in a parent file that others then inherit (#316).

You use the extends property to make a project configuration file inherit configuration from another file:

takomo.yml
extends: ../takomo.parent.yml

v3.36.0

Released on 2021/10/06, (GitHub)

Features

Load custom Handlebars helpers from additional directories

You can now specify additional directories from where Takomo loads custom Handlebars helpers by providing one or more directory paths to the helpersDir property of Takomo project configuration. The paths can be either absolute or relative to the current project directory (#276).

Read more from the docs.

v3.35.2

Released on 2021/09/29, (GitHub)

Bug fixes

  • Fix a bug that caused the stacks deployment order to go wrong in some cases where there was inter-region dependencies between stacks, (#312).

v3.35.1

Released on 2021/09/26, (GitHub)

Improvements

  • Improve AWS API invocations and handling of concurrent operations

v3.35.0

Released on 2021/09/21, (GitHub)

Features

Expect no changes to stacks when deploying

You can now invoke deploy stacks, deploy targets and bootstrap targets commands with --expect-no-changes option which causes the operation to fail if at least one of the targeted stacks would have changes. This is useful, for example, if you have made some clean-up to your local configuration and want to make sure that you have not unintentionally introduced some infrastructure changes (#308).

Bug fixes

  • Fix loading of stacks when the target regions has more than 100 stacks (#307).

v3.34.1

Released on 2021/09/20, (GitHub)

Improvements

  • Previously, Takomo could not update a stack if its status was ROLLBACK_FAILED. Now, if Takomo encounters stacks with ROLLBACK_FAILED status, it attempts to delete the failed stack, and if that succeeds, proceeds to deploy the stack normally).

Bug fixes

  • Fix texts shown on confirm deployment targets operation prompt

v3.34.0

Released on 2021/09/17, (GitHub)

Improvements

  • Previously, Takomo could not update a stack if its status was UPDATE_ROLLBACK_FAILED. Now, if Takomo encounters stacks with UPDATE_ROLLBACK_FAILED status, it attempts to continue rollback, and if that succeeds, proceeds to update the stack normally (#302).

v3.33.2

Released on 2021/09/15, (GitHub)

Small improvements.

v3.33.1

Released on 2021/09/12, (GitHub)

Features

New CLI command: list stacks in organization accounts

You can now use a new CLI command to list CloudFormation stacks from accounts that belong to your AWS organization.

List stacks from every account.

tkm org accounts list-stacks --config-set-type standard

List stacks from accounts that belong to the Root/Workload organizational unit.

tkm org accounts list-stacks ROOT/Workload --config-set-type standard

List all stacks from accounts 123456789012 and 210987654321

tkm org accounts list-stacks \
  -a 123456789012 210987654321 \
  --config-set-type standard

For more information, see the documentation.

Choose which config set and command path to use when deploying stacks to accounts

Two new options added to CLI commands that deploy or undeploy stacks from accounts that belong to your AWS organization.

  • --config-set <config-set>

    • Include only this config set.

  • --command-path <command-path>

    • Include only this command path. Using this option requires that also --config-set is used.

These options are supported in the following commands:

  • Deploy accounts

  • Undeploy accounts

  • Bootstrap accounts

  • Tear down accounts

v3.32.0

Released on 2021/08/26, (GitHub)

Improvements

  • Optimize deploying of stacks to minimize AWS API throttling that can occur in larger projects.

Bug fixes

  • Fix bug that prevented recreating failed stacks that have termination protection enabled (#293).

v3.31.2

Released on 2021/08/24, (GitHub)

Improvements

  • Optimize loading of currently existing stacks to speed up commands: deploy stacks and detect stack drift (#288).

v3.31.1

Released on 2021/08/23, (GitHub)

Improvements

  • Optimize loading of currently existing stacks to speed up the list stacks operation in larger projects.

v3.31.0

Released on 2021/08/17, (GitHub)

Features

New configuration property: Infer deployment target's name from its configuration file name

A new property inferDeploymentTargetNameFromFileName is now available in the configuration of the filesystem deployment target repository used to load deployment targets from the local filesystem. You can use it to instruct Takomo to infer deployment target names from their configuration files' names. Read more from the docs.

Bug fixes

  • Fix a bug that prevented stack groups to inherit custom validation schemas from their parent.

v3.30.0

Released on 2021/08/16, (GitHub)

Features

New configuration property: inheritTags

By default, stacks and stack groups inherit tags from their parent stack group. You can now disable this behaviour by setting inheritTags to false (#282). Read more from the docs.

v3.29.0

Released on 2021/08/16, (GitHub)

Features

New hook: Checksum hook

You can use this new hook to calculate checksums from directories in your project. For example, suppose you have a lambda function with its source code located in some directory. In that case, you can calculate a checksum from the directory and all files located under it and use it to skip the lambda deployment if the sources have not changed. Read more form the docs.

Bug fixes

  • Fix a bug that caused stdout buffer to exceed when a shell command executed with the cmd resolver produced large amounts of output to the stdout (#279).

v3.28.0

Released on 2021/08/15, (GitHub)

Features

Skip stack deploy if a hook returns a skip signal

You can now implement a custom hook to decide whether the following stack operation should be skipped (#254). For example, you might use this new feature to skip a stack update if your stack has a lambda function, but its source code has not changed.

To indicate that the following stack operation should be skipped, you need to return an output object from your hook that contains skip: true.

hooks/my-skip-hook.js
const execute = (input) => {
  // Some logic that determines if the stack operations should be skipped
  const skipIsNeeded = isSkipNeeded() 

  return {
    skip: skipIsNeeded,
    success: true,
  }
}

// Hook provider that initializes the hook
module.exports = {
  type: "example",
  init: (props) => ({ execute })
}

Read here how to implement custom hooks.

Bug fixes

  • Fix a bug that caused stdout buffer to exceed when a shell command executed with the cmd hook produced large amounts of output to the stdout.