Server yang baru mendapat alamat IP publik tidak menunggu lama untuk dikunjungi: dalam hitungan menit pertama, bot pemindai sudah mencoba SSH di port 22, HTTP di port 80, dan segala pintu yang pernah dipakai perangkat lain. Sebagian besar kunjungan itu tidak berbahaya, tetapi cukup satu service usang yang terlupa dimatikan — database uji coba, panel admin, bahkan server dev lama — untuk menjadi pintu masuk. Proyek ini mengamankan server publik secara metodis lewat tiga fase: audit apa yang sedang terbuka, firewall yang menutup semuanya kecuali yang kita izinkan, lalu verifikasi yang membuktikan aturan itu benar-benar bekerja — bukan sekadar terpasang.
Setiap fase menghasilkan artefak yang bisa dibaca ulang:
audit-baseline.sh— mengumpulkan service berjalan, port terbuka, user dengan shell, kunci SSH per user, dan paket tertinggal menjadi satu laporan bernomor beserta ringkasan temuan,latihan.nft— ruleset nftables default-deny: chain input berkebijakandrop, loopback dan balasan koneksi sah diloloskan, hanya SSH/HTTP/HTTPS yang dibuka, sisanya dicatat dengan rem lalu dibuang,validasi-ruleset.sh— sepuluh pemeriksaan struktur dengangrepyang harus lolos sebelum ruleset menyentuh server,verifikasi-keamanan.sh— membandingkan ruleset dengankebijakan-port.txt, menagih service merespons, lalu menjatuhkan vonis PASS atau FAIL beserta exit code-nya.
Tampilan Program Akhir #
Sesi berikut menunjukkan fase ketiga pada data contoh: server latihan python3 di port 8765 berperan sebagai service yang harus menjawab, lalu test suite membuktikan seluruh klaim proyek secara otomatis:
$ bash verifikasi-keamanan.sh latihan.nft kebijakan-port.txt http://127.0.0.1:8765/
== VERIFIKASI KEAMANAN SERVER ==
ruleset : latihan.nft
kebijakan : kebijakan-port.txt (port: 22 80 443)
[1] struktur ruleset
OK lolos 10 pemeriksaan validasi-ruleset.sh
[2] port yang dibuka ruleset
ruleset : 22 80 443
kebijakan: 22 80 443
OK port ruleset sama dengan kebijakan
[3] service merespons
OK http://127.0.0.1:8765/ menjawab (kode 200)
HASIL: PASS — 3/3 pemeriksaan lulus
$ bash tests/run-tests.sh | tail -n 5
OK service mati dilaporkan
OK port 8765 kembali bebas setelah server mati
OK argumen kurang keluar 4
OK berkas hilang keluar 4
PASSED: 27/27 test lulus
Tiga baris OK pada laporan pertama adalah inti proyek: struktur ruleset diperiksa sebelum dipasang, port yang dibuka sama persis dengan kebijakan tertulis, dan service di balik port itu benar-benar menjawab. Ketika salah satu syarat runtuh — service mati, atau kebijakan berubah tanpa diikuti ruleset — laporan berganti FAIL dengan exit code yang bisa dibaca cron.
Tujuan Pembelajaran #
Setelah menyelesaikan proyek ini, kita mampu:
- memetakan permukaan serangan server: service berjalan, port terbuka, alamat yang didengarkan, akun dengan shell, sampai paket yang tertinggal,
- membedakan port yang hanya mendengarkan loopback dari yang terjangkau dari luar,
- menulis ruleset nftables default-deny lengkap dan membacanya ulang baris per baris,
- memvalidasi struktur ruleset dengan
grepsebelum aturan diterapkan ke server, - menyusun kebijakan port sebagai berkas yang sama-sama dibaca manusia dan skrip,
- menguji aturan dari sisi klien: port terbuka harus merespons, port lain harus ditolak,
- menjadikan verifikasi sebagai kebiasaan berkala lewat cron dan checklist hardening berprioritas.
Prasyarat #
Proyek ini merangkai materi dari beberapa section sekaligus. Chapter yang paling sering dirujuk:
- Firewall — chain, table, policy, dan stateful inspection sebagai fondasi seluruh ruleset,
- nftables
— sintaks
nft, struktur table/chain/rule, dan ruleset default-deny, - ufw dan firewalld
— padanan perintah frontend bila server Anda dikelola lewat
ufw, - ss dan netstat — membaca socket yang mendengarkan beserta proses pemiliknya.
Tahapan Pengerjaan #
Proyek dikerjakan dalam tiga bagian berurutan. Setiap bagian diakhiri dengan artefak yang bisa diperiksa:
- Bagian 1: Audit Keamanan — memetakan service, port, user, kunci SSH, dan paket usang ke dalam satu laporan baseline.
- Bagian 2: Konfigurasi Firewall — menulis ruleset default-deny lengkap, membedahnya baris per baris, dan menolaknya bila strukturnya melenceng.
- Bagian 3: Verifikasi Keamanan — menguji port terbuka dan port tertutup dari sisi klien, lalu merangkum semuanya menjadi laporan PASS/FAIL yang dijadwalkan.
Mulailah dari Bagian 1 karena daftar izin di ruleset Bagian 2 dan seluruh pengujian Bagian 3 diambil langsung dari temuan audit — mengunci pintu sebelum tahu pintunya apa adanya hanya memindahkan masalah. Berkas sumber proyek (latihan.nft, kebijakan-port.txt, checklist-hardening.txt, tiga skrip di config/, serta tests/run-tests.sh dan docs/README.txt) tersedia pada bagian Berkas Sumber di bawah halaman setiap bagian, sehingga hasil pekerjaan bisa dibandingkan dengan versi referensi kapan saja.
Petakan port terbuka, service berjalan, dan user sebagai baseline keamanan.
Buka → # Bagian 2: Konfigurasi FirewallTerapkan aturan firewall default-deny dengan pengecualian yang terdokumentasi.
Buka → # Bagian 3: Verifikasi KeamananUji aturan firewall dan hardening untuk memastikan server benar-benar terlindungi.
Buka →Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
config/audit-baseline.sh
Unduh berkas#!/usr/bin/env bash
# audit-baseline.sh — kumpulkan baseline keamanan server ke satu laporan.
#
# Pemakaian:
# audit-baseline.sh <dir-data> > laporan-audit.txt
#
# <dir-data> adalah miniatur filesystem server yang berisi snapshot:
# services.txt systemctl list-units --type=service
# --state=running --no-pager --no-legend
# port-terbuka.txt ss -tlnH
# passwd cuplikan /etc/passwd
# upgradable.txt apt list --upgradable
# home/<user>/... home directory tiap user (untuk authorized_keys)
#
# Kode keluar:
# 0 laporan berhasil dihasilkan (temuan dibaca isinya, bukan kodenya)
# 1 pemakaian salah: argumen hilang atau snapshot tidak lengkap
set -u
if [ "$#" -ne 1 ]; then
printf 'pemakaian: audit-baseline.sh <dir-data>\n' >&2
exit 1
fi
DATA=$1
if [ ! -d "$DATA" ]; then
printf 'audit-baseline.sh: folder data tidak ditemukan: %s\n' "$DATA" >&2
exit 1
fi
for berkas in services.txt port-terbuka.txt passwd upgradable.txt; do
if [ ! -f "$DATA/$berkas" ]; then
printf 'audit-baseline.sh: berkas snapshot hilang: %s/%s\n' \
"$DATA" "$berkas" >&2
exit 1
fi
done
printf '===== AUDIT BASELINE KEAMANAN =====\n'
printf 'sumber data: %s\n\n' "$DATA"
# --- [1] service yang sedang berjalan ---------------------------------
jumlah_service=$(awk '$4 == "running" { c++ } END { print c + 0 }' \
"$DATA/services.txt")
printf '[1] SERVICE BERJALAN: %d\n' "$jumlah_service"
awk '$4 == "running" { print $1 }' "$DATA/services.txt" | sort |
sed 's/^/ /'
printf '\n'
# --- [2] port TCP yang terbuka ----------------------------------------
jumlah_port=$(grep -c . "$DATA/port-terbuka.txt")
printf '[2] PORT TCP TERBUKA: %d\n' "$jumlah_port"
awk '{
ket = "semua interface"
if (substr($4, 1, 4) == "127.")
ket = "loopback saja"
printf " %-15s %s\n", $4, ket
}' "$DATA/port-terbuka.txt"
printf '\n'
# --- [3] user yang punya shell login ----------------------------------
jumlah_user=$(awk -F: '$7 !~ /(nologin|false)$/ { c++ } END { print c + 0 }' \
"$DATA/passwd")
printf '[3] USER DENGAN SHELL LOGIN: %d\n' "$jumlah_user"
awk -F: '$7 !~ /(nologin|false)$/ { printf " %-8s %s\n", $1, $7 }' \
"$DATA/passwd"
printf '\n'
# --- [4] kunci SSH per user --------------------------------------------
printf '[4] KUNCI SSH PER USER:\n'
awk -F: '$7 !~ /(nologin|false)$/ { print $1, $6 }' "$DATA/passwd" |
while read -r user home; do
kunci="$DATA$home/.ssh/authorized_keys"
if [ -f "$kunci" ]; then
printf ' %-8s %d kunci\n' "$user" "$(grep -c . "$kunci")"
else
printf ' %-8s tanpa authorized_keys\n' "$user"
fi
done
printf '\n'
# --- [5] paket yang tertinggal pembaruan --------------------------------
jumlah_paket=$(grep -c 'upgradable from' "$DATA/upgradable.txt")
printf '[5] PAKET SIAP DIPERBARUI: %d\n' "$jumlah_paket"
grep 'upgradable from' "$DATA/upgradable.txt" | awk '{ print " " $1 }'
printf '\n'
# --- ringkasan temuan ----------------------------------------------------
jumlah_luar=$(awk '{ if (substr($4, 1, 4) != "127.") c++ }
END { print c + 0 }' "$DATA/port-terbuka.txt")
tanpa_kunci=$(awk -F: '$7 !~ /(nologin|false)$/ { print $1, $6 }' \
"$DATA/passwd" |
while read -r user home; do
[ -f "$DATA$home/.ssh/authorized_keys" ] || printf '%s\n' "$user"
done | paste -sd' ' -)
jumlah_tanpa=$(printf '%s' "$tanpa_kunci" | wc -w)
printf 'RINGKASAN TEMUAN:\n'
printf ' - %d port mendengarkan di semua interface (terjangkau dari luar)\n' \
"$jumlah_luar"
printf ' - %d akun shell tanpa authorized_keys: %s\n' \
"$jumlah_tanpa" "$tanpa_kunci"
printf ' - %d paket tertinggal pembaruan\n' "$jumlah_paket"
exit 0
config/validasi-ruleset.sh
Unduh berkas#!/usr/bin/env bash
# validasi-ruleset.sh — periksa struktur ruleset nftables sebelum diterapkan.
#
# Pemakaian:
# validasi-ruleset.sh <ruleset.nft>
#
# Pemeriksaan memakai grep pada bentuk baku yang kita sepakati di
# proyek ini; ubah daftar port = ubah ruleset, kebijakan-port.txt,
# dan pola dport di bawah ini bersama-sama.
#
# Kode keluar:
# 0 seluruh pemeriksaan lolos
# N jumlah pemeriksaan yang gagal
# 1 berkas ruleset tidak ditemukan
set -u
berkas=${1:-}
if [ -z "$berkas" ] || [ ! -f "$berkas" ]; then
printf 'validasi-ruleset.sh: berkas ruleset tidak ditemukan: %s\n' \
"$berkas" >&2
exit 1
fi
gagal=0
# periksa <pola> <pesan>: pola harus ditemukan.
periksa() {
if grep -qE -- "$1" "$berkas"; then
printf 'OK %s\n' "$2"
else
printf 'GAGAL %s\n' "$2"
gagal=$((gagal + 1))
fi
}
# tolak <pola> <pesan>: pola justru tidak boleh ada.
tolak() {
if grep -qE -- "$1" "$berkas"; then
printf 'GAGAL %s\n' "$2"
gagal=$((gagal + 1))
else
printf 'OK %s\n' "$2"
fi
}
periksa '^#!/usr/sbin/nft -f' 'shebang nft -f (bisa dieksekusi langsung)'
periksa '^flush ruleset' 'ruleset lama dibuang dulu (flush ruleset)'
periksa '^table inet filter' 'table inet filter dideklarasikan'
periksa 'policy drop;' 'kebijakan chain input: drop'
periksa 'iifname "lo" accept' 'loopback diizinkan'
periksa 'ct state established,related accept' 'balasan koneksi sah diizinkan'
periksa 'tcp dport \{ 22, 80, 443 \} accept' 'hanya SSH, HTTP, HTTPS yang dibuka'
periksa 'limit rate .* log prefix' 'paket yang jatuh ke policy dicatat dengan rem'
tolak 'policy accept;' 'tidak ada kebijakan accept yang menyelip'
tolak '^[[:space:]]*accept[[:space:]]*$' 'tidak ada aturan accept tanpa syarat'
exit "$gagal"
config/verifikasi-keamanan.sh
Unduh berkas#!/usr/bin/env bash
# verifikasi-keamanan.sh — buktikan ruleset, kebijakan port, dan service
# hidup dalam satu laporan PASS/FAIL.
#
# Pemakaian:
# verifikasi-keamanan.sh <ruleset.nft> <kebijakan-port.txt> <url-uji>
#
# Pemeriksaan:
# [1] struktur ruleset — memanggil validasi-ruleset.sh dari folder sama
# [2] port ruleset == daftar port di kebijakan-port.txt
# [3] service merespons — curl ke <url-uji>; exit 0 = ada yang menjawab
#
# Kode keluar:
# 0 semua pemeriksaan lulus (PASS)
# N jumlah pemeriksaan yang gagal (1-3)
# 4 pemakaian salah: argumen kurang atau berkas tidak ada
set -u
DIR=$(cd "$(dirname "$0")" && pwd)
if [ "$#" -ne 3 ]; then
printf 'pemakaian: verifikasi-keamanan.sh <ruleset> <kebijakan-port> <url-uji>\n' >&2
exit 4
fi
RULESET=$1
KEBIJAKAN=$2
URL=$3
for berkas in "$RULESET" "$KEBIJAKAN"; do
if [ ! -f "$berkas" ]; then
printf 'verifikasi-keamanan.sh: berkas tidak ditemukan: %s\n' \
"$berkas" >&2
exit 4
fi
done
if [ ! -f "$DIR/validasi-ruleset.sh" ]; then
printf 'verifikasi-keamanan.sh: validasi-ruleset.sh tidak ada di %s\n' \
"$DIR" >&2
exit 4
fi
gagal=0
# Daftar port di kebijakan dihitung lebih dulu untuk kepala laporan.
port_kebijakan=$(awk '$1 ~ /^[0-9]+$/ { print $1 }' "$KEBIJAKAN" |
sort -n | paste -sd' ' -)
printf '== VERIFIKASI KEAMANAN SERVER ==\n'
printf 'ruleset : %s\n' "$RULESET"
printf 'kebijakan : %s (port: %s)\n\n' "$KEBIJAKAN" \
"${port_kebijakan:-(kosong)}"
# --- [1] struktur ruleset -----------------------------------------------
out=$(bash "$DIR/validasi-ruleset.sh" "$RULESET")
status_val=$?
jumlah_ok=$(printf '%s\n' "$out" | grep -c '^OK')
printf '[1] struktur ruleset\n'
if [ "$status_val" -eq 0 ]; then
printf ' OK lolos %d pemeriksaan validasi-ruleset.sh\n' "$jumlah_ok"
else
printf ' GAGAL ditolak validasi-ruleset.sh (%d pemeriksaan gagal)\n' \
"$status_val"
gagal=$((gagal + 1))
fi
# --- [2] port yang dibuka ruleset == kebijakan ---------------------------
port_ruleset=$(grep -oE 'dport[[:space:]]+\{[^}]*\}' "$RULESET" |
grep -oE '[0-9]+' | sort -n | paste -sd' ' -)
printf '[2] port yang dibuka ruleset\n'
printf ' ruleset : %s\n' "${port_ruleset:-(kosong)}"
printf ' kebijakan: %s\n' "${port_kebijakan:-(kosong)}"
if [ -n "$port_kebijakan" ] && [ "$port_ruleset" = "$port_kebijakan" ]; then
printf ' OK port ruleset sama dengan kebijakan\n'
else
printf ' GAGAL port ruleset berbeda dengan kebijakan\n'
gagal=$((gagal + 1))
fi
# --- [3] service merespons ------------------------------------------------
printf '[3] service merespons\n'
kode=$(curl -s -o /dev/null -w '%{http_code}' --max-time 5 "$URL")
curl_exit=$?
if [ "$curl_exit" -eq 0 ]; then
printf ' OK %s menjawab (kode %s)\n' "$URL" "$kode"
else
printf ' GAGAL %s tidak menjawab (curl exit %d)\n' "$URL" "$curl_exit"
gagal=$((gagal + 1))
fi
# --- ringkasan ------------------------------------------------------------
lulus=$((3 - gagal))
printf '\nHASIL: '
if [ "$gagal" -eq 0 ]; then
printf 'PASS — 3/3 pemeriksaan lulus\n'
else
printf 'FAIL — %d/3 pemeriksaan lulus\n' "$lulus"
fi
exit "$gagal"
tests/run-tests.sh
Unduh berkas#!/usr/bin/env bash
# run-tests.sh — test suite untuk proyek firewall dan hardening server.
# Suite menyiapkan folder kerja terisolasi (mktemp), menyalin berkas
# config/, membangun fixture audit, menyalakan server latihan python3
# sebagai pengganti service sungguhan, lalu menguji: laporan audit dari
# fixture, validasi ruleset (valid dan rusak), verifikasi keamanan
# (PASS dan FAIL), beserta exit code tiap cabangnya.
# Jalankan dari mana saja: bash tests/run-tests.sh
set -u
SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
PROJ_DIR=$(dirname "$SCRIPT_DIR")
CONFIG="$PROJ_DIR/config"
PASS=0
FAIL=0
WORK=""
SERVER=""
# assert_eq <harapan> <nyata> <pesan>: bandingkan dua nilai.
assert_eq() {
if [ "$1" = "$2" ]; then
PASS=$((PASS + 1))
printf 'OK %s\n' "$3"
else
FAIL=$((FAIL + 1))
printf 'GAGAL %s: harapan %s, nyata %s\n' "$3" "$1" "$2"
fi
}
# assert_ada <pola> <berkas> <pesan>: pola harus ditemukan di berkas.
assert_ada() {
if grep -qF -- "$1" "$2"; then
PASS=$((PASS + 1))
printf 'OK %s\n' "$3"
else
FAIL=$((FAIL + 1))
printf 'GAGAL %s: pola tidak ditemukan di %s\n' "$3" "$2"
fi
}
bersihkan() {
if [ -n "$SERVER" ]; then
kill "$SERVER" 2> /dev/null
fi
if [ -n "$WORK" ]; then
rm -rf "$WORK"
fi
}
trap bersihkan EXIT
# --- siapkan folder kerja terisolasi ------------------------------------
WORK=$(mktemp -d)
cp "$CONFIG/latihan.nft" "$CONFIG/kebijakan-port.txt" \
"$CONFIG/audit-baseline.sh" "$CONFIG/validasi-ruleset.sh" \
"$CONFIG/verifikasi-keamanan.sh" "$WORK/"
cd "$WORK" || exit 1
# --- uji 1: audit menghasilkan laporan deterministik dari fixture --------
mkdir -p audit-data/home/budi/.ssh audit-data/home/siti/.ssh \
audit-data/home/deploy audit-data/root
cat > audit-data/services.txt <<'EOF'
nginx.service loaded active running A high performance web server and reverse proxy
postgresql.service loaded active running PostgreSQL RDBMS
redis-server.service loaded active running Advanced key-value store
ssh.service loaded active running OpenBSD Secure Shell server
EOF
cat > audit-data/port-terbuka.txt <<'EOF'
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
LISTEN 0 511 0.0.0.0:80 0.0.0.0:*
LISTEN 0 511 0.0.0.0:443 0.0.0.0:*
LISTEN 0 511 0.0.0.0:8080 0.0.0.0:*
LISTEN 0 24 127.0.0.1:5432 0.0.0.0:*
LISTEN 0 511 127.0.0.1:6379 0.0.0.0:*
EOF
cat > audit-data/passwd <<'EOF'
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
budi:x:1000:1000:Budi Santoso:/home/budi:/bin/bash
siti:x:1001:1001:Siti Rahma:/home/siti:/bin/bash
deploy:x:1002:1002:Deploy Bot:/home/deploy:/bin/bash
EOF
printf 'ssh-ed25519 AAAAC3NzaC1lZDI1...kunci-budi budi@laptop-budi\n' \
> audit-data/home/budi/.ssh/authorized_keys
printf 'ssh-ed25519 AAAAC3NzaC1lZDI1...kunci-siti-1 siti@laptop-siti\nssh-ed25519 AAAAC3NzaC1lZDI1...kunci-siti-2 siti@telepon-siti\n' \
> audit-data/home/siti/.ssh/authorized_keys
cat > audit-data/upgradable.txt <<'EOF'
Listing... Done
libssl3/stable 3.0.15-1~deb12u1 [upgradable from: 3.0.16-1~deb12u1]
openssl/stable 3.0.15-1~deb12u1 [upgradable from: 3.0.16-1~deb12u1]
redis-server/stable 5:7.0.15-1~deb12u1 [upgradable from: 5:7.0.16-1~deb12u1]
EOF
bash audit-baseline.sh audit-data > laporan-audit.txt
assert_eq 0 "$?" "audit menghasilkan laporan (exit 0)"
assert_ada '[1] SERVICE BERJALAN: 4' laporan-audit.txt \
"laporan memuat 4 service berjalan"
assert_ada '[2] PORT TCP TERBUKA: 6' laporan-audit.txt \
"laporan memuat 6 port terbuka"
assert_ada '0.0.0.0:8080 semua interface' laporan-audit.txt \
"port 8080 tercatat terbuka ke luar"
assert_ada '2 akun shell tanpa authorized_keys' laporan-audit.txt \
"temuan akun shell tanpa kunci"
assert_ada '3 paket tertinggal pembaruan' laporan-audit.txt \
"temuan paket tertinggal"
bash audit-baseline.sh > /dev/null 2>&1
assert_eq 1 "$?" "audit tanpa argumen keluar 1"
# --- uji 2: ruleset valid lolos validator --------------------------------
bash validasi-ruleset.sh latihan.nft > hasil-validasi.txt
assert_eq 0 "$?" "ruleset latihan.nft lolos validasi"
jumlah=$(grep -c '^OK' hasil-validasi.txt)
assert_eq 10 "$jumlah" "sepuluh pemeriksaan validasi semuanya OK"
# --- uji 3: ruleset rusak ditolak validator -------------------------------
cat > rusak.nft <<'EOF'
# rusak.nft — ruleset longgar: semua koneksi diterima.
table inet filter {
chain input {
type filter hook input priority filter; policy accept;
accept
}
}
EOF
bash validasi-ruleset.sh rusak.nft > hasil-rusak.txt
assert_eq 9 "$?" "ruleset rusak ditolak (9 pemeriksaan gagal)"
assert_ada 'GAGAL kebijakan chain input: drop' hasil-rusak.txt \
"policy yang salah dilaporkan"
assert_ada 'GAGAL tidak ada aturan accept tanpa syarat' hasil-rusak.txt \
"accept tanpa syarat dilaporkan"
bash validasi-ruleset.sh tidak-ada.nft > /dev/null 2>&1
assert_eq 1 "$?" "berkas ruleset hilang keluar 1"
# --- uji 4: verifikasi PASS pada port sesuai kebijakan --------------------
printf 'server latihan firewall\n' > index.html
python3 -m http.server 8765 --bind 127.0.0.1 > /dev/null 2>&1 &
SERVER=$!
siap=0
for i in 1 2 3 4 5 6 7 8 9 10; do
if curl -fsS -o /dev/null http://127.0.0.1:8765/ 2> /dev/null; then
siap=1
break
fi
sleep 0.2
done
assert_eq 1 "$siap" "server latihan siap di port 8765"
bash verifikasi-keamanan.sh latihan.nft kebijakan-port.txt \
http://127.0.0.1:8765/ > hasil-verifikasi.txt
assert_eq 0 "$?" "verifikasi PASS keluar 0"
assert_ada 'HASIL: PASS' hasil-verifikasi.txt "laporan berakhir PASS"
assert_ada 'port ruleset sama dengan kebijakan' hasil-verifikasi.txt \
"port ditandai sesuai kebijakan"
assert_ada 'menjawab (kode 200)' hasil-verifikasi.txt \
"service ditandai merespons"
# --- uji 5: kebijakan berbeda -> port melenceng ----------------------------
grep -v '^443' kebijakan-port.txt > kebijakan-tanpa-443.txt
bash verifikasi-keamanan.sh latihan.nft kebijakan-tanpa-443.txt \
http://127.0.0.1:8765/ > hasil-beda.txt
assert_eq 1 "$?" "kebijakan beda keluar 1"
assert_ada 'port ruleset berbeda dengan kebijakan' hasil-beda.txt \
"perbedaan port dilaporkan"
# --- uji 6: ruleset rusak di tangan verifikasi -----------------------------
bash verifikasi-keamanan.sh rusak.nft kebijakan-port.txt \
http://127.0.0.1:8765/ > hasil-verif-rusak.txt
assert_eq 2 "$?" "ruleset rusak + port melenceng keluar 2"
assert_ada 'ditolak validasi-ruleset.sh' hasil-verif-rusak.txt \
"kegagalan validator dilaporkan"
# --- uji 7: service mati -> FAIL, port kembali bebas -------------------------
kill "$SERVER" 2> /dev/null
wait "$SERVER" 2> /dev/null
SERVER=""
bash verifikasi-keamanan.sh latihan.nft kebijakan-port.txt \
http://127.0.0.1:8765/ > hasil-mati.txt
assert_eq 1 "$?" "service mati keluar 1"
assert_ada 'tidak menjawab' hasil-mati.txt "service mati dilaporkan"
jumlah=$(ss -tlnH '( sport = :8765 )' | grep -c .)
assert_eq 0 "$jumlah" "port 8765 kembali bebas setelah server mati"
# --- uji 8: pemakaian salah --------------------------------------------------
bash verifikasi-keamanan.sh latihan.nft > /dev/null 2>&1
assert_eq 4 "$?" "argumen kurang keluar 4"
bash verifikasi-keamanan.sh tidak-ada.nft kebijakan-port.txt \
http://127.0.0.1:8765/ > /dev/null 2>&1
assert_eq 4 "$?" "berkas hilang keluar 4"
# --- ringkasan ----------------------------------------------------------------
if [ "$FAIL" -eq 0 ]; then
printf 'PASSED: %d/%d test lulus\n' "$PASS" "$PASS"
else
printf 'FAILED: %d/%d test lulus\n' "$PASS" "$((PASS + FAIL))"
fi
[ "$FAIL" -eq 0 ]