Reputation: 7250
When executing expect
scripts, arguments are visible on ps ax
which can be a security vulnerability if they are sensitive.
Trying to automate opening a tab on iTerm2, running ssh admin@host
and entering the passphrase when asked Enter passphrase for key '/Users/admin/.ssh/key'
(the key is encrypted using that passphrase).
Host host
HostName 1.2.3.4
IdentityFile ~/.ssh/key
I would like to supply the passphrase to bash using read -sp 'Passphrase: ' passphrase
and then pipe it to expect
(which isn’t perfect at all from an OPSEC perspective but much better than having the passphrase leaked on ps ax
).
Perhaps there is a better way?
Bellow is some code that works but leaks the passphrase on ps ax
. Commented out is what I wish was possible (piping the passphrase to expect
).
#!/bin/bash
function new_tab() {
command=${1//\"/\\\"}
osascript \
-e "tell application \"iTerm2\"" \
-e "tell current window" \
-e "create tab with default profile" \
-e "delay 1" \
-e "tell current session" \
-e "write text \"$command\"" \
-e "end tell" \
-e "end tell" \
-e "end tell" > /dev/null
}
hostnames=(
"hostname-1"
"hostname-2"
)
read -sp 'Passphrase: ' passphrase
for hostname in "${hostnames[@]}"; do
# new_tab "echo $passphrase | expect $(pwd)/expect.exp \"$hostname\""
new_tab "expect $(pwd)/expect.exp \"$hostname\" \"$passphrase\""
done
#!/usr/bin/expect
set hostname [lindex $argv 0]
set passphrase [lindex $argv 1]
spawn ssh admin@$hostname
expect "passphrase"
send "$passphrase\r"
interact
Upvotes: 4
Views: 2249
Reputation: 7250
Yes, expect
can read from stdin
but there is a caveat: reading from stdin
isn’t compatible with interact
.
See https://stackoverflow.com/a/57847199/4579271
#!/usr/bin/expect
set passphrase [gets stdin]
#!/usr/bin/expect
set data [gets stdin]
scan $data "%s %s" hostname passphrase
Another approach is to use environment variables (as suggested by Glenn) but there is another caveat: environment variables are only available to the shell in which they are defined and its children.
Environment variables defined in batch.sh
would therefore not be available in the iTerm2 tabs created using osascript
.
So the only secure option I have is to drop osascript
altogether and have all the code (batch.sh
and expect.exp
) execute in the same shell and use environment variables to pass variables between bash
and expect
.
#!/bin/bash
hostnames=(
"hostname-1"
"hostname-2"
)
read -sp 'SSH key passphrase: ' passphrase
echo ""
export PASSPHRASE=$passphrase
for hostname in "${hostnames[@]}"; do
export HOSTNAME=$hostname
expect "$(dirname "$0")/expect.exp"
done
#!/usr/bin/expect
set timeout 10
spawn ssh admin@$env(HOSTNAME)
expect {
default {
puts "\nCould not connect to $env(HOSTNAME)"
exit 1
}
"passphrase" {
send "$env(PASSPHRASE)\r"
}
}
expect {
default {
puts "\nWrong passphrase"
exit 1
}
"admin@$env(HOSTNAME)" {
# Add automation commands here, then exit SSH session to close expect script moving on to the next hostname
send "exit\r"
}
}
interact
Upvotes: 2
Reputation: 246774
In the bashscript, read the password and then export
the variable. In expect, access it from the environment with $env(passphrase)
Upvotes: 3