ALBからS3コンテンツを配信してみた

S3のインターフェース型VPCエンドポイントを利用すると、ALBのターゲットにS3を指定できます
2024.05.20

Amazon S3のコンテンツを配信したい場合、S3の静的ウェブサイトホスティングを使用したり、S3の前段にCloudFront(CDN)を配置して配信することが多いかと思います。今回は、3つ目の選択肢として、S3をALBから配信する構成について紹介します。

S3バケットをプライベートにしたまま、ALBレイヤーでHTPS通信化や認証やセキュリティグループのアクセス制限を行うことができます。アプリケーションで利用するALBにS3配信を集約させることも可能です。また、外部・内部どちらのALBでも採用できます。

  • オンプレミスからプライベート通信によるS3アクセス
  • 認証付きURL/CookieでS3コンテンツを配信する代替案として、ALB認証でS3配信

などで有用です。

構成ポイント

本構成の肝はALBのターゲットにS3のインターフェース型VPCエンドポイントのIPを指定すること(昔からあるゲートウェイ型エンドポイントではない)です。

以下の様な特徴があります

  • S3バケットの公開は不要。S3のバケットポリシーではこのVPCエンドポイントからのアクセスを許可すればよい
  • ターゲットを利用するALBは外部(internet-facing)でも内部(internal)もよい
  • ALBからのヘルスチェックでは、リクエストヘッダーの制約から200 OKとはならない
  • クライアントからの通信はALBを経由するため、HTTPS通信する場合、S3バケット名をドメイン名に合わせ、ALBにACM証明書をインストール

ウォークスルー

S3に対してカスタムドメイン(s3.example.com 等)でALB経由でHTTPS通信してみます。

VPC

VPCを作成し、ALB向けとS3 VPCエンドポイント向けのセキュリティグループを作成します。

ALB向けのセキュリティグループでは、適切なIPレンジからのHTTPS通信を許可します。

VPCエンドポイント向けのセキュリティグループでは、ALB向けセキュリティグループをソースとしたHTTP(ALBヘルスチェックからのリクエスト)およびHTTPS(クライアントからリクエスト)通信を許可します。

S3のインターフェース型VPCエンドポイント

S3のインターフェース型VPCエンドポイントを作成します。

このエンドポイントには、先程作成したVPCエンドポイント向けのセキュリティグループをアタッチします。

S3バケット

ALBをアクセスする際のドメインと同じ名前のバケット名を作成します。

バケットポリシーで、インターフェース型VPCエンドポイントからの参照を許可します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Access-to-specific-VPCE-only",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": [
                "arn:aws:s3:::バケット名",
                "arn:aws:s3:::バケット名/*"
            ],
            "Condition": {
                "StringEquals": {
                    "aws:SourceVpce": "VPCエンドポイント"
                }
            }
        }
    ]
}

このポリシーの以下の変数を実環境に合わせて調整してください。

  • バケット名(s3.example.com など)
  • VPCエンドポイント(vcpe-1234 など)

ACM

S3をALB配信するドメイン向けのTLS証明書を取得します。

ALBターゲット

ALBに指定するターゲットを作成します。

ターゲットにはS3インターフェース型エンドポイントのIPアドレスを指定します。

  • ターゲット
    • タイプ:IPアドレス
    • プロトコル : HTTPS
  • ヘルスチェック :
    • プロトコル : HTTP
    • パス : /
    • サクセスコード : 307

ヘルスチェックの設定には注意が必要です。

ALBのヘルスチェックリクエストでは、ホスト情報をカスタマイズできません。そのため、本来のアクセス時(ホスト名=バケット名)のように、200 OKのレスポンスステータスが返ってきません。サクセスコードを非200番の 307 等に設定しましょう。

試しに、VPC内のEC2からS3のVPCエンドポイントのIPアドレスに向けて、S3の実在するオブジェクトのパス /index.html を指定してホスト名の有り・無しでリクエストしてみましょう。

ホスト名を渡す

S3バケット名と同じホストを渡すと、 200 OK が返ります

$ curl -H 'Host: s3.example.com' -D - 172.31.42.253/index.html
HTTP/1.1 200 OK
x-amz-id-2: Yr3UfhFrPZroQHhVqPB6KqjADkZ2YV/qRGfvzgrl8LtjDaSRP27PzRog3oGB8zejQaRJp93YujU=
x-amz-request-id: PD0DFTAGHN43561C
Date: Sun, 19 May 2024 04:29:05 GMT
Last-Modified: Fri, 17 May 2024 05:49:07 GMT
ETag: "b1946ac92492d2347c6235b4d2611184"
x-amz-server-side-encryption: AES256
Accept-Ranges: bytes
Content-Type: text/html
Server: AmazonS3
Content-Length: 6

hello

ホスト名を渡さない

ホストを渡さないと、301 Moved Permanently が返ります

$ curl -D - 172.31.42.253/index.html
HTTP/1.1 301 Moved Permanently
x-amz-bucket-region: us-east-1
x-amz-request-id: FCB7CZ5PWAJR5KCH
x-amz-id-2: S+9+4wTMYFpOnKAszTq7uLMN3EIqCS0sP8ndoCifV11NXuUcsHHwn4E4moBdja0DP6W5VQpjHg0=
Content-Type: application/xml
Transfer-Encoding: chunked
Date: Sun, 19 May 2024 04:31:38 GMT
Server: AmazonS3

<?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>s3.amazonaws.com</Endpoint>
	<Bucket>index.html</Bucket>
	<RequestId>FCB7CZ5PWAJR5KCH</RequestId>
	<HostId>S+9+4wTMYFpOnKAszTq7uLMN3EIqCS0sP8ndoCifV11NXuUcsHHwn4E4moBdja0DP6W5VQpjHg0=</HostId>
</Error>

ヘルスチェックのデフォルト設定(/ にHostヘッダーを渡さない)

ホストを渡さず、存在しないオブジェクトを指定すると、 301 Moved Permanently が返ります

$ curl -D - 172.31.42.253/
HTTP/1.1 307 Temporary Redirect
x-amz-id-2: 69mwFG+F3gy8vsPnBx11KD0eJDHdVfmsU3LMxUDVuLLMEY08AKAv61uK4yQ3EIQvn7g5Prt4YzA=
x-amz-request-id: Z2C6K86KCEH14AAR
Date: Sun, 19 May 2024 04:37:45 GMT
Location: https://aws.amazon.com/s3/
Server: AmazonS3
Content-Length: 0

ALB

Internet-facing OR Internalな ALBを作成します。要件に合わせて選択してください。

  • HTTPS(443)通信のターゲット: 作成したターゲット
  • 証明書 : 作成したACMの証明証
  • セキュリティグループ : 冒頭で作成したセキュリティグループ

Route 53

Route 53のゾーン内にAliasレコードでALBのエンドポイントを登録します。

疎通確認

最後にALB経由でS3アクセスします。

$ curl -D - https://s3.example.com/index.html
HTTP/2 200
date: Sun, 19 May 2024 04:55:13 GMT
content-type: text/html
content-length: 6
x-amz-id-2: oQ5lOebhzGBEV+J5E5ejyRyX1eAI5S1umYfuz+5isyb5Phkm89i0VJ2fW0OCZMOiYGAu7JmpVEA=
x-amz-request-id: EZY4G2BDAMS9AQ7B
last-modified: Fri, 17 May 2024 05:49:07 GMT
etag: "b1946ac92492d2347c6235b4d2611184"
x-amz-server-side-encryption: AES256
accept-ranges: bytes
server: AmazonS3

hello

無事、200 OKステータスとコンテンツが返ってきました。

まとめ

ALBからS3配信する方法を紹介しました。

オンプレミスからのプライベート通信のような内部ALBとの連携やアクセス制限が要件にある場合、ALB経由の配信も有力です。

ぜひご検討ください。

参考