Nginx implements tcp proxy and supports TLS encryption experiment

Nginx source code compilation

Regarding the construction and configuration of nginx, please refer to the author’s previous article: Real-time streaming media server construction test (nginx + rtmp)_How to test online whether the streaming media rtmp is successfully built – the first half of the CSDN blog; the only change is the compilation parameters (Add the stream module and add its corresponding ssl module):

./configure --prefix=/usr/local/nginx --with-http_stub_status_module \
--with-http_ssl_module --with-stream --with-stream_ssl_module \
--with-stream_realip_module --with-openssl=../openssl-1.0.1f --without-http_gzip_module

tcp proxy configuration experiment

Add the configuration of the stream module to the configuration file nginx.conf, as follows:

#lijd add 2023-11-4
stream {
    upstream backend {
        server 192.168.97.50:54321;
}
\t
server {
listen 12345 ssl;
\t\t
proxy_connect_timeout 60s;
        proxy_timeout 60s;
        proxy_pass backend;
    }
}
#lijd add end

Note: The real tcp server is: 192.168.97.50, port: 54321; the nginx proxy server address is: 192.168.97.51, port: 12345. The screenshot of the experimental results is as follows:

When the local client (192.168.80.67) connects to the 12345 port of the proxy server 192.168.97.51, the nginx proxy process will create a TCP connection with the 54321 port of the real backend server (192.168.97.50), as shown below:

The communication between the client and the server is successfully connected and data is sent, as shown in the following figure:

tcp encrypted channel configuration experiment

Generate CA

First, generate a set of your own CA, server certificate, and client certificate through the openssl that comes with the system. The specific commands are as follows:

==============================Generate CA related content============== ==================
# Generate private key for CA
openssl genrsa -out private/ca.prikey 2048

# Generate public key for CA authority
openssl rsa -in ca.prikey -pubout -out ca.pubkey

# Generate a self-signed certificate for the CA
openssl req -new -x509 -days 3650 -key private/ca.prikey -out ca.cert

=========================== Content related to generating server certificate================== ==========
# Generate server private key
openssl genrsa -out server/ser.prikey 2048

# Generate server certificate application file
openssl req -new -key server/ser.prikey -out server/ser.csr

# Generate server certificate signed by CA
openssl x509 -req -days 365 -in server/ser.csr -CA ca.cert -CAkey private/ca.prikey -CAcreateserial -out server/ser.cert

=========================== Contents related to generating client certificates ================= ===========
# Generate client private key
openssl genrsa -out client/cli.prikey 2048

# Generate client certificate application file
openssl req -new -key client/cli.prikey -out client/cli.csr

# Generate a client certificate signed by the CA
openssl x509 -req -days 365 -in client/cli.csr -CA ca.cert -CAkey private/ca.prikey -CAcreateserial -out client/cli.cert

# Generate client integration certificate, including public key and private key, for browser access scenarios
openssl pkcs12 -export -in client/cli.cert -inkey client/cli.prikey -out client/certificate.p12

All certificates generated are as follows:

TLS proxy one-way authentication experiment

The experimental environment is the same as the above tcp proxy configuration experiment. The nginx.conf configuration file adds some basic configurations of SSL, as follows:

#lijd add 2023-11-4
stream {
    upstream backend {
        server 192.168.97.50:54321;
}
\t
server {
listen 12345;
\t\t
proxy_connect_timeout 60s;
        proxy_timeout 60s;
        proxy_pass backend;

        #Set whether the connection between the nginx proxy and the real server is encrypted by SSL protocol
        proxy_ssl off;
\t\t
#Set the SSL protocol version used
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 SSLv2;
        ssl_ciphers AES128-SHA:AES256-SHA:RC4-SHA:DES-CBC3-SHA:RC4-MD5;
\t\t
        # Set the cipher suite used by the server
        ssl_certificate /lijd/CA/server/ser.cert;
        ssl_certificate_key /lijd/CA/server/ser.prikey;
\t\t
        ssl_session_cache shared:SSL:10m; # SSL TCP session cache settings shared memory area named
        
# SSL, zone size is 10MB
        ssl_session_timeout 10m; # SSL TCP session cache timeout is 10 minutes

        # Enable client authentication
#ssl_verify_client on;
#ssl_client_certificate /lijd/CA/ca.cert;
    }
}
#lijd add end

Note: The proxy_ssl parameter switch indicates whether the nginx proxy and the real tcp server in the background require SSL encryption.

Since the experiment requires TCP client channel encryption, it is difficult to find tools that support TCP client TLS encryption, so it is relatively troublesome to use a simple TCP protocol authentication test. The author thought of a way here: Since the http and https protocols are based on the tcp protocol, use the https request feature of the browser to simulate a tcp encrypted client; at this time, the real server in the background uses the IIS that comes with the system. The service (http server) acts as a tcp server. The real server in the background is as follows:

Access the backend server browser page through the tcp service of nginx proxy as follows:

You can see that the browser can access the real backend server through the nginx proxy and receive web page response data. The analysis of the data packets captured by the two links is as follows:

1. The packet capture analysis of the encrypted link between the browser (acting as a TCP client) and the nginx proxy is as follows:

2. The packet capture analysis of the pure TCP link between nginx and the background real server is as follows:

TLS proxy two-way authentication experiment

Two-way authentication requires nginx proxy configuration to enable client authentication. The configuration of nginx.conf releases the following two lines of comments:

ssl_verify_client on;
ssl_client_certificate /lijd/CA/ca.cert;

After restarting the nginx proxy, the page cannot be opened when accessed through the browser, as shown below:

The two-way authentication server needs to authenticate the client’s certificate information. At this time, the browser needs to import the client’s integrated certificate certificate.p12. A password is required when importing. After the import is successful, the following figure is shown:

Access the page again through the browser as shown below:

After clicking Confirm, you successfully access the page. Since the client and nginx directly become two-way authentication, the connection between nginx and the real server is still a pure TCP connection and the situation during one-way authentication is the same. Here is a capture of the data packets between the client and nginx, as shown below:

Conclusion

At this point, the experiment of using nginx proxy TLS encrypted channel has been completed. This chapter mainly discusses the following structure:

Interested students can study that the nginx proxy, client, and server have TLS encrypted channels in both directions. At this time, the proxy_ssl parameter in the nginx configuration needs to be set to on (the default is on, and it was stuck here for a long time during the experiment). At this time, the background TCP server needs to support TLS encryption.