4 of 4

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.

  • nmcli
  • hostnamectl
  • mount
  • automount
  • firewall-cmd
  • ssh-keygen
  • semanage
  • restorecon
  • setsebool

55 min7 exercises

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.

TaskTopicPointsMinutesSkills it draws on
C1Addresses, hostname, hosts147Network Configuration
C2NFS, autofs, SELinux boolean168File Systems, NFS and Autofs; SELinux Basics
C3firewalld147Firewalld
C4SSH keys, sshd126SSH Key Authentication
C5SELinux web server2010SELinux Basics; Services, Targets and Boot
C6Troubleshooting148all of the above
C7Persistence after reboot108Exam 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 pointWhere it came from
IPv6 address added, but method left as autoC1
/etc/hosts has the short name only, or the name before the addressC1
NFS line in fstab without _netdev, or the mount works only because it was typed by handC2
autofs map written, but autofs not enabled; or the master map file lacks the .autofs suffixC2
use_nfs_home_dirs set without -PC2
Rule added only at runtime (no --permanent), lost at --reloadC3
cockpit removed from runtime but still permanentC3
Key generated for root instead of natasha; PermitRootLogin set in sshd_config but a drop-in with a higher priority winsC4
Port added with semanage port -a but the virtual host does not listen on itC5
chcon used instead of semanage fcontext, so a later restorecon undoes itC5
setenforce 1 done, /etc/selinux/config still permissiveC5
Script made executable but the label is still admin_home_tC6
fstab fixed, daemon-reload not run, so the old generated unit still failsC6

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.

  1. 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):

    1. Static IPv4 192.168.122.50/24, gateway 192.168.122.1, DNS server 192.168.122.1.
    2. Static IPv6 fd00:122::50/64.
    3. The connection must start automatically and use these settings after a reboot.
    4. The static hostname must be node1.lab.example.
    5. /etc/hosts must resolve node2 and node2.lab.example to 192.168.122.51.
    Check your result
    • ip -br address shows both 192.168.122.50/24 and fd00:122::50/64 on the interface.
    • nmcli -g ipv4.method,ipv6.method,connection.autoconnect connection show "NAME" prints manual, manual and yes on separate lines.
    • hostnamectl --static prints node1.lab.example.
    • getent hosts node2 prints 192.168.122.51 followed by the names; ping -c1 node2.lab.example answers.
    Hint

    nmcli connection modify NAME ipv4.method manual ipv4.addresses ... ipv4.gateway ... ipv4.dns ... ipv6.method manual ipv6.addresses ..., then nmcli connection up NAME. Do not run up over 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
  2. Practice

    C2 · NFS mount and autofs home directories (16 points, 8 min)

    node2 exports /srv/share and /home/remoteusers (see the preparation). On node1:

    1. Mount node2.lab.example:/srv/share on /mnt/share permanently, at boot, with the NFS option set that waits for the network.
    2. Configure the automounter so that the home directory of any user NAME is mounted from node2.lab.example:/home/remoteusers/NAME on /rhome/NAME when first used, read-write.
    3. The user remoteuser1 (UID 4001, home /rhome/remoteuser1) already exists on node1. Set its password to Ex200!Lab and make it possible for it to log in with that home directory when SELinux is enforcing.
    4. autofs must be running and enabled.
    Check your result
    • findmnt /mnt/share shows type nfs4; cat /mnt/share/readme.txt prints hello from node2; grep /mnt/share /etc/fstab contains _netdev.
    • sudo systemctl is-enabled autofs prints enabled; systemctl is-active autofs prints active.
    • su - remoteuser1 -c 'pwd; cat notes.txt' prints /rhome/remoteuser1 and remote home; findmnt /rhome/remoteuser1 then shows an nfs4 mount.
    • getsebool use_nfs_home_dirs prints use_nfs_home_dirs --> on.
    Hint

    Master map: a file in /etc/auto.master.d/ ending in .autofs with /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
  3. Practice

    C3 · Firewall rules (14 points, 7 min)

    On node1, in the public zone (the default), with every rule permanent and active now:

    1. Allow the http service and the port 8081/tcp.
    2. Make sure the cockpit service is not allowed.
    3. Add a rich rule that rejects the ssh service for connections coming from 192.0.2.0/24.
    4. Forward incoming TCP port 8080 to local port 8081.
    Check your result
    • sudo firewall-cmd --list-all and sudo firewall-cmd --permanent --list-all both show http, 8081/tcp, the forward port port=8080:proto=tcp:toport=8081:toaddr=, and the rich rule; cockpit is not listed.
    • sudo firewall-cmd --get-default-zone prints public.
    • After sudo firewall-cmd --reload the lists are unchanged.
    Hint

    Use --permanent for every rule, then firewall-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
  4. Practice

    C4 · SSH keys and a hardened sshd (12 points, 6 min)

    node2 has the user natasha (password Ex200!Lab). On node1:

    1. As natasha, create an ed25519 key pair without a passphrase (default location) and install the public key for natasha on node2, so that ssh natasha@node2.lab.example hostname works without a password prompt.
    2. Configure sshd on node1 so that root cannot log in over SSH, and the number of authentication attempts per connection is limited to 3. 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 hostname prints node2.lab.example.
    • ls -l /home/natasha/.ssh/id_ed25519 is mode 600 and owned by natasha.
    • sudo sshd -T | grep -E 'permitrootlogin|maxauthtries' prints permitrootlogin no and maxauthtries 3.
    • ssh root@node1.lab.example from node2 is refused.
    Hint

    ssh-keygen -t ed25519 -N "" -f ~/.ssh/id_ed25519 as natasha, then ssh-copy-id. In RHEL 10 the first value found wins, so name the drop-in 01-local.conf. Restart or reload sshd after sshd -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'
  5. Challenge

    C5 · A web server under SELinux (20 points, 10 min)

    On node1:

    1. SELinux must be enforcing now and after a reboot.
    2. Publish the directory /srv/web by httpd on port 8081 through a virtual host. Create /srv/web/index.html containing Linux 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.
    3. httpd must be allowed by SELinux to listen on port 8081, persistently.
    4. Persistently allow users' home directories to be served by httpd (httpd_enable_homedirs).
    5. httpd must be running and enabled. curl http://localhost:8081 must print the page. The firewall allows 8081 from C3.
    Check your result
    • getenforce prints Enforcing; grep ^SELINUX= /etc/selinux/config prints SELINUX=enforcing.
    • curl -s http://localhost:8081 prints Linux Lab web.
    • ls -Zd /srv/web /srv/web/index.html shows httpd_sys_content_t; sudo semanage fcontext -l | grep '/srv/web' shows the rule.
    • sudo semanage port -l | grep -w 8081 shows http_port_t.
    • getsebool httpd_enable_homedirs prints httpd_enable_homedirs --> on.
    • sudo ausearch -m avc -ts recent shows no new denials for httpd.
    Hint

    A file created under /srv is labelled var_t. semanage fcontext -a -t httpd_sys_content_t "/srv/web(/.*)?" then restorecon -Rv /srv/web. semanage port -a -t http_port_t -p tcp 8081. The virtual host needs Listen 8081 and a <Directory> block with Require 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
  6. 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/intern

    Symptoms reported by the team:

    1. systemctl start report fails. The service must run, start at every boot, and /var/log/report.log must grow. Do not rewrite the script's content.
    2. intern was given the right to restart httpd through sudo, but sudo -l -U intern shows nothing.
    3. mount -a prints an error about /srv/extra. The image must mount on /srv/extra now and at boot, and the file must stay in /etc/fstab.
    Check your result
    • systemctl is-active report prints active; systemctl is-enabled report prints enabled; wc -l /var/log/report.log increases over 30 seconds.
    • sudo -l -U intern lists (ALL) /usr/bin/systemctl restart httpd; ls -l /etc/sudoers.d/intern is mode -r--r-----.
    • sudo mount -a prints nothing; findmnt /srv/extra shows ext4; sudo findmnt --verify reports 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 -c names the problem. For fstab: compare the option names with man 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
  7. 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.sh that prints one PASS or FAIL line per item and exits non-zero if any item failed. It must cover at least: default target, httpd, atd, tuned, chronyd, autofs, firewalld enabled; SELinux enforcing; the hostname; the mounts /srv/app, /srv/data, /mnt/exchange, /mnt/share; active swap on /dev/vdc1; audit=1 in the kernel arguments; and the page on port 8081.

    Check your result
    • sudo /root/final-check.sh prints only PASS lines and echo $? prints 0.
    • Temporarily stop httpd (sudo systemctl stop httpd), run the script again: it prints FAIL for httpd and exits non-zero. Start httpd again.
    • uptime -s is 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. Remember set -u does 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=$?"