문제상황
일반적인 http요청은 데이터가 암호화되지 않아 보안상으로 위험하다.
일반적인 브라우저들은 https를 권장하여 http요청으로 보낼 경우 위험표시가 뜨게 되어 미관상으로도 안좋은 인식이 생긴다
해결방법
docker환경에서 certbot이라는 컨테이너를 이용하여 무료로 ssl인증서를 발급하는 Lets Encrypt로 ssl을 발급받는다.
이미 구축된 이미지인 certbot은 사실 ssl인증서를 갱신하는 역할이기 때문에 초기에 ssl을 쓰기위해 미리 발급받는다.
적용과정
1.nginx>defualt.conf설정
upstream imageus_back {
server imageus_back:4000;
}
upstream imageus_image {
server imageus_image:4001;
}
server {
#기본적으로 브라우저에서 요청하는 포트를 받는다.
listen 80;
server_name codakcodak.site;
server_tokens off;
#ssl을 발급 및 갱신 하기위한 url
location /.well-known/acme-challenge/ {
allow all;
root /var/www/certbot;
}
#위의 url을 제외한 모든 url을 443포트를 사용하는 https로 redirect한다.
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name codakcodak.site;
server_tokens off;
#ssl로 발급받은 공개키와 비밀키 명시
ssl_certificate /etc/letsencrypt/live/codakcodak.site/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/codakcodak.site/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
#프론트 라우팅
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
}
#스웨거 라우팅
location /swaggerui {
proxy_pass http://imageus_back;
proxy_set_header X-Real-IP $remote_addr;
proxy_connect_timeout 5;
proxy_send_timeout 5;
proxy_read_timeout 5;
send_timeout 5;
}
#백서버 라우팅
location /backapi {
proxy_pass http://imageus_back;
proxy_set_header X-Real-IP $remote_addr;
proxy_connect_timeout 5;
proxy_send_timeout 5;
proxy_read_timeout 5;
send_timeout 5;
}
#이미지서버 라우팅
location /imageapi {
proxy_pass http://imageus_image;
proxy_set_header X-Real-IP $remote_addr;
proxy_connect_timeout 10;
proxy_send_timeout 10;
proxy_read_timeout 10;
send_timeout 5;
}
}
2.docker-compose.yml설정
certbot:
container_name: certbot
image: certbot/certbot
restart: unless-stopped
volumes:
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:7.10.2
container_name: elasticsearch
environment:
- cluster.name=es-docker
- node.name=node1
- bootstrap.memory_lock=true
- discovery.type=single-node
- "ES_JAVA_OPTS=-Xms2g -Xmx2g"
ports:
- 9200:9200
restart: always
platform: linux/amd64
healthcheck:
test: curl -u elastic:elastic -s -f elasticsearch:9200/_cat/health >/dev/null || exit 1
interval: 20s
timeout: 5s
retries: 100
*certbot을 통해 인증서를 발급 및 갱신하므로 nginx의 폴더와 공유를 해야 niginx가 발급받은 ssl을 쓸 수 있다.
3.첫 ssl 발급
https://github.com/wmnnd/nginx-certbot/blob/master/init-letsencrypt.sh
4.docker-compose 가동
어려웠던 개념
nginx의 /well-known/acme-challenge/ 라우팅 용도
ssl발급을 위해서는 ca(ssl을 발급하는 회사)에게 서버가 보내는 ip와 도메인이 일치하는지 확인해야 그 서버가 신뢰할 수 있다.
초기 ssl을 발급하는 init-letsencrypt.sh와 certbot의 내부적으로 보면
nginx에서 root경로 였던 /var/www/certbot에 서버에서 생성한 토큰을 /well-known/acme-challenge/토큰이름(파일)으로 저장한다.
그리고 삽입해놨던 이메일과 도메인주소와 위의 토큰이름을 ca회사에게 보내면 ca회사는 전달받은 도메인으로 토큰이름이 있는 도메인/var/www/certbo/well-known/acme-challenge/토큰이름(파일)
요청을 보내어 파일이 실제로 존재하는지 확인한다.
이때 확인이 되었다면 결국 서버는 자신의 도메인 안에서 자원을 만든것을 직접 ca회사에게 확인시켜준 것이므로 이로서 서버는 신뢰할 수 있다고 판단하고 ssl인증서를 발급한다.
https의 실제 통신 방식
* 클라이언트와 서버가 실제로 데이터가 오가기 전에 서버에서 먼저 ssl인증서를 준다.
결과
브라우저에서 경고메세지가 보이지 않아 서비스가 쾌적해보인다.
클라이언트와의 암호화된 데이터들을 안전하게 주고받아 보안적으로 강화되었다.