🔐

トラフィックフローから理解するAWS/AzureのPrivateLink

2024/04/01に公開

きっかけ

AWSとオンプレミスでインフラ系の開発を続けてきましたが、4月からAzureを扱うことになりました。
そこで自身が良く触るネットワーク周りから理解を深めようとしたところ、各プロバイダ間でもやっと違いを感じたので、整理したいと思ったのが動機です。

対象読者

  • AWSとAzureのPrivate Linkの違いを理解されたい方
  • それぞれのサービスにおけるトラフィックフローを理解されたい方

先に結論

PrivateLinkを利用するためのエンドポイントに着目し手考えると、
AWSはサービスに対してのPrivateLinkを提供するエンドポイントであり、
Azureはリソースに対してPrivateLinkを提供するエンドポイントであるという違いがあることを理解しました。

慣れの問題かもしれないですが、サービスカットでエンドポイントを作成するAWSの方がわかりやすい&使い勝手が良いように感じました。

以降、トラフィックフローの解説と実際にリソース作成中に気づいた違いについて説明いたします。

AWSのPrivateLink

AWSのPrivate Linkはマネージドサービスのほかにも、AWS上に構築したワークロードへのプライベートアクセスを提供することもできますが、今回はマネージドサービス向けのPrivateLinkについて確認していきます。
https://aws.amazon.com/jp/privatelink/

VPCエンドポイントなしのトラフィック

今回は以下のような構成において、EC2インスタンスからAWS CLIを利用することで、AWSのサービスエンドポイント[1]をたたいてみます。

トラフィックフロー

EC2インスタンスからs3 lsコマンドを発行してトラフィックフローを確認してみます。

--debugオプションをつけることでどこにリクエストを送っているのか確認してみると「zenn-privatelink.s3.us-east-1.amazonaws.com」にリクエストを送っていることがわかります。

[ec2-user@ip-10-0-0-176 ~]$aws s3 ls s3://zenn-privatelink --debug
(省略)
2024-03-30 14:03:49,366 - MainThread - botocore.regions - DEBUG - Endpoint provider result: https://zenn-privatelink.s3.us-east-1.amazonaws.com
(省略)

続いて先のFQDNがどのように名前解決されたか確認します。
VPCにはRoute53 ResolverというVPCに標準で備わるDNSサーバー(フォワーダー + フルサービスリゾルバー)があります。
このRoute53 Resolverのクエリログから確認すると、Public IPが解決されていることがわかります。
よって、このトラフィックはインターネットを経由してサービスエンドポイントにアクセスしています。

クエリログ
{
        "@timestamp": "2024-03-30 14:03:49.000",
        "@message": {
            "version": "1.100000",
            "account_id": "365298517117",
            "region": "us-east-1",
            "vpc_id": "vpc-09efc2534d3f29483",
            "query_timestamp": "2024-03-30T14:03:49Z",
            "query_name": "zenn-privatelink.s3.us-east-1.amazonaws.com.",
            "query_type": "A",
            "query_class": "IN",
            "rcode": "NOERROR",
            "answers": [
                {
                    "Rdata": "s3-r-w.us-east-1.amazonaws.com.",
                    "Type": "CNAME",
                    "Class": "IN"
                },
                {
                    "Rdata": "54.231.132.226",
                    "Type": "A",
                    "Class": "IN"
                },
                {
                    "Rdata": "16.182.66.90",
                    "Type": "A",
                    "Class": "IN"
                },
                {
                    "Rdata": "52.217.202.218",
                    "Type": "A",
                    "Class": "IN"
                },
                {
                    "Rdata": "52.217.72.240",
                    "Type": "A",
                    "Class": "IN"
                },
                {
                    "Rdata": "16.182.98.42",
                    "Type": "A",
                    "Class": "IN"
                },
                {
                    "Rdata": "52.216.39.26",
                    "Type": "A",
                    "Class": "IN"
                },
                {
                    "Rdata": "54.231.200.178",
                    "Type": "A",
                    "Class": "IN"
                },
                {
                    "Rdata": "52.217.12.120",
                    "Type": "A",
                    "Class": "IN"
                }
            ],
            "srcaddr": "10.0.0.176",
            "srcport": "46472",
            "transport": "UDP",
            "srcids": {
                "instance": "i-08c0b194dec370347"
            }
}

ここまでで検証したトラフィックフローを整理したものが以下の通りです。

VPCエンドポイントありのトラフィック(インターフェース)

続いて、今回の主題であるPrivatelinkを利用する構成です。
AWSではVPCエンドポイントを経由してPrivateLinkを利用します。
VPCエンドポイントには大きく、インターフェース型とゲートウェイ型の2種類があります。

今回はインターフェース型を利用してみます。構成は以下の通りです。
Private Subnetにインターフェース型のVPCエンドポイントを作成して、同じ操作を行ってみます。

トラフィックフロー

まずは先ほど同様EC2インスタンスからs3 lsコマンドを発行してトラフィックフローを確認してみます。

[ec2-user@ip-10-0-0-176 ~]$aws s3 ls s3://zenn-privatelink --debug
(省略)
2024-03-30 14:15:42,349 - MainThread - botocore.regions - DEBUG - Endpoint provider result: https://zenn-privatelink.s3.us-east-1.amazonaws.com
(省略)

続いて先のFQDNがどのように名前解決されたか確認します。
今回はPrivate IPが返却されました。
こちらはVPCエンドポイントのIPアドレスと一致しています。

クエリログ
{
        "@timestamp": "2024-03-30 14:17:26.000",
        "@message": {
            "version": "1.100000",
            "account_id": "365298517117",
            "region": "us-east-1",
            "vpc_id": "vpc-09efc2534d3f29483",
            "query_timestamp": "2024-03-30T14:17:26Z",
            "query_name": "zenn-privatelink.s3.us-east-1.amazonaws.com.",
            "query_type": "A",
            "query_class": "IN",
            "rcode": "NOERROR",
            "answers": [
                {
                    "Rdata": "10.0.1.125",
                    "Type": "A",
                    "Class": "IN"
                }
            ],
            "srcaddr": "10.0.0.176",
            "srcport": "60954",
            "transport": "UDP",
            "srcids": {
                "instance": "i-08c0b194dec370347"
            }
        },
        "query_name": "zenn-privatelink.s3.us-east-1.amazonaws.com."
    }

なぜ、同じFQDNにもかかわらず解決されるIPが変わったのかというと、VPCエンドポイントの作成オプションの1つである、プライベートDNS名を有効化を行っていたからです。

このオプションを有効化することによって、内部的にPrivate Hosted ZoneがVPCエンドポイントのデプロイ先VPCに関連づく形でデプロイされます。
これによってRoute53 Resolverは外部のDNSサーバにフォワードせず、作成されたPrivate Hosted ZoneにフォワードすることでプライベートIPが返却されます。

もし、このオプションを有効化していなかった場合はAWS CLIの「--endpoint-url」オプションで、インターフェースエンドポイントを参照する必要があります。
https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-configure-endpoints.html

ここまでで確認したトラフィックフローを整理したものが以下の通りです。

インターフェース型エンドポイントの優位性

セキュアかつ高可用性ネットワークを通過させるというメリットの他にも他方式と比較して優位である点をご紹介します。

  1. リソースベースポリシーのCondition句に指定できる
    →S3であればバケットポリシーのCondition句でVPCEからの通信に限定することができます。
  2. エンドポイントポリシーによって、アクセスできるリソースを限定することができる
  3. VPC外(他VPCやオンプレミスなど)からもアクセスできる
  4. エンドポイント自体にSGを付加し、アクセス制御できる
    →3の優位性の裏返しで、VPCE自体を保護する必要があるため、SGが付与できるのではと筆者は考えています。

VPCエンドポイントありのトラフィック(ゲートウェイ)

今回の構成は以下の通りです。
VPCにゲートウェイ型のVPCエンドポイントを作成して、同じ操作を行ってみます。

トラフィックフロー

まずは先ほど同様EC2インスタンスからs3 lsコマンドを発行してトラフィックフローを確認してみます。
同じFQDNにアクセスに行っていることが確認できます。

sh-5.2$ aws s3 ls s3://zenn-privatelink --debug
(省略)
2024-03-31 11:33:38,293 - MainThread - botocore.regions - DEBUG - Endpoint provider result: https://zenn-privatelink.s3.us-east-1.amazonaws.com
(省略)

続いて先のFQDNがどのように名前解決されたか確認します。
今回は先ほどのインターフェース型はPrivate IPが返却されましたが、今回は最初のVPCエンドポイントなしの構成と同様にPublic IPが返却されました。

クエリログ
{
    "version": "1.100000",
    "account_id": "365298517117",
    "region": "us-east-1",
    "vpc_id": "vpc-01f6d66a0d5780fbc",
    "query_timestamp": "2024-03-31T11:36:55Z",
    "query_name": "zenn-privatelink.s3.us-east-1.amazonaws.com.",
    "query_type": "A",
    "query_class": "IN",
    "rcode": "NOERROR",
    "answers": [
        {
            "Rdata": "s3-r-w.us-east-1.amazonaws.com.",
            "Type": "CNAME",
            "Class": "IN"
        },
        {
            "Rdata": "54.231.231.34",
            "Type": "A",
            "Class": "IN"
        },
        {
            "Rdata": "52.217.195.58",
            "Type": "A",
            "Class": "IN"
        },
        {
            "Rdata": "54.231.133.146",
            "Type": "A",
            "Class": "IN"
        },
        {
            "Rdata": "52.216.209.114",
            "Type": "A",
            "Class": "IN"
        },
        {
            "Rdata": "52.217.198.2",
            "Type": "A",
            "Class": "IN"
        },
        {
            "Rdata": "54.231.133.210",
            "Type": "A",
            "Class": "IN"
        },
        {
            "Rdata": "16.182.103.18",
            "Type": "A",
            "Class": "IN"
        },
        {
            "Rdata": "52.216.221.186",
            "Type": "A",
            "Class": "IN"
        }
    ],
    "srcaddr": "10.0.0.183",
    "srcport": "43012",
    "transport": "UDP",
    "srcids": {
        "instance": "i-0c9198d51db287554"
    }
}

流れが違うので少し驚かれたかもしれませんが、ゲートウェイ型のVPCエンドポイントへの誘導はDNSではなく、ルートテーブルで行っています
ルートテーブルによって誘導する流れについて説明します。

まず、ゲートウェイ型エンドポイント作成時に以下のようにルートテーブルを選択します。

指定したルートテーブルには以下のようなプレフィックスリストを対象とするレコードが挿入されます。

プレフィックスリストの中身を確認すると、先ほど名前解決されたIPが含まれる範囲であることが確認できます。

このルートによってトラフィックをVPCエンドポイントに誘導します。

ここまでで検証したトラフィックフローを整理したものが以下の通りです。

ゲートウェイ型エンドポイントの優位性

  1. リソースベースポリシーのCondition句に指定できる
    →S3であればバケットポリシーのCondition句でVPCEからの通信に限定することができます。
  2. エンドポイントポリシーによって、アクセスできるリソースを限定することができる
  3. 無料

AzureのPrivateLink

Azureにもプライベート通信を実現する、PrivateLinkサービスがあります。
https://learn.microsoft.com/ja-jp/azure/private-link/private-link-overview

プライベートエンドポイントなしのトラフィック

今回は以下のような構成において、Azure VMインスタンスからAzure CLIを利用することで、AzureのREST APIエンドポイント[2]をたたいてみます。

トラフィックフロー

Azure VMインスタンスからaz storage blob listコマンドを発行してトラフィックフローを確認してみます。
環境変数にターゲットのアカウント名であったり、アクセスキーは格納済みです。

--debugオプションをつけることでどこにリクエストを送っているのか確認してみると「zenn-privatelink.s3.us-east-1.amazonaws.com」にリクエストを送っていることがわかります。

azureuser@zenn-test-privatelink:~$ az storage blob list -c test --debug
(省略)
urllib3.connectionpool : https://zennprivatelink.blob.core.windows.net:443 "GET /test?restype=container&comp=list&maxresults=5000
(省略)

続いて先のFQDNがどのように名前解決されたか確認します。
今回は簡易的にdigコマンドで確認してみました。
Public IPが解決されていることが確認できます。

dig
azureuser@zenn-test-privatelink:~$ dig zennprivatelink.blob.core.windows.net

; <<>> DiG 9.16.48-Ubuntu <<>> zennprivatelink.blob.core.windows.net
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 20895
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;zennprivatelink.blob.core.windows.net. IN A

;; ANSWER SECTION:
zennprivatelink.blob.core.windows.net. 60 IN CNAME blob.blz22prdstr28a.store.core.windows.net.
blob.blz22prdstr28a.store.core.windows.net. 263 IN A 20.60.0.100

;; Query time: 4 msec
;; SERVER: 127.0.0.53#53(127.0.0.53)
;; WHEN: Sun Mar 31 08:48:30 UTC 2024
;; MSG SIZE  rcvd: 122

プライベートエンドポイントなしの状態では、インターネットを経由してAzure REST APIにアクセスしています。

プライベートエンドポイントありのトラフィック

今回の構成は以下の通りです。
Private Subnetにプライベートエンドポイントを作成して、同じ操作を行ってみます。

トラフィックフロー

まずは先ほど同様Azure VMインスタンスからs3 lsコマンドを発行してトラフィックフローを確認してみます。

[ec2-user@ip-10-0-0-176 ~]$aws s3 ls s3://zenn-privatelink --debug
(省略)
2024-03-30 14:15:42,349 - MainThread - botocore.regions - DEBUG - Endpoint provider result: https://zenn-privatelink.s3.us-east-1.amazonaws.com
(省略)

続いて先のFQDNがどのように名前解決されたか確認します。
今回はPrivate IPが返却されました。
こちらはプライベートエンドポイントのIPアドレスと一致しています。

クエリログ
azureuser@zenn-test-privatelink:~$ dig zennprivatelink.blob.core.windows.net

; <<>> DiG 9.16.48-Ubuntu <<>> zennprivatelink.blob.core.windows.net
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 8534
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;zennprivatelink.blob.core.windows.net. IN A

;; ANSWER SECTION:
zennprivatelink.blob.core.windows.net. 35 IN CNAME zennprivatelink.privatelink.blob.core.windows.net.
zennprivatelink.privatelink.blob.core.windows.net. 10 IN A 10.0.4.4

;; Query time: 8 msec
;; SERVER: 127.0.0.53#53(127.0.0.53)
;; WHEN: Sun Mar 31 09:09:59 UTC 2024
;; MSG SIZE  rcvd: 124

AzureもAWS同様エンドポイント作成時にプライベートDNSゾーンを作成します。

この設定によってレコードが挿入され、解決されるIPアドレスがプライベートエンドポイントのIPアドレスになっています。

触って気づいたAWSとAzureの違い

AWSのVPCエンドポイント(インターフェース型)と、Azureのプライベートエンドポイントで違いがないようにみえますが、ここにDNSのレコードに大きな違いがありました。
AzureはFQDN形式でレコードが挿入されているのに対して、
AWSはサービスのドメインに対してホスト名が*のワイルドカードで指定されています。


Azure



AWS


また、Azureはプライベートエンドポイントを作成する際に、サービスだけでなくリソース名まで指定しています。

Azureはまだ経験が浅く、ほかのサービスのプライベートエンドポイントは仕様が異なったりするかもしれませんが、このあたりの差分は頭に入れて見積もりや設計を進めていきたいと思いました。

脚注
  1. https://docs.aws.amazon.com/ja_jp/general/latest/gr/rande.html ↩︎

  2. https://learn.microsoft.com/ja-jp/rest/api/azure/ ↩︎

Discussion