Web service를 시작하기로 하였다.

CDN을 둬서 static contents들을 서빙하려하고 cloudfront를 사용하기로 결정하였다.

Data의 보관은 S3 bucket에 static contents를 두고 cloudfront에서 접근해서 가져가는 방식을 사용하기로 결정하였다.

 

기본 세팅

S3, Cloudfront, Route53 관련 세팅하는 것은 하나씩 읽어가면서 누르면 된다. 검색하면 포스팅한 글이 이미 많다.

개인적으로는 각 설정 항목에 대한 설정은 한번 자세히 보고 넘어야가야 한다는 생각이다.

혹은 cloudformation 템플릿을 이용해서 구성한다. 

CloudFront와 S3를 이용해서 서빙을 한다면 처음 세팅할때 이 부분을 반드시 "Yes"로 해주고 Identity는 Access S3 bucket content only through CloudFront를 선택한다.

만약 No로 한 경우에는 나중에 Origin 설정에서 바꾸려고 해도 바꿀수는 없고, Origin을 삭제하고 다시 만드는 방법이 있을 수 있겠다.

HTTPS로만 접근을 허용하겠지만
그렇다고 HTTP 요청을 다 버리고 싶진 않으니 Redirect 하도록 Behavior에서 설정해주었다.

 

TTL

TTL 설정을 통한 cache 전략에서 고민이 시작되었다.

평소에는 static 파일들을 추가만 할테니 TTL을 aws에서 default로 제공하는 것을 그냥 사용해도 아무런 문제가 없다.

문제는 hotfix. 

배포된 이미지 파일의 구문이 잘 못되서 급히 변경해야 되는 상황 같은 경우.

물론 Invalidations 기능이 있어서 긴급할때는 이 기능을 이용해서 cache를 다 날려버릴 수 있다.

AWS console에서 눌러가면서 하거나

 

아니면 awscli로 처리한다.

# sample

aws cloudfront create-invalidation --distribution-id $distribution_ID --paths "/*"

 

다시 TTL 설정으로 돌아와서 3개의 TTL 의미 파악을 못했다.

물론 HTTP Header에 Cache-Control: max-age=xx, Cache-Control: s-maxage=xx 같은 값이 없으면 default TTL인 것은 알겠으나, 
minimum TTL, maximum TTL 관련해서는 이 메뉴얼을 읽어보았지만 이해를 못했었다.

  • default TTL (Cache-Control, Expires header가 없는 경우)
  • minimum TTL
  • maximum TTL

 

그러던중에 이를 이해할 수 있게 정리한 포스팅을 찾았다.

  • 만약 Cache-Control 헤더의 max-age 값이 사용자가 정의한 minimum TTL과 maximum TTL 사이에 있는 경우, CloudFront는 maximum TTL에 지정된 시간에 대해 개체를 캐시합니다.
  • 만약 max-age 값이 사용자가 정의한 minimum TTL보다 작으면 CloudFront는 minimum TTL값에 대해 개체를 캐시합니다.
  • 만약 max-age 값이 사용자가 정의한 maximum TTL보다 큰 경우 CloudFront는 maximum TTL 값에 대해 개체를 캐시합니다.

대충 이해가 간다.

Cache-Contorl, Expires 해더를 이용해서 세팅을 해주면 TTL을 내가 원하는대로 맞춰서 사용할 수 있다는 것은 알겠다.

 

그럼 다시 Cloudfront로 돌아와서 Cache policies 중에 "Managed-CachingOptimized"의 TTL 세팅을 다시 본다.

  • Minimum TTL: 1 sec
  • Maximum TTL: 31536000 sec (1 year)
  • Default TTL: 86400 sec (1 day)

어떤 설정인지는 알겠는데 좀 더 확실하게 알아야겠다고 생각하고 메뉴얼을 다시 읽어 보았다.

AWS는 뉴얼을 잘 봐야하는 걸 알면서도 제대로 안보고 지나쳤던것이 문제였다.

이제서야 메뉴얼이 눈에 들어오기 시작한다.

메뉴얼을 자세히 보면 이해가 되겠지만 다시한번 적어보면서 이해를 해본다.

  • minimum TTL은 Min TTL, maximum TTL은 Max TTL로 표현한다.

표에 나오는 HTTP header

  • Cache-Control: max-age=<seconds>  (e.g. Cache-Control: max-age=1200)
  • Cache-Control: s-maxage=<seconds> (e.g. Cache-Control: s-maxage=1200)
  • Expires: <http-date> (e.g. Expires: Wed, 10 Mar 2021 07:28:00 GMT)
Origin 해더 Min TTL = 0 sec Min TTL > 0 sec (1초 보다 큼)
Origin object에
Cache-Control: max-age
헤더 추가
[CloudFront 캐싱]
Cloudfront는
Cache-Control max-age와 Max TTL의 값 중
더 작은 값 동안 캐싱


[Browser 캐싱]
Browser는
Cache-Control max-age 동안 캐싱

[CloudFront 캐싱]
Cloudfront는
Min TTL < max-age < Max TTL

- Cache-Control max-age 동안 캐싱
max-age < Min TTL
- Min TTL 동안 캐싱
max-age > Max TTL
- Max TTL 동안 캐싱

[Browser 캐싱]
Browser는
Cache-Control max-age 동안 캐싱

Origin object에
Cache-Control: max-age
헤더 추가 안함
[CloudFront 캐싱]
Cloudfront는 
default TTL
 동안 캐싱

[Browser 캐싱]
Browser 마다 다름
[CloudFront 캐싱]
Cloudfront는
Min TTL과 default TTL 둘중 더 값이 큰 값 동안 캐싱

[Browser 캐싱]
Browser 마다 다름
Origin object에
Cache-Control: max-age와
Cache-Control: s-maxage
헤더 추가 
[CloudFront 캐싱]
Cloudfront는 
Cache-Control s-maxage와 Max
 TTL의 값 중
더 작은 값 동안 캐싱


[Browser 캐싱]
Cache-Control max-age 동안 캐싱
[CloudFront 캐싱]
Cloudfront는
Min TTL < s-maxage < Max TTL

- Cache-Control s-maxage 동안 캐싱
s-maxage < Min TTL
- Min TTL 동안 캐싱
s-maxage > Max TTL
- Max TTL 동안 캐싱

[Browser 캐싱]
Browser는
Cache-Control max-age 동안 캐싱
Origin object에
Expires 헤더 추가
[CloudFront 캐싱]
Cloudfront는 
Expires의 날짜와 Max
 TTL의 값 중
더 빨리 만료되는 동안 객체를 캐싱


[Browser 캐싱]
Browser는
Expires의 날짜와 시간 까지 캐싱
[CloudFront 캐싱]
Cloudfront는
Min TTL < Expires < Max TTL

- Expires의 날짜와 시간 까지 캐싱
Expires < Min TTL
- Min TTL 동안 캐싱
Expires > Max TTL
- Max TTL 동안 캐싱

[Browser 캐싱]
Browser는
Expires의 날짜와 시간 까지 캐싱
Origin object에
Cache-Control: no-cache, no-store
혹은 private 
헤더 추가
CloudFront, Broser는 헤더의 설정에 따른다.

CloudFront에서 Cache-Control: no-cache 처리방식은 링크 참고
[CloudFront 캐싱]
Cloudfront는 Min TTL 동안 캐싱

[Browser 캐싱]
Browser 헤더의 설정을 따름

 

 

다음으로는 나의 static file들이 S3에 있으니 S3에 object 세팅을 해줘야 할 것 같다.

S3 object에 Metadata을 이용하면 되겠다.

일단 그럼 테스트를 한번 해본다.

테스트라서 빌드 디렉터리를 통째로 옵션을 줬지만,, 실제로는 파일 확장자 단위로 하거나 좀 더 잘게 나눠서 할 예정이다.

(react app 만들고 빌드할 설정과 aws s3 sync할 설정에 대한 설명은 제외,, 다른 방법으로도 테스트는 가능하므로)

> create-react-app sample-deploy
...
...

> cd sample-deploy
> yarn build
...
...

> aws s3 sync ./build s3://test-upload-bucket --metadata='{"Cache-Control":"max-age=300"}'
...
...

원하는대로 metadata가 세팅이 되었는지 확인해본다.

 

Value는 내가 원하는대로 올라갔는데 Key 값이 다르다.

"x-amz-meta-"로 시작하는 헤더는 User defined(사용자 정의) 메타데이터 HTTP 헤더로 별도로 구분하기 위한 키워드인데 이것은 원래 하려던것이 아니다.

 

다른 옵션을 찾아서 옵션을 바꿔보았다. '--cache-control' 로 해보니 원하는대로 Key, Value가 세팅되었다.

> aws s3 sync ./build s3://test-upload-bucket -cache-control max-age=1200
...
...

 

S3 Object 접근 제한

외부에서 S3 Object에 직접적인 접근은 제한을 걸고 싶다.

그래서 크게 2개의 접근만 허용해주고 나머지는 제한하려고 했다.

  • 업무하는 사무실의 접근
  • CloudFront의 접근

사무실에서의 접근은 가장 편하고 직관적인 IP 허용으로 처리했다.

CloudFront에서의 접근은 Origin Access Identity를 이용해서 허용해주었다. (ColudFront의 Origin 설정에서 확인)

 

S3의 Bucket에서 Permission 탭에 있는 Bucket policy 세팅 결과이다.

주요 정보들은 x, y 같은 것으로 바꿔두었다.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::test-upload-bucket/*",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": [
                        "x.x.x.x/32",
                        "y.y.y.y/32"
                    ]
                }
            }
        },
        {
            "Sid": "CloudfrontOAI",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E2ZZZ2IRJXXXXX"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::test-upload-bucket/*"
        }
    ]
}

테스트를 해본다.

wifi를 끈 휴대폰을 이용해서 S3 url에 직접 접근해았더니 Access Denied 발생한다.

Cloudfront에 접근해서 보니 잘 보인다.

참고로 Route53에 dns 세팅을 미리 해두었고 그것을 Alternative Domain Names(CNAMEs)에 추가해서 이용하였다. 

이 부분은 마우스 클릭 몇번이면 되므로 패스.

 

나머지는 운용해나가면서 적절히 맞춰가야겠는데

Behaviors에서 Path Pattern 적용해서 Cache policy 적용해주는것 (개발팀과 협의 (modify없이 add만)? 배포할때마다 버저닝?)

Error Pages에서 에러 발생에 대한 응답 페이지/코드 세팅해주는 정도를 추가로 맞추게 되지 않을까 싶다.

거기에 Origin이 늘어나면 거기에 따른 추가 설정들도..

'Infra' 카테고리의 다른 글

Python으로 Opendistro Account 생성하기  (0) 2021.03.17
Cloudfront와 S3를 이용한 웹 서비스 구성  (0) 2021.03.10
Hashicorp Terraform (테라폼)  (0) 2020.10.28
AWS Subnet 생성하기  (0) 2020.07.23
AWS VPC 생성하기  (0) 2020.07.23
AWS EKS Service Role 생성 (IAM)  (0) 2020.07.23

+ Recent posts