AWS SSL 적용

김소희·2023년 8월 31일
2

ec2로 서버 배포를 하고, 깃허브로 클라이언트 배포를 했으나
net::ERR_SSL_PROTOCOL_ERROR 가 뜨면서 잘 작동하지 않았다.

AWS에서 제공하는 인증서 관리 서비스인 ACM(AWS Certificate Manager)을 이용해서 웹 서버에 SSL을 적용하면 HTTPS요청을 처리할 수 있게 된다. 그런데 HTTPS 연결을 효과적으로 관리하고 분산시키려면 로드 밸런서가 필요하므로 ACM과 로드밸런서를 이용한 SSL인증서 관리를 해보려고 한다.

로드밸런서 : 클라이언트의 요청으로 인한 서버의 과부하 혹은 트래픽을 분산시켜줌으로서 속도 면에서나 서버의 가용성, 부하적인 측면에서 도움을 줄 수 있는 기술

  • SSL/TLS 종료 지원 : 로드밸런서가 SSL/TLS 연결 종료를 처리하여 클라이언트와 로드 밸런서 사이의 암호화된 연결을 해제하고 복호화한 후, 내부 서버와의 일반 HTTP 연결을 유지한다.
  • 보안 및 개인 정보 보호 : 로드 밸런서를 통해 SSL/TLS 암호화를 적용하면 사용자와 웹 애플리케이션 간의 통신이 외부에서 엿볼 수 없도록 보호된다.
  • 부하 분산 및 확장성 : HTTPS 연결은 복잡한 계산 작업을 필요로 하는데 로드 밸런서는 서버 간 트래픽을 균등하게 분산하여 성능을 최적화하고 서버 부하를 줄인다.
  • 고가용성 : 로드 밸런서는 여러 가용 영역에 걸쳐 배포하므로 하나의 가용 영역에서 장애가 발생하더라도 다른 가용 영역의 로드 밸런서가 트래픽을 처리할 수 있어서 서비스 중단을 방지한다.
  • 인증서 관리 : 로드 밸런서를 통해 인증서를 관리하면 간편하게 갱신하고 관리할 수 있다.

ACM SSL 적용 과정

사전작업 : 도메인 구입
1. ACM(amazon certificate manager) 에서 SSL 인증서 발급 및 호스팅 영역에 레코드 등록
2. Target group 생성
3. application load balancer 생성 및 security 정책 설정
4. route53의 domain A 레코드 변경

SSL 적용 후 동작 과정

  1. 클라이언트의 요청(Request)을 보낸다.
  2. 해당 요청을 로드밸런서가 HTTPS(port 443) 요청인지 일반적인 HTTP(port 80) 요청인지 판단한다.
  3. 만약 HTTP 요청이면 이 요청을 HTTPS 요청으로 Redirection 합니다. HTTPS 요청이면 Target Group(로드밸런싱 될 대상들) 의 80번 port로 요청을 포워딩한다.
  • 인증서 요청에서 퍼블릭 인증서를 선택 후 다음을 누른다
  • 도메인 네임을 입력하고 인증서를 생성한다.
  • 발급된 인증서에서 "Rout 53에서 레코드 생성"을 선택한다.
  • AWS에서 도메인을 구입한게 아니기 때문에 필터를 지워야 도메인이 검색된다.
  • 검증대기 상태가 끝나면 Rout 53에서 레코드 생성하려고 했으나 검증이 성공으로 넘어가지 않았다.

Rout 53에서 레코드 생성을 할 수 없어서 찾아보니 AWS DNS 서비스를 이용하여 도메인을 적용한 것이 아니라 외부 서비스로 도메인을 생성했기 때문에 EC2 서버에 nginx와 certbot 과 같은 인증서를 직접적으로 설치하고 설정하는 방법으로 해야했다.

나는 내도메인.한국에서 도메인을 구입해서 IP연결에 ec2 퍼블릭 IPv4 주소를 입력했으므로 인증서를 직접 설치해야했다.

아마존 리눅스 EC2 SSL 적용 과정

  1. nginx를 설치

    sudo yum install nginx

  2. 80번 포트가 들어오면 8080번 포트로 포워딩
sudo iptables -t nat -L --line-numbers
Chain PREROUTING (policy ACCEPT)
num  target     prot opt source               destination
1    REDIRECT   tcp  --  anywhere             anywhere tcp dpt:http redir ports 8080

Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
num  target     prot opt source               destination

Chain POSTROUTING (policy ACCEPT)
num  target     prot opt source               destination

$ sudo iptables -t nat -D PREROUTING 1

$ sudo iptables -t nat -L --line-numbers
Chain PREROUTING (policy ACCEPT)
num  target     prot opt source               destination

Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
num  target     prot opt source               destination

Chain POSTROUTING (policy ACCEPT)
num  target     prot opt source               destination
$ sudo vi /etc/nginx/nginx.conf

user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {}

http {
  upstream app {
    server 127.0.0.1:8080;
  }

  server {
    # 80번으로 요청이 오면, localhost의 8080번 포트로 연결해 준다는 의미입니다.
    listen 80;

    location / {
      proxy_pass http://app;
    }
  }
}

$ sudo service nginx restart
  1. SSL 인증서를 발행할 수 있는 툴인 Certbot을 설치
$ sudo dnf install -y python3 augeas-libs pip
...
Complete!
$ sudo python3 -m venv /opt/certbot/
$ ls /opt/certbot
bin  include  lib  lib64  pyvenv.cfg
$ ls /opt/certbot/bin
Activate.ps1  activate  activate.csh  activate.fish  pip  pip3  pip3.9
 python  python3  python3.9
$ sudo /opt/certbot/bin/pip install --upgrade pip
....
Successfully installed pip-23.1.2
$ sudo /opt/certbot/bin/pip install certbot
...
Successfully installed ConfigArgParse-1.5.3 PyOpenSS-23.1.1 acme-2.6.0
certbot-2.6.0 certifi-2023.5.7 cffi-1.15.1 charset-normalizer-3.1.0 co
nfigobj-5.0.8 cryptography-40.0.2 distro-1.8.0 idna-3.4 josepy-1.13.0 
parsedatetime-2.6 pycparser-2.21

$ sudo ln -s /opt/certbot/bin/certbot /usr/bin/certbot
  1. 주어진 TXT 레코드 값으로 DNS 세팅

    sudo certbot certonly -d [도메인 주소] --manual --preferred-challenges dns

  1. nginx.conf 수정하여 SSL 설정
$ sudo vi /etc/nginx/nginx.conf

user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {}

http {
  upstream app {
    server 127.0.0.1:8080;
  }

  # Redirect all traffic to HTTPS
  server {
    listen 80;
    return 301 https://$host$request_uri;
  }

  server {
    listen 443 ssl;
    ssl_certificate /etc/letsencrypt/live/[도메인 주소]/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/[도메인 주소]/privkey.pem;

    # Disable SSL
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

    # 통신과정에서 사용할 암호화 알고리즘
    ssl_prefer_server_ciphers on;
    ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;

    # Enable HSTS
    # client의 browser에게 http로 어떠한 것도 load 하지 말라고 규제합니다.
    # 이를 통해 http에서 https로 redirect 되는 request를 minimize 할 수 있습니다.
    add_header Strict-Transport-Security "max-age=31536000" always;

    # SSL sessions
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

    location / {
      proxy_pass http://app;
    }
  }
}
  1. 3개월마다 인증서 자동갱신하도록 설정

    sudo vi /etc/crontab
    15 3 * * * certbot renew --quiet --renew-hook "/etc/init.d/nginx reload" 를 맨 아래줄에 추가

😆 완 료 😆

남자친구가 프론트엔드 배포를 깃으로 도와줘서 이제 프로그램이 언제나 작동하게 되었다.

< 참고한 자료 >
ACM 공식문서
무료 도메인 구입방법
EC2에 인증서 설치
아마존 리눅스 Let's Encrypt 설치
EC2에 도커 설치
개발남발님 블로그
나의개발족보님 블로그

profile
백엔드 자바 개발자 소희의 노트

0개의 댓글