最近业务使用ssh命令通道对K8S的机器执行命令时出现失败,从失败内容看是io timeout,应该是访问超时。具体错误如下:
因此,通过抓包分析发现:
三次握手竟然是成功的,但握手成功之后,没有传输数据,而是大约5秒之后执行四次挥手,但是在server端发送了RST报文给client,导致出现了i/o timeout。
随之产生了疑问:为什么K8S的机器执行ssh通道会失败
带着这个问题,我们首先联合K8S的人一起看了下K8S机器执行失败的问题,经K8S的同事确认,K8S的机器都做了ssh登录限制,即/etc/hosts.allow和/etc/hosts.deny做了配置。
随机抽取几台K8S的机器看了下,这两个配置文件确实配置了对应的选项。
通过ssh访问失败的错误日志如下:(CentOS下日志文件在/var/log/secure)
使用audit查下到底是哪些进程对/etc/hosts.allow和/etc/hosts.deny有读操作:
auditctl -w /etc/hosts.allow -p rwxa
auditctl -w /etc/hosts.deny -p rwxa
执行完ssh命令之后,查看日志
ausearch -l >/tmp/a.log
是sshd会访问这两个文件。且系统调用号是257,对应的系统调用是openat
Sshd之所以会访问这两个文件,是因为通过tcp_wrapper访问的,sshd引用了libwrap库,而libwrap是tcp_wrapper编译出来的,在编译sshd的时候,编译选项加了libwrap,因此在访问sshd的时候,默认会有tcp_wrapper的行为,即主机网络控制。
我下载了openssh和tcp_wrappers源码,libwrap.so就是由tcp_wrappers编译出来的库文件,而在openssh中使用了libwrap.so的函数,并且在编译的时候指定了编译选项–with-tcp-wrappers。我尝试编译tcp_wrappers源码,但一直提示缺少头文件,网上找了一些方法也没有解决,看样子社区版源码和RHEL的发行版还是有出入的。
首先看了下libwrap.so文件的相关引用,从引用可以看出使用了tcp_wrapper的refuse
/* refuse - refuse request */
void refuse(request)
struct request_info *request;
{
syslog(deny_severity, "refused connect from %s",eval_client(request));
clean_exit(request);
/* NOTREACHED */
}
这里给出sshd使用tcp_wrappers实现主机网络访问控制的示意图
当然,linux下不止sshd使用了tcp_wrappers,例如rpcbind也使用tcp_wrappers。
本文没有阐述tcp_wrappers的配置语法,因为比较简单,而且网上有很多示例,所以就不阐述。之前有接触过linux下的/etc/hosts.allow和/etc/hosts.deny文件,但没有深入理解,因此趁这次遇到问题顺便深入理解一下。