2
2

Amazon CloudFront の署名付きURL(カスタムポリシー)を使って、安全にコンテンツを配信してみた

Last updated at Posted at 2022-02-25

はじめに

前回の記事では、CloudFront の署名付きURL(規定ポリシー)を使って、Private の S3 Bucket に格納している画像データを、安全性を高めたアクセス方法を確認しました。

今回の記事では、より柔軟なアクセスポリシーを定義できるカスタムポリシーを利用した方法を確認していきましょう。

2種類の署名付き URL

前回の記事でも記載しましたが、今回も改めて記載します。

署名付き URL は、セキュリティに関するポリシーの違いによって、「規定ポリシー」と「カスタムポリシー」の 2 種類あります。2 つのポリシーの違いを AWS Document に書かれている表から抜粋します。規定ポリシーは、デフォルトの設定になっており、手を加えない分比較的楽に生成できます。一方、カスタムポリシーは自分たちのワークロードに合わせたカスタマイズが可能で、柔軟にコントロールができます。カスタムポリシーの方は、複数のオブジェクトのために再利用出来たり、アクセス元の IP アドレスの制限が出来るため、便利に利用できそうですね。

image-20220225195842898.png

今回の記事では、カスタムポリシーを使った署名付き URL を生成する方法を確認していきます。

秘密鍵・公開鍵の作成

署名付き URL を生成するために、秘密鍵・公開鍵の生成が必要です。手元の Linux マシンなどで作成していきましょう。

mkdir ~/temp/cloudfront-presign/
cd ~/temp/cloudfront-presign/

秘密鍵を生成します

openssl genrsa -out private_key.pem 2048

秘密鍵から、CloudFront に登録するための公開鍵を生成します

openssl rsa -pubout -in private_key.pem -out public_key.pem

こんな感じに生成できました

> ls -lha
total 12K
drwxr-xr-x  2 ec2-user docker   51 Feb 25 20:18 .
drwxrwxr-x 36 ec2-user docker 4.0K Feb 25 19:12 ..
-rw-r--r--  1 ec2-user docker 1.7K Feb 25 20:18 private_key.pem
-rw-r--r--  1 ec2-user docker  451 Feb 25 20:18 public_key.pem

CloudFront に公開鍵をアップロード

CloudFront のページに移動して、Create public key を押します

image-20220225202106137.png

公開鍵の中身を確認して、登録をしていきます

cat public_key.pem

image-20220225202319453.png

登録されました。

image-20220225202407849.png

CloudFront に Key Group を作成

Key Group を作成して、アップロードした公開鍵を登録します

image-20220225202500082.png

名前や公開鍵の名前を選択します

image-20220225202545446.png

作成されました

image-20220225202614643.png

S3 Bucket の作成

適当な名前で Private な S3 Bucket を作成して、うちの猫の写真をアップロードします。この写真を、署名付き URL のアクセス確認に使っていきます。

image-20220225203426231.png

CloudFront の Distribution の作成

署名付き URL を利用するために、Create distributon を押します。

image-20220225203558305.png

  • Distribution の Origin として、作成した S3 Bucket を指定
  • OAI を利用して、S3 Bucket のアクセスを CloudFront のみに制限

image-20220225203852078.png

Restrict viewer access を有効にして、署名付き URL が無いとアクセスできないように設定します

image-20220225204031423.png

Create Distribution を押します

image-20220225204128034.png

Deploy プロセスが走りました

image-20220225204209601.png

署名付きURL(カスタムポリシー)の生成

カスタムポリシーを利用した署名付き URL は、AWS CLI では生成できず、何らかのプログラムで生成する必要があります。AWS Document にサンプルコードが記載されているため、これを参考にするとよいでしょう。

今回の記事では、Python を使った署名付き URL の生成を行います。ソースコードはこんな感じです。

  • Python の実行環境上で秘密鍵 /home/ec2-user/temp/cloudfront-presign/private_key.pem が存在している
  • 署名付き URL の対象となるパス https://d31z1elfcc2o1s.cloudfront.net/mycat.jpg を指定
  • 署名付き URL の有効期限を expire_date で指定
  • アクセス元の IP アドレスを 54.250.23.0/32 と指定 (とある EC2 インスタンスのもの)
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
from botocore.signers import CloudFrontSigner
from dateutil import tz


def rsa_signer(message):
    with open('/home/ec2-user/temp/cloudfront-presign/private_key.pem', '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())


key_id = 'K1DYHGI8XWLXZL'
url = 'https://d31z1elfcc2o1s.cloudfront.net/mycat.jpg'
expire_date = datetime.datetime(
    2022, 2, 25, 22, 10, 0, 0, tz.gettz('Asia/Tokyo'))

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.
policy = cloudfront_signer.build_policy(
    url, expire_date, date_greater_than=None, ip_address='54.250.23.0/32')

signed_url = cloudfront_signer.generate_presigned_url(
    url, date_less_than=None, policy=policy)
print(signed_url)

この Python コードを実行すると、署名付き URL を生成できます

> python cloudfront-create-presign.py
https://d31z1elfcc2o1s.cloudfront.net/mycat.jpg?Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cHM6Ly9kMzF6MWVsZmNjMm8xcy5jbG91ZGZyb250Lm5ldC9teWNhdC5qcGciLCJDb25kaXRpb24iOnsiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjE2NDU4ODEwMDB9LCJJcEFkZHJlc3MiOnsiQVdTOlNvdXJjZUlwIjoiMC4wLjAuMC8wIn19fV19&Signature=RmBo1DqAyEMSQWvMgubzHs2zufS03rceMEIvv8JHkQaMyQDtuu3aLTDSyQ9eO4Oyp~lkB2QrC-KM8v21eo9i0IRWFsbY5IreNpOqo5sLc8RWL9LpKWo6~EM1ykD29SCp8fObkLBe9ed85lNLqml2kDztHCV7ebYvU7fBUGHLnsQ4n4NZjRpipDfZdMJbhjx0DWfpp5VmaKIGh0XwZxMeNbR8vMIUEKn1DHLcyLLywkzyFZaI146NvekpDgS-VqMmxBIRVOjxhXc3p8JvPoTdAEYW3Dxp7Cit~Xd1xNoO9cn6GiFQUDn9uWD1fETSzASilj8NbpIzpJXU6S1n0I57XQ__&Key-Pair-Id=K1DYHGI8XWLXZL

アクセス確認

まず、通常通りに CloudFront 経由でアクセスを試みると、想定通りにエラーになります。

image-20220225224943999.png

次に、署名付き URL で、許可された IP アドレスからアクセスすると、正常に家猫の画像が出ます。かわいい。

image-20220225223014443.png

署名付き URL の 有効期限が切れたときの結果です。想定通りエラーになります。

image-20220225223038966.png

IP アドレスを制限するための WAF

署名付きURLのカスタムポリシーでは、アクセス元の IP アドレスが指定可能ですが、1個までという制限があります。Web アプリケーションとして認証を加えたうえで、アクセス元のクライアント IP を取得し生成することで、URL が仮に漏れたとしてもアクセスを防ぐ構成も可能です。

上記とは別の方法で、WAF を利用した 複数の IP アドレス制限を加えることも可能です。WAF の構成もしてみましょう。Create IP set を押します。

image-20220225221613336.png

アクセスを許可する IP アドレスを複数入力します。

image-20220225221745226.png

IP set が作成されました。

image-20220225221801738.png

WAF の Web ACL を作成します。

image-20220225221819429.png

適当に名前を入れて、CloudFront に紐づけます。

image-20220225221951132.png

Add my own rules and rule groups を選択します。

image-20220225222133497.png

作成した IP set を選択して、Allow を選びます

image-20220225222223822.png

ルールに合致しないものは Block とすることで、指定された IP アドレス以外を防ぎます

image-20220225222256457.png

Next

image-20220225222323717.png

Next

image-20220225222335482.png

Create を押します

image-20220225222348524.png

WAF の Web ACL が作成されました

image-20220225225617750.png

アクセス確認

WAF でブロックしている IP アドレスから、署名付き URL にアクセスしてみると、想定通りアクセスができません。WAF としてのエラーとなっており、カスタムポリシーとは異なったエラーが表示されます。

image-20220225222932946.png

検証を通じてわかったこと

  • カスタムポリシーでは、アクセス元の IP アドレスを指定可能
    • ただし、カスタムポリシー上では 1 個のみ指定可能
    • IP アドレスを複数利用して制限したい場合は、WAF を利用した IP アドレス制限が検討可能

付録 : ワイルドカードで複数のファイルを配信

参考URL

AWS Document : 署名付き URL の使用
https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/private-content-signed-urls.html

Python のサンプルコード
https://github.com/boto/boto3/blob/develop/boto3/examples/cloudfront.rst

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2