Proxy Nginx para back-end com autenticação de certificado de cliente SSL

14

Eu tenho dois servidores, ambos têm nginx. O servidor A está escutando 443 e está configurado para se autenticar com um certificado SSL do cliente.

O servidor B possui um processo interno que precisa se comunicar com o servidor A através do nginx.

Gostaria de configurar o Nginx no servidor B que ouvirá 8080 (sem criptografia, pois é toda a comunicação local) e proxy_pass para o ServerA: 443.

A questão é como injetar um certificado de cliente? Não encontrei nenhuma função proxy_xxxx que fizesse isso.

Eu sei como fazer um equivalente a isso com o socat, mas meu requisito é usar o nginx.

Bastien974
fonte
2
Observando as diretivas no módulo proxy do nginx, parece que não é possível fazer um servidor nginx usar um certificado para autenticar: nginx.org/en/docs/http/ngx_http_proxy_module.html O Apache suporta esse recurso.
NuTTyX
Era disso que eu tinha medo ... alguma idéia se existe um módulo personalizado ou algo que possa fazer isso funcionar? Esse tipo de recurso precisa existir!
precisa saber é o seguinte
Encontrei um utilitário para migrar arquivos de configuração do apache para o nginx ( github.com/nhnc-nginx/apache2nginx ), então baixei-o, criei um apache.conf fictício e passe-o pela ferramenta, mas obtive esse resultado :### Section 2: Unconverted directives ### # Flag Description # [S] Unsupported directives. # In conf file: dummy.conf # Line 32: SSLProxyMachineCertificateFile /path/to/cert (mod_ssl.c) # [S] SSLProxyMachineCertificateFile: No relevant directive in Nginx.
NuTTyX

Respostas:

21

É suficiente passar os detalhes do certificado do cliente?

Você pode adicionar

proxy_set_header X-SSL-CERT $ssl_client_escaped_cert;

à sua configuração e as informações do certificado estão disponíveis para o servidor B por meio de um cabeçalho X-SSL-Cert.

jwilkins
fonte
1
Como comentado aqui , estar ciente se o seu back-end pode substituir \tcom \na partir deste cabeçalho uma vez readed.
lucasvc
3
De acordo com a documentação do nginx , a $ssl_client_certvariável está obsoleta; a $ssl_client_escaped_certvariável deve ser usada em seu lugar.
Dubek
1
@dubek boa captura, eu atualizaria a resposta diretamente em casos como este.
Chris Stryczynski
Eu tenho tentado esta solução, mas apenas parece estar passando o certificado se a validação do certificado estiver ativada. Não quero ativá-lo. Existe uma maneira de fazê-lo funcionar sem ativar a validação?
juhako
5

Aparentemente, é isso que você está procurando: http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_ssl_certificate Disponível desde a versão 1.7.8.

location / {
    ...
    proxy_pass     the_other_nginx;
    proxy_ssl_certificate  the_certificate.pem;
    ...
}
Nicolas Malbran
fonte
1
Isto está errado. Isso atribui um certificado de cliente ao proxy a ser usado para as solicitações ao back-end. Mas o perguntou, disse que esta comunicação não é criptografada apenas como local, portanto não há verificação de certificado de cliente. A resposta de jwilkins funciona bem.
Kenyakorn Ketsombut 10/09
@KenyakornKetsombut Eu acredito que você interpretou mal a pergunta. O servidor B não possui criptografia (escutando 8080), mas precisa se comunicar com o servidor A (escutando 443, com criptografia). Então, B precisa enviar o certificado do cliente para A para se autenticar. Você pode usar proxy_ssl_certificate para fazer isso. jwilkins responder, encaminhará para A o certificado dado a B. Ambos podem funcionar dependendo do que você precisa.
Nicolas Malbran
Oi Nicolas. Eu estava tentando dizer: se o Servidor B não estiver usando criptografia (na porta 8080), ele não usará nada como HTTPS / SSL ou como você chamar. Os certificados de cliente fazem parte do SSL, portanto, essa parte não pode ser feita pelo Servidor B. B não pode enviar ou receber nenhum certificado de cliente.
Kenyakorn Ketsombut
1
Eu recebo o nginx: [emerg] nenhum "proxy_ssl_certificate_key" está definido para o certificado "certs / Roro_Client.pem" nginx: o arquivo de configuração /etc/nginx/nginx.conf falhou ao tentar isso com 1.8.0
Wolfgang Fahl
4

A questão parece ser amplamente dependente da versão. No Ubuntu 14.04 LTS, o nginx padrão é um 1.4 desatualizado. Primeiro você precisa instalar uma versão baseada em PPA

https://leftshift.io/upgrading-nginx-to-the-latest-version-on-ubuntu-servers

mostra como fazer isso com:

sudo add-apt-repository ppa:nginx/stable
sudo aptitude safe-upgrade

você deve terminar com:

nginx -v
nginx version: nginx/1.8.0

A configuração da resposta @ xatr0z https://serverfault.com/a/636455/162693 apontando para http://www.senginx.org/en/index.php/Proxy_HTTPS_Client_Certificate não funciona:

proposta não útil

backend {
    server some-ip:443;
}

server {
    listen 80;


    location / {
        proxy_ssl_certificate        certs/client.crt;
        proxy_ssl_certificate_key    certs/client.key;


        proxy_pass https://backend;
    }
}

não funciona imediatamente com 1.8.0. Provavelmente é apenas uma sugestão e não deve ser usado como um arquivo de configuração como tal ou depende de outra versão.

Estou testando com um servidor back-end A baseado em apache2 com SSL e certificados de cliente autoassinado ativados. As SSLOptions de configuração do Apache estão definidas para:

SSLOptions +ExportCertData +FakeBasicAuth + StdEnvVars

Isso facilita a depuração da situação, pois um script phpinfo () no lado de back-end mostra as informações do lado do servidor e do cliente.

Para verificar isso, usei:

https: // back-end / test / phpinfo

com o certificado SSL instalado no navegador e recebo seções como: SSL_SERVER_S_DN_CN para o certificado do servidor e SSL_CLIENT_S_DN_CN para o certificado do cliente.

Como primeira inicialização, usei (preencha as partes entre colchetes) para configurar o nginx no servidor front-end B:

server {
  listen 8080;
  server_name <frontend>;

  location / {
    proxy_buffering off;
    proxy_pass https://<backend>;
    #proxy_ssl_certificate      certs/<SSL Client Certificate>.crt;
    #proxy_ssl_certificate_key  certs/<SSL Client Certificate>.key;
  }
}

desassociando a parte específica do Certificado de Cliente SSL apenas para verificar se o próprio proxy reverso funciona.

nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
service nginx restart
nginx stop/waiting
nginx start/running, process 8931

Agora, o http: // frontend: 8080 / test / phpinfo.php funciona

SSL_SERVER_S_DN_CN para o certificado do servidor é exibido e SSL_CLIENT_S_DN_CN para o certificado do cliente (ainda) não é exibido

Agora, depois de descomentar:

server {
  listen 8080;
  server_name <frontend>;

  location / {
    proxy_buffering off;
    proxy_pass https://<backend>;
    proxy_ssl_certificate      certs/<SSL Client Certificate>.crt;
    proxy_ssl_certificate_key  certs/<SSL Client Certificate>.key;
  }
}

e verificando / reiniciando

nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
service nginx restart
nginx stop/waiting
nginx start/running, process 8931

http: // frontend: 8080 / test / phpinfo.php funciona e

SSL_SERVER_S_DN_CN para o certificado do servidor é exibido e SSL_CLIENT_S_DN_CN para o certificado do cliente é exibido

então agora temos as coisas funcionando conforme solicitado.

Observe o bug https://trac.nginx.org/nginx/ticket/872#ticket

Wolfgang Fahl
fonte
Você pode querer atente para a questão renegociação ruby-forum.com/topic/6875137 que poderia estragar o show
Wolfgang Fahl
1

Há um artigo bastante interessante sobre os certificados de cliente nginx e SSL; ele usa PHP com FastCGI como exemplo, mas acho que você pode adaptar isso a uma configuração de proxy reverso:

server {
    listen        443;
    ssl on;
    server_name example.com;

    ssl_certificate      /etc/nginx/certs/server.crt;
    ssl_certificate_key  /etc/nginx/certs/server.key;
    ssl_client_certificate /etc/nginx/certs/ca.crt;
    ssl_verify_client optional;

    location / {
        root           /var/www/example.com/html;
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_param  SCRIPT_FILENAME /var/www/example.com/lib/Request.class.php;
        fastcgi_param  VERIFIED $ssl_client_verify;
        fastcgi_param  DN $ssl_client_s_dn;
        include        fastcgi_params;
    }
}

Fonte http://nategood.com/client-side-certificate-authentication-in-ngi

Erik Kaplun
fonte