Amazon S3のPrivateLinkを使ってyum updateができるか試してみた

2021.02.05

しばたです。

先日Amazon S3でインターフェース型のVPC エンドポイント(PrivateLink使用)がサポートされ話題となっています。

また、従来からあるゲートウェイ型のS3 VPCエンドポイントは閉域ネットワークからAmazon Linuxのyumリポジトリへアクセスするために使うことが可能です。

今回新たにサポートされたインターフェース型のVPC エンドポイントがyumリポジトリへのアクセス用途に使えるのか気になったので試してみることにしました。

最初に結論から

はじめに結論から言うと、「インターフェース型のS3 VPCエンドポイントを使ってyum updateをするのは不可能ではなかったが、サポートされている行為か非常に怪しく、そうする意味も全然ない。」という身も蓋もない話になります。
閉域ネットワーク内からyum updateしたいときには従来どおりゲートウェイ型のVPCエンドポイントを使う様にしてください。

以降、試した詳細について記述していきますが純粋に技術的なチャレンジとして捉えていただければと思います。

そもそもAmazon Linuxのyum設定はどうなっているのか

はじめに、VPCエンドポイントを試す前にAmazon LinuxでyumがS3にアクセスするというのがどういう事かについて触れておきます。

本日時点で最新のAmazon Linux 2 *1において、yumが参照するリポジトリの設定は/etc/yum.repos.d/配下に記述されています。

$ ls /etc/yum.repos.d/
amzn2-core.repo  amzn2-extras.repo

このディレクトリにはamzn2-core.repoamzn2-extras.repoと2つの設定ファイルがあり、それぞれ

  • amzn2-core.repo : Amazon Linux 2 Coreリポジトリの設定
  • amzn2-extras.repo : Amazon Extras Libraryリポジトリの設定

となります。
これらのファイルの詳細まで触れませんがAmazon Linuxのyumは独自のリポジトリ設定を持っていることを押さえておいてください。

そしてこの設定の結果デフォルトで有効となっているリポジトリ情報はyum repolist enabled -vコマンドで調べることが可能で、実行結果は以下の様になります。

# 東京リージョンのインスタンスで実行した場合の結果 (リージョン毎で結果は変わる)
$ yum repolist enabled -v
Loading "extras_suggestions" plugin
Loading "langpacks" plugin
Loading "priorities" plugin
Loading "update-motd" plugin
Adding en_US to language list
Config time: 0.316
Yum version: 3.4.3
Setting up Package Sacks
pkgsack time: 0.231
Repo-id      : amzn2-core/2/x86_64
Repo-name    : Amazon Linux 2 core repository
Repo-revision: 1611627455
Repo-updated : Tue Jan 26 02:17:35 2021
Repo-pkgs    : 23,094
Repo-size    : 27 G
Repo-mirrors : http://amazonlinux.ap-northeast-1.amazonaws.com/2/core/latest/x86_64/mirror.list
Repo-baseurl : http://amazonlinux.ap-northeast-1.amazonaws.com/2/core/2.0/x86_64/34112b4f91c3e1ecf2b2e90cfd565b12690fa3c6a3e71a5ac19029d2a9bd3869/
Repo-expire  : 300 second(s) (last: Fri Feb  5 00:58:33 2021)
  Filter     : read-only:present
Repo-filename: /etc/yum.repos.d/amzn2-core.repo

Repo-id      : amzn2extra-docker/2/x86_64
Repo-name    : Amazon Extras repo for docker
Repo-revision: 1606253889
Repo-updated : Tue Nov 24 21:38:09 2020
Repo-pkgs    : 36
Repo-size    : 788 M
Repo-mirrors : http://amazonlinux.ap-northeast-1.amazonaws.com/2/extras/docker/latest/x86_64/mirror.list
Repo-baseurl : http://amazonlinux.ap-northeast-1.amazonaws.com/2/extras/docker/stable/x86_64/4bf88ee77c395ffe1e0c3ca68530dfb3a683ec65a4a1ce9c0ff394be50e922b2/
Repo-expire  : 21,600 second(s) (last: Fri Feb  5 00:58:33 2021)
  Filter     : read-only:present
Repo-filename: /etc/yum.repos.d/amzn2-extras.repo

repolist: 23,130

ここで重要なのはリポジトリのURLがhttp://amazonlinux.<リージョン名>.amazonaws.com/である点です。
このURLの実体はS3上に構築されたサイトであり、これがyumがS3にアクセスする意味になります。

ただ、yumの内部から見ればアクセス先は単なるHTTPサーバーでしかなく、今回試す内容は結局は

EC2インスタンスから amazonlinux.<リージョン名>.amazonaws.com というホストに対して通信できるかどうか

という点に行きつきます。
S3やyumの機能ではなく通信経路の話が本質です。

試してみた

ここからは実際に検証環境を作って試していきます。
はじめにVPCエンドポイントが一切ない場合と従来のゲートウェイ型のVPCエンドポイントがある場合を試し、その後インターフェース型のVPCエンドポイントがある場合を試していきます。

1. VPCエンドポイントが一切ない場合 (アクセス不可)

今回東京リージョンに下図の様な簡単なVPC環境を用意しました。

VPC外に出ることのできないPrivateなサブネットに検証用のAmazon Linux EC2インスタンスを用意しここからyumコマンドを実行します。
検証用インスタンスへログインするために踏み台サーバーも合わせて作っています。

この場合はPrivate subnetから外部に出ることができないのでyum updateは当然タイムアウトエラーとなります。

# yum updateはタイムアウトエラー
[検証サーバー ~]$ sudo yum update
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
Could not retrieve mirrorlist http://amazonlinux.ap-northeast-1.amazonaws.com/2/core/latest/x86_64/mirror.list error was
12: Timeout on http://amazonlinux.ap-northeast-1.amazonaws.com/2/core/latest/x86_64/mirror.list: (28, 'Connection timed out after 5000 milliseconds')

2. ゲートウェイ型のVPCエンドポイントがある場合 (アクセス可能)

次にこの環境にゲートウェイ型のVPCエンドポイントを追加してみます。

ゲートウェイ型のVPCエンドポイントは指定のルートテーブルに対して当該サービス(ここではS3)へのルートを増やすことで閉域ネットワークからAWSサービスへのアクセスを実現する仕組みです。
今回はこの様に検証用EC2のあるサブネットのルートテーブルにS3サービスへのルートが追加されています。

ちなみにこの追加されたルートの詳細についてはマネージドプリフィックスリストから確認可能です。

この状態であればyum updateは期待した動作をします。

# yum updateはうまくいく
[検証サーバー ~]$ sudo yum update
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
amzn2-core                                                                                   | 3.7 kB  00:00:00
amzn2extra-docker                                                                            | 3.0 kB  00:00:00
(1/5): amzn2-core/2/x86_64/group_gz                                                          | 2.5 kB  00:00:00
(2/5): amzn2-core/2/x86_64/updateinfo                                                        | 330 kB  00:00:00
(3/5): amzn2extra-docker/2/x86_64/updateinfo                                                 |   76 B  00:00:00
(4/5): amzn2extra-docker/2/x86_64/primary_db                                                 |  74 kB  00:00:00
(5/5): amzn2-core/2/x86_64/primary_db                                                        |  49 MB  00:00:01
No packages marked for update

今回の環境でyumリポジトリはamazonlinux.ap-northeast-1.amazonaws.comになるのですが、単純にcurlでアクセスしてみると以下の様な結果になります。

# curlでyumリポジトリにアクセスしてみる
[検証サーバー ~]$ curl -iv http://amazonlinux.ap-northeast-1.amazonaws.com/2/core/latest/x86_64/mirror.list
*   Trying 52.219.136.90...
* TCP_NODELAY set
* Connected to amazonlinux.ap-northeast-1.amazonaws.com (52.219.136.90) port 80 (#0)
> GET /2/core/latest/x86_64/mirror.list HTTP/1.1
> Host: amazonlinux.ap-northeast-1.amazonaws.com
> User-Agent: curl/7.61.1
> Accept: */*
>
< HTTP/1.1 200 OK

# ・・・(後略)・・・

この結果からamazonlinux.ap-northeast-1.amazonaws.comのアドレスは52.219.136.90で名前解決され、これはマネージドプリフィックスリストにある52.219.136.0/22に含まれるのでVPCエンドポイントを経由してS3へアクセスできる様になっていることがわかります。

3. インターフェース型のVPCエンドポイントがある場合 (アクセス可能?)

ここからやっと本記事の本題に入ります。
こんどはインターフェース型のVPCエンドポイントを検証用EC2にあるサブネットに追加します。

インターフェース型のVPCエンドポイントは指定のサブネットにAWSサービスへ繋がるENIを生やし、このENIにアクセスすることでサービスへのアクセスを肩代わりさせる仕組みとなります。

今回は下図の様に10.0.21.84のプライベートIPを持つENIが生成されています。
(検証用EC2のあるサブネットは10.0.21.0/24になります)

この状態でyum updateをしても、残念ながらタイムアウトエラーになってしまいます。

# yum updateはタイムアウトエラー
[検証サーバー ~]$ sudo yum update
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
Could not retrieve mirrorlist http://amazonlinux.ap-northeast-1.amazonaws.com/2/core/latest/x86_64/mirror.list error was
12: Timeout on http://amazonlinux.ap-northeast-1.amazonaws.com/2/core/latest/x86_64/mirror.list: (28, 'Connection timed out after 5000 milliseconds')

そしてcurlでアクセスすると以下の様な感じとなりamazonlinux.ap-northeast-1.amazonaws.com52.219.8.42で名前解決されていることがわかります。

# curlでyumリポジトリにアクセスしてみる
[検証サーバー ~]$ curl -iv http://amazonlinux.ap-northeast-1.amazonaws.com/2/core/latest/x86_64/mirror.list
*   Trying 52.219.8.42...
* TCP_NODELAY set
*   Trying 2406:daa0:4068:289:34db:8827::...
* TCP_NODELAY set
* Immediate connect fail for 2406:daa0:4068:289:34db:8827::: Network is unreachable

# ・・・(後略)・・・

インターフェース型のVPCエンドポイントでは10.0.21.84のプライベートIPにアクセスしてくれないとS3に到達できませんので、当然これではタイムアウトしてしまいます。

3-1. S3のインターフェース型VPCエンドポイントはプライベートDNS名をサポートしない

ここで他サービスのVPCエンドポイントを利用したことがある方は違和感を覚えられるかもしれませんが、残念ながらS3のインターフェース型VPCエンドポイントではプライベートDNS名はサポートされていません。

最初に紹介した記事やドキュメントにもきちんと記載されています。

Note
Amazon S3 interface endpoints do not support the private DNS feature of interface endpoints.

(S3 ユーザーガイドより引用)

このため他サービスの様にエンドポイントに対する名前解決がプライベートIPに差し替えられる動作は起こりません。こちらの記事にある様に、S3のインターフェース型VPCエンドポイントはエンドポイントURLを明示して使用するのが基本となります。

# S3のインターフェース型VPCエンドポイントはエンドポイントURLを明示して使用する
$ aws s3 --endpoint-url https://bucket.vpce-024816xxxxxxxx-uozxxxxx.s3.ap-northeast-1.vpce.amazonaws.com ls

3-2. じゃあ /etc/hosts を書き換えてしまえば良いのでは?

AWSの仕組みとしてDNSの差し替えができないのなら「自分で直接 /etc/hosts を書き換えてしまえば良いのでは?」と考えてしまうのが人情です。

以下の様な感じで/etc/hostsにVPCエンドポイントに対するエントリを追加して再チャレンジしてみました。

/etc/hosts

# VPCエンドポイントに対するエントリを追記
10.0.21.84 amazonlinux.ap-northeast-1.amazonaws.com

その結果、curlのアクセスはVPCエンドポイント(10.0.21.84)経由で疎通可能となり、

# /etc/hostsを書き換えてからcurlでyumリポジトリにアクセスしてみる
[検証サーバー ~]$ curl -iv http://amazonlinux.ap-northeast-1.amazonaws.com/2/core/latest/x86_64/mirror.list
*   Trying 10.0.21.84...
* TCP_NODELAY set
* Connected to amazonlinux.ap-northeast-1.amazonaws.com (10.0.21.84) port 80 (#0)
> GET /2/core/latest/x86_64/mirror.list HTTP/1.1
> Host: amazonlinux.ap-northeast-1.amazonaws.com
> User-Agent: curl/7.61.1
> Accept: */*
>
< HTTP/1.1 200 OK
HTTP/1.1 200 OK

# ・・・(後略)・・・

yum updateも正常に動作する様になりました。

# /etc/hostsを書き換えるとyum updateはうまくいく
[検証サーバー ~]$ sudo yum update
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
amzn2-core                                                                                   | 3.7 kB  00:00:00
amzn2extra-docker                                                                            | 3.0 kB  00:00:00
(1/5): amzn2-core/2/x86_64/group_gz                                                          | 2.5 kB  00:00:00
(2/5): amzn2-core/2/x86_64/updateinfo                                                        | 330 kB  00:00:00
(3/5): amzn2extra-docker/2/x86_64/updateinfo                                                 |   76 B  00:00:00
(4/5): amzn2extra-docker/2/x86_64/primary_db                                                 |  74 kB  00:00:00
(5/5): amzn2-core/2/x86_64/primary_db                                                        |  49 MB  00:00:01
No packages marked for update

一応yum updateを動作させることはできましたが、そもそもAWSとしては「プライベートDNS名はサポートされていません」と言っている以上この方法は使うべきではないでしょう。
従来からあるゲートウェイ型のVPCエンドポイントが廃止されるわけでもないので要件に応じて両者を使い分ける・併用するのがベストかと思います。

費用の問題

加えて機能面とは別に費用の問題もあります。

ゲートウェイ型のVPCエンドポイントは利用費が無料ですがインターフェース型のVPCエンドポイントはENIの利用費と通信費が発生します。
yum updateという用途だけみればゲートウェイ型のVPCエンドポイントを使い無料で可能な構成をわざわざ有償にする必要はまったくありません。

最後に

以上となります。

最初に述べた通り割と身も蓋もない結論ではあるのですが、新しい機能がサポートされ使い分けに悩むこともあるかと思います。
本記事の内容がそういった方の役に立てば幸いです。

脚注

  1. Amazon Linux 1でも同様ですが今回は触れません