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
Related
I'm trying to create a single file executable in Python and using Paramiko for my SSH. I need to eliminate external files such as private key files and try to go for embedded strings.
I tried this solution but it's not working for me:
Paramiko: Creating a PKey from a public key string
How do I accomplish this? Thanks.
The solution you mentioned:
key = paramiko.RSAKey(data=base64.b64decode('AAblablabla...'))
works fine however it may be inconvenient to store the key in base64 format.
The following code shows how to use the key stored in "plain-text" format (as key-files in ~/.ssh directory):
import paramiko
import StringIO
my_key = """\
-----BEGIN RSA PRIVATE KEY-----
<your key here>
-----END RSA PRIVATE KEY-----"""
pkey = paramiko.RSAKey.from_private_key(StringIO.StringIO(my_key))
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname='host', username='user', pkey=pkey)
...
ssh.close()
In Python 3:
import io
# ...
pkey = paramiko.RSAKey.from_private_key(io.StringIO(my_key))
See StringIO in Python3
I had the same issue where I'm trying to not have private key files using AWS secrets manager, just got it to work with the following. Notice the \n in the privatekey.
import io
privatekey = io.StringIO('-----BEGIN OPENSSH PRIVATE KEY-----\nRestOfTheKey\n-----END OPENSSH PRIVATE KEY-----')
pkey = paramiko.Ed25519Key.from_private_key(privatekey)
Then when you're connecting
aws_ssh = paramiko.SSHClient()
aws_ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
aws_ssh.connect(hostname='YOURHOST', username='YOURUSERNAME', pkey=pkey)
Now, however, if you're like me and using this for Lambda+Secrets Manager, and the secrets manager has a key+value and you're pulling the value of this privatekey from there. One thing to note is that secrets manager will escape the \n and turn it into \\n. To fix that, modify the above code to replace the \\n to \n.
awskeytemp = secrets['YOURKEY'].replace('\\n', '\n')
privatekey = io.StringIO(awskeytemp)
pkey = paramiko.Ed25519Key.from_private_key(privatekey)
To add a public key from a string on the ssh client you must set the keyword arg look_for_keys=False then use the MissingHostKeyPolicy classes missing_host_key() method to add the key from your string.
my_pub_key = "xx.xx.xx.xx ecdsa-sha2-nistp256 mlzdHAyNT....."
my_host = my_pub_key.split(' ')[0]
password = 'myFavortitePassword'
username = 'myUsername'
ssh_client=paramiko.SSHClient()
host_key_policy = paramiko.MissingHostKeyPolicy()
host_key_policy.missing_host_key(ssh_client, my_host, my_pub_key)
ssh_client.connect(hostname= my_host
,username=username
,password=password
,port=22
,look_for_keys=False)
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 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
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()
I'm trying to create a single file executable in Python and using Paramiko for my SSH. I need to eliminate external files such as private key files and try to go for embedded strings.
I tried this solution but it's not working for me:
Paramiko: Creating a PKey from a public key string
How do I accomplish this? Thanks.
The solution you mentioned:
key = paramiko.RSAKey(data=base64.b64decode('AAblablabla...'))
works fine however it may be inconvenient to store the key in base64 format.
The following code shows how to use the key stored in "plain-text" format (as key-files in ~/.ssh directory):
import paramiko
import StringIO
my_key = """\
-----BEGIN RSA PRIVATE KEY-----
<your key here>
-----END RSA PRIVATE KEY-----"""
pkey = paramiko.RSAKey.from_private_key(StringIO.StringIO(my_key))
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname='host', username='user', pkey=pkey)
...
ssh.close()
In Python 3:
import io
# ...
pkey = paramiko.RSAKey.from_private_key(io.StringIO(my_key))
See StringIO in Python3
I had the same issue where I'm trying to not have private key files using AWS secrets manager, just got it to work with the following. Notice the \n in the privatekey.
import io
privatekey = io.StringIO('-----BEGIN OPENSSH PRIVATE KEY-----\nRestOfTheKey\n-----END OPENSSH PRIVATE KEY-----')
pkey = paramiko.Ed25519Key.from_private_key(privatekey)
Then when you're connecting
aws_ssh = paramiko.SSHClient()
aws_ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
aws_ssh.connect(hostname='YOURHOST', username='YOURUSERNAME', pkey=pkey)
Now, however, if you're like me and using this for Lambda+Secrets Manager, and the secrets manager has a key+value and you're pulling the value of this privatekey from there. One thing to note is that secrets manager will escape the \n and turn it into \\n. To fix that, modify the above code to replace the \\n to \n.
awskeytemp = secrets['YOURKEY'].replace('\\n', '\n')
privatekey = io.StringIO(awskeytemp)
pkey = paramiko.Ed25519Key.from_private_key(privatekey)
To add a public key from a string on the ssh client you must set the keyword arg look_for_keys=False then use the MissingHostKeyPolicy classes missing_host_key() method to add the key from your string.
my_pub_key = "xx.xx.xx.xx ecdsa-sha2-nistp256 mlzdHAyNT....."
my_host = my_pub_key.split(' ')[0]
password = 'myFavortitePassword'
username = 'myUsername'
ssh_client=paramiko.SSHClient()
host_key_policy = paramiko.MissingHostKeyPolicy()
host_key_policy.missing_host_key(ssh_client, my_host, my_pub_key)
ssh_client.connect(hostname= my_host
,username=username
,password=password
,port=22
,look_for_keys=False)