가상의 향수 쇼핑몰을 주제로 프로젝트를 만족스럽게 구현하였고, AWS를 이용하여 프론트엔드 / 백엔드 / 데이터베이스도 성공적으로 배포하였습니다.
회원 기능을 구현하면서 로그인 상태를 검증하고 지속할 방법으로 쿠키를 사용하였는데, AWS의 기본 배포 환경은 HTTP 프로토콜을 사용중이고 이로 인해 웹 보안 정책에 의해 쿠키 사용이 차단되는 문제가 발생하였습니다.
이렇게되자 쿠키를 기반으로 동작하는 회원 기능이 마비되어버렸고, 문제 해결 방법을 찾았지만 결국 HTTPS 프로토콜을 적용하는 것이 최선의 방법이라 판단하였습니다.
HTTP를 사용할 경우, 특히 로그인 정보와 같은 민감한 데이터를 포함한 쿠키는 쉽게 가로채질 수 있으며, 이는 보안상 큰 위험을 초래합니다. HTTPS는 데이터를 암호화하여 전송하기 때문에, 쿠키 정보가 중간에 가로채지 않도록 보호할 수 있습니다. 최신 웹 브라우저들은 보안을 강화하기 위해 HTTPS를 사용하는 웹사이트를 우선시합니다. 이러한 브라우저들은 HTTP 웹사이트에서 설정된 쿠키를 차단하거나 제한할 수 있습니다.
HTTPS 적용을 위해서는 우선 SSL/TLS 인증서가 필요합니다. 그런데 인증서 발급을 위해서는 개인 소유의 도메인이 별도로 필요했습니다.
도메인의 구입과 인증서 발급 방법은 여러가지이지만, 프로젝트 배포는 이미 AWS를 사용중이고 도메인과 인증서도 AWS에서 처리하게 되면 각각의 서비스 연동이 더 수월하기 때문에 HTTPS 적용을 위해서 추가적인 AWS 서비스를 사용하기로 결정하였습니다. HTTPS 도입 과정에서 추가로 사용된 서비스들은 아래와 같습니다.
인터넷 트래픽을 사용자가 지정한 인프라로 라우팅하고, 도메인 이름과 서브도메인을 관리할 수 있는 서비스. Route 53을 사용하여 새 도메인을 등록하거나 기존 도메인을 관리할 수 있습니다.
사용자가 SSL/TLS 인증서를 쉽게 프로비저닝, 관리, 배포할 수 있게 해줍니다. 이러한 인증서는 웹사이트와 서버의 보안을 강화하는 데 사용됩니다. AWS Route 53을 통해 구입한 도메인은 AWS Certificate Manager에서 SSL/TLS 인증서를 무료로 발급받아 사용할 수 있습니다.
전 세계에 분산된 서버 네트워크를 사용하여 웹 콘텐츠와 애플리케이션을 사용자에게 빠르고 안정적으로 제공하는 서비스. CloudFront를 사용하여 S3에서 호스팅되는 프론트엔드를 배포하고, Route 53을 통해 구입한 도메인과 연결할 수 있습니다.
들어오는 애플리케이션 트래픽을 여러 Amazon EC2 인스턴스에 자동으로 분산시킴으로써, 애플리케이션의 가용성과 내결함성을 향상시키는 서비스. HTTPS를 지원하며 SSL/TLS 인증서를 사용하여 백엔드로 들어오는 암호화된 트래픽을 처리할 수 있게 해줍니다.
HTTPS 도입을 위한 작업은 아래의 순서로 진행되었습니다.
AWS Route 53을 통해 도메인 구입
개인 정보 보호 설정 활성화 및 DNS 설정 준비
ACM에서 새 SSL/TLS 인증서 요청
도메인 소유권 증명을 위한 DNS 검증 방법 선택
ACM에서 제공한 CNAME 레코드 정보를 Route 53에 추가
인증서의 도메인 소유권 검증 완료 및 상태 확인
CloudFront를 이용하여 S3로 배포 중인 프론트엔드를 구입한 도메인으로 연결
SSL 인증서 적용하여 HTTPS 사용 설정
Load Balancer 설정하여 EC2 백엔드에서 HTTPS 사용 가능하도록 함
HTTP 및 HTTPS 리스너 설정 및 SSL 인증서 적용
EC2 인스턴스를 대상그룹으로 지정하여 트래픽 처리
S3에서 프론트엔드 파일을 갱신하였음에도, CloudFront에서 처리하는 도메인은 이전 버전의 프론트엔드를 출력함.
CloudFront는 콘텐츠를 캐시하기 때문에 최신 변경 사항이 반영되지 않을 수 있음. CloudFront 콘솔에서 캐시 무효화(invalidation)를 실행하여 캐시된 내용을 강제로 새로고침하여 문제 해결.
ERR_CERT_COMMON_NAME_INVALID 에러.
Route 53에서 설정한 레코드의 URL과 ACM으로 발급받은 인증서의 적용된 URL 값이 일치하지 않아 유효하지 않은 인증서의 판정을 받음. 두 URL을 일치시켜 문제 해결.
로드 밸런서를 설정하고, HTTPS 트래픽이 정상 처리되는 것을 테스트했는데.. 연결 테스트(헬스체크)에서 Unhealthy 판정.
모든 작업을 완료하고 트래픽이 정상 처리되는 것만 확인하면 되는 단계에서 발생한 최후의 오류. 해결을 위해 몇 주 동안 무던히 노력했지만 결국 HTTPS 도입 시도를 수포로 만들고 말았습니다..
문제의 원인은 로드 밸런서에서 HTTPS 트래픽을 처리하지 못하고 있는 것이었습니다.
로그에서 elb_status_code가 "502"이고, target_status_code가 "-"인 것을 보아서는 로드 밸런서가 HTTP 502 오류를 반환하고 있으며, 이는 대상에서 적절한 응답을 받지 못하고 있는 것으로 보입니다.
네트워크 탭에서 확인된 정보에 따르면, 클라이언트(브라우저)는 OPTIONS 메소드를 사용하여 사전 요청(이른바 "preflight" 요청)을 서버에 보내고 있지만 이 사전 요청에 대한 응답이 없거나, 응답이 잘못되었을 때 502 오류가 발생할 수 있다고 합니다.
- 보안 그룹 및 네트워크 ACL 설정 확인:
EC2 인스턴스에서는 3001 포트를 허용하고 있으며, 네트워크 ACL 설정은 초기값 그대로 모든 트래픽을 허용하고 있는 상태임을 확인했습니다.
- 로드 밸런서 대상 그룹 설정 확인:
로드 밸런서의 대상 그룹 설정을 HTTP와 HTTPS로 구성하였고, EC2 인스턴스에서 사용하는 포트인 3001 포트로 적용되고 있음을 확인했습니다.
- ACM 인증서 유효성 확인 및 상태 검증:
발급된 SSL/TLS 인증서가 유효하며, Load Balancer와 CloudFront에 제대로 적용되었고, 모든 서브도메인이 포함되어있으며 유효한 상태임을 확인하였습니다.
- EC2 인스턴스 포트 설정 확인:
인스턴스 인바운드 규칙에 3001 포트가 허용중이며, SSH로 인스턴스에 접근하여 백엔드 서버가 포트 3001에서 수신 대기 중임을 확인했습니다.
- SSL/TLS 핸드셰이크 확인:
Load Balancer 로그를 통해 SSL/TLS 핸드셰이크가 성공적으로 수행되고 있음을 확인했습니다.
- 서버 시간 확인 및 재동기화:
EC2 인스턴스의 시간이 NTP(chronyd)를 통해 정확히 동기화되어 UTC 기준으로 적용됨을 확인하였습니다.
- Route 53 레코드 수정 및 서브도메인 설정:
서브 도메인 app.essence-aura.com 생성 및 로드 밸런서 라우팅 연결
메인 도메인에서 S3로 배포 중인 프론트엔드에 접근하고, 서브 도메인을 통해 백엔드 요청 전송
- Route 53 레코드 수정:
프론트엔드에서 백엔드로 요청을 보내는 서브 도메인 app.essence-aura.com을 생성하고, 로드 밸런서 라우팅을 연결하였습니다.
메인 도메인 essence-aura.com에서는 S3로 배포 중인 프론트엔드 정적 파일에 접근하며, 프론트엔드 내부적으로는 서브 도메인 app.essence-aura.com에게 백엔드 요청을 보내게 됩니다.
도메인 구입비 13달러와 3주의 시간이 수포로 돌아가는 순간..
결과적으로 HTTPS 도입 시도는 실패로 마무리되고 말았습니다. S3로 배포 중인 프론트엔드의 트래픽을 CloudFront을 이용해 Route 53으로 구입한 도메인과 연결, 구입한 도메인으로 접속했을 때 구현한 프론트엔드 내용이 잘 렌더링 되는 것을 확인했으나 서버로 요청을 보내는 것이 불가능한 상황입니다.
3주 가까운 시간동안 구글, AWS 공식문서, 여러 개발 커뮤니티에 ChatGPT까지 붙들고 문제 해결을 위해 엄청난 시간과 노력을 쏟아부었습니다.
정말 불행하고도, 슬픈 결론이지만 시도할 수 있는 방법들을 대부분 시도해보고 몇 번이고 반복했음에도 HTTPS 도입에 실패하였습니다. 문제 해결에 소모되는 시간이 너무 길어지는 탓에, 부득이하게 추가적인 해결 시도를 잠시 정지하고 밀려있는 다른 일에 집중하기로 결정하였습니다. HTTPS 도입같은 중요한 요소를 아예 포기할 수는 없으며 나중에 다시 시도해볼 예정이지만 우선 지금 시점에서는 더 이상 시간을 소모하지 않기로 결정하였습니다.