1. はじめに
CloudFormationのForEach関数を使用してリソースを作成する際に、テンプレート内のリソースを参照する方法でハマったので、備忘録として記録
2. 何をしたいのか
通常CloudFormationテンプレート内でリソースを参照するときは、
!Ref SampleVPC
のようにRef関数を使用すればいいが、ForEach関数を使用して作成リソースごとに参照するリソースを分ける場合は、!Ref SampleVPC
このような参照方法が使えません。
今回はAWS::EC2::SubnetRouteTableAssociation
の中で、テンプレート内のサブネットとルートテーブルを参照したいと思います。
3. テンプレート
AWSTemplateFormatVersion: 2010-09-09
Description: Create VPC, Subent
Transform: AWS::LanguageExtensions
# Parameters Section
Parameters:
System:
Type: String
Default: Sample
VpcCidr:
Type: String
Default: 10.0.0.0/24
# Mappings Section
Mappings:
# SubnetMappings
SubnetMappings:
SampleSubnet01:
Cidr: 10.0.0.0/27
Az: ap-northeast-1c
Number: 01
SampleSubnet02:
Cidr: 10.0.0.32/27
Az: ap-northeast-1a
Number: 02
SampleSubnet03:
Cidr: 10.0.0.64/27
Az: ap-northeast-1c
Number: 03
SampleSubnet04:
Cidr: 10.0.0.96/27
Az: ap-northeast-1a
Number: 04
SampleSubnet05:
Cidr: 10.0.0.128/27
Az: ap-northeast-1c
Number: 05
SampleSubnet06:
Cidr: 10.0.0.160/27
Az: ap-northeast-1a
Number: 06
# RouteTableMappings
RouteTableMappings:
SampleRouteTable01:
Number: 01
SampleRouteTable02:
Number: 02
SampleRouteTable03:
Number: 03
# RtbAssociationMappings
RtbAssociationMappings:
SampleRtbAssociation01:
RouteTable: SampleRouteTable01
Subnet: SampleSubnet01
SampleRtbAssociation02:
RouteTable: SampleRouteTable01
Subnet: SampleSubnet02
SampleRtbAssociation03:
RouteTable: SampleRouteTable02
Subnet: SampleSubnet03
SampleRtbAssociation04:
RouteTable: SampleRouteTable02
Subnet: SampleSubnet04
SampleRtbAssociation05:
RouteTable: SampleRouteTable03
Subnet: SampleSubnet05
SampleRtbAssociation06:
RouteTable: SampleRouteTable03
Subnet: SampleSubnet06
# Resources Section
Resources:
# Sample Prd Vpc
SampleVpc:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCidr
EnableDnsHostnames: true
EnableDnsSupport: true
Tags:
- Key: Name
Value: !Sub ${System}-vpc
# Subnet
# Private Subnets
'Fn::ForEach::SubnetLoop':
- SubnetName
- - SampleSubnet01
- SampleSubnet02
- SampleSubnet03
- SampleSubnet04
- SampleSubnet05
- SampleSubnet06
- '${SubnetName}':
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !FindInMap [SubnetMappings, !Ref SubnetName, Az]
CidrBlock: !FindInMap [SubnetMappings, !Ref SubnetName, Cidr]
VpcId: !Ref SampleVpc
Tags:
- Key: Name
Value: !Sub
- ${System}-subnet-${SubnetNumber}
- SubnetNumber: !FindInMap [SubnetMappings, !Ref SubnetName, Number]
# 3 RouteTables
'Fn::ForEach::RouteTableLoop':
- RouteTableName
- - SampleRouteTable01
- SampleRouteTable02
- SampleRouteTable03
- '${RouteTableName}':
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref SampleVpc
Tags:
- Key: Name
Value: !Sub
- ${System}-rtb-${RouteTableNumber}
- RouteTableNumber: !FindInMap [RouteTableMappings, !Ref RouteTableName, Number]
# 6 RouteTable Association
'Fn::ForEach::RtbAssociationLoop':
- RtbAssociationName
- - SampleRtbAssociation01
- SampleRtbAssociation02
- SampleRtbAssociation03
- SampleRtbAssociation04
- SampleRtbAssociation05
- SampleRtbAssociation06
- '${RtbAssociationName}':
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
### ↓↓↓ ハマったところ ↓↓↓
RouteTableId: !GetAtt [!FindInMap [RtbAssociationMappings, !Ref RtbAssociationName, RouteTable], RouteTableId]
SubnetId: !GetAtt [!FindInMap [RtbAssociationMappings, !Ref RtbAssociationName, Subnet], SubnetId]
4. ハマったところ
マッピングセクションからルートテーブルやサブネットの論理IDを参照するだけではうまくいかなかった。
そのため、GetAtt関数を使用し、その中でFindInMapで参照したルートテーブル(サブネット)名のIDを取得したことでうまくできた。
なお、ここの記述方法は以下でも可
Properties:
RouteTableId: !GetAtt
- !FindInMap [RtbAssociationMappings, !Ref RtbAssociationName, RouteTable]
- RouteTableId
SubnetId: !GetAtt
- !FindInMap [RtbAssociationMappings, !Ref RtbAssociationName, Subnet]
- SubnetId
5. おわりに
当たり前だが、やはりMappingsが長くなった。
今回はサブネットが6つなので、楽でしたが。
関数の中に関数を書いて、さらにその中に関数を書くと、記述方法がわからなくなってくるので、慣れていきたいと思いました。