kun432's blog

Alexaなどスマートスピーカーの話題中心に、Voiceflowの日本語情報を発信してます。たまにAWSやkubernetesなど。

〜スマートスピーカーやVoiceflowの記事は右メニューのカテゴリからどうぞ。〜

(Organizations環境で)Transit Gatewayを使ったアカウント跨ぎのVPC間通信をTerraformで作る

f:id:kun432:20210228193004p:plain

マルチアカウント間の通信にTransit Gatewayを使う場合、以下の記事にあるようにResouce Access Managerを使ってリソース共有を行う必要があります。

Organizations環境でTerraformを使ってやってみたのでメモ。なお、Organizationsの設定でAWS Resource Access Managerは有効になっている前提です。

f:id:kun432:20210228231928p:plain

目次

構成とコード

f:id:kun432:20210228224738p:plain

READMEに従えばできるはず。TF_VARS_*使えばvariables.tf修正する必要もないですね。

少し補足。

  • 実際には使いませんが、パブリックサブネットやInternet Gatewayも作ってます(他に色々試す場合にどうせ必要になるので)
  • EC2インスタンスは手動で適当に立てればいいです。
    • EC2インスタンスへのログインはSession Manager使えばいいと思います。VPCエンドポイントはTerraformで作成してます。
    • ただし、Session Manager使うためのIAMロールは作ってません。Systems Manager Quick Setupで作成されるAmazonSSMRoleForInstancesQuickSetup使えばいいかと思います。もちろん作ってもよし。
  • プライベートサブネットが各リージョンごとに複数あるのは、Transit Gatewayにアタッチされているサブネット以外からもアクセスできるということの確認のためです。

解説

Transit Gatewayの作成はモジュール化してます。OwnerとUserをうまく共通化する方法が思いつかなかったので、別モジュールになってます。

Owner側

variable "vpc_id" {}
variable "private_subnet_ids" {}
variable "private_rtb_id" {}
variable "user_account" {}
variable "user_cidr" {}

resource "aws_ec2_transit_gateway" "tgw" {
  dns_support                     = "enable"
  vpn_ecmp_support                = "disable"
  default_route_table_association = "enable"
  default_route_table_propagation = "enable"
  auto_accept_shared_attachments  = "enable"
}

resource "aws_ec2_transit_gateway_vpc_attachment" "tgw-attachment" {
  transit_gateway_id = aws_ec2_transit_gateway.tgw.id
  vpc_id             = var.vpc_id
  subnet_ids         = var.private_subnet_ids
  dns_support        = "enable"
}

resource "aws_ram_resource_share" "tgw" {
  name = "tgw"
  allow_external_principals = true
  tags = {
    Name = "tgw"
  }
}

resource "aws_ram_resource_association" "tgw" {
  resource_arn       = aws_ec2_transit_gateway.tgw.arn
  resource_share_arn = aws_ram_resource_share.tgw.arn
}

resource "aws_ram_principal_association" "tgw" {
  principal          = var.user_account
  resource_share_arn = aws_ram_resource_share.tgw.arn
}

resource "aws_route" "route_tgw" {
  route_table_id         = var.private_rtb_id
  destination_cidr_block = var.user_cidr
  transit_gateway_id     = aws_ec2_transit_gateway.tgw.id
}

Owner側では、

  • Transit Gatewayを作成
  • Resouce SharingでUserアカウントに共有

します。アカウント間のリソース共有は共有元・共有先の両方で設定しないといけないので、書き方いまいちピンとこないうちは試行錯誤してましたが、つながってみればほぼマニュアル通りな感じでした。

User側

variable "vpc_id" {}
variable "private_subnet_ids" {}
variable "private_rtb_id" {}
variable "owner_account" {}
variable "owner_cidr" {}

data "aws_ec2_transit_gateway" "tgw" {
  filter {
    name   = "owner-id"
    values = [var.owner_account]
  }
}

resource "aws_ec2_transit_gateway_vpc_attachment" "example" {
  vpc_id             = var.vpc_id
  subnet_ids         = var.private_subnet_ids
  transit_gateway_id = data.aws_ec2_transit_gateway.tgw.id
  dns_support        = "enable"
}

resource "aws_route" "route_tgw" {
  route_table_id         = var.private_rtb_id
  destination_cidr_block = var.owner_cidr
  transit_gateway_id     = data.aws_ec2_transit_gateway.tgw.id
}

User側では、Ownerが作成したTransit Gatewayを使うだけなので、dataリソースで読んでいます。Organizations環境でAWS Resource Access Managerが有効になっているので、とてもかんたんですね。

OrganizationsでAWS Resource Access Managerが無効になっている場合や、別組織のアカウントとのリソース共有では、ram_resource_share_accepterを使う必要があるようです(が試してないのでわからない)。詳しくはドキュメント見てください。

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ram_principal_association

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ram_resource_share_accepter

まとめ

Transit Gatewayとかリソース共有殆ど触ったことなかったので、一通りできてよかったし、モジュールの作り方もやっとわかった。これでいつでも作って壊せる環境ができたのでいろいろ試してみたいと思います。