<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Filipi Souza</title>
    <description>The latest articles on DEV Community by Filipi Souza (@filipi_souza_9aefcab771a7).</description>
    <link>https://dev.to/filipi_souza_9aefcab771a7</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3409640%2Fabd6ea44-6deb-4aa6-b2e1-0023ad59a797.jpg</url>
      <title>DEV Community: Filipi Souza</title>
      <link>https://dev.to/filipi_souza_9aefcab771a7</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/filipi_souza_9aefcab771a7"/>
    <language>en</language>
    <item>
      <title>🧭 Runbook: Como Rodar um Playbook Ansible com Pipeline CI/CD e SSH via Bastion</title>
      <dc:creator>Filipi Souza</dc:creator>
      <pubDate>Fri, 10 Oct 2025 17:38:50 +0000</pubDate>
      <link>https://dev.to/filipi_souza_9aefcab771a7/runbook-como-rodar-um-playbook-ansible-com-pipeline-cicd-e-ssh-via-bastion-9fn</link>
      <guid>https://dev.to/filipi_souza_9aefcab771a7/runbook-como-rodar-um-playbook-ansible-com-pipeline-cicd-e-ssh-via-bastion-9fn</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“Como automatizei execuções seguras do Ansible via bastion e pipeline CI/CD, com validação de hostnames e conexões persistentes.”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  📘 Objetivo
&lt;/h2&gt;

&lt;p&gt;Este runbook documenta o processo de &lt;strong&gt;execução controlada de playbooks Ansible&lt;/strong&gt; — tanto &lt;strong&gt;localmente&lt;/strong&gt; via Docker quanto &lt;strong&gt;automatizada&lt;/strong&gt; através de uma &lt;strong&gt;pipeline CI/CD&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;O caso de uso principal é o &lt;strong&gt;playbook de verificação de atualizações de segurança&lt;/strong&gt; em servidores Linux baseados em Debian/Ubuntu, para casos onde é preciso desativar o &lt;strong&gt;unattended-upgrades&lt;/strong&gt; por qualquer motivo que seja e assim receber apenas uma notificação que há atualizações para executar de forma planejada.&lt;br&gt;&lt;br&gt;
O playbook foi criado de forma &lt;strong&gt;idempotente&lt;/strong&gt; — ou seja, pode ser executado repetidamente sem causar efeitos colaterais — e utiliza &lt;strong&gt;conexão segura via bastion (JumpServer)&lt;/strong&gt;, com autenticação baseada em chaves SSH armazenadas de forma segura.&lt;/p&gt;


&lt;h2&gt;
  
  
  ⚙️ Arquitetura e Fluxo Geral
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CI/CD Agent / Local Host
      │
      │ (SSH via chave segura)
      ▼
Bastion Host (JumpServer)
      │
      │ (ProxyCommand)
      ▼
Instâncias Linux (AWS / Cloud Provider)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;A pipeline ou execução local inicia a verificação.
&lt;/li&gt;
&lt;li&gt;A chave SSH segura é baixada de um &lt;strong&gt;Key Vault&lt;/strong&gt; ou &lt;strong&gt;Secure Files&lt;/strong&gt; da ferramenta de CI/CD.
&lt;/li&gt;
&lt;li&gt;Um container Docker (com Ansible e dependências pré-instaladas) é iniciado.
&lt;/li&gt;
&lt;li&gt;O Ansible conecta-se ao bastion, que faz o proxy das conexões até os hosts alvo.
&lt;/li&gt;
&lt;li&gt;O playbook instala/atualiza o script remoto &lt;code&gt;/usr/local/bin/check-security-updates.sh&lt;/code&gt;, cria um cron diário e envia notificações para um canal de monitoramento (ex.: Discord, Slack, etc.) quando há atualizações de segurança disponíveis.&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;
  
  
  ✅ Pré-Requisitos
&lt;/h2&gt;
&lt;h3&gt;
  
  
  🔑 Acesso e Chaves SSH
&lt;/h3&gt;

&lt;p&gt;As chaves SSH utilizadas devem ser gerenciadas de forma segura.&lt;/p&gt;

&lt;p&gt;A chave pública correspondente deve estar presente no arquivo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~/.ssh/authorized_keys
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nos seguintes sistemas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bastion host (JumpServer)&lt;/li&gt;
&lt;li&gt;Servidores-alvo (instâncias Linux)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  💻 Dependências Locais
&lt;/h2&gt;

&lt;p&gt;Para execução manual/local:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Docker&lt;/strong&gt; instalado e configurado
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CLI da nuvem&lt;/strong&gt; (ex.: Azure CLI / AWS CLI) para acesso a segredos e login no registro de contêineres
&lt;/li&gt;
&lt;li&gt;Acesso de rede até o bastion (porta 22 liberada)
&lt;/li&gt;
&lt;li&gt;Uma imagem &lt;strong&gt;toolbox&lt;/strong&gt; disponível localmente, contendo:

&lt;ul&gt;
&lt;li&gt;Ansible&lt;/li&gt;
&lt;li&gt;OpenSSH Client&lt;/li&gt;
&lt;li&gt;Curl&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  ☁️ Acesso Cloud
&lt;/h3&gt;

&lt;p&gt;Antes de executar o playbook:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Verifique se o bastion está operacional e com rota válida até as instâncias-alvo.
&lt;/li&gt;
&lt;li&gt;Confirme se o inventário Ansible reflete corretamente os grupos e IPs dos servidores.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Teste rápido de acesso manual:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-i&lt;/span&gt; cicd-ansible-key.pem &lt;span class="nt"&gt;-J&lt;/span&gt; ubuntu@&amp;lt;bastion-host&amp;gt; ubuntu@&amp;lt;target-host&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📋 Inventário e Configurações
&lt;/h2&gt;

&lt;p&gt;Exemplo de inventário (&lt;code&gt;ansible/inventory/servers.ini&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[development]&lt;/span&gt;
&lt;span class="err"&gt;10.0.1.10&lt;/span&gt;
&lt;span class="err"&gt;10.0.2.15&lt;/span&gt;
&lt;span class="err"&gt;10.0.3.20&lt;/span&gt;

&lt;span class="nn"&gt;[development:vars]&lt;/span&gt;
&lt;span class="py"&gt;ansible_user&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;ubuntu&lt;/span&gt;
&lt;span class="py"&gt;ansible_ssh_private_key_file&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/workspace/ssh_key.pem&lt;/span&gt;
&lt;span class="py"&gt;ansible_ssh_common_args&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
  &lt;span class="err"&gt;-o&lt;/span&gt; &lt;span class="py"&gt;StrictHostKeyChecking&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;no&lt;/span&gt;
  &lt;span class="err"&gt;-o&lt;/span&gt; &lt;span class="py"&gt;UserKnownHostsFile&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/dev/null&lt;/span&gt;
  &lt;span class="err"&gt;-o&lt;/span&gt; &lt;span class="py"&gt;ConnectTimeout&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;20&lt;/span&gt;
  &lt;span class="err"&gt;-o&lt;/span&gt; &lt;span class="py"&gt;ServerAliveInterval&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;30&lt;/span&gt;
  &lt;span class="err"&gt;-o&lt;/span&gt; &lt;span class="py"&gt;ServerAliveCountMax&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;3&lt;/span&gt;
  &lt;span class="err"&gt;-o&lt;/span&gt; &lt;span class="py"&gt;BatchMode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;yes&lt;/span&gt;
  &lt;span class="err"&gt;-o&lt;/span&gt; &lt;span class="py"&gt;ControlMaster&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;auto&lt;/span&gt;
  &lt;span class="err"&gt;-o&lt;/span&gt; &lt;span class="py"&gt;ControlPersist&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;60s&lt;/span&gt;
  &lt;span class="err"&gt;-o&lt;/span&gt; &lt;span class="py"&gt;ControlPath&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;~/.ssh/cm-%r@%h:%p&lt;/span&gt;
  &lt;span class="err"&gt;-o&lt;/span&gt; &lt;span class="py"&gt;ProxyCommand&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"ssh -W %h:%p ubuntu@&amp;lt;bastion-host&amp;gt;"&lt;/span&gt;
&lt;span class="err"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Troque &lt;strong&gt;&lt;/strong&gt; pelo IP/DNS que será seu servidor bastion.&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Dica:&lt;/strong&gt; A combinação de &lt;code&gt;ControlMaster&lt;/code&gt;, &lt;code&gt;ControlPersist&lt;/code&gt; e &lt;code&gt;ControlPath&lt;/code&gt; permite o &lt;strong&gt;reaproveitamento da conexão SSH&lt;/strong&gt;, reduzindo a sobrecarga de autenticação e acelerando execuções consecutivas.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧱 Playbook — &lt;code&gt;check-security-updates.yaml&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Exemplo simplificado de playbook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Verifica por Atualizações de Segurança&lt;/span&gt;
  &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;development&lt;/span&gt;
  &lt;span class="na"&gt;become&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yes&lt;/span&gt;
  &lt;span class="na"&gt;tasks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Garantir que o curl está instalado&lt;/span&gt;
      &lt;span class="na"&gt;ansible.builtin.package&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;curl&lt;/span&gt;
        &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;present&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Criar script de verificação de updates&lt;/span&gt;
      &lt;span class="na"&gt;ansible.builtin.copy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;dest&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/usr/local/bin/check-security-updates.sh&lt;/span&gt;
        &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0755"&lt;/span&gt;
        &lt;span class="na"&gt;owner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;root&lt;/span&gt;
        &lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;root&lt;/span&gt;
        &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;#!/bin/bash&lt;/span&gt;
          &lt;span class="s"&gt;apt update -qq&lt;/span&gt;
          &lt;span class="s"&gt;updates=$(apt list --upgradable 2&amp;gt;/dev/null | grep -i security | wc -l)&lt;/span&gt;
          &lt;span class="s"&gt;if [ "$updates" -gt 0 ]; then&lt;/span&gt;
            &lt;span class="s"&gt;curl -s -X POST -H "Content-Type: application/json"               -d "{"content":"⚠️ Existem $updates atualizações de segurança pendentes no servidor $(hostname)."}"               https://example.com/webhook&lt;/span&gt;
          &lt;span class="s"&gt;fi&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Criar entrada no cron para rodar diariamente&lt;/span&gt;
      &lt;span class="na"&gt;ansible.builtin.cron&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Check&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;security&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;updates&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;notify"&lt;/span&gt;
        &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;root&lt;/span&gt;
        &lt;span class="na"&gt;job&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/usr/local/bin/check-security-updates.sh"&lt;/span&gt;
        &lt;span class="na"&gt;special_time&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;daily&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ &lt;strong&gt;Idempotente:&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Não recria o script se já existir e estiver atualizado.
&lt;/li&gt;
&lt;li&gt;Não duplica a entrada do cron.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧰 Execução Local (Manual)
&lt;/h2&gt;

&lt;p&gt;Exemplo de execução via Docker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; ~/infra/ansible:/workspace &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; ~/.ssh/known_hosts:/root/.ssh/known_hosts:ro &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; ~/.ssh/cicd-ansible-key.pem:/workspace/ssh_key.pem:ro &lt;span class="se"&gt;\ &lt;/span&gt; 
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;ANSIBLE_HOST_KEY_CHECKING&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;False &lt;span class="se"&gt;\&lt;/span&gt;
  myregistry.azurecr.io/toolbox-ubuntu:latest   &lt;span class="se"&gt;\&lt;/span&gt;
  ansible-playbook &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-i&lt;/span&gt; /workspace/inventory/servers.ini &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-l&lt;/span&gt; development &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--timeout&lt;/span&gt; 30 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--forks&lt;/span&gt; 1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--private-key&lt;/span&gt; /workspace/ssh_key.pem &lt;span class="se"&gt;\&lt;/span&gt;
  /workspace/playbooks/check-security-updates.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📋 &lt;strong&gt;O que este comando faz:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Monta o diretório local do Ansible dentro do container;
&lt;/li&gt;
&lt;li&gt;Usa a chave SSH privada para autenticação direta;
&lt;/li&gt;
&lt;li&gt;Executa o playbook contra o host ou grupo definido;
&lt;/li&gt;
&lt;li&gt;Reutiliza conexões SSH (&lt;code&gt;ControlPersist=60s&lt;/code&gt;) para melhor performance.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧩 Execução via Pipeline (CI/CD)
&lt;/h2&gt;

&lt;p&gt;A pipeline CI/CD executa os mesmos passos de forma automatizada:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Faz login no registro de contêineres (ex.: ACR, ECR, GCR).
&lt;/li&gt;
&lt;li&gt;Baixa a chave SSH segura da biblioteca de arquivos protegidos.
&lt;/li&gt;
&lt;li&gt;Prepara o inventário e a configuração SSH.
&lt;/li&gt;
&lt;li&gt;Valida o hostname remoto antes da execução.
&lt;/li&gt;
&lt;li&gt;Executa o playbook dentro do container Ansible.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Exemplo de Step (YAML)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Bash@3&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Run&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Ansible&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Playbook"&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;targetType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;inline'&lt;/span&gt;
    &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;docker run --rm \&lt;/span&gt;
        &lt;span class="s"&gt;-v "$(Pipeline.Workspace)/ansible:/workspace"\&lt;/span&gt;
        &lt;span class="s"&gt;-v "$(Agent.TempDirectory)/cicd-ansible-key.pem:/workspace/ssh_key.pem:ro"\&lt;/span&gt;
        &lt;span class="s"&gt;--network host\&lt;/span&gt;
        &lt;span class="s"&gt;myregistry.azurecr.io/toolbox-ubuntu:latest\&lt;/span&gt;
        &lt;span class="s"&gt;ansible-playbook\&lt;/span&gt;
        &lt;span class="s"&gt;-i /workspace/inventory/servers.ini\&lt;/span&gt;
        &lt;span class="s"&gt;-l development\&lt;/span&gt;
        &lt;span class="s"&gt;--timeout 30\&lt;/span&gt;
        &lt;span class="s"&gt;--forks 1\&lt;/span&gt;
        &lt;span class="s"&gt;--private-key /workspace/ssh_key.pem\&lt;/span&gt;
        &lt;span class="s"&gt;/workspace/playbooks/check-security-updates.yaml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ⚠️ Boas Práticas e Cuidados
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tipo&lt;/th&gt;
&lt;th&gt;Descrição&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;🔍 &lt;strong&gt;Seleção de Hosts&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Sempre valide o parâmetro &lt;code&gt;-l&lt;/code&gt; antes de executar. Ex.: &lt;code&gt;-l staging&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;⏱ &lt;strong&gt;Timeouts SSH&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;ConnectTimeout=10&lt;/code&gt; e &lt;code&gt;ServerAliveInterval=30&lt;/code&gt; para evitar bloqueios.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🔄 &lt;strong&gt;Multiplexação&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ControlPersist=60s&lt;/code&gt; acelera múltiplas conexões consecutivas.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🧱 &lt;strong&gt;Permissões&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;O script e o cron são criados como root — revise conforme as políticas de segurança.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🧩 &lt;strong&gt;Execução Idempotente&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Pode ser executado várias vezes, sem impacto negativo.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🧰 &lt;strong&gt;Fallback Automático&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Se o SCP falhar via bastion, o Ansible tenta automaticamente via SFTP.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🧾 Resumo Final
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Item&lt;/th&gt;
&lt;th&gt;Descrição&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;🔑 Chaves SSH&lt;/td&gt;
&lt;td&gt;Armazenadas de forma segura (Key Vault / Secret Library)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🧰 Execução Local&lt;/td&gt;
&lt;td&gt;Via Docker + chave privada montada&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;☁️ Execução CI/CD&lt;/td&gt;
&lt;td&gt;Pipeline com container Ansible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🧱 Playbook&lt;/td&gt;
&lt;td&gt;&lt;code&gt;check-security-updates.yaml&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;📋 Inventário&lt;/td&gt;
&lt;td&gt;&lt;code&gt;inventory/servers.ini&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🔐 Conexão Segura&lt;/td&gt;
&lt;td&gt;Bastion via &lt;code&gt;ProxyCommand&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;⚙️ Timeout e Persistência&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ConnectTimeout=10&lt;/code&gt;, &lt;code&gt;ControlPersist=60s&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🟢 Idempotente&lt;/td&gt;
&lt;td&gt;Sim&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🔔 Notificação&lt;/td&gt;
&lt;td&gt;Integrada com webhook (Discord/Slack/etc.)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🧠 Lições Aprendidas
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Lições Aprendidas&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A multiplexação SSH (&lt;code&gt;ControlPersist&lt;/code&gt;) reduz drasticamente o tempo de execução em playbooks grandes.
&lt;/li&gt;
&lt;li&gt;Adicionar timeouts explícitos (&lt;code&gt;ConnectTimeout&lt;/code&gt;, &lt;code&gt;ServerAliveInterval&lt;/code&gt;) previne travamentos na pipeline.
&lt;/li&gt;
&lt;li&gt;Separar as chaves SSH por contexto (pipeline, bastion, manutenção) aumenta a rastreabilidade e segurança.
&lt;/li&gt;
&lt;li&gt;Validar o hostname remoto antes de executar comandos evita incidentes em ambientes críticos.&lt;/li&gt;
&lt;/ul&gt;




&lt;blockquote&gt;
&lt;p&gt;✍️ Nem todo o código está nesse post, mas o post trás uma ideia geral de como estrutuar a execução do playbook através de uma pipeline.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>linux</category>
      <category>cicd</category>
      <category>security</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
