unexpected SSH behavior when run in subshell [duplicate] - shell

This question already has answers here:
ssh: The authenticity of host 'hostname' can't be established
(20 answers)
Closed 1 year ago.
we have a private network that we connect to using openconnect, then we run ssh to the server we want to work
I have a file named ssh.sh:
#!/usr/bin/expect -f
set timeout -1
spawn ssh -L 3306:localhost:3306 -L 8600:localhost:8600 -L 5672:localhost:5672 -L 5000:localhost:5000 myusername#xx.xxx.xxx.xxx
expect "myusername#xx.xxx.xxx.xxx's password:"
send -- "mypass\r"
expect eof
when I call it by ./ssh.sh command, it works. but when I call this script in another one by ./ssh.sh command, it says:
spawn ssh -L 3306:localhost:3306 -L 8600:localhost:8600 -L 5672:localhost:5672 -L 5000:localhost:5000 myusername#xx.xxx.xxx.xxx
The authenticity of host 'xx.xxx.xxx.xxx (xx.xxx.xxx.xxx)' can't be established.
ED25519 key fingerprint is SHA256:AkfGt+ZPLk5EnMl+QR4Lg1bJZwolgk%KTf1o4iFoP3E.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])?
UPDATE:
it works correctly when I just call ./ssh.sh, but not when called as subshell
even if I say yes to that message, it still doesn't connect

SSH uses a key fingerprint method to determine if you are in a secure channel. This means that the host that they are contacting provides an unfalsifiable fingerprint. However, this method requires that you actually acknowledge the their fingerprint is the right one the first time you connect, and check it on next connections. This is what
The authenticity of host 'xx.xxx.xxx.xxx (xx.xxx.xxx.xxx)' can't be established.
ED25519 key fingerprint is SHA256:AkfGt+ZPLk5EnMl+QR4Lg1bJZwolgk%KTf1o4iFoP3E.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])?
means.
Therefore, your problem likely arises from the fact that SSH saves the host fingerprint somewhere where it can access it when you call it by hand, but cannot on the other case (ie. you call it being an other user).
A solution would be, instead of accepting by hand to remember the fingerprint, to let ssh.sh do the work, with the following snippet:
expect {
"key fingerprint" {send "yes\r"; exp_continue}
"password:" {send "$pass\r"}
}

Related

Make script Error on "Authenticity of host cannot be established" message

I am writing a wrapper script that sets up passwordless ssh to other servers for other scripts to then use.
The issue is that the inner scripts are not capable of taking user input. For example, whenever it receives
The authenticity of host 'hostname.server (XXX.XXX.XX.XX)' can't be established.
RSA key fingerprint is RS:A-:FI:NG:ER:PR:IN:T-.
Are you sure you want to continue connecting (yes/no)?
and a user enters anything (no, yes or nothing and press enter), the inner scripts fail because they were not expecting input. I do not have any control over the inner scripts, nor can I edit them.
My wrapper script essentially sets up ssh, and also tests ssh into the server before the other scripts run.
I want the wrapper script to error on any ssh response that requires user input (like aforementioned one above) as well as any kind of ssh error, so the failure is known sooner in the wrapper script rather than later in the inner scripts.
What is a good way to do this?
The SSH option you're looking for is BatchMode.
From the man page:
BatchMode
If set to ``yes'', passphrase/password querying will be disabled.
This option is useful in scripts and other batch jobs where no
user is present to supply the password. The argument must be
``yes'' or ``no''. The default is ``no''.
It might also be valuable to set a timeout for your connections, so that network problems don't cause your ssh client to hang around forever:
ConnectTimeout
Specifies the timeout (in seconds) used when connecting to the
SSH server, instead of using the default system TCP timeout.
This value is used only when the target is down or really
unreachable, not when it refuses the connection.
The default value for ConnectTimeout may be 0, which would cause ssh to wait forever.
You can put this on the command line:
ssh -o BatchMode=yes -o ConnectTimeout=15 me#host.example.com
or in a configuration file like ~/.ssh/config:
host example host.example.com
hostname host.example.com
user me
BatchMode yes
ConnectTimeout 15
Note that upon failing to connect, SSH will return a status in its exit value, so you might use shell constructs like:
if ! ssh example bin/do_something; then
echo "ERROR: bailing out of $0." >&2
exit 1
fi
The ssh command will also produce standard error explaining why it failed.
Add the host fingerprint to the known_hosts file before calling ssh
ssh-keyscan -H your_hostname >> ~/.ssh/known_hosts
Just make sure you trust the server before adding the fingerprint to the known_hosts to avoid security issues.

Non-interactive SSH GPG Agent forwarding with pre-existing connection

I have got a bit of a chicken/ egg problem here.
The Problem
I would like to SSH to a remote machine and forward my local gpg-agent. The problem is that the gpg-agent on the remote machine only starts once the SSH connection is established. While the gpg-agent is NOT running on the remote machine, I cannot connect to the remote machine via SSH while specifying the forwarding.
In the light of this, this command does not work, since the remote gpg-agent is not running and therefore the /run/user/1000/gnupg/S.gpg-agent does not exist yet.
ssh -R /run/user/1000/gnupg/S.gpg-agent:/run/user/1000/gnupg/S.gpg-agent user#remotemachine
The Workaround
The alternative is to do it interactively/ manually as shown below.
ssh user#remotemachine
I am now connected via SSH and as a side effect, the gpg-agent got automatically started too.
When I now update the existing SSH connection, by opening the SSH PTY:
[enter]
~C
ssh> -R /run/user/1000/gnupg/S.gpg-agent:/run/user/1000/gnupg/S.gpg-agent
Forwarding port.
[enter]
I can now run my GPG commands on the remote machine by the use of my local gpg-agent.
The Aim
I would like to have the above workaround automated. Basically I want to SSH to the remote machine with ssh user#remotemachine and the remote machine will then automatically add the SSH forwarding to the existing SSH connection.
The Question
How can I make the remote machine automatically update the newly established SSH connection and add the gpg-agent forwarding?
Since you used the expect tag, here is a simple expect script that should suffice.
#!/usr/bin/expect -f
spawn ssh user#remotemachine
expect {$ }
send "date\r"
expect {$ }
send "~C"
expect "ssh> "
send -- "-R /run/user/1000/gnupg/S.gpg-agent:/run/user/1000/gnupg/S.gpg-agent\r"
expect -timeout 5 timeout exit "\r\n"
send "echo ok\r"
expect "\nok\r"
expect {$ }
interact
Put this in a file and do chmod +x on it. For some reason, I found I didn't get the Forwarding port message from the -R command unless I enabled ssh -v, so I just check for \r\n, but you can change this. Also, I assumed the shell prompt from the remote was $, so you might need to change that too, but if your prompt is [enter] then you need to say
expect -ex {[enter]}
to avoid the string being interpreted as a regular expression.

How to ignore or Pass 'Yes' when The authenticity of host can't be established in Expect Shell script during Automation

I want to Provide 'Yes' automatically or Ignore it and proceed in a SECURE way, when the below statement comes during execution of my Expect Shell script?.
#!/usr/bin/expect
spawn ssh $user#$host
The authenticity of host 'abcdef (10.566.1.98)' can't be established.
RSA key fingerprint is jk:94:ba:93:0b:eb:ff:df:ea:gh:hj:23:3c:hj:9c:be.
Are you sure you want to continue connecting (yes/no)?
It's possible to avoid this question and accept all incoming keys automaticatilly by using ssh client option StrictHostKeyChecking set to no (default setting is ask, which results in that question):
ssh -o StrictHostKeyChecking=no "$user#$host"
However, note that it would be hardly any secure, as you're basically accepting connect with everyone who may act as a given host. The only secure way to avoid question is to pre-distribute host public keys to clients, i.e. in form of pre-generated known hosts file, which can be used in some way like that:
ssh \
-o UserKnownHostsFile=PATH_TO_YOUR_KNOWN_HOSTS_FILE \
-o StrictHostKeyChecking=yes "$user#$host"
This way you'll avoid the question if the check fails, and ssh will result in non-zero exit status.
This works, and it's especially convenient for docker builds
ssh-keyscan hostname.example.com >> $HOME/.ssh/known_hosts
Make use of exp_continue for this scenario.
#!/usr/bin/expect
set prompt "#|>|\\\$"
spawn ssh dinesh#myhost
expect {
#If 'expect' sees '(yes/no )', then it will send 'yes'
#and continue the 'expect' loop
"(yes/no)" { send "yes\r";exp_continue}
#If 'password' seen first, then proceed as such.
"password"
}
send "root\r"
expect -re $prompt
Reference : Expect

How to stop authentication of host message from coming up.

I am writing a script to log into multiple Cisco routers. I am running into and issue. This message pops up every time. "The authenticity of host 'x.x.x.x (x.x.x.x)' cant be established RSA key fingerprint is X. Are you sure you want to continue connecting (yes/no)?
From everything I have read about this says this is normal for the first time sshing into it, but it should store the RSA key and no longer display this message. Is there anyway to stop this message from popping up?
Here is my code so far.
#!/usr/bin/expect -f
spawn ssh -l user x.x.x.x
sleep 3
expect "*word"
send "mypassword"
send \r
Add the following to your ssh options:
-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no
Alternatively, to avoid host key verification and not use known_hosts file for a particular remote machine, you can also add the following to /etc/ssh/ssh_config:
Host remote_machine_ip
StrictHostKeyChecking no
UserKnownHostsFile=/dev/null
/etc/ssh/ssh_config - Golbal configuration
$HOME/.ssh/config - User-specific configuration
You can expect that prompt to occur, and actually answer it:
spawn ssh -l user x.x.x.x
expect {
"connecting (yes/no)" {send "yes\r"; exp_continue}
"password:" {send "mypassword\r"}
}
exp_continue basically acts as a loop so that you can keep waiting for the password prompt.
If the "connecting" prompt does not occur, no problem: expect will see the password prompt and carry on.

Automatically accept rsa fingerprint using pscp

When you're using pscp to send files to a single machine is not a big deal because you will get the rsa fingerprint prompt once and never again after. But if you want to connect to 200 machines, you definitely don't want to type "yes" 200 times....
I'm using pscp on a Windows machine and I really don't care about the fingerprint, I only want to accept it. I'm using Amazon EC2 and the finger print change every time i restart the machines....
If there is a way to avoid it using pscp or a different tool please let me know!!!
Thanks!
See Putty won't cache the keys to access a server when run script in hudson
On Windows you can use prefix echo y | in front of your command which will blindly accept any host key every time. However, a more secure solution is to run interactively the first time, or generate a .reg file that can be run on any client machine.
I do not completely agree with the last answer. The first time you accept an SSH key, you know nothing about the remote host, so automatically accepting it makes no difference.
What I would do is auto accept the key the first time you connect to a host. I've read that doing something like yes yes | ssh user#host works, but it doesn't, because SSH does not read from stdin, but from a terminal.
What does work is to pass, that first time you connect, the following ssh option (it works for both scp and ssh:
scp -oStrictHostKeyChecking=no user#host1:file1 user#host2:file2
This command would add the key the first time you run it, but if, as Eric says, doing this once you have accepted the key is dangerous (man in the middle is uncool). If I were you I'd add it to a script that checked in ~/.ssh/known_hosts if there's already a line for that host, in which case I wouldn't add that option. On the other hand, if there was no line, I'd do so ;).
If you are dealing with an encrypted version of known_hosts, try with
ssh-keygen -F hostname
Here's something I'm actually using (function receiving the following arguments: user, host, source_file)
deployToServer() {
echo "Deployng to $1#$2 from $3"
if [ -z "`cat ~/.ssh/known_hosts | grep $2`" ] && [ -z "`ssh-keygen -F $2`" ]
then
echo 'Auto accepting SSH key'
scp -oStrictHostKeyChecking=no $3* $1#$2:.
else
scp $3* $1#$2:.
fi
}
Hope this helped ;)
The host ssh key fingerprint should not change if you simply reboot or stop/start an instance. If it does, then the instance/AMI is not configured correctly or something else (malicious?) is going on.
Good EC2 AMIs are set up to create a random host ssh key on first boot. Most popular AMIs will output the fingerprint to the console output. For security, you should be requesting the instance console output through the EC2 API (command line tool or console) and comparing that to the fingerprint in the ssh prompt.
By saying you "don't care about the fingerprint" you are saying that you don't care about encrypting the traffic between yourself and the instance and it's ok for anybody in between you and the instance to see that communication. It may even be possible for a man-in-the-middle to take over the ssh session and gain access to control your instance.
With ssh on Linux you can turn off the ssh fingerprint check with a command line or config file option. I hesitate to publish how to do this as it is not recommended and seriously reduces the safety of your connections.
A better option is to have your instances set up their own host ssh key to a secret value that you know. You can save the public side of the host ssh key in your known hosts file. This way your traffic is encrypted and safe, and you don't have to continually answer the prompt about the fingerprints when connecting to your own machine.
I created a expect file with following commands in it:
spawn ssh -i ec2Key.pem ubuntu#ec2IpAddress
expect "Are you sure you want to continue connecting (yes/no)?" { send "yes\n" }
interact
I was able to ssh into the ec2 console without disabling the rsa fingerprint. My machine was added to the known hosts of this ec2.
I hope it helps.

Resources