【手順画像付き】CIDR 重複対応:NLB 不要の AWS PrivateLink で VPC のインターネット通信を集約

CIDR 重複対応:NLB 不要の AWS PrivateLink で VPC のインターネット通信を集約
  • CIDR が重複して Transit Gateway が使えない VPC 環境でも、インターネット通信(HTTP・HTTPS)を集約する方法を紹介します。
  • 本記事では、PrivateLink を活用して VPC 間の通信を整理し集約することで、NAT ゲートウェイを削減する実践的な手法を解説します。
  • CIDR 重複問題があり、インターネット通信の集約にお悩みの方はぜひ参考にしてください!

こちらの記事の背景としては、社員に AWS ユーザーを払い出した結果、複数の VPC と NAT ゲートウェイが乱立した背景があります。
本記事の本筋とは関係ありませんが、興味がある方は以下の記事をご参照下さい。

2024/12/04 更新
AWS announces access to VPC resources over AWS PrivateLink
AWS PrivateLinkでNLBを介さずにVPC内リソースにアクセスできるようになりました。
詳細は上記の公式記事をご参照ください。
弊社でも元々 NLB を使っていたのですが、これを機に NLB を使わない方法へ移行しました。

背景

弊社では、プロジェクトごとに VPC を分けて運用しています。
インターネットへの接続方法として、NAT ゲートウェイを使うことを要件としていますが、VPC の数が増えてきてコストの増加がネックになっていました。

そのため、以下のように複数の VPC を Transit Gateway で繋いで、インターネット出口用に NAT ゲートウェイを集約することを考えました。

NAT ゲートウェイを使用した一元的なIPv4出力
https://docs.aws.amazon.com/ja_jp/whitepapers/latest/building-scalable-secure-multi-vpc-network-infrastructure/using-nat-gateway-for-centralized-egress.html

ただ、弊社の環境では Transit Gateway で VPC 間の接続ができないことが発覚しました。

原因

弊社の落ち度ではありますが、プロジェクトごとにユーザーを払い出すだけで、特に IP アドレス帯の取り決めはしていませんでした。
そのため、多くの VPC で CIDR が重複しており、Transit Gateway に各 VPC をアタッチできない状況となりました。
(正確にはアタッチはできますが、Transit Gateway ルートテーブルで指定する戻りのルートが複数の VPC で重複してしまう状況です。)

CIDR が同一の Amazon VPC に接続することはできますか?
AWS Transit Gateway では、CIDR が同一の Amazon VPC 間のルーティングはサポートしていません。新しい Amazon VPC をアタッチする場合、その CIDR が、既にアタッチされている Amazon VPC と同一ならば、AWS Transit Gateway では、新しい Amazon VPC のルートを AWS Transit Gateway ルートテーブルに伝播しません。CIDR が同一の Amazon VPC に接続することはできますか?

https://aws.amazon.com/jp/transit-gateway/faqs/

以下のようにプライベート NAT ゲートウェイを使用して、重複しない IP アドレスへ変換する方法も考えました。
ただ、この方法だと、結局各 VPC でプライベート NAT ゲートウェイを使うことになり、コスト削減の目的を満たしません。

重複するネットワーク間の通信を有効にする
https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/nat-gateway-scenarios.html#private-nat-overlapping-networks

方法

幸いなことに、各プロジェクトで NAT ゲートウェイを使用している用途は、HTTP/HTTPS でのインターネット通信が主でした。
そのため、今回の要件を満たす構成として、AWS PrivateLink と Proxy サーバを使用して、NAT ゲートウェイ経由のインターネット出口を集約しました。
AWS PrivateLink であれば、VPC 間の IP アドレス範囲が重複していても通信が可能です。
構成は以下のような感じです。

この構成図では通信元の VPC は4つだけですが、実際には多くの VPC が存在します。
また、NAT gateway / Proxy Instance はリージョン内の各 AZ に配置することで、より高可用性を持った運用が可能です。

2024/12/04 更新
一応、NLB が必要だった時の構成図を残しておきます。
以前は、PrivateLink からのトラフィックは、NLB が受け取りターゲットにルーティングしていました。
最新の更新では、PrivateLink からのトラフィックは、Resource Gateway が受け取り、Resource Configuration で指定されたリソースにルーティングできるようになった感じのようです。

NLB がある以前の構成図

管理者側の手順

まずは、VPC の作成からやっていきます。

VPC の作成

  1. 以下の URL から VPC やサブネットなどを作成します。
    https://ap-northeast-1.console.aws.amazon.com/vpcconsole/home?region=ap-northeast-1#CreateVpc:createMode=vpcWithResources
  2. 以下の設定で作成します。(下線の項目以外はデフォルトのままにしました。)
    • 作成するリソース:VPC など
      • これでサブネットなども同時に作ってくれます。
    • 名前タグの自動生成:☑️ 自動生成「Proxy」
      • VPC やサブネットの名前を自動で付けてくれます。後から変更可能です。
    • IPv4 CIDR ブロック:10.0.0.0/16
      • VPC のプライベートな IP アドレスの範囲です。後から変更できません。
      • インターネットに出るときのパブリックな IP アドレスとは無関係です。
    • アベイラビリティゾーン (AZ) の数:2
      • サブネットを配置する AWS データセンタの個数と認識しています。
    • パブリックサブネットの数:2
      • インターネットに出れるサブネットの個数です。
    • プライベートサブネットの数:2
      • インターネットに出れないサブネットの個数です。
      • 1つを Proxy サーバー用にします。
      • もう1つを NLB 用にします。
    • NAT ゲートウェイ ($):1 AZ 内
      • NAT ゲートウェイを使うなら、すべての AZ に配置するかどうかの設定です。
      • NAT ゲートウェイの数ごとに費用がかかるので、ひとまず1つの AZ に作成します。
      • ($)マークが料金のかかることを表している?)
    • VPC エンドポイント:S3 ゲートウェイ
      • VPC から S3 へ直接アクセスできるようにするものみたいです。
      • 付けること自体は無料で、料金の削減に貢献するようなのでそのままつけときます。
画像

Proxy サーバの準備

慣れているのでこちらの手順は AWS CLI コマンドで実施します。

  1. 以下の AWS CLI コマンドで、EC2 インスタンスにセッションマネージャーで接続するためのインスタンスプロファイルを作成します。
# Create IAM role
aws iam create-role \
    --role-name SSMRole \
    --assume-role-policy-document '{
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Principal": {
                    "Service": "ec2.amazonaws.com"
                },
                "Action": "sts:AssumeRole"
            }
        ]
    }'

# Attach IAM policy for SSM
aws iam attach-role-policy \
    --role-name SSMRole \
    --policy-arn arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore

# Create instance profile
aws iam create-instance-profile \
    --instance-profile-name SSMRole

# Add IAM role to instance profile
aws iam add-role-to-instance-profile \
    --instance-profile-name SSMRole \
    --role-name SSMRole
  1. 以下の AWS CLI コマンドで、Resource gateway からのトラフィックを許可するルールを持つ、Proxy インスタンス用のセキュリティグループを作成します。
    ※ アウトバウンドルールはデフォルトで作成されているので設定不要です。
SourceProtocolPort
10.0.0.0/16 (VPC CIDR)AllAll
Inbound Rule
DestinationProtocolPort
0.0.0.0/0AllAll
Outbound Rule
# Get VPC ID
VPC_ID=$(aws ec2 describe-vpcs \
    --filters "Name=tag:Name,Values=Proxy-vpc" \
    --query "Vpcs[].VpcId" \
    --output text)

# Create a security group for proxy instance
SECURITY_GROUP_ID=$(aws ec2 create-security-group \
    --group-name Proxy-sg \
    --description "Security group for proxy instance" \
    --vpc-id $VPC_ID \
    --query 'GroupId' \
    --output text)

# Add an inbound rule to allow all traffic from VPC
aws ec2 authorize-security-group-ingress \
    --group-id $SECURITY_GROUP_ID \
    --protocol -1 \
    --cidr 10.0.0.0/16
  1. 以下の AWS CLI コマンドで、このセキュリティグループを持つ EC2 インスタンスを、1つのプライベートサブネットに起動します。
# Get Amazon Linux 2 AMI ID
AMI_ID=$(aws ec2 describe-images \
    --owners amazon \
    --filters "Name=name,Values=amzn2-ami-hvm-2.0.*-x86_64-gp2" \
    --query 'sort_by(Images, &CreationDate)[-1].ImageId' \
    --output text)

# Get Subnet ID for running proxy instance
SUBNET_ID=$(aws ec2 describe-subnets \
    --filters "Name=tag:Name,Values=Proxy-subnet-private1-*" \
    --query "Subnets[].SubnetId" \
    --output text)

# Run EC2 instance for proxy
aws ec2 run-instances \
    --image-id $AMI_ID \
    --count 1 \
    --instance-type t2.micro \
    --iam-instance-profile Name=SSMRole \
    --security-group-ids $SECURITY_GROUP_ID \
    --subnet-id $SUBNET_ID \
    --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=ProxyInstance}]'
  1. 以下の AWS CLI コマンドで、セッションマネージャーを通して EC2 インスタンスに接続します。
# Get EC2 instance ID
EC2_ID=$(aws ec2 describe-instances \
    --filters "Name=tag:Name,Values=ProxyInstance" \
    --query "Reservations[].Instances[].InstanceId" \
    --output text)

# Start connect by Session Manager
aws ssm start-session --target $EC2_ID
  1. 以下のコマンドを実行し、Proxy サーバーを構築します。
    ここでは最低限の設定にしていますが、適宜ユースケースに合わせてカスタマイズしてください。
## Bellow command is at Session Manager.
# Ready for operating proxy
sh-4.2$ sudo yum -y install squid
sh-4.2$ sudo systemctl start squid
sh-4.2$ sudo systemctl enable squid
sh-4.2$ sudo lsof -i:3128
COMMAND  PID  USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
squid   3551 squid   11u  IPv6  33657      0t0  TCP *:squid (LISTEN)

Resource gateway の作成

Resource gateway の作成が完了すると、指定したサブネットに ENI が作成されます。
PrivateLink 経由のトラフィックは、この ENI から流れてくるイメージだと思っています。

  1. 以下の AWS CLI コマンドで、Resource gateway からのトラフィックを許可するルールを持つ、Resource gateway 用のセキュリティグループを作成します。
    ※ アウトバウンドルールはデフォルトで作成されているので設定不要です。
SourceProtocolPort
0.0.0.0/0AllAll
Inbound Rule
DestinationProtocolPort
0.0.0.0/0AllAll
Outbound Rule
# Get VPC ID
VPC_ID=$(aws ec2 describe-vpcs \
    --filters "Name=tag:Name,Values=Proxy-vpc" \
    --query "Vpcs[].VpcId" \
    --output text)

# Create a security group for resource gateway
SECURITY_GROUP_ID=$(aws ec2 create-security-group \
    --group-name ResourceGateway-sg \
    --description "Security group for resource gateway" \
    --vpc-id $VPC_ID \
    --query 'GroupId' \
    --output text)

# Add an inbound rule to allow all traffic
aws ec2 authorize-security-group-ingress \
    --group-id $SECURITY_GROUP_ID \
    --protocol -1 \
    --cidr 0.0.0.0/0
  1. 以下の URL から Resource gateway を作成します。
    https://ap-northeast-1.console.aws.amazon.com/vpcconsole/home?region=ap-northeast-1#CreateResourceGateway:
  1. 以下の設定で作成します。
    • Resource gateway name:proxy-rgw
    • IP address type:IPv4
    • VPC:Proxy-vpc
    • ☑️ ap-northeast-1a:Proxy-subnet-private1-ap-northeeast-1a
    • ☑️ ap-northeast-1c:Proxy-subnet-private2-ap-northeeast-1c
      • このサブネットに ENI が作成されます。
    • Security groups:ResourceGateway-sg
      • 作成される ENI に設定されるセキュリティグループです。
      • PrivateLink からのリソースまでのトラフィックが許可されている必要があります。
画像

Resource configuration の作成

ここで PrivateLink からのトラフィックのルーティング先を指定します。
指定された Resource gateway を通過する、指定されたポート番号のトラフィックを、指定されたリソースへルーティングされることになります。

  1. 以下の URL から Resource configuration を作成します。
    https://ap-northeast-1.console.aws.amazon.com/vpcconsole/home?region=ap-northeast-1#CreateResourceConfig:
  2. 以下の設定で作成します。
    • Name:Proxy-conf
    • Configuration type:◉ Resource
    • Type:Single
    • Protocol:TCP
    • Resource gateway:proxy-rgw
    • Resource type:◉ DNS resource
    • Domain name:proxy.awsexample.com
      • Proxy Instance の IP アドレスに解決されるドメイン名を指定しました。
      • 後述しますが、ここをドメイン名で指定すればプライベート DNS が有効になるのかなとも思ったのですが、そんな感じではなさそうでした。
      • IP アドレスで指定することもできます。
    • IP address type:IPv4
    • Port ranges
      • Lower bound:1
      • Upper bound:65535
    • Allow association with shareable service networks:◉ Allow
      • おそらく Amazon VPC Lattice の「サービスネットワーク」にて、この Configuration の関連付けを許可するか、ということだと思います。
        今回は「サービスネットワーク」は使いませんがデフォルトのままにしておきます。
画像

後述しますが、NLB を使用した VPC エンドポイントサービスの時と異なり、ドメインの所有を確認する項目などは見つからず、上記設定で VPC エンドポイントのプライベート DNS 名は設定されませんでした。
また、ルーティング先のリソースの指定にドメイン名は使えるものの、そのためにはそのドメイン名はリソースのプライベート IP アドレスを指していなくてはいけない状況です。
パブリックで使用しているドメイン名をプライベート DNS 名として使用する方法は今のところないのかもしれません。

ユーザー側の手順

各プロジェクトでは、VPC 上に VPC エンドポイントを作成したうえで、Proxy を設定してもらいました。

VPC エンドポイントの作成

  1. 以下の URL から VPC エンドポイントを作成します。
    https://ap-northeast-1.console.aws.amazon.com/vpcconsole/home?region=ap-northeast-1#CreateVpcEndpoint:
  2. 以下の設定で作成します。
    • Name tag - optional:Proxy-vpce
    • Type:Resources - New
    • Resource configurations:proxy-conf
    • VPC:<プロジェクト VPC>
    • DNS name:☑️ Enable DNS name
    • Subnets
      • ☑️ ap-northeast-1a:<プロジェクトサブネット AZ-a>
      • ☑️ ap-northeast-1c:<プロジェクトサブネット AZ-c>
    • Security groups:<セキュリティグループ ID>
      • 通信元からのトラフィックを許可するルールが必要です。
      • 弊社では、VPC CIDR からの通信をすべて許可するように案内にしています。
画像

Proxy の設定

作成された VPC エンドポイントを見てみても、プライベート DNS 名は有効化されていそうでしたが、ドメイン名は表示されませんでした。
そもそも有効化できるのかどうかもわからず、ひとまずは各プロジェクトでプライベート IP アドレスを確認して設定してもらう方針としました。

  1. 以下の URL より、作成した VPC エンドポイントの ID をもとに、プライベート IP アドレスを確認してもらいます。
    https://ap-northeast-1.console.aws.amazon.com/ec2/home?region=ap-northeast-1#NIC:description=:VPC%20Endpoint%20Interface;v=3;$case=tags:false%5C,client:false;$regex=tags:false%5C,client:false
  2. 各通信元サーバに Proxy 設定をしてもらいます。

今のところ、この構成で上手くいっています。
ただ、やはり一意なドメイン名を割り当てられると手順の配布が楽なので、プライベート DNS 名が使えると嬉しいと思いました。
もし、方法などありましたら、お問い合わせより教えていただけると嬉しいです。

また、Proxy で対応できない通信などもこれからでてくると思います。
その場合に備え、各プロジェクトに対して、IP アドレスの使用範囲を取り決めておこうと思います。

タイトルとURLをコピーしました