CloudFrontの署名付きURLを使用してプライベートなファイルを配信する
CloudFront 署名付きURLの利用
CloudFrontの署名付きURLを利用することで、プライベートなファイルの配信ができる
署名付きURLを利用する場合は、URLにクエリ文字列として署名が付与され、その署名が検証できない限りは 403 Forbidden となる
URLを知っている人のみがアクセスでき、また署名付きURLには有効期限がある
署名付きURLの利用手順
- 署名、検証のためのキーペアを作る
RSAキーペアを作る
openssl genrsa -out private_key.pem 2048
openssl rsa -pubout -in private_key.pem -out public_key.pem
キーペアは以下の制約がある
- SSH-2RSA キーペアである必要があります。
- base64 エンコードされた PEM 形式である必要があります。
- 2048 ビットのキーペアである必要があります。
最初4096ビットで作っていて署名に失敗してハマっていた
4096ビットの鍵で署名しようとすると以下のようなエラーになる
Your request contains empty/invalid/out of limits RSA Encoded Key
- CloudFrontにパブリックキーを登録する
- パブリックキーをCloudFrontキーグループに登録する
キーグループを作成しておくと、キーの更新が簡単になる
https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/private-content-trusted-signers.html#choosing-key-groups-or-AWS-accounts
- CloudFrontでの配信URLを署名する
aws cloudfront sign \
--url https://<distribution url>/<path> \
--key-pair-id <key pair id> \
--private-key file://private_key.pem \
--date-less-than YYYYMMDDTHH:mm:dd+09:00
署名付きURLが生成される
このURLにブラウザなどでアクセスするとファイルが見えるはず
--date-less-than
で署名の有効期限を設定でき、この日時を超えるとアクセスが無効になる
署名をする際は cloudfront:GetPublicKey
ポリシーが必要
- (おまけ)boto3で署名する
from botocore.signers import CloudFrontSigner
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
def rsa_signer(message):
private_key = serialization.load_pem_private_key(private_key_pem.encode(), password=None)
return private_key.sign(message, padding.PKCS1v15(), hashes.SHA1())
cloudfront_signer = CloudFrontSigner(cloudfront_key_id, rsa_signer)
url = f'https://{domain_name}/{path}'
expire_date = datetime.now() + timedelta(minutes=30)
signed_url = cloudfront_signer.generate_presigned_url(url, date_less_than=expire_date)
署名付きURLを利用するCloudFront環境をcdkで作る
// parameter store に 公開鍵を登録している
const publicKey = ssm.StringParameter.fromStringParameterAttributes(this, 'PublicKey', {
parameterName: props.signingPublicKeySsmParameterName,
});
// parameter storeの公開鍵からCloudFrontパブリックキーを作成
const cloudfrontPublicKey = new cloudfront.PublicKey(this, 'CloudfrontPublicKey', {
encodedKey: publicKey.stringValue,
});
// CloudFrontパブリックキーからキーグループを作成
const keyGroup = new cloudfront.KeyGroup(this, 'KeyGroup', {
items: [ cloudfrontPublicKey ],
});
// trusterdKeyGroups としてキーグループを指定してCloudFront distribution を作成
// 署名されたURL以外でのアクセスを拒否するようになる
const distribution = new cloudfront.Distribution(this, 'Distribution', {
defaultBehavior: {
origin: new cloudfrontOrigins.S3Origin(bucket),
trustedKeyGroups: [ keyGroup ],
},
domainNames,
certificate: cloudfrontCertificate,
});