[SSL] Let's Encrypt - Certbot docker를 이용하여 SSL 인증서 발급받기

Sean park·2021년 6월 5일
3
post-thumbnail

웹 페이지의 보안을 위해 Https는 필수적으로 사용되고 있습니다. Https를 사용하기 위해서는 SSL 인증서가 필요합니다.
이번 글에서는 무료 SSL 발급 인증 기관인 Let's Encrypt에서 제공하는 Certbot Docker image를 이용하여 SSL 인증서를 발급 받는 방법을 알아보겠습니다.

본 글에서는 Docker의 설치와 사용법에 대해 다루지 않습니다. 기본적인 Docker 사용법을 숙지하시기 바랍니다. 또한 서버 인증에 필요한 도메인도 미리 준비하시길 바랍니다.

Let's Encrypt를 이용하여 SSL 인증서를 발급받는 방법에는 크게 3가지 방법이 있습니다.

  • Webroot : 외부 웹 사이트에서 해당 호스트 서버에 접근하여 검증. 도메인 호스트 서버에 사용자(개발자)가 설정한 Webroot 경로에 접근하여 검증
  • DNS : 도메인의 DNS 서버에 TXT 필드에 Certbot에서 발급한 임의의 값을 넣어두고, TXT 필드의 값을 검사하여 검증
  • Standalone : 호스트 서버 자체에서 인증을 시도하는 방식

이번 글에서는 Webroot 방식을 이용하여 SSL 인증서를 발급받는 방법에 대해 알아보겠습니다.

Webroot 방식은 서버의 root 디렉토리에 Let's Encrypt에서 발급한 임의의 값을 넣어두고, 외부에서 해당 서버에 접근했을때 웹 서버의 root 디렉토리에 임의의 값이 있는지 확인하여 서버 인증을 받는 방식입니다. Webroot 방식을 사용하면 현재 운영중인 서버에서도 인증과 갱신이 가능하다는 장점이 있습니다.

하지만 Webroot 방식은 와일드카드 도메인 인증이 불가능 합니다. 와일드카드 도메인은 *.domain.com과 같이 sub 도메인을 포함한 모든 도메인을 의미합니다. 와일드카드 인증을 받으면 모든 sub 도메인에서도 Https 설정이 가능하지만, 해당 기능은 DNS 방식만 지원합니다.

Nginx 서버 설정하기

Let's Encrypt로 부터 실제로 운영하고 있는 서버라는 사실을 인정받기 위해 외부에서 접근할 수 있는 서버를 실행시켜야 합니다.
Nginx를 통해 외부에서 서버에 접근할 수 있도록 Nginx를 설정 파일을 작성해주겠습니다.

SSL 인증서를 받기위해 임의의 디렉토리를 미리 생성한 후, 해당 디렉토리에서 실행하였습니다. 각자 상황에 맞게 디렉토리를 지정하기 바랍니다.
또한 Let's Encrypt 인증은 80 포트와 443 포트만 가능합니다.

server {
     listen [::]:80;
     listen 80;

     server_name domain.com www.domain.com;

     location ~ /.well-known/acme-challenge {
         allow all; 
         root /var/www/certbot;
     }
} 
  • server_name : SSL 인증을 받을 도메인 주소입니다. 도메인 위치에 인증받을 도메인을 적어줍니다. 서브 도메인도 같이 적어줍니다.
  • location : Let's Encrypt에서 '/.well-known/acme-challenge' 해당 경로를 통해 인증을 시도합니다. root라고 적혀있는 Nginx의 root 경로로 접속하여 인증을 시도합니다. 그래서 Webroot 라고 불립니다.

Nginx의 설정 파일을 모두 작성했으면, 작업 디렉토리/conf.d/default.conf로 저장합니다.
이미 사용중인 Nginx 파일이 있다면 '/.well-known/acme-challenge' 해당 경로에 대한 설정만 추가도 무방합니다.

Docker-compose

Nginx와 Certbot docker를 실행시킬 docker-compose.yml 파일을 작성해줍니다.

version: "3.8"
services:
    web:
        image: nginx:latest
        restart: always
        volumes:
            - work dir/conf.d:/etc/nginx/conf.d
            - work dir/certbot/conf:/etc/nginx/ssl
            - work dir/certbot/data:/var/www/certbot
        ports:
            - 80:80
            - 443:443

    certbot:
        image: certbot/certbot:latest
        command: certonly --webroot --webroot-path=/var/www/certbot --email myemail@google.com --agree-tos --no-eff-email -d domain.com
        volumes:
            - work dir/certbot/conf:/etc/letsencrypt
            - work dir/certbot/logs:/var/log/letsencrypt
            - work dir/certbot/data:/var/www/certbot

Docker volume을 유의하여 docker-compose.yml 파일을 작성합니다. Certbot command에 있는 --webroot-path와 nginx의 volume의 경로에 유의하시길 바랍니다.

command에 대해 자세히 알아보겠습니다

  • certonly : SSL 인증서만 발급 받겠다는 것을 의미합니다.
  • --webroot : webroot 방식을 사용한다는 것을 의미합니다.
  • --webroot-path : 서버의 webroot rudfh
  • --email : Let's Encrypt의 알림을 받을 이메일
  • --agree-tos : ACME 서버 구독 동의
  • --no-eff-email : EFF 재단에 email을 공유하지 않음
  • -d : 인증받을 도메인 명

SSL 인증서 인증받기

docker-compose.yml 파일을 모두 작성했으면 docker-compose를 실행시켜 SSL 인증서를 발급받습니다.

docker-compose up -d

위 커맨드를 실행하여 인증을 시도합니다.

Creating network "nginx-ssl_default" with the default driver
Pulling web (nginx:latest)…
latest: Pulling from library/nginx
8559a31e96f4: Pull complete
8d69e59170f7: Pull complete
3f9f1ec1d262: Pull complete
d1f5ff4f210d: Pull complete
1e22bfa8652e: Pull complete
Digest: sha256:21f32f6c08406306d822a0e6e8b7dc81f53f336570e852e25fbe1e3e3d0d0133
Status: Downloaded newer image for nginx:latest
Pulling certbot (certbot/certbot:latest)…
latest: Pulling from certbot/certbot
cbdbe7a5bc2a: Pull complete
26ebcd19a4e3: Pull complete
a29d43ca1bb4: Pull complete
979dbbcf63e0: Pull complete
30beed04940c: Pull complete
48a1f8a4d505: Pull complete
4416e9b4bbe0: Pull complete
8173b4be7870: Pull complete
21c8dd124dab: Pull complete
c19b04e11dc7: Pull complete
1b560611cec1: Pull complete
Digest: sha256:568b8ebd95641a365a433da4437460e69fb279f6c9a159321988d413c6cde0ba
Status: Downloaded newer image for certbot/certbot:latest
Creating nginx-ssl_certbot_1 … done
Creating nginx-ssl_web_1     … done

위와 같이 Nginx와 Cerbot docker image를 pull 받고 컨테이너를 실행합니다.

인증에 성공했는지 확인해봅시다.

docker-compose ps

docker-compose의 상태를 확인해서 아래와 같이 Certbot의 상태고 Exit 0으로 표시된다면 정상적으로 발급된 상태입니다!

Name                      Command               	State                     Ports
certbot  		  certbot certonly --webroot …  Exit 0                                           
web      		  /docker-entrypoint.sh ngin …  Up       		  0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp

만일 Certbot의 상태가 Exit 0이 아니라면 docker-comopse.yml과 log를 확인합니다.
log는 아래 커맨드로 확인 가능합니다.

docker-compose logs -f

인증에 성공하였으면 certbot/conf 경로 아래 SSL 키가 생성된것을 알 수 있습니다.
해당 키값을 실제 실행 시키는 웹 서버의 설정 파일에 적용합니다.

Nginx는 아래와 같이 SSL 인증서 파일을 설정해줍니다.

.
.
.

http {
   server {
    listen 443 ssl;

    server_name domain.com;

    ssl_certificate /etc/letsencrypt/archive/domain.com/fullchain1.pem;
    ssl_certificate_key /etc/letsencrypt/archive/domain.com/privkey1.pem;

.
.
.

각자 상황에 맞게 인증서 위치를 설정해줍니다.

인증서 갱신

Let's Encrypt에서 제공하는 인증서의 유효 기간은 90일 입니다. 따라서 90일 마다 인증서를 갱신해주어야 합니다.
인증서는 만료 기간이 30일 이내일때 재발급 가능하며 --force-renewal 옵션을 통해 강제 재발급이 가능하지만, 인증서 발급 제한사항에 위배될 가능성이 있어 추천드리지 않습니다.

인증서 발급에 유의할 제약사항에 대해 자세한 내용을 알고싶다면 아래 글을 참조하시길 바랍니다.

https://findstar.pe.kr/2018/09/08/lets-encrypt-certificates-rate-limit/

인증서 재발급을 위한 Certbot docker 커맨드는 아래와 같습니다.

docker run --rm --name certbot -v '/etc/letsencrypt:/etc/letsencrypt' -v '/var/log/letsencrypt:/var/log/letsencrypt' -v '/etc/letsencrypt/data:/var/www/certbot' certbot/certbot renew --server https://acme-v02.api.letsencrypt.org/directory --cert-name domain.com

Docker volume은 자신의 환경에 맞게 적절히 설정해주시길 바랍니다.
위 커맨드를 실행 한 후 아래 커맨드로 남은 인증서 만료일을 확인하여 정상적으로 갱신되었는지 확인합니다.

docker run -it --rm --name certbot -v '/etc/letsencrypt:/etc/letsencrypt' -v '/var/log/letsencrypt:/var/log/letsencrypt' -v '/etc/letsencrypt/data:/var/www/certbot' certbot/certbot certificates




여기까지 Let's Ecrypt와 docker를 이용한 SSL 인증서 발급받는 방법에 대해 알아보았습니다. 인증서를 자동으로 갱신하기 위해 Crontab 등을 활용할 수 있습니다. Crontab을 위한 자동 갱신 코드 첨부합니다. 이 또한 각자의 환경과 상황에 맞게 사용하시길 바랍니다.

#!/bin/bash

docker run --rm --name certbot -v '/etc/letsencrypt:/etc/letsencrypt' -v '/var/log/letsencrypt:/var/log/letsencrypt' -v '/etc/letsencrypt/data:/var/www/certbot' certbot/certbot renew --server https://acme-v02.api.letsencrypt.org/directory --cert-name domain.com

위 커맨드를 .sh 파일로 저장한 후 chmod 400등으로 실행 권한을 부여합니다.

이후 crontab -e에 갱신 시케줄을 등록합니다. 저는 매일 새벽 4시에 실행하도록 설정하였습니다.

* 4 * * * /mydir/certbot-renew.sh

자신의 환경에 맞게 /etc/crontab에 실행 환경변수를 설정해줍니다.

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin



감사합니다.

profile
제 코드가 세상에 보탬이 되면 좋겠습니다.

0개의 댓글