この記事はぷりぷりあぷりけーしょんず Advent Calendar 2020の3日目の記事です。
概要
AWSのproductionアカウントとバックオフィスの人間が利用するAWSアカウントを分けて運用することは多いと思います。
両者のアカウントに作成したVPCをピアリングして疎通させるTerraformのメモです。
要件
新規に作成したアカウントA
から既存のアカウントB
へと繋ぎこみます。
実装
アカウント情報
下記のようにすることで、provider = aws.accountB
を指定することで既存のアカウントBに関するリソースの定義を行えます。
provider "aws" {}
provider "aws" {
alias = "accountB"
}
data "aws_caller_identity" "accountB" {
provider = aws.accountB
}
VPCリソース
既存アカウントBのVPCリソースはdataリソースで引っ張るようにします。provider = aws.accountBを忘れずに。
アカウントAとアカウントBのcidr_block
が被っていない必要があります。
resource "aws_vpc" "accountA" {
cidr_block = "10.0.0.0/16"
enable_dns_support = true
enable_dns_hostnames = true
tags = {
Name = "accountA-vpc"
}
}
data "aws_vpc" "accountB" {
provider = aws.accountB
filter {
name = "tag:Name"
values = ["accountB-vpc"]
}
}
Peering
resource "aws_vpc_peering_connection" "peer" {
peer_vpc_id = data.aws_vpc.accountB.id
vpc_id = aws_vpc.accountA.id
peer_owner_id = data.aws_caller_identity.accountB.account_id
peer_region = "ap-northeast-1"
auto_accept = false
tags = {
Name = "accountA"
Side = "Requester"
}
}
resource "aws_vpc_peering_connection_accepter" "peer" {
vpc_peering_connection_id = aws_vpc_peering_connection.peer.id
provider = aws.accountB
auto_accept = true
tags = {
Name = "accountB"
Side = "Accepter"
}
}
resource "aws_vpc_peering_connection_options" "requester" {
vpc_peering_connection_id = aws_vpc_peering_connection_accepter.peer.id
requester {
allow_remote_vpc_dns_resolution = true
}
}
resource "aws_vpc_peering_connection_options" "accepter" {
vpc_peering_connection_id = aws_vpc_peering_connection_accepter.peer.id
provider = aws.accountB
accepter {
allow_remote_vpc_dns_resolution = true
}
}
Route53の連携
AWSproviderのバージョンが新しいものでないと動作しません。筆者の環境は3.17
です。
アカウントAから既存アカウントBのプライベートレコードを引くことができるようにします。
検証してないですが、RDSのエンドポイントからAレコードを引けない気がしてならないので設定してます(未検証)。やるに越したことないので、DNS名を利用したい場合は設定します。
data "aws_route53_zone" "accountB" {
provider = aws.accountB
name = "accountB.local"
private_zone = true
}
resource "aws_route53_vpc_association_authorization" "assoc" {
provider = aws.accountB
vpc_id = aws_vpc.accountA.id
zone_id = data.aws_route53_zone.accountB.id
}
resource "aws_route53_zone_association" "assoc" {
vpc_id = aws_route53_vpc_association_authorization.accountB.vpc_id
zone_id = aws_route53_vpc_association_authorization.accountB.zone_id
}
ルートテーブルの設定
実際にはVPCのメインルートテーブルではなくサブネット単位でルートテーブルを作成してピアリング先と通信した方が良いです。
resource "aws_route_table" "accountA" {
vpc_id = aws_vpc.accountA.id
tags = {
Name = "accountA-rtb"
}
}
resource "aws_route" "accontA" {
route_table_id = aws_route_table.accountA.id
destination_cidr_block = data.aws_vpc.accountB.cidr_block
vpc_peering_connection_id = aws_vpc_peering_connection.peer.id
}
resource "aws_main_route_table_association" "accountA" {
route_table_id = aws_route_table.accountA.id
vpc_id = aws_vpc.accountA.id
}
data "aws_route_table" "accountB" {
provider = aws.accountB
filter {
name = "tag:Name"
values = ["accountB-rtb"]
}
}
resource "aws_route" "accountB" {
provider = aws.accountB
route_table_id = data.aws_route_table.accountB.id
destination_cidr_block = aws_vpc.accountA.cidr_block
vpc_peering_connection_id = aws_vpc_peering_connection.peer.id
}
デプロイ
ここまでで作成したファイルをmodule
として利用すると運用が簡単になります。Network周りのリソースは変更や削除をする機会も少ないと思うので。
例えば下記のような構成も考えられます。めちゃくちゃ適当なので、ディレクトリ構成のプラクティスは別途調べると良いでしょう(tfstateのバックエンドの設定とか諸々)。
├── network
│ ├── aws.tf
│ ├── vpc.tf
│ ├── peer.tf
│ ├── private_r53.tf
│ └── rtb.tf
└── main.tf
provider "aws" {
version = "~> 3.17"
region = "ap-northeast-1"
profile = アカウントAのプロファイル
}
provider "aws" {
version = "~> 3.17"
alias = "accountB"
region = "ap-northeast-1"
profile = アカウントBのプロファイル
}
module "network" {
source = "./network"
providers = {
aws = aws
aws.accountB = aws.accountB
}
}
まとめ
AWSの構成管理はTerraformやCDKなどで行うことが多いですが、やはりマネジメントコンソールからリソースを管理することもまだまだ多いと思います。
クロスアカウントなリソースの管理は煩雑なイメージもありますし、Terraformで管理するハードルも高いようなイメージがあります。
しかし実際に実装してみた所感としてはそこまで煩雑で手間がかかる印象もなかったので、今後もガンガン利用していきたいためメモとしてまとめてみました。