DEV Community

Cover image for Nginx, SSL e mTLS: Um Guia Prático para Criar um Ambiente mais seguro
Jorge Soares
Jorge Soares

Posted on

26

Nginx, SSL e mTLS: Um Guia Prático para Criar um Ambiente mais seguro

Olaaaaaa pessoas, muito boa tarde/manhã/noite, espero que vocês estejam bem.

Trilha sonora enquanto eu escrevia esse artigo:

https://open.spotify.com/intl-pt/track/5dpDnd3Nnw5dRql80RcI7M?si=41eec3a4d5eb45e9


Neste artigo, vamos fornecer um combo de informações. Aprenderemos desde a configuração de um servidor HTTPS usando o Nginx, passando pela criação de um certificado autoassinado e, por fim, configuraremos o mesmo servidor para ser um Mutual TLS ou apenas mTLS.

Nota: Nesta primeira parte, aprenderemos como configurar um ambiente HTTPS usando o Nginx.

Para este tutorial, estou usando o Docker com o Docker Compose para orquestrar nosso ambiente local, facilitando assim o processo de configuração do ambiente. Afinal, em 2023, ninguém mais configura um servidor Nginx diretamente na máquina.

Configurando o ambiente

Começaremos criando nosso diretório de projeto:



mkdir projeto-mtls


Enter fullscreen mode Exit fullscreen mode

Dentro da pasta, criaremos um arquivo docker-compose.yaml e uma pasta nginx que conterá tudo relacionado ao nosso servidor:



cd projeto-mtls
touch docker-compose.yaml # Arquivo do ambiente docker nosso.
mkdir nginx # Pasta que vai guardar tudo relacionado ao nginx
mkdir nginx/certs # Pasta que vai guardar nossos certificados.


Enter fullscreen mode Exit fullscreen mode

Feito isso, agora começaremos a configurar nosso servidor.

Vamos criar um arquivo nginx.conf:



touch nginx.conf


Enter fullscreen mode Exit fullscreen mode

Nele, configuraremos um servidor "simples" que retornará uma página HTML quando acessado em http://localhost:



server {
    listen 80;
    server_name localhost;

    location / {
        default_type text/html;
        return 200 "<!DOCTYPE html><h2>Hello World!</h2>\n";
    }
}


Enter fullscreen mode Exit fullscreen mode

Agora, para testarmos se tudo está funcionando, configuraremos nosso docker-compose.yaml da seguinte forma:



version: "3.8"
services:
  nginx:
    container_name: proxy-mtls
    restart: always
    image: nginx
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf
      - ./nginx/certs:/etc/nginx/certs
    ports:
      - "80:80"
      - "443:443"
    networks:
      - sandbox

networks:
  sandbox:
    driver: bridge


Enter fullscreen mode Exit fullscreen mode

Mapearemos a pasta nginx para dentro do container, para que as configurações e certificados sejam acessíveis no servidor:



docker-compose up # Inicializa os containers do Docker Compose.


Enter fullscreen mode Exit fullscreen mode

Com o servidor ativo, acesse http://localhost:

Página HTML, com o texto

Configurando o SSL

Agora que temos nosso servidor HTTP, precisamos configurar o SSL para começarmos a usar HTTPS nas requisições.

Para isso, precisamos gerar um certificado autoassinado.

Nota: Um certificado digital normalmente requer uma autoridade de certificação (CA) para validar sua autenticidade. No entanto, em casos de desenvolvimento, podemos atuar como a própria CA e assinar nosso próprio certificado, conhecido como "certificado autoassinado". Esse tipo de certificado não é válido em produção, mas é suficiente para ambientes de desenvolvimento.

Gerando a chave privada do certificado

Para gerar nosso certificado, usaremos o utilitário OpenSSL, amplamente utilizado para criptografia e segurança. Utilizaremos o comando a seguir para gerar uma chave privada:



openssl genpkey -algorithm RSA -out certs/localhost.key


Enter fullscreen mode Exit fullscreen mode

Este comando utiliza o algoritmo RSA, amplamente empregado em sistemas de segurança, como SSL/TLS, para criptografar comunicações na web. O resultado será salvo em certs/localhost.key.

Gerando a Solicitação de Assinatura de Certificado (CSR)

Agora, usaremos o OpenSSL para gerar uma Solicitação de Assinatura de Certificado (CSR):



openssl req -new -key certs/localhost.key -out certs/localhost.csr


Enter fullscreen mode Exit fullscreen mode

Essa solicitação contém informações necessárias para emitir nosso certificado. Informamos a chave privada a ser usada (certs/localhost.key) e o arquivo de saída (certs/localhost.csr).

Tela do terminal, com as informações necessárias para gerar um CSR

Ao executar esse comando, você precisará fornecer várias informações sobre a autoridade do certificado e detalhes de contato, que serão enviados à CA para autenticar o certificado da empresa.

Dica bonus sobre geração de CSR

Ver dica

Se você precisa gerar vários certificados ou deseja ter um "modelo" para facilitar a geração de certificados no futuro, pode criar um arquivo de configuração contendo configurações padrão. Isso agilizará o processo de geração de certificados.

Vamos criar um arquivo chamado template.csr.conf para ser nosso modelo:



touch template.csr.conf


Enter fullscreen mode Exit fullscreen mode

Dentro deste arquivo, colocaremos as seguintes informações:



[req]
default_bits = 2048
default_keyfile = localhost.key
distinguished_name = req_distinguished_name
req_extensions = req_ext
x509_extensions = v3_ca
req_extensions = v3_req

[req_distinguished_name]
countryName = Country Name (2 letter code)
countryName_default = BR
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = Sao Paulo
localityName = Locality Name (eg, city)
localityName_default = Sao Paulo
organizationName = Organization Name (eg, company)
organizationName_default = Localhost Ltda
organizationalUnitName = organizationalunit
organizationalUnitName_default = Development
commonName = Common Name (e.g. server FQDN or YOUR name)
commonName_default = localhost
commonName_max = 64

[req_ext]
subjectAltName = @alt_names

[v3_ca]
subjectAltName = @alt_names

[v3_req]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = 127.0.0.1
DNS.2 = localhost


Enter fullscreen mode Exit fullscreen mode

Nota: Eu não vou explicar aqui detalhes sobre esse arquivo, mas um ponto legal é que você pode configurar vários endereços no [alt_names] para que esse certificado suporte vários dominios.

Agora, execute o comando novamente, mas desta vez passando o arquivo de configuração:



openssl req -new -key certs/localhost.key -out certs/localhost.csr -config template.csr.conf


Enter fullscreen mode Exit fullscreen mode

Observe que, mesmo pedindo que você preencha informações, os dados pré-definidos são os que definimos no nosso modelo, economizando tempo durante o processo.

Gerando o Certificado Autoassinado

Após criar a chave privada e a solicitação de assinatura de certificado, chegou a hora de atuar como CA e assinar o certificado. Use o seguinte comando:



openssl x509 -req -days 365 -in certs/localhost.csr -signkey certs/localhost.key -out  certs/localhost.crt


Enter fullscreen mode Exit fullscreen mode

Este comando gera o certificado a partir da solicitação de assinatura de certificado (CSR). O certificado terá validade de 1 ano e será salvo em certs/localhost.crt.

Entenda o comando: x509 é usado para manipular certificados digitais. -req indica que estamos trabalhando com uma solicitação de assinatura de certificado. -days 365 define a validade do certificado em 1 ano. Os próximos três argumentos (-in, -signkey, -out) especificam o caminho da solicitação de assinatura de certificado, da chave privada e do arquivo de saída.

Testando o SSL

Após gerar o certificado, precisamos testá-lo. Para isso, faremos algumas alterações no nosso arquivo nginx.conf para indicar o uso de HTTPS em vez de HTTP:



server {
    listen 80;
    server_name localhost;

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

server {
    listen 443 ssl;
    server_name localhost;

    ssl_certificate /etc/nginx/certs/localhost.crt;
    ssl_certificate_key /etc/nginx/certs/localhost.key;

    location / {
        default_type text/html;
        return 200 "<!DOCTYPE html><h2>Hello World with HTTPS</h2>\n";
    }
}


Enter fullscreen mode Exit fullscreen mode

Agora, qualquer requisição para http://localhost será redirecionada para https://localhost. Observe que estamos usando os atributos ssl_certificate e ssl_certificate_key para apontar o certificado e a chave do nosso servidor.

Salve as alterações e reinicie o servidor:



docker-compose down
docker-compose up


Enter fullscreen mode Exit fullscreen mode

Ao acessar https://localhost, você receberá um aviso do navegador informando que o certificado de autoridade é inválido.

Aviso de SSL inválido no navegador Chrome.

Isso é esperado, uma vez que nós mesmos assinamos o certificado. Para continuar, clique em "Avançado" e depois em "Prosseguir para localhost (não seguro)".

Aviso de SSL inválido

Pronto, agora temos nosso servidor HTTPS funcionando:

Tela do Chrome, escrita Hello World with HTTPS

Até este ponto, já temos um servidor HTTPS funcionando perfeitamente. Agora, vamos para a parte do Mutual TLS ou mTLS.

Fechando as Portas com mTLS

Nota: O mTLS, ou Mutual Transport Layer Security, é uma extensão do protocolo TLS que autentica tanto o cliente quanto o servidor durante a comunicação na internet. Isso é feito por meio da troca de certificados digitais, onde cada parte verifica a identidade da outra. Esse nível adicional de autenticação reforça a segurança da comunicação, especialmente em ambientes sensíveis à segurança, como serviços bancários online e sistemas corporativos, protegendo contra ataques de intermediários mal-intencionados e garantindo uma conexão confiável e criptografada.

Para começar, criaremos um certificado para o cliente, seguindo os mesmos passos que fizemos para criar o certificado do servidor:



mkdir nginx/certs/clients # Vai guardar o certificado do nosso cliente


Enter fullscreen mode Exit fullscreen mode


openssl genpkey -algorithm RSA -out certs/clients/certificado-do-cliente.key
openssl req -new -key certs/clients/certificado-do-cliente.key -out certs/clients/certificado-do-cliente.csr -config template.csr.conf
openssl x509 -req -days 365 -in certs/clients/certificado-do-cliente.csr -signkey certs/clients/certificado-do-cliente.key -out  certs/clients/certificado-do-cliente.crt


Enter fullscreen mode Exit fullscreen mode

Após gerar o certificado do cliente, precisaremos configurar nosso servidor Nginx para trabalhar com mTLS. Para isso, faremos algumas atualizações em nosso arquivo de configuração:




server {
    listen 443 ssl;
    server_name localhost;

    ssl_certificate /etc/nginx/certs/localhost.crt;
    ssl_certificate_key /etc/nginx/certs/localhost.key;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers 'ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384';

    ssl_client_certificate /etc/nginx/certs/clients/certificado-do-cliente.crt;
    ssl_verify_client on;

    location / {
        default_type text/html;
        return 200 "<!DOCTYPE html><h2>Hello World Secury</h2>\n";
    }
}



Enter fullscreen mode Exit fullscreen mode

Agora, adicionamos algumas configurações adicionais ao nosso proxy. ssl_client_certificate especifica o certificado do cliente (que o cliente deve usar ao fazer chamadas para o nosso serviço), e ssl_verify_client ativa a verificação.

Com essa pequena mudança, garantimos que apenas o cliente que possua este certificado conseguirá fazer requisições para nosso ambiente.

Requisições sem o certificado resultarão em um erro:

Requisição no Postman, sem fechar o MTLS, informando que não foi possível finalizar a chamada

Agora, ao passar o certificado na requisição, a chamada será bem-sucedida:

Página html, escrito Hello World with mTLS

Considerações finais

Espero que este artigo seja útil para quem deseja estudar configurações de ambientes e segurança.

Até a próxima.

Se tiver alguma dúvida ou comentário, deixe-os aqui, e vamos compartilhar conhecimento.

AWS Security LIVE!

Tune in for AWS Security LIVE!

Join AWS Security LIVE! for expert insights and actionable tips to protect your organization and keep security teams prepared.

Learn More

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Engage with a sea of insights in this enlightening article, highly esteemed within the encouraging DEV Community. Programmers of every skill level are invited to participate and enrich our shared knowledge.

A simple "thank you" can uplift someone's spirits. Express your appreciation in the comments section!

On DEV, sharing knowledge smooths our journey and strengthens our community bonds. Found this useful? A brief thank you to the author can mean a lot.

Okay