이번 사이드 프로젝트를 하면서 Https 적용을 위해 CA(인증기관)에서 인증서를 받아 적용하려고 한다.
우선 전체적으로 지옥그 잡체였다. 뭔 받았는데 pem키가 dir파일로 받아지지 않나, 받다가 5번 이상 받아서 일주일 제한걸리지 않나... 이전 우테코에서 동료 크루가 정리한 블로그를 많이 참고했다 (thank's to 슬키)
Http와 Https의 차이는 무엇인가... 이전 웹 공부를 시작하기 전에는 http가 뭔지도 모르다가 이제는 뭔 s하나 안붙은걸로 뭐 인증되지 않은 사이트라니 붙이면 뭐가 달라지는지 겁나 복잡한거 같았다.
Https는 Http에 secure이라는 단어 하나가 붙은거다. 걍 보안적으로 더 안전하다는 의미이다. 보내는 정보들을 쌩으로 보내면 (http) 누구나 가로체기만 하면 까봐서 뭔지 알 수 있을 것이다. 이를 방지하기 위해서 보내는 정보를 암호화하는 것이다. 하지만 이 암호화 방식이 누구나 알고 있으면 암호화 해봤자 다 알 것이다. 그렇다면 https는 어떤식으로 암호화를 하고 복호화를 하는 것일까?
클라이언트, 서버측에서 대칭키를 만들어서 이를 복호화 암호화해서 주고 받는 것이다. 그렇담 그 대칭키를 만들기 위해서 서로 무언가를 주고 받아야할 텐데 그걸 어케할까? 이 부분은 찾아보면 정보가 굉장히 많으니 짧게 요약하겠다.
클라이언트 측에서 Https로 서버에 요청을 한다. 이때 클라이언트가 만든 난수를 함께 보낸다.
서버측은 클라측에서 받은 난수와 서버측에서 만든 난수와 비밀키를 통해 대칭키를 만든다. 이 후 서버측의 난수와 ssl을 같이 클라측에 보낸다.
클라측은 공개키(ssl 인증서를 복호화하면 나옴)와 서버, 클라이언트 측의 두 난수를 통해 대칭키를 만든다.
클라, 서버는 통신을 할때 각자 만든 대칭키를 통해 암호화 복호화를 하며 데이터를 주고 받는다.
자세한 부분은 RSA 암호키워드를 살펴보자. 요약하자면 공개키를 통해 누구나 암호화를 할 수 있지만 복호화는 비밀키로만 가능하다라는 의미이다. 이 과정을 통해 대칭키를 만든 두 난수는 양측(서버, 클라이언트) 밖에 모르고 이를 복호화 할 수 있는 것도 양측밖에 없으니 다른 제 3자는 복호화를 할 수 없는 것이다.
자 그럼 그 ssl이란 무엇일까? 보통 ssl 인증서라고 하는데 이건 뭐 이 사이트가 안전합니다~ 라고 알리는 인증서 정도라고 생각하면된다.
CA(인증기관)에서 이를 발급 해준다. 클라이언트 측은 이 ssl을 서버측으로 부터 받아 이를 해당 CA의 공개키를 통해 복호화를 하는데 이때 서버의 공개키를 얻게 된다. 이를 통해 클라측은 해당 ssl이 인증된 것이라는 것을 알게 되는 것이다.
CA는 인증기관이다. 그렇다. ssl 발급해주는 곳.
대표적으로 Letsencrypt가 있다. 왜 대표적이냐. 공짜다. 근데 귀찮은게 일정 기간이후면 만료된다. 따라서 자동발급을 도와주는 certbot이랑 같이 쓰는 것이 좋다.
가서 주세요 하면 준다.
certbot certonly -- ~~
하면 준다. 근데 받고 나서 어케 쓰는지도 모른다. 여권 집에 두고 공항 가면 쫓겨난다. 가서 보여줘야 들여보내준다. 자 인증서를 가져가서 보여줄 역할이 nginx다. nginx를 통해 80, 443 포트로 들어오는 요청에 ssl쓰라고 시킬꺼다. (443은 원래 https로 쓰이는 거고 80의 경우 http로 들어오는데 리다이렉트 해서 항상 https통신하게 만들어줄꺼다)
자 뭐 깔고하긴 귀찮다. 나는 아주 상큼하고 편안한 Docker를 사용할꺼다. Docker의 장점은 volume 세팅만 해주면 나중에 꺼졌을때 똑같은 환경으로 똑같이 킬 수 도 있고, 여러가지 장점이 있으니까 Docker를 선택하게 되었다.
version: '3'
services:
web:
image: nginx
restart: always
ports:
- 80:80
- 443:443
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
- /home/ubuntu/nginx:/usr/share/nginx/html
- /etc/letsencrypt/live/{도메인}/fullchain.pem:/etc/nginx/cert/fullchain.pem
- /etc/letsencrypt/live/{도메인}/privkey.pem:/etc/nginx/cert/privkey.pem
certbot:
image: certbot/certbot
command: certonly --webroot -w /usr/share/nginx/html -d {도메인}
volumes:
- /home/ubuntu/nginx:/usr/share/nginx/html
- /etc/letsencrypt:/etc/letsencrypt
depends_on:
- web
아 근데 여기서 중요한게 (뭐 이게 문제인지는 모르겠지만 일단 추측중) 이대로 실행 시키면 인증서fullchain.pem 받아오기 전에 nginx 켜져서 nginx 볼륨 설정에 마지막 두줄
- /etc/letsencrypt/live/{도메인}/fullchain.pem:/etc/nginx/cert/fullchain.pem
- /etc/letsencrypt/live/{도메인}/privkey.pem:/etc/nginx/cert/privkey.pem
이거 없어서 터질수 있으니 일단
docker compose run certbot certonly --webroot -w /usr/share/nginx/html -d {도메인}
로 certbot만 돌려서 우선 받아두자
아 근데 여기서 조금 의문이 드는게
sudo docker cp {CONTAINER_ID}:/etc/letsencrypt/live/{도메인명} /etc/letsencrypt/live
하라고 하는데 이미 볼륨 설정 해놔서 저장되지 않나? 근데 확인하고 싶어도 따라하다가 이미 명령어 입력해서 cp땜시 복사 된건지 볼륨설정으로 된건지 모르겠다. 다음에 할때 확인해봐야할듯
여기서 펨키가 저장되는 경로는 항상 /etc/letsencrypt/live/{도메인}/인거 같긴한데 혹시라도 안되서 의심되는게 경로면
docker exec {컨테이너id} /bin/bash
들어가서 직접 찾아보자... 해보니까 지옥이더라
대충 설명하자면 volume에서
- /etc/letsencrypt/live/{도메인}/fullchain.pem:/etc/nginx/cert/fullchain.pem
- /etc/letsencrypt/live/{도메인}/privkey.pem:/etc/nginx/cert/privkey.pem
이 부분이 각각 밖에 fullchain.pem이 있는 거를 도커 컨테이너 의에 /etc/nginx/cert/로 올려두겠다라는 의미다. 여기서 이 뒤에 경로가 nginx.config에서 key찾을때 써야하니 기억해두자
server {
listen 80 default_server;
listen [::]:80 default_server;
return 301 https://$host$request_uri;
}
server{
listen 443 ssl;
ssl_certificate /etc/nginx/cert/fullchain.pem;
ssl_certificate_key /etc/nginx/cert/privkey.pem;
location /{
proxy_pass http://172.17.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
일단 80부분은 나중에 보고 앞의
server{
listen 443 ssl;
ssl_certificate /etc/nginx/cert/fullchain.pem;
ssl_certificate_key /etc/nginx/cert/privkey.pem;
location /{
proxy_pass http://172.17.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
listen 443 ssl;
에서 443포트는 https들어오는 포트이다. https로 요청하면 443포트로 온다. 그렇게 약속된듯 ㅇㅇ. ssl은 ssl로 인증한다는 뜻이다.
ssl_certificate /etc/nginx/cert/fullchain.pem; ssl_certificate_key /etc/nginx/cert/privkey.pem;
은 이제 여기에 사용된 ssl은 fullchain.pem이고 private key는 privkey.pem라고 하는 부분이다. 앞의 경로는 docker-compose에서 볼륨 경로 설정할때거다.
그 밑의 내용은 온 요청을 http://172.17.0.1:8080로 포트포워딩하겠다는 의미이다.
server {
listen 80 default_server;
listen [::]:80 default_server;
return 301 https://$host$request_uri;
}
이 부분은 http 요청을 https로 돌리는 역할이다.
빡셌다. 그냥 이전에 동료 크루가 정리한 블로그 따라하면 되는 줄 알았다. 근데 아니다. 받아온 pem키가 dir로 되어있지않나(심지어 들어가짐 ㅋㅋㅋㅋㅋㅋ) 5번 넘겨서 일주일 제한걸리지 않나. dir로 받아오는건 해결책도 못찾았다. 이거 알아낼려고 docker container 들어가서 경로 다 파해치고 난리도 아니었다. 우연히 renew 해서 받은게 있어서 그거 복사해서 넣었다(그건 제대로받아짐 ㄷㄷ). 어케 저케 해결되서 결국 성공하긴 했다. 이번을 계기로 도커의 volume에 대해 궁금해지게 되었다. 다음 포스팅은 이에 관한것이 될듯 하다.