TT Lab
Get started
Learn Learning paths Courses

LFCS — Linux Foundation System Administrator

Runtime and Permanent Live in Different Places — SELinux, firewalld, sudoers, ACL, sshd

Continue in TT Lab

In one line

Almost every administration tool in the RHEL family keeps "now" and "permanent" separate. setsebool and -P, chcon and semanage fcontext, firewalld's runtime and permanent. And the effective value is told to you by a tool, not by a file — getsebool, firewall-cmd --list-all, sudo -l -U, getfacl, sshd -T. The labs in this module grade both on an AlmaLinux 9 VM.

Why this exists

The Operations domain of the LFCS explicitly says "manage access with SELinux", and the Networking domain requires packet filtering and OpenSSH configuration. A Pod has neither SELinux nor firewalld, so these items only brushed past in the practice exams. The earlier RHCE lab did the same things with Ansible, but what you have in your hands in the exam room is semanage and firewall-cmd.

This VM is Enforcing. So if you leave out the port context, httpd cannot bind 8081 and really does not start, and if you leave out permanent in firewalld, the rule disappears the moment you run --reload. Because the grading agent comes in on 8899/tcp, if you remove that port or change the default zone, grading cannot reach it — exactly the trap measured in the RHCE lab.

How it works

SELinux is one more layer on top of DAC. As RHEL 9 Using SELinux explains, the context (type) attached to processes and files has to match the policy's allow rules for access to succeed. Even root is no exception. A boolean is a switch that turns things on and off without rebuilding the policy, and without -P in setsebool(8), it changes now but goes back after a reboot. semanage boolean -l -C shows only what was changed from the default, and (on , on) is (current, permanent).

A file context lives in two places. The file's xattr (the value now) and the policy's rule list (the value it is supposed to have). chcon changes only the former and semanage-fcontext(8) changes the latter. If you do not change the latter, a single restorecon reverts it. So the order is add the rule → restorecon -R. Ports have types too. If you do not put 8081 into http_port_t with semanage-port(8), httpd_t cannot open that port, and the denial is left in ausearch -m avc.

firewalld is zones and two states. In firewall-cmd, adding --permanent applies to the configuration files only, and leaving it off applies only to the rules running now. --reload rereads permanent into runtime, so what you put only in runtime disappears then. A zone in firewalld.zone(5) is a unit that holds a different allow list per source or interface, and a new zone can be created only as permanent, so it appears in runtime only after a reload. A condition you cannot write with services and ports alone (source + port + action) is written in one line as a rich rule.

sudoers in fragments, check first. %ops ALL=(ALL) NOPASSWD: /usr/bin/systemctl in sudoers(5) means "the ops group, from anywhere, as anyone, systemctl only, without a password". If you put it in /etc/sudoers.d/, a package update does not overwrite it, and even if one fragment is wrong, only that fragment is filtered out. If you leave a syntax error in place, sudo as a whole refuses, so check first with visudo -cf. The result is told to you by sudo -l -U deploy.

Login environment and resource limits are applied at login. /etc/profile.d/*.sh are fragments the login shell reads as it passes through /etc/profile, and without export, they are visible only inside that shell and are not passed to programs the shell starts. The four fields of limits.conf(5) (target, soft/hard, item, value) are applied by pam_limits when a session opens, so looking at ulimit in an already open shell shows no change. A group is written as @ops.

An ACL is permission outside the nine bits. With owner, group, and other you cannot express "this one user as well". -m u:deploy:rwx of setfacl(1) is that, and the default ACL of -d is inherited by what will be created inside the directory. Once an ACL is attached, the group position in ls -l shows not the real group permission but the mask — it is normal for 750 with an ACL to look like 770. The mask trims the effective permissions, so you look at #effective in getfacl.

sshd uses the value it read first. According to sshd_config(5), if the same keyword appears several times, the first value wins. The first line of RHEL 9's sshd_config is Include /etc/ssh/sshd_config.d/*.conf, so drop-ins beat the main body. sshd -t tells you the syntax, and sshd -T tells you the effective values with every Include and Match resolved.

dnf is a transaction. history in the dnf command reference keeps a record per transaction and reverts with undo. There are two ways to exclude something from upgrades. The versionlock plugin pins to the current version, and exclude= in dnf.conf removes it from the candidates entirely. It is the same place as apt-mark hold on Ubuntu.

What it looks like in the field

The RHEL version of "httpd won't start, the configuration is right" is SELinux nine times out of ten. If journalctl -u httpd shows Permission denied, look at ausearch -m avc -ts recent. If it is a port, semanage port is the answer, and if it is a file, semanage fcontext + restorecon is the answer, and setenforce 0 is not the answer.

"I opened the firewall but it was closed after a reboot" means you left out --permanent, and "I opened it but it doesn't work now" means you gave only --permanent and did not --reload. They are two faces of the same tool, so the symptoms come out opposite.

"I gave an ACL but writing doesn't work" — look at the mask. A group permission change such as chmod g-w trims the mask along with it, so the effective value of user:deploy:rwx drops to r-x. getfacl tells you with #effective:r-x.

What you will do in the next lab

Save sestatus + setsebool -P → an fcontext rule for /srv/web + restorecon + 8081 as http_port_t + an httpd response → http and 8081 in the public zone in both runtime and permanent (keeping 8899) → a zone lab + source + rich rule → ops/deploy + sudoers.d/ops (0440, visudo -cf) → profile.d export + limits.d → an ACL and default ACL on /srv/web/upload → an sshd drop-in + sshd -T → install tree, lock it, and dnf history. The grader looks at the effective values with getsebool, semanage … -C, firewall-cmd --permanent, su - deploy, and sshd -T. It passes only when what you wrote in the files and what the tools say are the same.