Глобальная переменная в NGINX

#nginx #nginx-reverse-proxy

Вопрос:

Я использую NGINX для обслуживания статических файлов, обратного прокси-сервера в Django и проверки сертификатов клиентов.

Я не хочу, чтобы сертификат запрашивался в корневом каталоге URL, поэтому я создал другой сервер на Nginx.conf, чтобы запросить сертификат на порту 8443. Этот сервер предназначен только для того, чтобы запросить сертификат и перенаправить клиента обратно на порт 443, где происходит обратный прокси-сервер в Django.

Это мой Nginx.conf:

 
events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    sendfile        on;

    keepalive_timeout  65;

    gzip  on; 

    upstream app {
        server django:8000;
    }

    # Redirect from HTTP to HTTPS
    server {
        listen *:80;
        server_name localhost;
        return 301 https://localhost$request_uri;
    }

    server {
        
        listen *:443 ssl;
        server_name localhost;

        ssl_certificate      /etc/nginx/ssl/certificate.pem;
        ssl_certificate_key  /etc/nginx/ssl/certificate.key;
        ssl_password_file    /etc/nginx/ssl/certificate.pass;

        ssl_verify_client off;
        ssl_client_certificate /etc/nginx/ssl/chain.cer;
        ssl_verify_depth 3;

        ssl_protocols TLSv1.1 TLSv1.2;
        ssl_ciphers EECDH AESGCM:EDH AESGCM:AES256 EECDH:AES256 EDH;                
        ssl_prefer_server_ciphers  on;

        server_tokens off;
        underscores_in_headers on;

        location /static/ {
            autoindex off;
            alias /static_files/;
        }

        location / {
            try_files $uri $uri/ @app_web;
        }

        location @app_web {
            proxy_pass http://app;
            proxy_pass_request_headers on;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $http_host;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_set_header CERTINFO $http_certinfo;
            proxy_redirect off;
        }
    }

    server {
        
        listen *:8443 ssl;
        server_name localhost;

        ssl_certificate      /etc/nginx/ssl/certificate.pem;
        ssl_certificate_key  /etc/nginx/ssl/certificate.key;
        ssl_password_file    /etc/nginx/ssl/certificate.pass;

        ssl_verify_client on;
        ssl_client_certificate /etc/nginx/ssl/certificate.cer
        ssl_verify_depth 3;

        ssl_protocols TLSv1.1 TLSv1.2;
        ssl_ciphers EECDH AESGCM:EDH AESGCM:AES256 EECDH:AES256 EDH;                
        ssl_prefer_server_ciphers  on;

        add_header CERTINFO $ssl_client_s_dn;

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

Когда клиент аутентифицируется на порту 8443, и я возвращаю его на порт 443, мне нужно переслать информацию о его сертификате, $ssl_client_s_dn, чтобы быть более конкретным. Для этого я пытаюсь использовать метод add_header на сервере порта 8443 (CERTINFO) и метод proxy_set_header, фиксирующий значение с помощью $http_certinfo на сервере порта 443. Но это решение не работает. Заголовок не пересылается с порта 8443 на сервер порта 443.

Мой вопрос в следующем: есть ли способ сделать это? Могу ли я установить какую-то «глобальную» переменную в блоке http, изменить ее значение на порту 8443 и использовать обновленное значение на порту 443 для пересылки в Django?

Большое вам спасибо!

Комментарии:

1. Нет. add_header добавляет заголовок ответа и $http_certinfo является заголовком запроса. Вы не можете заставить браузер добавить другой заголовок запроса, кроме, возможно, файла cookie.

2. Рикардо, но есть ли способ сохранить эту информацию не в заголовке запроса, а в какой-то переменной и поделиться ею с другим сервером? Спасибо за ответ.

3. Вместо return 301 этого вы должны дублировать location блоки из первого server блока, чтобы этот server блок мог передавать учетные данные непосредственно в приложение.

4. Твое решение работает просто отлично, Ричард. Я передал учетные данные непосредственно в приложение и перенаправил клиента обратно на порт 443 через приложение. Спасибо вам за вашу помощь.