将本地端口或套接字文件转发到远程套接字文件


24

快速问题-我运行两个linux机器,一个是我自己的桌面,另一个是我的VPS。出于安全原因,在VPS端,我选择了与MySQL(/var/run/mysqld/mysql.sock)的套接字连接。我知道我可以这样进行隧道传输:ssh -L 3307:127.0.0.1:3306 user@site.com如果我将远程sql服务器设置为侦听某个端口,但是我想知道的是我可以做些什么:ssh -L /path/to/myremotesqlserver.sock:/var/run/mysqld/mysql.sock从而通过隧道传输两个套接字,而不是两个端口吗?

完全可以接受的解决方案是将本地端口转发到远程套接字文件,但是在可能的情况下,我试图不让tcp服务器在远程机器上运行。

(是的,我知道tcp会更容易)。


如果您不希望在mySQL框中使用TCP的原因是出于安全方面的考虑(例如,远程攻击等),则可以将其防火墙,如果不够好,请使mySQL仅侦听127.0.0.1。对于它的TCP连接,那么您可以轻松地通过SSH建立隧道。如果没有,我支持下面的socat解决方案。
Mattias Ahnberg '02

lwn.net/Articles/609321 OpenSSH 6.7将带来套接字转发
Hubbitus

@Hubbitus现在可以使用此功能了,如果可以,您可以提供示例答案吗?
CMCDragonkai '17年

该评论为答复形式,但被某人转换为评论。我现在看到您已经在下面建议了答案。
哈比图斯'17

Answers:


35

按需转发本地套接字

  • 设置SSH公钥身份验证
  • socat两端安装
  • 在本地为您的套接字创建一个目录,其他用户无法访问该目录。
export SOCKET_DIR=~/.remote-sockets
mkdir -p $SOCKET_DIR
socat "UNIX-LISTEN:$SOCKET_DIR/mysqld.sock,reuseaddr,fork" \
EXEC:'ssh user@server socat STDIO UNIX-CONNECT\:/var/run/mysqld/mysqld.sock'

然后

mysql -S $SOCKET_DIR/mysqld.sock -u mysqluser -p

通过ssh和socat转发unix域套接字而被盗


这很棒,应该是公认的答案。
约翰·史密斯可选

32

当时,当有人问这个问题时,这确实是不可能的,但如今是可能的。

您可以同时进行以下操作:UNIX => TCP和UNIX => UNIX转发。

例如:

ssh \
  -R/var/run/mysql.sock:/var/run/mysql.sock \
  -R127.0.0.1:3306:/var/run/mysql.sock \
  somehost

自OpenSSH 6.7起是可能的。


1
我设法使用上述方法将本地套接字转发到远程服务器套接字,并远程运行docker客户端(可以通过ssh直接完成,但是有趣之处在于:)ssh -L /home/user/docker.sock:/var/run/docker.sock dockerhost -N
sdkks

11

我还没有这样做,但是我会尝试用socat。也许像这样:

ssh xxx@yyy.zzz -L 9999:localhost:9999 "socat TCP-LISTEN:localhost:9999 UNIX-CONNECT:/var/run/mysqld/mysql.sock"
socat UNIX-LISTEN:/path/to/local/socket TCP:localhost:9999

再一次,我从来没有做过这样的事情。


我会尝试的,让您知道它的进展。我一直在使用基于tcp的实现。

我目前无法正常运作,但无论如何还是+1,我很喜欢。如果我解决该问题,我会通知您。

+1看起来很有用。
华纳2010年

5

自ssh 6.7起,不再需要socat。您可以直接转发unix域套接字,例如:

ssh -nNT -L $(pwd)/docker.sock:/var/run/docker.sock user@someremote

更多信息:https//medium.com/@dperny/forwarding-the-docker-socket-over-ssh-e6567cfab160


我还发现这对于以其他用户身份连接到本地套接字很有用。这使我可以针对断开某些用户ID(来自其自己的工作运行程序的连接)的服务器进程运行客户端程序。
华宝

使用sshd将套接字转发到同一台机器,但由不同用户控制的不同目录,以验证访问权限?你的用例是什么?
CMCDragonkai '18年

目录权限/访问不是问题。而是,特定守护程序会丢弃特定组中用户进行的任何连接尝试(以防止新手感到困惑)。使用ssh允许那些用户(通过隧道套接字)进行连接,就像他们不是该组中的用户一样,因此不会断开连接。
Warbo

有趣,有趣的是您所说的nix守护程序,我也正在处理与此有关的问题。我想知道为什么nix-daemon断开与特定组中用户的连接?这是安全配置吗?或与以下相关:nixos.org/nix/manual/#idm140737318362784
CMCDragonkai '18年

根据提交消息,这是为了防止“意外”使用。我在这里
Warbo,

2

@mpontes'/ @ javier答案的另一种修改是

ssh user@remoteserver -L 9999:localhost:9999 'socat TCP-LISTEN:9999,fork,bind=localhost UNIX-CONNECT:/var/run/mysqld/mysql.sock& pid=$!; trap "kill $pid" 0; while echo -ne " \b"; do sleep 5; done'

清洁器

ssh user@remoteserver -L 9999:localhost:9999 '
  socat TCP-LISTEN:9999,fork,bind=localhost UNIX-CONNECT:/var/run/mysqld/mysql.sock&
  pid=$!
  trap "kill $pid" 0
  while echo -ne " \b"; do
    sleep 5
  done
'

优点

  1. 在6.7之前的opensh上运行(例如CentOS 7)
  2. 在ssh终止时杀死socat,而不必重新SSH到远程服务器
  3. 允许非公共ssh登录(与ijk解决方案不同)

特征

  1. 由于-f未使用该选项,因此您可以使用公共密钥并通过在后台运行,&也可以交互式登录并使用Ctrl + Z并使用该密钥$!来存储pid。

缺点

  1. 不能轻易使用-fssh选项,因为那样会失去ssh的能力。此方法依赖于在前台运行并按Ctrl + C杀死。
  2. 更复杂

说明

  • socat ...& -在远程服务器上的后台运行socat
  • pid=$! -存储pid
  • trap kill\ $pid 0- kill $pid在bash终止上运行
  • while :; sleep... -无限循环
  • echo -ne \ \b-回声空间,后退空格。SSH断开连接后,此操作将失败。使用sleep 5,这意味着socatssh后最多可以运行5秒

注意:实际使用docker,port 2375/var/run/docker.sock和environment变量进行了测试DOCKER_HOST='tcp://localhost:2375',但对于mysql都应该相同

更新资料

使用SSH控件,您可以使用-f我的方式使用该标志,只需添加以下标志

-f -o ControlPath=~/.ssh/%C -o ControlMaster=auto

你会得到

ssh -f -o ControlPath=~/.ssh/%C -o ControlMaster=auto user@remoteserver -L 9999:localhost:9999 'set -m; socat TCP-LISTEN:9999,fork,bind=localhost UNIX-CONNECT:/var/run/mysqld/mysql.sock& pid=$!; trap "kill $pid" 0; while echo -ne " \b"; do sleep 5; done'

现在,您可以使用以下命令终止所有受控会话

ssh -o ControlPath=~/.ssh/%C -O exit remoteserver

这些-o选项可以保存在.ssh/config文件中,或者可以使用-S代替(但仍然需要-o ControlMaster


我在Docker容器中使用脚本将代码部署到其他主机。您的连接逻辑很棒,但是在bash会话结束时就结束了。这样可以防止我致电docker run ... connect.sh以建立隧道,然后再致电docker run ... deploy.sh。我想nohup&disown,但他们似乎打破socat通过关闭stdout和触发kill。有什么想法可以调整以支持这种情况(例如,当SSH启用时仍然关闭,但在被拒绝后仍然存在)?
克莱顿

好。实际上,这在终端中可以正常工作(使用w -f& disown)。显然,问题是由脚本“包装器”造成的。我欢迎您提出意见,但现在正在寻找更合适的问答。
claytond

@claytond不确定确切要做什么,但是是的,当容器的pid 1结束时,所有其他命令都会终止。在部署脚本方案中,我通常要做的是使用命令“ deploy”并为我的容器写一个入口点将显示“如果$ 1(命令)==部署然后”的映像,运行ssh命令,然后部署命令,然后结束,这将关闭ssh连接。您也可以docker run ... connect.shdocker exec {container name/id} deploy.sh,使它们一起玩。
安迪

你是对的。我实际上是exec在一个已经存在的run容器上使用,并且SSH管道在exec结束后并没有持续存在。我澄清这是由于脚本执行方式的古怪之处。如果我将调用移到它自己的脚本并进行调用nohup <script.sh> & disown,则它会在完成后幸存下来exec
克莱顿

1

详细阐述哈维尔的答案,这对我有用:

ssh -f xxx@yyy.zzz -L 9999:localhost:9999 "socat TCP-LISTEN:9999,fork,bind=localhost UNIX-CONNECT:/var/run/mysqld/mysql.sock"

您需要fork能够多次连接而不会在关闭第一个连接后死机。另外,socat允许您指定要绑定到的地址的方法是通过bind选项,而不是端口之前的地址。

之后,只需localhost:9999正常连接即可。然后拆除隧道:

ssh -f xxx@yyy.zzz "killall socat"

(或类似的方法,您可以做一些更复杂的事情,包括保持socat的PID)


1

是的,您可以使用socat。

首先使用SSH进行TCP隧道。然后像这样使用socat:

socat unix监听:/var/run/mysqld/mysqld.sock,fork,unlink-early tcp:127.0.0.1:3306

然后将权限授予新创建的套接字(可能是chmod 777)


从OpenSSH 6.6开始,这是可能的。
ysdx

3
chmod 777:nonononono!永远不要跑chmod 777。几乎不需要!甚至不是出于“测试目的”。如果文件是可读的,那么它是可读的。如果它是可写的,user或者group需要对其进行写操作,则它是可写的。绝对没有必要授予所有人写权限,而忘记chmod它又回到了理智的状态,这正是跨国公司遭到黑客攻击的方式。只是不要这样做。曾经 我写了Unix权限介绍。请阅读!
Martin Tournoij
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.