본문 바로가기

Networking

[실습] Amazon CloudFront (CDN) 이용하여 HTTP/HTTPS 서비스 구성하기 (S3 정적 웹 호스팅, Route 53, ACM, S3 Logging)

반응형

안녕하세요 서후아빠입니다. ^_^

이번 세션은 CloudFront에 S3의 정적 웹페이지나 ALB를 연결하고, CloudFront에서 발생하는 로그를 S3 버킷에 저장하는 구성을 실습해 보겠습니다.

구성을 간략히 설명하자면 CloudFront 앞쪽은 HTTPS(HTTP 요청 시 HTTPS 리다이렉션)로 통신하고 뒷쪽(S3, ALB)은 HTTP 통신하는 구조입니다. Origin (S3, EC2)의 변화에 대해서 CloudFront를 통해서 접근하는 경우와 직접 접근하는 경우의 차이점을 비교해 보시기 바랍니다. 

CDN쪽은 업무적으로 거리가 있는 관계로 차차 내용을 업데이트 하는 방향으로 나아가겠습니다.


구성도

CloudFront 통한 패킷 전달 과정은 아래와 같습니다.
1. 사용자가 도메인을 요청하면 Route 53에서 설정된 라우팅 경로에 따라서 CloudFront로 패킷을 전달합니다. 
  ① gtek.com으로 요청하면 albA로 패킷을 전달합니다.
  ② tek.com으로 요청하면 S3로 패킷을 전달합니다.
2. CloudFront에서는 HTTP의 경우 HTTPS로 리다이렉션 처리하고, ACM의 인증서를 읽어서 포핸드 연결하고, 요청 도메인에 따라서 백핸드인 Origin(S3 or albA)으로 패킷을 전달하고, 접근 로그에 대해서 S3(cf-log-bucket)에 저장합니다.

albA는 HTTP 구성이며, HTTPS로 구성할 경우 ACM의 인증서를 연결해주어야 합니다.

사전 작업

인프라 생성 : vpc, subnet, igw, routing table, ec2, alb, route 53, acm, bucket 등은 설명 생략합니다

2022.07.02 - [Networking] - [실습] Amazon VPC 구성요소 생성하기

 

[실습] Amazon VPC 구성요소 생성하기

안녕하세요 서후아빠입니다. ^_^ 이번 세션은 VPC 관련 구성요소에 대해서 실습을 해보겠습니다. 구성도 1단계 : VPC 생성 VPC > Your VPCs > Create VPC 구분 VPC settings (VPC Only 방식) VPC settings (VPC a..

sh-t.tistory.com

2022.07.13 - [Networking] - [실습] Amazon ELB (ALB, NLB) 구성하기

 

[실습] Amazon ELB (ALB, NLB) 구성하기

안녕하세요 서후아빠입니다. ^_^ 이번 세션은 AWS ELB 서비스 중에서 ALB, NLB에 대해서 간단히 실습을 해보겠습니다. 구성도 가용영역 2개(AZ-A-, AZ-C)이므로 가용영역별 ELB Interface가 자동 생성됩니다.

sh-t.tistory.com

2022.07.26 - [Security] - [실습] AWS Certificate Manager (ACM)을 이용하여 인증서(Public, Private) 발급하여 Route 53과 ELB 연동하기-1편 

 

[실습] AWS Certificate Manager (ACM)을 이용하여 인증서(Public, Private) 발급하여 Route 53과 ELB 연동하기-1편

안녕하세요 서후아빠입니다. ^_^ 이번 세션은 ACM에서 Public 도메인을 구매하고 Public 인증서를 발급하여 ALB에 연결하는 과정을 실습해보겠습니다. 이어서 진행되는 Private 도메인 등록과 인증서 발

sh-t.tistory.com

[실습] Amazon ELB 구성하기 (ALB, NLB)에서 ALB만 참고하시면 됩니다.
[실습] AWS Certificate Manager (ACM)을 이용하여 인증서(Public, Private) 발급하여 Route 53과 ELB 연동하기-1편에서 1~2단계만 진행하시면 됩니다. CloudFront에서 사용되는 ACM 인증서는 us-east-1에 생성해야 하며, 이번 세션에서는 *.gtek.com과 *.tek.com 2개의 인증서를 생성해야 하며, 당연히 Route 53에서 도메인도 gtek.com과 tek.com 2개를 등록해야 합니다.

1단계 : S3에 정적 웹 호스팅 생성

S3 > Buckets > Create bucket

Bucket name Block Public Access settings for this bucket 그 외 설정값
tek.com Block all public access : disabled 기본값 유지
Bucket name은 꼭 도메인 형태로 생성해야합니다.

S3 > Buckets > tek.com > Permissions (tab) > Block public access (bucket settings) > Block all public access “Off” 확인 > Bucket policy의 Edit > Bucket ARN 복사 (ex : arn:aws:s3:::tek.com) > Policy generator 

Select Policy Type Add Statement(s) > 아래 내용 설정 > Add Statement Generate Policy
Select Type of Policy : S3 Bucket Policy Effect : Allow
Principal : *
Actions : GetObject
ARN : arn:aws:s3:::tek.com
1. Generate Policy 클릭
2. 팝업창 내용(JSON) 복사
3. Close
# 팝업창 내용(JSON) 예시
{
  "Id": "Policy1663120161132",
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Stmt1663120112612",
      "Action": [
        "s3:GetObject"
      ],
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::tek.com",
      "Principal": "*"
    }
  ]
}

S3 > Buckets > tek.com > Permissions (tab) > Bucket policy의 Edit > Policy에 복사한 JSON 내용 붙여넣기 > Save changes > 에러 발생(에러 메시지 아래 참조) > 아래처럼 JSON 내용 수정 > Save changes > Bucket에 “Publicly accessible” 표시

# 에러 메시지 
Unknown Error
An unexpected error occurred.
API response
Action does not apply to any resource(s) in statement

# 수정된 팝업창 내용(JSON) 
{
  "Id": "Policy1663120161132",
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Stmt1663120112612",
      "Action": [
        "s3:GetObject"
      ],
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::tek.com/*",
      "Principal": "*"
    }
  ]
}

S3 > Buckets > tek.com > Upload > Add files > index.html

# index.html 예시
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8" />
  <title>Test</title>
</head>
<body>
  <p> S3 Web Test!! </p>
</body>
</html>

S3 > Buckets > tek.com > Properties (tab) > Static website hosting의 Edit

Static website hosting Hosting type Index document Error document(옵션) Redirection rules(옵션)
Enable Host a static website (or Redirect requests for an object) index.html - -

S3 > Buckets > tek.com > Properties (tab) > Static website hosting의 생성된 Bucket website endpoint 링크 클릭 > 웹페이지 접속(ex : http://tek.com.s3-website.ap-northeast-2.amazonaws.com) > "S3 Web Test!!" 출력

2단계 : CloudFront 생성

CloudFront > Distributions > Create a CloudFront distribution

구분 Origin
ALB 경우 Origin domain : albA-551235695.ap-northeast-2.elb.amazonaws.com
Protocol, port : HTTP only, 80
Origin path(옵션) : -
Name : 자동 등록(수정 가능)
Add custom header : -
Origin Shield : No
S3 경우 Origin domain : tek.com.s3.ap-northeast-2.amazonaws.com
Origin path(옵션) : -
Name : 자동 등록(수정 가능)
Add custom header : -
Origin access : Public
Add custom header : -
Origin Shield : No
Default cache behavior Function associations(옵션)
Path pattern : default
Compress objects automatically : Yes
Viewer
  - Viewer protocol policy : Redirect HTTP to HTTPS
  - Allowed HTTP methods : GET, HEAD
  - Restrict viewer access : No
Cache key and origin requests : Cache policy and origin request policy
  - Cache policy : CachingOptimized
  - Origin request policy(옵션) : -
  - Response headers policy(옵션) : -
Smooth streaming : No
Enable real-time logs : No
Viewer request : -
Viewer response : -
Origin request : -
Origin response : -
구분 Settings
ALB 경우
(gtek.com으로 접속하는 경우)
Price class : Use all edge locations (best performance)
AWS WAF web ACL(옵션) : -
Alternate domain name(CNAME, 옵션) : gtek.com
Custom SSL certificate(옵션) : *.gtek.com
Default root object(옵션) : -
Supported HTTP versions : HTTP/2
Standard logging : off
IPv6 : off
ALB 경우
(www.gtek.com으로 접속하는 경우)
Alternate domain name(CNAME, 옵션) : www.gtek.com
Custom SSL certificate(옵션) : *.gtek.com
Default root object(옵션) : -
나머지 항목은 gtek.com으로 접속하는는 경우와 동일하게 설정
S3 경우
(tek.com으로 접속하는 경우)
Alternate domain name(CNAME, 옵션) : tek.com
Custom SSL certificate(옵션) : *.tek.com
Default root object(옵션) : index.html
나머지 항목은 gtek.com으로 접속하는는 경우와 동일하게 설정
S3 경우
(www.tek.com으로 접속하는 경우)
Alternate domain name(CNAME, 옵션) : www.tek.com
Custom SSL certificate(옵션) : *.tek.com
Default root object(옵션) : index.html
나머지 항목은 gtek.com으로 접속하는는 경우와 동일하게 설정
Origin Shield : 향상된 캐시 적중률, Origin 부하 감소, 향상된 네트워크 성능
Compress objects automatically : 자동으로 파일 압축
Viewer protocol policy : 일반적으로 HTTP 통신은 보안이 취약하기 때문에 Redirect HTTP to HTTPS 선택
Function associations : CloudFront Functions, Lambda@Edge 선택 가능

사용자가 *.com으로 접속하는 경우도 있고, www.*.com으로 접속하는 경우도 있기 때문에 ALB와 S3 각각 2개의 CF(Total 4개)를 생성합니다.

CloudFront > Distributions > 생성된 ID에서 Domain name을 확인

각 도메인을 아래처럼 가정합니다.
- gtek.com에 대한 CF 도메인 : alb01aaaaaaaa.cloudfront.net 
- www.gtek.com에 대한 CF 도메인 : alb02aaaaaaaa.cloudfront.net 
- tek.com에 대한 CF 도메인 : s301bbbbbbbb.cloudfront.net 
- www.tek.com에 대한 CF 도메인 : s302bbbbbbbb.cloudfront.net

3단계 : ALB 접속 확인

브라우저에서 http://albA-551235695.ap-northeast-2.elb.amazonaws.com 접속 시도하면 hello World1 (or hello World2) 출력

# priA-ec2에서 접속할 때마다 로그 기록
tail -f /var/log/httpd/access_log
218.236.84.11 - - [20/Jul/2022:08:45:09 +0000] "GET / HTTP/1.1" 304 - "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36"

브라우저에서 http://alb01aaaaaaaa.cloudfront.net/ (or http://alb02aaaaaaaa.cloudfront.net/)접속 시도하면 https://alb01aaaaaaaa.cloudfront.net/ (or https://alb02aaaaaaaa.cloudfront.net/)로 리다이렉션되고, hello World1 (or hello World2) 출력

# priA-ec2에서 최초 1회는 로그 기록되고, 2회부터는 기록되지 않음(CF에서 Cashing 처리)
tail -f /var/log/httpd/access_log
13.124.199.83 - - [20/Jul/2022:08:50:55 +0000] "GET / HTTP/1.1" 200 14 "-" "Amazon CloudFront“
13.124.199.86 - - [20/Jul/2022:08:50:55 +0000] "GET /favicon.ico HTTP/1.1" 404 196 "-" "Amazon CloudFront"
S3의 경우도 https://s301bbbbbbbb.cloudfront.net/ (or https://s302bbbbbbbb.cloudfront.net/) 접속 시도하면 "S3 Web Test!!" 출력됩니다.

4단계 : Origin(priA-ec2)의 내용 변경

priA-ec2 접속하여 아래 명령어로 WEB 서비스 변경

# WEB page 문구 변경 설정 
sudo vi /var/www/html/index.html
NEW hello World1    // 2번 서버는 NEW hello World2

# Service restart 및 Service port listen 확인
sudo systemctl restart httpd
sudo netstat -tupan | grep 80
S3는 버킷에 업로드된 index.html파일 내용을 수정하시면 됩니다.

5단계 : ALB 접속 확인 (4단계 변경사항에 대한 반영여부 확인)

브라우저에서 http://albA-551235695.ap-northeast-2.elb.amazonaws.com  접속 시도하면 변경된 NEW hello World1 (or NEW hello World2) 출력

브라우저에서 https://alb01aaaaaaaa.cloudfront.net/ 접속 시도하면 변경되지 않은  hello World1 (or hello World2) 출력

CloudFront에서는 Origin에 변경사항이 발생된 것이 반영되지 않았기 때문에 과거 버전으로 응답을 하고 있는 것입니다.
TTL(Time to Live, Cashing된 Contents가 살아있는 시간) 시간이 지나면 Cashing에서 삭제되어 변경된 값을 출력하게 되며, 강제로 값을 변경하려면 6단계를 참고하시면 됩니다.
일반적으로 초기에는 TTL을 60초로 설정을 하고, 안정화된 후에는 시간을 늘려서 설정합니다.

S3의 경우도 index.html파일을 수정하면서 테스트하시면 됩니다.

6단계 : CloudFront 파일 무효화 (Invalidate)

CloudFront > Distributions > 생성된 ID 선택 > Invalidations (tab) > Create invalidation > Add object paths(/) > Create invalidation

브라우저에서 https://alb01aaaaaaaa.cloudfront.net/ 접속 시도하면 변경된 NEW hello World1 (or NEW hello World2) 출력

# CloudFront Domain으로 접속 시 log
tail -f /var/log/httpd/access_log
13.124.199.83 - - [20/Jul/2022:09:07:42 +0000] "GET / HTTP/1.1" 200 13 "-" "Amazon CloudFront"

7단계 : CloudFront를 Route 53에 연결

Route 53 > Hosted zones > gtek.com > Create record

구분 Record name Record type Alias Route traffic to Routing policy
ALB 경우
(gtek.com으로 접속하는 경우)
- A Enable Alias to CloudFront distribution Simple routing
ALB 경우
(www.gtek.com으로 접속하는 경우)
www A Enable Alias to CloudFront distribution Simple routing

Route 53 > Hosted zones > tek.com > Create record

구분 Record name Record type Alias Route traffic to Routing policy
S3 경우
(tek.com으로 접속하는 경우)
- A Enable Alias to CloudFront distribution Simple routing
S3 경우
(www.tek.com으로 접속하는 경우)
www A Enable Alias to CloudFront distribution Simple routing

8단계 : Route 53 접속 확인

브라우저에서 HTTP or HTTPS로 각 도메인(gtek.com, www.gtek.com, tek.com, www.tek.com)을 접속시도합니다.

옵션 : S3 bucket에 CloudFront logging 저장

S3 > cloudfront-log 선택 > Permissions (tab) > Object Ownership에서 Edit

Object Ownership I acknowledge that ACLs will be restored. Object Ownership
ACLs enabled Check Bucket owner preferred
Object Ownership이 기본값인 ACLs disabled인 경우 CloudFront에서 Bucket으로 Log 파일을 전송 불가능하기 때문에 ACLs disabled 상태에서 Standard logging 설정을 진행하면 권한 문제로 에러가 발생합니다.

CloudFront > Distributions > 생성된 ID 선택 > General (tab) > Standard logging > on

S3 bucket Log prefix(옵션) Cookie logging
cf-log-bucket tek.com off
Log prefix를 설정하면 bucket에 폴더(ex : tek.com, 보통 domain으로 생성)를 생성하고 그 폴더에 Log를 저장합니다.

브라우저로 접속 시도 2회하고 약 5분 대기

S3 > cf-log-bucket 선택 > tek.com > *.gz 선택 > 다운로드 > 다운받은 파일 압축 해제 > 메모장에서 확인

#Version: 1.0
#Fields: date time x-edge-location sc-bytes c-ip cs-method cs(Host) cs-uri-stem sc-status cs(Referer) cs(User-Agent) cs-uri-query cs(Cookie) x-edge-result-type x-edge-request-id x-host-header cs-protocol cs-bytes time-taken x-forwarded-for ssl-protocol ssl-cipher x-edge-response-result-type cs-protocol-version fle-status fle-encrypted-fields c-port time-to-first-byte x-edge-detailed-result-type sc-content-type sc-content-len sc-range-start sc-range-end
2022-07-20	09:23:13	ICN57-P2	347	218.236.84.11	GET	alb01aaaaaaaa.cloudfront.net	/	304	-	Mozilla/5.0%20(Windows%20NT%2010.0;%20Win64;%20x64)%20AppleWebKit/537.36%20(KHTML,%20like%20Gecko)%20Chrome/103.0.0.0%20Safari/537.36	-	-	Hit	royMFpLbmS60BQ_T-JdA0oMBt8pviILIRfoyHQ42sXO05QBiZ6LVdg==	alb01aaaaaaaa.cloudfront.net	http	575	0.035	-	-	-	Hit	HTTP/1.1	-	-	15806	0.035	Hit	-	-	-	-
2022-07-20	09:23:26	ICN57-P2	347	218.236.84.11	GET	alb01aaaaaaaa.cloudfront.net	/	304	-	Mozilla/5.0%20(Windows%20NT%2010.0;%20Win64;%20x64)%20AppleWebKit/537.36%20(KHTML,%20like%20Gecko)%20Chrome/103.0.0.0%20Safari/537.36	-	-	Hit	RkdLDIgohUujv4TevVko6AarafEBrwn7z-KPAClh723IHO3zePBimQ==	alb01aaaaaaaa.cloudfront.net	http	575	0.001	-	-	-	Hit	HTTP/1.1	-	-	15806	0.001	Hit	-	-	-	-

옵션 : 특정 지역 차단 or 특정 지역만 허용

CloudFront > Distributions > 생성된 ID 선택 > Geographic restrictions (tab)의 Edit > Restriction type(No restrictions or Allow list or Block list 중 선택하여 설정)

Allow list는 허용할 Region을 선택하는 옵션이고, Block list는 차단할 Region을 선택하는 옵션입니다.

옵션 : Origin 직접 접속에 대한 취약점 조치

CloudFront의 Origin(ALB or S3)는 Public에 위치하며, Origin을 HTTP로 구성할 경우 보안상 취약하기 때문에 CloudFront를 통하지 않고 직접 접속하는 경로는 모두 차단하는 것을 권고합니다. 

ALB의 경우는 보안그룹에 CloudFront IP만 허용하도록 설정합니다. (https://sh-t.tistory.com/28 참고)

S3의 경우는 "CloudFront > Distributions > 생성된 ID 선택 > Origins (tab)에서 Origins를 선택하고 Edit > Origin access" 에서 Origin access control settings or Legacy access identities을 설정하도록 합니다.

# S3 버킷 정책에서 CF만 허용하는 정책 예시 (ex : CF의 ID가 ET5YFVL9K6인 경우
{    
  "Version": "2008-10-17",
  "Id": "PolicyForCloudFrontPrivateContent",
  "Statement": [
    {
      "Sid": "1",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ET5YFVL9K6"
      },
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::tek.com/*"
    }
  ]
}

옵션 : 캐시(Cache policy), 원본 요청(CachingOptimized)

CloudFront > Policies  

내용 예시
Cache (tab) > Create cache policy TTL(내부 협의하여 시간 조정, 초) : Min(60), Max(36000), Default(3600)
Cache key settings 
  - Headers : Include the following headers 
  - Add header : Origin, Access-Control-Request-Method, Access-Control-Request-Headers, 
    X-Forwarded-For, Host, Authorization
Query strings : None
Cookies : None
Compression support : Gzip(Enable), Brotil(Enable)
Origin request (tab) > Create origin request policy Headers : All viewer headers  (or Include specified query stings 선택하고, Origin 선택)
Query strings : All (or Include specified query stings 선택하고, X-Source 입력)
Cookies : All (or None)

CloudFront 삭제

CloudFront > Distributions > 생성된 ID 선택 > Disable > 1~2분 대기 생성된 ID 선택 > Delete

기타

Client 입장에서 고정 EIP로 서비스 요청해야 하는 경우 CloudFront는 글로벌 서비스이기 때문에 불가능

이에 따라 "DNS -> NLB (고정 EIP 연결) -> ALB (302 리다이렉션) -> CloudFront"로 구성 변경 필요

반응형