TIL no.83 - AWS - Django - S3 multiple file Upload

박준규·2019년 11월 20일
5

AWS S3 서비스를 이용해 image를 upload하는 End-Point를 만드려고 합니다.

이를 위해 준비사항은 다음과 같습니다.

1. AWS IAM

AWS IAM(Identity and Access Management)이란 AWS resource 보안 서비스입니다.
AWS 서비스와 리소스에 대한 액세스를 안전하게 관리할 수 있습니다.

  • IAM 정책 setting
  • [STEP 1] IAM 정책 페이지에서 새로운 정책 생성
  • [STEP 2] 새로운 permission policy를 추가하는 페이지에서 JSON 탭으로 이동해서 다음의 JSON을 입력
{
        "Version": "2012-10-17",
        "Statement": [
            {
                "Sid": "VisualEditor0",
                "Effect": "Allow",
                "Action": [
                    "s3:PutObject",
                    "s3:GetObjectAcl",
                    "s3:GetObject",
                    "s3:ListBucket",
                    "s3:DeleteObject",
                    "s3:PutObjectAcl"
                ],
                "Resource": [
                    "arn:aws:s3:::example-bucket-name/*",
                    "arn:aws:s3:::example-bucket-name"
                ]
            }
        ]
    }

example-bucket-name 부분은 나중에 S3 bucket을 생성했을때,
해당 S3 bucket이름으로 바꾸어줍니다.

  • [STEP 3] 정책 이름과 설명 추가

  • [STEP 4] 정책 생성

  • User 생성

  • [STEP 1] IAM dashboard에서 사용자 클릭

  • [STEP 2] 사용자 추가 버튼 클릭

  • [STEP 3] Programmatic Access 항목 체크

  • [STEP 4] 만들어 놓은 정책을 선택하고 다음으로 넘어가기

  • [STEP 5] PASS

  • [STEP 6] PASS

  • [STEP 7] 새로운 유저 생성이 완료되면 “Download.csv” 버튼을 클릭해서 유저의 “Access Key ID”와 “Secret Access Key”를 다운로드 받기(이때 다운 받지 않으면 다시 다운로드 받을 수 없으므로 꼭 다운로드 받아야 함)

2. AWS S3 Bucket

Amazon S3 bucket 이란,
public cloud storage resource입니다.

Amazon S3 buckets는 object를 저장합니다.
object는 data와 descriptive metadata로 구성됩니다.

file folder와 같은 역할을 합니다.

  • AWS S3 bucket setting

  • [STEP 1 ~ 2] AWS S3 페이지로 가서 “Create bucket” 버튼을 클릭한 후 버켓 이름과 region을 선택

  • [STEP 3] “Block all public access”를 uncheck

  • [STEP 4 ~ 5] 버켓 생성이 완료되면 해당 버켓을 클릭해서 버켓의 설정 페이지로 이동

  • [STEP 6] 상단의 “Permission(권한)” 탭에서 “Bucket Policy(버킷 정책)” 탭을 눌른 후 다음의 JSON을 입력

    {
       "Version": "2012-10-17",
       "Statement": [
           {
               "Sid": "Stmt1507637373230",
               "Effect": "Allow",
               "Principal": {
                   "AWS": "{user_arn}"
               },
               "Action": [
                   "s3:GetObject",
                   "s3:PutObject",
                   "s3:DeleteObject"
               ],
               "Resource": "arn:aws:s3:::{bucket_name}/*"
           },
           {
               "Sid": "Stmt1507637391106",
               "Effect": "Allow",
               "Principal": "*",
               "Action": "s3:GetObject",
               "Resource": "arn:aws:s3:::{bucket_name}/*"
           }]
    }

    {user_arn} 은 IAM user의 ARN,
    {bucket_name}은 bucket의 이름입니다.
    IAM 유저의 ARN은 IAM 페이지 -> users 페이지 -> 해당 유저를 클릭하면
    나오는 페이지에서 확인 할 수 있습니다.

  • [STEP 6] save 버튼 클릭
    Public access warning은 일단 무시하겠습니다. 원칙적으로는 S3는 public access를 주지 않는것이 보안상 좋습니다. S3는 private하게 막고 S3 앞에 CloudFront를 붙여 CDN 기능을 구현하는것이 정석입니다.

  • [STEP 7] “CORS configuration” 버튼을 눌러서 아래와 같이 CORS 설정 후 save

    <?xml version="1.0" encoding="UTF-8"?>
    <CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <ExposeHeader>ETag</ExposeHeader>
    <AllowedHeader>*</AllowedHeader>
    </CORSRule>
    </CORSConfiguration>

3. Django

이제 기본적인 준비는 끝났습니다.
이제 formdata를 보내면 url로 돌려주는 End-Point를 만들어 보겠습니다.

그전에 python용 AWS 라이브러리인 boto3가 필요합니다.

pip install boto3

boto3를 설치하고 다음과 같이 view를 작성합니다.

import boto3

class FileToURL(View):
    s3_client = boto3.client(
            's3',
            aws_access_key_id={aws_access_key_id},
            aws_secret_access_key={aws_secret_access_key}
        )
    def post(self, request):

        for file in request.FILES.getlist('file'): 
            self.s3_client.upload_fileobj(
                file,
                {bucket-name},
                file.name,
                ExtraArgs={
                    "ContentType": file.content_type
                }
            )
            
        file_urls = [f"https://s3.ap-northeast-2.amazonaws.com/{bucket-name}/{file.name}" for file in request.FILES.getlist('file')]

        return JsonResponse({'files':file_urls}, status=200)

{aws_access_key_id}와 {aws_secret_access_key}는
1. AWS IAM에서 사용자를 생성하고
다운로드 받은 credentials.csv 파일에서 확인할 수 있습니다.

file_url에서 {bucket-name}은 2. AWS S3 Bucket에서 생성한 Bucket의 이름을 적어주면 됩니다.

또한, Front-End에서 Back-End API로 formdata를 보내게 되면
request.FILES에 file들이 담겨오게되는데
이때, request.FILES는 MultiValueDict 입니다.

MultiValueDict의 경우, getlist(key) 메서드를 사용해서 value에 해당하는 list를 받아올 수 있습니다.

profile
devzunky@gmail.com

5개의 댓글

comment-user-thumbnail
2020년 4월 7일

간단하고 명쾌하게 정리를 너무 잘해주셔서 큰 도움 되었습니다.
감사합니다.

1개의 답글
comment-user-thumbnail
2020년 7월 25일

순서대로 차근차근 설명해주셔서 많은 도움이 됐습니다. 감사합니다!!

1개의 답글
comment-user-thumbnail
2022년 8월 23일

덕분에 간단하게 구현하고 큰도움이 되었습니다! 정말 감사합니다~~ :)

답글 달기