CloudFront はバージニア北部、他は東京 — その理解は半分正しく、半分ずれています。別の会社で同じ構成をもう一度作るときに効くのは、region を変数にすることではありません。
「どこに置かれるか」はリソースの種類で決まる
AWS のリソースは region の扱いで 3 種類に分かれます。全部に region を指定する必要はありません。
| 種類 | 例 | region の扱い |
|---|---|---|
| グローバル | IAM / Route 53 / CloudFront distribution | region の概念がない。どの provider から作っても同じ 1 個ができる |
| us-east-1 固定要求 | CloudFront に付ける ACM 証明書 | CloudFront 本体はグローバルだが、証明書は us-east-1 の在庫しか参照されない |
| 通常のリージョナル | VPC / EC2 / RDS / ECS / ALB / S3 | provider の region に作られる — ここだけが本当の可変点 |
北部バージニアが要るのは 2 番目だけです。 CloudFront 本体はグローバルなので region を書く必要がありません。実際この repo でも modules/aws/cloudfront/main.tf と route53_unit/main.tf に region の記述は 0 件で、これが正しい状態です。
黙って東京に作られるのは、どういうときか
削る前は、security_group / route_table / internet_gateway の各リソースに region が散っていました。
BEFORE — 部品の中にリージョンが埋まっている
resource "aws_security_group" "db" { name = "cp-db-stg" region = "ap-northeast-1" // ← 部品が自分で東京を指している vpc_id = "vpc-xxxxxxxxxxxxxxxxx" }
これが移植時の事故になります。 他社案件にコピーして provider を大阪に変えても、この 9 リソースだけ黙って東京に作られます。plan はエラーも警告も出しません — 正常に見えるまま間違ったリージョンに立ちます。
AFTER — 部品はリージョンを知らない
resource "aws_security_group" "db" { name = "cp-db-${var.env}" vpc_id = var.vpc_id }
削った後、region を書いている場所は 2 つだけになりました。既定は 1 箇所、例外は名前で分かる形です。
| 場所 | 意味 | 移植時 |
|---|---|---|
stg/versions.tf の provider | この構成の既定リージョン | 1 行変えれば全体が移る |
stg/aws.tf の acm_..._us_east_1 | 意図的な例外 (証明書) | 変えてはいけない値 |
判断軸は「1 つの state で複数リージョンを扱うか」ひとつだけ
扱わないなら、provider に直書きで構いません。 stg/ prd/ のような環境別ディレクトリ構成では root module = 環境そのものなので、環境固有値がそこに直書きされているのはむしろ正しい設計です。変数化しても「変数のデフォルト値をどこかに直書きする」に化けるだけで、可変点は増えません。
扱う場合の手段は 2 つあります。
| 手段 | 書き方 | 備考 |
|---|---|---|
| provider alias | provider = aws.us_east_1 をリソースごとに指す | 従来からの方法。alias の定義が必要 |
| resource ごとの region 属性 | region = var.region をリソースに直接書く | AWS provider 6 系。この repo が使っている方法 |
acm_unit — alias 定義ゼロで東京とバージニアを作り分けている
resource "aws_acm_certificate" "main" { region = var.region // ← 呼び出し側が us-east-1 を渡す domain_name = var.domain_name subject_alternative_names = var.subject_alternative_names validation_method = "DNS" }
modules 側で region を知っているのは acm_unit だけです。 そこは「呼び出し側がリージョンを選ぶ module」という設計意図が var.region として表現されている — 知っていていい唯一の場所です。
「ベタ書きのせいで本当は違うところなのに」の実例
modules/aws/alb/outputs.tf に、Route 53 の alias レコードが ALB を指すためのホストゾーン ID がベタ書きされています。
// 東京リージョンのゾーンID(固定) output "zone_id_ap_northeast_1" { value = "Z14GRHDCWA56QT" // ← この値はリージョンごとに違う }
まさに懸念どおりの形です。 大阪や北米に移植すると、コード上は東京の ID を指したままレコードが作られます。しかも provider を変えても追随しません。
terraform state show で確認したところ、aws_lb.cloud_pratica.zone_id 属性が同じ値を持っていました。定数をやめて属性参照にすれば、リージョンが変わっても自動で追随します。
output "zone_id_cloud_pratica" { value = aws_lb.cloud_pratica.zone_id // ← リージョンに追随する }
| 定数 | 値 | リージョン依存 | 実害 |
|---|---|---|---|
ALB (alb/outputs.tf) | Z14GRHDCWA56QT | する | 移植時に誤ったゾーンを指す |
CloudFront (cloudfront/outputs.tf) | Z2FDTNDATAQYW2 | しない (全リージョン共通) | なし — output 名が紛らわしいだけ |
modules/) には書かない。