Certbot으로 HTTPS설정하기

JeongYong Park·2023년 8월 18일
1

이슈 트래커 프로젝트를 진행하면서 클라이언트-서버 통신 간을 안전하게 진행하기 위해 SSL 인증서를 적용해 HTTPS 통신을 수행하기 위해서 Certbot을 이용해보았습니다. HTTPS 통신과정의 이해와 어떻게 적용했는지 남기려고 합니다.

HTTPS

HTTPS는 말그래로 SSL(Secure Socket Layer)에 HTTP를 얹은 프로토콜입니다. 즉 보안이 보장된 HTTP 이라고 볼 수 있습니다.

HTTPS는 SSL 핸드쉐이크를 통해 클라이언트와 서버 간 연결을 진행하게 됩니다. 이 과정은 꽤 복잡하기 때문에 먼저 대칭키, 비대칭키 암호화 방식을 알 필요가 있습니다.

대칭키

대칭키는 말 그대로 암호화와 복호화시 사용하는 키가 동일한 암호화 기법입니다. 그러기 위해서는 양쪽이 모두 같은 키를 가져야 한다는 특징이 있습니다.

위 그림에서 A에서 B로 데이터를 전송할 때 대칭키를 통해 암호화를 하고 이를 받은 B는 같은 키를 통해 복호화를 진행할 수 있습니다.

그런데 이 방식에는 단점이 하나 있습니다. 바로 서로 같은 키를 가지기 위해 키를 주고 받아야 한다는 점입니다. 만약 A에서 B로, 혹은 B에서 A로 대칭키를 전달할 때 대칭키가 탈취되면 다른 사람도 데이터를 복호화 할 수 있게 됩니다.

이런 배경에서 나온 것이 비대칭키(공개키) 방식입니다.

비대칭키(공개키)

공개키 방식은 대칭키 방식과 다르게 키가 두 개 존재합니다. a라는 키로 암호화를 했다면 b라는 키로 복호화할 수 있고 b키로 암호화하면 a키로 복호화를 할 수 있게 됩니다. 둘 중 하나를 공개키, 나머지 하나를 비공개키로 정하게 됩니다.

HTTPS는 대칭키 암호화 방식과 비대칭키 암호화 방식을 모두 사용하는 프로토콜입니다.

각 키를 이용해서 데이터를 주고받는 순서를 알아보겠습니다.

  1. A의 공개키를 B에게 전달합니다.
  2. B는 A에게 데이터를 전달하기 위해 1에서 받은 공개키를 통해 데이터를 암호화합니다.
  3. A는 받은 데이터를 비공개키를 통해 복호화합니다.

A의 공개키가 탈취되어도 이를 복호화할 수 있는 것은 A의 비공개키를 통해서만 가능하기 때문에 대칭키 방식의 단점을 해결했다고 볼 수 있습니다.

그런데 데이터를 주고받을 때 A의 비공개키로 데이터를 암호화하는 경우도 있습니다. 이는 공개키가 탈취될 경우 데이터가 그대로 보이는 문제가 발생하는데 왜 사용되는 것일까요?

이 방식의 목적은 데이터의 보호가 목적이 아니기 때문입니다.
A에서 자신의 비공개키로 암호화된 데이터를 전달하고 이를 복호활 수 있다면 이는 A에서 보낸 데이터임을 보장할 수 있기 때문입니다.

즉, 공개키로 복호화 가능한 경우 정보를 전달한 사람의 신원을 보장해줍니다. 이것을 전자 서명이라고 하고 SSL 통신에서 사용됩니다.

SSL 인증서

SSL 통신에서 SSL 인증서를 사용하게 됩니다. SSL인증서에는 다음과 같은 정보가 포함되어 있습니다.

  • 서비스의 정보 (인증서를 발급한 CA, 서비스의 도메인 등)
  • 서버 측 공개키 (공개키의 내용, 공개키의 암호화 방법)

    🧐 CA?
    인증서의 역할은 클라이언트가 접속한 서버가 신뢰할 수 있는 서버임을 보장하는 역할을 합니다. 이 역할을 하는 기업들이 있는데 이런 기업들을 CA(Certificate Authority)라고 합니다.

위와 같은 내용들은 CA에 의해 암호화됩니다. 이때 사용하는 방식이 공개키 방식입니다. CA는 자신의 CA 비공개키를 이용해 서버가 CA에게 제출한 인증서를 암호화합니다.

그러면 이를 받은 클라이언트는 어떻게 CA의 비공개키로 암호화된 데이터를 복호화할 수 있을까요?
브라우저는 CA 리스트를 알고 있기 때문입니다. 이말은 브라우저는 CA 리스트와 함께 CA의 공개키를 이미 알고 있다는 얘기가 됩니다.

HTTPS 통신 과정

HTTPS는 위 대칭키 암호화 방식과 비대칭키 암호화 방식을 모두 이용합니다. 먼저 비대칭키 방식을 이용해 대칭키를 주고받고, 실제 데이터는 대칭키로 암호화/복호화를 진행해 주고받습니다.

간단하게 말했지만 실제는 좀 더 복잡합니다. 먼저 간략하게 설명하자면
handshake -> 통신 -> 통신종료 과정으로 진행됩니다. 좀 더 자세히 HTTPS 통신 과정을 알아보겠습니다.

핸드쉐이크 (Hand shake)

SSL 통신은 데이터를 주고받기 전에 서버가 신원이 검증된 서버인지, 어떻게 데이터를 암호화 할지 등에 대해 핸드쉐이크 과정을 통해 확인합니다.

  1. Client Hello
    • 먼저 클라이언트가 서버에 접속하는 단계로 시작합니다.
    • 클라이언트 측에서 랜덤 데이터(대칭키 제조에 필요. 아래에서 설명)를 생성후 전달합니다.
    • 클라이언트가 지원하는 암호화 방식들을 전달합니다.
      • 클라이언트가 가능한 암호화 방식을 서버에 알려주기 위해서입니다.
  2. Server Hello
    • 서버 측에서 Client Hello에 대한 응답으로 서버측 랜덤 데이터를 생성후 전달합니다.
    • 서버가 선택한 클라이언트의 암호화 방식을 전달합니다.
    • SSL 인증서를 전달합니다.
  3. 인증서 복호화
    • 클라이언트는 Server Hello 단계에서 넘어온 SSL 인증서를 복호화 합니다.
      • 이때 SSL 인증서는 CA의 비공개키로 암호화되어 있습니다.
      • 브라우저는 CA리스트와 CA의 공개키를 알고 있기 때문에 이를 이용해 인증서를 복호화 합니다.
    • 인증서 복호화가 성공한다면 이는 신원이 검증된 서버임을 보장하는 것입니다.
    • 클라이언트는 Client Hello, Server Hello 각 단계에서 생성한 랜덤 데이터를 가지고 pre master secret이라는 키를 생성합니다.
      • pre master secret은 임시적인 보안키입니다.
    • 이 키를 서버 측에 전달하기 위해 공개키 방식을 이용합니다. SSL 인증서에는 서버의 공개키가 포함되어 있기 때문에 이를 통해 pre master secret 키를 암호화해 전달합니다.
  4. pre master secret 복호화
    • 서버는 자신의 비공개키를 이용해 pre master secret을 복호화합니다.
    • 클라이언트와 서버는 각각 자신의 pre master secret과 서버의 pre master secret을 가지고 master secret을 생성합니다.
    • master secret을 통해 세션키를 생성하고 세션키를 이용해 서로가 데이터를 주고받을 때 암호화/복호화 를 수행합니다.
  5. 클라이언트와 서버는 핸드쉐이크의 종료를 서로에게 알립니다.

통신

통신 단계는 클라이언트와 서버가 데이터를 주고받는 단계입니다.

통신 종료

데이터의 전송이 모두 끝나면 SSL 통신이 끝났음을 서로에게 알려줍니다. 이때 master secret은 폐기 합니다.

Certbot으로 HTTPS 적용

1. 가비아에서 도메인 구매하기

가비아에서 도메인을 하나 구매합니다.

도메인 등록

DNS에 도메인을 등록합니다. 가비아의 DNS 설정으로 가서 아래와 같이 설정합니다. 값/위치에는 NGINX를 설치할 EC2의 IP주소를 기입합니다.

2. NGINX 설치

아래의 명령어를 통해 EC2에 NGINX를 설치해줍니다.

sudo apt update
sudo apt install nginx

3. Certbot 설치

HTTPS는 통신과정에서 인증서를 필요로 하기 때문에 인증서를 발급해야 합니다.
이를 간단하게 진행해주는 Certbot을 설치해줍니다. Certbot은 무료 오픈소스 소프트웨어로 Let's Encrypt 인증서를 통해 HTTPS 설정을 가능하게 합니다.

아래의 명령어를 통해 Certbot을 설치합니다.

sudo snap install certbot --classic

4. 인증서 발급

Certbot은 도메인에 인증서를 발급해주면서 NGINX에 관련 설정을 자동으로 세팅해줍니다.

아래 명령어를 입력해 인증서를 발급합니다.

sudo certbot --nginx -d {도메인}

위 명령어 사용시 이메일을 입력하라는 명령이 나올텐데 이메일을 입력해주고 이메일에서 인증을 눌러주면 설정이 완료됩니다.

5. NGINX 설정

아래 경로로 이동해 default 파일을 수정해줍니다.

/etc/nginx/sites-available

default파일을 열어보면 cerbot이 자동으로 https 관련 설정을 해줄 것입니다.
하지만 자동설정만은 https 설정만 해줄 뿐이지 리버스 프록시의 역할등의 추가적인 설정이 필요합니다.

server {
        server_name codesquad-project.site; # managed by Certbot

        location / {
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 클라이언트가 프록시 처리한 모든 서버의 IP 주소 목록
                proxy_set_header X-Forwarded-Proto $scheme; #프록시 서버의 HTTP 응답이 HTTPS로 변환
                proxy_set_header X-Real-IP $remote_addr; # 실제 방문자의 원격 ip 주소
                proxy_set_header Host $http_host; # 클라이언트가 요청한 원래 호스트 주소

                proxy_pass http://{private-ip}:8080; # 프록시 해줄 서버의 IP
        }

        listen [::]:443 ssl ipv6only=on; # managed by Certbot
        listen 443 ssl; # managed by Certbot

        # SSL 인증 설정
        ssl_certificate /etc/letsencrypt/live/codesquad-project.site/fullchain.pem; # managed by Certbot
        ssl_certificate_key /etc/letsencrypt/live/codesquad-project.site/privkey.pem; # managed by Certbot
        include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}

server {
        # http로 요청이 오면 https로 리다이렉트
        if ($host = codesquad-project.site) {
                return 301 https://$host$request_uri;
        } # managed by Certbot


        listen 80 ;
        listen [::]:80 ;

        server_name codesquad-project.site;

        return 404; # managed by Certbot
}

6. 재시작

모든 설정이 완료되었으니 NGINX를 재시작 해줍니다.

sudo systemctl restart nginx

결론

certbot을 통해 간단하게 HTTPS 통신을 적용할 수 있었습니다.
또한 NGINX를 리버스 프록시 처럼 사용하면서 클라이언트가 Spring WAS에 직접적으로 연결되지 않게 되고 WAS가 늘어나게 되어도 SSL 인증서를 추가로 발급받지 않게 되니 확장성 측면에서도 좋을 것 같습니다.

참고 자료

https://opentutorials.org/course/228/4894

profile
다음 단계를 고민하려고 노력하는 사람입니다

0개의 댓글