CloudFormation の Fn::GetAZs で ap-northeast-1d が返ってこなくてハマった

Posted on

CloudFormation で 3 AZ (Availability Zone) のサブネットを作るときに Fn::GetAZs でハマったのでメモしておきます。

利用できる AZ はアカウントによって違いがあるので、AZ をハードコーディングしてしまうと汎用性がなくなってしまいます。そのために用意されている関数が Fn::GetAZs で、指定されたリージョンの AZ を配列で返してくれます。

Fn::GetAZs で ap-northeast-1d が返ってこない

ap-northeast-1a, 1c, 1d が使えるアカウントで次のような CloudFormation テンプレートを書くと、なぜか "Template error: Fn::Select cannot select nonexistent value at index 2" というエラーになりました。配列に 2 つの AZ しか含まれていないようです。

Resources:

  PublicSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.0.0/24
      AvailabilityZone: !Select
        - 0
        - Fn::GetAZs: !Ref AWS::Region

  PublicSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.1.0/24
      AvailabilityZone: !Select
        - 1
        - Fn::GetAZs: !Ref AWS::Region

  PublicSubnet3:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.2.0/24
      AvailabilityZone: !Select
        - 2
        - Fn::GetAZs: !Ref AWS::Region

aws ec2 describe-availability-zones コマンドでは 3 AZ が取得できます。

$ aws ec2 describe-availability-zones --query 'AvailabilityZones[].ZoneName'
[
    "ap-northeast-1a",
    "ap-northeast-1c",
    "ap-northeast-1d"
]

おかしいなと思って、先ほどのテンプレートに Outputs を追加して配列の中身を確認してみました。

Outputs:
  AZs:
    Value: !Join [ ", ", !GetAZs ap-northeast-1 ]

すると、たしかに ap-northeast-1a, ap-northeast-1c しか返ってきません。

Fn::GetAZs は Default Subnet の AZ を返す

改めて Fn::GetAZs のドキュメントを読んでみると次のような注意書きがありました。

For the EC2-VPC platform, the Fn::GetAZs function returns only Availability Zones that have a default subnet unless none of the Availability Zones has a default subnet; in that case, all Availability Zones are returned.

Fn::GetAZs はアカウントで使える AZ のリストではなく、そのアカウントの Default Subnet の AZ が返ってくるというわけです。 ap-northeast-1d は最近できた AZ で、自分のアカウントの Default Subnet には存在しませんでした。罠すぎる…。

Default Subnet は次のコマンドで追加することができます。

$ aws ec2 create-default-subnet --availability-zone ap-northeast-1d

Default Subnet を ap-northeast-1d に作ったあと、先ほどの CloudFormation を流すと意図したとおり 3 AZ が取得できました。