《OpenShift 4.x HOL教程汇总》 说明:本文已经在OpenShift 4.9环境中验证
安全上下文(SC)和安全上下文约束(SCC)
红帽OpenShift包括一对关键功能,即安全上下文(SC)和安全上下文约束(SCC),它们允许容器化应用访问受保护的Linux功能。
默认情况下,OpenShift会阻止集群中运行的Container访问那些受保护的功能。这些Linux功能包括:享文件系统、root访问,以及一些核心功能,如KILL命令。这些功能会影响到在同一Linux内核中运行的其他容器,所以OpenShift集群限制了Container对它们的访问。大多数云原生应用在这些限制下运行良好,但有些容器(特别是有状态的工作负载)需要更大的访问权限。容器如果要使用这些功能,需要获取集群的许可。
应用的安全上下文(SC)规定了应用需要的权限,而OpenShift集群的安全上下文约束(SCC)规定了集群允许的权限。带有SCC的SC使应用能够请求访问,同时限制集群将授予的访问。
用SCC控制容器应用对宿主机受保护功能的访问
对受保护功能的访问不是由应用控制,而是由运行应用的环境控制。因此,即使是流氓或黑客的应用也不能授予自己对受保护功能的访问权。访问权不是由应用配置的,应用只能访问pod要求的并且集群批准的功能。
一个pod指定了应用想要执行的受保护功能。当然,集群不会允许应用请求任何它想要的访问,否则容器就会变的非常不安全。为了容器应用执行安全,集群限制了pod可以使用的访问。如果应用试图执行一个受保护的功能,除非pod将容器配置为允许对该功能的访问,否则Linux将阻止应用执行受保护功能。
一个容器应用对受保护功能访问的过程会涉及到以下三个角色和分工:
- 开发人员:开发使用受保护功能的应用。
- 部署人员:编写部署清单,该清单使用SC(安全上下文)声明pod以及每个容器需要访问哪些受保护的功能,还声明了使用哪种ServiceAccount使用这些被保护功能。
- 管理员:决定是否授予部署所需要的访问权。管理员将SCC(安全上下文约束)分配给 ServiceAccount,从而允许应用按照声明来访问Linux功能。SCC可以是OpenShift预定义的,也可能是一个自定义。如果SCC准许访问,则OpenShift的准入控制流程将允许部署pod以及容器。
容器可申请使用的 Linux 宿主机功能
- CHOWN — 可以改变文件所有权和组所有权
- KILL — 可以在没有匹配的用户ID的情况下向进程发送信号
- NET_BROADCAST — 可以广播和收听组播
- NET_ADMIN — 可以配置接口、路由表、组播、IP防火墙的管理等。
- SYS_CHROOT — 可以使用chroot命令
- SYS_ADMIN — 可以设置域名和主机名,运行mount和unmount,锁定/解锁共享内存等。
- SYS_TIME — 可以操纵系统时钟
- MKNOD — 提供mknod()的特权
- SETCAP - 可以设置或删除文件的功能
OpenShift 内置的 SCC
- restricted:拒绝对所有宿主机功能的访问,并要求pod在运行时使用集群分配给项目的UID和SELinux上下文。这是最安全的SCC,总是默认使用。将适用于大多数典型的无状态工作负载。
- nonroot:与restricted相同,但允许用户以任何非root UID运行。适用于需要可预测的非root UID的应用,但具有restricted所有其他限制。
- anyuid:与restricted相同,但允许用户以任何UID和GID运行。因为它允许在容器外以root用户身份运行,潜在的风险很大。如果使用,SELinux控制可以在增加保护层方面发挥重要作用。另外,使用seccomp来过滤掉不需要的系统调用也是一个好办法。
- hostmount-anyuid:提供restricted相同,但允许一个pod使用任何UID进行主机挂载。
- hostnetwork:允许使用主机网络和主机端口,但仍然要求pods在分配给项目的UID和SELinux上下文运行。
- hostaccess:允许访问所有主机项目命名空间,但仍然要求pods在分配给项目的UID和SELinux上下文运行。
- privileged:允许访问所有特权和宿主机功能,以及作为任何用户、组或fsGroup运行的能力,以及任何SELinux上下文。这是最宽松的SCC政策。
带有SCC的部署过程
部署准入流程
下面通过一个部署场景来了解集群的准入接纳过程是如何使用部署清单、ServiceAccount和SCC来决定是否可以部署一个pod的。
- 开发人员实现一个需要访问受保护功能的应用,并将该应用交付给部署人员。
- 部署人员为该应用创建一个部署清单。该清单指定了一个安全上下文和一个服务账户。
- 管理员创建一个 Role 并为其分配一个 SCC。
- 管理员创建一个ServiceAccount,并将其与(3)创建的 Role 绑定。
- 部署人员使用部署清单部署应用。
- OpenShift处理部署清单,并尝试部署pod。部署过程根据清单中指定的ServiceAccount来决定使用哪个SCC。OpenShift准入流程将清单的SC与SCC进行比较,决定是阻止还是允许Pod部署。
- 阻止:某些请求的权限未被授予,因此部署失败。
- 准许。所有请求的权限都被授予,因此部署会创建 pod。按照 pod 的SC描述来配置容器,并在该容器中运行应用。
基于SCC的部署准入示例
创建一个项目,然后查看项目的“annotations”。
$ oc new-project scc-test-project
$ oc get project scc-test-project -o yaml
。。。
apiVersion: project.openshift.io/v1
kind: Project
metadata:
name: scc-test-project
annotations:
openshift.io/sa.scc.mcs: s0:c26,c5
openshift.io/sa.scc.supplemental-groups: 1000000000/10000
openshift.io/sa.scc.uid-range: 1000000000/10000
。。。
$ git clone https://github.com/IBM/scc-tutorial-assets
$ cd scc-tutorial-assets/
三项“annotations”分别设置的是:
- SELinux — 如果SCC将seLinuxContext.type设置为MustRunAs,并且没有设置seLinuxContext.seLinuxOptions,那么
Multi-Category Security(MCS)选项将被用作默认的SELinux选项。 - group IDs — 如果SCC将supplementalGroups.type设置为MustRunAs,但没有指定范围,将默认使用项目的supplemental groups范围。
- user IDs — 如果SCC将runAsUser.type设置为MustRunAsRange,但没有指定范围,将默认使用项目的用户ID范围。
使用缺省SCC
本例使用OpenShift内置的名为“restricted”的SCC作为准入控制。
准入流程
- FAIL: 该清单要求的fsGroup是5555。SCC被设置为 MustRunAs,这意味着请求的ID必须在指定的 范围内。由于SCC没有提供一个范围,因此使用项目的默认 范围被使用。在这种情况下,5555不在范围内 1000000000-1000009999。
- FAIL: 该清单要求的runAsUser是1234。SCC设置为MustRunAsRange,这意味着请求的ID必须在指定范围内。由于SCC没有提供范围,因此使用了项目的默认范围。在这种情况下,1234不在1000000000-1000009999范围内。
- PASS: 清单请求的runAsGroup是5678。SCC被设置为RunAsAny,这意味着组ID 5678是允许的,并将被分配给所有容器。
- FAIL: 清单要求的SYS_TIME能力没有被SCC允许(在allowedCapabilities或defaultAddCapabilities中都没有列出)。
- Note: 由于 SCC 将 seLinuxContext 设置为 MustRunAs,但没有指定上下文,所以容器被分配了项目的默认上下文值 s0:c26,c5。
示例验证
- 按顺序执行以下命令,并确认“deploy_default”可以成功。
$ oc create -f deploy_default.yaml
$ oc get pod -l app=scc-tutorial-default
NAME READY STATUS RESTARTS AGE
scc-tutorial-deploy-default-655f475c87-w7h5f 1/1 Running 0 10m
$
$ oc rsh scc-tutorial-deploy-default-655f475c87-w7h5f
sh-4.4$ ls -ld / /tmp /var/opt/app/data
dr-xr-xr-x. 1 root root 17 Nov 28 00:40 /
drwxrwxrwt. 1 root root 6 Nov 3 13:56 /tmp
drwxrwsrwx. 2 root 1000610000 6 Nov 28 00:40 /var/opt/app/data
sh-4.4$ echo hello > /var/opt/app/data/volume.txt
sh-4.4$ echo hello > /tmp/temp.txt
sh-4.4$ echo hello > /fail.txt
sh: /fail.txt: Permission denied
sh-4.4$ ls -l /tmp/temp.txt /var/opt/app/data/volume.txt
-rw-r--r--. 1 1000610000 root 6 Nov 28 00:52 /tmp/temp.txt
-rw-r--r--. 1 1000610000 1000610000 6 Nov 28 00:52 /var/opt/app/data/volume.txt
sh-4.4$ whoami
1000610000
sh-4.4$ id
uid=1000610000(1000610000) gid=0(root) groups=0(root),1000610000
sh-4.4$ exit
- 执行命令,确认“deploy_sc”执行错误。
$ oc create -f deploy_sc.yaml
$ oc get events | grep replicaset/scc-tutorial-deploy-sc
9s Warning FailedCreate replicaset/scc-tutorial-deploy-sc-799dcd89d5 Error creating: pods "scc-tutorial-deploy-sc-799dcd89d5-" is forbidden: unable to validate against any security context constraint: [provider restricted: .spec.securityContext.fsGroup: Invalid value: []int64{5555}: 5555 is not an allowed group spec.containers[0].securityContext.runAsUser: Invalid value: 1234: must be in the ranges: [1000610000, 1000619999]]
使用定制SCC
本例使用定制的名为“my-custom-scc”的SCC作为准入控制。
- Pass:清单要求的fsGroup是5555。由于SCC被设置为MustRunAs,而且要求请求的ID必须在指定的5000-6000范围内,因此请求通过。
- Pass:清单要求的runAsUser是1234。由于SCC被设置为MustRunAsRange,而且要求请求的ID必须在指定的1000-2000范围内,因此请求通过。
- Pass:清单要求的runAsGroup是5678。由于SCC被设置为MustRunAs,而且要求请求的ID必须在指定的5000-6000范围内,因此请求通过。
- Pass:清单要求的SYS_TIME能力是SCC默认允许的。
示例验证
- 执行命令,创建SCC、ServiceAccount和Role对象。
$ oc create -f scc-tutorial-scc.yaml
$ oc create sa scc-tutorial-sa
$ oc create -f rbac.yaml
- 执行命令,确认“deploy_sc_sa”可以执行成功。
$ oc create -f deploy_sc_sa.yaml
$ oc get pod
NAME READY STATUS RESTARTS AGE
scc-tutorial-deploy-default-655f475c87-w7h5f 1/1 Running 0 29m
scc-tutorial-deploy-sc-sa-67d64f6b5b-wgbvq 1/1 Running 0 42s
$ oc rsh scc-tutorial-deploy-sc-sa-67d64f6b5b-wgbvq
sh-4.4$ whoami
1234
sh-4.4$ id
uid=1234(1234) gid=5678 groups=5678,5555,5777,5888
sh-4.4$ ls -ld / /tmp /var/opt/app/data
dr-xr-xr-x. 1 root root 17 Nov 28 01:09 /
drwxrwxrwt. 1 root root 6 Nov 3 13:56 /tmp
drwxrwsrwx. 2 root 5555 6 Nov 28 01:09 /var/opt/app/data
sh-4.4$ echo hello > /var/opt/app/data/volume.txt
sh-4.4$ echo hello > /tmp/temp.txt
sh-4.4$ echo hello > /fail.txt
sh: /fail.txt: Permission denied
sh-4.4$ ls -l /tmp/temp.txt /var/opt/app/data/volume.txt
-rw-r--r--. 1 1234 5678 6 Nov 28 01:13 /tmp/temp.txt
-rw-r--r--. 1 1234 5555 6 Nov 28 01:13 /var/opt/app/data/volume.txt
sh-4.4$ exit
参考
https://developer.ibm.com/learningpaths/secure-context-constraints-openshift/intro/ https://cloud.tencent.com/developer/article/1603597 https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ https://access.redhat.com/documentation/zh-cn/openshift_container_platform/4.9/html/authentication_and_authorization/managing-pod-security-policies
|