当我需要使用具有足够权限的用户通过 SSH 将文件从本地服务器(服务器 A(复制到远程服务器(服务器 B(时,我成功地做到了这一点,如下所示
localpath='/this/is/local/path/file1.txt'
remotepath='/this/is/remote/path/'
mypass='MyPassword123'
sshpass -p $mypass scp username@hostname:$localpath $remotepath
现在,我必须使用没有足够的复制权限的用户将文件从服务器 A 传输到服务器 C。然后一次 我连接到服务器C,我需要发送su
才能发送cd
,ls
等命令。
手动,我通过SSH访问服务器C,如下所示:
[root@ServerA ~]# ssh username@hostname
You are trying to access a restricted zone. Only Authorized Users allowed.
Password:
Last login: Sat Jun 13 10:17:40 2020 from XXX.XXX.XXX.XXX
ServerC ~ $
ServerC ~ $ su
Password:
ServerC /home/myuser #
ServerC /home/myuser # cd /documents/backups/
ServerC /documents/backups #
此时myuser
拥有超级用户权限,我可以发送命令。
那么,如何自动执行将文件从服务器 A 复制到服务器 C 的任务,并在连接到服务器 C 后发送su
?
到目前为止,我已经尝试过这样做:
sshpass -p $mypass ssh -t username@hostname "su -c "cd /documents/backups/ && ls""
它请求su
的密码,我能够发送cd
和ls
但是使用此命令,我不会将文件从服务器 A 复制到服务器 C,只是半自动访问服务器 C 并在服务器 C 中发送su
。
提前感谢任何帮助。
更新
# $TAR | ssh $username@$hostname "$COMMAND"
+ tar -cv -C /this/is/local/path/file1.txt .
+ ssh username@X.X.X.X 'set -x; rm -f /tmp/copy && mknod /tmp/copy p; su - <<< "su_password
set -x; tar -xv -C /this/is/remote/path/ . < /tmp/copy" & cat > /tmp/copy'
tar: /this/is/local/path/file1.txt: Cannot chdir: Not a directory
tar: Error is not recoverable: exiting now
You are trying to access a restricted zone. Only Authorized Users allowed.
Password:
+ rm -f /tmp/copy
+ mknod /tmp/copy p
+ su -
+ cat
Password:
编者按:本答案的先前版本使用sudo
,当前版本根据问题中的要求使用su
。
您可以使用tar
和管道,如下所示:
TAR="tar -cv -C $localpath ."
UNTAR="tar -xv -C $remotepath ."
PREPARE_PIPE="rm -f /tmp/copy && mknod /tmp/copy p"
NEWLINE=$'n' # that's the easiest way to get a literal newline
ROOT_PASSWORD=rootpasswordverydangerous
COMMAND="set -x; $PREPARE_PIPE; su - <<< "${ROOT_PASSWORD}${NEWLINE} set -x; $UNTAR < /tmp/copy" & cat > /tmp/copy"
$TAR | ssh username@hostname "$COMMAND"
解释:
tar -c .
将当前目录存档到单个文件中。我们不会将-f
传递给tar
,因此单个文件是标准输出。
tar -x .
将单个 tar 存档文件的内容提取到当前目录。我们不会将-f
传递给tar
,因此单个文件是标准输入。
-C <path>
告诉tar
cd
到<path>
中,以便它将成为从/复制到文件的当前目录。
-v
只是告诉 tar 列出 tar 存档/提取的文件,用于调试目的。
同样,set -x
只是为了调试目的而发出跟踪信息的bash
。
因此,我们将$localpath
存档到 stdout 中,并将其管道传输到ssh
,这会将其管道传输到$COMMAND
。
如果有一种方法可以在命令行中给su
密码,我们会使用类似的东西:
$TAR | ssh ... su --password ${ROOT_PASSWORD} -c "$UNTAR"
事情本来会很简单。
但su
没有。su
像贝壳一样运行,从标准中读取。因此,它将首先读取密码,一旦读取密码并且su
建立了根会话,它就会从 stdin读取命令。这就是为什么我们有su - <<< "${ROOT_PASSWORD}${NEWLINE}${UNTAR}
.
但是现在 stdin 由密码和命令使用,所以我们不能将其用作存档。我们可以使用另一个文件描述符,但我不想这样做,因为这样解决方案可以更容易地移植到sudo
而不是su
。sudo
关闭所有文件描述符,sudo -C 200
(仅关闭 200 以上的文件描述符(可能不起作用(在我的测试计算机上不起作用(。
如果我们朝这个方向走,我们会使用类似的东西
$TAR | ssh ... 'exec 9<&2 && sudo -S <<< $mypass bash -c "$UNTAR <&9"'
我们的下一个选择是执行类似cat > /tmp/archive.tar
的操作,以便将整个存档写入文件,然后具有类似$UNTAR < /tmp/archive.tar
.但是存档可能很大,我们可能会用完磁盘空间。
所以这个想法是创建一个专用管道 - 这PREPARE_PIPE
.管道不会将任何内容保存到磁盘,也不会将整个流存储在内存中,因此读取器和写入器必须同时工作(你知道,就像使用真正的管道一样(。
因此,从$ROOT_PASSWORD
重定向su
的 stdin,我们用cat > /tmp/copy
将ssh
的 stdin 拉入我们的管道中,并并行(&
(从管道中读取$UNTAR
(< /tmp/copy
(。
笔记:
- 如果网络速度太慢,您还可以将
-z
传递给两个tar
命令以压缩传递它。 tar
将保留源的元数据,例如时间戳和所有权。- 将
$ROOT_PASSWORD
传递给命令不是很好的做法,任何运行ps -ef
的人都可以看到密码。有一些方法可以更安全地将密码传递给服务器 C,我没有包含它,以免使这个答案进一步复杂化。 - 我建议要求服务器的所有者安装
sudo
,这样如果密码通过ps -ef
泄露,至少它不是root密码。