104

How do you configure fabric to connect to remote hosts using SSH keyfiles (for example, Amazon EC2 instances)?

Yuval Adam
  • 161,610
  • 92
  • 305
  • 395

8 Answers8

154

Finding a simple fabfile with a working example of SSH keyfile usage isn't easy for some reason. I wrote a blog post about it (with a matching gist).

Basically, the usage goes something like this:

from fabric.api import *

env.hosts = ['host.name.com']
env.user = 'user'
env.key_filename = '/path/to/keyfile.pem'

def local_uname():
    local('uname -a')

def remote_uname():
    run('uname -a')

The important part is setting the env.key_filename environment variable, so that the Paramiko configuration can look for it when connecting.

Yuval Adam
  • 161,610
  • 92
  • 305
  • 395
  • 4
    in the practice this is the better answer. – panchicore Oct 31 '12 at 20:17
  • 3
    `env.key_filename` [can contain a list of strings](http://docs.fabfile.org/en/latest/usage/env.html#key-filename) to try multiple keyfiles for a connection. – Carl G Apr 22 '14 at 12:29
  • 2
    I was setting the key programmatically in one of my tasks using the `settings` context manager and couldn't get it to recognize the key_filename until I changed `key_filename='/path/to/key'` to `key_filename=['/path/to/key']` so if anyone else is having trouble, making key_filename a list of keys might fix it. This is with fab 1.10.1 and Paramiko 1.15.2 – Jaymon May 05 '15 at 00:04
  • fabric.api doesnt exist – Aseem Jun 13 '18 at 14:27
  • 3
    @AseemHegshetye, It was removed in the latest Fabric 2. This answer is for Fabric 1. – Iulian Onofrei Aug 18 '18 at 22:06
  • 1
    I'd prefer explicit imports instead of import * – mit Oct 19 '18 at 12:05
  • can someone mention the explicit imports in this scenario? – karthik v Jan 17 '19 at 15:29
  • Despite defining the env.hosts = ['host-name.fqdn-format']. Following input is asked: No hosts found. Please specify (single) host string for connection: – karthik v Jan 17 '19 at 15:32
70

Also worth mentioning here that you can use the command line args for this:

fab command -i /path/to/key.pem [-H [user@]host[:port]]
Thomas
  • 6,515
  • 1
  • 31
  • 47
  • This didn't work for me, adding the SSH key to my keychain did however, by running ` eval 'ssh-agent' ` (<- use backticks here, not quotes) first and then `ssh-add /path/to/key.pem`. After that I could run fab without the -i flag. – Raoul Mar 10 '21 at 09:54
67

Another cool feature available as of Fabric 1.4 - Fabric now supports SSH configs.

If you already have all the SSH connection parameters in your ~/.ssh/config file, Fabric will natively support it, all you need to do is add:

env.use_ssh_config = True

at the beginning of your fabfile.

Yuval Adam
  • 161,610
  • 92
  • 305
  • 395
  • 2
    Very useful! If you run into errors like `IOError: [Errno 2] No such file or directory: ' /path/to/.ssh/key'` or `Login password for ' root':` just make sure you have no whitespaces in your `.ssh/config`. It's for example `User=root` instead of `User = root`... – dennis Dec 13 '13 at 12:39
  • @dennis This still seems to be an issue in 2016..! Thanks! – gabn88 Nov 08 '16 at 14:12
21

For fabric2 in fabfile use the following:

from fabric import task, Connection

@task
def staging(ctx):
    ctx.name = 'staging'
    ctx.user = 'ubuntu'
    ctx.host = '192.1.1.1'
    ctx.connect_kwargs.key_filename = os.environ['ENV_VAR_POINTS_TO_PRIVATE_KEY_PATH']

@task
def do_something_remote(ctx):
    with Connection(ctx.host, ctx.user, connect_kwargs=ctx.connect_kwargs) as conn:
        conn.sudo('supervisorctl status')

and run it with:

fab staging do_something_remote

UPDATE:
For multiple hosts (one host will do also) you can use this:

from fabric2 import task, SerialGroup

@task
def staging(ctx):
    conns = SerialGroup(
        'user@10.0.0.1',
        'user@10.0.0.2',
        connect_kwargs=
        {
            'key_filename': os.environ['PRIVATE_KEY_TO_HOST']
        })
    ctx.CONNS = conns
    ctx.APP_SERVICE_NAME = 'google'

@task
def stop(ctx):
    for conn in ctx.CONNS:
        conn.sudo('supervisorctl stop ' + ctx.APP_SERVICE_NAME)

and run it with fab or fab2:

fab staging stop
MikeL
  • 5,385
  • 42
  • 41
15

For me, the following didn't work:

env.user=["ubuntu"]
env.key_filename=['keyfile.pem']
env.hosts=["xxx-xx-xxx-xxx.ap-southeast-1.compute.amazonaws.com"]

or

fab command -i /path/to/key.pem [-H [user@]host[:port]]

However, the following did:

env.key_filename=['keyfile.pem']
env.hosts=["ubuntu@xxx-xx-xxx-xxx-southeast-1.compute.amazonaws.com"]

or

env.key_filename=['keyfileq.pem']
env.host_string="ubuntu@xxx-xx-xxx-xxx.ap-southeast-1.compute.amazonaws.com"
Gaurav Toshniwal
  • 3,552
  • 2
  • 24
  • 23
7

I had to do this today, my .py file was as simple as possible, like the one posted in the answer of @YuvalAdam but still I kept getting prompted for a password...

Looking at the paramiko (the library used by fabric for ssh) log, I found the line:

Incompatible ssh peer (no acceptable kex algorithm)

I updated paramiko with:

sudo pip install paramiko --upgrade

And now it's working.

flagg19
  • 1,782
  • 2
  • 22
  • 27
2

None of these answers worked for me on py3.7, fabric2.5.0 and paramiko 2.7.1.

However, using the PKey attribute in the documentation does work: http://docs.fabfile.org/en/2.5/concepts/authentication.html#private-key-objects

from paramiko import RSAKey
ctx.connect_kwargs.pkey = RSAKey.from_private_key_file('path_to_your_aws_key')
with Connection(ctx.host, user, connect_kwargs=ctx.connect_kwargs) as conn:
    //etc.... 
Keith Entzeroth
  • 2,049
  • 1
  • 18
  • 22
1

As stated above, Fabric will support .ssh/config file settings after a fashion, but using a pem file for ec2 seems to be problematic. IOW a properly setup .ssh/config file will work from the command line via 'ssh servername' and fail to work with 'fab sometask' when env.host=['servername'].

This was overcome by specifying the env.key_filename='keyfile' in my fabfile.py and duplicating the IdentityFile entry already in my .ssh/config.

This could be either Fabric or paramiko, which in my case was Fabric 1.5.3 and Paramiko 1.9.0.

Jeff Doran
  • 11
  • 1