2 of 4

RHCSA Practice ExamLesson 2 of 4

Part A: Users, access and automation (100 points)

Seven tasks on accounts, sudo, password policy, shared directories, scheduling, a script, archives and time. Work on node1.

  • useradd
  • chage
  • setfacl
  • crontab
  • systemctl list-timers
  • tar
  • find
  • grep
  • chronyc

55 min7 exercises

After this lesson you can

  • Complete the account, scheduling, scripting and text-processing tasks of the exam within about 55 minutes.

How to run Part A

Start the clock when you read A1. Work on node1. Everything you create must still be there after a reboot.

TaskTopicPointsMinutesSkills it draws on
A1Users, groups, sudo1810Users, Groups and sudo
A2Password policy, umask126Users, Groups and sudo; Shell Fluency
A3Shared directory126File Systems: permission problems
A4Cron, timer168Scheduling and Time
A5Script1810Shell Scripting
A6Archive, find, grep148Archives; Working with Text
A7Time client105Scheduling and Time

The tasks are independent apart from users (A1) being needed by A2, A3 and A4. If one task stalls for longer than 1.5 times its minutes, write down its number and move on.

A1 __/18  A2 __/12  A3 __/12  A4 __/16  A5 __/18  A6 __/14  A7 __/10   Part A = ___/100

Marking Part A

For each task run its checks, in a fresh shell, as the user named. Award the points only if every check passes. Record the result on the marking sheet from the briefing.

Common reason for a lost pointWhere it came from
Crontab typed for root instead of natashaA4: use crontab -u natasha
Timer started but not enabled, or the service enabled instead of the timerA4
Script not executable by others, or the usage message on stdoutA5
login.defs edited but the check expected only new users to be affectedA2: read what is asked
sudo -l correct but file mode wrong, so visudo -c complainsA1
Setgid missing, so files get the creator’s groupA3
chronyd restarted but not enabledA7

Total available in Part A: 100 points. Write your score before starting Part B.

Practice

0 of 7 done

Do these on your own system. They get harder. Check each result, then tick it off.

  1. Practice

    A1 · Users, groups and sudo (18 points, 10 min)

    On node1:

    1. Create the group devs with GID 5500 and the group sysadm.
    2. Create user natasha with UID 3456, primary group devs and supplementary group sysadm.
    3. Create user harry with supplementary group sysadm and the default shell /bin/bash.
    4. Create user sarah with the shell /sbin/nologin, not a member of sysadm.
    5. Set the password of all three users to Ex200!Lab.
    6. Members of sysadm must be able to run any command as root through sudo without being asked for a password. sarah must not have sudo rights.
    Check your result
    • id natasha shows uid=3456, gid=5500(devs), groups including sysadm.
    • id harry lists sysadm. getent passwd sarah | cut -d: -f7 prints /sbin/nologin.
    • getent group devs shows GID 5500.
    • sudo -l -U harry shows (ALL) NOPASSWD: ALL; sudo -l -U sarah says she may not run sudo.
    • sudo visudo -c reports every file parsed OK. su - sarah is refused with the message that the account is unavailable.
    Hint

    groupadd -g 5500 devs, useradd -u 3456 -g devs -G sysadm natasha, chpasswd, and a drop-in file /etc/sudoers.d/sysadm with %sysadm ALL=(ALL) NOPASSWD: ALL (check with visudo -c, mode 440).

    Solution
    sudo groupadd -g 5500 devs
    sudo groupadd sysadm
    sudo useradd -u 3456 -g devs -G sysadm natasha
    sudo useradd -G sysadm -s /bin/bash harry
    sudo useradd -s /sbin/nologin sarah
    for u in natasha harry sarah; do echo "$u:Ex200!Lab" | sudo chpasswd; done
    echo '%sysadm ALL=(ALL) NOPASSWD: ALL' | sudo tee /etc/sudoers.d/sysadm
    sudo chmod 440 /etc/sudoers.d/sysadm
    sudo visudo -c
    id natasha harry sarah
  2. Practice

    A2 · Password policy and default umask (12 points, 6 min)

    On node1:

    1. Accounts created from now on must have passwords that expire after 45 days, may not be changed within 2 days of the last change, and warn 7 days before expiry.
    2. natasha must change her password at least every 30 days, with a 5-day warning.
    3. harry must be forced to change his password at his next login.
    4. sarah's account must expire on 2027-12-31.
    5. Files that natasha creates in her login shell must have mode 640 and directories 750 by default.
    Check your result
    • grep -E '^PASS_(MAX|MIN|WARN)' /etc/login.defs shows PASS_MAX_DAYS 45, PASS_MIN_DAYS 2, PASS_WARN_AGE 7.
    • chage -l natasha shows maximum 30, warning 5. chage -l harry shows Last password change: password must be changed.
    • chage -l sarah shows Account expires: Dec 31, 2027.
    • sudo -i -u natasha umask prints 0027.
    Hint

    /etc/login.defs affects only users created afterwards. chage -M -W -d -E change existing ones. A login shell reads ~/.bash_profile, which sources ~/.bashrc: put umask 027 there.

    Solution
    sudo sed -i -E 's/^PASS_MAX_DAYS.*/PASS_MAX_DAYS   45/; s/^PASS_MIN_DAYS.*/PASS_MIN_DAYS   2/; s/^PASS_WARN_AGE.*/PASS_WARN_AGE   7/' /etc/login.defs
    sudo chage -M 30 -W 5 natasha
    sudo chage -d 0 harry
    sudo chage -E 2027-12-31 sarah
    echo 'umask 027' | sudo tee -a /home/natasha/.bashrc
    sudo chown natasha:devs /home/natasha/.bashrc
    grep -E '^PASS_(MAX|MIN|WARN)' /etc/login.defs
    chage -l natasha | head -8
    sudo -i -u natasha umask
  3. Practice

    A3 · Shared directory for the sysadm group (12 points, 6 min)

    On node1 create /srv/sysadm:

    • owned by root, group sysadm;
    • members of sysadm can create, read, modify and delete files in it; nobody else has any access;
    • every new file or directory created in it automatically belongs to group sysadm;
    • a file created by natasha must be writable by harry without anyone changing a mode by hand (regardless of their umask).
    Check your result
    • ls -ld /srv/sysadm shows drwxrws--- and group sysadm.
    • getfacl /srv/sysadm includes default:group:sysadm:rwx.
    • sudo -u natasha touch /srv/sysadm/a.txt && sudo -u harry bash -c 'echo ok >> /srv/sysadm/a.txt' succeeds.
    • sudo -u sarah ls /srv/sysadm is denied.
    Hint

    Mode 2770 gives setgid. A default ACL, setfacl -d -m g:sysadm:rwx, makes new files group-writable independent of umask. Note that natasha's umask is 027 from the previous task.

    Solution
    sudo mkdir -p /srv/sysadm
    sudo chown root:sysadm /srv/sysadm
    sudo chmod 2770 /srv/sysadm
    sudo setfacl -d -m g:sysadm:rwx /srv/sysadm
    sudo setfacl -m g:sysadm:rwx /srv/sysadm
    ls -ld /srv/sysadm
    getfacl /srv/sysadm
    sudo -u natasha touch /srv/sysadm/a.txt
    sudo -u harry bash -c 'echo ok >> /srv/sysadm/a.txt' && echo harry-can-write
  4. Practice

    A4 · Cron job and systemd timer (16 points, 8 min)

    On node1:

    1. Schedule a cron job for natasha that runs logger "EX200 in progress" at 14:23 every weekday (Monday to Friday).
    2. Create a systemd service report.service that runs /usr/local/bin/report.sh (you write it: it appends the output of date to /var/log/report.log), and a timer report.timer that runs it every day at 06:30 and runs it at the next boot if the machine was off at 06:30. The timer must be enabled and active.
    Check your result
    • crontab -l -u natasha shows 23 14 * * 1-5 logger "EX200 in progress".
    • systemctl is-enabled report.timer prints enabled; systemctl is-active report.timer prints active.
    • systemctl cat report.timer shows OnCalendar=--* 06:30:00 and Persistent=true.
    • sudo systemctl start report.service && tail -1 /var/log/report.log prints a date.
    Hint

    crontab -u natasha -e. The service is Type=oneshot; the timer needs [Install] WantedBy=timers.target. daemon-reload after creating units. Enable the timer.

    Solution
    ( sudo crontab -u natasha -l 2>/dev/null; echo '23 14 * * 1-5 logger "EX200 in progress"' ) | sudo crontab -u natasha -
    sudo crontab -u natasha -l
    printf '#!/bin/bash\ndate >> /var/log/report.log\n' | sudo tee /usr/local/bin/report.sh
    sudo chmod 755 /usr/local/bin/report.sh
    sudo tee /etc/systemd/system/report.service <<'EOT'
    [Unit]
    Description=Daily report
    
    [Service]
    Type=oneshot
    ExecStart=/usr/local/bin/report.sh
    EOT
    sudo tee /etc/systemd/system/report.timer <<'EOT'
    [Unit]
    Description=Run the report daily
    
    [Timer]
    OnCalendar=*-*-* 06:30:00
    Persistent=true
    
    [Install]
    WantedBy=timers.target
    EOT
    sudo systemctl daemon-reload
    sudo systemctl enable --now report.timer
    systemctl list-timers report.timer --no-pager
  5. Challenge

    A5 · A shell script that takes arguments (18 points, 10 min)

    On node1 create the executable script /usr/local/bin/fileinfo.sh, usable by every user:

    • For each argument, print ARGUMENT: directory if it is a directory, ARGUMENT: file (N bytes) if it is a regular file (N is its size), or ARGUMENT: missing otherwise.
    • The exit status is 0 if everything exists and 1 if at least one argument is missing.
    • With no arguments it prints Usage: SCRIPTNAME PATH... on standard error and exits with status 2.
    Check your result
    • fileinfo.sh /etc /etc/hostname prints /etc: directory and /etc/hostname: file (N bytes); echo $? is 0.
    • fileinfo.sh /etc /nope prints a missing line; echo $? is 1.
    • fileinfo.sh 2>/dev/null; echo $? prints 2; without the redirect the usage line is printed.
    • ls -l /usr/local/bin/fileinfo.sh shows -rwxr-xr-x. sudo -u sarah /usr/local/bin/fileinfo.sh /etc works.
    Hint

    Test the argument count with [ $# -eq 0 ], loop over "$@", use -d and -f, stat -c %s FILE for size, and keep a status variable.

    Solution
    sudo tee /usr/local/bin/fileinfo.sh <<'EOT'
    #!/bin/bash
    if [ $# -eq 0 ]; then
        echo "Usage: $0 PATH..." >&2
        exit 2
    fi
    status=0
    for p in "$@"; do
        if [ -d "$p" ]; then
            echo "$p: directory"
        elif [ -f "$p" ]; then
            echo "$p: file ($(stat -c %s "$p") bytes)"
        else
            echo "$p: missing"
            status=1
        fi
    done
    exit $status
    EOT
    sudo chmod 755 /usr/local/bin/fileinfo.sh
    fileinfo.sh /etc /etc/hostname /nope; echo $?
    fileinfo.sh; echo $?
  6. Practice

    A6 · Archives, find and grep (14 points, 8 min)

    On node1, as root:

    1. Create /root/ssh-backup.tar.bz2, a bzip2-compressed archive of the directory /etc/ssh.
    2. Create the directory /opt/restore and extract only etc/ssh/sshd_config from that archive into it.
    3. Write the paths of all regular files under /usr/share/doc larger than 100 KiB, sorted alphabetically, one per line, to /root/bigdocs.txt.
    4. Write every line of /etc/services that contains ssh (any case) and is not a comment line to /root/ssh-lines.txt.
    Check your result
    • file /root/ssh-backup.tar.bz2 says bzip2 compressed data; tar -tjf /root/ssh-backup.tar.bz2 lists etc/ssh/sshd_config.
    • find /opt/restore -type f prints only /opt/restore/etc/ssh/sshd_config.
    • /root/bigdocs.txt is non-empty, sorted (sort -c /root/bigdocs.txt prints nothing), every path exists and is over 100k.
    • /root/ssh-lines.txt has no line beginning with # and every line matches ssh ignoring case.
    Hint

    tar -cjf, tar -xjf ARCHIVE -C DIR MEMBER, find -type f -size +100k | sort, grep -i ssh FILE | grep -v '^#'. tar strips the leading / and warns; that is normal.

    Solution
    sudo tar -cjf /root/ssh-backup.tar.bz2 /etc/ssh
    sudo mkdir -p /opt/restore
    sudo tar -xjf /root/ssh-backup.tar.bz2 -C /opt/restore etc/ssh/sshd_config
    sudo find /opt/restore -type f
    sudo find /usr/share/doc -type f -size +100k | sort | sudo tee /root/bigdocs.txt >/dev/null
    grep -i ssh /etc/services | grep -v '^#' | sudo tee /root/ssh-lines.txt >/dev/null
    sudo sort -c /root/bigdocs.txt && echo sorted
  7. Warm-up

    A7 · Time client and time zone (10 points, 5 min)

    On node1 (node2 already serves time):

    1. Synchronise the clock with the server node2.lab.example only: remove or disable the default pool.
    2. Make sure the time service starts at boot.
    3. Set the system time zone to Asia/Riyadh.
    Check your result
    • grep -E '^(server|pool)' /etc/chrony.conf shows server node2.lab.example iburst and no active pool line.
    • systemctl is-enabled chronyd is enabled, systemctl is-active chronyd is active.
    • chronyc sources lists node2.lab.example (after a minute it carries ^*).
    • timedatectl | grep 'Time zone' shows Asia/Riyadh.
    Hint

    Comment out the pool line, add server node2.lab.example iburst, systemctl restart chronyd, timedatectl set-timezone Asia/Riyadh.

    Solution
    sudo sed -i 's/^pool /#pool /' /etc/chrony.conf
    echo 'server node2.lab.example iburst' | sudo tee -a /etc/chrony.conf
    sudo systemctl enable --now chronyd
    sudo systemctl restart chronyd
    sudo timedatectl set-timezone Asia/Riyadh
    sleep 5; chronyc sources
    timedatectl