結論
SHA-256による署名はできなかった。
AWSドキュメントに記載されているとおり、SHA-1だと問題はない。
ブログ記事を書いている最中に、できない理由が記載されているドキュメントを見つけた。
URL または Cookie の署名には、RSA-SHA1 を使用する必要があります。CloudFront では他のアルゴリズムを使用できません。
背景
SHA-256の署名でできるのか調べたきっかけは、banditでB303を検知したから。
またCloudFrontの署名付きURL/Cookie自体もゼロから構築したことがなかったため、その点も含めてやってみた。
やってみた
まずは今回の本題のSHA-256で署名してみたときの挙動を確認する。
下記、署名付きURLを生成するコードである。
中身はこのリンクを参考にしている。ドキュメントでも紹介されている。
import datetime
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, rsa
from botocore.signers import CloudFrontSigner
def rsa_signer(message):
with open('private_key.pem', 'rb') as key_file:
private_key = serialization.load_pem_private_key(
key_file.read(),
password=None,
backend=default_backend()
)
if isinstance(private_key, rsa.RSAPrivateKey):
# SHA-256でやってみる!
return private_key.sign(message, padding.PKCS1v15(), hashes.SHA256())
# return private_key.sign(message, padding.PKCS1v15(), hashes.SHA1())
key_id = 'XXX'
url = '<https://xxx.cloudfront.net/demo.jpg>'
expire_date = datetime.datetime(2024, 1, 30)
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)
出力されたurl
<https://xxx.cloudfront.net/demo.jpg?Expires=1706572800&Signature=pT0~xxx&Key-Pair-Id=XXX>
アクセスすると、AccessDeniedになる。
念のため、SHA-1だと問題ない。
署名付きURLのための実装手順
ざっくりとした流れは、プライベートコンテンツ提供のためのタスクリストに記載されている。
今回は以下の流れで実装した。
- S3バケットの作成
- パブリックキーの作成
- キーグループの作成
- ディストリビューションの作成(OAC設定含む)
- ビヘイビア編集でビューワーのアクセス制限をONにする(キーグループの指定)
- 署名付きURLを生成するプログラムの実装
パブリックキーはここを参照。
キーの生成は下記コマンドで。
openssl genrsa -out private_key.pem 2048
openssl rsa -pubout -in private_key.pem -out public_key.pem
ビヘイビアでビューワーのアクセス制限をONにする画面。
署名付きURLを生成するプログラムについては、コード例を参照する。
注意点は署名付きCookieのサンプルが用意されていないこと。
まとめ
AWSドキュメントにあるとおり、ClouldFrontの署名付きURLではRSA-SHA1を使う必要がある。他のアルゴリズムは対応していない。
今回は署名付きURLをシンプルに実装して全体像を把握することもできたのでよかった。
今後はポリシーやCookieなどやってみたい。