CloudFront에 signedCookie 적용하기

2024.02.25

서명된 쿠키(signed cookie)를 이용한 private content 적용하기

이 포스트는 지난번에 작성했던 CloudFront 에서 private content 제공하기 에서 이어집니다.
포스팅의 내용은 정확하지 않을수 있습니다.

지난번에 대략적으로 설명했던 private content 설정하기에서 서명된 쿠키를 적용하여 인증된 사람들한테만 컨텐츠를 제공하는 기능을 적용해본 후기글이다. 지난번 포스트에서는 서명된 url만 사용했봤었는데(사실 틀린내용도 있었음) 이번엔 사용 안해봤던 쿠키를 적용한 방법도 사용해 보고 지난 포스트에서 틀린내용들을 수정하여 소개한다.

cloudFront에 서명자 추가하기

기본적인 S3와 클라우드프론트를 생성하는 내용은 생략하고 클라우드프론트에 서명자를 추가하는 내용부터 설명하겠다. 클라우드프론트의 서명자가 무엇인지 궁금하다면 이전 포스트에서 클라우드프론트에 서명자 추가하기 부분을 읽어보자.

RSA 키 페어 생성하기

openSSL을 사용하여 private_key.pem 파일을 생성한다.

openssl genrsa -out private_key.pem 2048

생성된 private_key.pem 파일로 public_key.pem 파일을 생성한다.

openssl rsa -pubout -in private_key.pem -out public_key.pem

순서대로 명령어를 실행했다면 디렉토리에 private_key.pempublic_key.pem 파일이 생기것이다.

cloudFront에 퍼블릭 키 와 키 그룹 생성하기

위에서 생성한 퍼블릭 키를 클라우드프론트에 등록해야한다. aws 콘솔의 cloudFront 페이지에서 키 관리/퍼블릭 키 메뉴에 들어가서 퍼블릭 키를 생성한다.


create public key


키 값은 pem 파일에 있는 내용 그대로 붙여넣는다.


public key id


키 생성이 완료되면 ID 값을 기억해두자 나중에 서명된 쿠키를 생성할때 사용된다.
다음으로 생성한 퍼블릭 키로 키 그룹을 생성한다.


create key group


cloudFront 동작 수정하기

키 그룹까지 생성했다면 클라우드프론트의 동작에 키 그룹을 적용해야한다.
키 그룹을 적용하기 전에 먼저 클라우드프론트의 컨텐츠에 접근 가능한지 확인해보자.


cloudFront access test1


키 그룹을 적용하기전 아무나 접근이 가능한 상태이다.

키 그룹을 적용하려면 배포된 클라우드프론트의 동작 편집에 들어가서 뷰어 액세스 제한을 yes로 선택하고 아까전에 생성했던 키 그룹을 등록한다.


viewer access setting


해당 변경 사항을 저장하고 나면 이제 클라우드프론트에선 서명된 url 이나 서명된 쿠키를 가지고 있어야만 정상적으로 응답을 내려준다.
다시 클라우드프론트를 확인해보자.


cloudFront access test2


쿼리에 키페어 파라미터(서명된 url)나 쿠키를 요구하고있다.

aws-sdk를 이용한 서명된 쿠키 생성하기

이제 aws-sdk를 이용하여 쿠키를 생성해보자. @aws-sdk/cloudfront-signer 패키지를 설치한다.

npm i @aws-sdk/cloudfront-signer

해당 패키지의 getSignedCookies() 메소드를 사용하여 쿠키를 생성하는데 아래와 같은 접근 제한 옵션을 설정할수있다.

  • ipAdress 접근가능한 ip의 범위를 지정한다 192.168.0.0/24 와 같은 문자열로 작성한다.
  • dateGreaterThan 접근 가능한 시작 시간을 지정한다. dateString 문자열로 지정한다.
  • dateLessThan 만료 시간을 지정한다. greaterThan 과 마찬가지로 dateString 문자열로 지정한다.

getSignedCookies() 메소드를 호출할때 두가지 방법으로 옵션을 지정할수 있는데 하나는 메소드의 파라미터로 옵션을 전달하는 방법과 다른하나는 옵션을 json 형태의 문자열로 직접 작성해서 전달하는 방법이다. 솔직히 굳이 왜 이렇게 만들어놓은건진 모르겠지만 아무튼 편한 방법대로 선택해서 쓰자.

파라미터로 정책 적용 하는 방법

getSignedCookie

import { getSignedCookies } from "@aws-sdk/cloudfront-signer";

//클라우드프론트의 url
const cloudfrontDistributionDomain = "https://{본인의 클라우드프론트 주소}";
//접근할 파일 이름(주소) 파일이 s3에서 특정폴더안에 있다면 '/folder/test.png' 로 적는다
//만약 특정 폴더 전체를 허용하려면 /folder 와 같이 폴더 까지만 쓸수도 있다.
const objectKey = "test.png";
const url = `${cloudfrontDistributionDomain}/${objectKey}`;
const privateKey = "{open ssl로 생성했던 private key의 내용을 통째로 넣는다}";
const keyPairId = "{클라우드프론트 콘솔에서 생성한 퍼블릭 키의 ID}";
//만료 날짜를 설정한다.
const dateLessThan = '2024-12-31' 

const cookie = getSignedCookies({
  url: url,
  privateKey: privateKey,
  keyPairId: keyPairId,
  dateLessThan: dateLessThan
});

getSignedCookie() 메소드의 필수 파라미터로 url, privatekey, keyPair 이 세가지 값을 줘야하며 파라미터로 생성할경우 추가적으로 dateLessThan 이 필수 값이다.

json 문자열로 정책 적용하는 방법

파라미터가 아닌 json으로 정책을 적용할때는 아래와 같은 json을 직접 작성해야한다.

{
    "Statement": [
        {
            "Resource": "리소스의 url",
            "Condition": {
                "DateLessThan": {
                    "AWS:EpochTime":만료 날짜 (유닉스 시간)
                },
                "DateGreaterThan": {
                    "AWS:EpochTime":접근 가능 시작 날짜 (유닉스 시간)
                },
                "IpAddress": {
                    "AWS:SourceIp": "접근허용 ip 주소 범위 (192.168.0.1/24)"
                }
            }
        }
    ]
}

이렇게 작성한 정책은 반드시 문자열로 전달해야하기 때문에 JSON.stringify() 로 문자열로 변환해야한다.

//생략

const policy = JSON.stringify({
  Statement: [
    {
      Resource: "test.png",
      Condition: {
        IpAddress: {
          "AWS:SourceIp": "192.168.0.1",
        },
        DateLessThan: {
          "AWS:EpochTime": 1708860647,
        },
      },
    },
  ],
});

const cookie = getSignedCookies({
  url: url,
  privateKey: privateKey,
  keyPairId: keyPairId,
  policy:policy
});

생성한 쿠키 사용 방법

위의 두 방법중 하나로 메소드를 실행하면 아래의 세가지의 값들을 리턴한다.

{
  'CloudFront-Key-Pair-Id': '퍼블릭 키 id',
  'CloudFront-Signature': '인코딩 된 서명',
  'CloudFront-Policy': 'jwt로 인코딩된 정책'
  //또는 CloudFront-Policy 대신 CloudFront-Expires 가 리턴된다
}

이 3개를 전부 쿠키에 설정해줘야 클라우드프론트 리소스에 접근이 가능하다. postman 으로 쿠키를 설정하고 테스트를 해보자.


postman set cookie


postman의 쿠키설정 에서 클라우드프론트의 도메인을 추가하고 키=값 형태로 쿠키를 추가한다음 요청을 날려보자.


response


쿠키를 설정하자 정상적으로 리소스에 접근이 가능하다. 이렇게 서명된 쿠키를 적용하여 인증된 사용자만 특정 리소스에 접근이 가능하도록 지정해 보았다.

aws에서 추천하는 안전하게 서명된 쿠키 사용법

공식 문서에서 설명하는 안전하게 서명된 쿠키를 사용하는 사례를 설명하고 있다. 만약 실제로 서명된 쿠키를 적용해야할 경우 아래의 내용을 참고하자.

  • 쿠키 옵션에서 Expires 또는 Max-Age 속성을 제외하여 쿠키가 브라우저 세션(브라우저 종료시 없어짐)으로 유지되도록 사용
  • Secure 옵션 적용
  • 웬만하면 정책에 사용자의 ip를 넣어 해당 사용자만 쓸수있게 하기
  • 적당한 짧은 만료기간 설정

Do you want something exciting?

© 2022. YSH All rights reserved.