安全性上下文(SCC)


风晓
风晓 2024-01-23 12:26:51 50258 赞同 0 反对 0
分类: 资源
安全性上下文(SCC)

关于安全性上下文

通过权限系统,用户可以在 OpenShift 中有效控制不同用户在系统中对什么资源对象进行什么样的操作。用权限来控制的对象是资源。Security Context Constraints (SCC )是 OpenShift 中的容器安全组件,要管控的是具体容器可以执行那些操作或者不可以执行那些操作。

在集群中我们可以通过命令获取当前项目下系统中所有 SCC 的定义

$ oc get scc
NAME                              PRIV    CAPS                                           SELINUX     RUNASUSER          FSGROUP     SUPGROUP    PRIORITY     READONLYROOTFS   VOLUMES
anyuid                            false   <no value>                                     MustRunAs   RunAsAny           RunAsAny    RunAsAny    10           false            ["configMap","downwardAPI","emptyDir","persistentVolumeClaim","projected","secret"]
elasticsearch-scc                 false   <no value>                                     RunAsAny    RunAsAny           RunAsAny    RunAsAny    <no value>   false            ["configMap","emptyDir","hostPath","persistentVolumeClaim","secret"]
hostaccess                        false   <no value>                                     MustRunAs   MustRunAsRange     MustRunAs   RunAsAny    <no value>   false            ["configMap","downwardAPI","emptyDir","hostPath","persistentVolumeClaim","projected","secret"]
hostmount-anyuid                  false   <no value>                                     MustRunAs   RunAsAny           RunAsAny    RunAsAny    <no value>   false            ["configMap","downwardAPI","emptyDir","hostPath","nfs","persistentVolumeClaim","projected","secret"]
hostnetwork                       false   <no value>                                     MustRunAs   MustRunAsRange     MustRunAs   MustRunAs   <no value>   false            ["configMap","downwardAPI","emptyDir","persistentVolumeClaim","projected","secret"]
log-collector-scc                 false   <no value>                                     RunAsAny    RunAsAny           RunAsAny    RunAsAny    <no value>   true             ["configMap","emptyDir","hostPath","secret"]
machine-api-termination-handler   false   <no value>                                     MustRunAs   RunAsAny           MustRunAs   MustRunAs   <no value>   false            ["downwardAPI","hostPath"]
netobserv-ebpf-agent              false   ["BPF","PERFMON","NET_ADMIN","SYS_RESOURCE"]   RunAsAny    RunAsAny           RunAsAny    RunAsAny    <no value>   false            ["awsElasticBlockStore","azureDisk","azureFile","cephFS","cinder","configMap","csi","downwardAPI","emptyDir","ephemeral","fc","flexVolume","flocker","gcePersistentDisk","gitRepo","glusterfs","iscsi","nfs","persistentVolumeClaim","photonPersistentDisk","portworxVolume","projected","quobyte","rbd","scaleIO","secret","storageOS","vsphere"]
node-exporter                     true    <no value>                                     RunAsAny    RunAsAny           RunAsAny    RunAsAny    <no value>   false            ["*"]
nonroot                           false   <no value>                                     MustRunAs   MustRunAsNonRoot   RunAsAny    RunAsAny    <no value>   false            ["configMap","downwardAPI","emptyDir","persistentVolumeClaim","projected","secret"]
noobaa                            false   []                                             MustRunAs   RunAsAny           MustRunAs   RunAsAny    <no value>   false            ["configMap","downwardAPI","emptyDir","persistentVolumeClaim","projected","secret"]
noobaa-endpoint                   false   ["SETUID","SETGID"]                            MustRunAs   RunAsAny           MustRunAs   RunAsAny    <no value>   false            ["configMap","downwardAPI","emptyDir","persistentVolumeClaim","projected","secret"]
pipelines-scc                     false   ["SETFCAP"]                                    MustRunAs   RunAsAny           MustRunAs   RunAsAny    10           false            ["configMap","downwardAPI","emptyDir","persistentVolumeClaim","projected","secret"]
privileged                        true    ["*"]                                          RunAsAny    RunAsAny           RunAsAny    RunAsAny    <no value>   false            ["*"]
restricted                        false   <no value>                                     MustRunAs   MustRunAsRange     MustRunAs   RunAsAny    <no value>   false            ["configMap","downwardAPI","emptyDir","persistentVolumeClaim","projected","secret"]
rook-ceph                         true    <no value>                                     MustRunAs   RunAsAny           MustRunAs   RunAsAny    <no value>   false            ["configMap","downwardAPI","emptyDir","hostPath","persistentVolumeClaim","projected","secret"]
rook-ceph-csi                     true    ["SYS_ADMIN"]                                  RunAsAny    RunAsAny           RunAsAny    RunAsAny    <no value>   false            ["configMap","emptyDir","hostPath","projected"]

集群默认的安全性上下文约束官方描述如下表:

安全性上下文约束 描述
anyuid 提供 restricted SCC 的所有功能,但允许用户使用任何 UID 和任何 GID 运行。
hostaccess 允许访问所有主机命名空间,但仍要求使用分配至命名空间的 UID 和 SELinux 上下文运行容器集。警告此 SCC 允许主机访问命名空间、文件系统和 PID。它应当仅由受信任的容器集使用。请谨慎授予。
hostmount-anyuid 提供 restricted SCC 的所有功能,但允许主机以任何 UID 和系统中的任何 GID 挂载和运行。警告此 SCC 允许主机文件系统作为任何 UID 访问,包括 UID 0。请谨慎授予。
hostnetwork 允许使用主机网络和主机端口,但仍要求使用分配至命名空间的 UID 和 SELinux 上下文运行容器集。警告如果在 control plane 主机上运行额外的工作负载,在提供 hostnetwork 访问权限时要谨慎。在 control plane 主机上运行 hostnetwork 的工作负载是集群中的 root 用户,必须相应地信任它。
node-exporter 用于 Prometheus 节点导出器。警告此 SCC 允许主机文件系统作为任何 UID 访问,包括 UID 0。请谨慎授予。
nonroot 提供 restricted SCC 的所有功能,但允许用户使用任何非 root UID 运行。用户必须指定 UID,否则必须在容器运行时清单中指定。
privileged 允许访问所有特权和主机功能,并且能够以任何用户、任何组、任何 FSGroup 以及任何 SELinux 上下文运行。警告这是最宽松的 SCC,应仅用于集群管理。请谨慎授予。特权 SCC 允许:用户运行特权 PodPod 将主机目录挂载为卷Pod 以任意用户身份运行Pod 使用任意 MCS 标签运行Pod 使用主机的 IPC 命名空间Pod 使用主机的 PID 命名空间Pod 使用任何 FSGroupPod 使用任何补充组Pod 使用任何 seccomp 配置集Pod 请求任何功能注意在 Pod 规格中设置 privileged: true 并不一定会选择特权 SCC。如果用户有权使用,则具有 allowPrivilegedContainer: true 并有最高优先级的 SCC 会被选择。
restricted 拒绝访问所有主机功能,并且要求使用 UID 运行容器集,以及分配至命名空间的 SELinux 上下文。这是一个新安装可以提供的最严格的 SCC,经过身份验证的用户会默认使用它。受限的 SCC:确保 Pod 无法以特权方式运行确保 Pod 无法挂载主机目录卷要求 Pod 以预先分配的 UID 范围内的用户运行要求 pod 使用预先分配的 MCS 标签运行允许 Pod 使用任何 FSGroup允许 pod 使用任何补充组注意有限制的 SCC 是系统默认提供的、有最严格限制的 SCC。但是,您可以创建一个更加严格的自定义 SCC。例如,您可以创建一个 SCC,它将 readOnlyRootFS 限制为 true,并允许 PrivilegeEscalation 为 false。

举例

下面通过一个应用例子来具体体现使用 SCC 的作用。

使用一个用户在集群中创建一个项目并部署一个 httpd 容器 docker.io/library/httpd

$ oc new-project httpd-demo
$ oc new-app docker.io/library/httpd:2.4.17

当 httpd 镜像拉取完成并且部署到集群上后,查看 Pod 状态为 CrashLoopBackOff

$ oc get pod -n httpd-demo
NAME                     READY   STATUS             RESTARTS     AGE
httpd-5b4786b579-dcn55   0/1     CrashLoopBackOff   1 (5s ago)   10s

通过以下命令查看容器日志

$ oc logs httpd-5b4786b579-dcn55
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 10.131.1.135. Set the 'ServerName' directive globally to suppress this message
(13)Permission denied: AH00072: make_sock: could not bind to address [::]:80
(13)Permission denied: AH00072: make_sock: could not bind to address 0.0.0.0:80
no listening sockets available, shutting down
AH00015: Unable to open logs

通过日志发现容器启动的 httpd 程序因为无法监听 80 端口而导致错误退出。

此时我们通过修改 httpd 应用,增加一个 command 属性来覆盖容器默认的启动命令,避免容器因为进程启动的错误而使容器退出,从而获取容器的 shell 查看当前用户的 id。以有雀容器云管理平台为例:

通过 CLI 修改应用

$ oc edit deploy httpd -o json

修改前

 "containers": [
                    {
                        "image": "docker.io/library/httpd@sha256:ff734d5b9bfc1d33936211a9564e1811665ee9487d7ab38732ae38180dd613b9",
                        "imagePullPolicy": "IfNotPresent",
                        "name": "httpd",
                        "ports": [
                            {
                                "containerPort": 80,
                                "protocol": "TCP"
                            }
                        ],

修改后

 "containers": [
                    {
                        "image": "docker.io/library/httpd@sha256:ff734d5b9bfc1d33936211a9564e1811665ee9487d7ab38732ae38180dd613b9",
                        "imagePullPolicy": "IfNotPresent",
                        "command":["bash","-c","sleep 365d"],
                        "name": "httpd",
                        "ports": [
                            {
                                "containerPort": 80,
                                "protocol": "TCP"
                            }
                        ],

通过 Web 控制台修改

编辑Deployment
添加command参数


通过上述修改,让容器不再执行 httpd Dockefile 定义的 httpd 进程而是执行 sleep 365d 命令进入休眠。

此时查看 httpd Pod 状态为 Running

$ oc get pod 
NAME                    READY   STATUS    RESTARTS   AGE
httpd-fbdfd4d65-c44pd   1/1     Running   0          99s

通过 rsh 获取容器内的 shell,检查容器的运行用户

$ oc rsh httpd-fbdfd4d65-c44pd
$ id
uid=1000930000(1000930000) gid=0(root) groups=0(root),1000930000
$ 

上述可以看到当前容器的执行用户是一个UID 为 1000930000 的用户,而非 httpd 镜像定义的 httpd root用户,httpd 容器启动时,默认执行 httpd 进程尝试监听 80 端口,在Linux 上80 端口的监听是需要管路员权限的,作为普通用户的 1000930000 是没有权限监听的。

此时我们在计算节点上单独启动 httpd 容器观察发现可以正常运行。

$ docker run -it --rm -p 8081:8080 docker.io/library/httpd:2.4.17
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message
[Tue Nov 07 01:40:38.551504 2023] [mpm_event:notice] [pid 1:tid 139755712436096] AH00489: Apache/2.4.17 (Unix) configured -- resuming normal operations
[Tue Nov 07 01:40:38.551576 2023] [core:notice] [pid 1:tid 139755712436096] AH00094: Command line: 'httpd -D FOREGROUND

OpenShift 使用了docker 作为平台的容器引擎,因此符合 Docker 标准的镜像可以在 OpenShift 平台上运行。但观察上述两个容器的运行结果可以发现相同的镜像在 OpenShift 和 Docker 运行产生了不同的结果,究其原因是因为 DockerHub上的大量镜像是使用 root 用户启动应用的,OpenShift 从安全需要方面,引入了 SCC 这一特性,SCC 限制了容器内启动用户的 UID 范围,虽然镜像的 Dockerfile 定义了容器使用 root 用户启动应用程序,但是在容器云平台上运行时,平台会根据容器和用户的安全性上下文设置来决定是使用 Dockerfile 指定的用户运行还是随机生成一个普通用户运行。

此时查看系统的 SCC restricted 的 RUNASUSER 的值为 MustRunAsRange,因此容器启动必需需要响应的权限。

$ oc get scc restricted 
NAME         PRIV    CAPS         SELINUX     RUNASUSER        FSGROUP     SUPGROUP   PRIORITY     READONLYROOTFS   VOLUMES
restricted   false   <no value>   MustRunAs   MustRunAsRange   MustRunAs   RunAsAny   <no value>   false            ["configMap","downwardAPI","emptyDir","persistentVolumeClaim","projected","secret"]

如果想要运行 httpd 这个需要特权用户的镜像,就需要让当前用户获取在容器内按任意用户启动应用的权限。

方法一:

修改默认的 RUNASUSER 的值为 RUNASANY,允许使用任意用户,但是这样做会影响集群中所有的用户和 Service Account。

方法二:

将当前项目默认的 Service Account 加入有更高权限的 SCC 组。

此例我们使用方法二。

通过文章开始的 SCC 组的描述我们可以得知,系统默认定义的 SCC 组中 privileged SCC 组的权限最大,restricted 组的权限最小,普通用户及其创建项目的 Service Account 默认都是 restricted 组。在此例中我们想要提升容器内运行用户的权限,可以将当前项目下默认的 Service Account 加入到 anyuid SCC 组中。

$ oc adm policy add-scc-to-user anyuid -z default -n httpd-demo
clusterrole.rbac.authorization.k8s.io/system:openshift:scc:anyuid added: "default"        

此时我们将 httpd 应用添加的 command 参数去除(修改方式与添加 command 参数一致),再次查看 Pod 状态。

$ oc get pod 
NAME                     READY   STATUS    RESTARTS   AGE
httpd-8568d8c56b-gppnl   1/1     Running   0          70s

如果您发现该资源为电子书等存在侵权的资源或对该资源描述不正确等,可点击“私信”按钮向作者进行反馈;如作者无回复可进行平台仲裁,我们会在第一时间进行处理!

评价 0 条
风晓L1
粉丝 1 资源 2038 + 关注 私信
最近热门资源
银河麒麟桌面操作系统备份用户数据  130
统信桌面专业版【全盘安装UOS系统】介绍  129
银河麒麟桌面操作系统安装佳能打印机驱动方法  120
银河麒麟桌面操作系统 V10-SP1用户密码修改  108
麒麟系统连接打印机常见问题及解决方法  30
最近下载排行榜
银河麒麟桌面操作系统备份用户数据 0
统信桌面专业版【全盘安装UOS系统】介绍 0
银河麒麟桌面操作系统安装佳能打印机驱动方法 0
银河麒麟桌面操作系统 V10-SP1用户密码修改 0
麒麟系统连接打印机常见问题及解决方法 0
作者收入月榜
1

prtyaa 收益393.62元

2

zlj141319 收益218元

3

1843880570 收益214.2元

4

IT-feng 收益210.13元

5

风晓 收益208.24元

6

777 收益172.71元

7

Fhawking 收益106.6元

8

信创来了 收益105.84元

9

克里斯蒂亚诺诺 收益91.08元

10

技术-小陈 收益79.5元

请使用微信扫码

加入交流群

请使用微信扫一扫!