BlogLinux & scripting

SELinux on OpenShift: stop chmod 777-ing your way out

Read AVC denials, write a targeted policy module, and keep SCCs strict instead of granting privileged.

Aug 19, 2025·4 min readAdvanced·By the SecOpsLog team · command-tested

Something breaks, a log says 'Permission denied' on a file whose mode is clearly 0644, and within thirty seconds someone types setenforce 0. The problem 'goes away' — because you just turned off the seatbelt. SELinux denials are readable and the real fix is usually three commands, so it is worth learning to read them instead of reaching for the switch. On OpenShift, containers get SELinux contexts too — and Security Context Constraints assign MCS categories so two pods cannot read each other's volumes even as root.

This note reads an AVC denial, fixes the file context persistently, and explains how SCCs interact with volume mounts on OpenShift. For the broader host hardening baseline, see Linux hardening.

From AVC denial to a real fix

setenforce 0 disables protection host-wide. Permissive mode for one domain is the debug escape hatch.

1Reproduce errorPermission denied despite mode2ausearch -m AVCfind the denial record3audit2whyhuman-readable cause4semanage fcontextpersistent label rule5restoreconapply label now6Retest appdenial gone, enforcing on7Optional moduleaudit2allow -M for novel rules
bash — read the deniallive
ausearch -m AVC -ts recent
time->Tue Jun 10 10:42:01 2025
type=AVC avc: denied { read } for pid=2114 comm="nginx"
name="index.html" scontext=...:httpd_t tcontext=...:user_home_t
 
ausearch -m AVC -ts recent | audit2why
Was caused by: the file has the wrong SELinux type.
the fix is a file context, not setenforce 0

Read it left to right: the subject nginx (httpd_t) was denied read on a file labelled user_home_t. SELinux is not confused — a web server has no business reading a file typed as someone's home directory. The label is wrong, so fix the label.

Fix the label, not the enforcement

Set the correct context so it persists across a relabel — chcon alone is temporary and gets wiped by the next restorecon. Use semanage fcontext to record the rule, then restorecon to apply it. When the app genuinely needs a capability the default policy blocks, a boolean is the sanctioned switch — not a custom module you cannot explain six months later.

fix.sh
# persistent: teach the policy the correct type for this path
semanage fcontext -a -t httpd_sys_content_t "/srv/www(/.*)?"
restorecon -Rv /srv/www
# some needs are just a boolean away — no custom policy required
setsebool -P httpd_can_network_connect on
setenforce 0 is not a fix
It disables protection host-wide until the next reboot, and hides every future denial while it is off. If you must debug, use permissive mode for a single domain (semanage permissive -a httpd_t) so the rest of the system stays enforcing. Document any permissive domain and remove it when debugging finishes.

On OpenShift and Kubernetes

Containers get SELinux too. On OpenShift, Security Context Constraints (SCCs) assign each pod an MCS category pair, so two containers on the same node literally cannot read each other's volume files even as root. When a mounted volume throws permission errors, the culprit is almost always the label — set seLinuxOptions on the pod or let the platform relabel the mount with :Z or :z on the volumeMount rather than loosening the SCC to privileged.

Use :Z when only one pod uses the volume; use :z when multiple pods in the same namespace share it. Getting that wrong produces denials that look like random permission failures — check oc adm policy scc-review before you request a broader SCC.

deployment.yaml
spec:
template:
spec:
securityContext:
seLinuxOptions:
level: "s0:c123,c456" # assigned by SCC — do not invent randomly
containers:
- name: app
volumeMounts:
- name: data
mountPath: /var/lib/app
# :Z relabels for private use; :z for shared volumes

Where this goes next

Once reading denials is routine, generate a proper module for the legitimate ones: ausearch ... | audit2allow -M myapp builds a loadable policy you can review and ship, instead of a pile of booleans nobody remembers enabling. Pair host SELinux with Pod Security Admission and restricted SCCs so defense is layered, not optional. The Linux hardening course covers SSH, nftables, SELinux, auditd and CIS — harden a default install end to end.

Go deeper in a courseLinux hardeningSSH, nftables, SELinux, auditd and CIS — harden a default install.View course

Related posts