Linux Security Hardening

Panduan hardening keamanan Linux secara bertahap — mulai dari konfigurasi minimum yang wajib di semua server produksi, hingga level maksimum untuk lingkungan kritis. Setiap section adalah satu lapisan keamanan independen yang bisa diimplementasikan secara progresif.

00

Fondasi Sistem — Level Minimum

Tiga langkah wajib sebelum semua yang lain: sistem selalu diperbarui, login root dinonaktifkan, dan setiap admin memiliki akun non-root dengan sudo.

Update sistem dan aktifkan pembaruan keamanan otomatis

bash
# Debian / Ubuntu
apt update && apt upgrade -y
apt install unattended-upgrades apt-listchanges -y
dpkg-reconfigure -plow unattended-upgrades    # aktifkan interactive
# atau langsung:
echo 'Unattended-Upgrade::Automatic-Reboot "false";' >> /etc/apt/apt.conf.d/50unattended-upgrades
systemctl enable --now unattended-upgrades

# RHEL / Rocky / Alma / CentOS Stream
dnf update -y
dnf install dnf-automatic -y
# /etc/dnf/automatic.conf → apply_updates = yes
systemctl enable --now dnf-automatic-install.timer

# Verifikasi timer berjalan
systemctl list-timers | grep -E 'dnf|unattended'

Buat user admin non-root dan kunci akun root

bash
# Buat user baru
useradd -m -s /bin/bash -G sudo aldo          # Debian/Ubuntu (group sudo)
useradd -m -s /bin/bash -G wheel aldo         # RHEL/Rocky (group wheel)
passwd aldo

# Verifikasi akses sudo SEBELUM melanjutkan
su - aldo
sudo whoami                                    # harus output: root
exit

# Kunci akun root (bukan hapus - tetap bisa di-restore)
passwd -l root                                 # kunci password root
usermod -s /usr/sbin/nologin root              # cabut shell login root

# Verifikasi
grep root /etc/passwd                          # shell harus /usr/sbin/nologin
passwd -S root                                 # status L = locked

Konfigurasi sudo dengan prinsip least privilege

bash
# Selalu edit sudoers via visudo (syntax check otomatis)
visudo

# Di dalam file sudoers - contoh konfigurasi aman:
# Require password for all sudo (default sudoers sudah begini)
Defaults    passwd_tries=3
Defaults    badpass_message="Password salah, akses direkam."
Defaults    logfile="/var/log/sudo.log"
Defaults    log_input, log_output        # catat semua sesi sudo
Defaults    requiretty                   # cegah sudo dari cron/script liar

# User sudo dengan password (tidak pakai NOPASSWD)
%sudo   ALL=(ALL:ALL) ALL               # Debian
%wheel  ALL=(ALL:ALL) ALL               # RHEL

# Jika perlu NOPASSWD, batasi perintah spesifik saja:
aldo ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart nginx

# Verifikasi sudoers tidak ada syntax error
visudo -c
01

SSH Hardening — Level Minimum

SSH adalah titik masuk utama ke server. Konfigurasi yang lemah di sini membatalkan semua lapisan keamanan lainnya.

Konfigurasi sshd_config kritis

bash
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak

cat >> /etc/ssh/sshd_config << 'EOF'

# === Security Hardening ===
Port 2222                           # ganti port default (obscurity, bukan keamanan utama)
PermitRootLogin no                  # larang login langsung sebagai root
PasswordAuthentication no           # wajib key-based, nonaktifkan password
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
PermitEmptyPasswords no
ChallengeResponseAuthentication no
UsePAM yes

X11Forwarding no                    # matikan X11 forwarding
AllowAgentForwarding no
AllowTcpForwarding no               # matikan jika tidak butuh port forwarding
PermitTunnel no

MaxAuthTries 3                      # maksimal 3 percobaan login
MaxSessions 5
LoginGraceTime 30                   # timeout handshake 30 detik

ClientAliveInterval 300             # kirim keepalive tiap 5 menit
ClientAliveCountMax 2               # putus koneksi jika tidak ada respons 2x

# Whitelist algoritma kuat (SSH modern)
KexAlgorithms curve25519-sha256,ecdh-sha2-nistp521
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com
MACs hmac-sha2-512,hmac-sha2-256

# Batasi akses ke user/group tertentu
AllowUsers aldo deploy              # hanya user ini yang boleh SSH
# AllowGroups sshusers             # atau via group
EOF

# Validasi konfigurasi
sshd -t                             # dry-run, tampilkan error jika ada

# Restart (pastikan ada sesi backup!)
systemctl restart sshd
systemctl status sshd

Setup SSH key dan deploy ke server

bash
# === Di MESIN LOKAL ===
# Generate key ed25519
ssh-keygen -t ed25519 -C "aldo@laptop-$(date +%Y%m%d)" -f ~/.ssh/id_ed25519_server

# Copy public key ke server (sebelum menonaktifkan password auth!)
ssh-copy-id -i ~/.ssh/id_ed25519_server.pub -p 22 aldo@<server-ip>
# atau manual:
cat ~/.ssh/id_ed25519_server.pub | ssh aldo@<server-ip> "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

# Test login dengan key sebelum restart sshd
ssh -i ~/.ssh/id_ed25519_server -p 22 aldo@<server-ip>

# === Di SERVER ===
# Pastikan permissions authorized_keys benar
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
restorecon -Rv ~/.ssh                # SELinux: restore context

# Verifikasi setelah ganti port
ssh -i ~/.ssh/id_ed25519_server -p 2222 aldo@<server-ip>

Hardening tambahan: banner dan banner legal

bash
# Buat banner peringatan legal
cat > /etc/ssh/banner << 'EOF'
*******************************************************************
  AKSES TIDAK SAH DILARANG — Aktivitas direkam dan dimonitor.
  Dengan login, Anda menyetujui kebijakan penggunaan sistem ini.
*******************************************************************
EOF

# Tambahkan ke sshd_config
echo "Banner /etc/ssh/banner" >> /etc/ssh/sshd_config
systemctl reload sshd
02

Firewall — Level Minimum

Default deny untuk semua koneksi masuk — hanya port yang eksplisit diizinkan yang bisa diakses. Pilih UFW (Debian/Ubuntu) atau firewalld (RHEL).

UFW — Debian / Ubuntu

bash
apt install ufw -y

# Aturan default
ufw default deny incoming
ufw default allow outgoing
ufw default deny forward

# Izinkan port yang dibutuhkan
ufw allow 2222/tcp comment "SSH"
ufw allow 80/tcp  comment "HTTP"
ufw allow 443/tcp comment "HTTPS"

# Izinkan dari IP/subnet spesifik saja (lebih aman)
ufw allow from 10.0.0.0/8 to any port 2222

# Rate limiting SSH (cegah brute force)
ufw limit 2222/tcp

# Aktifkan
ufw enable
ufw status verbose

# Tambah / hapus rule
ufw deny 3306/tcp                    # blokir MySQL dari luar
ufw delete allow 80/tcp             # hapus rule
ufw reload

Firewalld — RHEL / Rocky / Alma

bash
systemctl enable --now firewalld

# Set zone default ke drop (tolak semua tanpa respons)
firewall-cmd --set-default-zone=drop

# Tambahkan service/port ke zone public
firewall-cmd --permanent --zone=public --add-port=2222/tcp
firewall-cmd --permanent --zone=public --add-service=http
firewall-cmd --permanent --zone=public --add-service=https

# Hapus service default yang tidak dibutuhkan
firewall-cmd --permanent --zone=public --remove-service=dhcpv6-client
firewall-cmd --permanent --zone=public --remove-service=cockpit

# Batasi SSH hanya dari IP tertentu
firewall-cmd --permanent --zone=drop --add-rich-rule='
  rule family="ipv4"
  source address="10.0.0.0/8"
  port port="2222" protocol="tcp"
  accept'

firewall-cmd --reload
firewall-cmd --list-all

Verifikasi port yang mendengarkan

bash
ss -tulnp                             # semua listening ports + proses
ss -tulnp | grep LISTEN               # filter hanya yang listen
netstat -tulnp 2>/dev/null || ss -tulnp

# Port yang tidak dikenal? selidiki prosesnya
lsof -i :<port>
fuser <port>/tcp
03

Proteksi Brute Force — Level Minimum

Fail2ban memantau log dan memblokir IP yang melakukan terlalu banyak percobaan login gagal. Perlindungan pertama terhadap serangan dictionary/brute-force otomatis.

Install dan konfigurasi dasar Fail2ban

bash
apt install fail2ban -y             # Debian/Ubuntu
dnf install fail2ban -y             # RHEL

# Selalu buat jail.local — jangan edit jail.conf langsung
cat > /etc/fail2ban/jail.local << 'EOF'
[DEFAULT]
# Waktu ban default: 1 jam
bantime  = 1h
# Jendela waktu penghitungan retry
findtime = 10m
# Maks percobaan gagal sebelum ban
maxretry = 3
# Jangan ban IP lokal
ignoreip = 127.0.0.1/8 ::1 10.0.0.0/8

# Backend untuk monitoring log
backend = auto
# Email notifikasi (opsional)
# destemail = admin@example.com
# sender = fail2ban@example.com
# action = %(action_mwl)s

[sshd]
enabled  = true
port     = 2222
logpath  = %(sshd_log)s
backend  = %(sshd_backend)s
maxretry = 3
bantime  = 24h          # ban 24 jam untuk SSH (lebih keras dari default)
EOF

systemctl enable --now fail2ban

Tambah jail untuk service lain

bash
# Tambahkan di /etc/fail2ban/jail.local
[nginx-http-auth]
enabled  = true
port     = http,https
logpath  = /var/log/nginx/error.log
maxretry = 5

[nginx-limit-req]
enabled  = true
port     = http,https
logpath  = /var/log/nginx/error.log
maxretry = 10

[postfix-sasl]
enabled  = true
port     = smtp,submission,imap,imaps
logpath  = %(postfix_log)s

systemctl reload fail2ban

Manajemen ban dan monitoring

bash
fail2ban-client status                  # status semua jail
fail2ban-client status sshd            # detail jail SSH: banned IPs, total

# Unban IP secara manual
fail2ban-client set sshd unbanip 1.2.3.4

# Lihat log fail2ban
tail -f /var/log/fail2ban.log
grep "Ban " /var/log/fail2ban.log | tail -20

# Test apakah IP dibanned
fail2ban-client get sshd banned
fail2ban-client get sshd banip 1.2.3.4  # cek status 1 IP
04

Kernel & Sysctl Hardening — Level Menengah

Parameter kernel untuk menutup celah jaringan umum: IP spoofing, ICMP redirect, SYN flood, dan membatasi informasi sensitif kernel yang bisa dibaca oleh proses biasa.

Hardening jaringan (network stack)

bash
cat > /etc/sysctl.d/99-security.conf << 'EOF'
# ─── Jaringan IPv4 ───────────────────────────────────────────
# Nonaktifkan IP forwarding (kecuali server ini adalah router/VPN)
net.ipv4.ip_forward = 0
net.ipv6.conf.all.forwarding = 0

# Blokir source routing (paket dengan rute yang ditentukan pengirim)
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0

# Tolak ICMP redirect (cegah rerouting jahat)
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv6.conf.all.accept_redirects = 0

# Log paket dari luar yang mengklaim IP internal (martian packets)
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1

# Proteksi SYN flood
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 2048

# Reverse path filtering (cegah IP spoofing)
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

# Abaikan broadcast ping (amplification attack)
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1

# Nonaktifkan IPv6 jika tidak digunakan
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
EOF

Hardening memori dan informasi kernel

bash
cat >> /etc/sysctl.d/99-security.conf << 'EOF'
# ─── Memori & Kernel ────────────────────────────────────────
# ASLR — Address Space Layout Randomization (level 2 = full randomisasi)
kernel.randomize_va_space = 2

# Batasi akses ke dmesg (log kernel) hanya untuk root
kernel.dmesg_restrict = 1

# Sembunyikan pointer kernel dari userspace (/proc, /sys)
kernel.kptr_restrict = 2

# Nonaktifkan SysRq magic key (berbahaya jika akses fisik/serial)
kernel.sysrq = 0

# Tambahkan PID ke core dump filename
kernel.core_uses_pid = 1

# Batasi akses ke perf events (data microarchitecture bisa bocorkan info)
kernel.perf_event_paranoid = 3

# Nonaktifkan core dumps untuk setuid programs
fs.suid_dumpable = 0

# Batasi symlink dan hardlink traversal (cegah TOCTOU attacks)
fs.protected_symlinks = 1
fs.protected_hardlinks = 1
fs.protected_fifos = 2
fs.protected_regular = 2
EOF

# Apply semua perubahan
sysctl -p /etc/sysctl.d/99-security.conf

# Verifikasi satu nilai
sysctl kernel.randomize_va_space
sysctl net.ipv4.tcp_syncookies
05

Audit & Logging — Level Menengah

Auditd mencatat siapa yang mengubah file kritis, menjalankan perintah privileged, atau mencoba eskalasi. Tanpa audit trail, investigasi insiden adalah tebak-tebakan.

Install auditd dan atur rules kritis

bash
apt install auditd audispd-plugins -y     # Debian/Ubuntu
dnf install audit audit-libs -y           # RHEL

systemctl enable --now auditd

cat > /etc/audit/rules.d/hardening.rules << 'EOF'
# Hapus rules yang ada dan set buffer
-D
-b 8192
-f 1

# ─── Identity & Access ────────────────────────────────────────
-w /etc/passwd         -p wa -k identity
-w /etc/shadow         -p wa -k identity
-w /etc/group          -p wa -k identity
-w /etc/gshadow        -p wa -k identity
-w /etc/sudoers        -p wa -k sudoers
-w /etc/sudoers.d/     -p wa -k sudoers
-w /var/log/auth.log   -p wa -k auth_log      # Debian
-w /var/log/secure     -p wa -k auth_log      # RHEL

# ─── SSH & PAM ────────────────────────────────────────────────
-w /etc/ssh/sshd_config      -p wa -k sshd_config
-w /etc/pam.d/               -p wa -k pam_config

# ─── Privileged commands ─────────────────────────────────────
-a always,exit -F arch=b64 -S execve -F uid=0 -F auid!=unset -k root_commands
-a always,exit -F path=/usr/bin/sudo       -F perm=x -k sudo_exec
-a always,exit -F path=/usr/bin/su         -F perm=x -k su_exec
-a always,exit -F path=/usr/sbin/useradd   -F perm=x -k user_mgmt
-a always,exit -F path=/usr/sbin/userdel   -F perm=x -k user_mgmt
-a always,exit -F path=/usr/sbin/usermod   -F perm=x -k user_mgmt
-a always,exit -F path=/usr/bin/passwd     -F perm=x -k user_mgmt

# ─── Kernel modules ──────────────────────────────────────────
-w /sbin/insmod    -p x -k modules
-w /sbin/rmmod     -p x -k modules
-w /sbin/modprobe  -p x -k modules
-a always,exit -F arch=b64 -S init_module,finit_module,delete_module -k modules

# ─── File & directory changes di lokasi sensitif ─────────────
-w /bin/   -p wa -k bin_changes
-w /sbin/  -p wa -k sbin_changes
-w /etc/cron.d/      -p wa -k cron
-w /etc/crontab      -p wa -k cron
-w /var/spool/cron/  -p wa -k cron

# ─── Eskalasi privilege & SUID ───────────────────────────────
-a always,exit -F arch=b64 -S setuid,setgid,setreuid,setregid -k privilege_escalation
-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat -F auid>=1000 -k file_perm_change

# Immutable — harus reboot untuk mengubah rules di atas
-e 2
EOF

# Load rules
augenrules --load
auditctl -l                               # verifikasi rules aktif

Query dan analisis audit log

bash
# Cari event berdasarkan key
ausearch -k sudoers --interpret             # perubahan sudoers
ausearch -k user_mgmt -ts today            # manajemen user hari ini
ausearch -k sshd_config -ts recent        # perubahan SSH config

# Laporan ringkas
aureport --summary                         # ringkasan semua event
aureport --login                           # semua event login
aureport --auth --failed                   # semua autentikasi gagal
aureport --exec                            # semua eksekusi program
aureport --file --summary                  # file paling sering diakses

# Filter berdasarkan waktu dan user
ausearch -ua aldo -ts "01/01/2025 00:00:00" -te "31/01/2025 23:59:59"

# Cek log audit secara langsung
tail -f /var/log/audit/audit.log | grep -E 'key=|type=EXECVE'

Sentralisasi log ke remote server

bash
# /etc/rsyslog.d/10-remote.conf (di server sumber)
# Kirim semua log ke log server (port 514 TCP terenkripsi lebih baik)
*.* action(type="omfwd" target="logserver.internal" port="514" protocol="tcp")

# Pastikan log tidak bisa dihapus attacker dengan chattr +a
chattr +a /var/log/auth.log
chattr +a /var/log/syslog
chattr +a /var/log/audit/audit.log

# Verifikasi
lsattr /var/log/auth.log               # harus tampil 'a' flag
systemctl restart rsyslog
06

File System & Integritas — Level Menengah

Cari dan perbaiki file berbahaya (SUID/world-writable), hardening mount point dengan flag noexec/nosuid/nodev, dan pasang AIDE untuk deteksi perubahan file yang tidak sah.

Audit file SUID, SGID, dan world-writable

bash
# Temukan semua file SUID (jalankan sebagai root)
find / -perm /4000 -type f -ls 2>/dev/null | sort -k11

# Temukan semua file SGID
find / -perm /2000 -type f -ls 2>/dev/null | sort -k11

# Temukan world-writable files (kecuali /proc dan /sys)
find / -perm -002 -type f \
  -not -path "/proc/*" \
  -not -path "/sys/*" \
  -not -path "/dev/*" \
  2>/dev/null

# Temukan world-writable directories tanpa sticky bit
find / -perm -002 -type d -not -perm -1000 \
  -not -path "/proc/*" -not -path "/sys/*" 2>/dev/null

# Hapus SUID dari program yang tidak perlu
chmod u-s /usr/bin/at                  # contoh: 'at' jarang dibutuhkan
chmod u-s /usr/bin/newgrp

# Simpan baseline untuk referensi
find / -perm /4000 -type f 2>/dev/null > /root/suid-baseline.txt

Hardening mount point di /etc/fstab

bash
# Tambahkan/update entri di /etc/fstab
# Backup dulu!
cp /etc/fstab /etc/fstab.bak

# Tambahkan flag keamanan ke partisi yang ada:
# (sesuaikan UUID/device dengan output 'blkid')
#
# /tmp — tidak ada alasan untuk menjalankan binary dari /tmp
tmpfs     /tmp     tmpfs  defaults,nodev,nosuid,noexec,size=1G  0 0

# /dev/shm — memory-mapped shared memory, sering dieksploitasi
tmpfs     /dev/shm tmpfs  defaults,nodev,nosuid,noexec          0 0

# /home — tidak perlu device files
UUID=xxxx /home    ext4   defaults,nodev,nosuid                 0 2

# /var/tmp — persistent temp, sama dengan /tmp
UUID=xxxx /var/tmp ext4   defaults,nodev,nosuid,noexec          0 2

# Remount tanpa reboot
mount -o remount /tmp
mount -o remount /dev/shm
mount | grep -E '/tmp|/dev/shm'        # verifikasi flag aktif

Permissions file konfigurasi kritis

bash
# File password — hanya root yang boleh baca
chmod 640 /etc/shadow
chmod 640 /etc/gshadow
chown root:shadow /etc/shadow
chown root:shadow /etc/gshadow

# File konfigurasi — semua user boleh baca (untuk lookup)
chmod 644 /etc/passwd
chmod 644 /etc/group

# Sudoers — hanya root
chmod 440 /etc/sudoers
chown root:root /etc/sudoers

# SSH host keys — private key hanya root
chmod 600 /etc/ssh/ssh_host_*_key
chmod 644 /etc/ssh/ssh_host_*_key.pub
chown root:root /etc/ssh/ssh_host_*

# Verifikasi
ls -la /etc/shadow /etc/passwd /etc/sudoers /etc/ssh/ssh_host_ed25519_key

AIDE — File Integrity Monitoring

bash
apt install aide aide-common -y        # Debian/Ubuntu
dnf install aide -y                    # RHEL

# Build database awal (berjalan lama ~10-30 menit)
aideinit
# Debian: database tersimpan di /var/lib/aide/aide.db.new
# RHEL:   database tersimpan di /var/lib/aide/aide.db.new.gz

# Aktifkan database (rename menjadi database aktif)
cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db      # Debian
# cp /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz  # RHEL

# Cek integritas (bandingkan sistem sekarang dengan baseline)
aide --check
# Output: Added/Removed/Changed files

# Update database setelah patch/update sistem yang sah
aide --update
cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db

# Jadwalkan cek harian via cron
cat > /etc/cron.d/aide-check << 'EOF'
MAILTO=admin@example.com
0 3 * * * root /usr/bin/aide --check 2>&1 | grep -E "^(AIDE|Changed|Added|Removed)"
EOF
07

Kebijakan Akun & Password — Level Menengah

Password yang lemah dan akun tidak aktif adalah pintu belakang yang sering diabaikan. Enforcing complexity, aging, dan lockout via login.defs dan PAM.

Password aging policy di /etc/login.defs

bash
# Edit /etc/login.defs
sed -i 's/^PASS_MAX_DAYS.*/PASS_MAX_DAYS   90/'  /etc/login.defs
sed -i 's/^PASS_MIN_DAYS.*/PASS_MIN_DAYS   7/'   /etc/login.defs
sed -i 's/^PASS_WARN_AGE.*/PASS_WARN_AGE   14/'  /etc/login.defs

# Terapkan ke user yang sudah ada (tidak otomatis untuk user lama)
chage -M 90 -m 7 -W 14 aldo
chage -l aldo                          # verifikasi

# Kunci akun otomatis setelah N hari tidak aktif (sejak password kadaluarsa)
useradd -D -f 30                       # default untuk user baru
chage -I 30 aldo                       # atau per-user

# Audit semua user: cek yang tidak punya password expiry
awk -F: '{ print $1 }' /etc/shadow | while read user; do
  exp=$(chage -l "$user" 2>/dev/null | grep "Maximum number" | awk '{print $NF}')
  echo "$user: $exp"
done

PAM — kompleksitas password

bash
apt install libpam-pwquality -y        # Debian/Ubuntu
dnf install libpwquality -y           # RHEL (sudah tersedia biasanya)

# /etc/security/pwquality.conf
cat > /etc/security/pwquality.conf << 'EOF'
# Panjang minimum 14 karakter
minlen = 14
# Minimal 3 dari 4 kelas karakter (upper, lower, digit, special)
minclass = 3
# Maksimal 3 karakter yang sama berturut-turut
maxrepeat = 3
# Maksimal 4 karakter berurutan (abc, 1234)
maxsequence = 4
# Cek terhadap nama di kolom GECOS /etc/passwd
gecoscheck = 1
# Cek terhadap dictionary words
dictcheck = 1
# Cek terhadap username
usercheck = 1
# Tolak jika password mirip password lama
difok = 5
EOF

# Debian — /etc/pam.d/common-password
# Pastikan baris ini ada:
# password requisite pam_pwquality.so retry=3

# RHEL — /etc/pam.d/system-auth dan password-auth
# Ganti baris pam_pwquality.so dengan:
# password requisite pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type=

PAM — lockout akun setelah percobaan gagal

bash
# pam_faillock: lock akun setelah N percobaan gagal
# Debian — tambahkan ke /etc/pam.d/common-auth:
# SEBELUM baris pam_unix.so
# auth required pam_faillock.so preauth silent deny=5 unlock_time=900
# auth [success=1 default=bad] pam_unix.so
# auth [default=die] pam_faillock.so authfail
# auth sufficient pam_faillock.so authsucc

# RHEL — /etc/security/faillock.conf (lebih modern, kernel 5+)
cat > /etc/security/faillock.conf << 'EOF'
deny = 5
unlock_time = 900
fail_interval = 900
even_deny_root
root_unlock_time = 60
EOF

# Cek status lockout user
faillock --user aldo
# Reset lockout manual
faillock --user aldo --reset

Nonaktifkan akun dan shell yang tidak dibutuhkan

bash
# Set shell /usr/sbin/nologin untuk akun sistem yang tidak perlu login
NOLOGIN_USERS="daemon bin sys sync games man lp mail news uucp nobody www-data backup operator list irc gnats"
for u in $NOLOGIN_USERS; do
  id "$u" &>/dev/null && usermod -s /usr/sbin/nologin "$u" && echo "nologin: $u"
done

# Audit user dengan shell login aktif (seharusnya hanya admin manusia)
awk -F: '$7 ~ //(bash|sh|zsh|fish|ksh|csh)$/ { print $1, $7 }' /etc/passwd

# Kunci akun yang sudah tidak aktif
passwd -l olduser
usermod -e 1 olduser               # set expiry ke epoch = kadaluarsa sekarang

# Cek user tanpa password (berbahaya!)
awk -F: '($2 == "" || $2 == "!") { print $1 }' /etc/shadow
08

SELinux & AppArmor — Level Tinggi

Mandatory Access Control membatasi apa yang boleh dilakukan setiap proses, bahkan jika proses tersebut sudah dikompromis. SELinux untuk RHEL/Fedora, AppArmor untuk Debian/Ubuntu.

SELinux — RHEL / Rocky / Alma / Fedora

bash
# Cek status
sestatus
getenforce                             # Enforcing / Permissive / Disabled

# Set ke enforcing (berlaku langsung, tanpa reboot)
setenforce 1

# Persistent — /etc/selinux/config
sed -i 's/^SELINUX=.*/SELINUX=enforcing/' /etc/selinux/config

# Buat permissive sementara untuk investigasi
setenforce 0
# ... investigate ...
setenforce 1

# Lihat denial terbaru
ausearch -m avc -ts recent
ausearch -m avc -ts recent | audit2why

# Buat dan load policy custom dari denial
ausearch -m avc -ts recent | audit2allow -M mypolicy
semodule -i mypolicy.pp
semodule -l | grep mypolicy            # verifikasi

# Context pada file
ls -Z /etc/passwd                      # lihat SELinux context
restorecon -Rv /var/www/html           # restore context default
chcon -t httpd_sys_content_t /srv/web  # ubah context satu file

AppArmor — Debian / Ubuntu

bash
apt install apparmor apparmor-utils apparmor-profiles -y

# Cek status
aa-status
systemctl status apparmor

# Set semua profil ke enforce mode
aa-enforce /etc/apparmor.d/*

# Lihat profil dalam complain mode (log tanpa blokir)
aa-complain /etc/apparmor.d/usr.sbin.nginx

# Update profil berdasarkan log (interaktif)
aa-logprof

# Lihat denial AppArmor
grep "apparmor" /var/log/kern.log | grep DENIED | tail -20
grep "apparmor" /var/log/syslog | grep DENIED | tail -20

# Generate profil baru untuk aplikasi
aa-genprof /usr/bin/myapp              # ikuti wizard interaktif

Investigasi dan debug denial

bash
# SELinux: gunakan sealert untuk analisis human-readable (RHEL)
dnf install setroubleshoot-server -y
sealert -a /var/log/audit/audit.log
sealert -l "*"                         # semua alert

# AppArmor: lihat log kernel
dmesg | grep apparmor | grep DENIED

# Test apakah suatu aksi akan diblokir
# SELinux:
sesearch --allow -s httpd_t -t var_log_t  # cek aturan yang ada
# AppArmor: cek dengan --dry-run
apparmor_parser -T /etc/apparmor.d/usr.sbin.nginx
09

2FA, Rootkit & Audit CIS — Level Maksimum

Lapisan terakhir untuk lingkungan kritis: autentikasi multi-faktor, deteksi rootkit, audit benchmark CIS, dan monitoring aktif proses serta koneksi jaringan.

Two-Factor Authentication (TOTP) untuk SSH

bash
apt install libpam-google-authenticator -y    # Debian/Ubuntu
dnf install google-authenticator-libpam -y    # RHEL

# Setup TOTP per user (jalankan sebagai user itu sendiri, BUKAN root)
su - aldo
google-authenticator
# Ikuti prompt: pilih y untuk time-based, y untuk update .google_authenticator,
# y untuk disallow multiple uses, n untuk 30-second window (atau y untuk toleransi lebih),
# y untuk rate limiting. Scan QR code dengan Google Authenticator / Authy / etc.
# SIMPAN emergency scratch codes!

# Konfigurasi PAM — /etc/pam.d/sshd
# Tambahkan di baris PERTAMA (sebelum @include):
# auth required pam_google_authenticator.so nullok

# Konfigurasi SSH — /etc/ssh/sshd_config
# Ganti atau tambahkan:
AuthenticationMethods publickey,keyboard-interactive
KbdInteractiveAuthentication yes
# Debian: ChallengeResponseAuthentication yes (flag lama)

systemctl restart sshd

# Test: login harus meminta key + TOTP code
# ssh -p 2222 aldo@<server>   → masukkan key → masukkan TOTP code

Rootkit scanner — rkhunter & chkrootkit

bash
apt install rkhunter chkrootkit -y        # Debian/Ubuntu
dnf install rkhunter -y                   # RHEL (chkrootkit dari EPEL)

# Setup rkhunter
rkhunter --update                         # update database signatures
rkhunter --propupd                        # simpan properti file sebagai baseline

# Scan penuh
rkhunter --check --sk --rwo              # --sk: skip key prompts, --rwo: report warnings only
rkhunter --check --sk 2>&1 | grep -E "Warning|Infected|Possible"

# chkrootkit
chkrootkit                                # scan semua
chkrootkit lrk5                           # scan rootkit spesifik

# Jadwalkan scan mingguan
cat > /etc/cron.d/rootkit-scan << 'EOF'
MAILTO=admin@example.com
0 4 * * 0 root rkhunter --check --sk --rwo 2>&1
0 5 * * 0 root chkrootkit 2>&1 | grep -v "not infected"
EOF

CIS Benchmark audit dengan Lynis

bash
apt install lynis -y                      # Debian/Ubuntu
dnf install lynis -y                      # RHEL (atau dari EPEL)

# Full audit sistem
lynis audit system

# Output penting di akhir:
# Hardening index: 67 [#############       ]
# Tests performed: 267
# Plugins enabled: 2

# Review rekomendasi
lynis audit system 2>&1 | grep -E "^\[WARNING\]|Suggestion"
cat /var/log/lynis.log | grep "SUGGESTION"
cat /var/log/lynis-report.dat | grep "warning"

# Detail test spesifik
lynis show details AUTH-9262             # cek detail test PAM
lynis show tests | grep AUTH             # daftar semua test AUTH

# Quick mode (lebih cepat, kurang detail)
lynis audit system --quick

Monitoring proses dan koneksi aktif

bash
# ─── Koneksi jaringan ─────────────────────────────────────────
ss -tulnp                              # semua listening ports + nama proses
ss -tnp state established             # koneksi yang sedang aktif
lsof -i -P -n | grep LISTEN           # listening processes via lsof

# Proses yang melakukan koneksi ke luar
lsof -i 4 -n -P | grep -v LISTEN
ss -tnp | awk 'NR>1 {print $5, $6}' | sort | uniq -c | sort -rn

# ─── Proses mencurigakan ─────────────────────────────────────
ps auxf                                # process tree dengan user
ps aux --sort=-%cpu | head -15         # top CPU consumers
ps aux --sort=-%mem | head -15         # top memory consumers

# Binary yang berjalan dari lokasi tidak biasa
ls -la /proc/*/exe 2>/dev/null | grep -v '/usr|/bin|/sbin|/lib|/opt'

# ─── Cron dan startup tersembunyi ────────────────────────────
crontab -l                             # cron user saat ini
cat /etc/crontab
ls -la /etc/cron.d/ /etc/cron.daily/ /etc/cron.weekly/
systemctl list-units --state=enabled --type=service  # service aktif

# ─── File yang baru dimodifikasi ─────────────────────────────
find /etc /bin /sbin /usr/bin /usr/sbin -newer /etc/passwd -type f 2>/dev/null
find /tmp /dev/shm /var/tmp -type f -newer /proc/1 2>/dev/null  # file baru di /tmp

Checklist verifikasi akhir hardening

bash
# ─── Ringkasan cek cepat — jalankan setelah hardening selesai ──

echo "=== 1. SSH ==="
sshd -T | grep -E "permitrootlogin|passwordauthentication|maxauthtries|port"

echo "=== 2. Firewall ==="
ufw status verbose 2>/dev/null || firewall-cmd --list-all 2>/dev/null

echo "=== 3. Fail2ban ==="
fail2ban-client status sshd 2>/dev/null

echo "=== 4. Listening ports ==="
ss -tulnp | grep LISTEN

echo "=== 5. Sysctl kritis ==="
sysctl kernel.randomize_va_space net.ipv4.tcp_syncookies kernel.dmesg_restrict

echo "=== 6. SUID files baru ==="
find / -perm /4000 -type f 2>/dev/null > /tmp/suid-now.txt
diff /root/suid-baseline.txt /tmp/suid-now.txt && echo "OK - tidak ada SUID baru"

echo "=== 7. Auditd ==="
systemctl is-active auditd
auditctl -l | wc -l

echo "=== 8. SELinux/AppArmor ==="
getenforce 2>/dev/null || aa-status --enabled 2>/dev/null && echo "MAC: aktif"

echo "=== 9. User dengan shell aktif ==="
awk -F: '$7 ~ //(bash|sh|zsh)$/ { print $1 }' /etc/passwd