×

创建和管理 SELinux 配置文件并将它们绑定到工作负载。

安全配置文件操作符仅支持 Red Hat Enterprise Linux CoreOS (RHCOS) 工作节点。不支持 Red Hat Enterprise Linux (RHEL) 节点。

创建 SELinux 配置文件

使用SelinuxProfile对象创建配置文件。

SelinuxProfile对象具有多个功能,可以实现更好的安全加固和可读性。

  • 将配置文件继承限制为当前命名空间或系统范围的配置文件。由于系统中通常安装了许多配置文件,但集群工作负载仅应使用其中一部分,因此可继承的系统配置文件列在spod实例的spec.selinuxOptions.allowedSystemProfiles中。

  • 执行权限、类和标签的基本验证。

  • 添加一个新的关键字@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

    策略被放置到安全配置文件操作符拥有的容器中的emptyDir中。策略以通用中间语言 (CIL) 格式保存在/etc/selinux.d/_.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

将 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:
      securityContext:
        runAsNonRoot: true
        seccompProfile:
          type: RuntimeDefault
      containers:
        - image: nginxinc/nginx-unprivileged:1.21
          name: nginx
          securityContext:
            allowPrivilegeEscalation: false
            capabilities:
              drop: [ALL]
            seLinuxOptions:
              # NOTE: This uses an appropriate SELinux type
              type: nginx-secure_nginx-deploy.process

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

应用 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

使用 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 (3)
    1 kind:变量指的是配置文件的种类。
    2 name:变量指的是配置文件的名称。
    3 可以使用通配符在镜像属性中启用默认安全配置文件:image: "*"

    使用image: "*"通配符属性将在给定命名空间中将所有新的 Pod 与默认安全配置文件绑定。

  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

复制控制器和 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 只能被正确的服务帐户使用。有关更多信息,请参阅“其他资源”。

从工作负载记录配置文件

安全配置文件操作符可以使用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:
      securityContext:
        runAsNonRoot: true
        seccompProfile:
          type: RuntimeDefault
      containers:
        - name: nginx
          image: quay.io/security-profiles-operator/test-nginx-unprivileged:1.21
          ports:
            - containerPort: 8080
          securityContext:
            allowPrivilegeEscalation: false
            capabilities:
              drop: [ALL]
        - name: redis
          image: quay.io/security-profiles-operator/redis:6.2.1
          securityContext:
            allowPrivilegeEscalation: false
            capabilities:
              drop: [ALL]
  5. 通过输入以下命令确认Pod处于运行中状态。

    $ 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. 确认安全配置文件操作符协调了两个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

合并每个容器的配置文件实例

默认情况下,每个容器实例都记录到单独的配置文件中。安全配置文件操作符可以将每个容器的配置文件合并到单个配置文件中。当使用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

关于seLinuxContext: RunAsAny

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

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

此外,如果您的集群启用了Pod安全准入,则命名空间必须用pod-security.kubernetes.io/enforce: privileged标记,因为只有privileged Pod安全标准允许使用自定义SELinux策略。

其他资源