안녕하세요 서후아빠입니다. ^_^
이번 세션은 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 구성요소 생성하기
2022.07.13 - [Networking] - [실습] Amazon ELB (ALB, NLB) 구성하기
[실습] 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"로 구성 변경 필요
'Networking' 카테고리의 다른 글
[Tip] Amazon Site-to-Site VPN 통신에서 특정 Instance가 VPN 통신이 안되는 경우 대응 순서 알아보기 (0) | 2022.07.21 |
---|---|
[Tip] AWS virtual private gateway (VGW) 생성 수 제한 해결하기 (0) | 2022.07.21 |
[실습] Amazon Route 53에서 Public & Private domain (도메인) 등록하기 (0) | 2022.07.20 |
[실습] Amazon TGW(Transit Gateway) 구성하기 (Hub역할 TGW, On-premise와 Site-to-Site VPN 연결)-6편 (0) | 2022.07.20 |
[이론] Amazon CloudFront (CDN 서비스) 기본 개념 (0) | 2022.07.19 |