Amazon S3 PrivateLink 経由で AWS CLI も SDK も使わず Curl で Get してみた
コンバンハ、千葉(幸)です。
先日、 Amazon S3 が AWS PrivateLink(インターフェース型 VPC エンドポイント) に対応しました。これにより、オンプレミスからプライベート IP を使用して S3 バケットに対してアクセスできるようになりました。
公式ドキュメントややってみたブログでは AWS CLI や AWS SDK を用いたケースが取り上げられています。そういった方式による認証を使用せず、単純な HTTPS アクセスで S3 上のファイルを取得したいと思い、検証してみました。
先にまとめ
- バケットポリシーで許可すれば IAM の認証情報なしで取得可能
- パス形式の場合、エンドポイントの DNS 名のサブドメインは「なし」か特定のものである必要あり
- 仮想ホスト形式の場合、名前解決の部分を頑張る必要がある
想定している構成
イメージとしては以下の通りです。
Direct Connectをなどを通じてオンプレミスと VPC が接続されており、オンプレミス上のクライアントが S3 にプライベートアクセスをしたいです。
クライアントには AWS CLI などのツールをセットアップせず、単純な Curl で S3 バケット内のオブジェクトを Get したいとします。
検証する構成
再現するのがハードルが高そうだったので、以下のお手軽構成で検証します。同一 VPC のインスタンスから接続します。
ルートテーブルや SecuriryGroup などのネットワーク設定、名前解決の部分を考慮すれば、 VPC の中からでも外からでも変わらないだろうという目論見です。
下準備
S3 インターフェースエンドポイント
設定済みであるとします。クライアントの EC2 インスタンスと疎通が取れる状態です。
S3 バケット
対象の S3 バケットはchibayuki-from-vpce
とし、以下のバケットポリシーを設定しています。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": "*", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::chibayuki-from-vpce/*", "Condition": { "StringEquals": { "aws:SourceVpce": "vpce-0562f2c59ac7b66e6" } } } ] }
ポリシー内で指定している vpce-id は S3 インターフェースエンドポイントのものです。
その他の設定は以下です。
- バケットのパブリックアクセスブロックをすべてオン
- バケット ACL はデフォルト(所有者のみ読み書き可)
- オブジェクト ACL もデフォルト(所有者のみ読み書き可)
バケット内には以下の慎ましいファイルを格納しています。
Hello
クライアント
クライアントの EC2 は Amazon Linux2 で、curl のバージョンは以下です。
curl --version curl 7.61.1 (x86_64-koji-linux-gnu) libcurl/7.61.1 OpenSSL/1.0.2k zlib/1.2.7 libidn2/2.3.0 libssh2/1.4.3 nghttp2/1.41.0 Release-Date: 2018-09-05 Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz HTTP2 UnixSockets HTTPS-proxy Metalink
やってみた
早速いくつかのパターンでアクセスしていきます。
前提として S3 PrivateLink はプライベートDNS 名に対応していないという仕様があるため、エンドポイント固有の DNS 名を指定します。
この辺りの詳細は以下エントリをご参照ください。
ちなみに今回のエンドポイントのリージョナル DNS 名は以下です。
*.vpce-0562f2c59ac7b66e6-4j54175z.s3.ap-northeast-1.vpce.amazonaws.com
手元の端末で名前解決を試みると、プライベート IP アドレスが返却されます。
% nslookup chiba.vpce-0562f2c59ac7b66e6-4j54175z.s3.ap-northeast-1.vpce.amazonaws.com Server: 218.xx.82.xx Address: 218.xx.82.xx#53 Non-authoritative answer: Name: chiba.vpce-0562f2c59ac7b66e6-4j54175z.s3.ap-northeast-1.vpce.amazonaws.com Address: 192.168.3.63 Name: chiba.vpce-0562f2c59ac7b66e6-4j54175z.s3.ap-northeast-1.vpce.amazonaws.com Address: 192.168.1.66
名前解決の際にはエンドポイントの先頭の*
には任意の値を入れられますし、削っても問題ありません。
クライアントがオンプレミスにいることを想定した場合、(少なくともパス形式では)この DNS 名を名前解決できる必要があります。
パス形式で HTTP
一番シンプルなパターンで試します。
*
を削った エンドポイント名の後に/バケット名/オブジェクト名
を付与して curl します。
[root@ip-192-168-0-168 ~]# curl http://vpce-0562f2c59ac7b66e6-4j54175z.s3.ap-northeast-1.vpce.amazonaws.com/chibayuki-from-vpce/Hello.txt Hello
問題なく Get できました。
-O
オプションを指定してダウンロードもできます。
[root@ip-192-168-0-168 ~]# curl -O http://chiba.vpce-0562f2c59ac7b66e6-4j54175z.s3.ap-northeast-1.vpce.amazonaws.com/chibayuki-from-vpce/Hello.txt % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 364 0 364 0 0 22750 0 --:--:-- --:--:-- --:--:-- 22750 [root@ip-192-168-0-168 ~]# ls | grep Hello Hello.txt
エンドポイントのサブドメインに注意
いくつか試行する中で気付いたのですが、この形式でアクセスする場合のサブドメインは任意のものが使えるわけではないようです。ひとまず以下で成功することは確認できました。
- なし(上記のパターン)
- bucket
bucket
を指定した場合は上記と同様に成功します。
[root@ip-192-168-0-168 ~]# curl http://bucket.vpce-0562f2c59ac7b66e6-4j54175z.s3.ap-northeast-1.vpce.amazonaws.com/chibayuki-from-vpce/Hello.txt Hello
適当な値、例えばchiba
やsaitama
を指定した場合はエラーになります。
[root@ip-192-168-0-168 ~]# curl http://chiba.vpce-0562f2c59ac7b66e6-4j54175z.s3.ap-northeast-1.vpce.amazonaws.com/chibayuki-from-vpce/Hello.txt <?xml version="1.0" encoding="UTF-8"?> <Error><Code>NoSuchBucket</Code><Message>The specified bucket does not exist</Message><BucketName>chiba.vpce-0562f2c59ac7b66e6-4j54175z.s3.ap-northeast-1.vpce.amazonaws.com</BucketName><RequestId>001HN8C12GPACH9J</RequestId><HostId>woMYg8S5RldFCQyMiiO30+4ueRmWrWSZMVo+KOssOt5Ge2cFaQn6o/eSEP+Uz9CZ8aE7eSZxWtc=</HostId></Error>
[root@ip-192-168-0-168 ~]# curl http://saitama.vpce-0562f2c59ac7b66e6-4j54175z.s3.ap-northeast-1.vpce.amazonaws.com/chibayuki-from-vpce/Hello.txt <?xml version="1.0" encoding="UTF-8"?> <Error><Code>NoSuchBucket</Code><Message>The specified bucket does not exist</Message><BucketName>saitama.vpce-0562f2c59ac7b66e6-4j54175z.s3.ap-northeast-1.vpce.amazonaws.com</BucketName><RequestId>YNEH987YXCACFRA2</RequestId><HostId>z1anjCV4SafrtMSGN0cH34CdakE7/lX/554uUZxT98vCpIVCyfRzXkolGQ7HlWNTIuDCuJMY+tc=</HostId></Error>
エンドポイント名がバケット名と解釈されるために発生しているエラーのようです。不思議仕様ですね。bucket
以外にも使用できるものはありそうですが、情報が見つかりませんでした。
IP アドレス直指定だとどうなる?
http://エンドポイントのIP/バケット名/オブジェクト名
で試してみました。
[root@ip-192-168-0-168 ~]# curl http://192.168.1.66/chibayuki-from-vpce/Hello.txt <?xml version="1.0" encoding="UTF-8"?> <Error><Code>PermanentRedirect</Code><Message>The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint.</Message><Endpoint>chibayuki-from-vpce.s3.amazonaws.com</Endpoint><Bucket>chibayuki-from-vpce</Bucket><RequestId>Y9ESJ9Z750YKECS5</RequestId><HostId>A9wDITlwdt1AdyoUoHWaaxIGdobMDyW8lpg9QgSpA/8CvkzwCSnNzA5yQI7VsHvWEkB540Ir9Bk=</HostId></Error>
エンドポイント名としてchibayuki-from-vpce.s3.amazonaws.com
を指定しろ、というエラーになりました。難しいですね。
パス形式で HTTPS
bucket
を指定した場合は特に変わらず成功します。
[root@ip-192-168-0-168 ~]# curl https://bucket.vpce-0562f2c59ac7b66e6-4j54175z.s3.ap-northeast-1.vpce.amazonaws.com/chibayuki-from-vpce/Hello.txt Hello
chiba
を指定した場合は SSL のエラーが出ます。
[root@ip-192-168-0-168 ~]# curl https://chiba.vpce-0562f2c59ac7b66e6-4j54175z.s3.ap-northeast-1.vpce.amazonaws.com/chibayuki-from-vpce/Hello.txt curl: (51) SSL: no alternative certificate subject name matches target host name 'chiba.vpce-0562f2c59ac7b66e6-4j54175z.s3.ap-northeast-1.vpce.amazonaws.com'
-k
を指定して無視すれば、HTTP の場合と同じエラーになります。
[root@ip-192-168-0-168 ~]# curl -k https://chiba.vpce-0562f2c59ac7b66e6-4j54175z.s3.ap-northeast-1.vpce.amazonaws.com/chibayuki-from-vpce/Hello.txt <?xml version="1.0" encoding="UTF-8"?> <Error><Code>NoSuchBucket</Code><Message>The specified bucket does not exist</Message><BucketName>chiba.vpce-0562f2c59ac7b66e6-4j54175z.s3.ap-northeast-1.vpce.amazonaws.com</BucketName><RequestId>CQYN8CNJYPFJN1VN</RequestId><HostId>ZI2dgHwR8QhFmHgNY8UBe9mZV7vG1vHk6d/P9oUfBN8Td080brcHB+9TYmgXLkcJW/m1jw1ImiY=</HostId></Error>
仮想ホスト形式で HTTP
仮想ホスト形式とは、東京リージョンの S3 バケットであれば以下のような形式で指定するものです。
https://バケット名.s3.ap-northeast-1.amazonaws.com
これをどう実現するかは悩ましいですが、以下のような力業でやってみました。
curl --resolve chibayuki-from-vpce.s3-ap-northeast-1.amazonaws.com:80:192.168.1.66\ http://chibayuki-from-vpce.s3-ap-northeast-1.amazonaws.com/Hello.txt Hello
コマンド内で指定している192.168.1.66
はインターフェースエンドポイントの IP アドレスです。
-v
オプションを付与すると以下のような形で流れが確認できます。
[root@ip-192-168-0-168 ~]# curl -v --resolve chibayuki-from-vpce.s3-ap-northeast-1.amazonaws.com:80:192.168.1.66 http://chibayuki-from-vpce.s3-ap-northeast-1.amazonaws.com/Hello.txt * Added chibayuki-from-vpce.s3-ap-northeast-1.amazonaws.com:80:192.168.1.66 to DNS cache * Hostname chibayuki-from-vpce.s3-ap-northeast-1.amazonaws.com was found in DNS cache * Trying 192.168.1.66... * TCP_NODELAY set * Connected to chibayuki-from-vpce.s3-ap-northeast-1.amazonaws.com (192.168.1.66) port 80 (#0) > GET /Hello.txt HTTP/1.1 > Host: chibayuki-from-vpce.s3-ap-northeast-1.amazonaws.com > User-Agent: curl/7.61.1 > Accept: */* > < HTTP/1.1 200 OK < x-amz-id-2: KMFqlsbu6XP4nAH41trufO8NI74GvobqKRocsaNo3Y+/xrSIHWNk+RjRpaAe7yFcC28kA6ioYo0= < x-amz-request-id: W41M3HJAR162B1X8 < Date: Wed, 31 Mar 2021 12:06:26 GMT < Last-Modified: Wed, 31 Mar 2021 10:51:34 GMT < ETag: "8b1a9953c4611296a827abf8c47804d7" < Accept-Ranges: bytes < Content-Type: text/plain < Content-Length: 5 < Server: AmazonS3 < * Connection #0 to host chibayuki-from-vpce.s3-ap-northeast-1.amazonaws.com left intact Hello
やっていることは/etc/hosts
にエントリを追加するのと同じですね。
同じようなことを試しているパターンは以下をご参照ください。
仮想ホスト形式で HTTPS
--resolve
オプションを使用するパターンで HTTPS に替えて試してみます。
[root@ip-192-168-0-168 ~]# curl --resolve chibayuki-from-vpce.s3-ap-northeast-1.amazonaws.com:443:192.168.1.66\ > https://chibayuki-from-vpce.s3-ap-northeast-1.amazonaws.com/Hello.txt curl: (51) SSL: no alternative certificate subject name matches target host name 'chibayuki-from-vpce.s3-ap-northeast-1.amazonaws.com'
ここでも証明書エラーが発生しています。
-k
と、折角なので-v
を付与して試してみました。
[root@ip-192-168-0-168 ~]# curl -k -v --resolve chibayuki-from-vpce.s3-ap-northeast-1.amazonaws.com:443:192.168.1.66\ > https://chibayuki-from-vpce.s3-ap-northeast-1.amazonaws.com/Hello.txt * Added chibayuki-from-vpce.s3-ap-northeast-1.amazonaws.com:443:192.168.1.66 to DNS cache * Hostname chibayuki-from-vpce.s3-ap-northeast-1.amazonaws.com was found in DNS cache * Trying 192.168.1.66... * TCP_NODELAY set * Connected to chibayuki-from-vpce.s3-ap-northeast-1.amazonaws.com (192.168.1.66) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH * successfully set certificate verify locations: * CAfile: /etc/pki/tls/certs/ca-bundle.crt CApath: none * TLSv1.2 (OUT), TLS header, Certificate Status (22): * TLSv1.2 (OUT), TLS handshake, Client hello (1): * TLSv1.2 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS change cipher, Change cipher spec (1): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / ECDHE-RSA-AES128-SHA * ALPN, server did not agree to a protocol * Server certificate: * subject: CN=s3.ap-northeast-1.amazonaws.com * start date: Mar 21 00:00:00 2021 GMT * expire date: Apr 19 23:59:59 2022 GMT * issuer: C=US; O=Amazon; OU=Server CA 1B; CN=Amazon * SSL certificate verify ok. > GET /Hello.txt HTTP/1.1 > Host: chibayuki-from-vpce.s3-ap-northeast-1.amazonaws.com > User-Agent: curl/7.61.1 > Accept: */* > < HTTP/1.1 200 OK < x-amz-id-2: pN9LMggrOk45bf+WyTUtOe+6SDncTDTEEUgmwFxft9tr/BvOWyxg2BAJS+d2vWP6EP2Qo5RzMSU= < x-amz-request-id: AW59F9D2NH1H6HBY < Date: Wed, 31 Mar 2021 12:21:30 GMT < Last-Modified: Wed, 31 Mar 2021 10:51:34 GMT < ETag: "8b1a9953c4611296a827abf8c47804d7" < Accept-Ranges: bytes < Content-Type: text/plain < Content-Length: 5 < Server: AmazonS3 < * Connection #0 to host chibayuki-from-vpce.s3-ap-northeast-1.amazonaws.com left intact Hello
諸々の処理を経て、最終的に Get できました。力業感がすごいですね。
終わりに
いくつかのパターンで Curl を試してみました。
バケットポリシーを適切に設定していれば、 IAM の認証情報がなくてもオブジェクトを取得できることが分かりました。
仮想ホスト形式の場合は、プライベートなホストゾーンでレコードを設定しておけば力業感少なく取得が実現できるかもしれません。
パス形式でのリクエストは一度廃止がアナウンスされましたが、廃止タイミングは延期になっている状態です。
パス形式の方がお手軽ですが、使用の際には将来的な廃止の可能性も念頭において採用ください。
以上、千葉(幸)がお送りしました。