백엔드 서버의 TLSv1.3에서 NGINX 역방향 프록시가 실패함

백엔드 서버의 TLSv1.3에서 NGINX 역방향 프록시가 실패함

저는 최근 모든 내부 서버를 TLSv1.2에서 TLSv1.3으로 전환하고 싶었습니다. 모두 최신 상태로 유지되고 이전 장치를 지원할 필요가 없기 때문입니다.

내 설정은 다음과 같습니다

역방향 프록시의 경우 주소는 192.168.20.2(Debian 11, NGINX v1.21.6)입니다. 이로 인해 공개적으로 유효한 Let Crypto 인증서가 중단되고 계속해서 TLSv1.2 및 TLSv1.3을 사용하여 다양한 클라이언트를 지원하게 됩니다. 요청은 다른 TLS 세션을 통해 server_name을 통해 올바른 백엔드 서버 IP로 전달됩니다.

여러 백엔드 서버가 있지만 단순화를 위해 하나만 설명하겠습니다(모든 구성은 동일함).

백엔드 서버, 주소는 192.168.30.2(Debian 11, NGINX v1.21.6)입니다. 이렇게 하면 웹 서버 인덱스 파일이 제공되는 다른 TLS 세션(자체 서명된 내부 인증서를 사용하여 역방향 프록시에 의해 시작됨)이 종료됩니다.

내 목표는 TLS 세션의 클라이언트와 서버를 모두 제어하므로 모든 백엔드 서버에서 TLSv1.2를 비활성화하여 새로운 TLS 버전과의 호환성을 유지하는 것이 가능합니다.

기본 사이트 구성에서 지적한 ssl-params.conf에 들어가서 TLSv1.2해당 섹션에서 간단히 ssl_protocols삭제했습니다 . nginx를 다시 시작한 후(오류 없이 잘 다시 시작됨) 사이트를 탐색하고 502 Bad Gateway.

문제가 TLS1.2를 제거하는 것일 수도 있다고 생각했지만 역방향 프록시 자체에서 컬을 실행한 후 웹 서버 인덱스 파일을 정상적으로 얻을 수 있었습니다. 그래서 문제는 리버스 프록시 NGINX 서버에 있다고 생각합니다.

여기에 누락된 모호한 TLS NGINX 트랩이 있을 수 있습니다.
온라인에서 아무것도 찾을 수 없으니 누군가 내 문제를 알려줄 수 있을까요?

백엔드 서버에 TLS를 사용하는 이유가 궁금하다면 역방향 프록시와 백엔드 서버 간의 연결이 네트워크의 신뢰할 수 없는 부분에 걸쳐 있으므로 암호화하기 때문입니다.

다음은 특정 백엔드 사이트에 연결하기 위한 모든 관련 구성입니다.

역방향 프록시:

# configuration file /etc/nginx/nginx.conf:
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
        worker_connections 768;
        # multi_accept on;
}
http {
        ##
        # Basic Settings
        ##

        sendfile on;
        tcp_nopush on;
        tcp_nodelay on;
        keepalive_timeout 65;
        types_hash_max_size 2048;
        server_tokens off;

        include /etc/nginx/mime.types;
        default_type application/octet-stream;

        ##
        # Rate Limiting
        ##

        limit_conn_zone $binary_remote_addr zone=limit_conn:1m;
        limit_conn limit_conn 100;
        limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=5r/s;

        ##
        # Gzip Settings
        ##

        gzip on;

        # gzip_vary on;
        # gzip_proxied any;
        # gzip_comp_level 6;
        # gzip_buffers 16 8k;
        # gzip_http_version 1.1;
        # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

        client_max_body_size 10000m;

        ##
        # Virtual Host Configs
        ##

        include /etc/nginx/sites-enabled/*;

        ##
        # Hardening
        ##
 
        add_header Allow "GET, POST, HEAD" always;
}


# configuration file /etc/nginx/snippets/ssl-params.conf:
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:TLS_AES_128_CCM_8_SHA256:TLS_AES_128_CCM_SHA256:ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
resolver 192.168.20.1 valid=300s;
resolver_timeout 5s;

ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

# configuration file /etc/nginx/sites-enabled/wiki.domain.com:
server {
        listen 443 ssl http2;
        ssl_certificate /etc/letsencrypt/live/wiki.domain.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/wiki.domain.com/privkey.pem;
        ssl_stapling on;
        ssl_stapling_verify on;
        ssl_trusted_certificate /etc/letsencrypt/live/wiki.domain.com/chain.pem;
        include snippets/ssl-params.conf;
        server_name wiki.domain.com;
        location / {
                proxy_pass https://192.168.30.2;
                proxy_set_header X-Real-IP $remote_addr;
        }
}

백엔드 서버:

# configuration file /etc/nginx/nginx.conf:
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
        worker_connections 768;
        # multi_accept on;
}

http {

        ##
        # Basic Settings
        ##

        sendfile on;
        tcp_nopush on;
        tcp_nodelay on;
        keepalive_timeout 65;
        types_hash_max_size 2048;

        include /etc/nginx/mime.types;
        default_type application/octet-stream;

        ##
        # Logging Settings
        ##

        access_log off;
        error_log  off;

        ##
        # Gzip Settings
        ##

        gzip on;

        client_body_buffer_size 1K;
        client_header_buffer_size 1k;
        client_max_body_size 10k;
        large_client_header_buffers 2 1k;

        server_tokens off;

        ##
        # Virtual Host Configs
        ##

        include /etc/nginx/sites-enabled/*;
}

# configuration file /etc/nginx/sites-enabled/dokuwiki.conf:
server {
    listen 443 ssl http2;
    include snippets/self-signed.conf;
    include snippets/ssl-params.conf;

    server_name _; 

    root         /var/www;
    index        index.html;
}

# configuration file /etc/nginx/snippets/self-signed.conf:
ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;

# configuration file /etc/nginx/snippets/ssl-params.conf:
ssl_protocols TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_8_SHA256:TLS_AES_128_CCM_SHA256:ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 192.168.30.1 valid=300s;
resolver_timeout 5s;
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header Content-Security-Policy "default-src 'self';";
add_header X-XSS-Protection "1; mode=block";

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

저는 테스트용 백엔드 서버로 기본 index.html을 사용했습니다.

내가 탐색하려고 할 때클라이언트 컴퓨터에서 역방향 프록시로:

user@clientmachine:~$ curl -vvvv https://wiki.domain.com
*   Trying PUBLICIP:443...
* Connected to wiki.domain.com (PUBLICIP) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use h2
* Server certificate:
*  subject: CN=wiki.domain.com
*  start date: May 17 09:56:32 2022 GMT
*  expire date: Aug 15 09:56:31 2022 GMT
*  subjectAltName: host "wiki.domain.com" matched cert's "wiki.domain.com"
*  issuer: C=US; O=Let's Encrypt; CN=R3
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x55619a9a25c0)
> GET / HTTP/2
> Host: wiki.domain.com
> user-agent: curl/7.74.0
> accept: */*
> 
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
< HTTP/2 502 
< server: nginx
< date: Mon, 13 Jun 2022 21:31:20 GMT
< content-type: text/html
< content-length: 150
< allow: GET, POST, HEAD
< 
<html>
<head><title>502 Bad Gateway</title></head>
<body>
<center><h1>502 Bad Gateway</h1></center>
<hr><center>nginx</center>
</body>
</html>
* Connection #0 to host wiki.domain.com left intact

백엔드 서버를 탐색하려고 하면역방향 프록시에서 백엔드로:

user@revproxy:~$ curl -kvvvv https://192.168.30.2/
*   Trying 192.168.30.2:443...
* Connected to 192.168.30.2 (192.168.30.2) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use h2
* Server certificate:
*  subject: C=US; ST=State; L=city; O=; CN=192.168.30.2
*  start date: Dec 10 16:29:30 2021 GMT
*  expire date: Feb 26 16:29:30 2031 GMT
*  issuer: C=US; ST=State; L=city; O=; CN=192.168.30.2
*  SSL certificate verify result: self signed certificate (18), continuing anyway.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x555ab8d305c0)
> GET / HTTP/2
> Host: 192.168.30.2
> user-agent: curl/7.74.0
> accept: */*
> 
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
< HTTP/2 200 
< server: nginx
< date: Mon, 13 Jun 2022 21:33:38 GMT
< content-type: text/html
< content-length: 329
< last-modified: Mon, 13 Jun 2022 21:05:52 GMT
< etag: "62a7a6b0-149"
< strict-transport-security: max-age=63072000; includeSubdomains
< x-frame-options: DENY
< x-content-type-options: nosniff
< content-security-policy: default-src 'self';
< x-xss-protection: 1; mode=block
< accept-ranges: bytes
< 
<!DOCTYPE html>

<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  <title>Spoon-Knife</title>
  <LINK href="styles.css" rel="stylesheet" type="text/css">
</head>

<body>

<!-- Feel free to change this text here -->
<p>
  Fork me? Fork you!
</p>
<p>
  I made a change
</p>

</body>
</html>
* Connection #0 to host 192.168.30.2 left intact

물론 TLSv1.2백엔드 서버의 ssl_protocols 섹션에 있는 ssl-params.conf에 이를 추가하면 갑자기 클라이언트 요청이 통과됩니다(클라이언트는 역방향 프록시에 대한 초기 연결에 여전히 TLSv1.3을 사용합니다).

답변1

여기서 해결책을 찾았습니다. https://forum.nginx.org/read.php?11,294147

분명히 NGINX는 프록시 통과 연결에 사용할 프로토콜을 알려줘야 합니다.

proxy_ssl_protocols TLSv1.3; 역방향 프록시 서버 블록을 사용하면 문제가 해결되었습니다.

관련 정보