certbot을 통해 Let's Encrypt에서 제공하는 무료 ssl 인증서 적용하는 방법
ssl 인증서는 클라이언트와 서버 간의 통신을 제3자가 보증해 주는 전자화된 문서인데요.
ssl 인증서를 사용함으로써 통신 내용이 공격자에게 노출되는 것을 막을 수 있으며, 통신 내용의 악의적인 변경을 방지할 수 있습니다.
또한 클라이언트는 접속하려는 서버가 신뢰할 수 있는 서버인지를 해당 인증서를 통해 판단할 수 있게 됩니다.
/*
SSL(Secure Socket Layer)과 TLS(Transport Layer Security Protocol)는 같은 의미인데요. SSL이 표준화기구 IETF의 관리로 바뀌면서 TLS라는 이름으로 바뀌게 되었으며, 아직까지 TLS라는 이름보다 SSL이라는 명칭이 더 많이 사용되고 있습니다.
*/
해당 포스팅에서는 "certbot이라는 오픈소스 툴을 사용하여 let's encrypt로부터 ssl 인증서를 발급받고 http 통신을 https로 암호화하는 과정"을 정리하였습니다.
적용에 앞서 필요한 것은 인증서를 적용할 서버와 개인 도메인이 준비되어 있어야 하는데요.
이때 도메인은 인증서를 적용할 서버에 연결되어 있어야 합니다. 또한 서버는 인증서 발급에 대한 http(80) 포트와 인증서를 발급받고 적용할 https(443) 포트에 대해 외부에 개방되어 있어야 합니다.
(아래는 Ubuntu 20.04.6 LTS 버전에서 실행된 예시이며, nginx가 적용되는 부분이 많기 때문에 nginx의 기본적인 동작 원리를 파악하고 보는 것이 이해에 도움이 됩니다.)
Let's Encrypt SSL 인증서 발급 방식
let's encrypt ssl 인증서 발급에는 'webroot', 'webserver', 'standalone', 'dns' 4가지 방식이 존재하는데요.
아래 내용을 통해 각각의 방식에 대한 내용 및 적용하는 방법을 살펴보겠습니다.
* Certbot 설치
sudo apt update
sudo apt-get install letsencrypt
letsencrypt에는 certbot이 포함되어 있기 때문에 패키지 관리 툴 apt를 통해 letsencrypt를 설치합니다.
certbot --version
그리고 해당 명령어를 통해 certbot 버전을 확인할 수 있습니다.
(해당 예시에서는 certbot 0.27.0가 설치되었습니다.)
sudo apt update
sudo api install certbot python3-certbot-nginx //nginx
sudo apt install certbot python3-certbot-apache //apache
아래에서 살펴볼 ssl 인증서 발급 과정들 중에서는 nginx나 apache와 같은 웹 서버가 전적으로 인증서를 제어하도록 하는 방법도 있는데요.
해당 방법을 사용하기 위해서는 웹 서버에 맞는(nginx or apache) certbot을 추가로 설치하여야 합니다.
1. webroot 방식
이미 실행 중인 웹 서버의 웹 루트 디렉터리 내에 인증서 유효성을 확인할 수 있는 파일을 업로드하여 인증서를 발급하는 방법입니다.
아래서 살펴볼 standalone 방식과 다르게 웹 서버(nginx or apache)의 중단 없이 발급할 수 있다는 특징이 있으며, 발급 이후 인증서의 자동 갱신도 가능합니다.
인증 방식은 인증서를 요청하는 도메인의 소유주임을 확인하기 위해 certbot의 웹 서버가 아닌, 서버의 웹 서버에서 특정 파일을 요청하여 인증하는 방식이며, 이때 아래 letsencrypt 폴더가 인증에 사용됩니다.
(/var/www/letsencrypt/.well-known/acme-challenge)
해당 폴더 생성 후 nginx 등의 웹 서버로 '{요청하는 도메인}/.well-known/acme-challenge' 안에 파일이 제공되도록 설정한 다음 명령어로 인증서를 받습니다.
mkdir -p /var/www/letsencrypt/.well-known/acme-challenge
* mkdir -p(-parents)의 경우 지정한 디렉터리 경로가 존재하지 않는다면 패턴에 맞게 디렉터리를 생성하는 명령어입니다.
다음은 webroot 경로를 알려주는 letsencrypt.conf 파일을 만드는데요. 해당 파일의 위치는 일반적으로 /etc/nginx/snippets/에 생성됩니다.
vim /etc/nginx/snippets/letsencrypt.conf
(vim 명령어를 통한 파일 생성 또는 수정)
location ^~ /.well-known/acme-challenge/ {
default_type "text/plain";
root /var/www/letsencrypt;
}
(letsencrypt.conf 파일의 내용)
include /etc/nginx/snippets/letsencrypt.conf;
letsencrypt.conf 파일을 정상적으로 생성했다면, 이어서 nginx 설정 파일의 server 영역에 파일을 참조할 수 있는 위 코드를 추가해 줍니다.
여기까지 설정을 마쳤다면 'systemctl restart nginx' 명령어를 통해 nginx를 다시 시작해 줍니다.
certbot certonly —webroot —webroot-path=/var/www/letsencrypt -d abcde.com
abcde.com 부분은 예시이며, 해당 부분에 실제 ssl 요청을 받을 도메인을 넣어주면 됩니다.
Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/abcde.com/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/abcde.com/privkey.pem
Your cert will expire on 2023-07-12.
여기까지 되었다면, 이메일 입력 후 Congratulations!라는 메시지와 함께 인증서가 발급된 것을 확인할 수 있는데요.
(2번째 줄과 4번째 줄의 경로는 인증서 및 인증서 키 관련 내용이며, 아래 nginx ssl 설정에서 해당 경로가 사용됩니다.)
***
여기서 인증서가 정상적으로 발급되었음에도 불구하고 'ERR_CONNECTION_REFUSED'라는 메시지와 함께 https에 대한 요청 결과가 나오지 않을 수 있습니다.
이유는 nginx에서 443 port로의 접근에 대한 설정이 되어 있지 않기 때문인데요.
server {
listen 80;
server_name abcde.com;
root /home/abcde/;
location / {
return 301 https://abcde.com$request_uri;
}
}
server {
listen 443 ssl default_server;
server_name abcde.com;
ssl on;
ssl_certificate /etc/letsencrypt/live/abcde.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/abcde.com/privkey.pem; // 비공개 키
ssl_protocols TLSv1.1 TLSv1.2;
include /etc/nginx/snippets/letsencrypt.conf;
location / {
root /home/abcde/;
try_files $uri $uri/ =404;
}
}
(nginx 설정 파일 / abcde.com은 예시입니다.)
nginx 설정 파일에 ssl에 대해 위 코드를 추가하고 nginx를 재실행하게 되면 https에 대한 요청이 정상적으로 되는 것을 확인할 수 있습니다.
2. webserver 방식
nginx나 apache 같은 웹 서버에서 직접 ssl 인증을 실시하여 인증서를 발급받는 방식입니다.
발급이나 갱신을 위해 웹 서버를 중단시킬 필요가 없으며, 웹 서버가 알아서 적절한 ssl 옵션을 제안하여 적용해 준다는 특징이 있습니다.
/*
해당 인증 방식을 사용 시 nginx, apache 설정에서 도메인이 제대로 설정되어 있어야 한다는 특징이 있습니다. nginx의 경우 설정이 적용되는 파일에 server_name 부분을 설정합니다.
*/
sudo certbot --nginx -d abcde.com
해당 명령어를 실행하면 Deploying Certificate to VirtualHost /etc/nginx/sites-enabled/default라는 가상 포스트에 인증서를 배포하고 있다는 메시지가 나오는데요.
(설정된 nginx 내용에 따라 default가 아닌 다른 파일이 될 수 있습니다.)
이후 https redirect 여부에 대한 선택 작업이 완료되면 해당 파일에 ssl 관련 설정이 추가로 적용되는 것을 확인할 수 있습니다.
***
certonly 값을 붙이는 이유는 웹 서버의 설정 파일에 인증서 관련 내용을 임의로 수정하지 않도록 하겠다는 것인데요.
여기서는 certonly 없이 명령어를 실행하였기 때문에 웹 서버가 ssl 인증서에 대한 내용을 알아서 적용해 준 것입니다.
3. standalone 방식
standalone 방식은 80 포트에 가상 standalone 웹 서버를 띄워 인증서를 발급받는 방식인데요.
해당 방식으로 인증서를 발급하기 위해서는 기존의 80 포트를 사용하는 서비스(nginx or apache)를 중지해야 한다는 특징이 있습니다.
또한 맨 위에서 이야기한 것처럼 A 레코드로 설정된 도메인이 해당 서버에 연결되어 있어야 하며, http(80 port), https(443 port)에 대한 방화벽 정책이 오픈되어 있어야 합니다.
sudo systemctl stop nginx
standalone 방식은 웹 서버를 임시로 빌리기 때문에 현재 구동되고 있는 웹 서비스는 잠시 중지합니다.
(위 코드는 nginx를 중지하는 예시이며, apache의 경우 sudo systemctl stop httpd를 사용합니다.)
sudo certbot certonly —standalone -d
이어서 해당 명령어를 통해 인증서를 발급받을 수 있는데요.
인증서 발급 후 443 포트(https)를 열어주는 과정이 필요한데, nginx 기준으로 위의 webroot 과정에서 443 포트를 열어주기 위해 했던 설정을 똑같이 해주면 됩니다.
4. DNS 방식
DNS 방식은 도메인을 쿼리해 확인되는 TXT 레코드를 통해 사이트의 유효성을 확인하는 방식입니다.
서버 관리자가 DNS를 관리 및 수정할 수 있어야 하며, 와일드카드 방식으로 인증서를 발급할 수 있다는 특징이 있습니다.
certbot certonly --manual -d abcde.com --preferred-challenges dns-01 --server https://acme-v02.api.letsencrypt.org/directory
(abcde.com은 예시입니다.)
해당 명령어에서 사용된 각 옵션을 살펴보면, --manual 옵션의 경우 수동으로 과정을 실행한다는 옵션이며, --preferred-challenges는 dns를 이용한 인증서 발급 방식을 사용하겠다는 옵션입니다.
dns-01의 경우 dns를 통한 preferred-challenges를 사용할 때 함께 적용되어야 하는 옵션이며 --server의 경우 Let's Encrypt의 ACME(자동화된 인증서 관리 환경) 서버 주소를 입력하는 부분입니다.
위 명령어를 수행하면 dns 서버에 _acme-challenge.abcde.com 이름의 TXT 레코드를 추가하라는 요청이 나오는데요.
아래와 같이 호스트 부분에 '_acme-challenge'를 넣고, 값 부분에 'ullmn-7...'에 대한 값을 넣어주면 됩니다.
< 참고 자료 >
https://happist.com/573990/최신-lets-encrypt-ssl-인증서-발급-방법-3가지-정리#4_DNS_iyonghae_balgeub_badgi
< nginx 관련 자료 >
2023.02.19 - [Programming/Web] - Nginx 이미지 서버 구축 방법(sites-available, sites-enabled)
'Programming > Web' 카테고리의 다른 글
스트랭글러 패턴(Strangler Pattern) 개념 정리 (0) | 2023.05.31 |
---|---|
CDN(Content Delivery Network)이란? 콘텐츠 전송 네트워크 개념 정리 (0) | 2023.05.28 |
OAuth, OAuth2 개념과 동작 방식 정리 (0) | 2023.03.22 |
(spring boot) RedisRepository 사용하는 방법, @RedisHash (0) | 2023.03.07 |
REST API Response Format, 응답 객체는 어떤 형식이 좋을까? (0) | 2023.02.25 |