
- 背景
- Terraform AWS Provider v6
- さて、普通にアップグレードするとどうなるでしょう?
- 実際にアップグレードしてみると、
- ソースコード例
- Aurora DSQLの構築
- Private DNS endpoint の爆誕
- まとめ
- 最後に
こんにちは、開発本部 開発2部 RetailHUB NetSuperグループに所属するホーク🦅アイ👁️です。
背景
私の所属するチームでは、現在新プロダクトをローンチに向けて鋭意開発中なのですが、そのデータベースアーキテクチャにAurora DSQLを採用しました。その構成はシンプルにシングルリージョンシングルクラスターです。このDSQLをTerraform管理で構築すべく調査しているとawsプロバイダのバージョンを最低でもv5.100.0以降にしないといけないことがわかりました。
チームで使っているTerraform群は現在、awsプロバイダのバージョンは5.44.0でした。そこでこの際と、当時最新のバージョン6.6.0へのアップグレードを試みることにしました。
また、この最新プロバイダバージョンを使ってインフラ構築を行った際にgo言語で実装したAPIサーバからDSQL接続を確立させるまでの間にぶち当たった問題とその解決策を紹介したいと思います。
Terraform AWS Provider v6
AWSクラウド用のメジャーなプロバイダであるAWS Hashicorpプロバイダをチーム内では既に利用しています。その最新major version 6が2025年6月19日GAされました。
公式のアップグレードガイドによると多くの更新情報がありますが、特に我々のチームの既存環境にインパクトがあると思われたのは以下の抜粋にあるようにregionに関する内容でした。
Enhanced Region Support Version 6.0.0 of the Terraform AWS Provider adds region to most resources making it significantly easier to manage infrastructure across AWS Regions without requiring multiple provider configurations.
さて、普通にアップグレードするとどうなるでしょう?
- 全リソースにリージョンを自動で埋め込んでくれる
- 全リソースにリージョンを自動で埋め込んでくれるが、providerブロックと重複して
ERRORになる - 全リソースにリージョンを埋め込め!という
ERRORになる - 全リソースにリージョンを埋め込むべき!という
WARNINGになる
実際にアップグレードしてみると、
terraform plan -refresh-onlyだけ実行して198のリソース差分が出ましたが、破壊的変更の対象リソースはなく、すべて内部的な管理が付加される以下の3つだけなのでstate更新だけでapplyは問題なく実行可能と判断したので実行し、無事に成功しました。
- region:v6のアップグレードガイドにある通り、リソース単位でリージョンを上書き設定できるようにほぼすべてのリソースに追加された引数。Optional and Computedの引数なので設定しなくても自動で値が入りstate管理に追加される
- 公式のregionエンハンス
- bucket_region:上のregionと同じ扱い
- Guideのaws_s3_bucketについて
- export:v6.4.0以上から追加されたoptions引数でACM証明書のエクスポート可否を設定するもの。デフォルトdisabledで実環境に影響なしのデフォルト値を管理対象にするものでしかない
- resource:aws_acm_certificate
ソースコード例
実際にapply前後でどのようなtfファイルの違いが出たかを見てみると確かにスッキリとした記述になった印象です。もともと、エイリアスを埋め込んでいたリソース全部に修正が必要でしたが、対象リソースも少なくそもそも各リソースに手を加えていたのでDRYの観点でも同様の修正にならざるを得ないのでそのまま改修を実施しました。
- main.tf(before)
providers = { aws.virginia = aws.virginia }
- main.tf(after) は、丸々その行を削除した状態
- provider.tf(before)
terraform { required_providers { aws = { source = "hashicorp/aws" version = "5.44.0" configuration_aliases = [aws.virginia] } } } provider "aws" { alias = "virginia" region = "us-east-1" profile = var.profile }
- provider.tf(after)
terraform { required_providers { aws = { source = "hashicorp/aws" version = "6.6.0" } random = { source = "hashicorp/random" version = ">= 3.0" } } } # 以下は、丸々削除
- route53/main.tf(before)
resource "aws_acm_certificate" "hogehoge" { provider = aws.virginia ... }
- route53/main.tf(after)
resource "aws_acm_certificate" "hogehoge" { region = "us-east-1" ... }
Aurora DSQLの構築
さて、本題のDSQL環境構築ですが最終的には以下のアーキテクチャ構成で構築しました。

DSQLクラスター自体はリソースのArgumentも少なくとてもシンプルな設定しかなく簡単に作成はできました。すると、パブリックエンドポイントというものがデフォルトで払い出されていました。RDSでは見ない、最初からパブリックネットワークに接続されたエンドポイントがあり、むしろプライベートネットワークのエンドポイントがない状態でした。ここで2つの課題が浮き彫りになりました。
- VPC内のECSクラスターからどのようにネットワーク導通を確保するか
- 実運用に耐えるようにセキュリティを考慮しなければならない
この2つの課題を解決させるために次に掲げる詳細設定で構築を完成させ実運用にも耐えうるセキュリティを確保するようにしました。
なお、デフォルトで払い出されるPublic endpointに対しては払い出し自体を無効化にする設定は今のところ存在しないのでそのままにしています。特にネットワークACLによるtraffic制御はしていないのでクラスターへの導通自体は可能ですが、DSQL接続時にパスワードの代わりとして使うトークン発行時の認証によりIAMロール権限不足でAccess Deniedになるので問題なしとしています。もし、運用中にDDos攻撃のようなアクセス過多による高trafficが発生した場合はその時にACL制御も検討する予定です。
Private DNS endpoint の爆誕
DSQLクラスターの詳細画面をコンソール上で確認すると、PrivateLinkという気になる項目タブがありました。公式ドキュメントによればVPCエンドポイントを使えば他のVPCにあるECSクラスターに対してあたかも同じプライベートサブネット上の対象物として接続確立可能になる仕組みでこれを使うことにしました。
VPC Privatelink Endpoint
VPCエンドポイントはDSQLの公式ドキュメントにもあるように以下のようにInterfaceで作成しました。vpc_idは、ECSクラスターの存在するvpc_idを設定します。service_nameは、1リージョン内のDSQLクラスター共通で作成時に自動で発行されるサービス名になります。subnet_idsは、ECSクラスターが接続しているサブネット(マルチAZ構成)を設定します。security_group_idsは、後述のセキュリティグループの設定を反映させるために変数でセキュリティグループIDを渡しています。private_dns_enabledは、デフォルトfalseで最初試してRoute53で扱いやすい自由な文字列でCNAMEを設定してみたのですが、それだとネットワーク導通せず、うまくいきそうになかったので諦めてtrue値にして自動で払い出されるプライベートDNS名を使うことにしました。tagsのName属性を使ってVPCエンドポイントのName部分を自由に編集することができます。
resource "aws_vpc_endpoint" "dsql_vpc_endpoint" { vpc_id = aws_vpc.ecs_cluster.id service_name = var.dsql_service_name vpc_endpoint_type = "Interface" subnet_ids = var.private_subnet_ids security_group_ids = [var.dsql_vpc_endpoint_id] private_dns_enabled = true tags = { Name = "dsql-endpoint" } }
Security Group
セキュリティグループは、以下のような厳密なinbound(ingress)ルールに設定しました。source_security_group_idは、APIサーバサービスが存在するECSクラスターからのみを許可する設定です。from_port,to_portは、特定ポート接続のみを許可する設定です。outbound (egress)ルールは不要なので設定なしです。
なお、aws_security_group_ruleリソース記法は古い記法でv6.6.0ではaws_vpc_security_group_ingress_ruleリソース記法を推奨していますが、referenced_security_group_idにそのままsource_security_group_idと同じIDを設定してうまくいくかどうかは動作確認していないため採用しませんでした。おそらく旧記法のaws_security_groupリソース内のingressブロックで表現可能だったのでそのブロックで表現されたリソースの場合は指定できないかもしれません。
resource "aws_security_group" "dsql_vpc_endpoint" { name = "dsql-vpc-endpoint" vpc_id = var.vpc_id tags = { Name = "dsql-vpc-endpoint" } } resource "aws_security_group_rule" "dsql_vpc_endpoint_ingress" { type = "ingress" from_port = 5432 to_port = 5432 protocol = "tcp" security_group_id = aws_security_group.dsql_vpc_endpoint.id source_security_group_id = aws_security_group.ecs_cluster.id }
IAMロール
IAMロールは、DSQLの仕様であるトークン認証・認可方式において必須設定となります。まず、ECSクラスターの特定タスクに対して接続許可ポリシー dsql:DbConnectAdminを追加しました。そのうえで、マイグレーションをGitHub Actionsで自動化するためにそのOpenID Connectに対しても接続許可ポリシーを追加しました。また、APIサーバは、カスタムロールを使って接続させるためにカスタムロールに対しての接続許可ポリシー dsql:DbConnectも追加しました。
# 以下のポリシーをECSタスクのIAMロールに関連付け statement { sid = "DSQLConnection" effect = "Allow" actions = [ "dsql:DbConnect", "dsql:DbConnectAdmin" ] resources = [ var.dsql_arn ] }
次に、公式ドキュメントに従って実際にDSQLのpostgresデータベースにadminで接続してカスタムロール作成、IAMロール権限付与、特定スキーマにCRUD権限を付与しました。
CREATE ROLE example WITH LOGIN; AWS IAM GRANT example TO '[ECSタスクのIAMロールARN]'; GRANT USAGE ON SCHEMA myschema TO example; GRANT SELECT, INSERT, UPDATE ON ALL TABLES IN SCHEMA myschema TO example;
まとめ
本ブログでは、前半では、HashiCorpが提供するTerraformのAWS Provider version 6 upgradeを実際に行った話についてでした。
また後半では、Amazon Aurora DSQLについての実運用のための構築方法について簡単ではありますが説明させていただきました。
我々の新プロダクトが無事運用開始された後の運用実談についてまた別の機会にお話できればと思います。
最後に
エブリーでは、ともに働く仲間を募集しています。
テックブログを読んで少しでもエブリーに興味を持っていただけた方は、ぜひ一度カジュアル面談にお越しください!