ssh-add from bash script and automate passphrase entry - linux

I am trying to do ssh-add from script (don't care about about security at the moment).
Now ssh prompts for passphrase, which needs to be automated, so i read couple of things like this and found expect.
And now i do following:
eval `ssh-agent -s`
script tmp.sh defined as :
#!/usr/bin/expect
spawn ssh-add /root/.ssh/id_rsa
expect "Enter passphrase for /root/.ssh/id_rsa:"
send "my_pass"
interact
./tmp.sh
ssh-add -l
If ssh-add would have worked it shows something like
4096 SHA256:wlfP/nhVSWXLcljBOen5GSYZXJGgfi/XJWfZeBwqRsM id_rsa (RSA)
But instead i get The agent has no identities. Seems like ssh-agent looses it's context.
Am open to other solutions to do this.

Personally, I find the use of expect a bit cumbersome. The following approach found how to make ssh-add read passphrase from a file rather informative.
So if your version of ssh-add allows the -p argument and you are not worried about security then this should work:
#!/bin/bash
# store a file somewheres with your passphrase. For example's sake
# I'll just use $HOME/.myscrt
<$HOME/.myscrt ssh-add -p ~/.ssh/id_rsa
Now if -p is not an option for you, I found the second method mildly ingenious:
#!/bin/bash
# Same passfile and some minor enhancements from the OP of the linked
# solution
PASS="$(<$HOME/.myscrt)"
# the following is just a one-liner method of making an executable
# one-line script echoing the password to STDOUT
install -vm700 <(echo "echo $PASS") "$PWD/ps.sh"
# then the magic happens. NOTE: your DISPLAY variable should be set
# for this method to work (see ssh-add(1))
[[ -z "$DISPLAY" ]] && export DISPLAY=:0
< id_rsa SSH_ASKPASS="$PWD/ps.sh" ssh-add - && shred -n3 -uz $PWD/ps.sh
When I tested the script I called "j", see below:
$ cd /tmp
$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/me/.ssh/id_rsa): /tmp/id_rsa
Enter passphrase (empty for no passphrase): asdfasdf
Enter same passphrase again: asdfasdf
Your identification has been saved in /tmp/id_rsa.
Your public key has been saved in /tmp/id_rsa.pub.
The key fingerprint is:
ed:1a:ae:c7:ac:47:5e:31:98:8e:18:8f:1c:67:94:6d jimconn#redapt-240
The key's randomart image is:
+--[ RSA 2048]----+
| o |
| o E |
| . . o |
| o o o.o |
| . O oS .o |
| + o o.. |
| =... |
| .*o |
| o=o |
+-----------------+
$ echo 'asdfasdf' > ~/.myscrt
$ chmod 0600 ~/.myscrt
$ ls -altr ~/.myscrt
-rw------- 1 me me 9 Feb 16 19:00 /home/me/.myscrt
$ cat ~/.myscrt
asdfasdf
$ ls -ltr
total 12
-rw-r--r-- 1 me me 400 Feb 16 18:59 id_rsa.pub
-rw------- 1 me me 1766 Feb 16 18:59 id_rsa
-rwx------ 1 me me 151 Feb 16 19:04 j
$ cat j
#!/bin/bash
PASS="$(<$HOME/.myscrt)"
install -vm700 <(echo "echo $PASS") "$PWD/ps.sh"
cat id_rsa | SSH_ASKPASS="$PWD/ps.sh" ssh-add - && shred -n3 -uz $PWD/ps.sh
$ ./j
‘/dev/fd/63’ -> ‘/tmp/so/ps.sh’
Identity added: (stdin) ((stdin))
$ ls
id_rsa id_rsa.pub j
So, one thing to quickly note about this method is that listing the identities loaded into ssh-agent will only show that stdin was loaded:
$ ssh-add -D
All identities removed.
$ ssh-add -l
2048 ed:1a:ae:c7:ac:47:5e:31:98:8e:18:8f:1c:67:94:6d (stdin) (RSA)
$ ./j
‘/dev/fd/63’ -> ‘/tmp/so/ps.sh’
Identity added: (stdin) ((stdin))
$ ssh-add -l
2048 ed:1a:ae:c7:ac:47:5e:31:98:8e:18:8f:1c:67:94:6d (stdin) (RSA)

UPDATED BECAUSE THE FIRST ONE DID NOT WORK
I did not try this, but if it is realy about expect loosing the context, it might be a good idea to set it up later:
auto-passphrase-add.expect (replacing tmp.sh)
/usr/bin/expect
spawn ./ssh-agent-ssh-add.sh /root/.ssh/id_rsa
expect "Enter passphrase for /root/.ssh/id_rsa:"
send "my_pass"
interact
ssh-agent-ssh-add.sh
#!/bin/sh
eval `ssh-agent -s`
ssh-add "$#"

Related

Answer "Yes" or "No" ONLY IF a command request it

I a writing a script. There is a command that colud request to answer yes or no to override a certain file.
I want to automate the script to answer YES or NO ONLY IF the command request it (i don't want to echo yes inside the command).
The command I am referring to is ssh-keygen, which requires to override the key in case already exists.
In my mind there is something like this...
if (ssh-keygen requests input) --> Sends yes to the ssh-keygen
In particular, I am using the following command:
ssh-keygen -t rsa -b 4096 -N '' -f ~/.ssh/id_rsa -q
Even if i am using -q, still asks yes or no to override the file.
Thanks in advance
i suggest using the echo command to send "yes" to the command.
echo "yes" | ssh-keygen -t rsa -b 4096 -N '' -f ~/.ssh/id_rsa -q
I would suggest you to check the yes command.
It is sending a loop of y.
If you want to force the acceptation of the command it should work.
But if the keygen request for an input (filename, etc.) it will also send 'y'.
the command would be :
yes | ssh-keygen -t rsa -b 4096 -N '' -f ~/.ssh/id_rsa -q

ssh key generation and copy ssh key to other machines

I am running the following script to generate and copy ssh key to other machines in my cluster for password-less ssh.
#!/bin/bash
#create host and password file
echo enter host-name,password in "host pass" format:
read hopa
echo "$hopa"> /root/host1.txt
sed -i 's/,/\n/g' /root/host1.txt
# SSH Key
#echo -en "y" | ssh-keygen -f id_rsa -t rsa -N ''
# Passwordless ssh
echo -en "y" | ssh-keygen -f id_rsa -t rsa -N ''
declare -A hp
while IFS=' ' read -r host pass
do
hp["$host"]="$pass"
done < /root/host1.txt
for host in "${!hp[#]}"
do
pass="${hp["$host"]}"
sshpass -p "${pass[i]}" ssh-copy-id -i id_rsa -o "StrictHostKeyChecking no" -f root#"${host[i]}" -p 22
done
When prompted for hostnames and their passwords:
My input:
cephadmin 1234,ceph2 1234,ceph3 1234,cephclient 1234
Output:
The key fingerprint is:
SHA256://CzhoYLtmVVRWoJTKfTkJV9BQbeKypzGoXBLV62KKw root#cephadmin
The key's randomart image is:
+---[RSA 3072]----+
| o+o+==.o|
| . .oB.*. .|
| + * B .. |
| . . B = . |
| o S + . . |
| . . + . . |
| E o *.=. |
| . =.*o+o |
| . oo .+o |
+----[SHA256]-----+
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "id_rsa.pub"
Number of key(s) added: 1
Now try logging into the machine, with: "ssh -o 'StrictHostKeyChecking no' -p '22' 'root#cephadmin'"
and check to make sure that only the key(s) you wanted were added.
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "id_rsa.pub"
Number of key(s) added: 1
Now try logging into the machine, with: "ssh -o 'StrictHostKeyChecking no' -p '22' 'root#ceph2'"
and check to make sure that only the key(s) you wanted were added.
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "id_rsa.pub"
Number of key(s) added: 1
Now try logging into the machine, with: "ssh -o 'StrictHostKeyChecking no' -p '22' 'root#ceph3'"
and check to make sure that only the key(s) you wanted were added.
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "id_rsa.pub"
Number of key(s) added: 1
Now try logging into the machine, with: "ssh -o 'StrictHostKeyChecking no' -p '22' 'root#cephclient'"
and check to make sure that only the key(s) you wanted were added.
When I try logging into cephclient machine with ssh cephclient I am being prompted for password
[root#localhost ~]# ssh cephclient
root#cephclient's password:
How can I make sure that my script works properly and I get the desired output, i.e. login to other machines without password?
first time it will ask password. From Second time onwards it will not ask password.

"echo "password" | sudo -S <command>" asks for password

I trying run a script without become the su user and I use this command for this:
echo "password" | sudo -S <command>
If I use this command for "scp", "mv", "whoami" commands, the command works very well but when I use for "chmod", the command asks for password for my user. I don't enter password and the command works. My problem is the system asks password to me. I don't want the system asks for password.
Problem ss is like this:
[myLocalUser#myServer test-dir]$ ls -lt
total 24
--wx-wx-wx 1 root root 1397 May 26 12:12 file1
--wx-wx-wx 1 root root 867 May 26 12:12 script1
--wx-wx-wx 1 root root 8293 May 26 12:12 file2
--wx-wx-wx 1 root root 2521 May 26 12:12 file3
[myLocalUser#myServer test-dir]$ echo "myPassw0rd" | sudo -S chmod 111 /tmp/test-dir/*
[sudo] password for myLocalUser: I DONT WANT ASK FOR PASSWORD
[myLocalUser#myServer test-dir]$ ls -lt
total 24
---x--x--x 1 root root 1397 May 26 12:12 file1
---x--x--x 1 root root 867 May 26 12:12 script1
---x--x--x 1 root root 8293 May 26 12:12 file2
---x--x--x 1 root root 2521 May 26 12:12 file3
You can use the sudoers file, located in /etc/sudoers, to allow specific users execute commands as root without password.
myLocalUser ALL=(ALL) NOPASSWD: /bin/chmod
With this line the user myLocalUser can execute chmod as root without a password is needed.
But this also breaks parts of the system security, so be aware not allow too much and fence the task as much as possible.
sudoers information
sudo -S prints prompt to stderr.
If you don't want to see it, redirect stderr to /dev/null
The following command redirects stderr at the local host:
echo <password> | ssh <server> sudo -S ls 2>/dev/null
It is equivalent to echo <password> | ssh <server> "sudo -S ls" 2>/dev/null
The following command redirects stderr at the remote server:
echo <password> | ssh <server> "sudo -S ls 2>/dev/null"
If you need to keep stderr, but hide [sudo] password for ... then you can use process substitution on the local or remote machine. Since sudo prompt has no newline, I use sed to cut out the sudo prompt. I do this to save the first line of stderr of the created process.
# local filtering
echo <password> | ssh <server> "sudo -S ls" 2> >(sed -e 's/^.sudo[^:]\+: //')
#remote filtering
echo <password> | ssh <server> "sudo -S ls 2> >(sed -e 's/^.sudo[^:]\+: //')"

Bash Scripting - passing no value

My aim is to create a bash script that can add new users to Ec2 and give access to ssh keys but I am having abit of an issue.
This is my current script and the script stops whenever it requires to generate a private/public key because it asks for the passphrase . How can I configure my script to just press enter?
#!/bin/bash
username=$1
ssh-keygen -b 1024 -f $username -t dsa
chmod 600 $username.pub
useradd $username
mkdir /home/$username/.ssh
chmod 700 /home/$username/.ssh
chown ball:ball /home/$username/.ssh
cat ball.pub >> /home/$username/.ssh/authorized_keys
chown 600 /home/.ssh/$username/authorized_keys
chown ball:ball /home/$username/.ssh/authorized_keys
[root#ip-172- /]# ssh-keygen -b 1024 -f ball -t dsa
Generating public/private dsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in ball.
You can pipe empty lines to ssh-keygen:
ssh-keygen -b 1024 -f ball -t dsa <<< ''
or
printf "" | ssh-keygen -b 1024 -f ball -t dsa
or reading from /dev/null:
ssh-keygen -b 1024 -f ball -t dsa < /dev/null

linux pipe with multiple programs asking for user input

I wonder how to create a pipe
program 1 | ... | program N
where multiple of the programs ask for user input. The problem is that | starts the programs in parallel and thus they start reading from the terminal in parallel.
For such cases it would be useful to have a pipe | that starts program (i+1) only after program i has produced some output.
Edit:
Example:
cat /dev/sda | bzip2 | gpg -c | ssh user#host 'cat > backup'
Here both gpg -c as well as ssh ask for a password.
A workaround for this particular example would be the creation of ssh key pairs, but this is not possible on every system, and I was wondering whether there is a general solution.
Also gpg allows for the passphrase to be passed as command line argument, but this is not suggested for security reasons.
You can use this construction:
(read a; echo "$a"; cat) > file
For example:
$ (read a; echo "$a"; echo cat is started > /dev/stderr; cat) > file
1
cat is started
2
3
Here 1, 2 and 3 were entered from keyboard; cat is started was written by echo.
Contents of file after execution of the command:
$ cat file
1
2
3
I am now using:
#!/bin/bash
sudo echo "I am root!"
sudo cat /dev/disk0 | bzip2 | gpg -c | (read -n 1 a; (echo -n "$a"; cat) | ssh user#host 'cat > backup')
The first sudo will prevent the second from asking the password again. As suggested above, the read postpones the starting of ssh. I used -n 1 for read since I don't want to wait for newline, and -n for echo to surpress the newline.
for one you can give gpg the password with the --passphrase option.
For ssh the best solution would be to login by key. But if you need to do by password the expect command will be good. Here's a good example: Use expect in bash script to provide password to SSH command
Expect also allows you to have some input - so if you don't want to hardcode your passwords this might be the way to go.
I've needed something similar a few times before, where the first command in the pipeline requires a password to be entered, and the next command doesn't automatically cater for this (like the way that less does).
Similar to Igor's response, I find the use of read inside a subshell useful:
cmd1 | ( read; cat - | cmd2 )

Resources