How to loop through values in a CloudFormation template

You are correct — there is no concept of a loop in AWS CloudFormation.

AWS CloudFormation is a declarative language. It describes the output desired, but does not state how the outcome should be achieved.

To perform logic like you describe, you will need to create an AWS Lambda-backed Custom Resource. CloudFormation will call the supplied Lambda function, which can then make any desired API calls.

The the template is only creating these buckets, then there is actually no benefit in using CloudFormation. Just run a program or script that does it directly.


Use the Count macro!

The Count macro provides a template-wide Count property for CloudFormation resources. It allows you to specify multiple resources of the same type without having to cut and paste.

Thus, the the following:

AWSTemplateFormatVersion: "2010-09-09"
Transform: Count
Resources:
  Bucket:
    Type: AWS::S3::Bucket
    Properties:
      Tags:
        - Key: TestKey
          Value: my bucket %d
    Count: 3

Would be equivalent to:

AWSTemplateFormatVersion: "2010-09-09"
Resources:
  Bucket1:
    Type: AWS::S3::Bucket
    Properties:
      Tags:
        - Key: TestKey
          Value: my bucket 1
  Bucket2:
    Type: AWS::S3::Bucket
    Properties:
      Tags:
        - Key: TestKey
          Value: my bucket 2
  Bucket3:
    Type: AWS::S3::Bucket
    Properties:
      Tags:
        - Key: TestKey
          Value: my bucket 3

An alternative would be to use CDK, which wraps CloudFormation in Typescript, Python, Java, .NET or Golang.


https://palletsprojects.com/p/jinja/ is another option for adding for-loops to CloudFormation templates. You will need to render the Jinja template before passing it to CloudFormation, as CloudFormation itself cannot currently process Jinja templates.

  {% for country in ["fr", "us", "gb"] %}
  {{country}}_myprod_bucket:
    Type: AWS::S3::Bucket
  {% endfor %}

Rendering that Jinja snippet would produce:

  fr_myprod_bucket:
    Type: AWS::S3::Bucket

  us_myprod_bucket:
    Type: AWS::S3::Bucket

  gb_myprod_bucket:
    Type: AWS::S3::Bucket