Fabric Error: "PasswordRequiredException: Private key file is encrypted" - python

How to submit the passphrase for a encrypted private key with Fabric?
It seems not to work with the following code as described in the official documentation:
from fabric import Connection
password = '1234'
c = Connection('foo',connect_kwargs={'passphrase': password})
result = c.run('uname -s')
Error Message:
File "/home/user/.miniconda3/envs/test/lib/python3.7/site-
packages/paramiko/ed25519key.py", line 97, in _parse_signing_key_data
"Private key file is encrypted"
PasswordRequiredException: Private key file is encrypted
My ~/.ssh/config file on my linux machine has the following entry:
host foo
hostname localhost
port 12345
user userxxx
ForwardAgent yes
ProxyJump reverse#test.com

Related

Paramiko RSAKey "private key file is encrypted"

I'm trying to use Paramiko to connect to an SFTP site.
"paramiko": {
"hashes": [
"sha256:6bef55b882c9d130f8015b9a26f4bd93f710e90fe7478b9dcc810304e79b3cd8",
"sha256:fedc9b1dd43bc1d45f67f1ceca10bc336605427a46dcdf8dec6bfea3edf57965"
],
"index": "pypi",
"version": "==3.0.0"
},
I have a .pem file in the form
-----BEGIN OPENSSH PRIVATE KEY-----
data for the key
-----END OPENSSH PRIVATE KEY-----
Worth mentioning that the key is encrypted with a passphrase.
I attempt to load the key file, providing the password and that works fine
# Works great :)
mykey = paramiko.RSAKey.from_private_key_file(key_file_path, password=password)
self.ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# this explodes
self.ssh_client.connect(hostname=settings.ftp_host, username=username, pkey=mykey, port=22)
self.ftp = self.ssh_client.open_sftp()
paramiko.ssh_exception.PasswordRequiredException: private key file is encrypted
If I change the connect to
self.ssh_client.connect(hostname=settings.ftp_host, username=username, pkey=mykey, port=22, passphrase=password)
paramiko.ssh_exception.SSHException: OpenSSH private key file checkints do not match
And if I try to use key_filename instead of pkey
self.ssh_client.connect(hostname=settings.ftp_host, username=username, key_filename=key_file_path, port=22, passphrase=password)
ValueError: q must be exactly 160, 224, or 256 bits long
I am able to successfully connect to the SFTP with this key using FileZilla I'm just not sure what I'm doing wrong in Paramiko.
Thanks!
Figured this out today.
I setup Parmiko's logging and saw that it was defaulting to try to use 'rsa-sha2-512'
2023-02-16 10:01:46 - DEBUG - transport.py:1871 - paramiko.transport - _log() - Our pubkey algorithm list: ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-rsa']
2023-02-16 10:01:46 - DEBUG - transport.py:1871 - paramiko.transport - _log() - Server did not send a server-sig-algs list; defaulting to our first preferred algo ('rsa-sha2-512')
Disabling 'rsa-sha2-512' and 'rsa-sha2-256' so Paramiko was forced to use 'ssh-rsa' fixes the issue.
self.ssh_client.connect(hostname=settings.ftp_host, username=username, pkey=mykey, disabled_algorithms=dict(pubkeys=["rsa-sha2-512", "rsa-sha2-256"]))

How to add ssh key correctly [duplicate]

I am writing a program using pysftp, and it wants to verify the SSH host Key against C:\Users\JohnCalvin\.ssh\known_hosts.
Using PuTTY, the terminal program is saving it to the Registry [HKEY_CURRENT_USER\Software\SimonTatham\PuTTY\SshHostKeys].
How do I reconcile the difference between pysftp and PuTTY?
My code is:
import pysftp as sftp
def push_file_to_server():
s = sftp.Connection(host='138.99.99.129', username='root', password='*********')
local_path = "testme.txt"
remote_path = "/home/testme.txt"
s.put(local_path, remote_path)
s.close()
push_file_to_server()
The error response I am receiving is:
E:\Program Files (x86)\Anaconda3\lib\site-packages\pysftp\__init__.py:61:
UserWarning: Failed to load HostKeys from C:\Users\JohnCalvin\.ssh\known_hosts. You will need to explicitly load HostKeys (cnopts.hostkeys.load(filename)) or disableHostKey checking (cnopts.hostkeys = None).
warnings.warn(wmsg, UserWarning)
Traceback (most recent call last):
File "E:\OneDrive\Python\GIT\DigitalCloud\pysftp_tutorial.py", line 14, in <module>
push_file_to_server()
File "E:\OneDrive\Python\GIT\DigitalCloud\pysftp_tutorial.py", line 7, in push_file_to_server
s = sftp.Connection(host='138.99.99.129', username='root', password='********')
File "E:\Program Files (x86)\Anaconda3\lib\site-packages\pysftp\__init__.py", line 132, in __init__
self._tconnect['hostkey'] = self._cnopts.get_hostkey(host)
File "E:\Program Files (x86)\Anaconda3\lib\site-packages\pysftp\__init__.py", line 71, in get_hostkey
raise SSHException("No hostkey for host %s found." % host) paramiko.ssh_exception.SSHException: No hostkey for host 138.99.99.129 found.
Exception ignored in: <bound method Connection.__del__ of <pysftp.Connection object at 0x00000222FF3A6BE0>>
Traceback (most recent call last):
File "E:\Program Files (x86)\Anaconda3\lib\site-packages\pysftp\__init__.py", line 1013, in __del__
self.close()
File "E:\Program Files (x86)\Anaconda3\lib\site-packages\pysftp\__init__.py", line 784, in close
if self._sftp_live:
AttributeError: 'Connection' object has no attribute '_sftp_live'
The pysftp has some bugs regarding host key handling, as described below. It also seems that the pysftp project was abandoned. Consider using Paramiko directly instead. The pysftp is just a wrapper on top of Paramiko and it does not add anything really significant. See pysftp vs. Paramiko.
For handling of host keys in Paramiko, see:
Paramiko "Unknown Server"
If you want to keep using pysftp, do not set cnopts.hostkeys = None (as the second most upvoted answer shows), unless you do not care about security. You lose a protection against Man-in-the-middle attacks by doing so.
Use CnOpts.hostkeys (returns HostKeys) to manage trusted host keys.
cnopts = pysftp.CnOpts(knownhosts='known_hosts')
with pysftp.Connection(host, username, password, cnopts=cnopts) as sftp:
where the known_hosts contains a server public key(s)] in a format like:
example.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQAB...
If you do not want to use an external file, you can also use
from base64 import decodebytes
# ...
keydata = b"""AAAAB3NzaC1yc2EAAAADAQAB..."""
key = paramiko.RSAKey(data=decodebytes(keydata))
cnopts = pysftp.CnOpts()
cnopts.hostkeys.add('example.com', 'ssh-rsa', key)
with pysftp.Connection(host, username, password, cnopts=cnopts) as sftp:
Though as of pysftp 0.2.9, this approach will issue a warning, what seems like a bug:
"Failed to load HostKeys" warning while connecting to SFTP server with pysftp
An easy way to retrieve the host key in the needed format is using OpenSSH ssh-keyscan:
$ ssh-keyscan example.com
# example.com SSH-2.0-OpenSSH_5.3
example.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQAB...
(due to a bug in pysftp, this does not work, if the server uses non-standard port – the entry starts with [example.com]:port + beware of redirecting ssh-keyscan to a file in PowerShell)
You can also make the application do the same automatically:
Use Paramiko AutoAddPolicy with pysftp
(It will automatically add host keys of new hosts to known_hosts, but for known host keys, it will not accept a changed key)
Though for an absolute security, you should not retrieve the host key remotely, as you cannot be sure, if you are not being attacked already.
See my article Where do I get SSH host key fingerprint to authorize the server?
It's for my WinSCP SFTP client, but most information there is valid in general.
If you need to verify the host key using its fingerprint only, see Python - pysftp / paramiko - Verify host key using its fingerprint.
One option is to disable the host key requirement:
import pysftp
cnopts = pysftp.CnOpts()
cnopts.hostkeys = None
with pysftp.Connection(host, username, password, cnopts=cnopts) as sftp:
sftp.put(local_path, remote_path)
You can find more info about that here:
https://stackoverflow.com/a/38355117/1060738
Important note:
By setting cnopts.hostkeys=None you'll lose the protection against Man-in-the-middle attacks by doing so. Use #martin-prikryl answer to avoid that.
Try to use the 0.2.8 version of pysftp library.
$ pip uninstall pysftp && pip install pysftp==0.2.8
And try with this:
try:
ftp = pysftp.Connection(host, username=user, password=password)
except:
print("Couldn't connect to ftp")
return False
Why this?
Basically is a bug with the 0.2.9 of pysftp
here all details
https://github.com/Yenthe666/auto_backup/issues/47
Cook book to use different ways of pysftp.CnOpts() and hostkeys options.
Source : https://pysftp.readthedocs.io/en/release_0.2.9/cookbook.html
Host Key checking is enabled by default. It will use ~/.ssh/known_hosts by default. If you wish to disable host key checking (NOT ADVISED) you will need to modify the default CnOpts and set the .hostkeys to None.
import pysftp
cnopts = pysftp.CnOpts()
cnopts.hostkeys = None
with pysftp.Connection('host', username='me', password='pass', cnopts=cnopts):
# do stuff here
To use a completely different known_hosts file, you can override CnOpts looking for ~/.ssh/known_hosts by specifying the file when instantiating.
import pysftp
cnopts = pysftp.CnOpts(knownhosts='path/to/your/knownhostsfile')
with pysftp.Connection('host', username='me', password='pass', cnopts=cnopts):
# do stuff here
If you wish to use ~/.ssh/known_hosts but add additional known host keys you can merge with update additional known_host format files by using .load method.
import pysftp
cnopts = pysftp.CnOpts()
cnopts.hostkeys.load('path/to/your/extra_knownhosts')
with pysftp.Connection('host', username='me', password='pass', cnopts=cnopts):
# do stuff here
If You try to connect by pysftp to "normal" FTP You have to set hostkey to None.
import pysftp
cnopts = pysftp.CnOpts()
cnopts.hostkeys = None
with pysftp.Connection(host='****',username='****',password='***',port=22,cnopts=cnopts) as sftp:
print('DO SOMETHING')
Connect to the server first with a Windows ssh client that uses the known_hosts file.
PuTTy stores the data in the windows registry,however OpenSSH uses the known_hosts file, and will add entries in there after you connect.
Default location for the file is %USERPROFILE%.ssh. I hope this helps
I've implemented auto_add_key in my pysftp github fork.
auto_add_key will add the key to known_hosts if auto_add_key=True
Once a key is present for a host in known_hosts this key will be checked.
Please reffer Martin Prikryl -> answer about security concerns.
Though for an absolute security, you should not retrieve the host key remotely, as you cannot be sure, if you are not being attacked already.
import pysftp as sftp
def push_file_to_server():
s = sftp.Connection(host='138.99.99.129', username='root', password='pass', auto_add_key=True)
local_path = "testme.txt"
remote_path = "/home/testme.txt"
s.put(local_path, remote_path)
s.close()
push_file_to_server()
Note: Why using context manager
import pysftp
with pysftp.Connection(host, username="whatever", password="whatever", auto_add_key=True) as sftp:
#do your stuff here
#connection closed
Hi We sort of had the same problem if I understand you well. So check what pysftp version you're using. If it's the latest one which is 0.2.9 downgrade to 0.2.8.
Check this out. https://github.com/Yenthe666/auto_backup/issues/47
FWIR, if authentication is only username & pw, add remote server ip address to known_hosts like ssh-keyscan -H 192.168.1.162 >> ~/.ssh/known_hosts for ref https://www.techrepublic.com/article/how-to-easily-add-an-ssh-fingerprint-to-your-knownhosts-file-in-linux/

How do I get a publickey out of my .pem file

When I ran my python code (using parmiko library python) I got this error:
Bad authentication type; allowed types: ['publickey', 'gssapi-keyex',
'gssapi-with-mic']
The path I supplied was to a .pem file which was my key to the server.
How do I get a public key out of this .pem file not necessarily using python?
(I am using a mac)
Here is the code I used:
import paramiko
def file_move():
k = paramiko.RSAKey.from_private_key_file("Insertadress")
c = paramiko.SSHClient()
c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
print ("connecting...")
c.connect(hostname = "inserthostname", username = None, password = "insert pw" ,pkey = k)
print ("connected!!!")
stdin, stdout, stderr = c.exec_command('ls')
c.close()
file_move()
Paramiko does not seem to have an API for extracting the public key from a private key, but since you are welcoming non-Python solutions too, here is a command line version:
ssh-keygen -y -f myprivatekey
where myprivatekey is the file containing your private key (named Insertaddress in the question).
This outputs the public key on standard output.
Tested on Linux (where the command is provided by the package openssh-client), but should work on a Mac too.

How to sftp connect through Paramiko with public key - python [duplicate]

I'm using Paramiko to connect through SSH to a server.
Basic authentication works well, but I can't understand how to connect with public key.
When I connect with PuTTY, the server tell me this:
Using username "root".
Authenticating with public key "rsa-key#ddddd.com"
Passphrase for key "rsa-key#ddddd.com": [i've inserted the passphrase here]
Last login: Mon Dec 5 09:25:18 2011 from ...
I connect to it with this ppk file:
PuTTY-User-Key-File-2: ssh-rsa
Encryption: aes256-cbc
Comment: rsa-key#dddd.com
Public-Lines: 4
[4 lines key]
Private-Lines: 8
[8 lines key]
Private-MAC: [hash]
With basic auth the error I get (from the log) is:
DEB [20111205-09:48:44.328] thr=1 paramiko.transport: userauth is OK
DEB [20111205-09:48:44.927] thr=1 paramiko.transport: Authentication type (password) not permitted.
DEB [20111205-09:48:44.927] thr=1 paramiko.transport: Allowed methods: ['publickey', 'gssapi-with-mic']
I've tried to include that ppk file and set to auth_public_key, but didn't work.
Can you help me?
Ok #Adam and #Kimvais were right, Paramiko cannot parse .ppk files.
So the way to go (thanks to #JimB too) is to convert .ppk file to OpenSSH private key format; this can be achieved using PuTTYgen as described here.
Then it's very simple getting connected with it:
import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('<hostname>', username='<username>', password='<password>', key_filename='<path/to/openssh-private-key-file>')
stdin, stdout, stderr = ssh.exec_command('ls')
print stdout.readlines()
ssh.close()
For me I doing this:
import paramiko
hostname = 'my hostname or IP'
myuser = 'the user to ssh connect'
mySSHK = '/path/to/sshkey.pub'
sshcon = paramiko.SSHClient() # will create the object
sshcon.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # no known_hosts error
sshcon.connect(hostname, username=myuser, key_filename=mySSHK) # no passwd needed
works for me pretty ok
To create a valid DSA format private key supported by Paramiko in Puttygen.
Click on Conversions then Export OpenSSH Key
#VonC's answer to (deleted) duplicate question:
If, as commented, Paraminko does not support PPK key, the official solution, as seen here, would be to use PuTTYgen.
But you can also use the Python library CkSshKey to make that same conversion directly in your program.
See "Convert PuTTY Private Key (ppk) to OpenSSH (pem)"
import sys
import chilkat
key = chilkat.CkSshKey()
# Load an unencrypted or encrypted PuTTY private key.
# If your PuTTY private key is encrypted, set the Password
# property before calling FromPuttyPrivateKey.
# If your PuTTY private key is not encrypted, it makes no diffference
# if Password is set or not set.
key.put_Password("secret")
# First load the .ppk file into a string:
keyStr = key.loadText("putty_private_key.ppk")
# Import into the SSH key object:
success = key.FromPuttyPrivateKey(keyStr)
if (success != True):
print(key.lastErrorText())
sys.exit()
# Convert to an encrypted or unencrypted OpenSSH key.
# First demonstrate converting to an unencrypted OpenSSH key
bEncrypt = False
unencryptedKeyStr = key.toOpenSshPrivateKey(bEncrypt)
success = key.SaveText(unencryptedKeyStr,"unencrypted_openssh.pem")
if (success != True):
print(key.lastErrorText())
sys.exit()

how to use a paramiko.PKey() in the .connect() method?

I would like to connect to an ssh server using an OpenSSH key passed to paramiko's .connect() method.
The following code raises paramiko.ssh_exception.AuthenticationException: Authentication failed. on .connect() even though the key looks correct:
import paramiko
# the key below is shortened for readability, it is made of blocks ending with \\n - in other words
# the return-carriage in the original file was replaced with \\n
key = "-----BEGIN RSA PRIVATE KEY-----\\nMIIEpQIBA(...)b+iro=\\n-----END RSA PRIVATE KEY-----\\n"
# this is to dump the key for checking a command-line connection with that key
with open("key.priv", "w") as f:
f.write(key.replace('\\n', '\n'))
key = paramiko.PKey(data=key)
params = {
'hostname': '10.0.0.1',
'port': 22,
'username': 'root',
'look_for_keys': False,
'timeout': 5,
'pkey' : key
}
ssh = paramiko.SSHClient() # Initiate SSH client
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # allow to add unknown ssh key
res = ssh.connect(**params)
Running the code:
Traceback (most recent call last):
File "C:/Users/aa/testsshkey.py", line 19, in <module>
res = ssh.connect(**params)
File "C:\Python27\lib\site-packages\paramiko\client.py", line 307, in connect
look_for_keys, gss_auth, gss_kex, gss_deleg_creds, gss_host)
File "C:\Python27\lib\site-packages\paramiko\client.py", line 519, in _auth
raise saved_exception
paramiko.ssh_exception.AuthenticationException: Authentication failed.
Process finished with exit code 1
I tried to have \\n and well as \n in key, no changes (both are accepted by paramiko.PKey()).
The code above also dumps the key to a file to test a command-line ssh connection, which succeeds:
host1$ chmod 600 key.priv
host1$ ssh root#10.0.0.1 -i key.priv
root#host2 #
Is there a specific format for the key to be passed to paramiko.PKey()? Its docs claim that
Raises SSHException:
if a key cannot be created from the data or msg given, or no key was passed in.
which does not happen in my case (therefore I assume that the format of the key is acceptable Edit: I checked with a random string and the "key" is still accepted, so no checks are made on the correctness of the key)
I found the solution using help from another answer:
# note the single backslash in \n
key = "-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAKCAQEAwK(...)J90XccMb+iro=\n-----END RSA PRIVATE KEY-----\n"
keyfile = StringIO.StringIO(key)
key = paramiko.RSAKey.from_private_key(keyfile)
key can now be passed to the parameters as per the code in the question

Categories

Resources