1

I've been trying to automate the creation of a user and configuration of the ssh access.

So far I created a script that access the host and creates the new user via expect, as follows:

expect -c '
spawn ssh '$user'@'$ip';
expect "assword: ";
send "'$passwd'\r";
expect "prompt\n";
send "adduser '$new_user'\r";
...
send "mkdir /home/'$new_user'/.ssh\r";
expect "prompt\n";
send "exit\r";
'

This works fine, after that I need to add the .pub key file to the authorized keys file in the host, there is where hell started.

I tried:

ssh_key='/home/.../key.pub'
content=$(cat $ssh_key)
expect -c '
spawn ssh '$user'@'$ip' "echo '$content' >> /home/'$new_user'/.ssh/authorized_keys;
expect "password:";
...
'

and got:

missing "
    while executing 
"spawn ssh [email protected] ""
couldn't read file "<ssh .pub key content> ...

I tried also:

cat $ssh_key | ssh $user@$ip "cat >> /home/$new_user/.ssh/authorized_keys"

Without success, I only get the password query blinking, I can't connect the expect with this last method.

1
  • You might make a habit of using shellcheck.net -- it would have caught your bug. Commented Sep 23, 2016 at 22:00

1 Answer 1

3

I'm going to ignore the larger problems here and focus specifically on your question. (There are larger problems: Don't use expect here -- if you rely on sshpass instead you can simplify this script immensely).

Right now, when you close your single quotes, you aren't starting any other kind of quotes. That means that when you substitute a variable with whitespace, you end the -c argument passed to expect.

Instead of doing this:

'foo'$bar'baz'

do this:

'foo'"$bar"'baz'

...so your script will look more like:

ssh_key='/home/.../key.pub'
content=$(<"$ssh_key")
expect -c '
spawn ssh '"$user"'@'"$ip"' "echo '"$content"' >> /home/'"$new_user"'/.ssh/authorized_keys;
expect "password:";
...
'

In terms of avoiding this altogether, though, consider something more like the following:

#!/bin/bash
#      ^^^^- NOT /bin/sh

content=$(<"$ssh_key") # more efficient alternative to $(cat ...)

# generate shell-quoted versions of your variables
# these are safe to substitute into a script
# ...even if the original content contains evil things like $(rm -rf /*)
printf -v content_q '%q' "$content"
printf -v new_user_q '%q' "$new_user"

# use those shell-quoted versions remotely
sshpass -f"$password_file" ssh "$host" bash -s <<EOF
adduser ${new_user_q}
printf '%s\n' ${content_q} >>/home/${new_user_q}/.ssh/authorized_keys
EOF
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.