• [Cognito] 사용자별 파일 접근하기 :: 마이구미
    AWS 2019. 11. 4. 22:52
    반응형
    이번 글은 AWS 의 S3, Congito 서비스를 이용한 하나의 예를 다뤄본다.
    간단하게 S3 는 스토리지, Congito 는 사용자 관리를 할 수 있다.
    두 서비스를 사용한 간단한 하나의 예로, 각 사용자만 접근할 수 있는 스토리지를 만들어 관리할 수 있다.
    S3 - https://aws.amazon.com/ko/s3/
    Cognito - https://aws.amazon.com/ko/cognito/
    Example Code - https://github.com/hotehrud/cognito_s3

     

    글에서 다루는 내용에 대한 예제 코드가 존재한다.

    예제 코드를 사용하기 위해서는 AWS 서비스 설정을 해주어야한다.

    그리고 나서 필요한 값들을 관련 config 파일에 넣어주면 된다.

    자세한 서비스 설정은 다루지 않더라도, 글을 읽는다면 예제 코드를 사용하는 것은 크게 어려움이 없을 것이다.

     


    글의 목적을 이해하기 위해 예를 들어본다.

     

    파일 업로드하는 기능이 있는 서비스를 만든다고 가정한다.

    이를 위해 웹 서버와 스토리지 서버를 나누어서 관리하고 있다.

    그렇다면 사용자가 업로드를 시도했을 경우, 대부분 다음과 같은 순서로 처리될 것이다.

     

    사용자 -> 웹 서버 -> 스토리지 서버

     

    위와 같은 경우는 웹 서버를 거치기 때문에 대역폭 증가와 같은 문제가 발생한다.

    사용자가 웹 서버를 거치지 않고, 직접 스토리지 서버에 요청할 수 있으면 이러한 문제를 해결할 수 있다.

     

    사용자 -> 스토리지 서버

     

    사용자가 직접 스토리지 서버에 접근하는 것이 크게 문제가 없어보인다.

    하지만 업로드 기능이 프라이빗한 성격을 가진다면, 인증이라는 행위가 필요하다.

    결과적으로, 웹 서버를 거치기 않아야하기 때문에 인증을 웹 서버없이 할 수 있어야한다.

     

    만약 이것이 가능하다면, 우리는 아래처럼 스토리지 서버에 접근을 쉽게 생각할 수 있다.

     

    • public/* 경로에 파일들을 존재하고, 모두가 접근할 수 있는 권한을 가진다.
    • private/{USER}/* 경로에는 각 사용자에 따른 파일들이 존재하고, 그 사용자만이 접근할 수 있는 권한을 가진다.

     

    스토리지에서 경로를 public/ 과 private/{각 사용자 ID}/ 로 나누어서, 원하는 상황에 따라 접근하면 된다.

    이와 같은 상황은 AWS 의 S3 와 Cognito 를 이용한 예제 중 하나이고, 간단하게 구현할 수 있다.

    프라이빗 접근이 필요할 경우에 각 사용자는 인증을 Cognito 를 통해 가져올 수 있다.

    즉, Cognito 는 인증 서버 행위를 해준다.

    결과적으로 이러한 요구사항을 웹 서버없이, Cognito 와 S3 를 통해 가능하게 된다.

    Cognito 를 통해 인증을 처리하여 마치 웹 서버없이, 클라이언트 사이드에서 하는 것처럼 동작할 수 있다.

     

    이 글에서는 이러한 예제를 실제로 구현해볼 것이다.

    예제 코드의 시나리오는 모든 로그인/비로그인 사용자가 공유할 수 있는 앨범이 있고, 각 로그인 사용자는 각자의 프라이빗한 앨범을 가진다.

    예를 들어 사용자 A, B, C 가 존재하고, 파일들이 존재한다고 가정하면 다음과 같다.

     

    public/logo.png
    private/A/apple.png
    private/B/pear.png
    private/C/grape.png

     

    위와 같은 파일 형태가 존재한다면, 다음을 의미한다.

     

    • public/logo.png 는 누구라도 접근할 수 있다.
    • private/A/apple.png 는 A 라는 사용자만 접근할 수 있다.
    • private/B/pear.png 는 B 라는 사용자만 접근할 수 있다.
    • private/C/grape.png 는 C 라는 사용자만 접근할 수 있다.

     

    예제 코드를 사용하기 위해서는 src/config/s3.js 에 설정 값을 본인의 AWS 설정에 맞게 바꿔줘야한다.

     

    const obj = {
      BUCKET_NAME: '', // S3 Bucket
      AWS_REGION: '', // AWS Region
      COGNITO_IDENTITY_POOL_ID: '', // Identity Pool Id
      COGNITO_USER_POOL_ID: '', // User Pool Id
      COGNITO_CLIENT_ID: '' // App Client Id
    };

     

     

    AWS 설정을 완료하고, 필요한 설정값을 맞게 넣는다면 문제없이 동작할 것이다.

    예제 코드는 React 와 AWS Amplify 를 사용한다.

     

    우선 사용하는 AWS 서비스 셋팅 방법을 알아본다.

    큰 범위에서는 다음과 같다.

     

    1. S3 - Bucket 생성
    2. Cognito - User pool 생성
    3. Cogntio - Identity Pool 생성
    4. Identity Pool authenticated/Unauthenticated role 을 위한 IAM 정책 설정.

     

    우선 S3 Bucket 을 생성한다.

    예제는 다른 설정은 필요없이 생성만 해도 무방하다.

    단지 생성한 Bucket 이름을 config 파일에 넣어주면 된다.

     

    그리고 나서 Cognito 서비스를 셋팅한다.

    다시 말하면, 회원가입, 로그인 등 사용자 관리를 위한 설정을 한다.

     

     

    우선 User Pool 을 생성한다.

    Cognito 는 Google, Facebook 과 같은 소셜 로그인 연동도 가능하지만, 여기서는 자체 Cognito 로그인만을 사용한다.

    User Pool 생성하면, 기본 셋팅이 아닌 단계별 셋팅을 통해 본인이 원하는 대로 설정할 수 있다.

     

    * 이메일을 통해 인증하면, 회원가입이 완료된다.

     

    설정은 크게 상관없으니, 본인이 원하는대로 하면 된다.

    최종적으로 user pool 을 생성했다면, App client 추가해주고, Domain Name 을 설정해준다.

     

     

    App client Id 를 얻기 위해 App Client 를 추가해줘야하고, 여기서는 다른 설정을 손댈 필요없다.

    Cognito 에서 제공해주는 로그인 기능을 사용하기 위해서는 Domain name 설정이 꼭 필요하다.

     

    그리고 나서 Federated Identities 를 통해 Identity Pool 을 생성한다.

    Identity Pool 의 미인증/인증에 관련된 설정들을 볼 수 있다.

     

     

    Identity pool 을 생성하면 위와 같은 이름(Cognito_cognito_s3Unauth_Role) 으로 IAM 에 Role 이 만들어진다.

    다음과 같이 생성된 role 이 존재한다.

     

     

    생성된 role 을 통해 S3 에 접근하는 정책을 설정해줄 것이다.

    이 정책은 위에서 언급한 public/private 에 대한 접근을 의미한다.

     

    각 Role 을 클릭한 후, Add inline policy 버튼을 통해 정책을 추가할 수 있다.

    우리는 S3 에 관련된 정책을 추가할 것이다.

     

     

    비로그인 사용자 S3 정책(Unauth)

    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Sid": "GetBucketListIfRequestIsForUser",
                "Action": [
                    "s3:ListBucket"
                ],
                "Effect": "Allow",
                "Resource": [
                    "arn:aws:s3:::cognito.s3"
                ]
            },
            {
                "Effect": "Allow",
                "Action": [
                    "s3:DeleteObject",
                    "s3:GetObject",
                    "s3:PutObject"
                ],
                "Resource": [
                    "arn:aws:s3:::{BUCKET_NAME}/public/*"
                ]
            }
        ]
    }

     

    로그인 여부와 상관없이 모든 살용자는 public 경로를 사용할 수 있다.

    위처럼 public 안에 있는 리스트를 접근하기 위해 ListBucket 과 함께 public/* 에 GetObject, PutObject, DeleteObject 권한을 가진다.

    * {BUCKET_NAME} 은 생성된 Bucket 이름을 넣으면 된다. ex) arn:aws:s3:::cognitoExample/public/*

     

    로그인 사용자 S3 정책(Auth)

     

    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Sid": "GetBucketListIfRequestIsForUser",
                "Action": [
                    "s3:ListBucket"
                ],
                "Effect": "Allow",
                "Resource": [
                    "arn:aws:s3:::{BUCKET_NAME}"
                ]
            },
            {
                "Sid": "AllowAccessToPrivateCognitoUserFolder",
                "Effect": "Allow",
                "Action": [
                    "s3:GetObject",
                    "s3:PutObject",
                    "s3:DeleteObject"
                ],
                "Resource": [
                    "arn:aws:s3:::{BUCKET_NAME}/public/*",
                    "arn:aws:s3:::{BUCKET_NAME}/private/${cognito-identity.amazonaws.com:sub}",
                    "arn:aws:s3:::{BUCKET_NAME}/private/${cognito-identity.amazonaws.com:sub}/*"
                ]
            },
            {
                "Condition": {
                    "StringLike": {
                        "s3:prefix": [
                            "public/",
                            "public/*",
                            "private/${cognito-identity.amazonaws.com:sub}/",
                            "private/${cognito-identity.amazonaws.com:sub}/*"
                        ]
                    }
                },
                "Action": [
                    "s3:ListBucket"
                ],
                "Resource": [
                    "arn:aws:s3:::{BUCKET_NAME}"
                ],
                "Effect": "Allow"
            }
        ]
    }

     

    로그인 사용자는 비로그인 사용자가 갖는 권한과 동일하면서, 추가적으로 각자의 private 경로에 폴더 접근 권한을 가진다.

    ${cognito-identity.amazonaws.com:sub} 는 각 사용자의 로그인 ID 가 아닌 identityId 를 의미한다.

    즉, 실제 경로는 다음과 같은 형태를 의미한다.

     

     

    결과적으로, 각 사용자는 private 경로 본인의 identityId 를 갖는 폴더에만 접근할 수 있다.

    웹 서버를 두지 않고도 많은 경우에서 실제로 편하고 쉽게 구현하여 사용할 수 있다.

     

    예제 코드는 Amplify 공식 문서를 통해 쉽게 이해할 수 있어 설명을 생략한다.

    https://aws-amplify.github.io/docs/js/storage

     

    src/js/s3.js
    src/js/amplify.js

     

    단순히 동작을 위한 코드로써, 상단에 존재하는 예제 링크를 참고하면 된다.

     

    반응형

    댓글 2

Designed by Tistory.