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를 받아올 수 있습니다.