Kubernetes为Pod或容器配置SecurityContext

半兽人 发表于: 2020-06-04   最后更新时间: 2020-06-07  

安全上下文定义了Pod或容器的特权和访问控制设置。 安全上下文设置包括但不限于:

  • 自由访问控制:访问对象(如文件)的权限是基于user ID(UID)和 group ID(GID)

  • Security Enhanced Linux (SELinux): 为对象分配了安全标签。

  • 以特权或非特权身份运行。

  • Linux Capabilities: 为进程提供一些特权,但不是root用户的所有特权。

  • AppArmor: 使用程序配置文件来限制单个程序的功能。

  • Seccomp: 过滤一个进程的系统调用。

  • AllowPrivilegeEscalation:控制进程是否可以比其父进程获得更多的特权。该布尔值直接控制在容器进程上是否设置了no_new_privs标志。 在以下情况下,AllowPrivilegeEscalation始终为true:
    1)以特权OR运行;
    2)具有CAP_SYS_ADMIN

  • readOnlyRootFilesystem: 将容器的root文件系统挂载为只读。

上述项目并不是一套完整的安全上下文设置 - 请参阅安全上下文SecurityContext完整列表。

有关Linux中的安全性机制的更多信息,请参见Overview of Linux Kernel Security Features

设置Pod的SecurityContext

要为Pod指定安全设置,需要在Pod sepc中增加securityContext字段。securityContext字段是PodSecurityContext对象。为Pod指定的安全设置将应用到Pod中的所有容器。下面是一个有securityContextemptyDir卷的Pod的配置文件:

apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo
spec:
  securityContext:
    runAsUser: 1000
    runAsGroup: 3000
    fsGroup: 2000
  volumes:
  - name: sec-ctx-vol
    emptyDir: {}
  containers:
  - name: sec-ctx-demo
    image: busybox
    command: [ "sh", "-c", "sleep 1h" ]
    volumeMounts:
    - name: sec-ctx-vol
      mountPath: /data/demo
    securityContext:
      allowPrivilegeEscalation: false

在配置文件中,runAsUser字段指定对于Pod中的所有容器,所有进程都以用户ID1000运行。runAsGroup字段为Pod的任何容器中的所有进程指定主要组ID3000。如果省略此字段,则容器的主要组ID将为root(0)。指定runAsGroup时,用户1000和组3000也将拥有所有创建的文件。由于指定了fsGroup字段,因此容器的所有进程也会补充组ID 2000的一部分。卷/data/demo以及在该卷中创建的任何文件的所有者均为组ID2000

创建Pod:

kubectl apply -f https://k8s.io/examples/pods/security/security-context.yaml

验证Pod容器是否运行:

kubectl get pod security-context-demo

获取正在运行的容器的shell:

kubectl exec -it security-context-demo -- sh

在shell中,列出正在运行的进程:

ps

输出显示进程正在以用户1000的身份运行,这是runAsUser的值:

PID   USER     TIME  COMMAND
    1 1000      0:00 sleep 1h
    6 1000      0:00 sh
...

进到/data,并列出目录。

cd /data
ls -l

输出显示,/data/demo目录包含组ID2000,也就是fsGroup的值。

drwxrwsrwx 2 root 2000 4096 Jun  6 20:08 demo

/data/demo目录中, 创建一个文件:

cd demo
echo hello > testfile

列出 /data/demo 目录:

ls -l

输出显示testfile具有组ID 2000,这是fsGroup的值。

-rw-r--r-- 1 1000 2000 6 Jun  6 20:08 testfile

运行以下命令

$ id
uid=1000 gid=3000 groups=2000

你会看到gid是3000,与runAsGroup字段相同。如果省略了 "runAsGroup",那么gid将保持为0(root),并且进程将能够与root(0)组所拥有的文件进行交互,并且具有root(0)组所需的组权限。

最后,退出shell:

exit

为Pods配置卷权限和所有权变更策略

默认情况下,Kubernetes递归地更改每个卷内容的所有权和权限,以匹配装入该卷时Pod的securityContext中指定的fsGroup。 对于数据量大的,检查和更改所有权和权限可能会花费大量时间,从而减慢了Pod的启动速度。 您可以在securityContext中使用fsGroupChangePolicy字段来控制Kubernetes检查和管理卷的所有权和权限的方式。

fsGroupChangePolicy - fsGroupChangePolicy定义了在暴露于Pod中之前更改卷的所有权和权限的行为。该字段仅适用于支持fsGroup控制的所有权和权限的卷类型。 该字段具有两个可能的值:

  • OnRootMismatch:仅当根目录的权限和所有权与卷的预期权限不匹配时,才更改权限和所有权。这可以帮助缩短更改卷的所有权和权限所需的时间。

  • Always: 挂载卷后,始终会变更卷的权限和所有权。

例如:

securityContext:
  runAsUser: 1000
  runAsGroup: 3000
  fsGroup: 2000
  fsGroupChangePolicy: "OnRootMismatch"

这是一个Alpha功能。要使用它,请为kube-api-serverkube-controller-managerkubelet启用功能门ConfigurableFSGroupPolicy

注意:此字段对临时卷类型(例如secret,configMap和emptydir)无效。

设置容器的安全上下文

要为容器指定安全设置,只要容器中包括securityContext字段,当它们重叠时,会覆盖在Pod级别的设置。容器级别的设置不会影响Pod的设置。

这是一个容器的Pod的配置文件。 Pod和Container都有一个securityContext字段:

apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo-2
spec:
  securityContext:
    runAsUser: 1000
  containers:
  - name: sec-ctx-demo-2
    image: gcr.io/google-samples/node-hello:1.0
    securityContext:
      runAsUser: 2000
      allowPrivilegeEscalation: false

创建Pod:

kubectl apply -f https://k8s.io/examples/pods/security/security-context-2.yaml

验证是否运行成功:

kubectl get pod security-context-demo-2

进入容器:

kubectl exec -it security-context-demo-2 -- sh

运行进程命令:

ps aux

输出显示进程正在以用户2000身份运行。这是为Container指定的runAsUser的值。 它会覆盖为Pod指定的值1000。

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
2000         1  0.0  0.0   4336   764 ?        Ss   20:36   0:00 /bin/sh -c node server.js
2000         8  0.1  0.5 772124 22604 ?        Sl   20:36   0:00 node server.js
...

退出shell:

exit

设置容器的功能

使用Linux功能,您可以授予进程某些特权,而无需授予root用户的所有特权。要为容器添加或删除Linux功能,可在Container清单的securityContext中包含功能字段。

首先,查看不包含功能字段时会发生什么。这是不添加或删除任何容器功能的配置文件:

apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo-3
spec:
  containers:
  - name: sec-ctx-3
    image: gcr.io/google-samples/node-hello:1.0

创建Pod:

kubectl apply -f https://k8s.io/examples/pods/security/security-context-3.yaml

验证容器是否运行成功:

kubectl get pod security-context-demo-3

进入到容器:

kubectl exec -it security-context-demo-3 -- sh

列出正在运行的进程:

ps aux

输出显示容器的进程ID(PID):

USER  PID %CPU %MEM    VSZ   RSS TTY   STAT START   TIME COMMAND
root    1  0.0  0.0   4336   796 ?     Ss   18:17   0:00 /bin/sh -c node server.js
root    5  0.1  0.5 772124 22700 ?     Sl   18:17   0:00 node server.js

查看进程1的状态:

cd /proc/1
cat status

The output shows the for the process:
输出显示该进程的功能图(capabilities bitmap):

...
CapPrm:    00000000a80425fb
CapEff:    00000000a80425fb
...

记下功能位图,然后退出:

exit

接下来,运行与前面的容器相同的容器,该配置增加了CAP_NET_ADMINCAP_SYS_TIME

apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo-4
spec:
  containers:
  - name: sec-ctx-4
    image: gcr.io/google-samples/node-hello:1.0
    securityContext:
      capabilities:
        add: ["NET_ADMIN", "SYS_TIME"]

创建Pod:

kubectl apply -f https://k8s.io/examples/pods/security/security-context-4.yaml

进入容器:

kubectl exec -it security-context-demo-4 -- sh

查看进程1:

cd /proc/1
cat status

输出显示该进程的功能位图:

...
CapPrm:    00000000aa0435fb
CapEff:    00000000aa0435fb
...

比较两个容器的功能:

00000000a80425fb
00000000aa0435fb

在第一个容器的功能位图中,位12和25被清除。在第二个容器中,设置了位12和25。位12是CAP_NET_ADMIN,位25是CAP_SYS_TIME。 有关功能常数的定义,请参见capability.h

注意:Linux功能常数的格式为CAP_XXX。 但是,当您在Container清单中列出功能时,必须忽略常量的CAP_部分。 例如,要添加CAP_SYS_TIME,需要在功能列表中包括SYS_TIME

SELinux标签分配给容器

要将SELinux标签分配给容器,只在Pod或容器的securityContext部分中包含seLinuxOptions字段,示例如下:

...
securityContext:
  seLinuxOptions:
    level: "s0:c123,c456"

注:要分配SELinux标签,必须在主机操作系统上加载SELinux安全模块。

最后,删除测试例子

删除Pod:

kubectl delete pod security-context-demo
kubectl delete pod security-context-demo-2
kubectl delete pod security-context-demo-3
kubectl delete pod security-context-demo-4


您需要解锁本帖隐藏内容请: 点击这里
本帖隐藏的内容




上一条: kubernetes通过kube-prometheus安装高可用的监控告警
下一条: kubernetes自定义资源版本