Risoluzione dei problemi di connessione SSH nei Playbook Ansible

Questa guida esperta fornisce un approccio sistematico per risolvere i comuni problemi di connessione SSH durante l'esecuzione dei playbook Ansible. Impara come sfruttare la massima verbosità (`-vvv`) per la diagnosi, risolvere errori di autenticazione relativi a chiavi private e permessi, correggere i problemi di `Host key verification failed` e diagnosticare blocchi di rete. Passaggi pratici ed esempi da riga di comando ti assicurano di poter isolare e risolvere rapidamente la causa principale dei timeout di connessione e dei messaggi di permesso negato, ripristinando un'automazione affidabile.

Risoluzione dei problemi di connessione SSH nei Playbook Ansible

Ansible utilizza comunemente Secure Shell (SSH) per comunicare con i nodi gestiti Linux e Unix. Può utilizzare altri plugin di connessione e l'automazione di Windows spesso utilizza WinRM, ma SSH è il percorso che la maggior parte dei team debuggia quotidianamente. Quando un playbook Ansible fallisce con un errore di connettività, quasi sempre indica un problema sottostante nella configurazione SSH standard tra la macchina di controllo e l'host di destinazione. Capire come diagnosticare sistematicamente questi fallimenti è cruciale per mantenere un'automazione affidabile.

Fase 1: Abilitazione della Verbosità e Controlli Iniziali

Il modo più veloce per smettere di indovinare è aumentare la verbosità dell'output. Gli errori SSH sono spesso mascherati, ma la massima verbosità rivela i parametri esatti che Ansible sta utilizzando e il messaggio di errore specifico restituito dal client OpenSSH sottostante.

Utilizza i Flag di Verbosità

Esegui il tuo comando di test o playbook con tre o quattro flag di verbosità (-v, -vv, -vvv, -vvvv). La maggior parte dei problemi di connessione vengono risolti esaminando l'output di -vvv.

# Testa la connettività a un host chiamato 'webserver' definito nel tuo inventario
ansible webserver -m ansible.builtin.ping -vvv

# Esegui un playbook con debug massimo
ansible-playbook site.yml -i inventory.ini -vvvv

Verifica l'Inventario e lo Stato dell'Host

Assicurati che l'host che stai targettizzando sia correttamente definito e raggiungibile.

  1. Il Nome dell'Host è Corretto? Ricontrolla l'ortografia nel tuo file di inventario (/etc/ansible/hosts o inventario personalizzato).
  2. Il Target è Attivo? Assicurati che il nodo gestito sia acceso e accessibile sulla rete.
  3. Le Variabili di Inventario sono Corrette? Conferma che le variabili essenziali come ansible_host (indirizzo IP o hostname) e ansible_user (nome utente remoto) siano impostate correttamente per il gruppo o host di destinazione.
# Esempio di frammento di inventario
[webservers]
web1 ansible_host=192.168.1.100 ansible_user=deploy_user ansible_port=22

Fase 2: Verifica della Connettività Manuale di Base

Se Ansible non riesce a connettersi, il primo passo deve sempre essere quello di confermare che SSH standard funzioni manualmente, utilizzando esattamente lo stesso utente, chiave e porta che Ansible è configurato per utilizzare.

Test SSH Manuale

Se stai utilizzando un utente specifico (ansible_user) e una chiave privata specifica (ansible_ssh_private_key_file), replica quella connessione manualmente.

# Test SSH standard (se si utilizza porta e chiave predefinite)
ssh <ansible_user>@<ansible_host>

# Test utilizzando una chiave privata e una porta non predefinite
ssh -i /path/to/private/key -p 2222 [email protected]

Se il test SSH manuale fallisce, risolvi prima quello. Ansible sta solo incapsulando lo stesso percorso SSH, quindi debuggare la sintassi del playbook prima che SSH funzioni di solito è una perdita di tempo.

Fase 3: Diagnosi degli Errori di Autenticazione

Gli errori di autenticazione sono la causa più comune dei problemi di connessione di Ansible. Di solito si manifestano come errori Authentication failed o Permission denied.

3.1 Permessi e Posizione della Chiave

Se Ansible utilizza chiavi SSH, assicurati che il file della chiave privata abbia i permessi corretti e ristretti sulla macchina di controllo. SSH spesso rifiuta chiavi troppo permissive.

# Imposta i permessi corretti sul file della chiave privata
chmod 600 /path/to/private/key

Inoltre, se utilizzi un Agente SSH, assicurati che la tua chiave sia aggiunta:

# Avvia l'agente se necessario
eval "$(ssh-agent -s)"
# Aggiungi la tua chiave all'agente
ssh-add /path/to/private/key

3.2 Fallimenti della Richiesta di Password (Timeout/Password Mancante)

Se la tua configurazione richiede una password (non consigliata per la produzione ma comune nei laboratori), Ansible deve riceverla. Se la connessione si blocca o scade, probabilmente Ansible sta aspettando una password che non è mai stata fornita.

Usa il flag --ask-pass o -k per richiedere la password di connessione SSH:

ansible webserver -m ansible.builtin.ping -k

3.3 Chiavi Autorizzate Remote

Verifica che la chiave pubblica corrispondente alla tua chiave privata sia correttamente installata nel file ~/.ssh/authorized_keys sul nodo gestito e che i permessi del file e della directory sul lato remoto siano corretti (700 per .ssh e 600 per authorized_keys).

Fase 4: Risoluzione degli Errori di Chiave Host

Ansible rispetta il file known_hosts, che memorizza l'impronta digitale dei server remoti. Se la chiave host di un nodo gestito cambia (ad esempio, a causa di una ricostruzione o riassegnazione IP), i tentativi di connessione SSH falliranno con un avviso che assomiglia a un attacco Man-in-the-Middle.

L'Errore Host key verification failed

Quando si verifica questo errore, devi aggiornare o rimuovere la voce di chiave in conflitto.

  1. Identifica il numero di riga in ~/.ssh/known_hosts menzionato nell'output dell'errore.
  2. Rimuovi la voce usando ssh-keygen.
# Sostituisci <hostname_or_ip> con l'host effettivo che fallisce
ssh-keygen -R <hostname_or_ip>

⚠️ Avviso di Sicurezza: Disabilitazione del Controllo Host

Per test temporanei o in ambienti di laboratorio altamente controllati dove l'instabilità dell'host è prevista, puoi configurare Ansible per ignorare il controllo della chiave host. Questo è fortemente sconsigliato per ambienti di produzione poiché ti espone ad attacchi MITM.

Nel tuo ansible.cfg (o variabile d'ambiente temporanea):

[defaults]
host_key_checking = False

Fase 5: Problemi di Rete, Firewall e Ambiente Remoto

A volte SSH si connette, ma la connessione si blocca o fallisce a causa della configurazione di rete o delle restrizioni sulla macchina di destinazione.

5.1 Blocco del Firewall

Se la connessione scade senza un prompt, probabilmente un firewall sta bloccando il tentativo di connessione. Controlla il firewall su tre punti:

  1. Locale (Macchina di Controllo): Assicurati che il traffico in uscita sulla porta 22 (o porta personalizzata) sia consentito.
  2. Percorso di Rete: Assicurati che nessun ACL di rete intermedio o firewall aziendale stia bloccando il traffico.
  3. Remoto (Nodo Gestito): Verifica che il firewall dell'host remoto (firewalld, ufw, ecc.) abbia SSH (di solito porta 22) aperto e configurato per l'interfaccia di rete corretta.

5.2 Errori dell'Interprete Python

Ansible richiede un interprete Python sul nodo gestito per eseguire i moduli. Sebbene non sia strettamente un fallimento SSH, la fase di connessione iniziale di Ansible comporta la raccolta di fatti, che è un'esecuzione di script Python. Se la macchina di destinazione è un'installazione minima senza Python 3, la connessione può fallire durante la fase di configurazione.

Se il tuo target utilizza Python 3 ma il percorso dell'interprete non è standard (ad esempio, python3.8 invece di python3), specifica il percorso corretto nel tuo inventario:

[target_host]
ansible_python_interpreter=/usr/bin/python3.8

5.3 Contesto SELinux o AppArmor

In rari casi, moduli di sicurezza eccessivamente restrittivi come SELinux (su RHEL/CentOS/Fedora) o AppArmor (su Ubuntu/Debian) potrebbero impedire l'accesso corretto al profilo della shell dell'utente remoto o ai permessi della directory durante la sessione SSH. Controlla i log di audit dell'host remoto (/var/log/audit/audit.log o equivalente) per negazioni AVC relative a SSH o all'accesso alla directory home dell'utente.

Pattern comuni da fallimenti reali di Ansible

Il testo dell'errore di solito ti dice quale strato ispezionare. UNREACHABLE! con Permission denied (publickey) non è lo stesso problema di Failed to connect to the host via ssh: Connection timed out. Il primo significa che il demone SSH ha risposto ma non ha accettato il percorso delle credenziali. Il secondo significa che la connessione TCP non è stata completata o che un firewall l'ha silenziosamente scartata.

Se gestisci istanze cloud, controlla il nome utente predefinito prima di cambiare le chiavi. Amazon Linux usa comunemente ec2-user, Ubuntu usa ubuntu, Debian usa spesso admin o debian, e le immagini personalizzate potrebbero usare qualcosa di completamente diverso. Una chiave valida con il nome utente remoto sbagliato ti dà comunque un fallimento della chiave pubblica. Il controllo più veloce è:

ssh -i key.pem [email protected]
ssh -i key.pem [email protected]

Per gli host bastion, rendi esplicito il percorso di salto nell'inventario in modo che ogni esecuzione utilizzi la stessa rotta:

[private_web]
web1 ansible_host=10.0.10.25 ansible_user=ubuntu

[private_web:vars]
ansible_ssh_common_args='-o [email protected]'

Se funziona sul tuo laptop ma fallisce in CI, confronta la versione SSH del runner CI, i permessi della chiave privata, il file known hosts e se il runner può raggiungere il bastion. I fallimenti CI spesso non sono affatto problemi di Ansible; il runner semplicemente non ha lo stesso percorso di rete o la chiave caricata nell'agente.

Un altro pattern è la confusione tra escalation dei privilegi e fallimento della connessione. SSH riesce, poi il playbook si blocca perché become necessita di una password sudo o perché l'utente remoto non è autorizzato a eseguire il comando. Testalo separatamente:

ansible web1 -m ansible.builtin.command -a "whoami" -vvv
ansible web1 -b -m ansible.builtin.command -a "whoami" -vvv

Se il primo comando restituisce l'utente di login e il secondo fallisce, lo strato SSH è sano. Risolvi sudoers, ansible_become_password o il tuo modello di privilegi invece di modificare le chiavi.

Variabili di inventario che vale la pena controllare due volte

Ansible ha diversi nomi di variabili che suonano simili, e gli esempi più vecchi su internet possono rendere tutto più confusionario. Preferisci i nomi correnti ansible_user, ansible_host, ansible_port, ansible_private_key_file e ansible_ssh_common_args nei nuovi inventari. Se l'inventario ha sia nomi vecchi che nuovi, o lo stesso host appare in più gruppi, usa ansible-inventory --host web1 per vedere il risultato risolto invece di leggere i file a occhio.

Controlla anche se ansible_connection è stato impostato da qualche parte inaspettata. Dispositivi di rete, container, attività di provisioning locale e host Windows possono utilizzare plugin di connessione diversi dall'SSH predefinito. Un host con ansible_connection=local non testerà affatto l'SSH remoto. Un host Windows che utilizza WinRM non dovrebbe essere debugato come un problema SSH a meno che tu non abbia configurato intenzionalmente OpenSSH su Windows.

Per inventari di grandi dimensioni, isola un host prima di eseguire l'intero playbook:

ansible web1 -i inventory.ini -m ansible.builtin.ping -vvv
ansible-playbook site.yml -i inventory.ini --limit web1 --check -vvv

Questo mantiene l'output leggibile e impedisce a un'esecuzione batch rumorosa di nascondere l'unica riga che conta.

Riepilogo degli Errori di Connessione Comuni e Soluzioni

Messaggio di Errore Causa Probabile Correzione Attuabile
Permission denied (publickey). Chiave non riconosciuta o permessi chiave errati. chmod 600 sulla chiave privata; verifica la chiave pubblica sull'host remoto.
Host key verification failed. Chiave host cambiata o file known_hosts corrotto. Usa ssh-keygen -R hostname per rimuovere la vecchia voce.
Connection timed out. Blocco firewall o host spento/non raggiungibile. Controlla la connettività manuale (ping, ssh); verifica le regole del firewall sull'host di destinazione.
La connessione si blocca/stalla. In attesa di input password non fornito. Esegui con -k o configura l'autenticazione basata su chiave.

Un ordine pratico delle operazioni

Quando debuggo i fallimenti SSH di Ansible, cerco di provare uno strato alla volta. Prima eseguo ansible-inventory --host <name> o ansible-inventory --graph in modo da sapere quali variabili Ansible vede effettivamente. Le sorprese dell'inventario sono comuni: una variabile di gruppo sovrascrive ansible_user, un inventario dinamico restituisce un indirizzo privato o un host è stato spostato in un gruppo con un ansible_port diverso.

Poi copio il comando SSH esatto implicito da -vvv. Se l'output mostra -o Port=2222 -o IdentityFile=/keys/deploy.pem -l ubuntu 10.0.4.18, testo quella combinazione esatta manualmente. Un ssh [email protected] riuscito non è sufficiente se Ansible sta usando una chiave, porta, hostname o configurazione SSH diversa.

Se SSH manuale funziona ma Ansible fallisce, cerco comportamenti specifici di Ansible: socket di multiplexing SSH obsoleti sotto ~/.ansible/cp, una variabile di inventario che punta all'interprete sbagliato, un prompt become che viene scambiato per un blocco della connessione o un playbook eseguito da CI senza lo stesso agente SSH che esiste sul mio laptop. Rimuovere ~/.ansible/cp/* è un test sicuro quando l'output di debug menziona ControlMaster o ControlPath; forza una nuova sessione SSH.

Un trucco utile è separare la connessione dall'esecuzione del modulo. ansible host -m ansible.builtin.raw -a "whoami" -vvv necessita di meno supporto Python remoto rispetto ai moduli normali. Se raw funziona ma ping fallisce, la tua rete e il percorso SSH sono probabilmente a posto, e il problema è probabilmente la scoperta di Python, i permessi o un problema di ambiente shell sul target.

Per gli inventari di produzione, documenta le ipotesi di connessione accanto al gruppo di host: utente remoto previsto, fonte della chiave, percorso bastion, porta SSH e se il controllo della chiave host è applicato. Il prossimo guasto è più facile quando tutti possono confrontare l'esecuzione fallita con il percorso previsto invece di fare reverse engineering dai log di debug.