LoginSignup
0

More than 3 years have passed since last update.

Terraform + クロスアカウント + VPCピアリング

Last updated at Posted at 2020-12-03

この記事はぷりぷりあぷりけーしょんず Advent Calendar 2020の3日目の記事です。

概要

AWSのproductionアカウントとバックオフィスの人間が利用するAWSアカウントを分けて運用することは多いと思います。

両者のアカウントに作成したVPCをピアリングして疎通させるTerraformのメモです。

要件

新規に作成したアカウントAから既存のアカウントBへと繋ぎこみます。

実装

アカウント情報

下記のようにすることで、provider = aws.accountBを指定することで既存のアカウントBに関するリソースの定義を行えます。

aws.tf
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が被っていない必要があります。

vpc.tf
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

peer.tf
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名を利用したい場合は設定します。

private_r53.tf
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のメインルートテーブルではなくサブネット単位でルートテーブルを作成してピアリング先と通信した方が良いです。

rtb.tf
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
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で管理するハードルも高いようなイメージがあります。

しかし実際に実装してみた所感としてはそこまで煩雑で手間がかかる印象もなかったので、今後もガンガン利用していきたいためメモとしてまとめてみました。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0