bash - 为多个命令使用用户/密码*一次*进行身份验证? ( session 多路复用)

标签 bash ssh sftp scp openssh

我从 Solaris 文档中获得了这个技巧,用于将 ssh 公钥复制到远程主机。

注意:ssh-copy-id 在 Solaris 上不可用

$ cat some_data_file | ssh user@host "cat >/tmp/some_data_file; some_shell_cmd"

我想调整它来做更多复杂的事情。

具体来说,我希望some_shell_command 是从本地 主机发送到远程 主机的脚本...脚本将与本地键盘交互(例如,当脚本在远程主机上运行时提示用户)。

我尝试了通过 stdin 从多个来源发送多个内容的方法。但是某些在 local shell 中工作的东西在 ssh 上不工作,并且一些东西,例如下面的,根本没有做我想要的:

$ echo "abc" | cat <(echo "def")     # echoes: def  (I wanted abc\ndef)
$ echo "abc" | cat  < <(echo "def")  # echoes: def  (I wanted abc\ndef)

$ echo "abc" | cat <<-EOF
> echo $(</dev/stdin)   #echoes: echo abc  (I wanted: abc) 
> EOF

# messed with eval for the above but that was a problem too.

@chepner得出结论,在单个 ssh 命令中完成所有这些操作是不可行的。他提出了一个理论上的替代方案,但没有像希望的那样起作用,但经过一些研究和调整后我让它起作用了,并记录了结果并将其发布为这个问题的答案。

如果没有该解决方案,默认情况下必须运行多个 sshscp 命令需要多次提示输入密码,这是一个主要的拖累。

我不能指望我在多用户环境中编写的脚本的所有用户都配置公钥授权,也不指望他们会忍受不得不一遍又一遍地输入密码。

最佳答案

OpenSSH session 多路复用


即使在使用早期版本的 OpenSSH 时,此解决方案也适用
ControlPersist选项不可用。 (此答案末尾的工作 bash 示例)


注:OpenSSH 3.9通过“控制主连接”(2005 年)引入了 session 多路复用,但是,直到 OpenSSH 5.6 才引入 ControlPersist 选项(2010 年发布)

ssh session 多路复用允许脚本进行一次身份验证并在经过身份验证的连接上执行多个 ssh 事务。例如,如果您有一个使用 sshscpsftp 运行多个不同任务的脚本,则每个事务都可以通过 OpenSSH “控制主 session ”指的是其命名套接字在文件系统中的位置。

以下一次性密码身份验证在运行必须执行多个 ssh 操作的脚本时非常有用,并且希望避免用户不得不多次密码身份验证,并且在以下情况下特别有用公钥身份验证不可行的情况 - 例如不允许,或至少未配置。


enter image description here


我见过的大多数解决方案都需要使用 ControlPersist 告诉 ssh 无限期地或特定秒数保持控制主连接打开。

不幸的是,使用 OpenSSH 5.6 之前的系统没有该选项(其中升级它们可能不可行)。不幸的是,似乎没有太多关于在线限制的文档或讨论。

阅读旧版本文档后,我发现 ControlPersistssh session 多路复用场景中出现较晚。这意味着可能有另一种方法来配置 session 多路复用,而不依赖于它之前的 ControlPersist 选项。

最初尝试从命令行选项而不是 config 参数配置持久 session ,我遇到了 ssh session 过早终止的问题,关闭控制连接客户端 session ,或者,连接保持打开状态( keep ssh control master alive),终端 I/O 被阻塞,脚本会挂起。

下面说明如何完成它。


OpenSSH option            ssh flag          Purpose
-------------------       ---------         -----------------------------
-o ControlMaster=yes      -M                Establishes sharable connection
-o ControlPath=path       -S path           Specifies path of connection's named socket
-o ControlPersist=600                       Keep shareable connection open 10 min.
-o ControlPersist=yes                       Keep shareable connection open indefinitely
                          -N                Don't create shell or run a command
                          -f                Go into background after authenticating
                          -O exit           Closes persistent connection
ControlPersist form       Equivalent        Purpose
-------------------       ----------------  -------------------------
-o ControlPersist=yes     ssh -Nf           Keep control connection open indefinitely
-o ControlPersist=300     ssh -f sleep 300  Keep control connection open 5 min.

Note: scp and sftp implement -S flag differently, and -M flag not at all, so, for those commands, the -o option form is always required.


Sketchy Overview of Operations:
Note: This incomplete example doesn't execute as shown.

ctl=<path to dir to store named socket>
ssh -fNMS $ctl user@host      # open control master connection
ssh -S $ctl …                 # example of ssh over connection
scp  -o ControlPath=$ctl …    # example of scp over connection
sftp -o ControlPath=$ctl …    # example of sftp over connection
ssh -S $ctl -O exit           # close control master connection

session 多路复用演示

(尝试一下。您会喜欢的。工作示例 - 仅验证一次):

运行这个脚本可能会比阅读它更快地帮助您理解它,而且它很吸引人。

注意:如果您无法访问远程主机,只需在“Host...?”处输入 localhost。提示你是否想尝试这个演示脚本

#!/bin/bash       # This script demonstrates ssh session multiplexing

trap "[ -z "$ctl" ] || ssh -S $ctl -O exit $user@$host" EXIT # closes conn, deletes fifo

read -p "Host to connect to? " host
read -p "User to login with? " user

BOLD="\n$(tput bold)"; NORMAL="$(tput sgr0)"

echo -e "${BOLD}Create authenticated persistent control master connection:${NORMAL}"

sshfifos=~/.ssh/controlmasters

[ -d $sshfifos ] || mkdir -p $sshfifos; chmod 755 $sshfifos

ctl=$sshfifos/$user@$host:22 # ssh stores named socket ctrl conn here

ssh -fNMS $ctl $user@$host  # Control Master: Prompts passwd then persists in background

lcldir=$(mktemp -d /tmp/XXXX)

echo -e "\nLocal  dir: $lcldir"

rmtdir=$(ssh -S $ctl $user@$host "mktemp -d /tmp/XXXX")

echo      "Remote dir: $rmtdir"

echo -e "${BOLD}Copy self to remote with scp:${NORMAL}"

scp -o ControlPath=$ctl ${BASH_SOURCE[0]} $user@$host:$rmtdir 

echo -e "${BOLD}Display 4 lines of remote script, with ssh:${NORMAL}"
echo "====================================================================="
echo $rmtdir | ssh -S $ctl $user@$host "dir=$(</dev/stdin); head -4 \$dir/*"
echo "====================================================================="

echo -e "${BOLD}Do some pointless things with sftp:${NORMAL}"
sftp -o ControlPath=$ctl $user@$host:$rmtdir <<EOF
    pwd
    ls
    lcd $lcldir
    get *
    quit
EOF

关于bash - 为多个命令使用用户/密码*一次*进行身份验证? ( session 多路复用),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41786904/

相关文章:

linux - 从 shell 脚本中的变量运行 shell 命令

git - 无法通过 SSH 连接到自定义端口上的 Gitlab 容器

java - 密码 'aes256-cbc' 是必需的,但不可用

ssh - 如何挂载远程 ecryptfs 目录?

linux - 如何使用 ssh + 密码连接到 Aptana studio 3? (SFTP)

android - 在多个模拟器上运行 Android 应用程序的雄心勃勃的尝试 - 无法停止模拟器

linux - 压缩文件夹的内容包括父目录

linux - 如何使用其所在目录的工作目录执行任意脚本?

java - 如何从 SFTP 服务器获取文件列表?

java - 通过SFTP传输文件