Creating SELinux profiles

Use the SelinuxProfile object to create SELinux profiles.

The SelinuxProfile object has several features that allow for better security hardening and readability:

  • Restricts the profiles to inherit from to the current namespace or a system-wide profile. Because there are typically many profiles installed on the system, but only a subset should be used by cluster workloads, the inheritable system profiles are listed in the spod instance in spec.selinuxOptions.allowedSystemProfiles.

  • Performs basic validation of the permissions, classes and labels.

  • Adds a new keyword @self that describes the process using the policy. This allows reusing a policy between workloads and namespaces easily, as the usage of the policy is based on the name and namespace.

  • Adds features for better security hardening and readability compared to writing a profile directly in the SELinux CIL language.

Procedure
  1. Create a project by running the following command:

    $ oc new-project nginx-deploy
  2. Create a policy that can be used with a non-privileged workload by creating the following SelinuxProfile object:

    apiVersion: security-profiles-operator.x-k8s.io/v1alpha2
    kind: SelinuxProfile
    metadata:
      name: nginx-secure
    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. Wait for selinuxd to install the policy by running the following command:

    $ oc wait --for=condition=ready selinuxprofile nginx-secure
    Example output
    selinuxprofile.security-profiles-operator.x-k8s.io/nginx-secure condition met

    The policies are placed into an emptyDir in the container owned by the Security Profiles Operator. The policies are saved in Common Intermediate Language (CIL) format in /etc/selinux.d/<name>_<namespace>.cil.

  4. Access the pod by running the following command:

    $ oc -n openshift-security-profiles rsh -c selinuxd ds/spod
Verification
  1. View the file contents with cat by running the following command:

    $ cat /etc/selinux.d/nginx-secure.cil
    Example output
    (block nginx-secure
    (blockinherit container)
    (allow process nginx-secure.process ( tcp_socket ( listen )))
    (allow process http_cache_port_t ( tcp_socket ( name_bind )))
    (allow process node_t ( tcp_socket ( node_bind )))
    )
  2. Verify that a policy has been installed by running the following command:

    $ semodule -l | grep nginx-secure
    Example output
    nginx-secure
Apply SELinux log policies

To log policy violations or AVC denials, set the SElinuxProfile profile to permissive.

Important

This procedure defines logging policies. It does not set enforcement policies.

Procedure
  • Add permissive: true to an SElinuxProfile:

    apiVersion: security-profiles-operator.x-k8s.io/v1alpha2
    kind: SelinuxProfile
    metadata:
      name: nginx-secure
    spec:
      permissive: true
Replicate controllers and SecurityContextConstraints

Deploy SELinux policies for replicating controllers such as deployments or daemon sets so the pods those controllers create can use custom SELinux policies.

Pods that the controllers create do not run with the identity of the user who creates the workload. Unless you select a ServiceAccount, the pods might use a restricted SecurityContextConstraints (SCC) object that does not allow custom security policies.

Procedure
  1. Create a project by running the following command:

    $ oc new-project nginx-secure
  2. Create the following RoleBinding object to allow SELinux policies to be used in the nginx-secure namespace:

    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. Create the Role object:

    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. Create the ServiceAccount object:

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      creationTimestamp: null
      name: spo-deploy-test
      namespace: nginx-secure
  5. Create the Deployment object:

    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.process
          containers:
          - name: nginx-unpriv
            image: quay.io/security-profiles-operator/test-nginx-unprivileged:1.21
            ports:
            - containerPort: 8080

    The spec.template.spec.securityContext.seLinuxOptions.type must exist before the Deployment is created.

    Note

    The SELinux type is not specified in the workload and is handled by the SCC. When the pods are created by the deployment and the ReplicaSet, the pods will run with the appropriate profile.

    Ensure that your SCC is usable by only the correct service account. Refer to Additional resources for more information.

About seLinuxContext: RunAsAny

To record SELinux policies, a webhook injects a permissive SELinux type so the pod logs AVC denials while recording.

The SELinux type makes the pod run in permissive mode, logging all the AVC denials into audit.log. By default, a workload is not allowed to run with a custom SELinux policy, but uses an automatically generated type.

To record a workload, the workload must use a service account that has permissions to use an SCC that allows the webhook to inject the permissive SELinux type. The privileged SCC contains seLinuxContext: RunAsAny.

In addition, the namespace must be labeled with pod-security.kubernetes.io/enforce: privileged if your cluster enables Pod Security Admission, because only the privileged Pod Security Standard allows using a custom SELinux policy.