はじめに

こんにちは!クラウドインテグレーション事業部の佐藤優太です。

先日、CloudFrontのVPCオリジンを使う構成を検討していた際、
対応リージョンを確認しようと公式ドキュメントを開くと以下のように書かれていました。

リージョン名 リージョン
アジアパシフィック (東京) ap-northeast-1 (except AZ apne1-az3)

東京リージョンは対応。ただし apne1-az3 を除く。

参考:VPC オリジンでサポートされている AWS リージョン

apne1-az3 って、どのAZ?という疑問が湧きました。

マネジメントコンソールに出てくるのは ap-northeast-1aap-northeast-1c であって、apne1-az3 の表記はどこにも見当たりません。

この「AZの2通りの呼び方」、知っていればすぐに解決する話ですが、知識があるかないかで大きく変わると感じました。

今回は、学んだ内容について整理していきます。

AZを指定する方法には2通りある

AZを指す方法には、2通りあります。

指定方法 性質
AZ名(Zone Name) ap-northeast-1a アカウントごとに物理AZへランダムにマッピングされる
AZ ID(Zone ID) apne1-az1 どのアカウントから見ても同じ物理AZを指す

普段マネジメントコンソールやCLIで目にするのは、ほぼ前者のAZ名です。

一方のAZ IDは、apne1-az1 のような形式です。命名規則は「リージョンの短縮形 + -az + 数字」で、東京リージョンなら apne1-az1apne1-az4 があります。

物理的なデータセンター群そのものに振られた識別子のようなものです。

AZ名の割り当てはアカウントごとに異なる

AWSのドキュメントには、以下のように書かれています。

AWS は、物理アベイラビリティーゾーンを AWS アカウントごとのアベイラビリティーゾーン名にランダムにマップします。このアプローチは、AWS リージョン 内のアベイラビリティーゾーンにリソースを分散するうえで役立ち、各リージョンのアベイラビリティーゾーン「a」にリソースが集中しなくてすみます。

参考:AWS リソースのアベイラビリティーゾーン ID

つまり ap-northeast-1a は、それぞれのアカウントから見たときの呼び名でしかありません。
図にすると以下のようになります。

                     物理データセンター(AZ ID)
                  apne1-az1   apne1-az2   apne1-az4
                     │           │           │
  アカウントA から  →  1c          1d          1a
  アカウントB から  →  1a          1c          1d
  アカウントC から  →  1d          1a          1c

同じ 1a という表記でも、アカウントAでは apne1-az4、アカウントBでは apne1-az1 を指している、という状態が起こり得ます。

なぜ割り当てがランダムなのか

理由は先ほどの引用にあったとおり、負荷の分散です。

考えてみれば当然で、「とりあえずAZを1つ選んでください」と言われたら、多くの人はリストの先頭にある a を選びます。全ユーザーが同じようにすると、a に対応する物理データセンターだけが混雑し、他のAZが空いたままになってしまいます。

アカウントごとに名前をシャッフルすることで、誰かの a は誰かの c になります。
結果としてリソースが自然に分散されます。
ユーザーが何も考えずに選んでも、全体としては均等になるという設計です。

実はランダム化されているリージョンは限られている

ここは意外と知られていないポイントだと思います。

AZ名がランダムにマッピングされるのは、AWSが2012年11月より前に作ったリージョンだけです。
具体的には以下の9リージョンです。

  • 米国東部(バージニア北部)
  • 米国西部(北カリフォルニア)
  • 米国西部(オレゴン)
  • アジアパシフィック(シンガポール)
  • アジアパシフィック(シドニー)
  • アジアパシフィック(東京)
  • 欧州(アイルランド)
  • 南米(サンパウロ)
  • AWS GovCloud(米国西部)

それ以外のリージョン(大阪、ソウル、フランクフルトなど)は、もともと全アカウントで統一されたマッピングになっています。

2025年11月に行われた仕様変更

ドキュメントに以下の一文が追記されています。

In the following Regions, for accounts created before November 2025, we independently map Availability Zones to codes for each AWS account.
Accounts created starting November 2025, get the same Availability Zones mapped to codes.

参考:AZ IDs – AWS Regions and Availability Zones

2025年11月以降に作成したアカウントでは、上記9リージョンでもマッピングが統一されるようになりました。東京リージョンも対象です。

既存アカウントは従来どおりランダムマッピングのままなので、

  • 2025年11月より前に作った既存アカウント → ランダムマッピング
  • 2025年11月以降に作った新規アカウント → 統一マッピング

が混在することになります。アカウントによって揃っていたり揃っていなかったりするという状態です。

「新しく作った検証アカウントでは問題なかったのに、本番の古いアカウントではズレていた」といった事故が起こる可能性があります。
以前より、AZ IDで明示的に確認する価値は上がっていると言えるのではないでしょうか。

AZ IDの確認方法

自分のアカウントでAZ名とAZ IDがどのように対応しているかは、すぐに確認することができます。

コンソールでの確認

意外なところですが、AWS RAMコンソールが一番見やすいです。
ドキュメントでも公式の手順として案内されています。

アカウントのアベイラビリティーゾーンの AZ ID を表示するには

  1. AWS RAM コンソールで AWS RAM コンソールページに移動します。
  2. [Your AZ ID](お客様の AZ ID)の下に現在の AWS リージョン に関する AZ ID が表示されます。

トップページに現在のリージョンの対応表がそのまま出ています。

個別のサブネットがどの物理AZにあるかを見たい場合は、VPCコンソールが使えます。

VPCコンソール → サブネット を開くと、一覧に「アベイラビリティーゾーンID」の列があります。既存環境の棚卸しをするときはこちらが便利です。

CLIでの確認

CLIならこの1行で対応表が出ます。

aws ec2 describe-availability-zones \
  --region ap-northeast-1 \
  --query "AvailabilityZones[].{Name:ZoneName,ID:ZoneId}" \
  --output table

実際の実行結果

~ $ aws ec2 describe-availability-zones \
>   --region ap-northeast-1 \
>   --query "AvailabilityZones[].{Name:ZoneName,ID:ZoneId}" \
>   --output table
----------------------------------
|    DescribeAvailabilityZones   |
+------------+-------------------+
|     ID     |       Name        |
+------------+-------------------+
|  apne1-az4 |  ap-northeast-1a  |
|  apne1-az1 |  ap-northeast-1c  |
|  apne1-az2 |  ap-northeast-1d  |
+------------+-------------------+
~ $ 

apne1-az3 って、どのAZ?

はじめにの疑問に対する補足です。

今回の結果に apne1-az3 は出てきません。
公式のAZ ID一覧には4つ載っているので、存在はするが、このアカウントからは見えていないということになります。

AWSのドキュメントには「制約のあるアベイラビリティーゾーン(Constrained Availability Zones)」の説明があり、拡張の余地がなくなったAZでは新規リソースの作成が制限されたり、新しいアカウントの一覧から外れたりすることがある、とされています。

参考:AWS Availability Zones

上記を踏まえると、CloudFrontのドキュメントの except AZ apne1-az3 が自分に影響するかについては、
実環境をチェックする必要があると言えます。

Terraformで構築時に明示的に指定する方法

aws_subnet には availability_zone_id という引数があり、AZ IDで直接指定できます。

resource "aws_subnet" "example" {
  vpc_id               = aws_vpc.example.id
  cidr_block           = "10.0.1.0/24"
  availability_zone_id = "apne1-az1"
}

これなら、どのアカウントで apply しても必ず apne1-az1 に着地します。
ただし、書き方には注意点があります。それぞれ実際に手を動かして確認してみました。

注意点1:AZ名とAZ IDは同時に指定できない

availability_zoneavailability_zone_id排他ConflictsWith)です。

どちらもAZを指定するための項目なので、同時に書くと「どちらに従えばいいのか」が決まりません。
「念のため両方書いて整合性を担保する」という書き方はできません。

実際に両方指定して terraform validate を実行してみます。

resource "aws_subnet" "conflict" {
  vpc_id     = aws_vpc.demo.id
  cidr_block = "10.0.1.0/24"

  availability_zone    = "ap-northeast-1a"
  availability_zone_id = "apne1-az1"
}

以下が実行結果です。

╷
│ Error: Conflicting configuration arguments
│ 
│   with aws_subnet.conflict,
│   on main.tf line 28, in resource "aws_subnet" "conflict":
│   28:   availability_zone    = "ap-northeast-1a"
│ 
│ "availability_zone": conflicts with availability_zone_id
╵
╷
│ Error: Conflicting configuration arguments
│ 
│   with aws_subnet.conflict,
│   on main.tf line 29, in resource "aws_subnet" "conflict":
│   29:   availability_zone_id = "apne1-az1"
│ 
│ "availability_zone_id": conflicts with availability_zone
╵

※ Terraform v1.15.9 / AWS Provider v6.61.0 で実行

エラーは2件出ます。 両方の属性に相互に ConflictsWith が設定されているためです。

なお、これは plan ではなく validate の時点で落ちます。
プロバイダのスキーマ検証で処理されるため、AWS認証情報がなくても再現できます

注意点2:指定方法を変更するとサブネットは再作成される

availability_zoneavailability_zone_id は、どちらも ForceNew です。

ForceNew は「この項目を変更したらリソースを作り直す」というプロバイダ側の指定

つまり既存コードをAZ名指定からAZ ID指定に書き換えると、サブネットが作り直しになります。こちらも確認してみます。

まずAZ名で指定してサブネットを作成します。

resource "aws_subnet" "demo" {
  vpc_id     = aws_vpc.demo.id
  cidr_block = "10.0.1.0/24"

  availability_zone = "ap-northeast-1a"
}

以下が実行結果の一部です。

Outputs:

placement = {
  "az_id" = "apne1-az4"
  "az_name" = "ap-northeast-1a"
}

ここでavailability_zone しか指定していないのに、AZ IDも返ってきている点が注目です。
両方 Optional かつ Computed なので、片方を指定すればもう片方は自動的に埋まります。既存環境がどの物理AZにいるかを確認するときにも使えます。

続いて、この記述を同じ物理AZではないAZ ID(このアカウントでは apne1-az1 = ap-northeast-1c)に差し替えて terraform plan します。

resource "aws_subnet" "demo" {
  vpc_id     = aws_vpc.demo.id
  cidr_block = "10.0.1.0/24"

  availability_zone_id = "apne1-az1"
}

以下が実行結果の一部です。

Terraform used the selected providers to generate the following execution plan.
Resource actions are indicated with the following symbols:
-/+ destroy and then create replacement

Terraform will perform the following actions:

  # aws_subnet.demo must be replaced
-/+ resource "aws_subnet" "demo" {
      ~ availability_zone                              = "ap-northeast-1a" -> (known after apply)
      ~ availability_zone_id                           = "apne1-az4" -> "apne1-az1" # forces replacement
      ~ id                                             = "subnet-xxxxxxxxxxxxxxxxx" -> (known after apply)
        # (12 unchanged attributes hidden)
    }

Plan: 1 to add, 0 to change, 1 to destroy.

# forces replacement が付き、-/+(destroyしてcreate)になりました。サブネットは作り直しです。

今回は空のサブネットなので消えても困りませんが、実際の環境ではEC2やRDSが載っています。
AZ名指定からAZ ID指定への移行は、新規構築のタイミングで行うのが現実的だと思います。

まとめ

  • ap-northeast-1aアカウントごとに割り当てられた表示名であり、物理的な場所を指すものではない
  • 物理的な場所を指すのはAZ IDapne1-az1 など)である
  • ランダムマッピングの対象は古い9リージョンだけで、東京は対象、大阪は対象外である
  • 2025年11月以降に作成したアカウントは統一マッピング、ただし既存アカウントとの混在には注意が必要である
  • 自分のアカウントの対応表はAWS RAMコンソールdescribe-availability-zones ですぐに確認できる
  • 構築時は、Terraformなら availability_zone_id でAZ IDを指定できる。ただしAZ名指定とは排他で、後から切り替えるとサブネットは再作成される

ドキュメントで見慣れない apne1-az3 を見つけたのがこのブログの出発点でしたが、調べてみると設計にも関わる話でした。
最後までお読みいただき、ありがとうございました!