Contents

通过SSH在远程计算机上运行shell脚本

1. 概述

作为系统管理员,我们经常会远程管理不同类型的服务器。在远程机器上执行脚本成为有效服务器管理的基本要求。值得注意的是,只有少数主要使用的远程管理工具可以从远程服务器获取数据。这些被广泛用于管理数百个远程服务器,以便于编排。

本教程将阐述在远程机器上执行脚本的最简单方法,将 Linux 和 Windows 都视为本地机器。

2. SSH

SSH 代表 Secure Shell,是一种加密网络协议,在 OSI 模型的第 7 层运行,用于在不安全的网络上提供安全的网络服务。它在 TCP 端口 22 上运行,最新版本为 SSHv2。

它具有许多有趣的功能,例如在远程服务器上运行命令、端口转发、隧道等。最初,客户端开始与服务器协商。然后,服务器进一步发送其公共交换密钥以调用通道并协商其他参数。协商成功后,显示服务器主机操作系统的登录提示。此外,端到端数据传输以加密形式进行。

在这里,我们将使用 SSH 模块在远程机器上执行脚本。

2.1.使用用户交互 SSH

为了便于说明,我们在本文中使用以下 BASH 脚本。它提取远程机器的基本详细信息,如主机名、IP 地址、日期和当前用户 ID:

#!/bin/bash
echo "CURRENT TIME = "`date`
echo "HOSTNAME = "`hostname`
echo "USER id = "`whoami`
echo "IP ADDRESS = "`ip a s enp0s3 | grep "inet " | cut -f6 -d" "`

首先,该命令将使用 SSH 登录远程框,然后在 Shell 中执行 bash 命令。bash 的“s”选项有助于从标准输入中读取可执行命令:

local-machine# ssh tools@192.168.56.103 'bash -s' < get_host_info.sh
tools@192.168.56.103's password:
CURRENT TIME = Sun Oct 3 18:29:38 IST 2021
HOSTNAME = REMOTE-SERVER
USER id = tools
IP ADDRESS = 192.168.56.103/24

2.2. 使用非交互式 SSH

不用说,每次都输入密码会很麻烦,在这种情况下,使用sshpass包并根据命令传递凭据。这是一个飞行黑客,提供了一种访问远程盒子的简单方法:

local-machine# sshpass -vvv -p [[email protected]](/cdn_cgi/l/email_protection) ssh tools@192.168.56.103 'bash -s' < get_host_info.sh
SSHPASS searching for password prompt using match "assword"
SSHPASS read: tools@192.168.56.103's password:
SSHPASS detected prompt. Sending password.
SSHPASS read:
CURRENT TIME = Sun Oct 3 18:42:23 IST 2021
HOSTNAME = REMOTE-SERVER
USER id = tools
IP ADDRESS = 192.168.56.103/24
local-machine#

在上面的详细片段中,sshpass正在搜索密码模式(没有 P/p – “assword”),它在其中向ssh提示符提供密码。要从文件中提供密码,我们可以使用sshpass的“-f”选项。它通过提供密码来支持ssh,但它不能取代ssh命令:

/uploads/run_shell_script_remote_ssh/1.jpg

3. 点链接

plink是适用于 Windows 平台的开源免费 SSH 客户端。它是在远程机器上自动执行 SSH 操作的最安全、干净和方便的方法。默认情况下,它使用 SSH 协议来远程管理 UNIX 机器。但除此之外,它还有其他选项,如 telnet、rlogin、raw 和 serial。最重要的是,plink足够灵活,可以轻松地与通过 SSH 远程执行脚本的 Windows 批处理脚本集成。

事不宜迟,让我们开始行动吧。

在这里,为了说明起见,我们部署了一个plink 0.62 版本:

C:\Users\blogdemo.01\Downloads>.\plink -V
plink: Release 0.62

get_host_info脚本放置在本地Windows机器中,如下图:

C:\Users\blogdemo.01\Downloads>dir | findstr get_host_info
03-10-2021    03:49    166    get_host_info.sh

为了更好地说明,让我们使用选项*-v获取命令的详细输出。在这里,我们将通信协议强制为 SSH,并在选项-m*下给出脚本名称:

C:\Users\blogdemo.01\Downloads>.\plink.exe -v -ssh tools@192.168.56.103 -m get_host_info.sh
Looking up host "192.168.56.103"
Connecting to 192.168.56.103 port 22
Server version: SSH-2.0-OpenSSH_7.6p1 Ubuntu-4ubuntu0.5
Using SSH protocol version 2
We claim version: SSH-2.0-PuTTY_Release_0.62
...
output truncated
...

首先,它从第 3 层 IP 可达性检查开始,并使用端口号 22 建立会话。其次,SSH 版本 2 是版本协商成功后的首选版本:

...
output truncated
...
Using Diffie-Hellman with standard group "group14"
Doing Diffie-Hellman key exchange with hash SHA-1
Host key fingerprint is:
ssh-rsa 2048 1e:77:e1:d2:eb:32:6b:b1:f9:cb:72:fe:ef:e6:a6:24
Initialised AES-256 SDCTR client->server encryption
Initialised HMAC-SHA1 client->server MAC algorithm
Initialised AES-256 SDCTR server->client encryption
Initialised HMAC-SHA1 server->client MAC algorithm

第三,Diffie-Hellman 密钥交换算法用于在两台机器之间交换密码密钥。此外,使用AES-256HMAC-SHA1算法对通信进行完全加密。

...
output truncated
...
Using username "tools".
tools@192.168.56.103's password:
Sent password
Access granted

最后,我们必须提供密码来验证会话。现在,plink在远程机器中启动子 shell 以在我们的本地 Windows 机器中执行get_host_info.sh

...
output truncated
...
Opened channel for session
Started a shell/command
CURRENT TIME = Sun Oct 3 15:32:40 IST 2021
HOSTNAME = REMOTE-SERVER
USER id = tools
Server sent command exit status 0
IP ADDRESS = 192.168.56.103/24
Disconnected: All channels closed

显然,始终输入密码会很乏味。因此,plink 使用选项*-pw支持内联密码功能。*选项-pw与选项*-m*一起支持它与 Windows 批处理脚本的更快集成,以便更好地管理远程**服务器:

C:\Users\blogdemo.01\Downloads>.\plink.exe tools@192.168.56.103 -m get_host_info.sh -pw blogdemo@123
CURRENT TIME = Sun Oct 3 03:49:18 IST 2021
HOSTNAME = REMOTE-SERVER
USER id = tools
IP ADDRESS = 192.168.56.103/24

4.使用Expect脚本

通常, Linux 中的** expect脚本可以实现多个基于 CLI 终端的进程的自动化**。为了更好地同化,让我们编写一个期望程序从 localhost 在远程机器上运行一个脚本。

下面解释了一个简单的expect脚本,它首先登录到远程框,将脚本从源复制到远程机器,然后执行它:

#!/usr/bin/expect
set timeout 60
spawn ssh [lindex $argv 1]@[lindex $argv 0]
expect "*?assword" {
    send "[lindex $argv 2]\r"
    }
expect ":~$ " {
    send "
        mkdir -p /home/tools/blogdemo/auto-test;
        cd /home/tools/blogdemo/auto-test;
        tree
        sshpass -p 'blogdemo@123' scp -r tools@10.45.67.11:/home/tools/cw/blogdemo/get_host_info.sh ./;
        tree
        bash get_host_info.sh\r"
    }
expect ":~$ " {
    send "exit\r"
    }
expect eof

使用chmod命令对创建的expect程序应用可执行权限。远程框的凭据和 IP 地址是程序的输入参数:

local-machine# chmod 755 get_host.exp
local-machine# ./get_host.exp "localhost" "tools" "blogdemo@123"
local-machine#

第一步,它与远程服务器生成一个新的ssh会话。根据 CLI 模式,它会发送成功登录的密码。该程序通过创建一个目录并从源计算机复制主脚本来创建测试环境。在这里,sshpass用于将密码内联发送到scp命令以复制主脚本。该程序使用远程框中的 BASH 命令执行复制的get_host_info.sh 。最后,它使用 exit 命令安全地终止通信通道:

local-machine# ./get_host.exp "192.168.56.103" "tools" "blogdemo@123"
spawn ssh tools@192.168.56.103
tools@192.168.56.103's password:
..
..
Last login: Mon Oct  4 12:19:02 2021 from 10.45.67.11
remote-machine# mkdir -p /home/tools/blogdemo/auto-test;
remote-machine# cd /home/tools/blogdemo/auto-test;
remote-machine# ls -ltrh
total 0
remote-machine# sshpass -p 'blogdemo@123' scp -r tools@10.45.67.11:/home/tools/cw/blogdemo/get_host_info.sh ./;
remote-machine# ls -ltrh
total 4.0K
-rw-rw-r-- 1 tools tools 168 Oct  4 12:20 get_host_info.sh
remote-machine# bash get_host_info.sh
CURRENT TIME = Mon Oct 4 12:20:42 IST 2021
HOSTNAME = REMOTE-SERVER
USER id = tools
IP ADDRESS = 192.168.56.103/24
remote-machine# exit
logout
Connection to localhost closed.
local-machine#

作为一个有用的提示,我们还可以添加一些清理命令,如rmmv以在正确退出后使目标清理干净。