How to automate scripted commands to a Cisco ASA via ssh

The premise *seemed* simple enough…  I just needed to send 4 or 5 commands to a Cisco ASA from a CentOS box in a cron job.  I mean, people write scripts all the time, and use ssh keys to automate those scripts against remote systems, right?  I do it all the time with Linux boxes, right?  Well…

I quickly discovered that there are two huge things that stop this standard practice from working with an ASA.

  1. The ASA does not understand semi-colons as replacements for returns.  This means you cannot use a standard single-line-style command in your ssh call.  each command must be sent with a real return.
  2. Though the ASA can make a set of keys to use with ssh, it cannot *store* any other keys for remote hosts, as needed when using key-based ssh from a remote linux box.  So, no key-based ssh; it must be password-only.  And there’s no way to provide the password to ssh in advance.

So what now?  Well, I worked on this one for a while… I almost gave up on it…  almost…

…until I stumbled across the “expect” program one day.  While it appears to have been originally designed for use with modems, it solved my problem perfectly.  It acts as a wrapper in a way, almost like a sub-shell, in which you stuff some instructions and your commands.  Since the virtual sub-shell has control, it runs your commands and listens for prompts popping up in STDOUT, and can respond to them.  Ah-hah!  A way to capture the password prompt with ssh!

Cutting to the chase, as I worked through it, I discovered that the expect program could not handle the ASA’s strange behavior on its own.  Since no matter how I tried to separate out the commands that I was trying to stuff into my ASA via expect, I could see in the debug that expect just kept putting them back together, separated by semi-colons (which, as I mentioned, does not work with the ASA).  The good news, is that after some troubleshooting, I came to the conclusion that the only way around that was to put my actual session commands into a sub-script, and call that sub-script from expect.  The logic looks like this:

crontab –>  expectScript.sh –>  commandScript.sh

Is all this making sense so far?

So anyway, here are the mechanics of it all, and hopefully it will become more clear:

The contents of the root crontab:

6 */8 * * * /home/jpavlov/expectScript.sh

The contents of /home/jpavlov/expectScript.sh:

#!/bin/bash
PASSWORD="asaSshPassword"
expect -d -c "set timeout -1;\
spawn /home/jpavlov/commandScript.sh;\
match_max 100000;\
expect *password:*;\
send -- $PASSWORD\r;\
interact;"

The contents of /home/jpavlov/commandScript.sh:

ssh routerUser@192.168.1.1 << EOF
en
routerEnablePassword
clear crypto ipsec sa peer 192.168.66.6
exit
exit
EOF

So, what do you think?  It works great for me.  Honestly, there’s too much here to go into much detail about in one post, but I want to pass along a couple random-but-related thoughts:

  1. If you want more detail, just Google something like “expect ssh“, and you’ll find good stuff out there.  Believe it or not, the man page is not the best place for this, since it seems to all be pointed toward handling modem requests and such.
  2. I tried using a series of “spawn” commands in the expect section for each of the session commands, and it works great when you do it against a Linux/Unix destination, but not the ASA.  That’s where, if you watch the debug with the “-d“, you’ll see that it is concatenating it all with semi-colons (as mentioned above).
  3. Be careful with the “expectfilter inside the “expectcommand set.  The filter is reg-ex aware and case-sensitive.  Make sure your filter matches, or it won’t work, obviously.

Just make sure you do a chmod 700 on the two scripts to keep it away from prying eyes.  You really shouldn’t do this on multi-use servers, but is less of a concern on a restricted box.

I hope that helps you!

🙂

And for all you that didn’t read the post clearly and are going to rave that I should use ssh keys (I just know you will)…  I’ll spare you the embarrassment by removing your post when you post (and you will)…

And for all you that insist that this method is insecure because the passwords are stored in a file… I assure you, my CentOS box is accessed by only administrators, and really, only me…

2 Comments

  1. Stas

    Some notes:

    1) To login via SSH with password use plink (from PuTTY suite). It has command line switch -pw
    eg: plink user@host -pw mYpAsSwOrD

    2) Sorry, but about public authentication. New ASA allows it! Version 8.4(4)3 understands this:

    username root attributes
    service-type admin
    ssh authentication publickey 61:3c:4d:ba:d5:3a:28:cc:d5:52:64:7c:86:b4:9e:9a:b2:e9:08:4e:86:8a:5f:eb:a6:2e:95:af:96:7d:16:c0 hashed

    Voila!

    3) Thank you for finding expect, it works for me too 🙂

  2. Jeremy Pavlov

    @stas
    Wow, that’s a great tip and update. Thanks!

Leave a Comment

Your email address will not be published. Required fields are marked *