여기에서는 Let’s Encrypt SSL 인증서 발급 및 자동 갱신 방법에 대해서 살펴 보도록 하겟습니다. 이 글 작성 후 변경 사항 등이 있어 최신 방법으로 업데이트 하였습니다.(2020년 12월 25일)
앞선 포스팅에서 무료 SSL 인증서를 비교해 보았고 그 중 향후 가능성이나 사용편리성을 고려시 Let’s Encrypt가 가장 낫겠다고 판단했고 이를 적용하겠다고 했습니다.
이번 포스팅에서는 Let’s Encrypt를 통해서 무료 SSL인증서 발급받고 자동으로 연장하는 방안에 대해서 살펴보도록 하겟습니다.
1. Let’s Encrypt 간략 소개
앞 포스팅에서 소개한 내용을 그개로 여기에서도 인용해 봅니다.
Let’s Encrypt은 HTTPS의 확산이 늦어지는 것은 SSL인증서에 있다고 보고 무료 인증서 보급을 통해 HTTPS의 확산을 늘리겠다는 취지로 시작된 비영리 프로젝트입니다.
Mozilla, Akamai, Cisco, eff, Identrust, 지말토(Gemalto)와 HP 엔터프라이즈, 패스틀리(Fastly), 두다(Duda)등이 스폰서로 참여해서 HTTPS Everywhere를 모토로 100% 무료 SSL 인증서를 발급 해주고 있습니다.
2016년 4월 정식 버젼을 출시했으며 2020년 12월 기준 2.34억개의 웹서버 인증이 진행되었습니다. (Let’s Encrypt 홈페이지 통계 기준), 참고로
- 인증서 발급 기관, CA(Certificate Authority) 중 점유율이 가장 높은 곳은 IdenTrust로 2020년 12월 기준으로 42%가 넘습니다.(42.3%)
- IdenTrust 다음으로는 DigiCert Group(15.7%) > Sectigo(14.1%) > GoDaddy Group(5.4%) > GlobalSign(2.3%
- Let’s Encrypt 점유율은 생각보다 낮아서 0.1%에 불과
- 하지만 Let’s Encrypt 사용을 아래 그래프에서 보듯 매우 빠르게 증가
(개인적인 생각으로는 무료이기 때문에 테스트로 중복 인증도 많다고 생각)
Let’s Encrypt의 정책은 독특합니다. 앞에서 HTTPS의 확산을 위한 비영리단체로 소개했듯이 Let’s Encrypt은 서버운영자들이 인증 관리를 철저히 하지 못한다는 점을 염려(?)해 인증서 설치부터 재발행(갱신)까지 다 책임진다는 자세로 인증관련 업무를 진행하고 있습니다.
인증기간이 90일로 상대적으로 짧은 것은 보안 상황이 계속 변동되므로 이를 반영해 갱신할 수 있도록 짧게 잡았으며 대신 자동으로 인증서가 연장(재발행)되는 기능을 사용하도록 권장하고 있습니다.
자동으로 연장(재발행)된다면 오히려 안심하고 사용할 수 있는 것이 아닌가 싶습니다.
- HTTPS Everywhere 를 추구하는 비영리 프로젝트
- 스폰서 : Mozilla, Akamai, Cisco, eff, Identrust
- IdenTrust cross-sign됨
- SSL 인증서 100% 무료화
- 인증기간 연장 및인증서 재발급 무료
- 사용편리성 : 콘솔상에서 인증서 발급/갱신/설치/세팅 자동화.
- 멀티도메인 지원, SAN 기능(여러 도메인을 한 인증서로 묶어주는 기능) 지원
2. Let’s Encrypt SSL 인증서 발급 방법 4가지
Let’s Encrypt SSL 인증서 발급 방법은 webroot와 Standalone, DNS의 3가지 방식이 있습니다. 인증서 발급은 사이트에서 인증기관인 Let’s Encrypt에 접속해 이 사이트의 유효성을 검증하는 과정을 거치며 이 과정을 아래 3가지 방법 중 하나를 선택해 진행할 수 있습니다.
- webroot : 사이트 디렉토리 내에 인증서 유효성을 확인할 수 있는 파일을 업로드하여 인증서를 발급하는 방법
. 실제 작동하고 있는 웹서버의 특정 데렉토리의 특정 파일 쓰기 작업을 통해서 인증
. 이 방식의 장점은 nginx를 중단시킬 필요가 없음.
. 이 방법의 단점은 인증 명령에 하나의 도메인 인증서만 발급 가능 - 웹서버
. Nginx나 아파치와 같은 웹서버에서 직접 SSL 인증을 실시하고 웹서버에 맞는 SSL세팅값을 부여
. 발급이나 갱신을 위해 웹서버를 중단시킬 필요가 없음
. 인증서 갱신 시 상황에 맞게 세팅을 자동으로 업데이트
. 사용자가 세팅을 변경할 수 있지만 자동 업데이트 시 반영되지는 않음 - Standalone : 사이트 작동을 멈추고 이 사이트의 네크워킹을 이용해 사이트 유효성을 확인해 Let’s Encrypt SSL 인증서를 발급하는 방식
. 80포트로 가상 staandalone 웹서버를 띄워 인증서를 발급
. 이 방식은 동시에 여러 도메인을 발급 받을 수 있음
. 그렇지만 인증서 발급 전에 Nginx를 중단하고 발급 완료 후 다시 Nginx를 시작해야 함 - DNS : 도메인을 쿼리해 확인되는 TXT 레코드로 사이트 유효성을 확인하는 방법
. 와일드 카드 방식으로 인증서를 발급 가능
. 이 방법은 당연하게도 서버 관리자가 도메인 DNS를 관리/수정할 수 있어야 하며
. 인증서 갱신 시마다 DNS에서 TXT값을 변경해야 하므로
외부에서 TXT 레코드를 입력할 수 있도록 DNS가 API를 제공하는 경우만 갱신 과정을 자동으로 처리(클라우두플레어 API가 대표적인 사례)
여기에서는 가장 안정적인 방식인 standalone 방식으로 SSL 인증서를 발급하는 방법에 대해서 알아보도록 하겠습니다. 보다 자세한 내용을 아래 글을 참조하시면 좋을 것 같습니다.
3. Let’s Encrypt에서 인증서 생성하기
현재 제 시스템 상황입니다.
- Ubuntu 20.04
- Nginx 1.19.64
- PHP 8.0
Let’s Encrypt에서 제공하는 소프트웨어 클라이언트인 letsencrypt를 사용하면 쉽고 편하게 적용할 수 있습니다.
아파치서버에서는 완전 자동으로 SSL인증을 획득하고 적용할 수 있는 Nginx 서버에서는 이러한 자동화가 조금 늦게 적용되는 것 같습니다. Nginx에서의 자동화 방법은 없는것은 아니므로 이는 뒷부분에서 살펴보도록 하겠습니다.
아무튼 Nginx에서 Let’s Encrypt 인증서 생성에는 몇가지 조건이 있습니다.
- root 접근 권한을 가지고 있어야 (즉 서버를 운영하고 있어야하므로 일반 웹호스팅은 안된다는 의미)
- Let’s Encrypt가 아직은 공식적으로 Nginx를 지원하지 않은 상태이므로 아파치보다는 상대적으로 매뉴얼 작업이 필요합니다.
2.1. SSL 인증을 위한 Certbot tool 설치
Let’s Encrypt SSL 인증서 발급은 Certbot을 이용합니다.
Certbot은 우분투 20.04를 설치 후 letsencrypt을 설치했다면 그 안에 포함되어 있기 때문에 별도 Certbot을 설치할 필요가 없습니다.
sudo apt update
sudo apt-get install letsencrypt -y
Code language: PHP (php)
2.2. certbot으로 인증서를 생성
이렇게 Certbot tool이 설치되었다면 SSL 인증을 시작해 보도록 하겠습니다.
우선 웹서버를 중단시킵니다. 이는 80포트를 사용하지 않토록 만들기 위한 것입니다.
아무 디렉토리에서나 가능한 명령이지만 root로 이동해서 진행해 봅니다.
cd /root/
service nginx stop
Code language: PHP (php)
이제 certbot 명령을 이용해 SSL 인증을 시작합니다. standalone 명령을 사용하고 도메인 이름만으로 인증이 진행되는 -d 옵션을 적용합니다.
certbot certonly --standalone -d 사이트명.com -d www.사이트명.com
Code language: PHP (php)
그러면 아래와 질문들이 나오면서 인증이 진행됩니다. 첫번째로은 이메일 주소를 입력하라고 나옵니다. 이메일을 입력해야 다음 단계로 넘어갈 수 있으니 연락을 받을 수 있는 이메일을 입력합니다.
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator standalone, Installer None
Enter email address (used for urgent renewal and security notices) (Enter 'c' to cancel)
:
Code language: PHP (php)
그 다음 단계는 서비스 약관에 동의하느냐고 묻습니다. 모든 서비스가 그러하듯이 Y를 누르지 않으면 서비스를 이용할 수 없기 때문에 A를 누릅니다.
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf. You must agree in order to register with the ACME server at https://acme-v02.api.letsencrypt.org/directory
(A)gree/(C)ancel: A
Code language: PHP (php)
마지막 질문은 재단에 이메일 주소를 공유할 것인지를 질문 합니다 간혹 귀찮게 하는 경우도 있어 N를 선택하라는 조언도 많은데 저는 이 비영리기관에 도움이 될 수 있다면 이라는 긍정적인 생각으로 Y를 눌렀습니다.
Would you be willing to share your email address with the Electronic Frontier Foundation, a founding partner of the Let's Encrypt project and the non-profit organization that develops Certbot? We'd like to send you email about our work encrypting the web, EFF news, campaigns, and ways to support digital freedom.
(Y)es/(N)o: Y
Code language: PHP (php)
그러면 다음과 같이 진행되고 인증을 축하다는 메세지가 나옵니다.
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for example.com
http-01 challenge for www.example.com
Waiting for verification…
Cleaning up challenges
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/example.com/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/example.com/privkey.pem
Your cert will expire on 2021-03-25. To obtain a new or tweaked version of this certificate in the future, simply run certbot again. To non-interactively renew <em>all</em> of your certificates, run "certbot renew"
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
Code language: PHP (php)
인증이 완료되면 웹서버를 다시 가동시킵니다.
service nginx restart
Code language: PHP (php)
2.3. 여러개 도메인을 한번에 인증받기
이 standalone 옵션은 또한 한꺼번에 여러 개의 사이트를 인증 받을 수 있는데요. 아래와 같은 명령을 사용할 수 있습니다. 이는 연속해서 사이트명을 나열해주면 가능합니다.
service nginx stop
certbot certonly --standalone -d 사이트명.com -d www.사이트명.com -d 사이트명2.com -d www.사이트명2.com -d 사이트명3.com -d www.사이트명3.com
service nginx restart
Code language: PHP (php)
단 이렇게 여러개 사이트를 인증 받을 시 인증서 존재 위치가 맨앞 사이트명으로 통일되게 됩니다. 나중에 사이트를 없앨 때 난감할 수도 있습니다.
2.4. DH Param 생성, 적용하기
여기가지 진행하면 SSL 인증서 설치는 끝나지만 보다 보안을 강화하기 위해서 DH Param 생성을 합니다.
DH Param은 일부 암호화 알고리듬에 사용되는 커다란 난수 하나를 미리 생성해 두어서 암호화 성능을 향상시키고 보안을 높이는 방법입니다.
실제로 DH Param을 비적용시와 적용 시 보안 점수를 측정해보니 한등급 차이가 날 정도로 Gap이 컷습니다. DH Param를 적용시는 A+ 보안등급이 나오고 DH Param를 비적용시는 A-가 나오네요.
mkdir /etc/nginx/ssl
cd /etc/nginx/ssl
openssl dhparam -out dhparams.pem 4096 # 2048비트로 하려면 4096대신 2048로 대체 한다.
openssl rand 48
session_ticket.key # 세션 티켓키도 생성 이는 시간이 거의 걸리지 않는다.
Code language: PHP (php)
3. 암호화 알고리즘 설정하기
XE 분야에서 탁월한 식견을 자랑하는 가지곰님이 Xpress Engine 공홈에 올린 SSL의 정석 (아파치 & nginx)
라는 글에 의하면 실제로 보안을 제공하는 것은 인증서가 아니라 암호화 알고리즘이라고 이야기 하고 있습니다.
인증서를 획득하는게 중요한게 아니고 얼마나 철저한 암호화 설정을 하느냐가 중요하다는 것입니다.
이 중에서 중요한 것은 ssl_ciphers인데요. 이에 대해서는 모질라 재단에서 제공하는 SSL Configuration Generator를 사용하면 좋을 것 같습니다.
여기에서는 nginx 1.17.7을 기준으로 보안 설정을 추천하고 있습니다. 여기서는 NGINX 기준으로 모던 브라우저와 올드 브라오져 중간에 있는 Intermediate를 선택해 설정한 내용을 여기에 옮겨 봅니다.
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
<code>ssl_certificate /path/to/signed_cert_plus_intermediates; </code>
<code>ssl_certificate_key /path/to/private_key; </code>
<code>ssl_session_timeout 1d; </code>
<code>ssl_session_cache shared:MozSSL:10m; # about 40000 sessions </code>
<code>ssl_session_tickets off; </code>
<code># curl https://ssl-config.mozilla.org/ffdhe2048.txt > /path/to/dhparam </code>
<code>ssl_dhparam /path/to/dhparam; </code>
<code># intermediate configuration </code>
<code>ssl_protocols TLSv1.2 TLSv1.3; </code>
<code>ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; </code>
<code>ssl_prefer_server_ciphers off; </code>
<code># HSTS (ngx_http_headers_module is required) (63072000 seconds) </code>
<code>add_header Strict-Transport-Security "max-age=63072000" always; </code>
<code># OCSP stapling ssl_stapling on; </code>
<code>ssl_stapling_verify on; </code>
<code># verify chain of trust of OCSP response using Root CA and Intermediate certs</code>
<code>ssl_trusted_certificate /path/to/root_CA_cert_plus_intermediates; </code>
<code># replace with the IP address of your resolver </code>
<code>resolver 127.0.0.1;</code>
}
Code language: PHP (php)
nginx 서비스 재시작
세팅이 완료되었으면 ginx 서비스를 재시작 명령을 주어 설정이 반영되도록 합니다.
nginx -t # 혹 설정에 문제가 없는지 점검
service nginx restart # nginx 서비스를 재시작해 설정을 반영시킴
Code language: PHP (php)
보안 점수 확인
그리고 Qualys SSL Labs으로 이동해서 보안점수가 어는정도 나오는지 테스트해봅니다.
제대로 세팅만하면 A+은 그냥 나옵니다.
4. Let’s Encrypt 인증서 자동 갱신
Let’s Encrypt 무료 SSL 인증서는 3개월단위로 인증서가 발급됩니다. 3개월마다 수동으로 이를 업데이트 시키려면 엄청 신경을 써야하고 바쁘다보면 그냥 지나칠 경우가 많겠지요.
다행히도 Let’s Encrypt에서는 인증서 자동 갱신 방법을 제공하고 있습니다.
우선 자동 실행 스크립트 파일을 만듭니다. 크론 실행이 가장 안정적으로 작동하는 경우는 /bin 폴더에 자동 실행 파일이 있는 경우라서 이 폴더에 자동 실행 스크립트 파일을 만듭니다.
cd /bin
nano letsencrypt.sh
Code language: PHP (php)
여기에 아래와 같은 내용을 추가합니다.
!/bin/sh
/etc/init.d/nginx stop
/usr/local/bin/certbot renew> /var/log/letsencrypt/le-renew.log
fuser -k 80/tcp
/etc/init.d/nginx start
Code language: PHP (php)
이 자동 스크립트 파일에 권한을 부여합니다.
chmod +x letsencrypt.sh
Code language: PHP (php)
이어 크론탭을 열어 편집 상태로 만듭니다.
ceontab e
Code language: PHP (php)
아래처럼 일정 시간마다 이를 시행하라고 명령을 줍니다.
30 4 * * 0 letsencrypt.sh
Code language: PHP (php)
저장하고 나와서는 크론을 다시 실행 시킵니다.
service cron start
Code language: PHP (php)
자동 갱신 모의 테스트
Let’s Encrypt 인증서는 자동 갱신이 제대로 작동하는지 모의 테스트 할 수 있는 기능을 제공하는데요. 바로 –dry-run 옵션을 사용할 수 있습니다.
sudo certbot renew --dry-run
Code language: PHP (php)
그러면 다음과 같은 메세지를 출력합니다.
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Processing /etc/letsencrypt/renewal/example.com.conf
Cert not due for renewal, but simulating renewal for dry run
Plugins selected: Authenticator standalone, Installer None
Renewing an existing certificate
Performing the following challenges:
http-01 challenge for example.com
http-01 challenge for www.example.com
Waiting for verification…
Cleaning up challenges
new certificate deployed without reload, fullchain is
/etc/letsencrypt/live/example.com/fullchain.pem
** DRY RUN: simulating 'certbot renew' close to cert expiry
** (The test certificates below have not been saved.)
Congratulations, all renewals succeeded. The following certs have been renewed:
/etc/letsencrypt/live/example.com/fullchain.pem (success)
** DRY RUN: simulating 'certbot renew' close to cert expiry
** (The test certificates above have not been saved.)
IMPORTANT NOTES:
Your account credentials have been saved in your Certbot
configuration directory at /etc/letsencrypt. You should make a
secure backup of this folder now. This configuration directory will
also contain certificates and private keys obtained by Certbot so
making regular backups of this folder is ideal.
Code language: PHP (php)
5. SSL 사용을 위한 워드프레스 설정하기
워드프레스에서는 별로 할것은 없습니다.
워드프레스 어드민의 설정 – 일반으로 가서 워드프레스 주소와 사이트주소에 S를 붙여줍니다.
SSL 설정 후 속도 개선하기
SSL을 설정하고 인터넷을 실행하면 속도가 떨어졌다고 느낄 수 있습니다.
이를 해결하는 방법은 OCSP Stapling을 적용하는 방법이라고 합니다.
ssl_dhparam /폴더/경로/아까.생성한.dhparam;
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /폴더/경로/2~3번.인증서.붙인거.파일명;
resolver 8.8.8.8 8.8.4.4;
Code language: PHP (php)
resolver는 내부적으로 인증서 발급업체와의 통신을 위해 사용하는 네임서버라고 하구요. 일반 서버호스팅은 IDC에서 제공하는 네임서버 성능이 좋지 않아서 구글에서 제공하는 네임서버로 셋팅한다고 합니다.
6. 마치며
이상으로 간단히 SSL 적용 방법을 적어 보았습니다.
이 분야에의 문외한이 겁없이 시작해서 많은 시행착오 끝에 SSL를 적용했습니다. 참 어려운 여정이었습니다.
이제 적용하고 보니 이게 최선인가하는 회의가 듭니다. 왜냐면 SSL 적용후 속도가 만족스럽지 못하기 때문이죠.
다들 속도때문에 SSL은 로그인이나 회원 가입등 일부 부분에서만 사용한다고 하네요. 네이버도 일부분만 적용한다고.
우선 가상호스팅을 사용하고 있으므로 보안 차원이라도 SSL을 적용하는게 좋을 것 같고, 속도 문제는 차후 어떻게 개선할지 고민해 봐야겠습니다.
SSL 인증서 관련 참고
최신 Let’s Encrypt SSL 인증서 발급 방법 4가지 정리
Let’s Encrypt SSL 인증서 발급 및 자동 갱신 방법(업데이트)
최신 보안 트렌드를 반영한 Let’s Encrypt 인증서 세팅 방법
웹, 브라우저, 서버에서 SSL 인증서 정보 확인 방법, SSL 인증서 만료일 확인 등
서버 보안 관련
랜섬웨어 대응, 서버 및 워드프레스 필수 보안 설정 15가지
리눅스 서버 root 사용 중지로 리눅스 서버 보안 강화하기
우분투 서버 보안 자동 업데이트 및 업데이트 메일 통보 방법
워드프레스 보안 진단 WPScan 사용법 및 이메일로 결과 받아보기
DDoS 취약 기능 XMLRPC 사용 중지로 워드프레스 보안 강화하기