Nginx TLS 1.3 setup

 

TLS 1.3

네트워크상에서 서로 주고받는 데이터를 암호화하는데 사용되는 프로토콜 TLS (Transport Layer Security) 의 새로운 1.3 버전이 2018년 8월에 정식 게시되었다. 2008년 8월에 게시되었던 TLS 1.2 버전 이후 10년만에 업데이트된 TLS 1.3 버전은 보다 빠르고 더욱 안전한 보안 연결을 제공한다.

 

OpenSSL + Nginx

우분투 서버에서는 OpenSSL이 TLS를 담당하는데, 2018년 9월에 출시된 OpenSSL 1.1.1 버전부터 TLS 1.3을 지원한다. 또한 웹 서버 Nginx는 1.13.0 버전부터 TLS 1.3을 지원한다. 다만 우분투 서버 18.04 버전에 기본 설치된 OpenSSL은 1.1.0 버전, Nginx는 1.14.0 버전이기 때문에 Nginx에 TLS 1.3을 적용하기 위해서는 OpenSSL을 1.1.1 이상의 버전으로 업그레이드해야 한다.

이때 두 가지 방식을 사용할 수 있는데, 첫번째는 우분투 서버 18.04에 설치된 OpenSSL을 업그레이드하는 방법이고, 두번째는 우분투 서버 18.04에 설치된 OpenSSL은 그대로 놔두고 Nginx에 OpenSSL 1.1.1 버전을 넣고 다시 빌드해서 사용하는 방법이다. 우분투 서버에 설치된 OpenSSL은 시스템 전반에 관여하기 때문에 임의로 새로운 버전으로 업그레이드했을 경우 예상하지 못한 문제가 발생할 수 있다. 따라서 Nginx에 직접 OpenSSL 1.1.1 버전을 넣어서 사용하는 방법을 선택했다.

 

소스 코드 준비

Nginx에 OpenSSL 1.1.1 버전을 넣고 다시 빌드하기 위해서 Nginx와 OpenSSL의 소스 코드를 준비한다. 이때 Nginx의 소스 코드는 Nginx 측에서 제공하는 것과 우분투 측에서 제공하는 것 중에서 선택할 수 있는데, Nginx가 설치되는 경로나 기본 설정 파일의 내용 등이 서로 다르기 때문에 우분투 서버에 맞게 우분투 측에서 제공하는 소스 코드를 선택했다.

sudo apt update
sudo apt install dpkg-dev

먼저 우분투 패키지 저장소 정보를 업데이트한 다음, 소스 코드를 얻고 빌드하는데 필요한 dpkg-dev를 설치한다.

sudo nano /etc/apt/sources.list

nano 편집기로 우분투의 패키지 저장소 주소를 관리하는 파일을 연다.

deb-src http://archive.ubuntu.com/ubuntu/ bionic main restricted
deb-src http://archive.ubuntu.com/ubuntu/ bionic-updates main restricted
deb-src http://security.ubuntu.com/ubuntu bionic-security main restricted

소스 코드를 얻을 수 있는 deb-src로 시작하는 주소들이 기본적으로 주석 처리되어 있는데, 위의 세 주소 앞의 #을 제거해서 주석 처리를 해제한다. http 부분의 URI는 시스템마다 다를 수 있다. deb-src로 시작하고 bionic main restrictedbionic-updates main restrictedbionic-security main restricted로 끝나는 세 주소의 주석 처리를 해제한다. 편집이 끝났으면 Ctrl키와 x키를 동시에 눌러 nano 편집기를 빠져나오면서 저장한다.

cd /tmp

이제 소스 코드를 내려받는데, 작업하기 편하도록 /tmp 디렉토리로 이동한다.

sudo apt update
sudo apt source nginx

우분투 패키지 저장소 목록을 반드시 다시 업데이트하고, 우분투의 패키지 저장소에서 Nginx 소스 코드를 내려받는다.

그다음, OpenSSL 웹사이트 https://www.openssl.org/source/ 에 접속해서 1.1.1 버전의 소스 코드 다운로드 주소를 확인한다. 이 글을 작성하는 현재의 최신 1.1.1 버전은 1.1.1a이고 다운로드 주소는 https://www.openssl.org/source/openssl-1.1.1a.tar.gz 이다.

wget https://www.openssl.org/source/openssl-1.1.1a.tar.gz
tar -zxvf openssl-1.1.1a.tar.gz

wget 명령으로 OpenSSL 소스 파일을 내려받고, tar 명령으로 내려받은 파일의 압축을 해제한다.

ls /tmp/

소스 코드가 저장된 디렉토리 이름을 확인한다. nginx-1.14.0openssl-1.1.1a 형태의 디렉토리 이름이 보일 것이다.

sudo mkdir /usr/local/src/nginx
sudo mkdir /usr/local/src/openssl

소스 코드를 관리할 디렉토리를 생성한다.

sudo cp -r /tmp/nginx-1.14.0 /usr/local/src/nginx/
sudo cp -r /tmp/openssl-1.1.1a /usr/local/src/openssl/

내려받은 소스 코드를 앞서 생성한 디렉토리로 복사한다.

 

Nginx 빌드

sudo nano /usr/local/src/nginx/nginx-1.14.0/debian/rules

nano 편집기로 Nginx 빌드 설정 파일을 연다.

# configure flags
common_configure_flags := \
                        --with-cc-opt="$(debian_cflags)" \
                        --with-ld-opt="$(debian_ldflags)" \
                        --prefix=/usr/share/nginx \
                        --conf-path=/etc/nginx/nginx.conf \
                        --http-log-path=/var/log/nginx/access.log \
                        --error-log-path=/var/log/nginx/error.log \
                        --lock-path=/var/lock/nginx.lock \
                        --pid-path=/run/nginx.pid \
                        --modules-path=/usr/lib/nginx/modules \
                        --http-client-body-temp-path=/var/lib/nginx/body \
                        --http-fastcgi-temp-path=/var/lib/nginx/fastcgi \
                        --http-proxy-temp-path=/var/lib/nginx/proxy \
                        --http-scgi-temp-path=/var/lib/nginx/scgi \
                        --http-uwsgi-temp-path=/var/lib/nginx/uwsgi \
                        --with-debug \
                        --with-pcre-jit \
                        --with-http_ssl_module \
                        --with-http_stub_status_module \
                        --with-http_realip_module \
                        --with-http_auth_request_module \
                        --with-http_v2_module \
                        --with-http_dav_module \
                        --with-http_slice_module \
                        --with-threads \
                        --with-openssl=/usr/local/src/openssl/openssl-1.1.1a

light_configure_flags := \

common_configure_flags 부분을 찾아서 위의 예시에 색깔로 표시한 내용을 추가한다. 새로운 내용 추가로 인해 –with-threads가 더이상 마지막 항목이 아니게 되므로 뒷부분에 \를 추가해야 한다. 편집이 끝났으면 Ctrl키와 x키를 동시에 눌러 nano 편집기를 빠져나오면서 저장한다.

sudo apt update
sudo apt build-dep nginx

우분투 패키지 저장소 목록을 업데이트하고, Nginx가 의존하는 패키지를 설치한다.

cd /usr/local/src/nginx/nginx-1.14.0

Nginx 소스 디렉토리로 이동한다.

sudo dpkg-buildpackage -b -j1 -uc -us

Nginx를 빌드한다.

 

Nginx 설치

ls /usr/local/src/nginx/

빌드된 파일들의 이름을 확인한다. .deb 확장자의 파일이 빌드된 설치 파일이다.

sudo apt remove nginx nginx-common nginx-core nginx-light nginx-full nginx-extras

기존에 설치된 Nginx가 있다면 제거한다.

sudo apt install nginx

The following NEW packages will be installed:
  libnginx-mod-http-geoip libnginx-mod-http-image-filter libnginx-mod-http-xslt-filter libnginx-mod-mail libnginx-mod-stream nginx nginx-common nginx-core

Do you want to continue? [Y/n] n

apt install 명령어로 Nginx 설치 명령을 내려서 어떤 패키지들이 설치되는지만 확인하고 설치 여부를 묻는 메시지가 나오면 n을 입력해서 취소한다. 이 예시에서는 8가지 패키지를 설치해야 함을 확인했다.

그다음, 확인한 8가지 패키지에 해당하는 설치 파일을 /usr/local/src/nginx/ 경로에 빌드된 .deb 파일들 중에서 찾아서 아래의 명령어로 설치한다. 이때 각 패키지의 의존 관계 때문에 설치하는 순서가 중요한데, nginx-common 패키지를 가장 먼저 설치하고, 그다음 libnginx-mod 패키지들을 설치하고, 그다음 nginx-core 등의 패키지를 설치하고, 마지막으로 nginx 패키지를 설치한다. 위에서 확인한 8가지 패키지의 설치 명령은 아래와 같다:

sudo dpkg -i /usr/local/src/nginx/nginx-common_1.14.0-0ubuntu1.2_all.deb

sudo dpkg -i /usr/local/src/nginx/libnginx-mod-http-geoip_1.14.0-0ubuntu1.2_amd64.deb
sudo dpkg -i /usr/local/src/nginx/libnginx-mod-http-image-filter_1.14.0-0ubuntu1.2_amd64.deb
sudo dpkg -i /usr/local/src/nginx/libnginx-mod-http-xslt-filter_1.14.0-0ubuntu1.2_amd64.deb
sudo dpkg -i /usr/local/src/nginx/libnginx-mod-mail_1.14.0-0ubuntu1.2_amd64.deb
sudo dpkg -i /usr/local/src/nginx/libnginx-mod-stream_1.14.0-0ubuntu1.2_amd64.deb

sudo dpkg -i /usr/local/src/nginx/nginx-core_1.14.0-0ubuntu1.2_amd64.deb

sudo dpkg -i /usr/local/src/nginx/nginx_1.14.0-0ubuntu1.2_all.deb

sudo systemctl start nginx

설치가 완료되었으면 Nginx를 작동시킨다.

nginx -V

Nginx의 세부 버전 정보를 확인한다. (V는 대문자이다)
built with OpenSSL 1.1.1a 등의 문구를 통해서 Nginx가 OpenSSL 1.1.1a 버전을 사용함을 확인할 수 있다.

sudo apt-mark hold nginx-common nginx-core nginx
sudo apt-mark hold libnginx-mod-http-geoip libnginx-mod-http-image-filter libnginx-mod-http-xslt-filter libnginx-mod-mail libnginx-mod-stream

만일 apt upgrade 명령으로 패키지가 업그레이드되면 OpenSSL 1.1.1이 포함되지 않은 원래의 버전으로 되돌아간다. 직접 빌드해서 설치한 8가지 패키지들이 apt upgrade 명령에서 보류되도록 apt-mark hold 명령으로 지정해준다.

 

TLS 1.3 서버 블록 설정

작동 중인 웹사이트의 서버 블록에 TLS 1.3 설정을 추가한다. 앞선 글 웹 서버: Nginx에서 작성한 서버 블록을 예로 들면 아래와 같다:

sudo nano /etc/nginx/sites-available/example.com

nano 편집기로 example.com의 서버 블록 파일을 연다.

server {
        listen 80 default_server;

        server_name example.com www.example.com;

        return 301 https://$server_name$request_uri;
}

server {
        listen 443 ssl http2 default_server;

        server_name example.com www.example.com;

        root /var/www/example.com/html;

        ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
        ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
        ssl_dhparam /etc/ssl/certs/dhparam.pem;

        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_prefer_server_ciphers on;
        ssl_ciphers TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256;
        ssl_ecdh_curve secp384r1;
        ssl_session_timeout 10m;
        ssl_session_cache shared:SSL:10m;
        ssl_session_tickets off;
        ssl_stapling on;
        ssl_stapling_verify on;
        resolver 1.1.1.1 1.0.0.1 valid=300s;
        resolver_timeout 5s;

        add_header Strict-Transport-Security max-age=31536000;
        add_header X-Frame-Options SAMEORIGIN;
        add_header X-Content-Type-Options nosniff;
        add_header X-XSS-Protection "1; mode=block";

        index index.html index.htm;

        location / {
                try_files $uri $uri/ =404;
        }
}

빨간색으로 표시된 부분을 추가해서 TLSv1.3 작동을 켜고, TLS 1.3이 사용하는 암호화 조합을 추가한다. 만일 443 포트에 default_server로 지정된 서버 블록이 있다면 이 서버 블록에 TLS 1.3을 적용해야 정상 작동한다.

이외의 서버 블록의 내용은 앞선 글 웹 서버: Nginx를 참고한다.

편집을 끝냈으면 Ctrl키와 x키를 동시에 눌러서 nano 편집기를 빠져나오면서 저장한다.

sudo nginx -t
sudo systemctl restart nginx

Nginx 설정의 기본적인 문법 오류를 검사하고, Nginx를 재시작한다.

 

TLS 1.3 작동 확인

TLS 1.3을 지원하는 웹 브라우저로 접속하면 TLS 1.3 연결이 올바르게 생성되었는지 확인할 수 있다.

구글 크롬 웹 브라우저를 예로 들면, 웹 사이트에 접속한 다음 Ctrl Shift i 키를 동시에 누르면 개발자 도구가 나타나는데, 상단의 Security 메뉴를 보면 현재 TLS 1.3으로 연결되었는지 확인할 수 있다.

만일 Bitdefender 같은 SSL 검사 기능이 있는 시스템 보호 프로그램을 사용하고 있다면 이 기능을 꺼야 올바른 TLS 정보를 확인할 수 있다.

chrome-tls13.png

 

본 글의 저작권은 작성자 Varins에게 있습니다.
Varins의 사전 서면 동의 없이는 본 글의 전부 또는 일부를 무단으로 전재, 게시, 배포하는 것을 금지합니다.

코멘트 없음
맨위로