[aws] boto3 이용한 presigned url 만들기 - troubleshooting

Seunghyun Moon·2024년 1월 2일
0

aws

목록 보기
5/5

AWS Presigned URL 이란?

AWS Presigned URL 이란?
A user who does not have AWS credentials or permission to access an S3 object can be granted temporary access by using a presigned URL.

오늘의 이슈

요즘 진행하는 프로젝트에서 AWS S3 를 활용해 이미지 데이터를 처리할 일이 생겼다.
AWS S3에서 presigned url 생성 중 겪은 에러 처리 방법을 공유한다.

boto3 documentation에 친절하게 설명과 생성 함수까지 작성해준다.

import logging
import boto3
from botocore.exceptions import ClientError


def create_presigned_url(bucket_name, object_name, expiration=3600):
    """Generate a presigned URL to share an S3 object

    :param bucket_name: string
    :param object_name: string
    :param expiration: Time in seconds for the presigned URL to remain valid
    :return: Presigned URL as string. If error, returns None.
    """

    # Generate a presigned URL for the S3 object
    s3_client = boto3.client('s3')
    try:
        response = s3_client.generate_presigned_url('get_object',
                                                    Params={'Bucket': bucket_name,
                                                            'Key': object_name},
                                                    ExpiresIn=expiration)
    except ClientError as e:
        logging.error(e)
        return None

    # The response contains the presigned URL
    return response

바로 적용해본다.
내가 작성한 코드 스니펫

def init_aws_session():
    
    return boto3.Session(region_name=AWS_REGION,
                         aws_access_key_id=ACCESS_KEY_ID,
                         aws_secret_access_key=ACCESS_SECRET_KEY)
def test2():

    session = init_aws_session()
    s3 = session.client('s3')
    res = s3.list_objects_v2(Bucket=BUCKET_NAME)
    
    return [create_presigned_url(bucket_name=BUCKET_NAME, object_name=obj_key) for obj_key in [obj['Key'] for obj in res['Contents']]]

아래와 같은 리스트가 리턴된다.

리턴된 presigned url 예시

https://test-1219moonpasha.s3.amazonaws.com/testimage.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAW2ZRGBEP352EIVE5%2F20240102%2Feu-south-2%2Fs3%2Faws4_request&X-Amz-Date=20240102T151219Z&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=35f171d1400098b6c49dab88437d7ed5b28ac575e49fb21d3b1ccf79bf368ef2

확인해보니 IllegalLocationConstraintException 에러가 나면서 접근이 안된다.



원인 분석

검색에 들어간다.
검색 해보니 문제 원인은 아래 중 하나일 것 같다.
1. 권한 문제
2. boto3 클라이언트의 리전과 S3 버킷의 리전이 달라서 생기는 문제.

이번 경우는 2번이었다.
나의 로직에서는 init_aws_session() 함수를 사용할 때 리전을 특정해준다. 그래서 리전 문제는 아닌줄 알아서 약간 헤맸다. 알고보니 AWS에서 제공해 준 create_presigned_url() 을 그대로 가져다 쓰다 보니, boto3 클라이언트를 두번 사용했고, 두번째 클라이언트 사용 시에 리전이 특정이 안됐었다.
코드 수정.

def create_presigned_url(bucket_name, object_name, expiration=3600):
    """Generate a presigned URL to share an S3 object

    :param bucket_name: string
    :param object_name: string
    :param expiration: Time in seconds for the presigned URL to remain valid
    :return: Presigned URL as string. If error, returns None.
    """

    # Generate a presigned URL for the S3 object
    session = init_aws_session()
    s3 = session.client('s3', region_name=AWS_REGION, endpoint_url=S3_ENDPOINT_URL)

    try:
        response = s3.generate_presigned_url('get_object',
                                                    Params={'Bucket': bucket_name,
                                                            'Key': object_name},
                                                    ExpiresIn=expiration)
    except ClientError as e:
        logging.error(e)
        return None

    # The response contains the presigned URL
    return response

다시 생성된 presigned url 확인해보니 정상 작동된다.

https://s3.eu-south-2.amazonaws.com/test-1219moonpasha/testimage.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAW2ZRGBEP352EIVE5%2F20240102%2Feu-south-2%2Fs3%2Faws4_request&X-Amz-Date=20240102T151001Z&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=c466cf5350a06477673c9d0e6cdd2c5f47d29ecae013df958e7a1251b7e04e98

결과 분석

반환된 url을 확인해본다. 다행히 파라미터는 같았지만 요청하는 url이 달랐다.
제대로 만들어진 url은
s3.{region}.amazonaws.com/{bucket_name}/{object_key}
형식이다.


profile
I live fullest

0개의 댓글