RHCSA Practice ExamLesson 4 of 4
Part C: Network, shared storage and security (100 points)
Seven tasks on addressing, NFS and autofs, firewalld, SSH keys, SELinux, troubleshooting and the final reboot check.
nmclihostnamectlmountautomountfirewall-cmdssh-keygensemanagerestoreconsetsebool
After this lesson you can
- Complete the network, NFS, firewall, SSH, SELinux and troubleshooting tasks in about 55 minutes.
- Prove that every earlier task survived a reboot by running a final persistence check.
How to run Part C
Do C1 first in the whole exam: several other tasks need node2 by name. Do C2 and C4 only after node2 has finished the recovery relabel from B5. Do C3 before C5 so the port is open when you test. Keep C6 and C7 for last; C7 only after everything else is done, because it reboots both machines.
| Task | Topic | Points | Minutes | Skills it draws on |
|---|---|---|---|---|
| C1 | Addresses, hostname, hosts | 14 | 7 | Network Configuration |
| C2 | NFS, autofs, SELinux boolean | 16 | 8 | File Systems, NFS and Autofs; SELinux Basics |
| C3 | firewalld | 14 | 7 | Firewalld |
| C4 | SSH keys, sshd | 12 | 6 | SSH Key Authentication |
| C5 | SELinux web server | 20 | 10 | SELinux Basics; Services, Targets and Boot |
| C6 | Troubleshooting | 14 | 8 | all of the above |
| C7 | Persistence after reboot | 10 | 8 | Exam Technique |
C1 __/14 C2 __/16 C3 __/14 C4 __/12 C5 __/20 C6 __/14 C7 __/10 Part C = ___/100
Total = A ___ + B ___ + C ___ = ___/300 pass at 210
Marking Part C
| Common reason for a lost point | Where it came from |
|---|---|
IPv6 address added, but method left as auto | C1 |
/etc/hosts has the short name only, or the name before the address | C1 |
NFS line in fstab without _netdev, or the mount works only because it was typed by hand | C2 |
autofs map written, but autofs not enabled; or the master map file lacks the .autofs suffix | C2 |
use_nfs_home_dirs set without -P | C2 |
Rule added only at runtime (no --permanent), lost at --reload | C3 |
cockpit removed from runtime but still permanent | C3 |
Key generated for root instead of natasha; PermitRootLogin set in sshd_config but a drop-in with a higher priority wins | C4 |
Port added with semanage port -a but the virtual host does not listen on it | C5 |
chcon used instead of semanage fcontext, so a later restorecon undoes it | C5 |
setenforce 1 done, /etc/selinux/config still permissive | C5 |
Script made executable but the label is still admin_home_t | C6 |
fstab fixed, daemon-reload not run, so the old generated unit still fails | C6 |
Total available in Part C: 100 points. Add Parts A, B and C on the marking sheet. 210 or more passes this practice exam.
Practice
0 of 7 done
Do these on your own system. They get harder. Check each result, then tick it off.
- Warm-up
C1 · Addresses, hostname and name resolution (14 points, 7 min)
On node1, using the existing wired connection (find its name with
nmcli connection show):- Static IPv4
192.168.122.50/24, gateway192.168.122.1, DNS server192.168.122.1. - Static IPv6
fd00:122::50/64. - The connection must start automatically and use these settings after a reboot.
- The static hostname must be
node1.lab.example. /etc/hostsmust resolvenode2andnode2.lab.exampleto192.168.122.51.
Check your result
ip -br addressshows both192.168.122.50/24andfd00:122::50/64on the interface.nmcli -g ipv4.method,ipv6.method,connection.autoconnect connection show "NAME"printsmanual,manualandyeson separate lines.hostnamectl --staticprintsnode1.lab.example.getent hosts node2prints192.168.122.51followed by the names;ping -c1 node2.lab.exampleanswers.
Hint
nmcli connection modify NAME ipv4.method manual ipv4.addresses ... ipv4.gateway ... ipv4.dns ... ipv6.method manual ipv6.addresses ..., thennmcli connection up NAME. Do not runupover an SSH session you depend on without a second way in.Solution
nmcli connection show CON=$(nmcli -g NAME connection show --active | head -1) sudo nmcli connection modify "$CON" \ ipv4.method manual ipv4.addresses 192.168.122.50/24 \ ipv4.gateway 192.168.122.1 ipv4.dns 192.168.122.1 \ ipv6.method manual ipv6.addresses fd00:122::50/64 \ connection.autoconnect yes sudo nmcli connection up "$CON" sudo hostnamectl set-hostname node1.lab.example echo '192.168.122.51 node2.lab.example node2' | sudo tee -a /etc/hosts ip -br address getent hosts node2 - Static IPv4
- Practice
C2 · NFS mount and autofs home directories (16 points, 8 min)
node2 exports
/srv/shareand/home/remoteusers(see the preparation). On node1:- Mount
node2.lab.example:/srv/shareon/mnt/sharepermanently, at boot, with the NFS option set that waits for the network. - Configure the automounter so that the home directory of any user
NAMEis mounted fromnode2.lab.example:/home/remoteusers/NAMEon/rhome/NAMEwhen first used, read-write. - The user
remoteuser1(UID 4001, home/rhome/remoteuser1) already exists on node1. Set its password toEx200!Laband make it possible for it to log in with that home directory when SELinux is enforcing. autofsmust be running and enabled.
Check your result
findmnt /mnt/shareshows typenfs4;cat /mnt/share/readme.txtprintshello from node2;grep /mnt/share /etc/fstabcontains_netdev.sudo systemctl is-enabled autofsprintsenabled;systemctl is-active autofsprintsactive.su - remoteuser1 -c 'pwd; cat notes.txt'prints/rhome/remoteuser1andremote home;findmnt /rhome/remoteuser1then shows annfs4mount.getsebool use_nfs_home_dirsprintsuse_nfs_home_dirs --> on.
Hint
Master map: a file in
/etc/auto.master.d/ending in.autofswith/rhome /etc/auto.rhome. In the map file use the key*and&for the user name.setsebool -P use_nfs_home_dirs on.Solution
sudo dnf install -y nfs-utils autofs sudo mkdir -p /mnt/share echo 'node2.lab.example:/srv/share /mnt/share nfs defaults,_netdev 0 0' | sudo tee -a /etc/fstab sudo systemctl daemon-reload && sudo mount -a echo '/rhome /etc/auto.rhome' | sudo tee /etc/auto.master.d/rhome.autofs echo '* -rw,sync node2.lab.example:/home/remoteusers/&' | sudo tee /etc/auto.rhome sudo systemctl enable --now autofs echo 'remoteuser1:Ex200!Lab' | sudo chpasswd sudo setsebool -P use_nfs_home_dirs on su - remoteuser1 -c 'pwd; cat notes.txt' findmnt /rhome/remoteuser1 - Mount
- Practice
C3 · Firewall rules (14 points, 7 min)
On node1, in the
publiczone (the default), with every rule permanent and active now:- Allow the
httpservice and the port8081/tcp. - Make sure the
cockpitservice is not allowed. - Add a rich rule that rejects the
sshservice for connections coming from192.0.2.0/24. - Forward incoming TCP port
8080to local port8081.
Check your result
sudo firewall-cmd --list-allandsudo firewall-cmd --permanent --list-allboth showhttp,8081/tcp, the forward portport=8080:proto=tcp:toport=8081:toaddr=, and the rich rule;cockpitis not listed.sudo firewall-cmd --get-default-zoneprintspublic.- After
sudo firewall-cmd --reloadthe lists are unchanged.
Hint
Use
--permanentfor every rule, thenfirewall-cmd --reload. Rich rule:rule family="ipv4" source address="192.0.2.0/24" service name="ssh" reject.Solution
sudo firewall-cmd --permanent --add-service=http sudo firewall-cmd --permanent --add-port=8081/tcp sudo firewall-cmd --permanent --remove-service=cockpit sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.0.2.0/24" service name="ssh" reject' sudo firewall-cmd --permanent --add-forward-port=port=8080:proto=tcp:toport=8081 sudo firewall-cmd --reload sudo firewall-cmd --list-all - Allow the
- Practice
C4 · SSH keys and a hardened sshd (12 points, 6 min)
node2 has the user
natasha(passwordEx200!Lab). On node1:- As
natasha, create an ed25519 key pair without a passphrase (default location) and install the public key fornatashaon node2, so thatssh natasha@node2.lab.example hostnameworks without a password prompt. - Configure sshd on node1 so that
rootcannot log in over SSH, and the number of authentication attempts per connection is limited to3. Use a drop-in file; the setting must be effective, not only written.
Check your result
sudo -u natasha ssh -o BatchMode=yes natasha@node2.lab.example hostnameprintsnode2.lab.example.ls -l /home/natasha/.ssh/id_ed25519is mode600and owned bynatasha.sudo sshd -T | grep -E 'permitrootlogin|maxauthtries'printspermitrootlogin noandmaxauthtries 3.ssh root@node1.lab.examplefrom node2 is refused.
Hint
ssh-keygen -t ed25519 -N "" -f ~/.ssh/id_ed25519as natasha, thenssh-copy-id. In RHEL 10 the first value found wins, so name the drop-in01-local.conf. Restart or reloadsshdaftersshd -t.Solution
sudo -u natasha ssh-keygen -t ed25519 -N "" -f /home/natasha/.ssh/id_ed25519 sudo -u natasha ssh-copy-id -i /home/natasha/.ssh/id_ed25519.pub natasha@node2.lab.example sudo -u natasha ssh natasha@node2.lab.example hostname printf 'PermitRootLogin no\nMaxAuthTries 3\n' | sudo tee /etc/ssh/sshd_config.d/01-local.conf sudo sshd -t && sudo systemctl reload sshd sudo sshd -T | grep -E 'permitrootlogin|maxauthtries' - As
- Challenge
C5 · A web server under SELinux (20 points, 10 min)
On node1:
- SELinux must be enforcing now and after a reboot.
- Publish the directory
/srv/webbyhttpdon port 8081 through a virtual host. Create/srv/web/index.htmlcontainingLinux Lab web. The content must be readable by httpd with SELinux enforcing, by giving the directory a persistent file-context rule, not by switching SELinux off. - httpd must be allowed by SELinux to listen on port
8081, persistently. - Persistently allow users' home directories to be served by httpd (
httpd_enable_homedirs). httpdmust be running and enabled.curl http://localhost:8081must print the page. The firewall allows 8081 from C3.
Check your result
getenforceprintsEnforcing;grep ^SELINUX= /etc/selinux/configprintsSELINUX=enforcing.curl -s http://localhost:8081printsLinux Lab web.ls -Zd /srv/web /srv/web/index.htmlshowshttpd_sys_content_t;sudo semanage fcontext -l | grep '/srv/web'shows the rule.sudo semanage port -l | grep -w 8081showshttp_port_t.getsebool httpd_enable_homedirsprintshttpd_enable_homedirs --> on.sudo ausearch -m avc -ts recentshows no new denials for httpd.
Hint
A file created under
/srvis labelledvar_t.semanage fcontext -a -t httpd_sys_content_t "/srv/web(/.*)?"thenrestorecon -Rv /srv/web.semanage port -a -t http_port_t -p tcp 8081. The virtual host needsListen 8081and a<Directory>block withRequire all granted.Solution
sudo dnf install -y policycoreutils-python-utils httpd sudo setenforce 1 sudo sed -i 's/^SELINUX=.*/SELINUX=enforcing/' /etc/selinux/config sudo mkdir -p /srv/web echo 'Linux Lab web' | sudo tee /srv/web/index.html sudo semanage fcontext -a -t httpd_sys_content_t "/srv/web(/.*)?" sudo restorecon -Rv /srv/web sudo semanage port -a -t http_port_t -p tcp 8081 sudo setsebool -P httpd_enable_homedirs on sudo tee /etc/httpd/conf.d/lab.conf <<'EOT' Listen 8081 <VirtualHost *:8081> DocumentRoot "/srv/web" <Directory "/srv/web"> Require all granted </Directory> </VirtualHost> EOT sudo apachectl configtest sudo systemctl enable --now httpd sudo systemctl restart httpd curl -s http://localhost:8081 ls -Zd /srv/web /srv/web/index.html - Challenge
C6 · Fix what is broken (14 points, 8 min)
Setup (run once as root on node1, then read the symptoms):
mkdir -p /srv/extra /srv/images truncate -s 64M /srv/images/extra.img && mkfs.ext4 -qF /srv/images/extra.img echo '/srv/images/extra.img /srv/extra ext4 loop,defalts 0 0' >> /etc/fstab cat > /root/report.sh <<'EOT' #!/bin/bash while true; do date >> /var/log/report.log; sleep 30; done EOT mv /root/report.sh /usr/local/bin/report.sh chmod 644 /usr/local/bin/report.sh printf '[Unit]\nDescription=Report writer\n\n[Service]\nExecStart=/usr/local/bin/report.sh\n\n[Install]\nWantedBy=multi-user.target\n' > /etc/systemd/system/report.service systemctl daemon-reload useradd -m intern echo 'intern ALL=(ALL) /usr/bin/systemctl restart httpd' > /etc/sudoers.d/intern chmod 666 /etc/sudoers.d/internSymptoms reported by the team:
systemctl start reportfails. The service must run, start at every boot, and/var/log/report.logmust grow. Do not rewrite the script's content.internwas given the right to restarthttpdthrough sudo, butsudo -l -U internshows nothing.mount -aprints an error about/srv/extra. The image must mount on/srv/extranow and at boot, and the file must stay in/etc/fstab.
Check your result
systemctl is-active reportprintsactive;systemctl is-enabled reportprintsenabled;wc -l /var/log/report.logincreases over 30 seconds.sudo -l -U internlists(ALL) /usr/bin/systemctl restart httpd;ls -l /etc/sudoers.d/internis mode-r--r-----.sudo mount -aprints nothing;findmnt /srv/extrashowsext4;sudo findmnt --verifyreports no errors for/srv/extra.
Hint
Read the logs before guessing:
systemctl status report,journalctl -u report -b,ausearch -m avc -ts recent. Two faults hide behind one symptom: a missing mode, and a wrong SELinux label (ls -Z,restorecon). For sudo:visudo -cnames the problem. For fstab: compare the option names withman 5 fstab.Solution
# 1. Service: not executable, and wrong SELinux type after mv from /root ls -lZ /usr/local/bin/report.sh sudo chmod 755 /usr/local/bin/report.sh sudo restorecon -v /usr/local/bin/report.sh sudo systemctl enable --now report # 2. sudoers: file mode must be 0440 sudo visudo -c sudo chmod 0440 /etc/sudoers.d/intern sudo -l -U intern # 3. fstab: 'defalts' is not an option sudo sed -i 's/loop,defalts/loop,defaults/' /etc/fstab sudo systemctl daemon-reload sudo mount -a && findmnt /srv/extra - Challenge
C7 · Reboot and prove it (10 points, 8 min)
Reboot both machines. After node1 is up, without changing anything, run a check that proves the results of the earlier tasks survived. Then write the check as a script
/root/final-check.shthat prints onePASSorFAILline per item and exits non-zero if any item failed. It must cover at least: default target,httpd,atd,tuned,chronyd,autofs,firewalldenabled; SELinux enforcing; the hostname; the mounts/srv/app,/srv/data,/mnt/exchange,/mnt/share; active swap on/dev/vdc1;audit=1in the kernel arguments; and the page on port 8081.Check your result
sudo /root/final-check.shprints onlyPASSlines andecho $?prints0.- Temporarily stop
httpd(sudo systemctl stop httpd), run the script again: it printsFAILfor httpd and exits non-zero. Start httpd again. uptime -sis later than the time you started Part C.
Hint
A small function
chk()that takes a label and a command, runs the command quietly and prints PASS or FAIL, keeps the script short. Rememberset -udoes not stop failed commands; count failures yourself.Solution
sudo tee /root/final-check.sh <<'EOT' #!/bin/bash fail=0 chk() { # chk "label" command... local label=$1; shift if "$@" >/dev/null 2>&1; then echo "PASS $label"; else echo "FAIL $label"; fail=1; fi } chk "default target" test "$(systemctl get-default)" = multi-user.target for s in httpd atd tuned chronyd autofs firewalld; do chk "$s enabled+active" bash -c "systemctl is-enabled $s && systemctl is-active $s" done chk "SELinux enforcing" test "$(getenforce)" = Enforcing chk "hostname" test "$(hostnamectl --static)" = node1.lab.example for m in /srv/app /srv/data /mnt/exchange /mnt/share; do chk "mount $m" findmnt "$m"; done chk "swap on vdc1" bash -c "swapon --show=NAME --noheadings | grep -q /dev/vdc1" chk "audit=1 argument" bash -c "grep -qw audit=1 /proc/cmdline" chk "web page :8081" bash -c "curl -s http://localhost:8081 | grep -q 'Linux Lab web'" exit $fail EOT sudo chmod 755 /root/final-check.sh sudo reboot # after the reboot: sudo /root/final-check.sh; echo "exit=$?"