KodeKloud 100 Days Challenge: Days 1-4 (Or: How I Learned to Stop Worrying and Love the Slow Labs)

Table of Contents
“Before going deeper into kernel-level work, I went back to Linux fundamentals. This is what runs under every K8s cluster and eBPF probe â owning it isn’t optional.”
This series is a deliberate return to Linux fundamentals before going deeper into kernel-level work â CentOS, user management, SSH hardening, permissions. The stuff that runs silently under every K8s cluster and eBPF probe. Owning it isn’t optional.
Four problems this week: non-interactive user creation, temporary account expiry, disabling root SSH across multiple servers, and file permission management. All documented here as a reference.
Day 1: Non-Interactive Users#
The Task#
Create a user with a non-interactive shell â standard pattern for service accounts and system users that should never have a login session.
sudo useradd -s /usr/sbin/nologin username
sudo usermod -s /usr/sbin/nologin username
# Verify
getent passwd username
Expected output:
username:x:1001:1001::/home/username:/usr/sbin/nologin
The Failure Mode#
Ran all of this on the wrong host. Spent time wondering why validation wasn’t passing before checking hostname. Always verify your target host before running privileged commands â hostname before anything else.
# First command in any lab session
hostname
# Then connect to the right target
ssh benny@<server-ip>
Diagnostic Reference#
# Verify shell assignment
getent passwd username
# List all non-interactive accounts
grep nologin /etc/passwd
# Check current host before running anything
hostname
whoami
Day 2: Temporary Users with Account Expiry#
The Task#
Create a user with an expiration date â standard pattern for contractor access, temporary credentials, or time-bounded permissions.
ssh benny@<server-ip>
sudo useradd anita -e 2023-06-05
# Verify
id anita
chage -l anita
Expected output:
Account expires: Jun 05, 2023
useradd vs adduser#
useradd is the low-level utility â explicit flags, no interactive prompts, scriptable. adduser is a higher-level wrapper that prompts interactively. For automation, always use useradd.
Scheduled Account Locking#
# Lock an account after a time window using 'at'
echo "usermod --lock username" | at now + 20 minutes
Useful for temporary access that needs to expire automatically without relying on a human to remember to revoke it. In production, use a proper secrets manager or PAM configuration instead â at jobs don’t survive reboots and have no audit trail.
Diagnostic Reference#
# Full account expiry details
chage -l username
# List all accounts with expiry dates set
awk -F: '$8 != "" {print $1, $8}' /etc/shadow
# Manually expire an account immediately
sudo chage -E 0 username
# Unlock
sudo usermod --unlock username
Day 3: Disabling Root SSH Across Multiple Servers#
The Task#
Disable root login across all servers in the Stratos Datacenter. Direct root SSH is a basic hardening requirement â it removes the universal target account from remote attack surface and forces audit trails through named accounts with sudo.
The Manual Approach#
sudo vi /etc/ssh/sshd_config
# PermitRootLogin no â uncomment and set
sudo systemctl restart sshd
The Problem#
Multiple servers. Manual approach doesn’t scale and introduces inconsistency â one missed server, one typo, and you have an uneven security posture with no visibility into which hosts are actually hardened.
The Automated Approach#
for server in stapp01 stapp02 stapp03; do
ssh $server "sudo sed -i 's/#PermitRootLogin no/PermitRootLogin no/' /etc/ssh/sshd_config && sudo systemctl restart sshd"
done
Consistent across all targets, auditable, repeatable. The right answer for anything that needs to be applied to a fleet.
Verify#
# Confirm the setting on each server
for server in stapp01 stapp02 stapp03; do
echo "$server:"
ssh $server "grep PermitRootLogin /etc/ssh/sshd_config"
done
# Test that root login is actually blocked
ssh root@stapp01
# Should return: Permission denied, please try again
Diagnostic Reference#
# Check SSH config for root login setting
grep -i permitrootlogin /etc/ssh/sshd_config
# View SSH service status and recent auth logs
sudo systemctl status sshd
sudo journalctl -u sshd -n 50
# Check auth log for failed root login attempts
sudo grep "Failed.*root" /var/log/secure
Day 4: File Permissions#
The Task#
Make /tmp/xfusioncorp.sh executable for all users on App Server 1.
ssh app1@<server-ip>
chmod 755 /tmp/xfusioncorp.sh
# Verify
ls -l /tmp/xfusioncorp.sh
Expected output:
-rwxr-xr-x 1 root root 156 Dec 15 10:23 /tmp/xfusioncorp.sh
Permission Reference#
| Mode | Octal | Binary | Meaning |
|---|---|---|---|
| Owner | 7 | 111 | read, write, execute |
| Group | 5 | 101 | read, execute |
| Others | 5 | 101 | read, execute |
755 is the standard for executable scripts that everyone needs to run but only the owner should modify.
Common patterns:
# Read-only for everyone
chmod 444 file
# Owner full, others read-only
chmod 644 file
# Executable for everyone, owner-writable
chmod 755 script.sh
# Private â owner only
chmod 600 secret
# Directory with standard access
chmod 755 /path/to/dir
Diagnostic Reference#
# Check permissions
ls -l filename
stat filename
# Find files with dangerous permissions
find /tmp -perm -o+w -type f
# Full path permission audit
namei -l /tmp/xfusioncorp.sh
What I’d Do Differently#
- Root SSH hardening: Use Ansible from the start instead of a manual loop. The loop works but has no idempotency guarantees â Ansible’s
lineinfilemodule handles thesshd_configedit cleanly and is repeatable without side effects. - Temporary users: Don’t use
atfor account expiry in production. Usechage -Ewith a proper date and back it up with monitoring that alerts when accounts aren’t expired on schedule. - User creation: For any fleet larger than a few servers, use a directory service (LDAP, FreeIPA) instead of local user management. Local accounts don’t scale and create audit gaps.
Diagnostic Reference#
# Always first â verify your target host
hostname
whoami
# User management
getent passwd username
chage -l username
grep nologin /etc/passwd
# SSH hardening
grep -i permitrootlogin /etc/ssh/sshd_config
sudo journalctl -u sshd -n 50
sudo grep "Failed.*root" /var/log/secure
# Permissions
ls -l filename
stat filename
namei -l /path/to/file
find /tmp -perm -o+w -type f
Tags#
#Linux #Infrastructure #Security #SysAdmin #Automation
About the Author#
Elijah Udom (elijahu) is an Infrastructure & Cloud Engineer based in Lagos, Nigeria. AWS, Kubernetes, eBPF security, AI/ML infrastructure. Building in the open.