<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <docs>https://blogs.law.harvard.edu/tech/rss</docs>
    <title>Automação on FXShell - DevOps &amp; Sec</title>
    <link>https://fxshelll.github.io/tags/automa%C3%A7%C3%A3o/</link>
    <description>Recent content in Automação on FXShell - DevOps &amp; Sec</description>
    <image>
      <title>Automação on FXShell - DevOps &amp; Sec</title>
      <link>https://fxshelll.github.io/tags/automa%C3%A7%C3%A3o/</link>
      <url>fxshell.png</url>
    </image>
    <ttl>1440</ttl>
    <generator>Hugo 0.152.2</generator>
    <language>pt-br</language>
    <lastBuildDate>Sun, 03 May 2026 17:52:44 UT</lastBuildDate>
    <atom:link href="https://fxshelll.github.io/tags/automa%C3%A7%C3%A3o/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Ansible SSL: Certificados Let&#39;s Encrypt Automáticos com AWX</title>
      <link>https://fxshelll.github.io/posts/ansible-ssl-letsencrypt/</link>
      <pubDate>Sun, 03 May 2026 13:00:00 UT</pubDate>
      <dc:creator>Felipe da Matta</dc:creator>
      <guid>https://fxshelll.github.io/posts/ansible-ssl-letsencrypt/</guid>
      <description>Você já acordou às 3 da manhã com o alerta de que um certificado SSL expirou em produção? Ou descobriu que um cliente tentou acessar o site e viu a tela vermelha do browser dizendo &ldquo;conexão não é segura&rdquo;? Esse é o custo de gerenciar SSL na mão.
Neste lab eu automatizei o ciclo completo de criação e renovação de certificados SSL para três sites diferentes — fxshell1.com.br, fxshell2.com.br e fxshell3.com.br — usando Ansible + Certbot + Let&rsquo;s Encrypt. Cada certificado cobre o domínio raiz e o www no mesmo cert (SAN). O AWX agenda a renovação automática toda terça-feira às 03:00 UTC; quando disparado manualmente, um survey pergunta quais tenants renovar antes de executar. Nenhum clique desnecessário, nenhuma surpresa.
</description>
      <content:encoded><![CDATA[Você já acordou às 3 da manhã com o alerta de que um certificado SSL expirou em produção? Ou descobriu que um cliente tentou acessar o site e viu a tela vermelha do browser dizendo &ldquo;conexão não é segura&rdquo;? Esse é o custo de gerenciar SSL na mão.
Neste lab eu automatizei o ciclo completo de criação e renovação de certificados SSL para três sites diferentes — fxshell1.com.br, fxshell2.com.br e fxshell3.com.br — usando Ansible + Certbot + Let&rsquo;s Encrypt. Cada certificado cobre o domínio raiz e o www no mesmo cert (SAN). O AWX agenda a renovação automática toda terça-feira às 03:00 UTC; quando disparado manualmente, um survey pergunta quais tenants renovar antes de executar. Nenhum clique desnecessário, nenhuma surpresa.
Objetivo do Lab Construir uma automação completa que:
Instala e configura o Certbot em múltiplos servidores Emite um único certificado cobrindo dominio.com.br e www.dominio.com.br (SAN — Subject Alternative Names) Configura o Nginx para servir o desafio ACME e depois ativa HTTPS com TLS 1.3 + HSTS Agenda renovação automática no AWX toda terça-feira às 03:00 UTC Quando executado manualmente, pergunta via survey quais tenants renovar Tecnologias Utilizadas Ansible é a ferramenta de automação que conecta via SSH nos servidores e aplica as configurações descritas em playbooks YAML. Sem agente instalado, sem daemon. Um comando no control node e todos os servidores ficam no estado desejado. Usado massivamente em times DevOps para garantir que a infraestrutura seja reproduzível e auditável.
Certbot é o cliente oficial do protocolo ACME, mantido pela Electronic Frontier Foundation. Ele faz a comunicação com a CA do Let&rsquo;s Encrypt: prova que você controla o domínio (através de um arquivo temporário no servidor), recebe o certificado assinado, e salva tudo no /etc/letsencrypt/live/&lt;domínio&gt;/. No lab ele é instalado como snap — a forma recomendada atualmente, que sempre traz a versão mais recente.
Let&rsquo;s Encrypt é uma Autoridade Certificadora (CA) gratuita e automatizada, mantida por Mozilla, Cisco, EFF e outros. Emite certificados X.509 válidos por 90 dias para qualquer domínio que você consiga provar que controla. A curta validade é intencional — força automação e garante que certificados comprometidos expirem rápido.
ACME v2 é o protocolo que Let&rsquo;s Encrypt usa para emissão automatizada. No método webroot, o Certbot cria um arquivo temporário em /.well-known/acme-challenge/ no seu servidor web. A CA do Let&rsquo;s Encrypt faz uma requisição HTTP para esse arquivo e, se conseguir ler, confirma que você controla o domínio e emite o certificado.
Nginx é o servidor web que fica na frente da aplicação. No lab ele tem duas responsabilidades: servir o diretório do desafio ACME durante a validação, e depois servir HTTPS com o certificado emitido. Configuramos TLS 1.2/1.3, HSTS, OCSP Stapling e headers de segurança.
AWX é a versão open source do Ansible Automation Platform (Red Hat Tower). Ele fornece uma interface web e API para executar playbooks Ansible de forma centralizada, com controle de acesso, logs históricos, e — o que mais importa aqui — schedules (cron jobs) para execução automática de jobs.
Arquitetura ┌─────────────────────────────────────────────────────────────┐ │ AWX / Ansible Tower │ │ Job Template: SSL Create Job Template: SSL Renewal │ │ Schedule: RRULE FREQ=DAILY às 03:00 UTC │ └──────────────────────────┬──────────────────────────────────┘ │ Trigger / SSH ▼ ┌─────────────────────────────────────────────────────────────┐ │ Ansible Control Node │ │ playbook-ssl-create.yml │ │ playbook-ssl-renewal.yml │ │ roles/ssl_certbot roles/ssl_renewal │ └────────┬──────────────────┬────────────────────┬────────────┘ │ SSH │ SSH │ SSH ▼ ▼ ▼ ┌──────────────┐ ┌──────────────────┐ ┌──────────────────┐ │ fxshell1.com │ │ fxshell2.com.br │ │ fxshell3.com.br│ │ Nginx + SSL │ │ Nginx + SSL │ │ Nginx + SSL │ │ 192.168.1.10 │ │ 192.168.1.11 │ │ 192.168.1.12 │ └──────┬───────┘ └────────┬─────────┘ └────────┬─────────┘ │ │ │ └───────────────────┴──────────────────────┘ │ ACME HTTP Challenge ▼ ┌────────────────────────┐ │ Let&#39;s Encrypt CA │ │ ACME v2 Protocol │ │ Certificado 90 dias │ └────────────────────────┘ Componente Função AWX Orquestra execução, agenda renovação diária, guarda histórico Ansible Control Node Executa roles, conecta nos servidores via SSH Role ssl_certbot Instala Certbot, configura Nginx HTTP, emite certificado, sobe HTTPS Role ssl_renewal Verifica validade, renova se &lt;30 dias, registra log Nginx Serve ACME challenge, proxy HTTPS com TLS 1.3 + HSTS Let&rsquo;s Encrypt CA Valida domínio via ACME, emite certificado X.509 gratuito Como o Fluxo Funciona O AWX dispara o playbook ssl-create.yml. O Ansible conecta em cada servidor via SSH e executa a role ssl_certbot em sequência:
Instala o Certbot via snap e cria o symlink em /usr/bin/certbot Garante que o Nginx está instalado e rodando Faz o deploy do template nginx-http.conf.j2 — configuração HTTP simples que serve o diretório .well-known/acme-challenge/ e redireciona todo o resto para HTTPS Verifica se o certificado já existe em /etc/letsencrypt/live/&lt;domínio&gt;/ Se não existir, executa certbot certonly --webroot — o Certbot cria o arquivo de desafio, a CA do Let&rsquo;s Encrypt faz o GET HTTP para validar, e o certificado é emitido Faz o deploy do template nginx-ssl.conf.j2 — configuração HTTPS completa com TLS 1.2/1.3, HSTS, OCSP Stapling e security headers Verifica a data de expiração do certificado emitido com openssl x509 -enddate Para renovação, o job ssl-renewal.yml roda diariamente. Para cada servidor, ele lê a data de expiração do certificado atual, calcula os dias restantes, e só executa certbot renew se faltarem menos de 30 dias. Se renovou, notifica o handler para recarregar o Nginx.
Estrutura do Projeto ansible-ssl-letsencrypt/ ├── ansible.cfg # Config: inventory, become, pipelining ├── playbook-ssl-create.yml # Playbook principal: emite certificados ├── playbook-ssl-renewal.yml # Playbook de renovação: usado pelo AWX ├── awx-job-template.yml # Definição dos Job Templates e Schedule ├── inventory/ │ └── hosts.yml # 3 hosts com site_domain, email, webroot ├── group_vars/ │ └── all.yml # Certbot config, Nginx SSL params globais ├── roles/ │ ├── ssl_certbot/ │ │ ├── tasks/main.yml # Instala, configura Nginx, emite cert │ │ ├── handlers/main.yml # restart/reload nginx │ │ └── templates/ │ │ ├── nginx-http.conf.j2 # Config HTTP + ACME challenge │ │ └── nginx-ssl.conf.j2 # Config HTTPS + TLS 1.3 + HSTS │ └── ssl_renewal/ │ ├── tasks/main.yml # Verifica validade, renova, loga │ ├── handlers/main.yml # reload nginx após renovação │ └── templates/ │ └── renewal-report.j2 # Relatório de renovação └── diagrama/ ├── ansible-ssl-letsencrypt.html # Diagrama animado interativo ├── ansible-ssl-letsencrypt.gif # GIF para blog e LinkedIn └── gerar_gif.py # Script Pillow que gerou o GIF Inventário — Os 3 Sites O inventário define os três servidores. Cada host tem site_domain (nome principal, usado como --cert-name pelo Certbot) e site_domains (lista com raiz e www, usada tanto no certbot certonly quanto nos server_name do Nginx).
# inventory/hosts.yml all: children: webservers: hosts: fxshell1_server: ansible_host: 192.168.1.10 ansible_user: ubuntu site_domain: fxshell1.com.br # cert-name no Certbot site_domains: # SAN: raiz + www no mesmo cert - fxshell1.com.br - www.fxshell1.com.br site_email: admin@fxshell1.com.br site_webroot: /var/www/fxshell nginx_config_name: fxshell1.com.br fxshell2_server: ansible_host: 192.168.1.11 ansible_user: ubuntu site_domain: fxshell2.com.br site_domains: - fxshell2.com.br - www.fxshell2.com.br site_email: admin@fxshell2.com.br site_webroot: /var/www/fxshell2 nginx_config_name: fxshell2.com.br fxshell3_server: ansible_host: 192.168.1.12 ansible_user: ubuntu site_domain: fxshell3.com.br site_domains: - fxshell3.com.br - www.fxshell3.com.br site_email: admin@fxshell3.com.br site_webroot: /var/www/fxshell3 nginx_config_name: fxshell3.com.br O Certbot aceita múltiplos --domain num único comando. O primeiro domínio da lista vira o nome do certificado (/etc/letsencrypt/live/fxshell1.com.br/), e os demais entram como SANs. O resultado é um único arquivo .pem válido para fxshell1.com.br e www.fxshell1.com.br — sem precisar de dois certificados separados.
Role ssl_certbot — O Coração da Emissão A task mais importante da role verifica se o certificado já existe antes de tentar emitir. Isso garante idempotência — você pode rodar o playbook quantas vezes quiser sem gerar requisições desnecessárias para a CA (o Let&rsquo;s Encrypt tem rate limits).
O comando usa um loop Jinja2 para gerar múltiplos --domain, cobrindo dominio.com.br e www.dominio.com.br num único certificado SAN:
# roles/ssl_certbot/tasks/main.yml (trecho) - name: Verificar se certificado já existe stat: path: &#34;{{ certbot_certs_dir }}/{{ site_domain }}/fullchain.pem&#34; register: cert_exists - name: Obter certificado SSL via certbot (webroot — raiz + www) command: &gt; certbot certonly --webroot --webroot-path {{ site_webroot }} {% for d in site_domains %}--domain {{ d }} {% endfor %} --email {{ site_email }} --agree-tos --non-interactive {% if certbot_staging %}--staging{% endif %} --rsa-key-size {{ certbot_rsa_key_size }} --keep-until-expiring when: not cert_exists.stat.exists Para fxshell1_server, o comando expandido fica:
certbot certonly --webroot --webroot-path /var/www/fxshell \ --domain fxshell1.com.br --domain www.fxshell1.com.br \ --email admin@fxshell1.com.br --agree-tos --non-interactive \ --rsa-key-size 4096 --keep-until-expiring O flag --keep-until-expiring garante que, mesmo se o certificado já existir, o Certbot não vai renovar antes de 30 dias. O flag --staging permite testar o fluxo completo sem consumir os rate limits de produção do Let&rsquo;s Encrypt.
Template Nginx HTTPS O template nginx-ssl.conf.j2 gera uma config com as melhores práticas de TLS:
server { listen 443 ssl http2; server_name {{ site_domain }} www.{{ site_domain }}; ssl_certificate {{ certbot_certs_dir }}/{{ site_domain }}/fullchain.pem; ssl_certificate_key {{ certbot_certs_dir }}/{{ site_domain }}/privkey.pem; ssl_trusted_certificate {{ certbot_certs_dir }}/{{ site_domain }}/chain.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:...; ssl_prefer_server_ciphers off; ssl_session_cache shared:SSL:50m; ssl_stapling on; ssl_stapling_verify on; # HSTS: força HTTPS por 1 ano em todos os subdomínios add_header Strict-Transport-Security &#34;max-age=31536000; includeSubDomains; preload&#34; always; add_header X-Frame-Options DENY; add_header X-Content-Type-Options nosniff; } O OCSP Stapling (ssl_stapling on) reduz a latência das conexões: em vez de o browser consultar a CA para verificar se o certificado foi revogado, o servidor já faz essa consulta periodicamente e inclui a resposta assinada no handshake TLS.
Role ssl_renewal — Lógica de Renovação A task de renovação calcula os dias restantes com openssl e date, e só chama o certbot renew se a condição for verdadeira:
- name: Calcular dias restantes shell: | end_date=&#34;{{ cert_end_date.stdout }}&#34; today=$(date +%s) expiry=$(date -d &#34;$end_date&#34; +%s) echo $(( (expiry - today) / 86400 )) register: days_remaining - name: Renovar certificado se faltam menos de 30 dias command: &gt; certbot renew --cert-name {{ site_domain }} --non-interactive --quiet when: days_remaining.stdout | int &lt; 30 notify: reload nginx Cada execução registra uma linha em /var/log/certbot-renewal.log com data, domínio, dias restantes e se foi renovado.
AWX — Job Templates e Schedule A configuração do AWX está documentada no arquivo awx-job-template.yml. Os dois jobs principais são:
SSL - Criar Certificado: roda sob demanda com survey para o operador escolher domínio e ambiente (staging/produção).
SSL - Renovar Certificados: tem dois modos de uso:
Schedule automático — toda terça-feira às 03:00 UTC, renova todos os hosts do grupo webservers Execução manual com survey — antes de executar, o AWX exibe um formulário para o operador selecionar quais tenants renovar O survey de seleção de tenants funciona assim: o campo tenants aceita o nome de um ou mais hosts separados por vírgula (ex: fxshell1_server,fxshell2_server) ou o grupo webservers para renovar todos. Esse valor é passado para a diretiva hosts: do playbook, que funciona como um --limit dinâmico.
# O playbook usa o valor do survey como filtro de hosts - name: Renovar certificados SSL Let&#39;s Encrypt hosts: &#34;{{ tenants | default(&#39;webservers&#39;) }}&#34; O schedule usa a sintaxe RFC 5545 (iCalendar RRULE), que é o formato que o AWX aceita:
DTSTART:20240102T030000Z RRULE:FREQ=WEEKLY;BYDAY=TU # BYDAY=TU = Tuesday (terça-feira) # FREQ=WEEKLY = toda semana # Hora: 03:00 UTC Para configurar manualmente na interface do AWX:
Projects → Criar projeto apontando para o repositório git Inventories → Importar hosts.yml com os 3 servidores Credentials → Adicionar chave SSH dos servidores Job Templates → SSL - Criar Certificado (playbook-ssl-create.yml) Job Templates → SSL - Renovar (playbook-ssl-renewal.yml) → Habilitar Survey com campo &#34;tenants&#34; → Habilitar ask_limit_on_launch: true Schedules → Adicionar no job de renovação: → Recurrence: Weekly, Day: Tuesday, Time: 03:00 UTC → Default tenants: webservers (todos) Executando # 1. Testar conectividade com todos os servidores ansible all -m ping # 2. Testar com staging primeiro (não gasta rate limit) ansible-playbook playbook-ssl-create.yml -e &#34;certbot_staging=true&#34; # 3. Verificar o que seria feito (dry-run parcial) ansible-playbook playbook-ssl-create.yml --check # 4. Emitir certificados reais para todos os sites ansible-playbook playbook-ssl-create.yml # 5. Emitir só para um site específico ansible-playbook playbook-ssl-create.yml -l fxshell1_server # 6. Forçar renovação manualmente ansible-playbook playbook-ssl-renewal.yml -e &#34;force_renewal=true&#34; # 7. Testar HTTPS após emissão curl -I https://fxshell1.com.br curl -I https://fxshell2.com.br curl -I https://fxshell3.com.br Para verificar os headers de segurança:
curl -sI https://fxshell1.com.br | grep -E &#34;Strict-Transport|X-Frame|X-Content&#34; Monitoramento e Troubleshooting Sintoma Causa provável Solução certbot: command not found Snap não instalou ou symlink faltando Verificar snap list certbot e recriar symlink Challenge failed: connection refused Nginx não está rodando ou porta 80 bloqueada systemctl status nginx e verificar firewall Too many certificates already issued Rate limit do Let&rsquo;s Encrypt atingido Usar --staging para testes; aguardar 7 dias nginx: configuration file test failed Caminho do certificado errado no template Verificar se /etc/letsencrypt/live/&lt;domínio&gt;/ existe SSL certificate has expired Renovação automática falhou Verificar /var/log/certbot-renewal.log e /var/log/letsencrypt/ AWX job falha com Permission denied Usuário SSH sem sudo configurado Verificar become: true e sudoers no servidor # Verificar logs do certbot cat /var/log/letsencrypt/letsencrypt.log | tail -50 # Verificar log de renovação customizado cat /var/log/certbot-renewal.log # Testar validade do certificado manualmente openssl s_client -connect fxshell1.com.br:443 -servername fxshell1.com.br &lt; /dev/null 2&gt;/dev/null \ | openssl x509 -noout -enddate Para Que Serve no Mercado Times DevOps e SRE que gerenciam dezenas ou centenas de domínios usam exatamente esse padrão. As variações incluem:
Wildcard certificates com validação DNS ao invés de HTTP (necessário quando os servidores não têm porta 80 pública) Integração com Vault para armazenar as credenciais dos provedores DNS e automatizar renovação de wildcards Pipeline de CI/CD que dispara o playbook quando um novo site é adicionado ao inventário Certificados internos usando a mesma lógica com uma CA própria (CFSSL, Vault PKI) para serviços internos que não precisam de CA pública O princípio é o mesmo em qualquer escala: infraestrutura declarativa, idempotente, auditável. Um certificado expirado em produção é a prova de que existe um processo manual em algum lugar esperando para falhar.
Conclusão O que resolve esse lab não é só a automação do certbot — é a combinação de idempotência do Ansible com a orquestração do AWX. Você pode executar esse playbook mil vezes e o resultado é sempre o mesmo: se o certificado existe e está válido, nada muda. Se está para expirar, é renovado. Se não existe, é criado. Esse nível de previsibilidade é o que separa infraestrutura mantida de infraestrutura gerenciada.
Referências Certbot Documentation Let&rsquo;s Encrypt — Rate Limits ACME Protocol RFC 8555 Nginx SSL Configuration AWX Project Ansible Documentation Mozilla SSL Configuration Generator ]]></content:encoded>
    </item>
  </channel>
</rss>
