AWS 환경에서 node 앱 https 서비스 하기

시작

지난 번 포스팅에서 이어 AWS EC2에서 서비스하고 있는 express 어플리케이션을 HTTPS 로 서비스하는 방법에 대해 공유해보고자 합니다. 대부분의 웹 서비스들은 HTTP로 접속하는 경우에도 HTTPS로 리다이렉트되도록 서비스하고 있습니다. HTTP와 HTTPS 의 차이는 데이터 전송 시 secure encoding 여부라 볼 수 있습니다. data를 암호화해서 전송하므로 좀 더 보안에 유리한 측면이 있습니다. 이번 포스팅에서는 AWS 에서 제공하는 기능을 최대한 활용하여 HTTPS 서비스해보도록 합니다.

HTTPS Certification

HTTPS 서비스 사용시 공인된 CA 기관의 인증서가 필요합니다. AWS 서비스 중 하나인 Certification Manager를 사용하면 Amazone에서 발급되는 인증서를 사용하여 간편하게 서비스할 수 있습니다. 등록방법은 다음과 같습니다. 도메인 검증 시 AWS Route53를 통해 도메인을 관리하는 경우 클릭으로 CNAME 생성되므로 좀 더 간편하게 진행하실 수 있습니다.

  1. 인증 기관 선택
  2. 도메인 연결
  3. 도메인 검증 (CNAME 등록)

Load Balancer

HTTPS 요청이 CA 인증기관을 거쳐 EC2에 request가 정상적으로 도달하도록 설정해봅시다. Certification Manager를 통해 생성한 인증서를 도메인에 연결을 완료시켰습니다. 이 포스팅에서 로드 밸런서를 사용하여 SSL 인증을 거쳐 EC2에 요청이 전달되도록 할 것입니다. 그림으로 요약하면 다음과 같습니다.

AWS EC2 > Load Balancer 생성해봅시다. 리스너는 HTTP / HTTPS 설정을 추가합니다.

다음 단계에서 HTTPS 리스너를 설정한 경우에 ACM에서 인증서 선택를 통해 간편하게 SSL 인증 설정을 할 수 있습니다. 만약 이전 단계에서 리스너에 HTTPS가 없는 경우 해당 단계는 무시됩니다.

다음 단계 3. 보안 그룹 설정에서는 EC2 Inbound 에 HTTP / HTTPS 포트가 설정되도록 합니다. 기존에 사용하던 보안 그룹에 Inbound 설정을 해도 무관합니다.

  1. 라우팅 구성에서는 로드 밸런스가 dispatch 할 프로토콜 및 대상 그룹을 설정합니다. 우선은 대상 그룹 및 헬스 체크 모두 HTTP로 설정하겠습니다.
  1. 대상 등록에서는 대상그룹에 맞는 인스턴스를 연결하여 로드밸런스 설정을 마무리짓습니다.

위 과정을 통해 로드 밸런서 설정이 완료되었습니다. https 호출 시 ACM에서 인증하여 EC2로 요청될 것입니다. 하지만 지금 설정으로는 정상적인 HTTPS 서비스가 불가합니다. 다음 단계로 넘어갑시다.

Reverse Proxy

로드 밸런서 설정 이후 특별한 설정을 하지 않는 경우에 EC2 Express App 8080 포트를 Listen 하고 있을 겁니다. 도메인을 아무리 호출해도 Bad Request 오류가 발생하는 상황입니다. 더불어 로드밸런스의 헬스 체크 (대상 그룹의 대상이 정상적인 응답을 하는지 주기적으로 호출하여 체크)도 실패하게 됩니다.

NGINX의 Reverse Proxy 기능을 통해 HTTP / HTTPS 호출 모두 Express App의 8080 포트로 호출되도록 변경하겠습니다. 이 과정을 거치면 정상적으로 어플리케이션을 서비스할 수 있습니다.

EC2에 NGINX 를 설치해 봅시다. 필자의 OS 환경은 Unbuntu입니다.

sudo apt-get install nginx
nginx -v

설치가 정상적으로 완료된 경우에는 NGINX Reverse Proxy 설정을 할 차례입니다. /etc/nginx/sites-enabled 에 domain.conf 파일을 추가하여 reverse proxy 설정을 하도록 하겠습니다.

cd /etc/nginx/sites-enabled
sudo cp default domain.conf
sudo vi domain.conf

vi 를 통해 domain.conf 설정을 아래와 같이 변경해줍니다.

server {
        listen 80;
        listen 443;

				# 내 도메인 주소
        server_name domain.com;

				# Note! NGINX 에서 HTTP request Redirect   
				# 만약 AWS 로드 밸런서 Health Check이 HTTP인 경우 Fail 되므로 우선 사용 X
				# NGINX 단에서 리다이렉트 사용 시 해당 주석 부분 사용

				#proxy_set_header X-Forwarded-Proto $scheme;
        #if ( $http_x_forwarded_proto != 'https' ) {
        #       return 301 https://$host$request_uri;
        #}

		    location / {
	        proxy_set_header X-Real-IP $remote_addr;
	        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
	        proxy_set_header Host $http_host;
	        proxy_set_header X-NginX-Proxy true;

					# 서비스 되고 있는 Express App 포트
	        proxy_pass <http://127.0.0.1:8080>;
	        proxy_redirect off;
    }

}

설정을 마쳤다면 NGINX 를 재시작해줍니다.

sudo systemctl restart nginx 
sudo systemctl status nginx

지금까지 설정을 완료하였다면 HTTP / HTTPS 호출이 모두 정상적으로 Express로 호출되는 것을 볼 수 있습니다. 하지만 HTTP 호출이 HTTPS 로 리다이렉트 되지는 않는다. 이에 대한 해결 방안은 두 가지가 있을 수 있습니다.

  • NGINX Reverse Proxy 시 HTTPS 리다이렉트
  • Express Application 단에서 HTTPS 리다이렉트

NGINX 에서 리다이렉트하는 경우 로드 밸런서의 Health Check 의 리다이렉트는 별도로 처리해야 Express App 까지 도달하여 Application 단위의 체크가 가능할 것입니다. 필자는 Application 단에서 리다이렉트를 구현해보았습니다. Express 앱 상단에 다음과 같은 코드를 삽입해줍니다.

// app.js

// healthcheck
app.get('/helath-check', (req, res) => {
  res.send('Health Success');
});

// redirect
// 로드 밸런싱 사용 시 Header 에 X-Forwarded-Proto 포함되어 요청됨
if (dotenv.APP_ENV === 'production') {
  app.use(function (req, res, next) {
    if (!req.secure && req.get('X-Forwarded-Proto') !== 'https') {
      res.redirect('https://' + req.get('Host') + req.url);
    } else next();
  });
}

설정을 완료하고 HTTP 로 도메인을 호출하는 경우 정상적으로 리다이렉트 됩니다.

마무리

AWS에서 제공하는 기능을 최대한 활용하여 Express 앱 HTTPS 로 리다이렉트하는 방법에 대해 알아보았습니다. 설정을 마무리하고 보니 NGINX / Application에서 모두 리다이렉트를 구현해도 좋을 것 같습니다. Node 앱을 서비스하는 조금의 도움이 되었으면 합니다. 읽어주셔서 감사합니다.

답글 남기기

이메일 주소는 공개되지 않습니다.