이 포스트는 지난번에 작성했던 CloudFront 에서 private content 제공하기 에서 이어집니다.
포스팅의 내용은 정확하지 않을수 있습니다.
지난번에 대략적으로 설명했던 private content 설정하기에서 서명된 쿠키를 적용하여 인증된 사람들한테만 컨텐츠를 제공하는 기능을 적용해본 후기글이다. 지난번 포스트에서는 서명된 url만 사용했봤었는데(사실 틀린내용도 있었음) 이번엔 사용 안해봤던 쿠키를 적용한 방법도 사용해 보고 지난 포스트에서 틀린내용들을 수정하여 소개한다.
기본적인 S3와 클라우드프론트를 생성하는 내용은 생략하고 클라우드프론트에 서명자를 추가하는 내용부터 설명하겠다. 클라우드프론트의 서명자
가 무엇인지 궁금하다면 이전 포스트에서 클라우드프론트에 서명자 추가하기 부분을 읽어보자.
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.pem
과 public_key.pem
파일이 생기것이다.
위에서 생성한 퍼블릭 키를 클라우드프론트에 등록해야한다. aws 콘솔의 cloudFront 페이지에서 키 관리/퍼블릭 키 메뉴에 들어가서 퍼블릭 키를 생성한다.
키 값은 pem 파일에 있는 내용 그대로 붙여넣는다.
키 생성이 완료되면 ID 값을 기억해두자 나중에 서명된 쿠키를 생성할때 사용된다.
다음으로 생성한 퍼블릭 키로 키 그룹을 생성한다.
키 그룹까지 생성했다면 클라우드프론트의 동작에 키 그룹을 적용해야한다.
키 그룹을 적용하기 전에 먼저 클라우드프론트의 컨텐츠에 접근 가능한지 확인해보자.
키 그룹을 적용하기전 아무나 접근이 가능한 상태이다.
키 그룹을 적용하려면 배포된 클라우드프론트의 동작 편집
에 들어가서 뷰어 액세스 제한을 yes로 선택하고 아까전에 생성했던 키 그룹을 등록한다.
해당 변경 사항을 저장하고 나면 이제 클라우드프론트에선 서명된 url 이나 서명된 쿠키를 가지고 있어야만 정상적으로 응답을 내려준다.
다시 클라우드프론트를 확인해보자.
쿼리에 키페어 파라미터(서명된 url)나 쿠키를 요구하고있다.
이제 aws-sdk를 이용하여 쿠키를 생성해보자. @aws-sdk/cloudfront-signer
패키지를 설치한다.
npm i @aws-sdk/cloudfront-signer
해당 패키지의 getSignedCookies()
메소드를 사용하여 쿠키를 생성하는데 아래와 같은 접근 제한 옵션을 설정할수있다.
192.168.0.0/24
와 같은 문자열로 작성한다.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을 직접 작성해야한다.
{
"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의 쿠키설정 에서 클라우드프론트의 도메인을 추가하고 키=값
형태로 쿠키를 추가한다음 요청을 날려보자.
쿠키를 설정하자 정상적으로 리소스에 접근이 가능하다. 이렇게 서명된 쿠키를 적용하여 인증된 사용자만 특정 리소스에 접근이 가능하도록 지정해 보았다.
공식 문서에서 설명하는 안전하게 서명된 쿠키를 사용하는 사례를 설명하고 있다. 만약 실제로 서명된 쿠키를 적용해야할 경우 아래의 내용을 참고하자.