Tips en Trucs 2011

Automatisch inloggen met expect

Je moet een taak automatisch op verschillende computers uitvoeren. Je kent de gebruikersnaam en het wachtwoord, maar je kunt geen gebruik maken van PKI (Public Key Infrastructure).

Geef het dan nog niet op, want er bestaat een nog niet wijdverspreid gebruikt, klein maar zeer krachtig hulpmiddel, namelijk expect.

Expect start een interactieve opdracht en verzorgt de interactie zoals de opdracht die verwacht (expect). Misschien moet je een vraag met ja of nee beantwoorden of een naam of wachtwoord ingeven. Daarnaast kun je condities opgeven om expect te sturen in de conversatie met de opdracht. Laten we SSH als voorbeeld gebruiken.

Om op een externe computer via ssh in te loggen, gebruik je de opdracht:
ssh dany@externe.computer.be
Password: 
Je kent het wachtwoord. Je typt het wachtwoord in en krijgt toegang tot de externe computer. Maar wat als je 200 externe computers moet bereiken? Dat wordt wel erg veel typen. Gelukkig hebben we expect. Met expect kun je namelijk scripts schrijven:
#!/usr/bin/expect
spawn /usr/bin/ssh dany@[lindex $argv 0]

Dit is nog geen volledig script. Expect zal met deze opdrachtregel de ssh opdracht uitvoeren met de gebruikersnaam dany naar de externe computer die opgegeven werd bij het opstarten van het script (eerste argument). Dit argument wordt door [lindex $argv 0] aan de ssh opdracht doorgegeven. Als expect de ssh opdracht heeft opgestart, moet expect gepast op de vragen van de ssh opdracht reageren.

Indien ssh voor de eerste keer met een externe computer contact maakt, vraagt ssh of de vingerafdruk van de externe computer authentiek is. Op het internet kun je met deze controle de vervelende man-in-the-middle aanvallen tegenhouden, maar op mijn eigen LAN netwerk kan ik de computers vertrouwen. Expect mag in zo'n geval de vraag "Are you sure you want to continue connecting (yes/no)?" met yes beantwoorden waardoor de ssh opdracht kan doorgaan:
expect {
-re ".*Are.*.*yes.*no.*" {
send "yes\r"
exp_continue
}
Daarna zal de externe computer het wachtwoord opvragen. Wanneer ssh om een wachtwoord vraagt, moet expect dit wachtwoord invullen en met Return bevestigen (\r).
"*?assword:*" {
send "WacTWooRd"
send "\r"
interact
}
}

Na het verzenden van het wachtwoord, zorgt de interact opdracht dat de controle terug aan de terminal wordt gegeven en je de besturing van expect terug overneemt. In plaats van de interact opdracht kun je expect verder zelf opdrachten zoals uname -a en exit laten sturen. Maar dit laat ik aan jullie over.

Beveiliging

Als je expect gebruikt voor dit soort automatisering, is het opslaan van wachtwoorden in het script zelf gevaarlijk en zonder problemen door spionerende blikken te achterhalen. Beter is het wachtwoord in een apart bestand op te slaan. Expect kan het wachtwoord dan uit dit bestand ophalen.

Maak met de volgende opdrachten het bestand met het wachtwoord aan en pas de rechten van dit bestand aan zodat het enkel door de gebruiker gelezen kan worden:
echo "WacTWooRd" > $HOME/.secret
chmod 400 $HOME/.secret
Het expect script pas je aan zodat het wachtwoord uit het .secret bestand gelezen wordt en in een variabele gestopt wordt. Verder wordt het script aangepast zodat bij het verzenden van het wachtwoord de inhoud van de variabele gebruikt wordt. Het volledige expect script wordt dan:
#!/usr/bin/expect
set tmp [open ~/.secret]
set password [read $tmp]
close $tmp
spawn /usr/bin/ssh dany@[lindex $argv 0]
expect {
-re ".*Are.*.*yes.*no.*" {
send "yes\r"
exp_continue
}
"*?assword:*" {
send $password
send "\r"
interact
}
}

Op het internet vind je veel prachtige voorbeelden (examples) van verschillende technieken waarbij expect gebruikt wordt. Als je iets wilt automatiseren, vind je voorbeelden van hoe je het kunt aanpakken.