「Amazon S3 インターフェースエンドポイント(PrivateLink)ではプライベート DNS をサポートしていません」 の意味を絵をかいて腹落ちさせてみた

インターフェースエンドポイント博士になろう

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

2023/3/15追記

「サポートしていません」の時代に本エントリを書いたのですが、アップデートによりサポートされるようになりました。その内容を以下エントリに書きました。

以降の記述は当時の内容としてお楽しみください。上記のエントリとあわせて読むとより理解が捗ると思います。


コンバンハ、千葉(幸)です。

先日、Amazon S3 向けの PrivateLink(インターフェースエンドポイント)がサポートされました。

これによりオンプレミスから S3 へのプライベートアクセスが、簡単に構成できるようになりました。

注意点として、S3 インターフェースエンドポイントではプライベート DNS 名が使用できないというものがあります。

AWS ドキュメントでも以下の通りしっかり記述があります。

Interface_VPC_endpoints__AWS_PrivateLink__-_Amazon_Virtual_Private_Cloud

この記述を見た時に私は「あー(なるほど)ね、はいはいはい」と軽く流していました。何となく分かった気でいたのです。

しかし、しばらくして心の中のリトル千葉が「つまりどういうことですか?一言で説明してください」と問いかけてきた時に、すぐ答えることができませんでした。(彼らは得てして忘れた頃にやって来る)

このままでは私の沽券に関わりますので、きちんと整理してみることにします。

ざっくり目次

本エントリは大まかに以下の構成となっています。書いている内に膨らんでそこそこのボリュームになりました。ちょっと長めなので、その旨ご承知おきください。

  • 先にまとめ(すでにちょっと長い)
  • PrivateLink とは
  • プライベート DNS 名とは
  • エンドポイント固有の DNS 名とは
  • S3 の PrivateLink
  • 自前でプライベートホストゾーン作ってみる

先にまとめ

まずは一般的なインターフェースエンドポイントについての説明です。以下図では東京リージョンの KMS 向けのエンドポイントを例に取ります。

privatelink_image

  • インターフェースエンドポイントのプライベートDNS 名を有効にすると、対応するサービスエンドポイント名のプライベートホストゾーンが VPC に関連づけられる
    • プライベートホストゾーンではインターフェースエンドポイントのプライベート IP を指し示すレコードセットが登録されている
    • VPC 内の Amazon Provided DNS( Route53 リゾルバ)は関連づけられたプライベートホストゾーン内のレコードセットを名前解決できる
      • VPC 内の DNS サポートに関するパラメータが有効である必要あり
    • 上記を利用することで向き先のサービスエンドポイントの DNS 名を変更することなく、PrivateLink 経由のアクセスが可能となる
  • インターフェースエンドポイントを作成するとエンドポイント固有の DNS 名が払い出される
    • エンドポイント固有の DNS 名には以下の種類がある
      • リージョナル DNS 名
      • ゾーナル DNS 名
    • エンドポイント固有の DNS 名はパブリックに名前解決できる
    • VPC 外のリゾルバから名前解決してもプライベート IP アドレスが返却される
    • 明示的にエンドポイント固有の DNS 名を指定して通信を行うこともできる

続いて Amazon S3 向けのインターフェースエンドポイントについてです。

s3_privatelink

  • S3 向けにはゲートウェイタイプのエンドポイントも存在する
    • VPC 内のリソースがあえて PrivateLink を経由するメリットは無い
  • プライベート DNS 名は使用できない
  • PrivateLink を使用する場合、エンドポイント固有の DNS 名を明示的に指定する必要がある

つまりどういうことですか?一言で説明してください

「 S3 PrivateLink ではエンドポイント固有の DNS 名を指定する必要があります。」

冒頭でほとんど言いたいことを言い切ってしまったのですが、順次補足をしていきます。

まずは基本的なところをおさらいしておきましょう。PrivateLink は、インターフェース型の VPC エンドポイントとセットで用いられるものです。

VPC 内、特にプライベートサブネット上のリソースが AWS サービスにリクエストを実行する際に、その経路を提供してくれます。

AWS のサービスエンドポイント

通常、AWS の API を実行する場合はそのサービスエンドポイントにリクエストが到達(多くは HTTPS のみ)する必要があります。

冒頭と同様に東京リージョンの KMS を例に取ると、そのサービスエンドポイントは以下の通りです。

kms.ap-northeast-1.amazonaws.com

例えば AWS CLI で aws kms コマンドを実行する際も、裏側では`https://kms.ap-northeast-1.amazonaws.com`へのリクエストを実行しています。`--debug`オプションを付与することで確認できます。

% aws kms list-aliases --debug
---略---
POST
/

content-type:application/x-amz-json-1.1
host:kms.ap-northeast-1.amazonaws.com
x-amz-date:20210315T153535Z
x-amz-target:TrentService.ListAliases

content-type;host;x-amz-date;x-amz-target
xxxx6fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a
2021-03-16 00:35:35,077 - MainThread - botocore.auth - DEBUG - StringToSign:
AWS4-HMAC-SHA256
20210315T153535Z
20210315/ap-northeast-1/kms/aws4_request
xxxx75691a8b1426c6ee4faa0b10cdfde521328e8e48e1979195b9a879df56b8
2021-03-16 00:35:35,077 - MainThread - botocore.auth - DEBUG - Signature:
xxxx910e801811c8d1cc6e00d932e37e0b8103a2484e74e19fa7d569753398ee
2021-03-16 00:35:35,077 - MainThread - botocore.endpoint - DEBUG - Sending http request: <AWSPreparedRequest stream_output=False, method=POST, url=https://kms.ap-northeast-1.amazonaws.com/, headers={'X-Amz-Target': b'TrentService.ListAliases', 'Content-Type': b'application/x-amz-json-1.1', 'User-Agent': b'aws-cli/2.1.30 Python/3.8.8 Darwin/19.6.0 exe/x86_64 prompt/off command/kms.list-aliases', 'X-Amz-Date': b'20210315T153535Z', 'Authorization': b'AWS4-HMAC-SHA256 Credential=AKIAxxxxIH733IWA5GNW/20210315/ap-northeast-1/kms/aws4_request, SignedHeaders=content-type;host;x-amz-date;x-amz-target, Signature=xxxx910e801811c8d1cc6e00d932e37e0b8103a2484e74e19fa7d569753398ee', 'Content-Length': '2'}>
2021-03-16 00:35:35,078 - MainThread - botocore.httpsession - DEBUG - Certificate path: /usr/local/aws-cli/botocore/cacert.pem
2021-03-16 00:35:35,078 - MainThread - urllib3.connectionpool - DEBUG - Starting new HTTPS connection (1): kms.ap-northeast-1.amazonaws.com:443
2021-03-16 00:35:35,255 - MainThread - urllib3.connectionpool - DEBUG - https://kms.ap-northeast-1.amazonaws.com:443 "POST / HTTP/1.1" 200 4729
---略---

KMS のサービスエンドポイントが取りうる IP レンジについての情報は見つけられませんでしたが、例えば手元の端末で名前解決を行うと以下のようなグローバル IP アドレスが引けます。

% dig +short kms.ap-northeast-1.amazonaws.com
52.119.223.105

第一オクテットが 54 や 27 のアドレスが返ってくることもありました。

プライベートサブネットからサービスエンドポイントへの到達

AWS サービスのエンドポイントに到達するためには、グローバル IP アドレスでの通信が必要なことが分かりました。では、プライベートサブネット内のインスタンスが通信を行いたい場合はどうすればいいでしょうか。

一つは NAT ゲートウェイを使用するパターンが思いつきます。AWS サービスエンドポイント以外にもインターネット上のリソースに対して通信要件を持つ場合には、すべてまとめて NAT ゲートウェイによって実現する、というのもよくとる構成です。

他には、NAT インスタンスやプロキシサーバを用いるパターンもあります。

ここまで見てきたのはいずれも宛先をグローバル IP アドレスとするパターンです。インターフェースエンドポイントを使用することで宛先をプライベート IP アドレスとすることができます。

”不思議経路” PrivateLink

インターフェースエンドポイントを VPC 内に作成すると、そのインターフェースのプライベート IP アドレスが払い出されます。作成時には配置するサブネットを指定することになりますので、そのサブネットの IP レンジの中から自動的に採番されます。

クライアントはインターネット上の AWS サービスエンドポイントではなく、VPC 上のインターフェースエンドポイントに対してリクエストを実行することができるようになります。

インターフェースエンドポイントに到達したリクエストは裏側でいい感じにサービスのエンドポイントに到達します。 ここで言う「サービスのエンドポイント」が、ここまで見てきたようなインターネット上の物と同一かは分かりません。

AWS ドキュメントでは以下の表現がなされています。

VPC エンドポイントは、VPC およびサポートされている AWS のサービスと、AWS PrivateLink を利用した VPC エンドポイントサービスとの間のプライベート接続を可能にします。AWS PrivateLink は、プライベート IP アドレスを使用して、サービスにプライベートにアクセスすることを可能にするテクノロジーです。VPC と他のサービス間のトラフィックは、Amazon ネットワークを離れません。VPC エンドポイントは、インターネットゲートウェイ、仮想プライベートゲートウェイ、NAT デバイス、VPN 接続、または AWS Direct Connect 接続を必要としません。VPC のインスタンスは、サービスのリソースと通信するためにパブリック IP アドレスを必要としません。

privatelink_fushigi

インターフェースエンドポイントには他の ENI 同様 SecuriryGroup を関連づけることができますが、そのアウトバウンドは考慮する必要がありません。アウトバウンド通信を許可していなくても、「いい感じ」の通信を実現してくれます。

具体的な仕組みは公開されていないので、「ははーん 要するに”不思議経路”なんだな?」と思っておけばよいでしょう。

インターフェースエンドポイントのプライベート DNS 名とは

インターフェースエンドポイント宛にプライベート IP アドレスで通信を行えることは分かりましたが、その IP アドレスはどのように名前解決すればよいでしょうか。一般的な手段はプライベート DNS 名を使用することです。

インターフェースエンドポイントの作成時に、プライベート DNS 名を有効にするかどうかの指定ができます。

privatednsname

注釈に書かれているメッセージは以下の通りです。

Associates a private hosted zone with the VPC that contains a record set that enables you to leverage Amazon’s private network connectivity to the service while making requests to the service’s default public endpoint DNS name. To use this feature, ensure that the attributes ‘Enable DNS hostnames’ and ‘Enable DNS support’ are enabled for your VPC.

ざっくり、以下の内容が説明されています。

  • 機能を有効化するとプライベートホストゾーンを VPC に関連づけます
  • ホストゾーンには以下を可能にするレコードセットが含まれています
    • 「デフォルトのパブリックなサービスエンドポイント DNS 名を指定したリクエスト」がサービスへのプライベートネットワーク接続を行うこと
  • この機能を使うためには VPC で以下が有効になっている必要があります
    • Enable DNS hostnames
    • Enable DNS support

再び東京リージョンの KMS を例に取ると、デフォルトのパブリックなサービスエンドポイントの DNS 名はkms.ap-northeast-1.amazonaws.comです。通常これを名前解決するとグローバル IP が返却されます。

kms.ap-northeast-1.amazonaws.comへの DNS クエリに対して「インターフェースエンドポイントのプライベート IP 」を返却してくれるプライベートホストゾーンが作成されることで、向き先を変えることなくプライベート接続が可能となります。

インターフェースエンドポイントを使用する場合、多くはこの機能を利用することでしょう。

プライベートホストゾーンを確認してみよう

VPC に関連づいたプライベートホストゾーンはaws route53 list-hosted-zones-by-vpcで確認できます。

2020年6月のアップデートで対応した機能です。

実際に確認してみると、以下の結果が得られました。

% aws route53 list-hosted-zones-by-vpc \
  --vpc-id vpc-0e4acafc38414468c \
  --vpc-region ap-northeast-1
{
    "HostedZoneSummaries": [
        {
            "HostedZoneId": "Z05071057SB0KFR1B498",
            "Name": "efs.ap-northeast-1.amazonaws.com.",
            "Owner": {
                "OwningService": "efs.amazonaws.com"
            }
        },
        {
            "HostedZoneId": "Z01981912L44VGQF8N6PG",
            "Name": "kms.ap-northeast-1.amazonaws.com.",
            "Owner": {
                "OwningService": "vpce.amazonaws.com"
            }
        }
    ],
    "MaxItems": "100"
}

エンドポイント名に対応したプライベートホストゾーンが作成されていることが分かりますね。

(ちなみに efs のホストゾーンが何故関連づけられているのかは分かりません。このエントリにおいては完全に不要な情報なのですが、びっくりしたのでそのまま載せてみました。どういう場合に関連づけられるのか知っている方がいたら教えてください。)

このホストゾーンの所有者は自分ではないので、詳細は確認できませんでした。

% aws route53 get-hosted-zone --id Z01981912L44VGQF8N6PG

An error occurred (AccessDenied) when calling the GetHostedZone operation: User: arn:aws:iam::012345678910:user/chiba-cli is not authorized to access this resource

プライベートホストゾーンを使用して名前解決してみよう

上記の VPC 内の EC2 インスタンスからkms.ap-northeast-1.amazonaws.comの名前解決を試みると、インターフェースエンドポイントが持つプライベート IP アドレスが返却されました。

sh-4.2$ nslookup kms.ap-northeast-1.amazonaws.com
Server:         192.168.0.2
Address:        192.168.0.2#53

Non-authoritative answer:
Name:   kms.ap-northeast-1.amazonaws.com
Address: 192.168.3.179
Name:   kms.ap-northeast-1.amazonaws.com
Address: 192.168.1.57

これで、 VPC 上の EC2 がaws kmsコマンドなどを実行する際には、宛先の DNS 名を考慮することなく(デフォルトから変更することなく)PrivateLink 経由での通信が実現できます。

インターフェースエンドポイントのエンドポイント固有の DNS 名とは

一般的にはここまで見てきたようなプライベート DNS 名を使用するのですが、もう一つのパターンもあります。エンドポイント固有の DNS 名です。

先ほど例にとった KMS のエンドポイントは、2つの AZ (a,c)にまたがるように作成していました。その場合、以下のように関連する DNS 名が確認できます。

endpointdnsname

書き起こしてみると以下となります。上から3つがエンドポイント固有の DNS 名です。

  • vpce-079f1da40dc9fbd0d-v3ywxne0.kms.ap-northeast-1.vpce.amazonaws.com (Z2E726K9Y6RL4W)
  • vpce-079f1da40dc9fbd0d-v3ywxne0-ap-northeast-1a.kms.ap-northeast-1.vpce.amazonaws.com (Z2E726K9Y6RL4W)
  • vpce-079f1da40dc9fbd0d-v3ywxne0-ap-northeast-1c.kms.ap-northeast-1.vpce.amazonaws.com (Z2E726K9Y6RL4W)
  • kms.ap-northeast-1.amazonaws.com (Z01981912L44VGQF8N6PG)

末尾に表示されているのはホストゾーン ID です。プライベート DNS 名の後に表示されているZ01981912L44VGQF8N6PGは先ほど確認したものと一致しています。

Z2E726K9Y6RL4Wは、パブリックなホストゾーンap-northeast-1.vpce.amazonaws.comのものかと思います。東京リージョンでインターフェースエンドポイントを作成された方は、同じホストゾーン ID が確認できるのではないでしょうか。

エンドポイント固有の DNS 名を名前解決してみよう

ここまで「リージョナル」「ゾーナル」という言葉を当たり前のように使ってきましたが、その意味は以下の結果を確認すると分かりやすいかと思います。

手元の端末で名前解決を試みます。

リージョナル DNS 名の場合。

% dig vpce-079f1da40dc9fbd0d-v3ywxne0.kms.ap-northeast-1.vpce.amazonaws.com +short
192.168.3.179
192.168.1.57

ゾーナル DNS 名(a)の場合。

% dig vpce-079f1da40dc9fbd0d-v3ywxne0-ap-northeast-1a.kms.ap-northeast-1.vpce.amazonaws.com +short
192.168.1.57

ゾーナルDNS 名(c)の場合。

% dig vpce-079f1da40dc9fbd0d-v3ywxne0-ap-northeast-1c.kms.ap-northeast-1.vpce.amazonaws.com +short
192.168.3.179

リージョナルの場合は両方のインターフェースエンドポイントのプライベート IP アドレスが、ゾーナルの場合には対応する AZ のプライベート IP アドレスのみが返却されます。

ゾーナル DNS 名を使用するケースとして、AWS ドキュメントでは「障害の封じ込め」や「AZ間の転送料金の削減」が挙げられています。

これらの DNS 名はパブリックに名前解決可能でありながら、プライベート IP アドレスを返却してくれます。インターナル ELB や RDS のDNS 名と同じですね。

エンドポイント固有の DNS 名ってどう使うの?

AWS CLI では以下のようにオプションを付与することで指定できます。

`--endpoint-url https://vpce-079f1da40dc9fbd0d-v3ywxne0.kms.ap-northeast-1.vpce.amazonaws.com`

インターフェイスVPCエンドポイント(AWS PrivateLink)-Amazon Virtual Private Cloud

プライベート DNS 名を使用するより一手間加わりますが、ゾーナル DNS 名を使用したい場合にはこういった指定の仕方が必須となります。

一般的な PrivateLink (インターフェースエンドポイント)について確認してきました。ここからようやく本題の Amazon S3 PrivateLink について確認します。

再三言及しましたが、Amazon S3 向けの PrivateLink ではプライベート DNS 名は使用できません

つまりはエンドポイント固有の DNS 名を使用する必要がある、というのはここまで読まれた皆さんならすっと理解できたかと思います。

では、何故 S3 だけそのような特別仕様なのでしょうか。

S3 向けの VPC エンドポイントにはゲートウェイ型もある

答えの一つとして考えているのはゲートウェイ型の VPC エンドポイントの存在です。ゲートウェイ型のエンドポイントを引き続き使用できるよう、プライベート DNS 名に対応していないのではと想像しています。

(現状では S3 が唯一ゲートウェイ型とインターフェース型 両方のエンドポイントを持つサービスです。)

s3_privatelink_gateway

ゲートウェイ型のエンドポイントを使用できるのはエンドポイントがアタッチされた VPC 内のリソースのみです。VPC 外からエンドポイント経由でアクセスしたい場合、プロキシサーバを立てたりといったひと工夫が必要です。

過去には以下のような複雑な構成をとった例もあります。

ちなみにゲートウェイ型を使用する場合、インターフェース型と違いルートテーブルにエントリを追加する必要があります。プレフィックスリストと呼ばれる特定のサービスの IP レンジを示す ID を宛先に指定し、ターゲットにエンドポイントを指定します。

東京リージョンの S3 のプレフィックスリストは以下で確認できます。

% aws ec2 describe-prefix-lists --region ap-northeast-1\
  --query "PrefixLists[?PrefixListName==\`com.amazonaws.ap-northeast-1.s3\`]"
[
    {
        "Cidrs": [
            "3.5.152.0/21",
            "52.219.0.0/20",
            "52.219.152.0/22",
            "52.219.136.0/22",
            "52.219.16.0/22",
            "52.219.68.0/22"
        ],
        "PrefixListId": "pl-61a54008",
        "PrefixListName": "com.amazonaws.ap-northeast-1.s3"
    }
]

サービスエンドポイントs3.ap-northeast-1. amazonaws.comを名前解決すると上記の IP レンジの中のいずれかのグローバル IP アドレスが返却されます。

少し脇道に逸れて

インターフェース型のエンドポイントの場合、なぜゲートウェイ型で行ったような「ルートテーブルエントリの追加」が不要なのか分かりますか?

はい。

そうですね。

PrivateLink を経由する場合クライアントから見た宛先 IP アドレスはインターフェースエンドポイントのプライベート IP アドレスであり、そこに向けたルートはデフォルトのlocalをターゲットとするエントリに内包されているからですね。

VPC 内から S3 宛の通信に PrivateLink を使用するメリットはあるのか?

「ゲートウェイ型のエンドポイントを引き続き使用できるよう」と上で述べましたが、それはつまりゲートウェイ型の方がメリットがあると考えているということです。

(インターフェース型の方がメリットがあるのであれば、すべてそちらに寄せてプライベート DNS 名が使えるという選択肢があってもいいだろう、ということです。)

先述の通りゲートウェイ型を使用できるのは VPC 内のリソースとなりますので、ここでは「 VPC 内から S3 宛の通信」のケースにおいて両者を比較します。

大きくは、利用料帯域幅が評価の観点と考えています。

s3_privatelink_merit


2022/4のアップデートにより、「AZ を跨いだ通信量にかかる料金」がなくなりました。


利用料

インターフェース型の場合、以下を考慮する必要があります。

  • エンドポイントごとにかかる時間料金
  • エンドポイントの処理データ量にかかる料金
  • AZ を跨いだ通信量にかかる料金

例えばマルチ AZ でインターフェースエンドポイントを使用する場合、設置するだけで月におよそ 20 ドルかかります。それに加えてデータ量、通信量に応じた料金がかかりますので、扱うデータ量が多ければコストが嵩むことになります。

ゲートウェイ型では、上記の料金のいずれも発生しません。

帯域幅

インターフェース型については以下の記述があります。

各インターフェイスエンドポイントは、アベイラビリティーゾーンあたり最大 10 Gbps の帯域幅をサポートでき、最大 40 Gbps までバーストできます。

ゲートウェイ型では帯域について言及された記述は見つけられませんでした。

同じ種類の物理デバイスによって実現されるインターネットゲートウェイでは「帯域幅制限なし」とされています。ゲートウェイ型でも同じ考え方では、と想像しています。

インターネットゲートウェイは水平にスケーリングされるため、冗長性と高可用性を達成できます。帯域幅制限はありません。

少なくとも、「ゲートウェイ型のみでは帯域が不足するためインターフェース型を使用する」というケースは無い、と考えています。

その他

「インターフェース型でのみできること」として SecuriryGroup による制御が思いつきます。

同一サブネットに複数の EC2 インスタンスがあり、その中の特定のインスタンスのみ S3 への疎通を許可したい、という場合にインターフェースエンドポイントの SecuriryGroup のインバウンドで制御するということができます。

とは言え、そのような要件のためだけにわざわざインターフェース型を採用するのは考えづらいです。 インスタンス側の SecuriryGroup のアウトバウンドや IAM での制御を行う方がシンプルに済むでしょう。

S3 インターフェースエンドポイントはオンプレミスからのプライベート接続のため

ここまで見てきたことを総合すると、 VPC 内からインターフェースエンドポイントを経由するメリットは無い、と考えています。

S3 PrivateLink はあくまで VPC 外、特にオンプレミスからのプライベート接続を主たるユースケースとして想定したものでしょう。 GA 発表時の AWS ブログでもそれが読み取れます。

AWS PrivateLink for Amazon S3 is Now Generally Available | AWS News Blog

オンプレからの接続イメージは以下の通りです。

s3_privatelink_gateway_onprem

おさらいとなりますが、 Amazon Provided DNS は VPC 外部から直接は参照できません。フォワーダを立てたり、 Resolver インバウンドエンドポイントを使用するといったひと工夫が必要になります。

諸々鑑みて、以下理由から S3 PrivateLink ではエンドポイント固有の DNS 名の使用が必要になっていると想像しています。

  • VPC 内のリソースには引き続きゲートウェイ型エンドポイントを使用させたい
  • VPC 外のリソースがエンドポイントのプライベート IP アドレスを名前解決できる必要がある

仮想ホスト形式とパス形式

少し話がそれますが、エンドポイント固有の DNS 名に関連する話として S3 アクセスの URL 形式があります。

以下2種類があります。

  • 仮想ホスト形式
  • パス形式

東京リージョンの S3 バケットcm-chiba-hogehogeにアクセスする場合を考えると、それぞれ以下の URL となります。

  • `https://cm-chiba-hogehoge.s3.ap-northeast-1.amazonaws.com`
  • `https://s3.ap-northeast-1.amazonaws.com/cm-chiba-hogehoge`

後者のパス形式の方が古い形式となります。

2020年10月以降に作成されたバケットに対してはパス形式でのリクエストが廃止される、というアナウンスがありましたが、現在では廃止は延期されています。(具体的な時期は言及なし)

詳細は以下を参照してください。

上記の仕様と関係あるのか、S3 インターフェースエンドポイントの固有の DNS 名では先頭にワイルドカードが付与されています。

  • *.vpce-0562f2c59ac7b66e6-4j54175z.s3.ap-northeast-1.vpce.amazonaws.com (Z2E726K9Y6RL4W)
  • *.vpce-0562f2c59ac7b66e6-4j54175z-ap-northeast-1a.s3.ap-northeast-1.vpce.amazonaws.com (Z2E726K9Y6RL4W)
  • *.vpce-0562f2c59ac7b66e6-4j54175z-ap-northeast-1c.s3.ap-northeast-1.vpce.amazonaws.com (Z2E726K9Y6RL4W)

ここに任意の値を入れて名前解決しても、同じプライベート IP アドレスが返却されます。

おまけ

思いついてしまったやつを書きます。

プライベート DNS 名がダメなら自分でプライベートホストゾーンを作ればいいじゃない

S3 PrivateLink でプライベート DNS 名が使用できないことは分かりました。とは言え、プライベート DNS 名がやってくれる事といえば「 AWS が管理するプライベートホストゾーンを VPC に関連づけていい感じのレコードを登録してくれる 」、それだけです。

だったら自前でs3.ap-northeast-1. amazonaws.comというホストゾーンを作ってしまえばいいじゃない、と私は思いました。

そうする事で得られるメリットは、例えば、まぁ、はい、あまり思いつきませんが、思いついたからには試さずにはいられません。

プライベートホストゾーンのレコードを名前解決できるのは Amazon Provided DNS のみのため、VPC 外部からアクセスする場合はひと工夫が必要、というのは先述の通りです。

s3_privatehostzones_iijanai

プライベートホストゾーンを作成する

さっくりと作りました。

ホストゾーン名はs3.ap-northeast-1. amazonaws.comで、 S3 インターフェースエンドポイントのプライベート IP を指定した A レコードセットを作成しました。

Route_53_Console_Hosted_Zones

VPC に関連づけて、以下のように確認できました。

% aws route53 list-hosted-zones-by-vpc \
  --vpc-id vpc-0e4acafc38414468c \
  --vpc-region ap-northeast-1
{
    "HostedZoneSummaries": [
        {
            "HostedZoneId": "Z05071057SB0KFR1B498",
            "Name": "efs.ap-northeast-1.amazonaws.com.",
            "Owner": {
                "OwningService": "efs.amazonaws.com"
            }
        },
        {
            "HostedZoneId": "Z04222883VDDIZ8V6WEXU",
            "Name": "s3.ap-northeast-1.amazonaws.com.",
            "Owner": {
                "OwningAccount": "012345678910"
            }
        }
    ],
    "MaxItems": "100"
}

S3 へアクセスしてみる

今回は以下の構成で試します。

s3_privatehostzones_yattemita

インターフェースエンドポイントと同一 VPC のパブリックサブネットにある EC2 インスタンスから S3 へのアクセスを行います。

通常はインターネットゲートウェイ経由で S3 にアクセス可能ですが、今回はプライベートホストゾーンが設定済みのため、PrivateLink を経由することになります。

インターフェースエンドポイントにアタッチした SecuriryGroup をコントロールし、挙動の変化を確認します。

名前解決

インスタンスから S3 エンドポイントの名前解決を試みると、先ほど自分で設定した通りの IP アドレスが返却されます。

sh-4.2$ nslookup s3.ap-northeast-1.amazonaws.com
Server:         192.168.0.2
Address:        192.168.0.2#53

Non-authoritative answer:
Name:   s3.ap-northeast-1.amazonaws.com
Address: 192.168.1.66
Name:   s3.ap-northeast-1.amazonaws.com
Address: 192.168.3.63

通常アクセス

まずはインターフェースエンドポイントの SecuriryGroup を制限していない状態でaws s3 ls --region ap-northeast-1を行います。(今回のケースでは--regionを指定しないとリージョンに依存しないs3.amazonaws.comにアクセスを試みてしまいます。)

sh-4.2$ aws s3 ls --region ap-northeast-1
2021-01-26 11:32:26 xxxxxx-chiba
2020-08-19 05:19:01 aws-athena-query-results-012345678910-ap-northeast-1
2020-03-09 05:41:29 cf-templates-xxxxxxxx-ap-northeast-1
---以下略---

通常通り結果が得られました。とは言え「本当に PrivateLink 経由してる?」と言うのが分かりづらいですね。

SecuriryGroup でブロック

インターフェースエンドポイントの SecuriryGroup でクライアント EC2 からのインバウンドを除外して再試行します。

デフォルトだとタイムアウトの秒数が長くて待つのがしんどいので、短めにして試します。(それでも5回リトライするので多少待ちます。)

sh-4.2$ aws s3 ls --region ap-northeast-1 --cli-connect-timeout 5 
Connect timeout on endpoint URL: "https://s3.ap-northeast-1.amazonaws.com/"

エンドポイントへ接続できずにタイムアウトしました。パブリックサブネットにあるインスタンスでも、インターフェースエンドポイントに接続を試みたことが分かります。

仮想ホスト形式になるとそのままではうまくいかなかった

上記のaws s3 lsコマンドでは、アクセスする先はs3.ap-northeast-1.amazonaws.comです。

それであれば特に動作は問題なかったのですが、例えば以下のコマンドでは失敗しました。

sh-4.2$ aws s3 cp test.txt s3://cm-chiba-hogehoge
upload failed: ./test.txt to s3://cm-chiba-hogehoge/test.txt Could not connect to the endpoint URL: "https://cm-chiba-hogehoge.s3.ap-northeast-1.amazonaws.com/test.txt"

上記のコマンドを実行する時点ではクライアントとインターフェースエンドポイント間の SecuriryGroup は開放しています。

通信を試みているのが`https://cm-chiba-hogehoge.s3.ap-northeast-1.amazonaws.com/`であり、当該 DNS 名を名前解決できない、という状況です。

sh-4.2$ nslookup cm-chiba-hogehoge.s3.ap-northeast-1.amazonaws.com/
Server:         192.168.0.2
Address:        192.168.0.2#53

** server can't find cm-chiba-hogehoge.s3.ap-northeast-1.amazonaws.com/: NXDOMAIN

戯れに--region ap-northeast-1を付与しても同様です。

sh-4.2$ aws s3 cp test.txt s3://cm-chiba-hogehoge --region ap-northeast-1
upload failed: ./test.txt to s3://cm-chiba-hogehoge/test.txt Could not connect to the endpoint URL: "https://cm-chiba-hogehoge.s3.ap-northeast-1.amazonaws.com/test.txt"

それでも何とかしたい

ホストゾーンに以下のレコードセットを追加しました。

ワイルドカードを使用した CNAME レコードセットを作成し、値として先ほどの A レコードセットを設定しました。

これでどんなバケット名の仮想ホスト形式でも、インターフェースエンドポイントのプライベート IP アドレスを名前解決できます。

sh-4.2$ nslookup cm-chiba-hogehoge.s3.ap-northeast-1.amazonaws.com
Server:         192.168.0.2
Address:        192.168.0.2#53

Non-authoritative answer:
cm-chiba-hogehoge.s3.ap-northeast-1.amazonaws.com       canonical name = s3.ap-northeast-1.amazonaws.com.
Name:   s3.ap-northeast-1.amazonaws.com
Address: 192.168.3.63
Name:   s3.ap-northeast-1.amazonaws.com
Address: 192.168.1.66

この下ごしらえをした状態であれば、問題なくaws s3 cpコマンドを実行できました。

sh-4.2$ aws s3 cp test.txt s3://cm-chiba-hogehoge
upload: ./test.txt to s3://cm-chiba-hogehoge/test.txt

ちょっと一工夫が必要でしたね。プライベート DNS 名が使用できないのには、こういった部分が関係しているのかもしれません。(全く関係ないかもしれません。)

まとめ

  • インターフェースエンドポイントには以下の DNS 名がある
    • プライベート DNS 名
    • エンドポイント固有の DNS 名
  • S3 では以下の VPC エンドポイントがある
    • ゲートウェイ型
    • インターフェース型
  • S3 PrivateLink ではプライベート DNS 名に対応していない
  • つまりどういうことですか?一言で説明してください
    • 「 S3 PrivateLink ではエンドポイント固有の DNS 名を指定する必要があります。」

終わりに

S3 インターフェースエンドポイントの仕様について確認しました。

書いてみたら思ったより長文となりましたが、一通り読んだ心の中のリトル千葉も概ね納得していました。皆さんの中のリトル皆さんが腹落ちする一助になれば幸いです。

以上、千葉(幸)がお送りしました。