[AWS] CloudFront 서명된 URL

HYEOB KIM·2022년 6월 7일
1

aws

목록 보기
27/62

사전에 드리는 말씀

이 문서는 구글에 널려 있는 서명된 URL 관련 가이드 메뉴얼을 따라할 시 작동되지 않았거나, 용어의 의미가 모호해서 어려움을 겪으신 분들을 위한 자료입니다.

구글에 서명된 URL(Signed URL)과 관련된 자료를 찾아보았을 때, 용어에 대해 제대로 이해하지 못한 채 작성된 정보, 잘못된 정보들이 꽤 많아서 그러한 가이드를 따라할 시 URL이 제대로 작동되지 않았습니다.

그래서 최대한 AWS 공식문서를 참조해 나름대로 Signed URL을 구현했고, 성공했습니다.

Signed URL

단시간(최소 몇 분) 동안만 유효한 URL을 사용하여 프라이빗 콘텐츠를 배포할 수 있습니다. 이때, 유효한 URL을 서명된 URL(Signed URL)이라고 합니다.

아키텍처

S3 버킷을 생성하고, 버킷 안에 간단한 index.html 파일을 업로드 합니다. 버킷 앞단에는 CloudFront를 붙이고, CloudFront서명된 URL을 이용해서만 버킷의 index.html에 접근할 수 있도록 합니다.

실습 과정

1. S3 버킷 생성

버킷을 생성합니다.

ACL은 비활성화하고,

퍼블릭 액세스를 허용합니다.

2. index.html 파일 업로드

아래와 같은 내용의 index.html 파일을 버킷에 업로드합니다.

<h1>hello world!</h1>

3. 키 페어 생성

리눅스 서버를 하나 생성합니다.

openssl 패키지를 설치합니다.
(이미 설치되어 있을 수도 있습니다)

% sudo yum install -y openssl

먼저 RSA 알고리즘을 이용한 private key를 생성합니다.

% openssl genrsa -out private_key.pem

그리고 private key를 이용해 public key를 생성합니다.

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

4. 퍼블릭 키 등록

[CloudFront 콘솔] > [키 관리] > [퍼블릭 키] > [퍼블릭 키 생성]

생성한 퍼블릭 키 내용을 넣고 생성합니다.

5. 키 그룹 생성

[CloudFront 콘솔] > [키 관리] > [키 그룹] > [키 그룹 생성]

아까 생성한 퍼블릭 키를 선택하고 키 그룹을 생성합니다.

6. CloudFront 배포

배포를 생성합니다.

원본

원본 도메인은 이전에 생성한 S3 버킷을 선택하고, OAI를 사용하도록 한 뒤, 버킷에 대한 OAI를 생성합니다.
(OAICloudFront를 통해서만 원본에 액세스할 수 있도록 제한합니다)

기본 캐시 동작

다른 값들은 기본값으로 하되, 뷰어 액세스 제한 항목을 주목합니다.

뷰어 액세스 제한Yes로 지정하고, 인증 유형을 이전에 생성한 키 그룹으로 지정합니다.

다른 값들은 모두 기본값으로 두고, 배포를 생성합니다.

7. 서명값 생성

다시 리눅스 서버로 돌아옵니다.

아래 내용의 policy라는 파일을 생성합니다.

% vim policy
{
    "Statement": [
        {
            "Resource": "base URL or stream name",
            "Condition": {
                "DateLessThan": {
                    "AWS:EpochTime": ending date and time in Unix time format and UTC
                }
            }
        }
    ]
}

Resource 속성에는 CloudFront도메인접근할 파일 경로를 입력합니다.
(프로토콜은 http 또는 https을 사용할 수 있고, 프로토콜에 따라 서명값이 다르게 나옵니다. 도메인 뒤에 접근 파일 경로까지 반드시 적어줘야 합니다)
AWS:EpochTime에는 서명된 URL이 만료될 시간을 입력합니다.
=> EpochTime 확인 사이트

{
    "Statement": [
        {
            "Resource": "https://dip2vyhcaqkt6.cloudfront.net/index.html",
            "Condition": {
                "DateLessThan": {
                    "AWS:EpochTime": 1654909923
                }
            }
        }
    ]
}

policyprivate key을 이용해 서명값을 생성합니다.

한 줄로 된 긴 서명값이 생성됩니다.

% cat policy | tr -d "\n" | tr -d " \t\n\r" | openssl sha1 -sign private_key.pem | openssl base64 -A | tr -- '+=/' '-_~'
ZaXiGaLrSdEj3RXp...YF3T4DBJA__

8. 서명된 URL 작성

서명된 URL의 형식은 아래와 같습니다.

<policy에 적힌 resource >?Expires=<policy에 적힌 epochtime>&Signature=<생성한 서명값>&Key-Pair-Id=<Cloudfront 퍼블릭  ID>

<policy에 적힌 resource 값><policy에 적힌 epochtime>policy 파일 내용에서 확인 가능합니다.

{
    "Statement": [
        {
            "Resource": "https://dip2vyhcaqkt6.cloudfront.net/index.html",
            "Condition": {
                "DateLessThan": {
                    "AWS:EpochTime": 1654909923
                }
            }
        }
    ]
}

<생성한 서명값>은 한 줄로 된 긴 값입니다.

ZaXiGaLrSdEj3RXp...YF3T4DBJA__

<Cloudfront 퍼블릭 키 ID>[CloudFront 콘솔] > [키 관리] > [퍼블릭 키]에서 확인 가능합니다.

결과적으로 생성된 서명된 URL은 아래와 같습니다.

https://dip2vyhcaqkt6.cloudfront.net/index.html?Expires=1654909923&Signature=ZaXiGaLrSdEj3RXpugEY0TPGlDPtSN44AHGMGPS~1zzicTdU-Hvb-Q2ZY0Nd3-UmEr0HbHtFHDI8HHPU0lbazfUngmX1BTpMSMr53sLdUJRXqxuPF~d-G-9-idGzBO686S1iR-WxisiduG1Se544UE7fNcg6RJOa6UrGyVmbMdbu4hv4Ebt5YxYkQZiDxqyBlPKxBvquny9Bw3OjmVmJNsGZUxdNdg-RlS-31gOLj1e7koI~ZfS1Wb1BVaPcra9WY2Qe1WehQSLjxy7o63vCi1mrzgLCaWuFXLuttRxmrl7fIONHytqfg-joyid8GwEZuR-PCF93tt87GYF3T4DBJA__&Key-Pair-Id=K36JF7FEPZS1C3

9. 테스트

단순히 CloudFront 도메인을 이용해 접속하면 접속되지 않습니다.

생성한 서명된 URL을 이용하면 정상적으로 접속되는 것을 확인할 수 있습니다.

Expires 속성에 명시된 만료 EpochTime이 지나면 해당 서명된 URL은 만료됩니다.

트러블 슈팅

Missing key

Missing Key 에러가 나타난다면, Key-Pair-Id 속성값이 잘못되었다는 의미입니다.

CloudFront 콘솔퍼블릭 키 ID를 제대로 입력했는지 확인해보시기 바랍니다.

Access Denied

액세스 거부(403)는 여러가지 원인으로 발생할 수 있습니다.

  1. EpochTime 불일치: policy 파일에 적힌 EpochTime과 동일한지 확인하세요.
  2. 잘못된 서명값: policy파일에 적힌 http 프로토콜과 URL로 접근할 때 http 프로토콜이 같아야 합니다. 예를 들어, policy 파일의 Resource에는 http로 적어서 서명값을 만들고, 접근할 때 https 프로토콜을 사용한다면 접근이 제한됩니다.

참고 사이트

profile
Devops Engineer

0개의 댓글