10

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.

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
scottyp
  • 295
  • 1
  • 4
  • 13

3 Answers3

24

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

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
teegaar
  • 876
  • 9
  • 19
  • Works perfectly! Thanks teegaar :) BTW, do you think this kind of private key embed is safe? Or do you have other suggestions (like using public key instead) that works with paramiko? cheers. – scottyp Dec 28 '14 at 13:44
  • scottyp, I think it is not safe as you store your key in the executable. You may take measures to make it harder to reveal the key but anyway it won't be totally safe. – teegaar Dec 28 '14 at 14:31
  • key = paramiko.RSAKey(data=base64.b64decode('AAblablabla...')) does not work,it throws "paramiko.ssh_exception.SSHException: Invalid key (class: RSAKey, data type: -BEGIN OPENSSH PRIVATE KEY-----" – focus zheng Apr 20 '23 at 06:32
2

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)
Henry Ecker
  • 34,399
  • 18
  • 41
  • 57
Kush-Work
  • 21
  • 2
  • Hi, nice first answer! Please clarify or edit your answer if you can, as it says `will escape the '\n' and turn it into '\n'` which is the same value. – Mmm Feb 12 '23 at 15:31
-1

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)