Preferable way to automatically update SSH config file using Python?
Asked Answered
F

4

10

I'm using Fabric to automate some of my workflow, most of which involves manipulating EC2 instances.

I'm looking for a way to keep my .ssh/config file up-to-date, as I regularly spin up and shutdown EC2 instances, and it's very helpful to me if I can ssh into them easily for debugging and so on.

Entries within my SSH config file look like this

Host ins_id
Hostname xxxxxxxx.com
User ubuntu
IdentityFile ~/.ssh/kp.pem

At the moment, I'm doing something like the following (making use of Fabric and boto), which is frankly a rubbish approach:

def my_cool_spin_up_function(self):
    . . .
    . . .
    ssh_conf = os.path.join(homedir, '.ssh/config')
    ssh_info = '\n'.join(['Host %s'         % name,
                          'Hostname %s'     % ins.dns_name,
                          'User %s'         % env.user,
                          'IdentityFile %s' % kp_loc,
                          '\n'])
    w_com = 'echo %s | cat - %s | tee %s > /dev/null' % (ssh_info, ssh_conf, ssh_conf)
    local(w_com)

As you can see, this will just keep prepending to my config file every time it's called, which is fine, because SSH takes the first section for each Host in config, but it means the file builds up and up. . .

I'm wondering if there are any Python libraries that allow one to treat .ssh/config as a more of a configuration file, whose relevant parts can be updated as and when. For example, it would be brilliant if you could simply treat .ssh/config as a dictionary and abstract away the file reading/writing. . .

Thanks for any suggestions!

Flexor answered 6/12, 2011 at 15:53 Comment(1)
Did you decide on a better approach?Beekeeper
C
10

What we do for this sort of configuration is maintain a directory of configuration fragments, which can be added/removed as necessary, and then doing something along the lines of:

cat .ssh/config.d/* > .ssh/config

This will append things in lexical order, which means the ordering depends on how you elect to name your files. This makes it very easy to expire old configurations, remove specific items, and otherwise control the config file.

Cautery answered 6/12, 2011 at 16:30 Comment(1)
I guess this is a step up from what I'm doing, but it's still not ideal. . .Flexor
Z
3

This thread many years old but let me give a shot at this as I had the same problem and the thread has no accepted solution.

I ended up using the Include feature on ssh_config

     Include
             Include the specified configuration file(s).  Multiple pathnames may be specified and each pathname may contain glob(7) wildcards and, for user configurations, shell-like
             ‘~’ references to user home directories.  Files without absolute paths are assumed to be in ~/.ssh if included in a user configuration file or /etc/ssh if included from the
             system configuration file.  Include directive may appear inside a Match or Host block to perform conditional inclusion.

So in my main ~/.ssh/config I have the default options and then at the TOP - because of these issues there is one line

Include ~/.ssh/config.d/*
...
(rest of the file)

These two files are generated automatically from a bash script running out of crontab using aws and gcloud, the command line tools from the cloud providers.

The advantage of this method is that it does not touch your .ssh/config file as it might contain sensitive entries that you do not want messed up.

Zaneta answered 24/2, 2023 at 21:29 Comment(0)
M
1

I had a similar issue and am now using this Python package to solve it. https://github.com/emileindik/slosh

$ pip install slosh
$ slosh [email protected] --save-as myserver

This will perform the desired ssh connection and also create an entry in your SSH config file that looks like

Host=myserver
    HostName=1.1.1.1
    User=ubuntu

The same entry can be updated by using the same alias name. For example, adding a .pem file to the connection:

$ slosh -i ~/.ssh/mykey.pem [email protected] --save-as myserver

It currently supports a number of ssh options but let me know if there additional options that should be added!

[disclaimer] I created slosh

Mcdougald answered 12/3, 2024 at 23:50 Comment(0)
F
0

How about something like this:

class SSHConfig(object):

    def __init__(self, filename=None):
        if filename is not None:
            self.read(filename)
        else:
            self.conf = dict()

    def read(self, filename):
        self.conf = dict(line.decode("utf-8").rstrip().split(" ", 1) for line in open(filename)) 

    def write(self, filename):
        with open(filename, "w") as f:
            for key, value in self.conf.items():
                f.write("%s %s\n".encode("utf-8") % (key, value))

    def set(self, key, value):
        self.conf[key] = value

    def get(self, key):
        return self.conf.get(key, None)
Form answered 6/12, 2011 at 16:32 Comment(2)
I get the idea but this wouldn't work for multiple sections in the config file, because of the way you're storing things in conf. I think I may write a small Python module along these lines though if no-one shows me an already available solution. . . Thanks.Flexor
@Flexor - Did you do this in the end? I am looking for something similar.Emmalynne

© 2022 - 2025 — McMap. All rights reserved.