KNZLABS :: RHCSA Foundations

Module 8: Manage Security

RHCSA domain covered: Manage Security (9).

Labs in this kit: Lab 02 (permissions + ACLs), Lab 04 (SELinux).

Security on RHEL is layered, and the exam tests your ability to work each layer *and* to diagnose which layer is blocking you when something fails. The mental model below is the order to think in: a packet has to get through the firewall, then the file's POSIX permissions (and any ACL exceptions) decide who can open it, and finally SELinux decides what the *process* is allowed to do with it. When something is mysteriously "permission denied" and the ownership looks right, the answer is almost always SELinux.

The security layers


┌─────────────────────────────────────────────┐
│ firewalld     (what packets reach the host) │
├─────────────────────────────────────────────┤
│ POSIX perms   (who can open the file)       │
├─────────────────────────────────────────────┤
│ ACLs          (exceptions to POSIX)         │
├─────────────────────────────────────────────┤
│ SELinux       (what the process is allowed) │
└─────────────────────────────────────────────┘

Walk the layers top-to-bottom when troubleshooting. The classic exam scenario: a web server returns 403 even though ls -l shows the files are readable. POSIX permissions are fine — but SELinux thinks the files have the wrong *type label* for httpd to serve. Always check SELinux.

ACLs — exceptions to standard permissions

What it is: Access Control Lists let you grant permissions to *additional* specific users or groups beyond the single owner/group/other that standard POSIX permissions allow.

Why it matters: when a task says "alice needs write access too, but don't change the existing ownership," POSIX can't express that — ACLs can. The exam uses this exact framing.


getfacl /srv/projects                          # view ACLs
ls -l /srv/projects                            # a trailing '+' means ACLs exist

setfacl -m u:alice:rwx     /srv/projects        # grant a USER an ACL
setfacl -m g:engineering:rx /srv/projects        # grant a GROUP an ACL
setfacl -d -m g:engineering:rwx /srv/projects   # DEFAULT ACL (inherited by new files)

setfacl -x u:alice /srv/projects               # remove one entry
setfacl -b /srv/projects                       # remove ALL ACLs

setfacl -m modifies (adds/changes) an entry: u:alice:rwx for a user, g:engineering:rx for a group. The -d flag sets a *default* ACL — it doesn't affect the directory itself, it dictates what new files created inside inherit. The detail to remember is the mask: it's a ceiling on the effective permissions of named users and groups. If you grant u:alice:rwx but the mask is r-x, alice effectively gets r-x — the mask wins. A + at the end of an ls -l permission string is the visible flag that ACLs are present; don't overlook it when diagnosing access.

SELinux modes

What it is: SELinux is mandatory access control — it confines processes to only the actions its policy permits, independent of file ownership. It runs in Enforcing (block + log), Permissive (allow + log), or Disabled.

Why it matters: SELinux is the layer people disable in frustration and the exam expects you to *leave it enforcing* and fix the actual policy problem.


getenforce                                # current mode
sestatus                                  # full state
setenforce 0                              # to Permissive (RUNTIME only)
setenforce 1                              # to Enforcing (RUNTIME only)

# Persistent mode change:
sed -i 's/^SELINUX=.*/SELINUX=enforcing/' /etc/selinux/config

The key distinction: setenforce changes the mode *right now* but doesn't survive reboot; the persistent setting lives in /etc/selinux/config. Permissive mode is a diagnostic tool — it stops blocking but keeps *logging* denials, so you can see everything SELinux *would* have blocked without breaking the system. Use it to gather information, then switch back to Enforcing and fix the root cause. Never set SELINUX=disabled on the exam unless explicitly told — leaving it disabled fails hardening-oriented tasks.

File contexts — the labels SELinux enforces

What it is: every file has an SELinux *context* (notably a type label like httpd_sys_content_t). Policy rules say which process types may access which file types. Relocating files often breaks the labels.

Why it matters: the "web server can't read its files" scenario is a context problem, and fixing it *persistently* (not just with chcon) is the scored skill.


ls -Z /var/www/html/                      # view contexts
chcon -t httpd_sys_content_t /data/file   # change a context (RUNTIME — wiped by relabel)
restorecon -Rv /data                      # reset to the policy's defaults

# PERSISTENT: register the path with the policy, then apply
semanage fcontext -a -t httpd_sys_content_t '/data/web(/.*)?'
restorecon -Rv /data/web

semanage fcontext -l | grep /data/web     # verify the rule is recorded

This is the most important "persistence" trap in SELinux. chcon changes a label *now*, but it's not recorded in the policy — the next restorecon or filesystem relabel reverts it, so a chcon-only fix fails the post-reboot check. The durable fix is two steps: semanage fcontext -a *records* the desired label for a path in the policy database, then restorecon *applies* that recorded rule to the files on disk. The regex (/.*)? at the end of the path matches both the directory itself and everything beneath it. Think of it as semanage = "remember this rule," restorecon = "make the files match the rules."

Booleans — policy on/off switches

What it is: SELinux booleans are named toggles that turn predefined policy behaviors on or off (e.g., "may httpd make network connections to a database").

Why it matters: many "the app is denied even though contexts are right" problems are solved by flipping one boolean — and forgetting to make it persistent is the #1 SELinux mistake.


getsebool -a | less                            # list all booleans
getsebool httpd_can_network_connect_db          # check one
setsebool -P httpd_can_network_connect_db on    # set PERSISTENTLY (the -P)

The entire lesson here is the -P flag. setsebool httpd_can_network_connect_db on works until reboot; setsebool -P ... writes it into the policy so it survives. On an exam graded after reboot, a boolean set without -P reverts and you fail the task even though it "worked" when you tested it. Always -P.

SELinux ports

What it is: SELinux also labels network ports. To let a service listen on a non-standard port, you must label that port for the service's type.

Why it matters: "make httpd listen on 8443" fails silently under SELinux unless you label the port — a subtle, testable detail.


semanage port -a -t http_port_t -p tcp 8443    # allow httpd's type on 8443
semanage port -l | grep http_port_t            # verify

Even with the firewall open and httpd configured, SELinux blocks the bind to an unlabeled port. semanage port -a adds the port to the service's type so the bind is permitted. This is the kind of step that's invisible until you check journalctl/ausearch and see the denial.

Troubleshooting SELinux denials

What it is: tools that read the audit log to show *why* SELinux blocked something and suggest a fix.

Why it matters: the fastest path from "it's denied" to "here's the boolean/context to fix" runs through these commands.


ausearch -m AVC -ts recent                      # recent denials
ausearch -m AVC -ts today | audit2why           # WHY each denial happened
audit2allow -a                                  # suggest a policy rule (use with care)

When something is blocked, SELinux logs an AVC (Access Vector Cache) denial. ausearch -m AVC -ts recent pulls the recent ones; piping to audit2why translates the cryptic log line into a plain explanation and often names the exact boolean or context that would fix it. audit2allow can generate a custom policy module to permit the action — but treat that as a last resort. On the exam, the right fix is almost always a boolean flip or an fcontext correction, not a custom module.

SSH key-based authentication

What it is: SSH keys let users authenticate with a cryptographic key pair instead of a password — more secure and scriptable.

Why it matters: "configure key-based login" and "disable password authentication" are standard hardening tasks.


ssh-keygen -t ed25519 -C 'alice@laptop'         # generate a key pair
ssh-copy-id alice@server                         # install the public key on the server

Disable password auth in /etc/ssh/sshd_config:


PasswordAuthentication no
PermitRootLogin prohibit-password

Then reload: systemctl reload sshd. ssh-copy-id is the safe way to install your public key into the server's ~/.ssh/authorized_keys with correct permissions — doing it by hand risks wrong modes (the .ssh directory must be 700 and authorized_keys 600, or sshd ignores them). PermitRootLogin prohibit-password allows root in by key but not by password — a common middle-ground hardening setting.

Common pitfalls

  • setsebool without -P evaporates on reboot — the single most common SELinux mistake. Always -P.
  • chcon is overwritten by the next restorecon or relabel. For a durable context change, use semanage fcontext -a then restorecon.
  • A + after ls -l permissions means ACLs are set — don't ignore it when something has unexpected access.
  • Permissive mode still LOGS denials — use it to gather information during troubleshooting, then return to Enforcing.
  • Forgetting to label a non-standard port with semanage port -a → the service can't bind even with the firewall open.
  • Setting SELINUX=disabled to "make it work" → fails hardening tasks and requires a full relabel to re-enable. Fix the policy instead.

Exam tips

  • The mental checklist for "permission denied" that shouldn't be: check POSIX (ls -l), check ACLs (the +), then check SELinux (ls -Z, ausearch -m AVC -ts recent). The third one is the usual culprit.
  • audit2why turns a denial into an explanation and often hands you the fix — run it before reaching for audit2allow.
  • Every SELinux persistence command has a tell: -P for booleans, semanage (not chcon) for contexts and ports. If you used setenforce, setsebool without -P, or chcon, assume it won't survive reboot.
Next: Module 9 — Containers.