10 个 Kubernetes 安全上下文配置

在 Kubernetes 中安全地运行工作负载是很困难的,有很多配置都可能会影响到整个 Kubernetes API 的安全性,这需要我们有大量的知识积累来正确的实施。Kubernetes 在安全方面提供了一个强大的工具 securityContext,每个 Pod 和容器清单都可以使用这个属性。在本文中我们将了解各种 securityContext 的配置,探讨它们的含义,以及我们应该如何使用它们。

securityContext 设置在 PodSpec 和ContainerSpec 规范中都有定义,这里我们分别用[P][C]来表示。需要注意的是,如果一个设置在两个作用域中都可以使用和配置,那么我们应该优先考虑设置容器级别的。

1runAsNonRoot [P/C]


我们知道容器是使用 namespaces 和 cgroups 来限制其进程,但只要在部署的时候做了一次错误的配置,就可以让这些进程访问主机上的资源。如果该进程以 root 身份运行,它对这些资源的访问权限与主机 root 账户是相同的。此外,如果其他 pod 或容器设置被用来减少约束(比如 procMount 或 capabilities),拥有一个 root UID 就会提高风险,除非你有一个非常好的原因,否则你不应该以 root 身份运行一个容器。

那么,如果你有一个使用 root 的镜像需要部署,那应该怎么办呢?

1.1 使用基础镜像中提供的用户

通常情况下,基础镜像已经创建并提供了一个用户,例如,官方的 Node.js 镜像带有一个 UID 为 1000 的名为 node 的用户,我们就可以使用该身份来运行容器,但他们并没有在 Dockerfile 中明确地设置当前用户。我们可以在运行时用 runAsUser 设置来配置它,或者用自定义的 Dockerfile 来更改镜像中的当前用户。这里我们来看看使用自定义的 Dockerfile 来构建我们自己的镜像的例子。

在不深入了解镜像构建的情况下,让我们假设我们有一个预先构建好的 npm 应用程序。这里是一个最小的 Dockerfile 文件,用来构建一个基于 node:slim 的镜像,并以提供的 node 用户身份运行。

FROM node:slim
COPY --chown=node . /home/node/app/   # <--- Copy app into the home directory with right ownership
USER 1000                             # <--- Switch active user to “node” (by UID)
WORKDIR /home/node/app                # <--- Switch current directory to app
ENTRYPOINT ["npm", "start"]           # <--- This will now exec as the “node” user instead of root

其中以 USER 开头的一行就是关键设置,这使得 node 成为从这个镜像启动的任何容器里面的默认用户。我们使用 UID 而不是用户的名字,因为 Kubernetes 无法在启动容器前将镜像的默认用户名映射到 UID 上,并且在部署时指定 runAsNotRoot: true,会返回有关错误。

1.2 基础镜像没有提供用户

如果我们使用的基础镜像没有提供一个可以使用的用户,那么我们又应该怎么做呢?对于大部分进程来说,我们只需在自定义的 Dockerfile 中创建一个用户并使用它即可。如下所示:

FROM node:slim
RUN useradd somebody -u 10001 --create-home --user-group  # <--- Create a user
COPY --chown=somebody . /home/somebody/app/
USER 10001
WORKDIR /home/somebody/app
ENTRYPOINT ["npm", "start"]

这里我们增加了一行创建用户的 RUN 命令即可。不过需要注意的是这对于 node.js 和 npm 来说,这很好用,但是其他工具可能需要文件系统的不同元素进行所有权变更。如果遇到任何问题,需要查阅对应工具的文档。

2runAsUser/runAsGroup [P/C]


容器镜像可能有一个特定的用户或组,我们可以用 runAsUser 和 runAsGroup 来进行覆盖。通常,这些设置与包含具有相同所有权 ID 的文件的卷挂载结合在一起。

....
spec:
  containers:
    - name: web
      image: mycorp/webapp:1.2.3
  securityContext:
    runAsNonRoot: true
    runAsUser: 10001
....

不过使用这些配置也是有风险的,因为你为容器做出的运行时决定可能与原始镜像不兼容。例如,jenkins/jenkins 镜像以名为 jenkins:jenkins 的组:用户身份运行,其应用文件全部由该用户拥有。如果我们配置一个不同的用户,它将无法启动,因为该用户不存在于镜像的 /etc/passwd 文件中。即使它以某种方式存在,它也很可能在读写 jenkins:jenkins 拥有的文件时出现问题。我们可以用一个简单的 docker 运行命令来验证这个问题。

$ docker run --rm -it -u eric:eric jenkins/jenkins
docker: Error response from daemon: unable to find user eric: no matching entries in passwd file.

上面我们提到确保容器进程不以 root 用户身份运行是一个非常好的主意,但不要依赖 runAsUser 或 runAsGroup 设置来保证这一点,未来有人可能会删除这些配置,请确保同时将 runAsNonRoot 设置为 true。

5避免使用特权容器 [C]


给容器授予特权模式是非常危险的,一般会有一种更简单的方式来实现特定的权限,或者可以通过授予 Linux Capabilities 权限来控制。容器运行时控制器着特权模式的具体实现,但是它会授予容器所有的特权,并解除由 cgroup 控制器执行的限制,它还可以修改 Linux 安全模块的配置,并允许容器内的进程逃离容器。

容器在宿主机中提供了进程隔离,所以即使容器是使用 root 身份运行的,也有容器运行时不授予容器的 Capabilities。如果配置了特权模式,容器运行时就会授予系统 root 的所有能力,从安全角度来看,这是很危险的,因为它允许对底层宿主机系统的所有操作访问。

避免使用特权模式,如果你的容器确实需要额外的能力,只需通过添加 capabilities 来满足你的需求。除非你的容器需要控制主机内核中的系统级设置,如访问特定的硬件或重新配置网络,并且需要访问主机文件系统,那么它就不需要特权模式。

          securityContext:
            allowPrivilegeEscalation: true
            capabilities:
              drop:
                - ALL
              add:
                - NET_BIND_SERVICE
            # www-data -> 101
            runAsUser: 101

6Linux Capabilities [C]


Capabilities 是一个内核级别的权限,它允许对内核调用权限进行更细粒度的控制,而不是简单地以 root 身份运行。Capabilities 包括更改文件权限、控制网络子系统和执行系统管理等功能。在 securityContext 中,Kubernetes 可以添加或删除 Capabilities,单个 Capabilities 或逗号分隔的列表可以作为一个字符串数组进行配置。另外,我们也可以使用 all 来添加或删除所有的配置。这种配置会被传递给容器运行时,在它创建容器的时候会配置上 Capabilities 集合,如果 securityContext 中没有配置,那么容器将会直接容器运行时提供的所有默认配置。

securityContext:
  capabilities:
    drop:
      - all
    add: ["MKNOD"]

一般推荐的做法是先删除所有的配置,然后只添加你的应用程序实际需要的,在大部分情况下,应用程序在正常运行中实际上不需要任何 Capabilities,通过删除所有配置来测试,并通过监控审计日志来调试问题,看看哪些功能被阻止了。

请注意,当在 securityContext 中列出要放弃或添加的 Capabilities 时,你要删除内核在命名 Capabilities 时使用的 CAP_ 前缀。capsh 工具可以给我们一个比较友好的调试信息,可以来说明你的容器中到底启用了哪些 Capabilities,当然不要在生产容器中使用这个工具,因为这使得攻击者很容易弄清楚哪些 Capabilities 被启用了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值