AWS CloudFormation
DevOpsツール
AWS CloudFormation
概要
AWS CloudFormationは、AWSが提供するネイティブのInfrastructure as Code(IaC)サービスです。JSON/YAMLテンプレートを使用してAWSリソースを宣言的に定義・管理し、AWSサービスとの密接な統合によりスタック単位での組織的なリソース管理を実現します。
詳細
AWS CloudFormationは2011年にAWSによって開始された最も歴史のあるIaCサービスの一つです。AWSネイティブサービスとして、全てのAWSリソースを網羅的にサポートし、新しいAWSサービスがリリースされると比較的早期にCloudFormationでも利用可能になります。
CloudFormationの主要な特徴は「スタック」という概念によるリソース管理です。関連するリソースをスタック単位でグループ化し、作成・更新・削除を一括して行えます。また、リソース間の依存関係を自動的に解決し、適切な順序で作成・削除を実行します。
変更セット機能により、実際に変更を適用する前に「何が変更されるか」をプレビューでき、安全なインフラ運用が可能です。また、Drift Detection機能により、テンプレートと実際のリソース状態の差分を検出できます。
最近では、CDK(Cloud Development Kit)により、プログラミング言語(TypeScript、Python、Java、C#、Go)でCloudFormationテンプレートを生成することも可能になっています。
メリット・デメリット
メリット
- AWSネイティブ: AWSサービスとの完全統合、追加コスト不要
- 包括的サポート: 全AWSリソースを網羅的にサポート
- スタック管理: 関連リソースを組織的に管理
- 変更セット: 変更内容の事前プレビューで安全なデプロイ
- ロールバック機能: 失敗時の自動ロールバック
デメリット
- AWS限定: AWS以外のクラウドプロバイダーは非対応
- JSON/YAML複雑性: 大規模テンプレートが複雑になりがち
- 学習コスト: AWS固有の記法とパラメータの習得が必要
- 実行速度: 大規模スタックでは作成・更新に時間がかかる
- 状態管理: スタック外で作成されたリソースとの連携が困難
参考ページ
公式リソース
- AWS CloudFormation - AWS公式サイト
- CloudFormation User Guide - 公式ドキュメント
- CloudFormation Template Reference - テンプレートリファレンス
- AWS CDK - Cloud Development Kit
学習リソース
- CloudFormation Samples - サンプルテンプレート集
- CloudFormation Best Practices - ベストプラクティス
- AWS Workshop - ハンズオンワークショップ
書き方の例
基本的なテンプレート構造(YAML)
# basic-template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Basic CloudFormation template example'
# パラメータ定義
Parameters:
Environment:
Type: String
Default: development
AllowedValues:
- development
- staging
- production
Description: Environment name
InstanceType:
Type: String
Default: t3.micro
AllowedValues:
- t3.micro
- t3.small
- t3.medium
Description: EC2 instance type
# マッピング(環境別設定)
Mappings:
EnvironmentConfig:
development:
InstanceType: t3.micro
MinSize: 1
MaxSize: 2
staging:
InstanceType: t3.small
MinSize: 2
MaxSize: 4
production:
InstanceType: t3.medium
MinSize: 3
MaxSize: 10
# 条件分岐
Conditions:
IsProduction: !Equals [!Ref Environment, production]
CreateMultipleInstances: !Not [!Equals [!Ref Environment, development]]
# リソース定義
Resources:
# 後述のサンプルを参照
# 出力
Outputs:
EnvironmentName:
Description: Environment name
Value: !Ref Environment
Export:
Name: !Sub '${AWS::StackName}-Environment'
VPCとサブネット作成
# vpc-infrastructure.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: 'VPC and networking infrastructure'
Parameters:
VpcCidr:
Type: String
Default: '10.0.0.0/16'
Description: CIDR block for VPC
Resources:
# VPC
MainVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCidr
EnableDnsHostnames: true
EnableDnsSupport: true
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-vpc'
# インターネットゲートウェイ
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-igw'
# IGWをVPCにアタッチ
InternetGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref InternetGateway
VpcId: !Ref MainVPC
# パブリックサブネット(AZ-a)
PublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref MainVPC
AvailabilityZone: !Select [0, !GetAZs '']
CidrBlock: !Select [0, !Cidr [!Ref VpcCidr, 6, 8]]
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-public-subnet-1'
# パブリックサブネット(AZ-c)
PublicSubnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref MainVPC
AvailabilityZone: !Select [1, !GetAZs '']
CidrBlock: !Select [1, !Cidr [!Ref VpcCidr, 6, 8]]
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-public-subnet-2'
# プライベートサブネット(AZ-a)
PrivateSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref MainVPC
AvailabilityZone: !Select [0, !GetAZs '']
CidrBlock: !Select [2, !Cidr [!Ref VpcCidr, 6, 8]]
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-private-subnet-1'
# プライベートサブネット(AZ-c)
PrivateSubnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref MainVPC
AvailabilityZone: !Select [1, !GetAZs '']
CidrBlock: !Select [3, !Cidr [!Ref VpcCidr, 6, 8]]
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-private-subnet-2'
# パブリックルートテーブル
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref MainVPC
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-public-rt'
# パブリックルート(IGW向け)
DefaultPublicRoute:
Type: AWS::EC2::Route
DependsOn: InternetGatewayAttachment
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
# パブリックサブネットとルートテーブル関連付け
PublicSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet1
PublicSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet2
Outputs:
VPC:
Description: VPC ID
Value: !Ref MainVPC
Export:
Name: !Sub '${AWS::StackName}-VPCID'
PublicSubnets:
Description: Public subnets
Value: !Join [',', [!Ref PublicSubnet1, !Ref PublicSubnet2]]
Export:
Name: !Sub '${AWS::StackName}-PublicSubnets'
PrivateSubnets:
Description: Private subnets
Value: !Join [',', [!Ref PrivateSubnet1, !Ref PrivateSubnet2]]
Export:
Name: !Sub '${AWS::StackName}-PrivateSubnets'
EC2インスタンスとセキュリティグループ
# ec2-infrastructure.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: 'EC2 instances and security groups'
Parameters:
NetworkStackName:
Type: String
Description: Name of the network stack to import values from
InstanceType:
Type: String
Default: t3.micro
Description: EC2 instance type
KeyName:
Type: AWS::EC2::KeyPair::KeyName
Description: Name of an existing EC2 KeyPair
Resources:
# ウェブサーバー用セキュリティグループ
WebServerSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Security group for web servers
VpcId:
Fn::ImportValue: !Sub '${NetworkStackName}-VPCID'
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: 0.0.0.0/0
SecurityGroupEgress:
- IpProtocol: -1
CidrIp: 0.0.0.0/0
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-web-sg'
# EC2インスタンス用IAMロール
EC2Role:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Action:
- sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-ec2-role'
# インスタンスプロファイル
EC2InstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Roles:
- !Ref EC2Role
# ユーザーデータスクリプト
UserDataScript:
Type: AWS::CloudFormation::WaitConditionHandle
# EC2インスタンス
WebServer1:
Type: AWS::EC2::Instance
Properties:
ImageId: !Sub '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2}}'
InstanceType: !Ref InstanceType
KeyName: !Ref KeyName
SecurityGroupIds:
- !Ref WebServerSecurityGroup
SubnetId: !Select
- 0
- !Split
- ','
- Fn::ImportValue: !Sub '${NetworkStackName}-PublicSubnets'
IamInstanceProfile: !Ref EC2InstanceProfile
UserData:
Fn::Base64: !Sub |
#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
# Simple web page
cat > /var/www/html/index.html << EOF
<!DOCTYPE html>
<html>
<head>
<title>CloudFormation Demo</title>
</head>
<body>
<h1>Hello from CloudFormation!</h1>
<p>Instance ID: $(curl -s http://169.254.169.254/latest/meta-data/instance-id)</p>
<p>Region: ${AWS::Region}</p>
<p>Stack: ${AWS::StackName}</p>
</body>
</html>
EOF
# Install CloudWatch agent
yum install -y amazon-cloudwatch-agent
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-web-server-1'
WebServer2:
Type: AWS::EC2::Instance
Properties:
ImageId: !Sub '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2}}'
InstanceType: !Ref InstanceType
KeyName: !Ref KeyName
SecurityGroupIds:
- !Ref WebServerSecurityGroup
SubnetId: !Select
- 1
- !Split
- ','
- Fn::ImportValue: !Sub '${NetworkStackName}-PublicSubnets'
IamInstanceProfile: !Ref EC2InstanceProfile
UserData:
Fn::Base64: !Sub |
#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
cat > /var/www/html/index.html << EOF
<!DOCTYPE html>
<html>
<head>
<title>CloudFormation Demo</title>
</head>
<body>
<h1>Hello from CloudFormation! (Server 2)</h1>
<p>Instance ID: $(curl -s http://169.254.169.254/latest/meta-data/instance-id)</p>
<p>Region: ${AWS::Region}</p>
<p>Stack: ${AWS::StackName}</p>
</body>
</html>
EOF
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-web-server-2'
Outputs:
WebServer1PublicIp:
Description: Web Server 1 Public IP
Value: !GetAtt WebServer1.PublicIp
WebServer2PublicIp:
Description: Web Server 2 Public IP
Value: !GetAtt WebServer2.PublicIp
WebServer1URL:
Description: Web Server 1 URL
Value: !Sub 'http://${WebServer1.PublicIp}'
WebServer2URL:
Description: Web Server 2 URL
Value: !Sub 'http://${WebServer2.PublicIp}'
ALB(Application Load Balancer)構成
# alb-infrastructure.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Application Load Balancer infrastructure'
Parameters:
NetworkStackName:
Type: String
Description: Name of the network stack to import values from
ComputeStackName:
Type: String
Description: Name of the compute stack to import values from
Resources:
# ALB用セキュリティグループ
ALBSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Security group for Application Load Balancer
VpcId:
Fn::ImportValue: !Sub '${NetworkStackName}-VPCID'
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
SecurityGroupEgress:
- IpProtocol: -1
CidrIp: 0.0.0.0/0
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-alb-sg'
# Application Load Balancer
ApplicationLoadBalancer:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Name: !Sub '${AWS::StackName}-alb'
Scheme: internet-facing
Type: application
SecurityGroups:
- !Ref ALBSecurityGroup
Subnets: !Split
- ','
- Fn::ImportValue: !Sub '${NetworkStackName}-PublicSubnets'
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-alb'
# ターゲットグループ
WebServerTargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Name: !Sub '${AWS::StackName}-web-tg'
Port: 80
Protocol: HTTP
VpcId:
Fn::ImportValue: !Sub '${NetworkStackName}-VPCID'
HealthCheckIntervalSeconds: 30
HealthCheckPath: /
HealthCheckProtocol: HTTP
HealthCheckTimeoutSeconds: 5
HealthyThresholdCount: 2
UnhealthyThresholdCount: 3
TargetType: instance
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-web-tg'
# ALBリスナー
ALBListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
DefaultActions:
- Type: forward
TargetGroupArn: !Ref WebServerTargetGroup
LoadBalancerArn: !Ref ApplicationLoadBalancer
Port: 80
Protocol: HTTP
Outputs:
LoadBalancerURL:
Description: Application Load Balancer URL
Value: !Sub 'http://${ApplicationLoadBalancer.DNSName}'
LoadBalancerDNSName:
Description: Application Load Balancer DNS Name
Value: !GetAtt ApplicationLoadBalancer.DNSName
TargetGroup:
Description: Target Group ARN
Value: !Ref WebServerTargetGroup
Export:
Name: !Sub '${AWS::StackName}-TargetGroup'
S3バケットとCloudFront配信
# s3-cloudfront.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: 'S3 bucket with CloudFront distribution for static website'
Parameters:
DomainName:
Type: String
Description: Domain name for the website (optional)
Default: ''
Conditions:
HasDomainName: !Not [!Equals [!Ref DomainName, '']]
Resources:
# S3バケット(ウェブサイトホスティング用)
WebsiteBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub '${AWS::StackName}-website-${AWS::AccountId}'
WebsiteConfiguration:
IndexDocument: index.html
ErrorDocument: error.html
PublicAccessBlockConfiguration:
BlockPublicAcls: false
BlockPublicPolicy: false
IgnorePublicAcls: false
RestrictPublicBuckets: false
VersioningConfiguration:
Status: Enabled
LifecycleConfiguration:
Rules:
- Id: DeleteOldVersions
Status: Enabled
NoncurrentVersionExpirationInDays: 30
# S3バケットポリシー(CloudFrontからのアクセス許可)
WebsiteBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref WebsiteBucket
PolicyDocument:
Statement:
- Sid: PublicReadGetObject
Effect: Allow
Principal:
Service: cloudfront.amazonaws.com
Action: s3:GetObject
Resource: !Sub '${WebsiteBucket}/*'
Condition:
StringEquals:
'AWS:SourceArn': !Sub 'arn:aws:cloudfront::${AWS::AccountId}:distribution/${CloudFrontDistribution}'
# CloudFront Origin Access Control
OriginAccessControl:
Type: AWS::CloudFront::OriginAccessControl
Properties:
OriginAccessControlConfig:
Name: !Sub '${AWS::StackName}-oac'
OriginAccessControlOriginType: s3
SigningBehavior: always
SigningProtocol: sigv4
# CloudFront Distribution
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- DomainName: !GetAtt WebsiteBucket.RegionalDomainName
Id: S3Origin
S3OriginConfig:
OriginAccessIdentity: ''
OriginAccessControlId: !Ref OriginAccessControl
Enabled: true
DefaultRootObject: index.html
DefaultCacheBehavior:
TargetOriginId: S3Origin
ViewerProtocolPolicy: redirect-to-https
CachePolicyId: 4135ea2d-6df8-44a3-9df3-4b5a84be39ad # CachingOptimized
OriginRequestPolicyId: 88a5eaf4-2fd4-4709-b370-b4c650ea3fcf # CORS-S3Origin
PriceClass: PriceClass_100
CustomErrorResponses:
- ErrorCode: 404
ResponseCode: 200
ResponsePagePath: /index.html
- ErrorCode: 403
ResponseCode: 200
ResponsePagePath: /index.html
Aliases: !If
- HasDomainName
- [!Ref DomainName]
- []
Tags:
- Key: Name
Value: !Sub '${AWS::StackName}-cloudfront'
Outputs:
BucketName:
Description: S3 Bucket Name
Value: !Ref WebsiteBucket
BucketWebsiteURL:
Description: S3 Website URL
Value: !GetAtt WebsiteBucket.WebsiteURL
CloudFrontDistributionId:
Description: CloudFront Distribution ID
Value: !Ref CloudFrontDistribution
CloudFrontDomainName:
Description: CloudFront Domain Name
Value: !GetAtt CloudFrontDistribution.DomainName
WebsiteURL:
Description: Website URL
Value: !Sub 'https://${CloudFrontDistribution.DomainName}'
CloudFormation基本コマンド
# スタック作成
aws cloudformation create-stack \
--stack-name my-infrastructure \
--template-body file://template.yaml \
--parameters ParameterKey=Environment,ParameterValue=development \
--capabilities CAPABILITY_IAM
# スタック更新
aws cloudformation update-stack \
--stack-name my-infrastructure \
--template-body file://template.yaml \
--parameters ParameterKey=Environment,ParameterValue=staging
# 変更セット作成・確認
aws cloudformation create-change-set \
--stack-name my-infrastructure \
--template-body file://template.yaml \
--change-set-name my-changes \
--parameters ParameterKey=Environment,ParameterValue=production
aws cloudformation describe-change-set \
--stack-name my-infrastructure \
--change-set-name my-changes
# 変更セット実行
aws cloudformation execute-change-set \
--stack-name my-infrastructure \
--change-set-name my-changes
# スタック削除
aws cloudformation delete-stack \
--stack-name my-infrastructure
# スタック一覧
aws cloudformation list-stacks \
--stack-status-filter CREATE_COMPLETE UPDATE_COMPLETE
# スタック詳細表示
aws cloudformation describe-stacks \
--stack-name my-infrastructure
# スタックリソース一覧
aws cloudformation list-stack-resources \
--stack-name my-infrastructure
# スタックイベント確認
aws cloudformation describe-stack-events \
--stack-name my-infrastructure
# テンプレート検証
aws cloudformation validate-template \
--template-body file://template.yaml
# ドリフト検出
aws cloudformation detect-stack-drift \
--stack-name my-infrastructure
aws cloudformation describe-stack-drift-detection-status \
--stack-drift-detection-id <detection-id>
ネストされたスタック
# master-stack.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Master stack orchestrating nested stacks'
Parameters:
Environment:
Type: String
Default: development
Resources:
# ネットワークスタック
NetworkStack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: https://my-templates-bucket.s3.amazonaws.com/vpc-infrastructure.yaml
Parameters:
VpcCidr: '10.0.0.0/16'
Tags:
- Key: Environment
Value: !Ref Environment
# コンピュートスタック
ComputeStack:
Type: AWS::CloudFormation::Stack
DependsOn: NetworkStack
Properties:
TemplateURL: https://my-templates-bucket.s3.amazonaws.com/ec2-infrastructure.yaml
Parameters:
NetworkStackName: !GetAtt NetworkStack.Outputs.StackName
InstanceType: t3.micro
KeyName: my-key-pair
Tags:
- Key: Environment
Value: !Ref Environment
# ロードバランサースタック
LoadBalancerStack:
Type: AWS::CloudFormation::Stack
DependsOn: [NetworkStack, ComputeStack]
Properties:
TemplateURL: https://my-templates-bucket.s3.amazonaws.com/alb-infrastructure.yaml
Parameters:
NetworkStackName: !GetAtt NetworkStack.Outputs.StackName
ComputeStackName: !GetAtt ComputeStack.Outputs.StackName
Tags:
- Key: Environment
Value: !Ref Environment
Outputs:
WebsiteURL:
Description: Website URL
Value: !GetAtt LoadBalancerStack.Outputs.LoadBalancerURL
開発ワークフロー
1. テンプレート作成
# テンプレート作成
vim my-infrastructure.yaml
# 検証
aws cloudformation validate-template \
--template-body file://my-infrastructure.yaml
2. 開発・テストサイクル
# 開発環境デプロイ
aws cloudformation create-stack \
--stack-name dev-infrastructure \
--template-body file://my-infrastructure.yaml \
--parameters ParameterKey=Environment,ParameterValue=development
# 変更時は変更セットで確認
aws cloudformation create-change-set \
--stack-name dev-infrastructure \
--template-body file://my-infrastructure.yaml \
--change-set-name update-$(date +%Y%m%d-%H%M%S)
# 実行
aws cloudformation execute-change-set \
--change-set-name update-$(date +%Y%m%d-%H%M%S) \
--stack-name dev-infrastructure
3. CI/CD統合
# .github/workflows/cloudformation.yml
name: CloudFormation Deployment
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-1
- name: Validate CloudFormation templates
run: |
for template in templates/*.yaml; do
aws cloudformation validate-template --template-body file://$template
done
deploy-dev:
needs: validate
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-1
- name: Deploy to development
run: |
aws cloudformation deploy \
--template-file templates/main.yaml \
--stack-name dev-infrastructure \
--parameter-overrides Environment=development \
--capabilities CAPABILITY_IAM \
--no-fail-on-empty-changeset