👾

東京、大阪リージョン間の VPC Peering 設定を Terraform import block で Terraform 管理にする

2024/10/15に公開

はじめに

最近手動で作成されていた VPC Peering 設定を Terraform import block で Terraform 管理下にしたのでそのおさらいとしてまとめておきます。

背景

AWS VPC Peeringは、異なる VPC 間で通信を可能にする接続を確立するための仕組みです。VPC Peering には、ピア接続をリクエストするリクエスター( requester )と、その接続を承認するアクセプター( accepter )の2つの役割があります。
例えば、大阪リージョン( ap-northeast-3 )と東京リージョン( ap-northeast-1 )の VPC 間で接続を行う場合、大阪側がリクエスター、東京側がアクセプターになるといった具合です。

これまで、既存のリソースを Terraform で管理するためには、terraform import コマンドを手動で実行していました。しかし、Terraform 1.5から導入された import block を使うことで、構成ファイルにインポート操作を直接記述でき、よりスムーズにリソースを管理できるようになりました。

今回の対象

今回は、以下の AWS リソースを Terraform でインポートし、管理する方法を見ていきます。

  • VPC Peering(リクエスター:大阪、アクセプター:東京)
  • Route Table(大阪と東京のそれぞれのVPC)

VPC Peering の設定はあらかじめ AWS コンソールで設定済みの想定でおこなます。
AWS コンソールでの設定の仕方は以下のブログなどを参照してください。
https://zenn.dev/rescuenow/articles/8e21a751c828c6

Terraform ファイルの作成

今回は簡単のためにファイルを分けずに main.tf だけで解説していきます。
全体は以下です。

main.tf
# -------------------------------------------------------------
# プロバイダーの設定
# -------------------------------------------------------------
provider "aws" {
  alias  = "tokyo"
  region = "ap-northeast-1"
}

provider "aws" {
  alias  = "osaka"
  region = "ap-northeast-3"
}

# -------------------------------------------------------------
# 変数定義
# -------------------------------------------------------------
variable "tokyo_vpc_id" {
  type = string
}

variable "osaka_vpc_id" {
  type = string
}

variable "vpc_peering_id" {
  type = string
}

variable "tokyo_route_table_id" {
  type = string
}

variable "osaka_route_table_id" {
  type = string
}

locals {
  tokyo_vpc_cidr = "10.1.0.0/24"
  osaka_vpc_cidr = "10.2.0.0/24"
}

# -------------------------------------------------------------
# リクエスター大阪側の設定
# -------------------------------------------------------------
resource "aws_vpc_peering_connection" "main" {
  provider    = aws.osaka
  vpc_id      = var.osaka_vpc_id # 大阪リージョンのVPC ID
  peer_vpc_id = var.tokyo_vpc_id # 東京リージョンのVPC ID
}

import {
  id = var.vpc_peering_id
  to = aws_vpc_peering_connection.main
}

# -------------------------------------------------------------
# アクセプター東京側の設定
# -------------------------------------------------------------
resource "aws_vpc_peering_connection_accepter" "main" {
  vpc_peering_connection_id = aws_vpc_peering_connection.main.id
}

import {
  id = var.vpc_peering_id
  to = aws_vpc_peering_connection_accepter.main
}

# -------------------------------------------------------------
# 大阪リージョンの Route Table に 東京リージョンの CIDR を追加
# -------------------------------------------------------------
resource "aws_route" "to_tokyo" {
  provider                  = aws.osaka
  route_table_id            = var.osaka_route_table_id
  destination_cidr_block    = local.tokyo_vpc_cidr # 東京側の CIDR
  vpc_peering_connection_id = aws_vpc_peering_connection.main.id
}

import {
  id = format("%s_%s", var.osaka_route_table_id, local.tokyo_vpc_cidr)
  to = aws_route.to_tokyo
}

# -------------------------------------------------------------
# 東京リージョンの Route Table に 大阪リージョンの CIDR を追加
# -------------------------------------------------------------
resource "aws_route" "to_osaka" {
  route_table_id            = var.tokyo_route_table_id
  destination_cidr_block    = local.osaka_vpc_cidr # 大阪側の CIDR
  vpc_peering_connection_id = aws_vpc_peering_connection.main.id
}

import {
  id = format("%s_%s", var.tokyo_route_table_id, local.osaka_vpc_cidr)
  to = aws_route.to_osaka
}

1. プロバイダーの設定と変数定義部分

まず、AWS プロバイダーの設定を行います。大阪リージョンと東京リージョンの両方のプロバイダーを定義します。
また必要な変数を定義しています。
今回はすでに VPC やルートテーブルが作成されているという前提のため変数定義をしています。

# -------------------------------------------------------------
# プロバイダーの設定
# -------------------------------------------------------------
provider "aws" {
  alias  = "tokyo"
  region = "ap-northeast-1"
}

provider "aws" {
  alias  = "osaka"
  region = "ap-northeast-3"
}

# -------------------------------------------------------------
# 変数定義
# -------------------------------------------------------------
variable "tokyo_vpc_id" {
  type = string
}

variable "osaka_vpc_id" {
  type = string
}

variable "vpc_peering_id" {
  type = string
}

variable "tokyo_route_table_id" {
  type = string
}

variable "osaka_route_table_id" {
  type = string
}

locals {
  tokyo_vpc_cidr = "10.1.0.0/24"
  osaka_vpc_cidr = "10.2.0.0/24"
}

2. VPC Peering の定義(リクエスターとアクセプター)

次に、大阪と東京の VPC 間で VPC Peering を設定します。それぞれのリソースを定義し、import block で既存のリソースを取り込みます。

リクエスター(大阪側)の設定

まずは、大阪リージョン( ap-northeast-3 )側の VPC (リクエスター)です。ここでは、接続をリクエストする VPC Peering のリソースを定義します。

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

# -------------------------------------------------------------
# リクエスター大阪側の設定
# -------------------------------------------------------------
resource "aws_vpc_peering_connection" "main" {
  provider    = aws.osaka
  vpc_id      = var.osaka_vpc_id # 大阪リージョンのVPC ID
  peer_vpc_id = var.tokyo_vpc_id # 東京リージョンのVPC ID
}

import {
  id = var.vpc_peering_id
  to = aws_vpc_peering_connection.main
}

アクセプター(東京側)の設定

次に、東京リージョン( ap-northeast-1 )側の VPC (アクセプター)の設定です。こちらは、大阪からの接続リクエストを承認する設定です。

https://registry.terraform.io/providers/rgeraskin/aws2/latest/docs/resources/vpc_peering_connection_accepter

# -------------------------------------------------------------
# アクセプター東京側の設定
# -------------------------------------------------------------
resource "aws_vpc_peering_connection_accepter" "main" {
  vpc_peering_connection_id = aws_vpc_peering_connection.main.id
}

import {
  id = var.vpc_peering_id
  to = aws_vpc_peering_connection_accepter.main
}

3. Route Table の設定

VPC Peering が確立されたら、それぞれのVPCのルートテーブルにピア接続を追加します。

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route#import

大阪リージョン側のルート

# -------------------------------------------------------------
# 大阪リージョンの Route Table に 東京リージョンの CIDR を追加
# -------------------------------------------------------------
resource "aws_route" "to_tokyo" {
  provider                  = aws.osaka
  route_table_id            = var.osaka_route_table_id
  destination_cidr_block    = local.tokyo_vpc_cidr # 東京側の CIDR
  vpc_peering_connection_id = aws_vpc_peering_connection.main.id
}

import {
  id = format("%s_%s", var.osaka_route_table_id, local.tokyo_vpc_cidr)
  to = aws_route.to_tokyo
}

東京リージョン側のルート

# -------------------------------------------------------------
# 東京リージョンの Route Table に 大阪リージョンの CIDR を追加
# -------------------------------------------------------------
resource "aws_route" "to_osaka" {
  route_table_id            = var.tokyo_route_table_id
  destination_cidr_block    = local.osaka_vpc_cidr # 大阪側の CIDR
  vpc_peering_connection_id = aws_vpc_peering_connection.main.id
}

import {
  id = format("%s_%s", var.tokyo_route_table_id, local.osaka_vpc_cidr)
  to = aws_route.to_osaka
}

4. Plan と Apply

ここまでの設定を終えたら、terraform plan で計画を確認し、terraform apply で適用します。

terraform plan
terraform apply

ちなみに plan の時は以下のようになりました。4個の import なので期待した通りです💪
実際には少しずつ import block の設定を書いて plan した結果から差分がなくなるように修正していくことになると思います。

% terraform plan
var.osaka_route_table_id
  Enter a value: rtb-0b893b0376a5ac2ea

var.osaka_vpc_id
  Enter a value: vpc-03c8bb0387d52af49

var.tokyo_route_table_id
  Enter a value: rtb-09acd6754ff54a34e

var.tokyo_vpc_id
  Enter a value: vpc-05e624e4333185f4b

var.vpc_peering_id
  Enter a value: pcx-0d51922e47310740b

aws_vpc_peering_connection.main: Preparing import... [id=pcx-0d51922e47310740b]
aws_vpc_peering_connection.main: Refreshing state... [id=pcx-0d51922e47310740b]
aws_vpc_peering_connection_accepter.main: Preparing import... [id=pcx-0d51922e47310740b]
aws_route.to_osaka: Preparing import... [id=rtb-09acd6754ff54a34e_10.2.0.0/24]
aws_route.to_tokyo: Preparing import... [id=rtb-0b893b0376a5ac2ea_10.1.0.0/24]
aws_route.to_tokyo: Refreshing state... [id=r-rtb-0b893b0376a5ac2ea53682283]
aws_route.to_osaka: Refreshing state... [id=r-rtb-09acd6754ff54a34e2377918344]
aws_vpc_peering_connection_accepter.main: Refreshing state... [id=pcx-0d51922e47310740b]

Terraform will perform the following actions:

  # aws_route.to_osaka will be imported
    resource "aws_route" "to_osaka" {
        destination_cidr_block    = "10.2.0.0/24"
        id                        = "r-rtb-09acd6754ff54a34e2377918344"
        origin                    = "CreateRoute"
        route_table_id            = "rtb-09acd6754ff54a34e"
        state                     = "active"
        vpc_peering_connection_id = "pcx-0d51922e47310740b"
    }

  # aws_route.to_tokyo will be imported
    resource "aws_route" "to_tokyo" {
        destination_cidr_block    = "10.1.0.0/24"
        id                        = "r-rtb-0b893b0376a5ac2ea53682283"
        origin                    = "CreateRoute"
        route_table_id            = "rtb-0b893b0376a5ac2ea"
        state                     = "active"
        vpc_peering_connection_id = "pcx-0d51922e47310740b"
    }

  # aws_vpc_peering_connection.main will be imported
    resource "aws_vpc_peering_connection" "main" {
        accept_status = "active"
        id            = "pcx-0d51922e47310740b"
        peer_owner_id = "xxxxxxxxxxxxx"
        peer_region   = "ap-northeast-1"
        peer_vpc_id   = "vpc-05e624e4333185f4b"
        tags          = {}
        tags_all      = {}
        vpc_id        = "vpc-03c8bb0387d52af49"

        accepter {
            allow_remote_vpc_dns_resolution = false
        }

        requester {
            allow_remote_vpc_dns_resolution = false
        }
    }

  # aws_vpc_peering_connection_accepter.main will be imported
    resource "aws_vpc_peering_connection_accepter" "main" {
        accept_status             = "active"
        id                        = "pcx-0d51922e47310740b"
        peer_owner_id             = "xxxxxxxxxxxxx"
        peer_region               = "ap-northeast-1"
        peer_vpc_id               = "vpc-05e624e4333185f4b"
        tags                      = {}
        tags_all                  = {}
        vpc_id                    = "vpc-03c8bb0387d52af49"
        vpc_peering_connection_id = "pcx-0d51922e47310740b"

        accepter {
            allow_remote_vpc_dns_resolution = false
        }

        requester {
            allow_remote_vpc_dns_resolution = false
        }
    }

Plan: 4 to import, 0 to add, 0 to change, 0 to destroy.

───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.

まとめ

今回の手順で、VPC Peering を Terraform の import block を使って管理する方法を紹介しました。import block は、既存リソースを Terraform の構成ファイルに統合する新しい手法で、手動でインポートする必要がなくなり、リソース管理が一貫性を持つようになります。

リクエスターとアクセプターの役割を明確に区別し、それぞれの接続オプションやルーティング設定を適切に行うことが重要です。今回の VPC Peering の例では、大阪リージョンがリクエスター、東京リージョンがアクセプターとして接続が確立されましたが、他のリージョン間や VPC 間の接続にも同様の手法が使えます。

これで、既存の AWS リソースを効率よく Terraform で管理できるようになります。今後も import block を活用してインフラのコード管理を進めていきましょう!

import block に関するレスキューナウの記事
https://zenn.dev/rescuenow/articles/62da053a883858

レスキューナウテックブログ

Discussion