DEV Community

Jon Holman
Jon Holman

Posted on • Originally published at jonholman.com

1 1

Go Global with AWS - Use AWS CloudFormation StackSets to go global with ease

I have wanted to create a multi-region, global application with AWS to see how much effort it would be. I finally took some time to create a simple proof of concept, and I am amazed by how easy it was, thanks to CloudFormation StackSets. CloudFormation StackSets makes deploying the same stack to multiple regions and accounts easy. AWS CDK, AWS SAM, AWS CloudFormation, and I'm sure many other IaC tools can create CloudFormation StackSets. To keep this proof of concept small and straightforward, I used AWS SAM to simplify the creation of the CloudFormation resources for AWS Lambda with Amazon API Gateway in the regional deployments. These concepts can easily be applied to a more robust application to deploy across multiple accounts and regions.

To begin, I created a simple single-region template using AWS SAM and its CLI while I worked on that. With the lambda function's code inline within the template. Once I had the per region template the way I wanted, I moved that template to be nested within a CloudFormation StackSet. I would have preferred to be able to keep the nested template as YAML. Supplying YAML for the StackSet's TemplateBody attributed resulted in the error message 'expected type: String, found: JSONObject.' It wanted a string, so I put a | after TemplateBody, which converted the YAML indented below into a multiline string. This sample leverages 16 AWS regions. The last time I ran it, it completed deployment in 18 minutes.

This simple proof of concept only has one file, template.yaml, available in the GitHub gist below with instructions to deploy and remove beneath it.

AWSTemplateFormatVersion: 2010-09-09
Description: multi-region-sam-poc
Parameters:
DomainName:
Type: String
Route53ZoneId:
Type: String
Resources:
AWSCloudFormationStackSetAdministrationRole:
Type: AWS::IAM::Role
Properties:
RoleName: AWSCloudFormationStackSetAdministrationRole
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service: cloudformation.amazonaws.com
Action:
- sts:AssumeRole
AWSCloudFormationStackSetExecutionRole:
Type: AWS::IAM::Role
Properties:
RoleName: AWSCloudFormationStackSetExecutionRole
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
AWS: !GetAtt AWSCloudFormationStackSetAdministrationRole.Arn
Action:
- sts:AssumeRole
ManagedPolicyArns:
- !Sub arn:${AWS::Partition}:iam::aws:policy/AdministratorAccess
MyStackSet:
DependsOn:
- AWSCloudFormationStackSetExecutionRole
Type: AWS::CloudFormation::StackSet
Properties:
StackSetName: !Sub ${AWS::StackName}-StackSet
Description: Multi-Region AWS SAM POC
PermissionModel: SELF_MANAGED
Capabilities:
- CAPABILITY_AUTO_EXPAND
- CAPABILITY_IAM
ManagedExecution:
Active: true
StackInstancesGroup:
- DeploymentTargets:
Accounts:
- !Ref AWS::AccountId
Regions:
- us-east-1
- us-east-2
- us-west-1
- us-west-2
- ap-south-1
- ap-northeast-2
- ap-southeast-1
- ap-southeast-2
- ap-northeast-1
- ca-central-1
- eu-central-1
- eu-west-1
- eu-west-2
- eu-west-3
- eu-north-1
- sa-east-1
# - ap-northeast-3 # HttpApi not available
# I did not opt-in to any additional regions
OperationPreferences:
RegionConcurrencyType: PARALLEL
Parameters:
- ParameterKey: DomainName
ParameterValue: !Ref DomainName
- ParameterKey: Route53ZoneId
ParameterValue: !Ref Route53ZoneId
TemplateBody: |
AWSTemplateFormatVersion: 2010-09-09
Transform: 'AWS::Serverless-2016-10-31'
Description: multi-region-sam-poc per region template
Globals:
Function:
MemorySize: 128
Timeout: 3
HttpApi:
Domain:
CertificateArn: !Ref Certificate
DomainName: !Ref DomainName
Parameters:
DomainName:
Type: String
Route53ZoneId:
Type: String
Resources:
Certificate:
Type: 'AWS::CertificateManager::Certificate'
Properties:
DomainName: !Ref DomainName
DomainValidationOptions:
- HostedZoneId: !Ref Route53ZoneId
DomainName: !Ref DomainName
ValidationMethod: DNS
DnsRecord:
Type: 'AWS::Route53::RecordSet'
Properties:
HostedZoneId: !Ref Route53ZoneId
Name: !Ref DomainName
Type: A
AliasTarget:
HostedZoneId: !GetAtt
- ServerlessHttpApi
- DomainName
- RegionalHostedZoneId
DNSName: !GetAtt
- ServerlessHttpApi
- DomainName
- RegionalDomainName
EvaluateTargetHealth: true
Region: !Ref 'AWS::Region'
SetIdentifier: !Sub '${AWS::Region}-${DomainName}'
LambdaFunction:
Type: 'AWS::Serverless::Function'
Properties:
InlineCode: |
import json
def handler(event, context):
return {
"statusCode": 200,
"body": json.dumps({"message": f"Greetings from {context.invoked_function_arn.split(':')[3]}"}),
}
Handler: index.handler
Runtime: python3.9
Architectures:
- x86_64
Events:
Root:
Type: HttpApi
Properties:
Path: /
Method: get
Outputs:
SharedUrl:
Value: !Sub 'https://${ServerlessHttpApi.DomainName}/'
IndividualUrl:
Description: API Gateway endpoint URL for this region's Lambda function
Value: !Sub 'https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/"'
Outputs:
SharedUrl:
Value: !Sub https://${DomainName}/
view raw template.yaml hosted with ❤ by GitHub

To deploy this sample application, you need:

  • An AWS Account
  • A Route53 hosted zone in the AWS account you are using
  • Then to deploy, you can use any of these:

To deploy your application for the first time.

Run the following in your shell (replace <domain_name> and <route_53_zone_id> for your environment):

For the AWS CLI:

aws cloudformation create-stack --region us-east-1 --stack-name multi-region-sam-poc --template-body file://template.yaml --capabilities CAPABILITY_NAMED_IAM --parameters ParameterKey=DomainName,ParameterValue=<domain_name> ParameterKey=Route53ZoneId,ParameterValue=<route_53_zone_id>

For the AWS SAM CLI:

sam deploy --guided

To delete the sample application that you created.

For the AWS CLI:

aws cloudformation delete-stack --region us-east-1 --stack-name multi-region-sam-poc

For the AWS SAM CLI:

sam delete

Thanks for reading. If you have any questions or feedback, please leave a comment or message me on Twitter, link to the right.

Image of Datadog

Create and maintain end-to-end frontend tests

Learn best practices on creating frontend tests, testing on-premise apps, integrating tests into your CI/CD pipeline, and using Datadog’s testing tunnel.

Download The Guide

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay