Ubuntu 16.04에서 Nginx용 자체 서명 SSL 인증서를 만드는 방법


소개

TLS(Transport Layer Security)와 이전 SSL(Secure Sockets Layer)은 일반 트래픽을 보호되고 암호화된 래퍼로 래핑하는 데 사용되는 웹 프로토콜입니다.

이 기술을 사용하여 서버는 외부 당사자가 메시지를 가로챌 가능성 없이 서버와 클라이언트 간에 안전하게 트래픽을 보낼 수 있습니다. 인증서 시스템은 또한 사용자가 연결 중인 사이트의 신원을 확인하는 데 도움을 줍니다.

이 가이드에서는 Ubuntu 16.04 서버에서 Nginx 웹 서버와 함께 사용하기 위해 자체 서명된 SSL 인증서를 설정하는 방법을 보여줍니다.

참고: 자체 서명된 인증서는 서버와 모든 클라이언트 간의 통신을 암호화합니다. 그러나 웹 브라우저에 포함된 신뢰할 수 있는 인증 기관에서 서명하지 않았기 때문에 사용자는 인증서를 사용하여 서버의 ID를 자동으로 확인할 수 없습니다.

자체 서명된 인증서는 서버와 연결된 도메인 이름이 없고 암호화된 웹 인터페이스가 사용자를 향하지 않는 경우에 적합할 수 있습니다. 도메인 이름이 있으면 대부분의 경우 CA 서명 인증서를 사용하는 것이 좋습니다. 여기에서 Let’s Encrypt 프로젝트로 신뢰할 수 있는 무료 인증서를 설정하는 방법을 확인할 수 있습니다.

전제 조건

시작하기 전에 루트가 아닌 사용자가 sudo 권한으로 구성되어 있어야 합니다. Ubuntu 16.04에 대한 초기 서버 설정에 따라 이러한 사용자 계정을 설정하는 방법을 배울 수 있습니다.

또한 Nginx 웹 서버가 설치되어 있어야 합니다. 서버에 전체 LEMP(Linux, Nginx, MySQL, PHP) 스택을 설치하려는 경우 Ubuntu 16.04에서 LEMP 설정에 대한 가이드를 따를 수 있습니다.

Nginx 웹 서버만 원하는 경우 대신 Ubuntu 16.04에 Nginx 설치 가이드를 따를 수 있습니다.

전제 조건을 완료했으면 아래를 계속하십시오.

1단계: SSL 인증서 생성

TLS/SSL은 공개 인증서와 개인 키의 조합을 사용하여 작동합니다. SSL 키는 서버에서 비밀로 유지됩니다. 클라이언트로 전송되는 콘텐츠를 암호화하는 데 사용됩니다. SSL 인증서는 콘텐츠를 요청하는 모든 사람과 공개적으로 공유됩니다. 연결된 SSL 키로 서명된 콘텐츠를 해독하는 데 사용할 수 있습니다.

단일 명령으로 OpenSSL을 사용하여 자체 서명된 키 및 인증서 쌍을 만들 수 있습니다.

  1. sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl/private/nginx-selfsigned.key -out /etc/ssl/certs/nginx-selfsigned.crt

일련의 질문을 받게 됩니다. 살펴보기 전에 실행 중인 명령에서 어떤 일이 발생하는지 살펴보겠습니다.

  • openssl: OpenSSL 인증서, 키 및 기타 파일을 만들고 관리하기 위한 기본 명령줄 도구입니다.
  • req: 이 하위 명령은 X.509 인증서 서명 요청(CSR) 관리를 사용하도록 지정합니다. "X.509\는 SSL 및 TLS가 키 및 인증서 관리를 위해 준수하는 공개 키 인프라 표준입니다. 새 X.509 인증서를 생성하려고 하므로 이 하위 명령을 사용합니다.
  • -x509: 일반적으로 발생하는 인증서 서명 요청을 생성하는 대신 자체 서명된 인증서를 만들고 싶다고 유틸리티에 알려 이전 하위 명령을 추가로 수정합니다.
  • -nodes: 이것은 OpenSSL이 암호로 인증서를 보호하는 옵션을 건너뛰도록 지시합니다. 서버가 시작될 때 사용자 개입 없이 파일을 읽을 수 있으려면 Nginx가 필요합니다. 암호는 다시 시작할 때마다 암호를 입력해야 하므로 이러한 일이 발생하지 않도록 합니다.
  • -days 365: 이 옵션은 인증서가 유효한 것으로 간주되는 기간을 설정합니다. 여기서는 1년으로 설정했습니다.
  • -newkey rsa:2048: 새 인증서와 새 키를 동시에 생성하도록 지정합니다. 이전 단계에서 인증서 서명에 필요한 키를 생성하지 않았으므로 인증서와 함께 생성해야 합니다. rsa:2048 부분은 2048비트 길이의 RSA 키를 만들도록 지시합니다.
  • -keyout: 이 행은 OpenSSL에 생성 중인 개인 키 파일을 저장할 위치를 알려줍니다.
  • -out: OpenSSL에 우리가 만들고 있는 인증서를 둘 위치를 알려줍니다.

위에서 언급했듯이 이러한 옵션은 키 파일과 인증서를 모두 생성합니다. 인증서에 정보를 올바르게 삽입하기 위해 서버에 대한 몇 가지 질문을 받게 됩니다.

프롬프트를 적절하게 작성하십시오. 가장 중요한 줄은 일반 이름(예: 서버 FQDN 또는 귀하의 이름)을 요청하는 줄입니다. 서버와 연결된 도메인 이름을 입력하거나 서버의 공용 IP 주소를 입력해야 합니다.

전체 프롬프트는 다음과 같습니다.

Output
Country Name (2 letter code) [AU]:US State or Province Name (full name) [Some-State]:New York Locality Name (eg, city) []:New York City Organization Name (eg, company) [Internet Widgits Pty Ltd]:Bouncy Castles, Inc. Organizational Unit Name (eg, section) []:Ministry of Water Slides Common Name (e.g. server FQDN or YOUR name) []:server_IP_address Email Address []:admin@your_domain.com

생성한 두 파일 모두 /etc/ssl 디렉토리의 적절한 하위 디렉토리에 배치됩니다.

OpenSSL을 사용하는 동안 클라이언트와 Perfect Forward Secrecy 협상에 사용되는 강력한 Diffie-Hellman 그룹도 만들어야 합니다.

다음을 입력하면 됩니다.

  1. sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

이 작업은 몇 분 정도 걸릴 수 있지만 완료되면 구성에서 사용할 수 있는 /etc/ssl/certs/dhparam.pem에 강력한 DH 그룹이 생성됩니다.

2단계: SSL을 사용하도록 Nginx 구성

/etc/ssl 디렉터리 아래에 키 및 인증서 파일을 만들었습니다. 이제 이를 활용하기 위해 Nginx 구성을 수정하기만 하면 됩니다.

구성을 약간 조정할 것입니다.

  1. SSL 키와 인증서 파일 위치를 포함하는 구성 스니펫을 생성합니다.
  2. 향후 모든 인증서와 함께 사용할 수 있는 강력한 SSL 설정이 포함된 구성 스니펫을 생성합니다.
  3. SSL 요청을 처리하고 위의 두 스니펫을 사용하도록 Nginx 서버 블록을 조정합니다.

Nginx를 구성하는 이 방법을 사용하면 서버 블록을 깨끗하게 유지하고 공통 구성 세그먼트를 재사용 가능한 모듈에 넣을 수 있습니다.

SSL 키 및 인증서를 가리키는 구성 조각 만들기

먼저 /etc/nginx/snippets 디렉토리에 새로운 Nginx 구성 스니펫을 생성해 보겠습니다.

이 파일의 용도를 적절하게 구분하기 위해 self-signed.conf라고 부르겠습니다.

  1. sudo nano /etc/nginx/snippets/self-signed.conf

이 파일 내에서 ssl_certificate 지시문을 인증서 파일로 설정하고 ssl_certificate_key를 관련 키로 설정하기만 하면 됩니다. 우리의 경우에는 다음과 같이 보일 것입니다.

ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;

해당 줄을 추가했으면 파일을 저장하고 닫습니다.

강력한 암호화 설정으로 구성 스니펫 생성

다음으로 일부 SSL 설정을 정의하는 또 다른 스니펫을 생성합니다. 이렇게 하면 강력한 SSL 암호화 제품군으로 Nginx가 설정되고 서버 보안을 유지하는 데 도움이 되는 몇 가지 고급 기능이 활성화됩니다.

설정할 매개변수는 향후 Nginx 구성에서 재사용할 수 있으므로 파일에 일반 이름을 지정합니다.

  1. sudo nano /etc/nginx/snippets/ssl-params.conf

Nginx SSL을 안전하게 설정하기 위해 여기에서 권장 사항을 사용합니다.

위에 링크된 사이트의 권장 설정은 강력한 보안을 제공합니다. 경우에 따라 클라이언트 호환성을 희생해야 합니다. 이전 클라이언트를 지원해야 하는 경우 "예, 레거시/오래된 소프트웨어에서 작동하는 암호화 제품군을 제공합니다.\라고 표시된 페이지의 링크를 클릭하여 액세스할 수 있는 대체 목록이 있습니다. 해당 목록은 아래 복사된 항목으로 대체될 수 있습니다.

사용하는 구성의 선택은 주로 지원해야 하는 항목에 따라 달라집니다. 둘 다 훌륭한 보안을 제공합니다.

우리의 목적을 위해 제공된 설정을 전체적으로 복사할 수 있습니다. 약간의 수정만 하면 됩니다.

먼저 업스트림 요청에 대해 선호하는 DNS 확인자를 추가합니다. 이 가이드에서는 Google을 사용합니다. 또한 이전에 생성한 Diffie-Hellman 파일을 가리키도록 ssl_dhparam 설정을 설정합니다.

마지막으로 잠시 시간을 내어 "사전 로드\ 기능에 대해 읽어보십시오. HSTS를 사전 로드하면 보안이 강화되지만 실수로 활성화하거나 잘못 활성화하면 광범위한 결과를 초래할 수 있습니다. 이 가이드에서는 설정을 사전 로드하지 않지만 의미를 이해하고 있다고 확신하는 경우 수정할 수 있습니다.

# from https://cipherli.st/
# and https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# Disable preloading HSTS for now.  You can use the commented out header line that includes
# the "preload" directive if you understand the implications.
#add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;

ssl_dhparam /etc/ssl/certs/dhparam.pem;

자체 서명된 인증서를 사용하고 있기 때문에 SSL 스테이플링은 사용되지 않습니다. Nginx는 단순히 경고를 출력하고 자체 서명된 인증서에 대한 스테이플링을 비활성화하며 계속해서 올바르게 작동합니다.

완료되면 파일을 저장하고 닫습니다.

SSL을 사용하도록 Nginx 구성 조정

이제 스니펫이 있으므로 Nginx 구성을 조정하여 SSL을 활성화할 수 있습니다.

이 가이드에서는 /etc/nginx/sites-available 디렉토리에 있는 기본 서버 블록 파일을 사용하고 있다고 가정합니다. 다른 서버 블록 파일을 사용하는 경우 아래 명령에서 이름을 대체하십시오.

계속 진행하기 전에 현재 서버 블록 파일을 백업해 보겠습니다.

  1. sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/default.bak

이제 서버 블록 파일을 열어 조정합니다.

  1. sudo nano /etc/nginx/sites-available/default

내부에서 서버 블록은 아마도 다음과 같이 시작될 것입니다.

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    # SSL configuration

    # listen 443 ssl default_server;
    # listen [::]:443 ssl default_server;

    . . .

암호화되지 않은 HTTP 요청이 자동으로 암호화된 HTTPS로 리디렉션되도록 이 구성을 수정할 것입니다. 이것은 우리 사이트에 최고의 보안을 제공합니다. HTTP 및 HTTPS 트래픽을 모두 허용하려면 다음에 나오는 대체 구성을 사용하십시오.

구성을 두 개의 개별 블록으로 분할합니다. 두 개의 첫 번째 listen 지시문 뒤에 server_name 지시문을 추가하여 서버의 도메인 이름 또는 IP 주소로 설정합니다. 그런 다음 생성할 두 번째 서버 블록에 대한 리디렉션을 설정합니다. 그런 다음 이 짧은 블록을 닫습니다.

참고: 모든 것이 제대로 작동하는지 확인할 때까지 302 리디렉션을 사용합니다. 나중에 이를 영구 301 리디렉션으로 변경할 수 있습니다.

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name server_domain_or_IP;
    return 302 https://$server_name$request_uri;
}

    # SSL configuration

    # listen 443 ssl default_server;
    # listen [::]:443 ssl default_server;

    . . .

다음으로 나머지 구성을 포함하기 위해 바로 아래에서 새 서버 블록을 시작해야 합니다. 포트 443을 사용하는 두 개의 listen 지시문을 주석 해제할 수 있습니다. 이 블록 내에서 HTTP/2를 활성화하기 위해 이 줄에 http2를 추가할 수 있습니다. 그런 다음 설정한 두 개의 스니펫 파일을 포함하기만 하면 됩니다.

참고: 각 IP 버전 및 포트 조합에 대한 default_server 한정자를 포함하는 listen 지시문은 하나만 있을 수 있습니다. default_server가 설정된 이러한 포트에 대해 다른 서버 블록을 활성화한 경우 블록 중 하나에서 수정자를 제거해야 합니다.

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name server_domain_or_IP;
    return 302 https://$server_name$request_uri;
}

server {

    # SSL configuration

    listen 443 ssl http2 default_server;
    listen [::]:443 ssl http2 default_server;
    include snippets/self-signed.conf;
    include snippets/ssl-params.conf;

    . . .

완료되면 파일을 저장하고 닫습니다.

(대체 구성) HTTP 및 HTTPS 트래픽 모두 허용

암호화된 콘텐츠와 암호화되지 않은 콘텐츠를 모두 허용하고 싶거나 허용해야 하는 경우 Nginx를 약간 다르게 구성해야 합니다. 이것은 일반적으로 피할 수 있는 경우 권장되지 않지만 경우에 따라 필요할 수 있습니다. 기본적으로 두 개의 개별 서버 블록을 하나의 블록으로 압축하고 리디렉션을 제거합니다.

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    listen 443 ssl http2 default_server;
    listen [::]:443 ssl http2 default_server;

    server_name server_domain_or_IP;
    include snippets/self-signed.conf;
    include snippets/ssl-params.conf;

    . . .

완료되면 파일을 저장하고 닫습니다.

3단계: 방화벽 조정

전제 조건 가이드에서 권장하는 대로 ufw 방화벽을 활성화한 경우 SSL 트래픽을 허용하도록 설정을 조정해야 합니다. 운 좋게도 Nginx는 설치 시 ufw로 몇 개의 프로필을 등록합니다.

다음을 입력하여 사용 가능한 프로필을 볼 수 있습니다.

  1. sudo ufw app list

다음과 같은 목록이 표시되어야 합니다.

Output
Available applications: Nginx Full Nginx HTTP Nginx HTTPS OpenSSH

다음을 입력하여 현재 설정을 볼 수 있습니다.

  1. sudo ufw status

아마도 다음과 같을 것입니다. 이는 웹 서버에 HTTP 트래픽만 허용됨을 의미합니다.

Output
Status: active To Action From -- ------ ---- OpenSSH ALLOW Anywhere Nginx HTTP ALLOW Anywhere OpenSSH (v6) ALLOW Anywhere (v6) Nginx HTTP (v6) ALLOW Anywhere (v6)

HTTPS 트래픽을 추가로 허용하려면 "Nginx Full\ 프로필을 허용한 다음 중복 "Nginx HTTP\ 프로필 허용을 삭제할 수 있습니다.

  1. sudo ufw allow 'Nginx Full'
  2. sudo ufw delete allow 'Nginx HTTP'

현재 상태는 다음과 같아야 합니다.

  1. sudo ufw status
Output
Status: active To Action From -- ------ ---- OpenSSH ALLOW Anywhere Nginx Full ALLOW Anywhere OpenSSH (v6) ALLOW Anywhere (v6) Nginx Full (v6) ALLOW Anywhere (v6)

4단계: Nginx에서 변경 사항 활성화

이제 변경 사항을 적용하고 방화벽을 조정했으므로 Nginx를 다시 시작하여 새로운 변경 사항을 구현할 수 있습니다.

먼저 파일에 구문 오류가 없는지 확인해야 합니다. 다음을 입력하면 됩니다.

  1. sudo nginx -t

모든 것이 성공하면 다음과 같은 결과가 나타납니다.

Output
nginx: [warn] "ssl_stapling" ignored, issuer certificate not found nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful

처음에 경고를 확인하십시오. 앞서 언급했듯이 이 특정 설정은 자체 서명된 인증서가 SSL 스테이플링을 사용할 수 없기 때문에 경고를 표시합니다. 이것은 예상된 것이며 서버는 여전히 연결을 올바르게 암호화할 수 있습니다.

출력이 위와 일치하면 구성 파일에 구문 오류가 없습니다. 변경 사항을 구현하기 위해 Nginx를 안전하게 다시 시작할 수 있습니다.

  1. sudo systemctl restart nginx

5단계: 암호화 테스트

이제 SSL 서버를 테스트할 준비가 되었습니다.

웹 브라우저를 열고 주소 표시줄에 https:// 다음에 서버의 도메인 이름 또는 IP를 입력합니다.

https://server_domain_or_IP

우리가 만든 인증서는 브라우저의 신뢰할 수 있는 인증 기관 중 하나에서 서명하지 않았기 때문에 아래와 같은 무섭게 보이는 경고가 표시될 수 있습니다.

이는 정상적인 현상입니다. 우리는 인증서의 암호화 측면에만 관심이 있으며 호스트의 신뢰성에 대한 제3자 검증에는 관심이 없습니다. "고급\을 클릭하면 호스트로 계속 진행할 수 있는 링크가 제공됩니다.

귀하의 사이트로 이동해야 합니다. 브라우저 주소 표시줄을 보면 그 위에 "x\가 있는 자물쇠가 표시됩니다. 이 경우 이는 인증서를 확인할 수 없음을 의미합니다. 여전히 연결을 암호화하고 있습니다.

HTTP 콘텐츠를 HTTPS로 자동 리디렉션하는 두 개의 서버 블록으로 Nginx를 구성한 경우 리디렉션이 올바르게 작동하는지 확인할 수도 있습니다.

http://server_domain_or_IP

동일한 아이콘이 표시되면 리디렉션이 올바르게 작동했음을 의미합니다.

6단계: 영구 리디렉션으로 변경

리디렉션이 올바르게 작동하고 암호화된 트래픽만 허용하려는 것이 확실한 경우 Nginx 구성을 수정하여 리디렉션을 영구적으로 만들어야 합니다.

서버 블록 구성 파일을 다시 엽니다.

  1. sudo nano /etc/nginx/sites-available/default

return 302를 찾아 return 301로 변경합니다.

server {
	listen 80 default_server;
	listen [::]:80 default_server;
	server_name server_domain_or_IP;
	return 301 https://$server_name$request_uri;
}

. . .

파일을 저장하고 닫습니다.

구문 오류에 대한 구성을 확인하십시오.

  1. sudo nginx -t

준비가 되면 Nginx를 다시 시작하여 리디렉션을 영구적으로 만듭니다.

  1. sudo systemctl restart nginx

결론

클라이언트 연결에 강력한 암호화를 사용하도록 Nginx 서버를 구성했습니다. 이렇게 하면 요청을 안전하게 처리할 수 있으며 외부인이 트래픽을 읽을 수 없습니다.