#amazon-web-services #aws-lambda #boto3 #amazon-cloudfront #aws-lambda-edge
Вопрос:
Я пытаюсь сгенерировать URL-адрес под председательством s3. Логика для этого написана в Lambda@Edge, python 3.7
def lambda_handler(event, context):
request = event['Records'][0]['cf']['request']
headers = request['headers']
s3 = boto3.client('s3',config=Config(signature_version='s3v4'))
url = s3.generate_presigned_url(ClientMethod='get_object',
Params={'Bucket': 'BUCKET_NAME',
'Key':'abc.jpeg'
},
ExpiresIn=3600)
response = {
'status': '302',
'statusDescription': 'Found',
'headers': {
'location': [{
'key': 'Location',
'value': url
}]
}
}
return response
Когда я тестирую этот код в простой Лямбде, я получаю разные URL-адреса для каждого вызова. Но если я добавлю cloudfront и вызову доменное имя cloudfront, то тот же URL-адрес будет сгенерирован до истечения срока действия URL-адреса.
Почему я не получаю разные URL-адреса для каждого вызова, как в случае 1?
Комментарии:
1. Не могли бы вы показать свою процедуру генерации URL-адресов с предварительной подписью CloudFront? Я получаю разные URL-адреса просто отлично, используя Boto3.
Ответ №1:
Вам нужно создать подписывающее лицо для CloudFront и использовать generate_presigned_url
его от подписывающего лица. Этот фрагмент кода генерирует разные URL-адреса каждый раз, когда я пытаюсь.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
from datetime import datetime, timedelta
from botocore.signers import CloudFrontSigner
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.asymmetric import padding
from cf_url_gen.config import Bucket, Operation, config
class CFClient(object):
"""CloudFront client class
Creates a CloudFront client object for generting S3 resource URLs.
"""
def __init__(
self,
cf_key_id: str = os.getenv("CF_KEY_ID"),
cf_key_path: str = os.getenv("CF_KEY_PATH"),
cf_ttl_sec: int = 300,
):
"""The __init__ method for CFClient class
Args:
cf_key_id (str, optional): CloudFront key id, can be set via environment variable `CF_KEY_ID`
cf_key_path (str, optional): CloudFront key path, can be set via environment variable `CF_KEY_PATH`
cf_ttl_sec (int, optional): URL validity duration from UTC timestamp, default value 300 seconds
"""
with open(cf_key_path, "rb") as key_file:
_key = serialization.load_pem_private_key(key_file.read(), password=None, backend=default_backend())
self.signer = CloudFrontSigner(cf_key_id, lambda m: _key.sign(m, padding.PKCS1v15(), hashes.SHA1()))
self.ttl = cf_ttl_sec
def get_url_with_prefix(self, file_path: str, url_prefix: str, is_signed: bool = True) -> str:
"""Method for generating CloudFront URLs for file paths with given url prefix
Args:
file_path (str): Full file path in S3 bucket excluding bucket name
url_prefix (str): URL prefix to use for signing or generating S3 resource URL
is_signed (bool): Flag indicating whether URL should be signed or not
Returns:
CloudFront url string based on provided signing options
"""
if not is_signed:
return os.path.join(url_prefix, file_path)
else:
end_date = datetime.utcnow() timedelta(seconds=self.ttl)
file_url = os.path.join(url_prefix, file_path)
return self.signer.generate_presigned_url(file_url, date_less_than=end_date)
Примечание. Префиксом URL-адреса должен быть URL-адрес домена CloudFront для вашей корзины S3, обычно что-то вроде https://bucketname.yourdomain.com или что-то подобное.