Ansible: 建议在 ssh 抛出“unix 域套接字“太长”错误时更新控制路径设置

创建于 2015-07-09  ·  66评论  ·  资料来源: ansible/ansible

问题类型

特色理念

组件名称

ssh 控制持续存在

ANSIBLE 版本

2.0

概括

尝试使用 ec2 插件时,ssh 失败并显示以下错误:

SSH Error: unix_listener: "/Users/luke/.ansible/cp/ansible-ssh-ec2-255-255-255-255.compute-1.amazonaws.com-22-ubuntu.CErvOvRE5U0urCgm" too long for Unix domain socket

这是完整的示例:

$ ansible -vvvv -i ec2.py -u ubuntu us-east-1 -m ping
<ec2-255-255-255-255.compute-1.amazonaws.com> ESTABLISH CONNECTION FOR USER: ubuntu
<ec2-255-255-255-255.compute-1.amazonaws.com> REMOTE_MODULE ping
<ec2-255-255-255-255.compute-1.amazonaws.com> EXEC ssh -C -tt -vvv -o ControlMaster=auto -o ControlPersist=60s -o ControlPath="/Users/luke/.ansible/cp/ansible-ssh-%h-%p-%r" -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 ec2-255-255-255-255.compute-1.amazonaws.com /bin/sh -c 'mkdir -p $HOME/.ansible/tmp/ansible-tmp-1436458336.4-21039895766180 && chmod a+rx $HOME/.ansible/tmp/ansible-tmp-1436458336.4-21039895766180 && echo $HOME/.ansible/tmp/ansible-tmp-1436458336.4-21039895766180'
ec2-255-255-255-255.compute-1.amazonaws.com | FAILED => SSH Error: unix_listener: "/Users/luke/.ansible/cp/ansible-ssh-ec2-255-255-255-255.compute-1.amazonaws.com-22-ubuntu.CErvOvRE5U0urCgm" too long for Unix domain socket
    while connecting to 255.255.255.255:22
It is sometimes useful to re-run the command using -vvvv, which prints SSH debug output to help diagnose the issue.

我已经更改了这里的一些敏感信息,例如 IP 等。

affects_2.0 affects_2.3 feature

最有用的评论

将此添加到我的 ansible 配置以缩短路径:

[ssh_connection]
control_path = %(directory)s/%%h-%%p-%%r

将其包含在错误输出中或做其他更优雅的事情而不是失败可能会很有用。

所有66条评论

将此添加到我的 ansible 配置以缩短路径:

[ssh_connection]
control_path = %(directory)s/%%h-%%p-%%r

将其包含在错误输出中或做其他更优雅的事情而不是失败可能会很有用。

对我来说同样的错误! 我同意 LukeHoersten 在此修复程序中的观点。

感谢您指出您的解决方案@LukeHoersten

没问题。 希望我们能在那里得到更可靠的修复。 尤其对新人不利。

ansible 配置有另一个注释掉的建议
control_path = %(directory)s/%%h-%%r

但是是的,帮助消息会很有用。

我也刚打了这个。 我是新手,浪费了大量时间。 谢谢你的回答! 我同意,需要修复。

我也 :+1: 对于这个功能。

今天就遇到了。 感谢您对ansible.cfg的提示!!

编辑 control_path 在 Mac OSX El Capitan 上不起作用。

这在 El Capitan 中对我有用:

[ssh_connection]
control_path = %(directory)s/%%h-%%r

正如@willotter指出的那样,它是https://raw.githubusercontent.com/ansible/ansible/devel/examples/ansible.cfg 中注释掉的语句之一

有兴趣知道为什么这是一个问题 - 因为长路径名何时是 Windows 之外的问题?

升级到 EI Capitan 后,这对我有用。

[ssh_connection]
control_path = %(directory)s/%%h-%%p-%%r

@deyvsh为什么这是一个问题 - 因为长路径名何时是 Windows 之外的问题?

因为 El Capitan 是由 Apple 发布的。 除了中文页面之外,这是唯一一个似乎在 MacOS 中引用此新行为的页面。 我在尝试在 emacs 中使用 TRAMP 模式时遇到了同样的问题,该模式允许通过 ssh 透明访问远程文件。 关于 unix 域套接字的长文件名的相同错误,但不像 Ansible 那样容易解决。

@cswarth ansible配置刚刚传递给您的 ssh 客户端。 您可以像这样在 ssh 配置文件~/.ssh/config设置 control_path:

Host *
  ControlPath /tmp/%r@%h:%p

我没有 Mac OS X,所以我无法对此进行测试,但这应该可以工作,除非 emacs 将任何特定参数传递给 SSH。

@willotter我不得不调整这个想法并将它添加到我的 ansible.cfg 文件中才能让它工作。

[ssh_connection]
control_path = /tmp/%%h-%%p-%%r

2017 年更新:看起来@willotter不再存在:(

@LukeHoersten谢谢你,为我解决了这个问题!

造成这种情况的根本原因是

https://github.com/openssh/openssh-portable/blob/9ada37d36003a77902e90a3214981e417457cf13/misc.c#L1070

int
unix_listener(const char *path, int backlog, int unlink_first)
{
    struct sockaddr_un sunaddr;
    int saved_errno, sock;

    memset(&sunaddr, 0, sizeof(sunaddr));
    sunaddr.sun_family = AF_UNIX;
    if (strlcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path)) >= sizeof(sunaddr.sun_path)) {
        error("%s: \"%s\" too long for Unix domain socket", __func__,
            path);
        errno = ENAMETOOLONG;
        return -1;
    }

要知道限制(sizeof(sunaddr.sun_path)),我们需要看https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man4/unix.4.html

           struct sockaddr_un {
                   u_char  sun_len;
                   u_char  sun_family;
                   char    sun_path[104];
           };

路径限制为 104 个字符,包括 0 终止符。

这也在https://en.wikibooks.org/wiki/OpenSSH/Cookbook/Multiplexing#Manually_Establishing_Multiplexed_Connections中讨论,这也表明您正在使用

从 6.7 开始,%r@%h:%p 及其变体的组合可以用 %C 替换,%C 本身会从 %l%h%p%r 的串联生成散列。

最后,你想使用

[ssh_connection]
control_path = %(directory)s/%%C

此外,您希望他妈的远离 /tmp 或任何其他世界可写、世界可读的位置,因为安全性。

另见http://pastebin.com/ugXKMFsv

@isotopp很好的建议。 我想知道为什么我们不只是将默认值更改为control_path = %(directory)s/%%C以避免将来出现问题。

@LukeHoersten我认为

[:~] $ grep -i control ~/.ssh/config
ControlMaster auto
ControlPath ~/.ssh/_%C

Ping @bcoca - 请参阅上面的分析和提议的更改。

+1

因为它不适用于许多运行甚至稍旧版本的 openssh 的操作系统/发行版

http://pastebin.com/ugXKMFsv 中的拟议更改仅更改文档和评论。 将适用于旧版本的 openssh,但会使指向 %C 的指针更加明显。

我的机器上有一个很长的用户名(11 个字符),这导致我的目录超过了字符限制。

https://github.com/ansible/ansible/blob/devel/examples/ansible.cfg#L216 -L225

我放弃了-%%r ,它为我解决了这个问题。

我今天遇到了这个错误,因为我提供了我的 group_vars 文件而不是我的库存文件,并且 ansible 以某种方式愉快地解析了加密文件并接受了 182937891273891723981723891723987189237189237981273981 之类的东西作为主机名。 SSH 在注意到长长的 ControlPath 之前也没有觉得这很奇怪。 对后代的警告 - 使用 -vvvv 运行所有内容,并确保您指向正确的主机等等。

这次真是万分感谢。 它修复了我在 OS X El Capitan 上的错误。

+1
这刚刚解决了我在 OS X El Capitan 上的问题。

在 OS X EL Capitan 上也为我工作。 请注意,如果您已经通过 brew 安装了 ansible,则该文件为/usr/local/etc/ansible/ansible.cfg

:+1 这发生在我身上,我只是试图做一个ansible all -i inventory -m ping的主机名,如ec2-XX-XXX-XX-XX.eu-west-1.compute.amazonaws.com

这在 El Capitan 上对我有用:

我在当前目录中创建了一个ansible.cfg文件:

[ssh_connection]
control_path = %(directory)s/%%C

现在运行ansible ..没有给我任何 ssh 错误。

在 OS X EL Capitan 上也为我工作。 请注意,如果您通过 brew 安装了 ansible,则该文件为 /usr/local/etc/ansible/ansible.cfg

我是 El Capitan 并通过 brew 安装了 ansible,它忽略了我尝试使用这些设置添加的/usr/local/etc/ansible/ansible.cfg文件。

@tleyden这很奇怪, /usr/local/etc/ansible/ansible.cfg对我来说很好用。

哦,我刚刚意识到不同之处——我通过pip install ansible安装了 ansible,而不是通过 brew

为什么最后会添加像CErvOvRE5U0urCgm这样的字符串? 由于那条无用的字符串,事情对我来说破裂了。

只需在此处添加一些评论以明确可以采取哪些行动:

  • 文档。 看起来建议的文档更新在此票证链接的要点中,但不在 PR 中,因此从未合并。
  • 更好地捕获错误——如果使用了 %C 并且 ssh 不支持它,那么告诉人们用 %l-%h-%p 替换。 如果路径太长,告诉人们尝试 %C 或简单地缩短路径。
  • 尝试检测我们使用的 ssh 是否支持 %C,如果支持,请使用它,否则不要(也许这仅与默认相关,而不是当用户在其配置文件中配置某些内容时?)(有但是要小心不要让连接花费更长的时间)。

我还补充道:
%(directory)s/%%h‐%%r
但是我的路还是太长了? 我怎样才能解决这个问题:

SSH Error: unix_listener: "/Users/myfullname/.ansible/cp/ec2-xx-xx-xx-xx.eu-central-1.compute.amazonaws.com-centos.AAZFTHkT5xXXXXXX" too long for Unix domain socket
    while connecting to 52.xx.xx.xx:22

我在 Ubuntu 16.04 上的 ansible 2.1.0.0 看到了这个问题

$ ssh -V
OpenSSH_7.2p2 Ubuntu-4ubuntu1, OpenSSL 1.0.2g-fips  1 Mar 2016

将此添加到我的 ansible.cfg 工作:

[ssh_connection]
control_path=%(directory)s/%%h-%%p-%%r

或者,即使没有更改 ansible.cfg 中的 ssh_connection.control_path,将长 AWS 域名更改为 IP 地址也会修复它。

正如其他人所说,使用 -vvvv 运行时,此错误并不明显。 我必须复制调试输出中的命令并直接在终端中运行它才能看到错误“Unix 域套接字太长”。

我也有同样的问题。

这个问题非常烦人,必须根据运行 Ansible playbook 的机器在 IP 和 FQDN 之间来回切换……从 Ansible 方面计划的任何真正的解决方案?

@swoodford ,也许您可​​以向 linux 发行版提出问题以更改默认设置。 例如,fedora 维护者可以默认使用较短的控制套接字。 问题似乎是希望在默认情况下与旧发行版保持兼容性。 我不确定这是否有意义,因为新发行版的用户现在应该更多。 这意味着至少较新的发行版不应该介意在打包期间更改默认值,因为发行版知道它是最新的,可以使用更可靠的选项。

我仍然认为 ansible 应该改变 dafault。

很搞笑。 前段时间我们在 cdist 中遇到了同样的问题(并且正在研究与此相关的另一个错误)。 Unix 中的 sun_path 限制是一个非常非常古老的限制,它在 2016 年困扰着我们。

最简单的解决方案:无。
第二个最佳解决方案:尽量保持套接字名称简短。 如果 home dir 是一条很长的路,仍然会中断
第三个最佳解决方案:将其存储在 /tmp/short-random-path/c 中的某处(只需要一个字符)

长期解决方案:摆脱 sun_path 限制或提高到合理的 2016 年默认值(奥斯汀组/posix 中的任何人在这里阅读?)

%(directory)代表什么?

@isotopp

这是放入~/.ssh/config文件的正确语法(带下划线前缀)吗?

ControlMaster auto
ControlPath ~/.ssh/_%C

这是一个与 ansible.cfg 文件中的双%%具有相同含义的转义符吗? 我正在尝试以与即使在 ansible 之外使用 ssh 相同的方式配置它们。

即使在我的项目中将control_path到我的 ansible.cfg 之后,我仍然收到此错误,但我恢复到 2.1.3 版,运行了在运行 2.2.1 时抛出错误的相同命令,并且问题已解决。

版本仍然存在此问题:ansible 2.2.0.0

真是奇怪的问题。 Fedora 24 上的 ansible 2.2.0.0 -> 存在问题
2016/07/05 在 OSX 上的 git head -> 问题不存在。

@bcoca我一直是向后兼容的粉丝(是的,我发送了那个 centos 6.5 修复程序)。 在使用哪个控制路径的 openssh/distro 版本上让它动态怎么样?

它已经是动态的,请参阅默认“智能”连接背后的逻辑

从主机连接到主机时,也许您的背包中没有 ssh 密钥? :)

附带说明一下,%C 现在不是一个很好的默认设置,因为 EL7 有 openssh 6.6,并且 %C 直到 openssh 6.7 才被添加并且还没有被反向移植。

不过,您可以在 EL7 上使用 %l%h%p%r 的完全扩展形式,但只能部分缓解,因为它当然仍然不会进行散列。

应该由发行版所有者更改默认配置以适应随附的软件包。 我认为上游不应该等待 7 年才能推进像这样的重要改进。

由于我仍在使用 Ansible 2.2 版和 Ansible Tower 3.1.1,我也遇到了这个问题。 正如@dennisobien 在我们之前指出的那样,将清单从 AWS 域名更改为 AWS IP 地址解决了这个问题。 但是,我首先尝试在配置中仅使用这些变量,但并没有解决问题:

---
ssh_connection:
  control_path: "%(directory)s/%%h-%%p-%%r"

@b-long ,使用 control_path %(directory)s/%%C

我的服务器有这个问题,我无权更改它。 客户端怎么解决?

@thefourtheye这纯粹是客户端问题,而不是服务器问题。 您可以在本主题前面的 ansible.cfg 文件中找到要设置的选项。

@antoineco哦,谢谢。 我对 ansible 完全陌生,我什至没有在我的机器上安装它。 仍然在主目录中保留文件ansible.cfg会起作用吗?

我有同样的问题,我尝试了所有解决方案,包括在 ~/ 中添加配置文件 .ansible.cfg:
[defaults] inventory=/etc/ansible/hosts [ssh_connection] control_path=%(directory)s/%%h-%%r control_path_dir=~/.ansible/cp

并将知道主机和 ip 添加到 ssh known_hosts。 但它仍然不起作用,它是EC2上的ubuntu。
这是错误:

fatal: [default]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: Warning: Permanently added 'ec2-xx-192-174-42.ap-northeast-1.compute.amazonaws.com,xx.192.174.42' (ECDSA) to the list of known hosts.\r\nunix_listener: \"/Users/name/.ansible/cp/ec2-xx-192-174-42.ap-northeast-1.compute.amazonaws.com-ubuntu.1fndG2vtHPliheeZ\" too long for Unix domain socket\r\n", "unreachable": true

您没有使用建议的解决方案control_path = %(directory)s/%%C

@akostadinov谢谢,它起作用了。 这里的解决方案太多了。

这里的解决方案太多了。

要是再难点就好了……诅咒那些解决方案提供商!

我尝试在我的定位机器的~/ansible.cfg文件中添加这里建议的所有行,但没有帮助。 我要放弃了。

现在对我有用的是使用nslookup获取机器的 IP 地址并使用它登录。

@thefourtheye ,我不确定您在这里看到了多少“建议行”。 使用获得 50 多个赞的帖子。 但是除了正确的选项之外,您还需要使用ansible 知道的配置文件。 在你的情况下~/.ansible.cfg 。 尽量注意细节,用户配置文件前面的点是一个常见的unix约定。

@akostadinov对不起,这是一个错字。 这是它的样子

➜  ~ cat ~/.ansible.cfg
[ssh_connection]
control_path = %(directory)s/%%h-%%p-%%r

我只想和我的.ansible.cfg

[ssh_connection]
control_path = /tmp/control_%%l_%%h_%%p_%%r

对我来说, directory长得可笑,后半部分只是压死骆驼的最后一根稻草。 我的.ssh/config也有这个,所以我可以重用相同的连接:

ControlMaster                    auto
ControlPath                      /tmp/control_%l_%h_%p_%r

抱歉,硬编码的 tmp 不仅不可移植,而且存在严重的安全风险。 出于充分的理由,MacOS 不允许用户写入 /tmp 并为每个用户提供隔离的(私有)tmp 文件夹。

Tmp 仅在您使用操作系统提供的 tmp 路径时才有效,例如 %(tmp)s ... 在修补 ansible 之后。

伙计们,请阅读现有评论,每个人都来问同样的事情并且有人添加相同的解决方案是荒谬的。 使用正确的配置文件并查看https://github.com/ansible/ansible/issues/11536#issuecomment -153030743。

有人,请关闭线程以避免进一步的垃圾邮件。

@ssbarnea 硬编码的任何东西都不可移植...这就是为什么它不是 ansible 的默认设置...不确定我是否同意安全问题或 macOS 问题,因为 /tmp 是粘性的,并且 openssh 对这些文件使用了合理的模式 (0600)。

关于使用%C的解决方案,该解决方案需要最近的 openssh ...

我并不关心古老的 ssh 版本,尤其是在 ansible 控制器上。 为了进化,我们需要让一些事情落后,在这种情况下并不是什么大不了的事,因为受影响的人可能会更改配置以便能够继续使用它。

我认为对于 Ansible 用户体验 (UX) 来说,提供适合大多数用户的默认值是必不可少的,从而最大限度地减少更改的需要。 我怀疑我们是否有超过 1-2% 的用户使用不支持%C的 open openssh 版本。

我认为我们需要尽快在 Ansible 中实现几个关键的 INI 变量,因为每隔一周我们就会遇到由于缺少它们而导致的错误: %(tmpdir)s m $(configdir)s%(inventorydir)s

如果我们有这些人,就能够创建可靠的相对路径。

可悲的是,在我的情况下,问题更糟,因为我们使用 Ansible 作为 CI 的一部分,并且因为像许多人一样,我们在同一台机器上有多个 Jenkins 节点,在同一用户下运行,我们确实经常遇到 ssh 会话劫持。 无论如何,我的问题更复杂,超出了这张票的范围。

6 个月前,我为所有版本的 ssh 以通用方式解决了这个问题。 如果有人看到 Ansible 2.3+ 的问题,那是因为您在 ansible.cfg 中设置了自定义控制路径,而不是将其留空。

https://github.com/ansible/ansible/commit/ac78347f2bc4a489c7e254c6c1d950fb45f240ad

https://github.com/ansible/ansible/blob/devel/examples/ansible.cfg#L360 -L367

# The path to use for the ControlPath sockets. This defaults to a hashed string of the hostname, 
# port and username (empty string in the config). The hash mitigates a common problem users 
# found with long hostames and the conventional %(directory)s/ansible-ssh-%%h-%%p-%%r format. 
# In those cases, a "too long for Unix domain socket" ssh error would occur.
#
# Example:
# control_path = %(directory)s/%%h-%%r
#control_path =

由于这个对话在没有参考上面的补丁的情况下继续进行,我将把它锁定。 如果您对该主题还有其他疑问,请使用邮件列表。

此页面是否有帮助?
0 / 5 - 0 等级