Managing SELinux profiles
Create and manage SELinux profiles and bind them to workloads.
The Security Profiles Operator supports only Red Hat Enterprise Linux CoreOS (RHCOS) worker nodes. Red Hat Enterprise Linux (RHEL) nodes are not supported. |
Creating SELinux profiles
Use the SelinuxProfile
object to create 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 inspec.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
Create a project by running the following command:
$ oc new-project nginx-deploy
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
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
Wait for
selinuxd
to install the policy by running the following command:$ oc wait --for=condition=ready -n nginx-deploy 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
.Access the pod by running the following command:
$ oc -n openshift-security-profiles rsh -c selinuxd ds/spod
Verification
View the file contents with
cat
by running the following command:$ cat /etc/selinux.d/nginx-secure_nginx-deploy.cil
Example output
(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 )))
)
Verify that a policy has been installed by running the following command:
$ semodule -l | grep nginx-secure
Example output
nginx-secure_nginx-deploy
Applying SELinux profiles to a pod
Create a pod to apply one of the created profiles.
For SELinux profiles, the namespace must be labelled to allow privileged workloads.
Procedure
Apply the
scc.podSecurityLabelSync=false
label to thenginx-deploy
namespace by running the following command:$ oc label ns nginx-deploy security.openshift.io/scc.podSecurityLabelSync=false
Apply the
privileged
label to thenginx-deploy
namespace by running the following command:$ oc label ns nginx-deploy --overwrite=true pod-security.kubernetes.io/enforce=privileged
Obtain the SELinux profile usage string by running the following command:
$ oc get selinuxprofile.security-profiles-operator.x-k8s.io/nginx-secure -n nginx-deploy -ojsonpath='{.status.usage}'
Example output
nginx-secure_nginx-deploy.process
Apply the output string in the workload manifest in the
.spec.containers[].securityContext.seLinuxOptions
attribute: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
The SELinux
type
must exist before creating the workload.
Applying SELinux log policies
To log policy violations or AVC denials, set the SElinuxProfile
profile to permissive
.
This procedure defines logging policies. It does not set enforcement policies. |
Procedure
Add
permissive: true
to anSElinuxProfile
:apiVersion: security-profiles-operator.x-k8s.io/v1alpha2
kind: SelinuxProfile
metadata:
name: nginx-secure
namespace: nginx-deploy
spec:
permissive: true
Binding workloads to profiles with ProfileBindings
You can use the ProfileBinding
resource to bind a security profile to the SecurityContext
of a container.
Procedure
To bind a pod that uses a
quay.io/security-profiles-operator/test-nginx-unprivileged:1.21
image to the exampleSelinuxProfile
profile, create aProfileBinding
object in the same namespace with the pod and theSelinuxProfile
objects: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 The kind:
variable refers to the name of the profile.2 The name:
variable refers to the name of the profile.Label the namespace with
enable-binding=true
by running the following command:$ oc label ns my-namespace spo.x-k8s.io/enable-binding=true
Define a pod named
test-pod.yaml
:apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- name: test-container
image: quay.io/security-profiles-operator/test-nginx-unprivileged:1.21
Create the pod:
$ oc create -f test-pod.yaml
If the pod already exists, you must re-create the pod for the binding to work properly.
Verification
Confirm the pod inherits the
ProfileBinding
by running the following command:$ oc get pod test-pod -o jsonpath='{.spec.containers[*].securityContext.seLinuxOptions.type}'
Example output
profile_nginx-binding.process
Replicating controllers and SecurityContextConstraints
When you deploy SELinux policies for replicating controllers, such as deployments or daemon sets, note that the Pod
objects spawned by the controllers are not running with the identity of the user who creates the workload. Unless a ServiceAccount
is selected, the pods might revert to using a restricted SecurityContextConstraints
(SCC) which does not allow use of custom security policies.
Procedure
Create a project by running the following command:
$ oc new-project nginx-secure
Create the following
RoleBinding
object to allow SELinux policies to be used in thenginx-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
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
Create the
ServiceAccount
object:apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: null
name: spo-deploy-test
namespace: nginx-secure
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_nginx-secure.process (1)
containers:
- name: nginx-unpriv
image: quay.io/security-profiles-operator/test-nginx-unprivileged:1.21
ports:
- containerPort: 8080
1 The .seLinuxOptions.type
must exist before the Deployment is created.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.
Recording profiles from workloads
The Security Profiles Operator can record system calls with ProfileRecording
objects, making it easier to create baseline profiles for applications.
When using the log enricher for recording SELinux profiles, verify the log enricher feature is enabled. See Additional resources for more information.
A container with |
Procedure
Create a project by running the following command:
$ oc new-project my-namespace
Label the namespace with
enable-recording=true
by running the following command:$ oc label ns my-namespace spo.x-k8s.io/enable-recording=true
Create a
ProfileRecording
object containing arecorder: logs
variable: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
Create a workload to record:
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
Confirm the pod is in a
Running
state by entering the following command:$ oc -n my-namespace get pods
Example output
NAME READY STATUS RESTARTS AGE
my-pod 2/2 Running 0 18s
Confirm the enricher indicates that it receives audit logs for those containers:
$ oc -n openshift-security-profiles logs --since=1m --selector name=spod -c log-enricher
Example output
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"
Verification
Remove the pod:
$ oc -n my-namepace delete pod my-pod
Confirm the Security Profiles Operator reconciles the two SELinux profiles:
$ oc get selinuxprofiles -lspo.x-k8s.io/recording-id=test-recording -n my-namespace
Example output for selinuxprofile
NAME USAGE STATE
test-recording-nginx test-recording-nginx_my-namespace.process Installed
test-recording-redis test-recording-redis_my-namespace.process Installed
Merging per-container profile instances
By default, each container instance records into a separate profile. The Security Profiles Operator can merge the per-container profiles into a single profile. Merging profiles is useful when deploying applications using ReplicaSet
or Deployment
objects.
Procedure
Edit a
ProfileRecording
object to include amergeStrategy: containers
variable: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
Label the namespace by running the following command:
$ 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
Create the workload with the following 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
To record the individual profiles, delete the deployment by running the following command:
$ oc delete deployment nginx-deploy -n my-namespace
To merge the profiles, delete the profile recording by running the following command:
$ oc delete profilerecording test-recording -n my-namespace
To start the merge operation and generate the results profile, run the following command:
$ oc get selinuxprofiles -lspo.x-k8s.io/recording-id=test-recording -n my-namespace
Example output for selinuxprofiles
NAME USAGE STATE
test-recording-nginx-record test-recording-nginx-record_my-namespace.process Installed
To view the permissions used by any of the containers, run the following command:
$ oc get selinuxprofiles test-recording-nginx-record -o yaml
About seLinuxContext: RunAsAny
Recording of SELinux policies is implemented with a webhook that injects a special SELinux type to the pods being recorded. 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 auto-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 the Pod Security Admission because only the privileged
Pod Security Standard allows using a custom SELinux policy.