在Fabric中使用SSH密钥文件

问题:在Fabric中使用SSH密钥文件

如何配置结构以使用SSH密钥文件连接到远程主机(例如,Amazon EC2实例)?

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


回答 0

在这里还值得一提的是,您可以为此使用命令行参数:

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

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]]

回答 1

由于某种原因,要找到一个简单的fabfile以及一个使用SSH密钥文件的有效示例并不容易。我写了一篇有关它的博客文章带有匹配的要点)。

基本上,用法是这样的:

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')

重要的是设置env.key_filename环境变量,以便Paramiko配置在连接时可以查找它。

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.


回答 2

从Fabric 1.4开始提供的另一个很酷的功能-Fabric现在支持SSH配置

如果您的文件中已经包含所有SSH连接参数~/.ssh/config,Fabric将本地支持它,您只需添加:

env.use_ssh_config = True

在fabfile的开头。

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.


回答 3

对于fabfile中的fabric2,请使用以下命令:

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')

并运行:

fab staging do_something_remote

更新:
对于多个主机(一个主机也可以),您可以使用以下命令:

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)

并使用fab或fab2运行它:

fab staging stop

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

回答 4

对我来说,以下方法无效:

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

要么

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

但是,执行以下操作:

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

要么

env.key_filename=['keyfileq.pem']
env.host_string="ubuntu@xxx-xx-xxx-xxx.ap-southeast-1.compute.amazonaws.com"

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"

回答 5

我今天必须这样做,我的.py文件尽可能简单,就像在@YuvalAdam答案中发布的文件一样,但仍然不断提示输入密码…

查看paramiko(fabric用于ssh的库)日志,发现以下行:

不兼容的SSH节点(没有可接受的KEX算法)

我更新paramiko了:

sudo pip install paramiko --upgrade

现在它正在工作。

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.


回答 6

如上所述,Fabric将在某种形式之后支持.ssh / config文件设置,但是将pem文件用于ec2似乎是有问题的。IOW一个正确设置的.ssh / config文件将通过“ ssh服务器名”从命令行运行,并且当env.host = [‘服务器名’]时无法与“ fab sometask”一起工作。

通过在我的fabfile.py中指定env.key_filename =’keyfile’并复制我的.ssh / config中已经存在的IdentityFile条目,可以解决此问题。

这可以是Fabric或paramiko,在我的情况下是Fabric 1.5.3和Paramiko 1.9.0。

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.


回答 7

这些答案对py3.7,fabric2.5.0和paramiko 2.7.1都不起作用。

但是,使用文档中的PKey属性确实可以: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.... 

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....