7.6. 管理 SELinux 配置集

创建和管理 SELinux 配置集并将其绑定到工作负载。

重要

Security Profiles Operator 仅支持 Red Hat Enterprise Linux CoreOS (RHCOS) worker 节点。不支持 Red Hat Enterprise Linux (RHEL) 节点。

7.6.1. 创建 SELinux 配置集

使用 SelinuxProfile 对象来创建配置集。

SelinuxProfile 对象有几个功能,允许改进安全强化和可读性:

  • 限制配置集从继承到当前命名空间或系统范围的配置集。因为系统中通常会安装很多配置集,但集群工作负载只能使用子集,所以可继承的系统配置集列在 spec.selinuxOptions.allowedSystemProfilesspod 实例中。
  • 执行权限、类和标签的基本验证。
  • 添加新的关键字 @self,用于描述使用该策略的进程。这允许在工作负载和命名空间间轻松使用策略,因为策略的使用取决于名称和命名空间。
  • 与直接在 SELinux CIL 语言中写入配置文件相比,添加了更高的安全强化和易读功能。

流程

  1. 运行以下命令来创建项目:

    $ oc new-project nginx-deploy
  2. 通过创建以下 SelinuxProfile 对象来创建可与非特权工作负载一起使用的策略:

    apiVersion: security-profiles-operator.x-k8s.io/v1alpha2
    kind: SelinuxProfile
    metadata:
      name: nginx-secure
      namespace: nginx-deploy
    spec:
      allow:
        '@self':
          tcp_socket:
          - listen
        http_cache_port_t:
          tcp_socket:
          - name_bind
        node_t:
          tcp_socket:
          - node_bind
      inherit:
      - kind: System
        name: container
  3. 运行以下命令,等待 selinuxd 安装策略:

    $ oc wait --for=condition=ready -n nginx-deploy selinuxprofile nginx-secure

    输出示例

    selinuxprofile.security-profiles-operator.x-k8s.io/nginx-secure condition met

    策略被放入由 Security Profiles Operator 拥有的容器中的 emptyDir 中。策略以通用中间语言 (CIL) 格式保存,格式为 /etc/selinux.d/<name>_<namespace>.cil

  4. 运行以下命令来访问 pod:

    $ oc -n openshift-security-profiles rsh -c selinuxd ds/spod

验证

  1. 运行以下命令,使用 cat 查看文件内容:

    $ cat /etc/selinux.d/nginx-secure_nginx-deploy.cil

    输出示例

    (block nginx-secure_nginx-deploy
    (blockinherit container)
    (allow process nginx-secure_nginx-deploy.process ( tcp_socket ( listen )))
    (allow process http_cache_port_t ( tcp_socket ( name_bind )))
    (allow process node_t ( tcp_socket ( node_bind )))
    )

  2. 运行以下命令验证策略是否已安装:

    $ semodule -l | grep nginx-secure

    输出示例

    nginx-secure_nginx-deploy

7.6.2. 将 SELinux 配置集应用到 pod

创建 pod 以应用其中一个创建的配置集。

对于 SELinux 配置集,必须标记命名空间以允许 特权 工作负载。

流程

  1. 运行以下命令,将 scc.podSecurityLabelSync=false 标签应用到 nginx-deploy 命名空间:

    $ oc label ns nginx-deploy security.openshift.io/scc.podSecurityLabelSync=false
  2. 运行以下命令,将 privileged 标签应用到 nginx-deploy 命名空间:

    $ oc label ns nginx-deploy --overwrite=true pod-security.kubernetes.io/enforce=privileged
  3. 运行以下命令来获取 SELinux 配置集使用字符串:

    $ oc get selinuxprofile.security-profiles-operator.x-k8s.io/nginx-secure -n nginx-deploy -ojsonpath='{.status.usage}'

    输出示例

    nginx-secure_nginx-deploy.process

  4. .spec.containers[].securityContext.seLinuxOptions 属性中应用工作负载清单中的输出字符串:

    apiVersion: v1
    kind: Pod
    metadata:
      name: nginx-secure
      namespace: nginx-deploy
    spec:
      containers:
        - image: nginxinc/nginx-unprivileged:1.21
          name: nginx
          securityContext:
            seLinuxOptions:
              # NOTE: This uses an appropriate SELinux type
              type: nginx-secure_nginx-deploy.process
    重要

    在创建工作负载前,SELinux type 必须存在。

7.6.2.1. 应用 SELinux 日志策略

要记录策略违反或 AVC 拒绝,请将 SElinuxProfile 配置集设置为 permissive

重要

此流程定义日志策略。它没有设置强制策略。

流程

  • SElinuxProfile 中添加 permissive: true

    apiVersion: security-profiles-operator.x-k8s.io/v1alpha2
    kind: SelinuxProfile
    metadata:
      name: nginx-secure
      namespace: nginx-deploy
    spec:
      permissive: true

7.6.2.2. 使用 ProfileBindings 将工作负载绑定到配置集

您可以使用 ProfileBinding 资源将安全配置集绑定到容器的 SecurityContext

流程

  1. 要将使用 quay.io/security-profiles-operator/test-nginx-unprivileged:1.21 镜像的 pod 绑定到示例 SelinuxProfile 配置集,请在与 pod 和 SelinuxProfile 对象相同的命名空间中创建一个 ProfileBinding 对象:

    apiVersion: security-profiles-operator.x-k8s.io/v1alpha1
    kind: ProfileBinding
    metadata:
      namespace: my-namespace
      name: nginx-binding
    spec:
      profileRef:
        kind: SelinuxProfile 1
        name: profile 2
      image: quay.io/security-profiles-operator/test-nginx-unprivileged:1.21
    1
    kind: 变量引用配置集的名称。
    2
    name: 变量引用配置集的名称。
  2. 运行以下命令,使用 enable-binding=true 标记命名空间:

    $ oc label ns my-namespace spo.x-k8s.io/enable-binding=true
  3. 定义名为 test-pod.yaml 的 pod:

    apiVersion: v1
    kind: Pod
    metadata:
      name: test-pod
    spec:
      containers:
      - name: test-container
        image: quay.io/security-profiles-operator/test-nginx-unprivileged:1.21
  4. 创建 pod:

    $ oc create -f test-pod.yaml
    注意

    如果 pod 已存在,您必须重新创建 pod 才能使绑定正常工作。

验证

  • 运行以下命令确认 pod 会继承 ProfileBinding

    $ oc get pod test-pod -o jsonpath='{.spec.containers[*].securityContext.seLinuxOptions.type}'

    输出示例

    profile_nginx-binding.process

7.6.2.3. 复制控制器和 SecurityContextConstraints

当您为复制控制器(如部署或守护进程集)部署 SELinux 策略时,请注意控制器生成的 Pod 对象不会与创建工作负载的用户的身份运行。除非选择了 ServiceAccount,否则 Pod 可能会恢复到使用不允许使用自定义安全策略的受限 SecurityContextConstraints (SCC)。

流程

  1. 运行以下命令来创建项目:

    $ oc new-project nginx-secure
  2. 创建以下 RoleBinding 对象,以允许在 nginx-secure 命名空间中使用 SELinux 策略:

    kind: RoleBinding
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: spo-nginx
      namespace: nginx-secure
    subjects:
    - kind: ServiceAccount
      name: spo-deploy-test
    roleRef:
      kind: Role
      name: spo-nginx
      apiGroup: rbac.authorization.k8s.io
  3. 创建 Role 对象:

    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      creationTimestamp: null
      name: spo-nginx
      namespace: nginx-secure
    rules:
    - apiGroups:
      - security.openshift.io
      resources:
      - securitycontextconstraints
      resourceNames:
      - privileged
      verbs:
      - use
  4. 创建 ServiceAccount 对象:

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      creationTimestamp: null
      name: spo-deploy-test
      namespace: nginx-secure
  5. 创建 Deployment 对象:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: selinux-test
      namespace: nginx-secure
      metadata:
        labels:
          app: selinux-test
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: selinux-test
      template:
        metadata:
          labels:
            app: selinux-test
        spec:
          serviceAccountName: spo-deploy-test
          securityContext:
            seLinuxOptions:
              type: nginx-secure_nginx-secure.process 1
          containers:
          - name: nginx-unpriv
            image: quay.io/security-profiles-operator/test-nginx-unprivileged:1.21
            ports:
            - containerPort: 8080
    1
    在创建 Deployment 前,必须存在 .seLinuxOptions.type
    注意

    SELinux 类型没有在工作负载中指定,并由 SCC 处理。当 Pod 由部署和 ReplicaSet 创建时,pod 将以适当的配置集运行。

确保您的 SCC 仅可供正确的服务帐户使用。如需更多信息,请参阅附加资源

7.6.3. 从工作负载记录配置集

Security Profiles Operator 可以使用 ProfileRecording 对象记录系统调用,从而更轻松地为应用程序创建基准配置集。

当使用日志增强器来记录 SELinux 配置集时,请验证日志增强功能是否已启用。如需更多信息,请参阅附加资源

注意

具有 privileged: true 安全上下文保留的容器可防止基于日志的记录。特权容器不受到 SELinux 策略的影响,基于日志的记录利用特殊的 SELinux 配置集记录事件。

流程

  1. 运行以下命令来创建项目:

    $ oc new-project my-namespace
  2. 运行以下命令,使用 enable-recording=true 标记命名空间:

    $ oc label ns my-namespace spo.x-k8s.io/enable-recording=true
  3. 创建包含 recorder: logs 变量的 ProfileRecording 对象:

    apiVersion: security-profiles-operator.x-k8s.io/v1alpha1
    kind: ProfileRecording
    metadata:
      namespace: my-namespace
      name: test-recording
    spec:
      kind: SelinuxProfile
      recorder: logs
      podSelector:
        matchLabels:
          app: my-app
  4. 创建一个工作负载来记录:

    apiVersion: v1
    kind: Pod
    metadata:
      namespace: my-namespace
      name: my-pod
      labels:
        app: my-app
    spec:
      containers:
        - name: nginx
          image: quay.io/security-profiles-operator/test-nginx-unprivileged:1.21
          ports:
            - containerPort: 8080
        - name: redis
          image: quay.io/security-profiles-operator/redis:6.2.1
  5. 输入以下命令确认 pod 处于 Running 状态:

    $ oc -n my-namespace get pods

    输出示例

    NAME     READY   STATUS    RESTARTS   AGE
    my-pod   2/2     Running   0          18s

  6. 确认增强器表示它接收这些容器的审计日志:

    $ oc -n openshift-security-profiles logs --since=1m --selector name=spod -c log-enricher

    输出示例

    I0517 13:55:36.383187  348295 enricher.go:376] log-enricher "msg"="audit" "container"="redis" "namespace"="my-namespace" "node"="ip-10-0-189-53.us-east-2.compute.internal" "perm"="name_bind" "pod"="my-pod" "profile"="test-recording_redis_6kmrb_1684331729" "scontext"="system_u:system_r:selinuxrecording.process:s0:c4,c27" "tclass"="tcp_socket" "tcontext"="system_u:object_r:redis_port_t:s0" "timestamp"="1684331735.105:273965" "type"="selinux"

验证

  1. 删除 pod:

    $ oc -n my-namepace delete pod my-pod
  2. 确认 Security Profiles Operator 协调两个 SELinux 配置集:

    $ oc get selinuxprofiles -lspo.x-k8s.io/recording-id=test-recording -n my-namespace

    selinuxprofile 的输出示例

    NAME                   USAGE                                       STATE
    test-recording-nginx   test-recording-nginx_my-namespace.process   Installed
    test-recording-redis   test-recording-redis_my-namespace.process   Installed

7.6.3.1. 每个容器配置集实例合并

默认情况下,每个容器实例记录都记录到单独的配置文件中。Security Profiles Operator 可将每个容器配置集合并到一个配置集中。当使用 ReplicaSetDeployment 对象部署应用程序时,合并配置集很有用。

流程

  1. 编辑 ProfileRecording 对象使其包含 mergeStrategy: containers 变量:

    apiVersion: security-profiles-operator.x-k8s.io/v1alpha1
    kind: ProfileRecording
    metadata:
      # The name of the Recording is the same as the resulting SelinuxProfile CRD
      # after reconciliation.
      name: test-recording
      namespace: my-namespace
    spec:
      kind: SelinuxProfile
      recorder: logs
      mergeStrategy: containers
      podSelector:
        matchLabels:
          app: sp-record
  2. 运行以下命令标记命名空间:

    $ oc label ns my-namespace security.openshift.io/scc.podSecurityLabelSync=false pod-security.kubernetes.io/enforce=privileged pod-security.kubernetes.io/audit=privileged pod-security.kubernetes.io/warn=privileged --overwrite=true
  3. 使用以下 YAML 创建工作负载:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deploy
      namespace: my-namespace
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: sp-record
      template:
        metadata:
          labels:
            app: sp-record
        spec:
          serviceAccountName: spo-record-sa
          containers:
          - name: nginx-record
            image: quay.io/security-profiles-operator/test-nginx-unprivileged:1.21
            ports:
            - containerPort: 8080
  4. 要记录单个配置集,请运行以下命令删除部署:

    $ oc delete deployment nginx-deploy -n my-namespace
  5. 要合并配置集,请运行以下命令删除配置集记录:

    $ oc delete profilerecording test-recording -n my-namespace
  6. 要启动合并操作并生成结果配置集,请运行以下命令:

    $ oc get selinuxprofiles -lspo.x-k8s.io/recording-id=test-recording -n my-namespace

    selinuxprofiles 的输出示例

    NAME                          USAGE                                              STATE
    test-recording-nginx-record   test-recording-nginx-record_my-namespace.process   Installed

  7. 要查看任何容器使用的权限,请运行以下命令:

    $ oc get selinuxprofiles test-recording-nginx-record -o yaml

7.6.3.2. 关于 SELinuxContext: RunAsAny

SELinux 策略的记录是通过一个 webhook 来实现的,它将一个特殊的 SELinux 类型注入被记录的 pod。SELinux 类型使 pod 以 permissive 模式运行,将所有 AVC 拒绝记录到 audit.log 中。默认情况下,不允许使用自定义 SELinux 策略运行工作负载,而是使用自动生成的类型。

要记录工作负载,工作负载必须使用具有使用 SCC 权限的服务帐户,允许 Webhook 注入 permissive SELinux 类型。privileged SCC 包含 seLinuxContext: RunAsAny

另外,如果集群启用了 Pod Security Admission,则命名空间必须使用 pod-security.kubernetes.io/enforce: privileged 标记,因为只有 privileged Pod Security Standard 允许使用自定义 SELinux 策略。

其他资源