본문 바로가기

백엔드 개발/Docker

[ssl] aws에 docker와 letsencrypt(certbot) 이용해서 ssl 인증 적용하기

반응형

1. ssl를 적용할 수 밖에 없던 과정

수개월째 백수로 지내면서 개인프로젝트를 하고 있다.

개인프로젝트에 ssl을 도입할 수 밖에 없는 이유가 두가지 있었다.


첫째, JWT 기반의 로그인을 하고 있다. JWT는 stateless라는 장점이 있어서 애플리케이션을 확장할 떄 좋지만 보안에 있어서 취약하다. 왜냐하면 사용자 정보가 일부분 들어갈 수도 있고 단순히 해쉬 알고리즘만 안다면 정보를 알 수 있기 때문이다. 그래서 ssl 인증은 필수다.


두번째, 페이스북 로그인 때문이다. 페이스북 로그인을 도입했는데 개발단계에서 localhost를 사용하는 것은 허용되지만 사용에서 https를 사용하지 않는 도메인은 허용하지 않는다.




2. 사전 조사

ssl은 전 회사에서 aws에서 제공해주는 ssl을 이용해서 도입했었다.

aws에서 ssl 도입하듯이 클릭 몇번으로 가능하면 정말 좋겠지만 이번 개인프로젝트는 어떤 환경에서도 동일한 개발환경와 확장성을 목표로 했기 때문에 자체적인 ssl 인증서를 발급해서 적용해야만 했다.

찾아보니 3개월마다 갱신해야하는 단점이 있지만 무료로 인증서를 발급해주는 기관이 있었다.


그리고 certbot이라는 간편하게 인증서의 발급과 갱신을 도와주는 도구가 있었다.

만약 컨테이너를 사용하지 않는다면 정말 간단하게 ssl 인증서를 도입할 수 있을 듯 하다.


우선 본 프로젝트에 ssl 인증을 도입하기 전에 테스트 삼아 약식으로 인증서 발급과 ssl 인증을 도입해보고자 한다.


아래는 내가 참고한 글들이다.

컨테이너에서 certbot을 이용하기 위해 webroot라는 플러그인을 사용했다.


https://agock.com/2017/01/set-lets-encrypt-nginx-web-server-webroot-plugin/


https://codechacha.com/ko/letsencrypt-using-nginx-certbot/


https://xxcv.tistory.com/6



4. 도메인 발급과 도커 머신 띄우기

1.  ssl 인증을 하기 위해서는 도메인은 필수이다.

굳이 구입할 필요없이 freenom이라는 사이트에서는 1개월에서 12개월까지 사용할 수 있는 무료 도메인을 발급해주고 있다.

회원가입해서 발급받도록 하자.

필자는 minussl.ml 이라는 도메인을 발급받았다.



도메인 네임 서버 사용하는 법은 알아보도록 하자.


1.상단의 services에서 my domain-> Manage Domain 으로 이동

2. 상단의 Management Tools에서 nameservers에서 첫번째 라디오박스를 선택한다.



3. 상단의 manage Freenom DNS를 선택한다.


4. Target에는 이후의 aws 인스턴스의 ip주소를 넣어주면 되고 Record 값도 넣어주면 된다.



2. aws에서 인스턴스를 띄우고 도커를 설치하자.

필자는 간편하게 docker-machine을 이용해서 간편하게 aws에 docker가 설치되어있는 인스턴스를 띄웠다.

docker-machine을 이용한다면 이후에 docker swarm이라는 컨테이너 오케스트레이션 툴을 간편하게 도입할 수 있으니 기회가 되  면 학습해보도록 하자.



필자는 aws 인스턴스를 띄우는 일이 자주 있길래 쉘 스크립트를 작성해서 자동화시켰다.

혹시 필요한 독자가 있다면 참고


#! /bin/bash
# you need input your access key using 'aws configuration' command

read -p "instance name: " machineName
read -p "instance type: " instanceType

instanceType=${instanceType:-t2.micro}

docker-machine create -d amazonec2 \
--amazonec2-instance-type $instanceType \
--amazonec2-region ap-northeast-2 $machineName

docker-machine ls
docker-machine ssh $machineName sudo usermod -aG docker ubuntu


5. aws 인스턴스의 port open

ec2 인스턴스가 속해있는 보안그룹의 port를 열어줘야한다.

별 일아닌 거 같지만 막상 작업을 완료하고 나서 안되는 상황을 겪게 되면 정말 골때리고 시간 낭비 오지게하니 생각났을 때 진행하자.

(필자는 덤벙대는 바람에 좌절을 겪은 적이 몇번 있다)


잘 모르겠다면 아래 링크를 참고하도록 하고 포트는 여러 상황을 실험해보기 위해서 80, 443, 8080, 7946 네개를 열어보기로 한다.


http://hellogohn.com/post_one137


위에 도메인네임서버에 인스턴스를 연결하는 방법이 있으니 참고해서 연결하도록 하자.



6. nginx 이미지를 받아서 컨테이너를 띄워보자

사용할 이미지는 nginx:mainline-nginx 이다.



docker run --name [container name] -it -d -p 80:80 -p 443:443 -p 8080:8080 -p 7946:7946 -v [호스트 폴더]:[컨테이너 폴더] nginx:mainline-alpine


위 명령어를 이용해서 컨테이너를 실행하자.    

볼륨 옵션에서 폴더 명은 /var/www/본인 도메인명 으로 하기를 권장한다.

이 폴더에 발급받은 인증서가 위치할 것이다.


그리고 인증서 발급할 때 이 폴더에  www.[도메인]/.well-known/acme-challenge/의 요청을 매핑시키는 방법으로 도메인을 소유하고 있는지 인증한다.


필자는 아래와 같은 명령어를 사용했다.


docker run --name ssltest -it -d -p 80:80 -p 443:443 -p 8080:8080 -p 7946:7946 -v /var/www/minussl:/var/www/minussl nginx:mainline-alpine


7. 인증서 발급을 위해 nginx 설정

docker exec -it [container name] sh 로 bash를 실행한다.


nginx 설정파일을 수정해서 /var/www/minussl이 폴더ㄹ www.minussl.ml/.well-known/acme-challenge/로 오는 요청을 매핑할 것이다.


nginx 설정파일은 /etc/nginx/conf.d/default.conf에 위치하고 있으니 vi 명령어로 편집화면으로 들어간다.


http{} 중괄호 안에 아래 설정을 추가하도록 하자.



   location ^~ /.well-known/acme-challenge/ {
                default_type "text/plain";
                root /var/www/minussl;
    }


편집화면에서 나와서 nginx -T로 틀린 부분은 없었는지 확인하고 없다면 nginx -s reload로 재실행한다.

그리고 인터넷 브라우저에서 해당 도메인으로 들어가서 정상 작동되는지 확인해보자.


80포트를 열어놓았고 host와 바인딩했기 때문에 접속가능하다.


8. 인증서 발급 받기



https://certbot.eff.org/lets-encrypt/ubuntuxenial-other


위 링크에서 software는 none of the above 선택하고 system은 각자에 맞춰서 선택해서 설치하면 된다.

설치가 성공적으로 되었다면


sudo certbot certonly --webroot -w [인증서 발급받을 폴더( docker container에 볼륨 옵션줬던 폴더)] -d [본인 도메인 주소]

를 입력하면 된다.


필자는 아래와 같이 명령어를 주었다.

sudo certbot certonly --webroot -w /var/www/minussl -d minussl.ml


이메일을 입력해야하고 아까도 강조했듯이 /.well-known/acme-challenge/ 이 주소로 요청이 갔을 때 볼륨 옵션주었던 폴더가 매핑되어야한다.


위와같이 성공적으로 발급이 되었다.



그런데 문제가 있다. 발급된 privkey.pem와 fullchain.pem 파일은 심볼릭 링크이다. 그래서 도커에서 연결이 불가능하므로 진본파일을 /var/www/minussl로 옮겨주어야한다.

우선 /etc/letsencrypt/live/minussl.ml으로는 권한문제로 파일을 조회해볼 수 없다.

sudo chmod ug+rwx 명령어로 접근권한을 얻고 디렉토리로 가서 파일의 원본 위치를 확인해보자.



저 중 fullchain1.pem과 privkey1.pem을  -v 옵션을 주었던 폴더로 옮겨야 nginx 컨테이너에서도 인증서를 사용할 수 있다.

sudo mp ../../archive/minussl.ml/[파일명] /var/www/minussl/[파일명]으로 복사해주자.


이제 컨테이너로 접속해서 파일이 공유되는지 확인해보자


공유되고 있으니 이제 nginx 설정파일을 수정하면 ssl 설정만하면 끝이다.


9. nginx 설정

현재 nginx.conf 파일은 include 옵션으로  /etc/nginx/conf.d/ 아래의 conf 확장자의 모든 파일들을 참조하고 있다.

우선 vi /etc/nginx/conf.d/https.conf 로 파일을 하나 생성해보자. 443 포트를 매핑해볼 것이다.


server {
listen 443 ssl;
server_name minussl.ml;

ssl_certificate /var/www/minussl/fullchain1.pem;
ssl_certificate_key /var/www/minussl/privkey1.pem;

ssl_session_timeout 5m;
ssl_protocols SSLv2 SSLv3 TLSv1;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;


location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}


자 파일을 생성하고 nginx -s reload로 설정을 적용하자.

그리고 https://[도메인]으로 바로 접속해보자.


상큼하게 적용되었다.

위 설정파일에서 포트 번호만 바꿔서 새로 파일을 생성해줘도 잘 매핑된다.





구글링해보면 80 포트 자체를 443으로 돌려서 https로만 접속하는 방법도 있다.

본인의 프로젝트의 입맛에 맞게 설정해보길 바란다.


인증서 발급과 설정은 생각보다 쉬워서 별로 어렵지 않게 할 수 있을 것이다.

이제 내가 할 작업은 기존의 애플리케이션에서 client layer와 auth-server에 https를 적용하는 것이다.

특히 auth-server는 nginx의 procxy_pass를 이용해서 ssl을 적용할 생각이다.

spring boot에서 embedded tomcat 옵션으로 ssl을 손쉽게 적용할 수 있지만 컨테이너를 띄울때마다 인증서와 -v 옵션으로 매핑해줘야하는게 안좋다.


더군다나 docker swarm으로 다른 ec2 인스턴스에 컨테이너가 띄워질 가능성도 있으니 말이다.

인증서에 대한 정보는 load balance 역할을 하는 nginx만 알고 service명으로 컨테이너들을 매핑해서 라운드 로빈 방식으로 배치하는 것을 고려하고 있다.


반응형