简体   繁体   English

哪个 PID 在没有网络工具的情况下使用 k8s pod 内的 PORT

[英]Which PID is using a PORT inside a k8s pod without net tools

Sorry about the long question post, but I think it can be useful to others to learn how this works.很抱歉,问题很长,但我认为对其他人了解它是如何工作的很有用。

What I know:我知道的:

On any linux host ( not using docker container ), I can look at /proc/net/tcp to extract information tcp socket related.在任何 linux主机不使用 docker 容器)上,我可以查看/proc/net/tcp以提取与 tcp 套接字相关的信息。

So, I can detect the ports in LISTEN state with:因此,我可以通过以下方式检测LISTEN state 中的端口:

cat /proc/net/tcp | 
 grep " 0A " | 
  sed 's/^[^:]*: \(..\)\(..\)\(..\)\(..\):\(....\).*/echo $((0x\4)).$((0x\3)).$((0x\2)).$((0x\1)):$((0x\5))/g' | 
   bash

Results:结果:

0.0.0.0:111
10.174.109.1:53
127.0.0.53:53
0.0.0.0:22
127.0.0.1:631
0.0.0.0:8000

/proc/net/tcp gives UID , GID , unfortunately does not provides the PID . /proc/net/tcp给出UIDGID ,不幸的是不提供PID But returns the inode .但返回inode That I can use to discover the PID using it as file descriptor.我可以使用它作为文件描述符来发现PID

So one way is to search /proc looking for the inode socket.所以一种方法是搜索/proc寻找inode套接字。 It's slow, but works on host:它很慢,但适用于主机:

cat /proc/net/tcp |
 grep " 0A " |
  sed 's/^[^:]*: \(..\)\(..\)\(..\)\(..\):\(....\).\{72\}\([^ ]*\).*/echo $((0x\4)).$((0x\3)).$((0x\2)).$((0x\1)):$((0x\5))\\\t$(find \/proc\/ -type d -name fd 2>\/dev\/null \| while read f\; do ls -l $f 2>\/dev\/null \| grep -q \6 \&\& echo $f; done)/g' |
   bash

output: output:

0.0.0.0:111     /proc/1/task/1/fd /proc/1/fd /proc/924/task/924/fd /proc/924/fd
10.174.109.1:53 /proc/23189/task/23189/fd /proc/23189/fd
127.0.0.53:53   /proc/923/task/923/fd /proc/923/fd
0.0.0.0:22      /proc/1194/task/1194/fd /proc/1194/fd
127.0.0.1:631   /proc/13921/task/13921/fd /proc/13921/fd
0.0.0.0:8000    /proc/23122/task/23122/fd /proc/23122/fd

Permission tip 1: You will only see what you have permission to look at.权限提示 1:您只会看到您有权查看的内容。

Permission tip 2: fake root used in containers does not have access to all file descriptors in /proc/*/fd .权限提示 2:容器中使用的root无法访问/proc/*/fd中的所有文件描述符。 You need to query it for each user.您需要为每个用户查询它。

If you run as normal user the results are:如果您以普通用户身份运行,结果是:

0.0.0.0:111
10.174.109.1:53
127.0.0.53:53
0.0.0.0:22
127.0.0.1:631
0.0.0.0:8000    /proc/23122/task/23122/fd /proc/23122/fd

Using unshare to isolate environment it works as expected:使用unshare隔离环境,它按预期工作:

$ unshare -r --fork --pid unshare -r --fork --pid --mount-proc -n bash
# ps -fe
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  2 07:19 pts/6    00:00:00 bash
root       100     1  0 07:19 pts/6    00:00:00 ps -fe
# netstat -ntpl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
# python -m SimpleHTTPServer &
[1] 152
# Serving HTTP on 0.0.0.0 port 8000 ...
netstat -ntpl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:8000            0.0.0.0:*               LISTEN      152/python          
# cat /proc/net/tcp |
>  grep " 0A " |
>   sed 's/^[^:]*: \(..\)\(..\)\(..\)\(..\):\(....\).\{72\}\([^ ]*\).*/echo $((0x\4)).$((0x\3)).$((0x\2)).$((0x\1)):$((0x\5))\\\t$(find \/proc\/ -type d -name fd 2>\/dev\/null \| while read f\; do ls -l $f 2>\/dev\/null \| grep -q \6 \&\& echo $f; done)/g' |
>    bash
0.0.0.0:8000    /proc/152/task/152/fd /proc/152/fd
# ls -l /proc/152/fd
total 0
lrwx------ 1 root root 64 mai 25 07:20 0 -> /dev/pts/6
lrwx------ 1 root root 64 mai 25 07:20 1 -> /dev/pts/6
lrwx------ 1 root root 64 mai 25 07:20 2 -> /dev/pts/6
lrwx------ 1 root root 64 mai 25 07:20 3 -> 'socket:[52409024]'
lr-x------ 1 root root 64 mai 25 07:20 7 -> /dev/urandom
# cat /proc/net/tcp
  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode                                                     
   0: 00000000:1F40 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 52409024 1 0000000000000000 100 0 0 10 0 

Inside a docker container in my host, it seems to work in same way.在我的主机中的 docker 容器内,它似乎以相同的方式工作。

The problem:问题:

I have a container inside a kubernetes pod running jitsi.我在运行 jitsi 的 kubernetes pod 中有一个容器。 Inside this container, I am unable to get the PID of the service listening the ports.在这个容器内,我无法获取侦听端口的服务的 PID。

Nor after installing netstat:安装 netstat 后也不行:

root@jitsi-586cb55594-kfz6m:/# netstat -ntpl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:5222            0.0.0.0:*               LISTEN      -                   
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      -                   
tcp        0      0 0.0.0.0:5269            0.0.0.0:*               LISTEN      -                   
tcp        0      0 0.0.0.0:8888            0.0.0.0:*               LISTEN      -                   
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      -                   
tcp        0      0 0.0.0.0:5280            0.0.0.0:*               LISTEN      -                   
tcp        0      0 0.0.0.0:5347            0.0.0.0:*               LISTEN      -                   
tcp6       0      0 :::5222                 :::*                    LISTEN      -                   
tcp6       0      0 :::5269                 :::*                    LISTEN      -                   
tcp6       0      0 :::5280                 :::*                    LISTEN      -                   
# ps -fe
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 May22 ?        00:00:00 s6-svscan -t0 /var/run/s6/services
root        32     1  0 May22 ?        00:00:00 s6-supervise s6-fdholderd
root       199     1  0 May22 ?        00:00:00 s6-supervise jicofo
jicofo     203   199  0 May22 ?        00:04:17 java -Xmx3072m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp -Dnet.java.sip.communicator.SC_HOME_DIR_LOCATION=/ -Dnet.java.sip.communicator.SC_HOME_DIR_NAME=config -Djava
root      5990     0  0 09:48 pts/2    00:00:00 bash
root     10926  5990  0 09:57 pts/2    00:00:00 ps -fe

Finally the Questions:最后的问题:

a) Why can't I read the file descriptors of the proccess listening port 5222? a) 为什么我无法读取进程监听端口 5222 的文件描述符?

root@jitsi-586cb55594-kfz6m:/# cat /proc/net/tcp | grep " 0A "
    0: 00000000:1466 00000000:0000 0A 00000000:00000000 00:00000000 00000000   101        0 244887827 1 ffff9bd749145800 100 0 0 10 0                 
...
root@jitsi-586cb55594-kfz6m:/# echo $(( 0x1466 ))
5222
root@jitsi-586cb55594-kfz6m:/# ls -l  /proc/*/fd/* 2>/dev/null | grep 244887827                                                     
root@jitsi-586cb55594-kfz6m:/# echo $?
1
root@jitsi-586cb55594-kfz6m:/# su - svc
svc@jitsi-586cb55594-kfz6m:~$ id -u
101
svc@jitsi-586cb55594-kfz6m:~$ ls -l /proc/*/fd/* 2>/dev/null | grep 244887827
svc@jitsi-586cb55594-kfz6m:~$ echo $?
1

b) There is another way to list inode and link it to a pid without searching /proc/*/fd ? b) 还有另一种方法可以列出inode并将其链接到pid而无需搜索/proc/*/fd

Update 1:更新 1:

Based on Anton Kostenko tip, I looked to AppArmor.根据Anton Kostenko的提示,我查看了 AppArmor。 It's not the case because the server don't use AppArmor, but searching, took me to SELinux.事实并非如此,因为服务器不使用 AppArmor,而是搜索,将我带到了 SELinux。

In a ubuntu machine where AppArmor is running, I got:在运行 AppArmor 的 ubuntu 机器中,我得到:

$ sudo apparmor_status  | grep dock                                                                              
   docker-default

In the OKE(Oracle Kubernetes Engine, my case) node there is no AppArmor.在 OKE(Oracle Kubernetes 引擎,我的例子)节点中没有 AppArmor。 I got SELinux instead:我得到了 SELinux:

$ man selinuxenabled | grep EXIT -A1
EXIT STATUS
       It exits with status 0 if SELinux is enabled and 1 if it is not enabled.
$ selinuxenabled && echo $?
0

Now, I do believe that SELinux is blocking the /proc/*/fd listing from root inside the container.现在,我确实相信SELinux正在阻止/proc/*/fd从容器内的根目录列出。 But I don't know yet how to unlock it.但是我还不知道怎么解锁。

References:参考:

https://jvns.ca/blog/2016/10/10/what-even-is-a-container/ https://jvns.ca/blog/2016/10/10/what-even-is-a-container/

The issue is solved by adding the POSIX capability: CAP_SYS_PTRACE通过添加 POSIX 功能解决了该问题: CAP_SYS_PTRACE

I'm my case the container are under kubernetes orchestration.我的情况是容器在 kubernetes 编排下。

this reference explains about kubectl and POSIX Capabilities 本参考资料解释了kubectlPOSIX Capabilities

So I have所以我有

root@jitsi-55584f98bf-6cwpn:/# cat /proc/1/status | grep Cap
CapInh: 00000000a80425fb
CapPrm: 00000000a80425fb
CapEff: 00000000a80425fb
CapBnd: 00000000a80425fb
CapAmb: 0000000000000000

So I careful read the POSIX Capabilities Manual .所以我仔细阅读了POSIX Capabilities Manual But even adding CAP_SYS_ADMIN , the PID does not appear on netstat .但即使添加CAP_SYS_ADMINPID也不会出现在netstat上。 So I tested all capabilities.所以我测试了所有的能力。 CAP_SYS_PTRACE is The Chosen One CAP_SYS_PTRACE天选之人

root@jitsi-65c6b5d4f7-r546h:/# cat /proc/1/status | grep Cap
CapInh: 00000000a80c25fb
CapPrm: 00000000a80c25fb
CapEff: 00000000a80c25fb
CapBnd: 00000000a80c25fb
CapAmb: 0000000000000000

So here my deployment spec change:所以这里我的部署规范更改:

...
spec:
  ...
  template:
    ...
    spec:
      ...
      containers:
        ...
        securityContext:
          capabilities:
            add:
            - SYS_PTRACE
...

Yet I don't know what security reasons selinux use to do it.但是我不知道selinux使用什么安全原因来做到这一点。 But for now it's good enough for me.但现在对我来说已经足够了。

References:参考:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM