AWS S3 Pre-Signed URL 초간단 사용 방법
보통 사용자가 S3 bucket에 접근해서 파일을 다운로드하거나 업로드하려면 3가지 방법이 가능합니다.
- public bucket으로 만들기 : 이렇게 구성하면 따로 관리할 필요 없이 모든 사용자가 S3 bucket에 파일을 올리거나 다운로드할 수 있습니다. 하지만 공개되서는 안 되는 파일에 대한 접근을 설정할 수 없다는 점이 단점입니다.
- IAM 자격증명 공유 : Access Key pari(access key, secret access key)를 설정해서 특정 사람만 저장소를 쓸 수 있게 제한하는 방법입니다. 하지만 관리가 힘들고 자격증명이 바뀌거나 유출될 경우 모든 사람에게 다시 key pair를 줘야 한다는 단점이 있습니다.
- IAM 사용자 역할 부여 : IAM을 통해 역할 권한을 부여합니다. 이렇게하면 지정한 사람만 저장소에 접근이 가능합니다. 하지만 여전히 관리가 불편하고 사용자 숫자 제한(5000개)이라는 제한사항이 존재합니다.
이렇게 Bucket 자체를 보안상의 이유로 공개적으로 운영하기는 좀 그렇고, 그렇다고 사용자에게 S3 접근권한을 설정하고 관리하기 버거울 때 사용하는 것이 바로 Pre-Signed Url입니다. 미리 서명된 URL이라는 의미인데요. 이 URL로 아래와 같은 일들을 할 수 있습니다.
- 발급받은 URL로 파일을 다운로드 받거나 업로드할 수 있음
- URL의 만료기간을 설정하여 만료된 이후 접근을 제한할 수 있음
굉장히 편리하겠죠?
Pre-signed Url은 아래와 같은 흐름으로 사용합니다.
- 사용자가 Pre-Signed Url 요청
- 백엔드(앱서버)에서 Pre-Signed Url 생성을 S3에 요청
- S3에서 Pre-Signed Url을 발행
- 백엔드에서 사용자에게 Pre-Signed Url 응답
- 사용자가 Pre-Signed Url로 파일 업로드/다운로드
Pre-signed URL을 쓰는 이유
Pre-signed Url은 주로 두 가지 목적으로 사용합니다.
- 보안상의 이유 : 앞에서 설명한 것처럼 완전히 Bucket을 오픈하지 않고 특정 사람에게만 공개해서 사용하기 위해 씁니다. 예를 들어, 회원 가입자나 결제한 사람에게만 특정 이미지 콘텐츠를 보여준다던지 하는 기능을 구현할 때 딱이겠죠.
- 성능상의 이유 : 단순히 보안적인 이유로만 사용하지 않습니다. 보통 이미지 업로드를 비롯한 파일 업로드는 서버를 거치도록 구현합니다. 저장소에 서비스 관련 민감한 정보들이 저장될 수 있어 사용자가 직접 저장소에 접근하는 것은 보안적으로 문제가 발생할 가능성이 높기 때문이죠. 그래서 파일이 서버를 한번 거쳐서 S3에 저장되는 이중 작업을 해야 합니다.
하지만 위에서처럼 서버에서는 Pre-Signed Url만 발행해 주고 사용자가 해당 Url을 통해서만 파일을 업로드하게 되면 앞의 이중작업이 필요 없게 됩니다. 훨씬 효율적이죠.
Pre-Signed Url 발급하기
"""
클라이언트에서 AWS S3 업로드를 위한 Pre-signed Url을 생성하는 메서드
"""
@classmethod
def get_pre_signed_url(cls, file_name: str, service_name: str, exp_time: int = 300) -> str:
s3_client = boto3.client('s3')
try:
object_key = service_name + "/" + file_name
response = s3_client.generate_presigned_url(
ClientMethod='put_object',
Params={
'Bucket': BUCKET_NAME_CONTENTS,
'Key': object_key
},
ExpiresIn=exp_time
)
return response
except StorageError as e:
raise e
위 예제는 python에서 boto3(Python용 AWS SDK) 활용해서 Pre-signed Url을 생성하는 것인데요.
Url 생성 메서드가 boto3에 있기 때문에 아주 쉽습니다. 다만, 들어가는 Parameter에 대해서는 제대로 알 필요가 있죠.
generate_presigned_url 메서드에는 총 3개의 Parameter가 들어갑니다.
- Client Method : 사용자가 어떤 작업을 할 것인지 의미하는 Param. put_object는 파일 업로드, get_object는 파일 가져오기를 의미합니다. 또, URL을 통해 요청을 보낼 때 설정한 HTTP Method로 보내야 합니다. 예를 들어, put_object로 URL을 생성했다면 PUT Method로 요청을 보내야합니다.
- Params : S3 Bucket에 대한 정보와 파일이 저장될 키값(파일 이름)을 설정합니다.
- ExpiresIn : URL 만료 시간을 설정합니다. 단위는 초입니다.
위 메서드를 실행하면 Pre-Signed Url이 리턴되게 됩니다.
Postman으로 이미지 업로드 해보기
이제 Pre-Signed Url을 받았으면 실제로 사용해 봐야겠죠?
해당 Url로 Postman을 통해 요청을 보내보겠습니다. PUT 메서드로 이미지 파일을 업로드해볼 건데요.
파일을 업로드할 때 HTTP 요청의 Body에 파일을 Binary 형태로 담아서 보내게 됩니다.
위처럼 URL을 적고 알맞은 HTTP Method를 선택한 뒤, Body > binary를 선택합니다. 그럼 Select files 버튼이 나오는데 이걸로 보내려는 파일을 선택합니다. 그리고 요청을 보내면 200 OK 응답이 오게 됩니다.
만약, 403 에러가 뜬다면 2가지 가능성이 있는데요.
- URL이 만료된 경우 : 만료시간을 너무 짧게 설정해서 이미 사용할 수 없는 상태일 수 있습니다.
- 잘못된 권한 접근인 경우 : 예를 들어 파일 가져오기(get_object)를 설정해서 URL을 생성했는데 막상 요청은 PUT으로 보내게 되면 설정 내용이 다르다며 실행이 거부됩니다.