안녕하세요, codedbyjst입니다.
이번엔 HTTPS 배포를 위한 첫 단계로써, API 서버에 HTTPS를 적용하는 방법을 알려드리도록 하겠습니다.
SSL 인증서는 어디에 있는가?
우선 시작하기에 앞서, SSL 인증서가 어디에 존재하면 되는지 생각해보겠습니다.
예를 들어, 저희가 ohmycarset.com 이라는 도메인을 구매했다고 생각해보겠습니다.(정확히는, '빌린' 것이지만, 그냥 구매했다고 하겠습니다.)
도메인을 구매할 수 있는 곳은 다양하기에, 꼭 AWS Route 53이 아니더라도 가비아, 클라우드플레어 등의 업체에서 구매하셨을 것입니다.
이 때, SSL 인증서는 어디에 있으면 될까요? 해당 구매한 업체의 설정창에서 등록하면 되는 걸까요? 일종의 A, CNAME 등의 레코드처럼 그냥 등록하면 되는 걸까요?
SSL 인증서는 '원본 서버'에 있다.
이는 SSL 인증서의 동작 방식을 잘못 이해하여 발생하는 문제입니다.
SSL 인증서를 통한 패킷 암호화/복호화의 책임은 '원본 서버'에 있습니다. 도메인을 구매한 업체(도메인 네임 등록체, 네임 서버 운영체)는 SSL과 관련해서 해 줄 것이 기본적으로는 없습니다.
네임 서버의 역할은 해당 서버에 대한 기본적인 공개 정보 제공이지, 모든 패킷의 암호화/복호화 처리가 아니기 때문입니다.(정말 그랬다면, 업체는 엄청난 비용을 부담해야 할 겁니다.)
또한, 그런 기능을 제공해준다고 하더라도, 네임 서버와 원본 서버 사이의 패킷은 암호화되지 않으므로 보안적으로도 위험합니다.
SSL 인증서를 발급해주는 업체는 별도로 존재합니다.
이를 저희는 CA, 'Certificate Authority'라고 부릅니다. 대표적인 업체로는 IdenTrust, Digicert, GlobalSign, Let's Encrypt 등이 있습니다. Let's Encrypt는 많이 들어보셨을 수도 있겠네요.
또한, 해당 업체에서 직접 발급해주기도 하지만, 일반적으로는 SSL 인증서 발급 대행 업체를 이용하게 됩니다.
가격은 상황에 따라, 플랜에 따라, 발급체에 따라 천차만별로 다르지만 보통 저렴한 것이 1년에 15~25만원 수준입니다.
이게 저렴한지는 여러분들의 판단에 맡기겠습니다만, 저한테는 조금 부담되는 금액이네요.
특히, 도메인을 여러 개 소유하면 각각에 대해 모두 발급받아야 하여 쉽지 않은 금액입니다.
더 저렴한 옵션은?
여러분이 저와 같은 감정을 느끼셨다면, 아마 이런 생각을 하게 되셨을 겁니다.
'누가 공짜로 안 주나...?'
다행히도, 세상에는 돈이 정말 많은 업체들이 존재합니다. 대표적으로, 아래의 그림 속의 업체들이 그러한 서비스를 제공해줍니다.
하지만 세상에 공짜는 없겠죠. 이들 업체들은 모두 각각의 장단점을 갖고 있습니다.
업체명 | 특징(무료버전) |
SSL For Free, Zero SSL | 1.90일간 유효 2. 최대 2개의 도메인(원본, www)에 대해 무료 |
AWS Certificate Manager | 1. 1년간 유효, 자동 연장 가능 2. 와일드카드 지원 3. 공인 인증서 private key를 다운로드 할 수 없음. 반드시 AWS 내의 서비스(ALB, Cloudfront등)와 연동하여 이용해야함. |
Let's Encrypt | 1. 90일간 유효 2. 와일드카드 지원 3. Certbot을 통한 자동 인증서 연장 지원 (단, 발급 및 연장 설정 CLI 작업 필요) |
아무래도 EC2 등의 서비스를 이용하고 있다 보니 AWS Certificate Manager가 눈에 들어오실 텐데요, ACM의 경우 공인 인증서 발급은 매우 자유롭게 해주지만 private key를 다운로드 할 수 없다는 치명적인 단점이 있습니다. 따라서 원본 서버 레벨에서 SSL 처리를 해줄 수 없습니다.
이는 Application Load Balancer등의 서비스를 별도로 이용해야 한다는 의미인데, 이는 당연히 추가적인 비용 부담으로 이어지게 됩니다. 특히 ALB의 요금 체계에는 요청 처리 건수당 요금이 붙어있어, 요청 처리 건수가 많은 API 서버의 경우 치명적일 수 있습니다.
따라서 개인적으로 Certbot을 통한 인증을 추천하는 편입니다. 비록 90일간 유효하지만, certbot을 활용하면 자동 갱신이 가능하고, 무엇보다 무료이니까요!
1. Certbot 인증서 생성(Webroot 방식 이용)
이제 본격적으로 인증서를 생성해 보겠습니다.
인증서를 만들기 위해선 본인이 도메인의 소유주라는 것을 증명해야 하는데, Certbot은 이를 위한 여러가지 방법을 제공합니다.
현재 서버를 이용해서 프론트엔드 분들이 작업을 진행중이시기에, 본 글에서는 서버를 중단시키지 않고 진행할 수 있는 Webroot 방식을 이용하도록 하겠습니다.
또, 진행되는 모든 과정은 'api.ohmycarset.com'이라는 도메인의 인증서를 받는 것에 한정합니다.
Webroot 방식은 서버에 특정한 파일을 만들어두고, 도메인을 통해 서버에 접근해 해당 파일을 확인할 수 있는지 검증하는 방식입니다.
따라서 파일이 위치할 경로를 미리 만들어두어야 합니다.
아래 명령어로 미리 디렉터리를 생성합니다.
$sudo mkdir -p /var/www/letsencrypt/.well-known/acme-challenge
그 후, nginx가 해당 파일을 접근할 수 있도록 설정해줘야 합니다.
기존에 이미 작성해놓은 설정 파일이 있다면, 해당 파일을 열어줍니다.
$sudo vi /etc/nginx/sites-enabled/api.ohmycarset.com
해당 파일에 아래와 같이 내용을 추가해줍니다.
(아래의 3줄이 추가된 부분입니다.)
server { # server 블록
listen 80;
server_name api.ohmycarset.com;
access_log /var/log/nginx/proxy/access.log;
error_log /var/log/nginx/proxy/error.log;
location / { # location 블록
include /etc/nginx/proxy_params;
proxy_pass http://localhost:8080; # reverse proxy의 기능
}
# 인증서 발급을 위한 추가 설정
location ^~ /.well-known/acme-challenge {
allow all;
root /var/www/letsencrypt;
}
}
그 후 적용을 위해 nginx 서버를 재시작해줍니다.
(물론, 그 전에 $sudo nginx -t 로 올바르게 설정되었는지 확인하고 진행하세요.)
$sudo systemctl restart nginx
이제, certbot을 설치하여 과정을 진행합니다.
certbot의 경우 letsencrypt 패키지를 설치하면 포함되어 있으므로, 아래의 명령어로 설치합니다.
$sudo apt update
$sudo apt install letsencrypt
설치가 완료되면, 아래의 명령어를 통해 SSL 인증서를 발급받습니다.
참고로, -d 뒤에 본인이 인증받고 싶은 도메인을 쓰면 되는데, 여러 개를 원하신다면 '-d 도메인1 -d 도메인2' 이런 식으로 하시면 됩니다.
포맷 :
$sudo certbot certonly --webroot --webroot-path=/var/www/letsencrypt -d [인증받고 싶은 도메인]
실제 예시 :
$sudo certbot certonly --webroot --webroot-path=/var/www/letsencrypt -d api.ohmycarset.com
큰 문제가 없다면 위처럼 인증서를 받아 저장해줄 겁니다.
위 경로들이 필요하니, 메모해두세요.(본 글의 경우, 경로는 아래와 같습니다.)
인증서 경로 : /etc/letsencrypt/live/api.ohmycarset.com/fullchain.pem
암호 경로 : /etc/letsencrypt/live/api.ohmycarset.com/privkey.pem
2. 서버 NGINX 설정
이제 발급받은 인증서를 이용해서 nginx에 인증서를 등록하면 됩니다.
위에서 /etc/nginx/sites-enabled/api.ohmycarset.com을 수정해주었는데요, 이제 해당 파일을 아래와 같이 수정해줍니다.
server { # server 블록
listen 80;
server_name api.ohmycarset.com;
access_log /var/log/nginx/proxy/access.log;
error_log /var/log/nginx/proxy/error.log;
location / { # location 블록
include /etc/nginx/proxy_params;
proxy_pass http://localhost:8080; # reverse proxy의 기능
}
# 인증서 발급을 위한 추가 설정
location ^~ /.well-known/acme-challenge {
allow all;
root /var/www/letsencrypt;
}
}
### 이 아래가 추가된 부분입니다.
# HTTPS
server {
listen 443 ssl;
server_name api.ohmycarset.com;
ssl_certificate /etc/letsencrypt/live/api.ohmycarset.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.ohmycarset.com/privkey.pem;
location / {
proxy_pass http://localhost:8080;
}
}
수정 후, 문법에 문제가 없었는지 아래 명령어로 확인합니다.
문제가 없다면 위와 같이 나올 것입니다.
이제, 새로운 설정을 적용하기 위해 nginx 서비스를 재시작합니다.
$sudo systemctl restart nginx
제대로 적용되었는지 확인을 위해 https로 접근해보겠습니다.
(물론, EC2를 사용중이시라면 보안 그룹에서 https용 포트를 열어주셔야 합니다.)
정상적으로 적용된 것을 확인할 수 있습니다.
또, 추가적으로 http로 온 요청을 모두 https로 바꾼다던가 하는 것도 가능하니 찾아보시면 될 것 같습니다.
개발이 도움이 되셨으면 좋겠습니다. 긴 글 읽어주셔서 감사합니다.
'개발팁' 카테고리의 다른 글
Nginx와 Docker Compose로 무중단 배포하기 (0) | 2023.08.20 |
---|---|
스프링 부트 CORS 설정법 정리 (0) | 2023.08.12 |
Spring Boot + Redis Cache 사용법 정리 (0) | 2023.08.11 |
[Fastapi]파라미터 올바르게 다루기 (0) | 2023.03.03 |
[Fastapi]sqlalchemy말고, pymysql로 데이터베이스(Mysql)와 통신하기 (4) | 2023.02.23 |