CloudFrontでS3の署名付きURLを発行する


CloudFrontでS3の署名付きURLを発行する方法です。

暗号鍵、公開鍵の生成

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

CloudFrontキーグループに公開鍵の追加

ここはAWSコンソールで作成するだけなので割愛します。

SecretsManagerに暗号鍵を登録

今回、作成した暗号鍵はシークレットキーに保存し、Lambdaから取得します。
AWSコンソールを利用して暗号鍵を貼り付けると値がおかしくなるようなので
AWS CLIを利用し登録します。

aws secretsmanager create-secret --name <シークレット名> --secret-string file://private_key.pem --region ap-northeast-1

署名付きURLの発行(Lambda)

import json, base64, sys, re, datetime
import boto3
from botocore.exceptions import ClientError
from botocore.signers import CloudFrontSigner
sys.path.append('/opt/')
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

def lambda_handler(event, context):
    cloudfront_signer = CloudFrontSigner('yourKeyId', rsa_signer)
    url = 'CloudFrontURI'
    expire_date = datetime.datetime(2021, 9, 15)
    #署名付きURLの発行
    signed_url = cloudfront_signer.generate_presigned_url(url, date_less_than=expire_date)
    return {
        'statusCode': 200,
        'headers': {
            'Access-Control-Allow-Headers': 'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token',
            'Access-Control-Allow-Origin': '*',
            'Access-Control-Allow-Methods': 'OPTIONS,POST,GET'
        },
        'body': signed_url
    }

def rsa_signer(message): 
    secret_name = "yourSecretname"
    region_name = "ap-northeast-1"
    session = boto3.session.Session()
    client = session.client(
        service_name='secretsmanager',
        region_name=region_name
    )
    get_secret_value_response = client.get_secret_value(
        SecretId=secret_name
    )
    cloudfront_pk_text = get_secret_value_response['SecretString']
    cloudfront_pk_bytes = str.encode(cloudfront_pk_text, encoding='ascii')
    cloudfront_pk = serialization.load_pem_private_key(cloudfront_pk_bytes, password=None, backend=default_backend())
    return cloudfront_pk.sign(message, padding.PKCS1v15(), hashes.SHA1())