일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 알고리즘
- 실행컨텍스트
- this
- 코어자바스크립트
- v8 원리
- 테스트 코드 툴 비교
- 자바스크립트 엔진 v8
- gql restapi 차이
- FP 특징
- 항해99
- next js
- chromatic error
- 항해99 미니프로젝트
- 타입스크립트
- 웹팩 기본개념
- 웹 크롤링
- 리액트 메모
- 리액트 렌더링 최적화
- 리액트 메모이제이션
- toggle-btn
- 리액트
- 함수형 프로그래밍 특징
- Js module
- JS module system
- 항해99 부트캠프
- 항해99 사전스터디
- 리덕스
- jwt
- 렌더링 최적화
- js배열 알고리즘
- Today
- Total
Jaeilit
Vercel 배포가 자꾸 실패한 이유 (403 Fobidden) + AWS WAF 본문
개인 프로젝트를 하던 중 전에 Vercel 배포할때는 까지 본적 없는 에러를 발견했고 이를 해결해 나간 과정을 설명하려고 합니다.
먼저 히스토리를 위해서 도메인 구입과 연결한 것부터 이야기를 하려고 합니다.
# 도메인 연결 부터
프로젝트 코드보다 인프라에 더 집중을 할 때이다. 도메인 연결부터 이야기를 할 필요는 없지만 전체적인 과정을 설명을 하기 위해 먼저 이야기를 하려고한다. 도메인을 구입을 했는데 .co.kr .com 등 같은 최상위 도메인이 .shop 이나 가비아에서 500원에 파는 것들이 있기한데 지속적으로 운영을 할 목적으로 시작한 프로젝트라 나중에 혹시나 도메인을 이전해야한다거나 할 때 또 귀찮은 일을 해야하는게 2번 일하는 것 같아서 싫었고 또 다른 이유는 도메인을 이전하면 SEO에도 영향이 갈까봐 처음부터 .co.kr 도메인을 구입했다.
# 클라우드 플레어 포기 -> AWS Router 53
처음 DNS 서비스로는 클라우드 플레어를 선택했는데, 이 프로젝트를 저번에도 진행하다가 한번 접은 적이 있다. 접은 이유가 뭘 잘못 만졌더니 인스턴스가 날라갔었다. 프리티어 기간도 끝나가기도 해서 그냥 지워버렸다. 이때 서버 프레임워크로 nestjs를 사용하고 있었는데 로그를 보니 알 수 없는 무분별한 봇 공격이 많았다. 클라우드 플레어는 보안으로 정평이 나있기에 이번엔 클라우드 플레어를 선택했다. 하지만 DNS 연결 과정에서 구매한 도메인과 ec2 퍼블릭 Ip 에 대해서 검증을 하려니 이게 느린건지 보통 정상적이면 많이 걸려도 1~2시간일텐데 24시간 내에 검증이 된다는 안내만 있을 뿐 실패했는지 진행하고 있는건지 알 수가 없었고 (수파베이스로 프로젝트 한 것이 있는데 이메일 서비스를 연결 할때 DNS 검증을 하루 종일 기다렸다가 잘못 된 걸 알고 수정했더니 10분도 안돼서 검증 된 걸 겪어서 기다림은 희망고문이라는 걸 그때 알게됐다.) 계속 이거에 내 시간과 감정을 쏟을 수 없었고 같은 aws 면 호환성이 좋을거라 생각하고 AWS Router 53에서 설정하게 됐다.
# 배포 서버가 2개니까 도메인도 2개 필요한가?
router 53에도 구매한 도메인과 레코드 설정해주고 vercel 에 도메인을 연결했는데 검증이 됐다 안됐다가 계속 초 단위로 스위칭 상태가 됐다. 가만히 생각해보면 도메인은 1갠데 버셀 프론트가 띄워진 서버와 ec2 서버 ip 가 서로 이건 내 도메인이야 아니야 이건 내꺼야 서로 싸우는 중이였다. 근데 이상하다. 서버 1개당 도메인 1개만 사용할 수 있는데,,? 왜 서로 검증하려고 하는거지? 처음에는 같은 서버에서 프론트/백이 배포된거면 프록시로 포트별로 나눠주면 도메인 1개면 된다고 생각했는데 내 상황은 배포 된 서버가 서로 다른 상황이라 도메인도 2개가 필요하나? 라는 생각을 주말 2일동안 했다. 주말 2일동안 계속 벽에 부딪힌 결과 그 역할을 alb에 맡기면 된다. 이건 나중에 설명을 하도록하고 결론부터 이야기하면 먼저 서버 2개를 하나의 도메인으로 바라보게 했다. Router 53 레코드에 vercel 에서 도메인을 연결하려고 할 때 검증하라고 준 A와 CNAME 유형의 레코드 이름과 값을 입력해서 DNS 검증을 하게 했고 버셀에서 성공적으로 검증됐고 스위칭도 안됐다.
# 서버는 서브 도메인 사용하기
서버는 사실 외부 도메인이 필요 없다. 외부에서 퍼블릭 ip로 얼마든지 접근이 가능하니까 도메인을 굳이 연결 할 필요가 없다. 보통 프로젝트 할때 메이저 서비스들을 많이 참고하는 편인데 마켓컬리에서 보면 api.marketcuury 이런식의 서브도메인을 사용하는 것을 봤고 관리하기 편하려고 서브 도메인으로 구별을 해둔건지, 일단 따라하면서 장단점을 생각해보기로 했다. 서브 도메인은 Router 53에 방금 만든 루트 도메인과 동일하게 api.도메인을 하나 더 만들고 제공해주는 NS 등 레코드를 루트 도메인에 그대로 복붙하면 된다.
# alb
여기까지 오게 된 이유는 클라이언트 컴포넌트에서 http 로 요청을 보내면 mixed content 에러가 발생해서 서버도 똑같이 https 로 맞춰주기위함이였다. aws acm 에서 구매한 도메인으로 ssl 인증서를 발급받고 lb에서 80포트는 그대로 https 로 보내고 8080 서버 포트는 api로 리다이렉션을 걸어줬다.
사진에 보이지 않지만 위에 https 443포트로 발급 받은 인증서도 연결해두었다.
여기까지는 글 제목과 관련이 없는 글이였다.
인프라는 대충 된 것 같고 프로젝트에 간단한 코드를 작성을 하고 배포를 했는데 빌드 시 에러가 발생했고 에러 발생 지점을 저 로그가 전부라 정확하게 알 수는 없는데 Forbidden 을 보면 서버 컴포넌트에서 fetch 할때 try catch에 걸린 지점인 것 같다.
# 왜 발생했지?
ec2에 배포 된 도커 컨테이너 로그를 찍어봐도 아무 로그도 남아있지 않았다. 어떻게 보면 이것도 당연한 일인데 Forbidden 403은 접근을 거부당한 것이라 서버까지 요청이 안갔을 것이니 로그가 찍힐리 없다. 그럼 요청이 어디서 커트 당한걸까? 인스턴스에 보안그룹이 문제일까 생각해서 인바운드 규칙에 서버고 ssh http고 다 열었고 재빌드 해봐도 에러는 동일하게 발생했고 다음으로 살펴볼건 alb인데 여기서 요청을 커트를 할 규칙,정책이 없다. 도무지 어디서 커트한건지 찾을 수가 없어서 정말 말도 안되지만 cors인가?.. 생각했고 이걸 하루씩이나 고민했다. cors는 정해둔 오리진에 한해서만 요청을 받는건데 서버가 오리진을 갖고 있지 않아서 cors랑 무관하지만 혹시나 하는 마음에 nestjs cors 을 다 열어두기도 특정 오리진만 열어두기도 하면서 하루를 보냈다. 이때 열어둔 오리진이 env에 설정되어있었는데 env 설정이 잘못된 줄 알고 하루종일 컨테이너 env 도 같이 찍어보기도 했다.
#AWS WAF
도메인 연결할 때 클라우드 플레어 부분에서 잠깐 무분별한 봇 공격에 대해서 이야기를 했는데 위에서 설명은 안했지만 봇 공격을 막을려고 WAF 로 해외 ip는 전부 차단하는 룰을 정하고 alb 에 연결해두었다.
접근을 막고 아래에서 다른 국가로 접근해보면 403 Forbidden 에러가 발생한다.
지금까지도 잘 막아주고있는데 vercel 배포할때 에러 났던 시간과 대조해보면 여기랑 딱 맞아떨어진다. (사진 시간과 무관)
결론은 vercel이 배포할때 서버 컴포넌트에 프리렌더할때 패칭하려고 접근한 것도 막은 것이다.
# 시도-1
버셀이 접근하는 ip만 특정할 수 있으면 해외 ip를 차단하더라도 특정 ip만 열어두는 규칙을 하나 더 만들어서 우선순위로 우선 적용되게해서 열어둘 수는 있는데 문제는 버셀 ip를 어떻게 특정할 것이다. 처음에는 vercel 과 연결 해둔 a 레코드에 72.~~.~~.~~ ip 를 주는데 혹시나해서 이 ip를 넣어봤지만 역시 이건 클라이언트쪽 ip니 버셀 배포 시스템 ip와 다르니까 안되는게 당연했다.
# 시도-2
버셀 배포 ip 는 동적으로 구성되서 ip를 특정할 수 없지만 유료옵션을 이용하면 가능하다.
유료이기 때문에 ip를 특정하는 것은 포기했다.
https://vercel.com/guides/how-to-allowlist-deployment-ip-address
https://vercel.com/guides/can-i-get-a-fixed-ip-address
# 시도-3
region 서울로 설정하기
https://vercel.com/docs/functions/configuring-functions/region
이건 배포 된 이후에 정적 리소스를 받아오는 region 을 설정하는 건데 혹시나 해서 국내로 설정했지만 빌드 결과는 달리지지 않았다.
# 결론
waf로 해외 ip를 차단하면서 봇을 막으려고 했는데 버셀 해외 ip까지 막혀서 빌드 때마다 forbidden 으로 접근이 막혔던 것이다.
해외 ip 차단을 풀고 봇만 막으려면 aws bot control 를 고민해보면 되는데 waf 와 별개로 또 추가금이 발생하니 야금야금 돈만 늘어나는 느낌이라 적용하기 두려워진다.
https://docs.aws.amazon.com/ko_kr/waf/latest/developerguide/waf-bot-control.html
https://aws.amazon.com/ko/waf/pricing/
아직은 인프라에 집중하는 것 보다 서비스적 구색을 갖추는거에 집중을 하는 것이 나을 것 같아서 bot control 도입을 고민해보도록 했다.
'TIL' 카테고리의 다른 글
Git action + CICD (EC2 + ECR) (1) | 2024.08.30 |
---|---|
smtp sendgrid 이메일 보내기 (0) | 2024.08.29 |
UI 라이브러리 초기세팅 (0) | 2024.06.27 |
토글버튼 만들어보기 (0) | 2024.06.20 |
렌더링과 리렌더링 최적화(메모이제이션) (0) | 2024.05.02 |