即使设置 cap_net_raw 也无法在 linux 容器中打开原始套接字
Posted
技术标签:
【中文标题】即使设置 cap_net_raw 也无法在 linux 容器中打开原始套接字【英文标题】:unable open raw socket in a linux container even after setting cap_net_raw 【发布时间】:2021-09-30 02:00:58 【问题描述】:我正在运行一个代码,该代码在 docker 容器内打开一个原始套接字,其中 kubernetes 作为协调器。
以下是我的示例代码:
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <errno.h>
#include <netinet/tcp.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
int main (void)
//Create a raw socket
int s = socket (AF_INET, SOCK_RAW, IPPROTO_SCTP);
if(s == -1)
perror("Failed to create socket");
exit(1);
在我的容器/pod 中以非 root 用户身份运行代码时,出现此错误。
./rawSocTest
Failed to create socket: Operation not permitted
这很明显,因为它需要 root 级别的权限才能打开原始套接字。我通过设置能力 cap_net_raw 纠正了这一点。
getcap rawSocTest
rawSocTest = cap_net_raw+eip
现在当我再次运行它时。我得到一个不同的错误。
./rawSocTest
bash: ./rawSocTest: Permission denied
根据我的理解,设置功能应该可以解决我的问题。我在这里错过了什么吗?还是这是容器的已知限制?
提前致谢。
【问题讨论】:
这可能取决于您的 Dockerfile。你能展示一下吗?如果您不执行任何操作以在其他用户下运行,则您的容器应以 root 身份运行并具有所需的访问权限。 我在我的 dockerfile 中创建了一个用户和组,并在将二进制文件复制到映像后将所有权设置为该用户和组(基础映像是 CentOS nano 映像)。在此步骤之后,还在 dockerfile 中处理能力设置。在 kubernetes 部署的 manfest 文件中,安全上下文部分,我设置了 runAsuser 并提供了用户的用户 ID。我登录到 pod 并验证了相同的内容。 请将您进程的有效上限转储到容器中,grep CapEff /proc/self/status
。我怀疑通过切换到非 root 用户并且不设置二进制文件的文件功能,您最终会成为 Python 电影中没有胳膊和腿的“黑骑士”,也就是说,没有必要的有效上限。
【参考方案1】:
我解决了。我需要在 Kubernetes 部署的容器的安全上下文部分中设置功能。我添加了 NET_RAW 功能以允许创建原始套接字。我的印象是,只需在构建过程中添加能力 cap_net_raw 就足够了。但事实证明我的理解是错误的。
我做了一些研究并清理了部署解决方案。我在我的 pod 安全策略的允许功能部分添加了 NET_RAW。然后创建了角色和角色绑定。通过角色绑定将其链接到将部署我的 pod 的命名空间中的服务帐户。然后在 pod 部署中使用了这个 serviceAccount。不确定这是否是一个好的解决方案。
【讨论】:
您是否陷入了“文件上限”(在二进制文件上设置)、“有界上限”(在初始容器进程上设置)和“有效上限”之间的差距?切换到非 root 用户时,有效上限通常会被清除,因此您可能会以为容器指定的功能结束并设置为有界上限,但您没有有效上限,否则您的套接字系统调用将失败。 "不确定这是否是一个好的解决方案。" 就我自己的经验而言,这是 Kubernetes 安全框架内的正确解决方案。跨度>以上是关于即使设置 cap_net_raw 也无法在 linux 容器中打开原始套接字的主要内容,如果未能解决你的问题,请参考以下文章
即使设置了解决方案,也无法在更新 Swift 后使用 withMemoryRebound
即使在设置 EnableDelayedExpansion [重复] 之后,也无法在批处理文件中的 for 循环内设置变量值