An improved version of gcloud compute config-ssh, a convenient way to setup connectivity to your virtual machines hosted within GCP.
gcloud_sync_ssh
An improved version of gcloud compute config-ssh
, a convenient way to setup connectivity to your virtual machines hosted within GCP.
This tools has some benefits:
And some drawbacks:
I’ve used it for a couple of months for my modest needs and it did the job flawlessly. YMMV - see ‘Limitations’ below.
pipx install gcloud_sync_ssh
pyenv virtualenv 3.6 gcloud_sync_ssh
pip install -r requirements.txt
python -m gcloud_sync_ssh
gcloud_sync_ssh --help
The tool works in four phases. It optionally changes the gcloud authentication context, then it enumerates projects and instances, then it updates your SSH config in memory and finally saves it after making a backup and showing you the diff.
By default, gcloud_sync_ssh
edits the standard ~/.ssh/config
. This will be fine for most uses. It may be changed with -c/--config
.
Some people prefer the tool to operate on an isolated file, like ~/.ssh/config.auto
. A few things to keep in mind if you go down that path:
chmod 0600 ~/.ssh/config.auto
for SSH to read itInclude ~/.ssh/config.auto
to your existing ~/.ssh/config
before any Match
or Host
block.ssh -F ~/.ssh/config.auto
instead of setting up the Include
.First it will optionally change your gcloud
authentication context as desired, using the--login
option for email accounts or --service-account
option for service accounts.
If none of these options are specified, gcloud_sync_ssh
will not touch modify your gcloud
authentication settings - and will function with your current settings.
Your current settings will be restored once the tools exits.
Be aware that authentication is a user-level setting. When using special authentication, avoid running gcloud
while gcloud_sync_ssh
is running. This also applies to other tools that piggy back on gcloud auth, like Terraform gcloud backend in application-default mode.
You may select a project with the --project
option. This option can be specified several times to select multiple projects. This option accepts fnmatch
-style globbing (i.e. using *
, ?
…).
--project my-project-name
--project project-web-1 --project-web-2
--project 'project-web-*'
(Beware shell quoting rules for globbing characters)--all-projects
There are quite a few cases to consider.
The simplest case is updates : running instances already in your configuration, but the external IP changes.
Your configuration will be updated in place and nothing else will change. There are no options controlling this behavior.
Then we have deletions:
STOPPED
status will be removed from your configuration. You can disable this using the -nrs|--no-remove-stopped
flag..<project-name>
. You can disable that using the -nrv|--no-remove-vanished
flag.Finally, we have additions. A new Host
block will be added to your configuration for newly detected instances. The complexity comes from the many ways to specify how that block will be generated. There are two parts to this : the ‘template’ is the set of options that doesn’t change from host to host, and the ‘specifics’ which are the couple of options that are allowed to vary.
The Host
template is computed as such:
--no-inference --debug-template
.Host
block in your config is added to this template. The inferred values override the defaults. You can turn this off by passing the --no-inference
flag. You can see the results of this stage by passing -dt|--debug-template
.-kw/--kwarg
option possibly several times.Here is an exemple of a Host template that overrides defaults :
$ gcloud_sync_ssh --debug-template --no-inference -kw IdentityFile=/secret/id_rsa -kw UserKnownHostsFile=/data/known_hosts
2020-09-07 20:23:18.290 | INFO | Displaying host template
CheckHostIP no
IdentitiesOnly yes
IdentityFile /secret/id_rsa
UserKnownHostsFile /data/known_hosts
2020-09-07 20:23:18.291 | INFO | Done displaying host template
The ‘specifics’ are:
Hostname
kwarg, that will be set to the instance external IP (or first external IP, if there are several). This is the whole point of this tool, and it cannot be controlled by an option.HostKeyAlias
kwarg, that will be set to compute.<instance_id>
. This is what gcloud compute config-ssh
does. This will prevent warnings because of external IP changes. You can disable generating those with -nk|--no-host-key-alias
.You don’t have to blindly trust the tool. By default it will show you the diff and ask for approval before saving - while still saving a backup.
If you want to use it from cron
or CI, this behavior might be counterproductive, so it can be disabled:
--not-interactive
--no-backup
gcloud auth list
)gcloud compute config-ssh
does. Notably, it has consistent space delimiting instead of having =
on some lines and
on others. (Probably won’t fix)Host
. (TODO: Accept Python plugins to allow arbitrarily complex schemes to add/edit SSH config per host).<project-name>
. This is the GCP default. I found no other way to attribute a Host in your SSH config to a given SSH project. Workaround: remove everything with gcloud compute config-ssh --remove
then use gcloud_sync_ssh
as usual. (TODO: Support --overwrite
flag that removes everything in the config block before running)The above are roughly sorted given how concerning they are to me. None are preventing me to achieve my goals with the tool - but some may hinder you.
Using this script to setup connectivity should work well enough for ~hundreds of instances whose external IPs change ~daily. I use it for ~dozens of instances whose IPs change ~daily.
If your external IPs change very frequently, or if you have thousands of instances, this tool can still be a useful crutch, but you may want to look into alternatives.
Here are my thoughts on the subject, ordered by effort required.
.internal
TLD for free. A jumpbox is a way to get access to your instances. [ XXX Other ways ? ]hosts
file or a SSH config file. Store that in Storage at a well known URI. Download that in whichever way you like, then Include
it in your SSH config.kubectl
but that’s okay.Grab a TODO from the Limitations list, an issue or bring your own issue to solve.
If it makes sense, please add tests and make sure they pass with python -m pytest
.
The code contained in this repository is licensed under the terms of the MIT license unless otherwise noted in the source code file.