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.
- 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.
- 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
sshfrom a remote linux box. So, no key-based
ssh; it must be password-only. And there’s no way to provide the password to
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:
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
6 */8 * * * /home/jpavlov/expectScript.sh
The contents of
expect -d -c "set timeout -1;\
send -- $PASSWORD\r;\
The contents of
ssh routerUser@192.168.1.1 << EOF
clear crypto ipsec sa peer 192.168.66.6
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:
- If you want more detail, just Google something like “
expect ssh“, and you’ll find good stuff out there. Believe it or not, the
manpage is not the best place for this, since it seems to all be pointed toward handling modem requests and such.
- 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).
- Be careful with the “
expect” filter inside the “
expect” command 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…