巧用Python登陆远程服务器

用Python进行远程登陆服务器
这篇文章介绍如何通过使用Paramiko和SCP Python库自动化远程服务器任务 。使用Python来SSH到主机,执行任务,传输文件等 。
paramiko和scp是两个Python库,我们可以一起使用它们来自动化我们想要在远程主机上运行的任务,比如重新启动服务、进行更新或获取日志文件 。
设置SSH密钥
要验证SSH连接,我们需要设置一个私有的RSA SSH密钥(不要与OpenSSH混淆) 。我们可以使用以下命令生成密钥:
$ ssh-keygen -t rsa这将提示我们为密钥提供一个名称 。随便你怎么说:
Generating a public/private rsa key pair. Enter the file in which you wish to save they key (i.e., /home/username/.ssh/id_rsa):接下来,系统将提示您提供一个密码(不必填写) 。
现在我们有了密钥,我们需要将其复制到远程主机 。最简单的方法是使用ssh-copy-id:
$ ssh-copy-id -i ~/.ssh/mykey username@my_remote_host.org 
验证SSH密钥
如果你想检查你已经有哪些密钥,这些可以在你的系统的.ssh目录中找到:
$ cd ~/.ssh我们正在寻找以以下头文件开头的键:
-----BEGIN RSA PRIVATE KEY-----...-----END RSA PRIVATE KEY-----

巧用Python登陆远程服务器

文章插图
 
构造脚本
让我们安装库 。
$ pip3 install paramiko scp在我们编写一些有意义的Python代码之前,还有一件事要做!创建一个配置文件来保存连接到主机所需的变量 。下面是我们进入服务器所需要的基本内容:
  • Host:我们试图访问的远程主机的IP地址或URL 。
  • Username:这是您用于SSH到服务器的用户名 。
  • Passphrase(可选):如果您在创建ssh密钥时指定了一个Passphrase,请在这里指定 。请记住,您的SSH密钥密码短语与您的用户密码不同 。
  • SSH Key:我们前面创建的密钥的文件路径 。在OSX上,它们存在于系统的~/.ssh文件夹 。我们目标的SSH密钥必须有一个附带的密钥,文件扩展名为.pub 。这是我们的公钥;如果您遵循前面的步骤,那么应该已经为您生成了这个文件 。
如果你试图从远程主机上传或下载文件,你需要包含两个额外的变量:
  • Remote Path:文件传输目标的远程目录的路径 。我们可以上传东西到这个文件夹或者下载它的内容 。
  • Local Path:与上述想法相同,但相反 。为了方便起见,我们将使用的本地路径是简单的/data,并包含可爱的狐狸gif的图片 。
现在我们有了创建一个config.py文件所需的一切:
"""Remote host configuration."""from os import environ, pathfrom dotenv import load_dotenv# Load environment variables from .envbasedir = path.abspath(path.dirname(__file__))load_dotenv(path.join(basedir, '.env'))# Read environment variableshost = environ.get('REMOTE_HOST')user = environ.get('REMOTE_USERNAME')ssh_key_filepath = environ.get('SSH_KEY')remote_path = environ.get('REMOTE_PATH')local_file_directory = 'data'新建SSH客户端
我们将创建一个名为RemoteClient的类来处理与远程主机的交互 。在我们搞得太复杂之前,让我们先用config.py中创建的变量实例化RemoteClient类:
"""Client to handle connections and actions executed against a remote host."""class RemoteClient:"""Client to interact with a remote host via SSH & SCP."""def __init__(self, host, user, ssh_key_filepath, remote_path):self.host = hostself.user = userself.ssh_key_filepath = ssh_key_filepathself.remote_path = remote_path 
到目前为止还没有什么令人印象深刻的:我们只是设置了一些变量,并将它们传递到一个无用的类中 。让我们在不离开构造函数的情况下进一步讨论:
 
"""Client to handle connections and actions executed against a remote host."""from paramiko import SSHClient, AutoAddPolicy, RSAKeyfrom paramiko.auth_handler import AuthenticationException, SSHExceptionclass RemoteClient:"""Client to interact with a remote host via SSH & SCP."""def __init__(self, host, user, ssh_key_filepath, remote_path):self.host = hostself.user = userself.ssh_key_filepath = ssh_key_filepathself.remote_path = remote_pathself.client = Noneself.scp = Noneself.conn = Noneself._upload_ssh_key()我们已经添加了三个新东西来实例化我们的类:
self.client = None: self.Client最终将在我们的类中充当连接对象,类似于处理数据库库中的conn等术语 。在显式连接到远程主机之前,我们的连接将为None 。


推荐阅读