Paramiko: Verifying and permanently adding SSH host key - ssh-keys

With Paramiko, one can set up a SSH key callback like this:
def someCallbackFunction(client, hostname, key):
...
client = SSHClient()
client.load_system_host_keys()
client.set_missing_host_key_policy(someCallbackFunction) # <--
client.connect(...)
The callback gets the SSH client instance, the hostname and a paramiko.RSAKey instance as parameters and must return if the key is accepted, or raise an exception otherwise.
How can I verify the SSH key with the provided parameters? For example, how can I get the RSA fingerprint so that the user can compare it? And is it possible to let Paramiko permanently add the key to "known_hosts"?

I couldn't find a way to write to (Open)SSH's known_hosts file, but as there are different variants (as of the PuTTY source code), I will just leave this and write accepted hosts to my own program's configuration.
Concerning the fingerprint, I found that Paramiko already provides this: PKey.get_fingerprint. In order to get the human-readable fingerprint, simply apply binascii.hexlify.

Related

PyCharm says remote host ID has changed, but ssh-keyscan does not

This morning PyCharm started warning me:
Warning: remote host identification has changed! IT IS
POSSIBLE THAT SOMEONE IS DOING SOMETHING
NASTY! Someone could be eavesdropping on you
right now (man-in-the-middle-attack)! It is also
possible that the host key has just been changed. The
fingerprint for the ssh-ed25519 key sent by the
remote host is
[redacted A]
Do you want to update the key in
/Users/[myhome]/.ssh/known_hosts and resume
connecting?
Then it asks if I want to change ~/Users/[myhome]/.ssh/known_hosts.
The target host is used as an sftp to transfer my code to the remote server. Its name is an alias for two data transfer nodes. I can look at their ssh public keys using ssh-keyscan -t ed25519 alias.remotehost.com and I get a key that matches the one in my known_hosts file. I can also connect to a different remote server, at which time I do not get a warning about changed ssh keys, and ssh-keyscan the original remote host and I get the same keys in known_hosts.
The key that PyCharm says is new does not match any of the now twice confirmed ssh keys. The format of the PyCharm-message-derived key is even totally different from the keys from ssh-keyscan.
What is going on? I don't want to just blast through a security warning, and I'd like some guidance on where to look to see why PyCharm is giving me this warning that I cannot confirm otherwise.
The reason is not necessarily a security issue. Did you double-check your SSH configuration, in particular the known_hosts file used by PyCharm is the same you're checking?
https://man.openbsd.org/ssh_config#UserKnownHostsFile
You may want to take a look at the PyCharm SSH Configurations ... Connection Parameters; for example the different format you're seeing might be related to storing hosts in hash format option (to be confirmed):
https://www.jetbrains.com/help/pycharm/settings-tools-ssh-configurations.html
You can try to recreate a SSH configuration from scratch as described here:
https://www.jetbrains.com/help/pycharm/create-ssh-configurations.html
If you're 100% sure that the key in the known_hosts file is the right one and matches your target server's, this will remove the entry in known_hosts file and you should be again prompted to accept the server key on the next connection:
ssh-keygen -R <host>
(where host is your target server, IP or hostname: "alias.remotehost.com" in your example; you can provide the path for the file using -f <path>)
References
ssh remote host identification has changed
https://stackabuse.com/how-to-fix-warning-remote-host-identification-has-changed-on-mac-and-linux/
https://youtrack.jetbrains.com/issue/CPP-19720

Why can I connect through SSH without using the required private key?

I am trying to connect to a server through SSH, using a private key that is required for the connection to succeed.
ssh -i <path-to-my-private-key> <user>#<server-ip>
It works. However, even if I don't use the private key, or if I use the wrong one, it works too, while it should not. Why does it work?
If you mean you can successfully log in to your server by running ssh ubuntu#<my-ec2-url> without using the -i <path-to-my-private-key> option, it is likely that you are running ssh-agent.
ssh-agent caches private keys in memory so that they can be used for authentication without having to enter the password on every connection.
As #jarmod points out, it is also possible that you have configured a private key for your target host in your ~/.ssh/config file. For example:
Host my-ec2-url
IdentityFile ~/.ssh/something-not-named-id_rsa
...although this is less likely, because unless you had created an unprotected private key, this would still prompt you for a key passphrase (and it would obviously need to match the public keys you have configured on the remote host).

Can I specify the expected host key fingerprint for Ansible ssh?

I'd like to be able to check the public key fingerprint for each host (the ssh servers) in an inventory into my host_vars directory. All my searches on the topic lead me to various resources describing either how to specify the client key or how to disable host key checking altogether. It seems to me though that once I've established that a host (server) key is authentic, it would be good to share that knowledge with others and keep the security benefit of host key checking. Is this possible?
I would suspect that in the same way those articles you have read are updating ansible_ssh_common_args in order to set -o UserKnownHostsFile=/dev/null you can similarly update that fact to use -o UserKnownHostsFile={{ playbook_dir }}/my_known_hosts to bundle the known hosts file alongside the playbooks that would use them

SSH won't connect after asking about host authenticity

I'm having a problem; git returns this alert:
The authenticity of host 'bitbucket.org (104.192.143.2)' can't be established.
RSA key fingerprint is SHA256:zzXQOXSRBEiUtuE8AikJYKwbHaxvSc0ojez9YXaGp1
Are you sure you want to continue connecting (yes/no)?
When I choose yes, it returns this:
Warning: Permanently added 'bitbucket.org,104.192.143.2' (RSA) to the list of known hosts.
ssh_packet_read: Connection closed
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.
What is the problem?
Where must I add the RSA number? Please, I'm desperate. :(
The authenticity of host 'bitbucket.org (104.192.143.2)' can't be established. RSA key fingerprint is SHA256:zzXQOXSRBEiUtuE8AikJYKwbHaxvSc0ojez9YXaGp1 Are you sure you want to continue connecting (yes/no)?
This is normal and it's safe to say yes. ssh is being overly paranoid by asking you to confirm it. You can turn it off by setting StrictHostKeyChecking to no in your ssh config.
Remembering the public key of each server you connect to is a security feature of ssh to protect you from a man-in-the-middle attack. It goes something like this:
The first time you ssh to a host its public key (that's all that SHA256:zzXQ... stuff) is remembered, usually in ~/.ssh/known_hosts.
Every time thereafter ssh will check that the same host is still using the same key. This authenticates that bitbucket.org is still the same server you were talking to the first time.
If the keys don't match it could mean one of two things. First is that the server admin reinstalled their ssh server and forgot to keep the same key. This is common for small sites, but unlikely for something like bitbucket.org.
The second possibility is that the ssh server has been hijacked. It doesn't matter how. One common way is for a rogue DNS server to return their own malicious IP address instead of the real address for bitbucket.org. Common enough on public wifi connections.
As for why it won't connect after confirming, it's right there in the error message.
$ git clone git#bitbucket.org:RobeJablonski/sda-robert.git
Cloning into 'sda-robert'...
conq: repository access denied.
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.
The repository exists, that can be verified, so you don't have access rights (neither do I). Bitbucket determines who you are using your ssh key. This means you're not logging in with the right key. It has to be the same key as is associated with your account on BitBucket.
You can find your BitBucket ssh keys in your Bitbucket settings under https://bitbucket.org/account/user//ssh-keys/. Then you have to check if ssh is using that key. You can check what it's using using ssh -v git#bitbucket.org. It will spew out a lot of stuff but you're looking for the last instance of debug1: Offering RSA public key: /Users/blah/.ssh/blah.
Once you find that, check if /Users/blah/.ssh/blah.pub matches what BitBucket thinks your ssh key is. If they don't match, then you'll have to find the matching key and configure ssh to use that key for bitbucket.org.
If you've lost the key, you should change your ssh key on bitbucket.org.
Make sure you have followed below steps in your application server:
Have you created public key:
cd ~/.ssh/
To generate keygeneration:
ssh-keygen
Copy public key value (NOT PRIVATE KEY)
cat ~/.ssh/id_rsa.pub
Install git :
sudo apt install git
ATLASSIAN SETUP :
SETTINGS -> Access keys -> Add key
https://bitbucket.org/compassitesinc/your-repository/admin/access-keys/
Make sure your email address added to the User group (with admin permission)
SETTINGS -> User and group access
Add your email address with admin access
Inside your application root directory clone your repository.
cd /var/www/html/
git clone git#bitbucket.org:organization_name/repo_application.git repo_application
You need to create an SSH key on the machine you wish to connect to GitHub or Bitbucket, then add that key to your online account. You can do this by following this:
https://confluence.atlassian.com/bitbucket/set-up-ssh-for-git-728138079.html

StrictHostKeyChecking config on PSFTP.EXE

I come accross StrictHostKeyChecking configuration when I needed to setup sftp communication between two servers (e.g. Windows Server ---> Linux Server). As defined here (use find for string match "StrictHostKeyChecking"):
If this flag is set to “yes”, ssh will never automatically add host keys to the ~/.ssh/known_hosts file, and refuses to connect to hosts whose host key has changed. This option forces the user to manually add all new hosts. If this flag is set to “no”, ssh will automatically add new host keys to the user known hosts files.
I want to use PSFTP.EXE to transfer files to the Unix server from Windows machine and there is obviously no concept of ~/.ssh/known_hosts. My question is then...what is the equivalent for StrictHostKeyChecking for PSFTP.EXE. Is it simple -batch which avoids interactive prompts ?
By default all PuTTY tools (including psftp) behave as StrictHostKeyChecking=ask.
With -batch, psftp (and pscp and plink) behave as StrictHostKeyChecking=yes.
If you use this switch and psftp finds that server's host key has changed you will get:
WARNING - POTENTIAL SECURITY BREACH! The server's host key does not
match the one PuTTY has cached in the registry. This means that either
the server administrator has changed the host key, or you have
actually connected to another computer pretending to be the server.
The new ... key fingerprint is:
...
Connection abandoned.
While without the switch (the default behavior), you will get an interactive prompt.
Likewise for the host key of a new server.
The psftp (nor any other PuTTY tool) never behaves as StrictHostKeyChecking=no. Unless you use some ugly and insecure hacks like here: How to pass echo y to plink.exe for first connection.
Obviously the -batch affects all other prompts too, not just host key prompts (comparing with StrictHostKeyChecking). There are these prompts in psftp (pscp and plink):
Username, passphrase, password, password change and keyboard-interactive prompts (connection aborts with -batch)
Insecure algorithm prompt (the same behavior as with host key prompt)
Append to existing log file? (logging is disabled with -batch when log file already exists and Ask user every time option is enabled for What to do if the log file already exists)