CloudFrontの署名付きURLを使ったアップロードとダウンロードを試すメモ。
以前はrootユーザーで「CloudFrontのキーペア」を作る必要があったが、IAMユーザーで「信頼されたキーグループ」を利用することができるようになっており、今後はこちらが推奨される。
参考リンク
- 署名付き URL と署名付き Cookie を作成できる署名者の指定
- 【初心者向け】CloudFront経由でS3のファイルを見る【やってみた】
- 【初心者向け】CloudFrontで署名付きURLを発行する【やってみた】
- 【AWS】CloudFrontで署名付きURLの設定方法(プライベートコンテンツの配信)
- [アップデート] root ユーザー作業が不要に!Amazon CloudFront で署名付き URL/Cookie 向け公開鍵を IAM ユーザー権限で管理できるようになりました。
手順
キーペアの準備
キーペアを作成する。
プライベートキーを作成する。
$ openssl genrsa -out private_key.pem 2048 Generating RSA private key, 2048 bit long modulus .....................................+++ ...+++ e is 65537 (0x10001)
パブリックキーを抽出する。
$ openssl rsa -pubout -in private_key.pem -out public_key.pem writing RSA key
CloudFrontにパブリックキーをアップロードする。
パブリックキーを作成する。
キーグループを作成する。
ディストリビューションの作成
適当なS3バケットを用意する。
OAIを使ったディストリビューションを作成する。
他はデフォルトで作成する。
適当に置いたファイルにCloudFront経由でアクセスできることを確認する。
$ curl http://d2rn9ssidbwc6t.cloudfront.net/test.txt Hello World
ディストリビューションの設定変更
ビヘイビアを編集する。
アクセスできなくなったことを確認する。
$ curl http://d2rn9ssidbwc6t.cloudfront.net/test.txt <?xml version="1.0" encoding="UTF-8"?><Error><Code>MissingKey</Code><Message>Missing Key-Pair-Id query parameter or cookie value</Message></Error>
ダウンロード
PythonでCloudFront署名付きURLを作成する例は以下にある。
venvを作成してbotocoreをインストールする。
python3 -m venv .env source .env/bin/activate pip install cryptography botocore
スクリプトを作成する。
generate_url.py
import datetime import os from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import padding from botocore.signers import CloudFrontSigner path_to_key = os.getenv('PATH_TO_KEY') key_id = os.getenv('KEY_ID') url = os.getenv('URL') expires_in_seconds = os.getenv('EXPIRES_IN_SECONDS') expire_date = datetime.datetime.now() - datetime.timedelta(seconds=int(expires_in_seconds)) def rsa_signer(message): with open(path_to_key, 'rb') as key_file: private_key = serialization.load_pem_private_key( key_file.read(), password=None, backend=default_backend() ) return private_key.sign(message, padding.PKCS1v15(), hashes.SHA1()) cloudfront_signer = CloudFrontSigner(key_id, rsa_signer) # Create a signed url that will be valid until the specific expiry date # provided using a canned policy. signed_url = cloudfront_signer.generate_presigned_url( url, date_less_than=expire_date) print(signed_url)
スクリプトを実行する。
export PATH_TO_KEY="./private_key.pem" export KEY_ID="K1GRQBXU1LP9D1" export URL="https://d2rn9ssidbwc6t.cloudfront.net/test.txt" export EXPIRES_IN_SECONDS="3600" URL=$(python generate_url.py) echo ${URL}
https://d2rn9ssidbwc6t.cloudfront.net/test.txt?Expires=1632752859&Signature=Zd9XVJ8p563S5-H1Fq1KgjWtKzg6Oq2nIumgiYGdDvUJ5pDVS06idJOhUYlQTvAcL~KU3REfX2brISu299f51uPEwyGIFEKKxyayROalin7CoPtOlEEwK06EiBEP8QOJg6K6drTyFzJbtnxQ~vPl6fBOa6TUYUalaQlc3k4LVyU7z3aiX9fVhxX2C~lc9Y2sD8QgPtjn5MWREJcduZcKoMCtGy~3AXohhuZYkWQh7UwCf0PX1ILBiEvMCRUGffR643gIqfepFUT49qjdAqp2FmeVftm~EeqFAmPRjw1OfpBQIUR8Dv0huPpt3D0t3smON38rdq6wZSUpJi5xQgtagg__&Key-Pair-Id=K1GRQBXU1LP9D1
生成されたURLにアクセスする。
curl ${URL} Hello World
と思ったら、どうやら署名付きURLの生成はAWS CLIでもできた!
aws cloudfront sign --url ${URL} --key-pair-id ${KEY_ID} --private-key file://${PATH_TO_KEY} --date-less-than 2021-9-28
アップロード
アップロードを許可するには、PUTを許可する。(ついでにHTTPSのみにしておく。)
バケットポリシーでOAIからのPutObjectを許可する必要がある。
{ "Version": "2008-10-17", "Id": "PolicyForCloudFrontPrivateContent", "Statement": [ { "Sid": "1", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity EY4QI76AG4Z6G" }, "Action": [ "s3:GetObject", "s3:PutObject" ], "Resource": "arn:aws:s3:::test-XXXXXXXXXXXX/*" } ] }
同じスクリプトでURLを生成する。新たにアップロードするファイル用にURLは変える。
export PATH_TO_KEY="./private_key.pem" export KEY_ID="K1GRQBXU1LP9D1" export URL="https://d2rn9ssidbwc6t.cloudfront.net/test2.txt" export EXPIRES_IN_SECONDS="3600" URL=$(python generate_url.py)
x-amz-content-sha256
ヘッダを付与する必要がある。
CloudFront に PUT リクエストを送信してファイルを Amazon S3 バケットにアップロードする場合は、リクエストに x-amz-content-sha256 ヘッダーを追加する必要があります。ヘッダー値にはリクエストの本文の SHA256 ハッシュが含まれている必要があります。詳細については、Amazon Simple Storage Service API リファレンスの「一般的なリクエストヘッダー」ページで x-amz-content-sha256 ヘッダーに関するドキュメントを参照してください。
なお、OAI経由ではPOSTに対応していないため、マルチパートアップロードはできない。
POST リクエストはサポートされません。
オブジェクトの所有者がOAIになるため、x-amz-acl:bucket-owner-full-control
ヘッダを付与する必要もある。
FILE="test2.txt" DIGEST=$(openssl dgst -sha256 -hex < ${FILE} 2>/dev/null | sed 's/^.* //') curl -D - -XPUT \ -H "X-Amz-Content-SHA256: ${DIGEST}" \ -H "x-amz-acl:bucket-owner-full-control" \ --upload-file ${FILE} ${URL}
これでアップロード成功した。
$ curl -D - -XPUT \ > -H "X-Amz-Content-SHA256: ${DIGEST}" \ > -H "x-amz-acl:bucket-owner-full-control" \ > --upload-file ${FILE} ${URL} HTTP/2 200 content-length: 0 date: Mon, 27 Sep 2021 06:31:24 GMT x-amz-version-id: O5iexVYv2_zgKu4tP046Jpl6TVaIoMA0 x-amz-server-side-encryption: AES256 etag: "cbf41347bb1978f6f32087b2cf01e351" server: AmazonS3 x-cache: Miss from cloudfront via: 1.1 376eb6903adf0a53329357c7636f4f3b.cloudfront.net (CloudFront) x-amz-cf-pop: NRT51-C1 x-amz-cf-id: gRIqakR-MoVZvijoL9KJAhtG7JDilYLF850ennszVjYDTe3jcwLrkw==