バックエンドサーバーの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に転送されます。

複数のバックエンドサーバーがありますが、単純化のために1つだけ説明します(すべての構成は同じです)。

バックエンドサーバーのアドレスは192.168.30.2(Debian 11、NGINX v1.21.6)です。これにより、Webサーバーのインデックスファイルが提供される別のTLSセッション(自己署名付き内部証明書を使用してリバースプロキシによって開始されます)が終了します。

私の目標はTLSセッションのクライアントとサーバーの両方を制御するので、すべてのバックエンドサーバーでTLSv1.2を無効にして、新しいTLSバージョンとの互換性を維持することができます。

デフォルトのサイト設定で指摘したssl-params.confに入り、そのTLSv1.2セクションから簡単にssl_protocols削除しました。 nginxを再起動した後(エラーなしでうまく再起動した)サイトを閲覧してください502 Bad Gateway

私は問題がTLS1.2を削除するかもしれないと思いましたが、リバースプロキシ自体でカールを実行した後、Webサーバーのインデックスファイルを正常に取得できました。だから問題はリバースプロキシ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; リバースプロキシサーバーブロックを使用して問題を解決しました。

関連情報