Linux : Praktikum Hardening SSH dan Audit Konfigurasi: Difference between revisions

m Protected "Linux : Praktikum Hardening SSH dan Audit Konfigurasi": Proteksi editorial: edit/move sysop ([Edit=Allow only administrators] (indefinite) [Move=Allow only administrators] (indefinite))
Revisi: sudut audit server warisan + tautan artikel konsep pasangan (Page 761)
 
Line 1: Line 1:
'''SSH hardening''' sering diajarkan sebagai daftar baris sakti: matikan password, matikan root, ganti port. Di server nyata, daftar itu sering gagal bukan karena salah tulis, tetapi karena berkas yang kamu edit bukan berkas yang dibaca <code>sshd</code>.
Lima lapis hardening SSH sudah dipasang. Port diganti, password dimatikan, Fail2ban berjalan, dan log tampak tenang. Lalu datang pertanyaan yang jarang ditanyakan: '''kapan terakhir kali kamu membuktikan lapis mana yang benar-benar aktif?'''


Artikel ini adalah lab pendamping: kamu akan membangun baseline hardening di '''instance sshd kedua''' yang tidak menyentuh layanan produksi, lalu mematahkannya satu per satu. Tujuannya bukan menghafal opsi, tetapi bisa menunjuk bukti: setting mana yang benar-benar aktif, untuk user mana, dan dari mana asalnya.
Artikel ini adalah lab '''audit''', bukan lab pemasangan. Artikel konsep [[Linux : SSH Hardening Lanjutan (Lima Lapis Kunci Akses)]] membangun lima lapis dari nol. Di sini arahnya dibalik: kamu menerima server warisan yang katanya "sudah aman", lalu membuat '''lembar temuan''' yang setiap barisnya punya bukti perintah.


== 🎯 Tujuan ==
== 🎯 Tujuan ==
Setelah mengikuti lab ini, kamu bisa:
Setelah mengikuti lab ini, kamu bisa:


* Menjelaskan '''lima lapis keputusan akses SSH''' dan berhenti di lapis pertama yang gagal.
* Mengaudit konfigurasi SSH yang sudah berjalan tanpa mengubah apa pun lebih dulu.
* Membaca konfigurasi efektif <code>sshd</code> lewat <code>sshd -T</code>, bukan menebak dari isi berkas.
* Menunjuk '''lapis mana yang menolak''' sebuah login, bukan menebak.
* Membuktikan bahwa urutan <code>Include</code> membuat nilai dari <code>sshd_config.d/</code> menang atas berkas utama.
* Membaca konfigurasi efektif per user dengan <code>sshd -T -C</code>.
* Menguji <code>Match</code> untuk dua user berbeda pada satu berkas konfigurasi.
* Menemukan dua jebakan paling sering: '''urutan Include''' dan '''Match yang bertentangan'''.
* Menegakkan kunci-saja, larangan root, <code>AllowUsers</code>, dan izin berkas yang benar.
* Menyusun lembar temuan berisi temuan, bukti, risiko, dan tindakan.
* Menjelaskan kenapa <code>sshd -t</code> wajib dijalankan sebelum reload atau restart.
* Memperbaiki temuan tanpa mengunci diri sendiri di luar server.


== 📍 Konteks nyata ==
== 📍 Konteks nyata ==
Bayangkan pos jaga sekolah. Ada gerbang (jaringan), daftar nama yang boleh masuk (identitas), kartu atau sidik jari (metode), kunci ruang tertentu (kewenangan), dan buku tamu (jejak).
Bayangkan kamu menerima kunci gedung lab dari admin sebelumnya. Ia bilang: "pintunya sudah diganti nomornya, satpam sudah dipasang, aman."


Kalau gerbangnya terbuka tetapi daftar nama tidak pernah dibaca, penjaga tetap meloloskan siapa pun. Itulah yang terjadi saat kamu menulis <code>PasswordAuthentication no</code> di berkas utama, sementara berkas lain di folder <code>sshd_config.d/</code> menulis <code>yes</code> dan dibaca lebih dulu.
Tugasmu bukan mempercayai kalimat itu, tetapi berkeliling: mencoba pintu, membaca daftar tamu, mengecek ruang mana yang terbuka, dan menanyakan di mana bukunya. Audit bekerja persis begitu — '''kecurigaan bukan bukti, dan ingatan bukan catatan'''.


* 💡 '''Tips:''' pegangan pertama hardening SSH: '''berkas yang kamu tulis belum tentu berkas yang dibaca'''. Selalu tutup pekerjaan dengan <code>sshd -T</code> dan <code>-C</code>, bukan dengan perasaan "sudah saya matikan".
* 🔥 '''Kasus nyata:''' sebuah SMK memindahkan SSH ke port 2222 dan memasang Fail2ban. Di berkas <code>/etc/ssh/sshd_config</code> tertulis <code>PasswordAuthentication no</code>, dan admin sudah memverifikasinya berkali-kali. Yang tidak dibaca: <code>/etc/ssh/sshd_config.d/50-cloud-init.conf</code> dari image server berisi <code>PasswordAuthentication yes</code>. Karena <code>Include</code> duduk di baris pertama, nilai itu dibaca lebih dulu dan menang. Tujuh bulan kemudian akun <code>operator</code> dengan sandi <code>operator123</code> dipakai bergantian empat orang, dan nilai dua kelas berubah pada suatu malam.
 
Perintah <code>sshd -T</code> adalah mode uji lanjutan: ia mencetak '''konfigurasi efektif''' setelah semua <code>Include</code> dan <code>Match</code> diterapkan. Tanpa alat itu, kamu hanya membaca niat, bukan kenyataan.


== 🧠 Konsep singkat ==
== 🧠 Konsep singkat ==
Akses SSH adalah keputusan berlapis, bukan satu saklar. Setiap lapis bisa menolak lebih dulu, dan lapis sesudahnya tidak akan pernah dievaluasi.
Audit SSH berarti memeriksa lima lapis yang sama seperti artikel konsep, tetapi dengan urutan terbalik: mulai dari bukti, bukan dari niat.


{| class="wikitable"
{| class="wikitable"
! Lapis !! Pertanyaan !! Alat bukti
! Lapis !! Pertanyaan audit !! Alat bukti
|-
|-
| 1. Jaringan || Apakah paket sampai ke port yang benar? || <code>ss -tlnp</code>, aturan firewall
| 1. Identitas || Sandi masih diterima? || <code>passwordauthentication</code> efektif
|-
|-
| 2. Identitas || Apakah akun ini boleh login dari sini? || <code>AllowUsers</code>, <code>DenyUsers</code>
| 2. Keanggotaan || Siapa yang dibatasi? || <code>allowusers</code>, <code>allowgroups</code>
|-
|-
| 3. Metode || Dengan apa identitas dibuktikan? || <code>PubkeyAuthentication</code>, <code>PasswordAuthentication</code>
| 3. Kewenangan || Boleh apa setelah masuk? || <code>permitrootlogin</code>, <code>disableforwarding</code>
|-
|-
| 4. Kewenangan || Setelah masuk, boleh melakukan apa? || <code>PermitRootLogin</code>, <code>sudo -l</code>
| 4. Batas || Berapa lama dan berapa kali? || <code>maxauthtries</code>, <code>logingracetime</code>
|-
|-
| 5. Jejak || Apa yang tercatat setelah semuanya? || <code>journalctl -u ssh</code>, <code>lastb</code>
| 5. Bukti || Apa yang tercatat? || <code>loglevel</code>, <code>auth.log</code>
|}
|}


Aturan kerjanya sederhana: '''berhenti di lapis pertama yang gagal'''. Kalau <code>Connection refused</code>, jangan mengutak-atik <code>AllowUsers</code>. Kalau kunci ditolak padahal akun benar, jangan menyalakan password sebagai "solusi".
Aturan kerjanya: '''berhenti di lapis pertama yang gagal'''. Kalau login ditolak karena <code>AllowUsers</code>, jangan menyimpulkan "kuncinya salah" lalu membuat kunci baru.
 
=== 🔹 Tiga perintah yang mirip, artinya beda ===
* <code>sshd -t</code> — hanya memeriksa '''keabsahan''' berkas. Tidak mencetak apa pun kalau sehat. Ini rem darurat sebelum reload.
* <code>sshd -T</code> — mencetak '''konfigurasi efektif''' setelah semua <code>Include</code> diterapkan. Inilah kebenaran yang dipakai daemon.
* <code>sshd -T -C user=...,addr=...,host=...</code> — konfigurasi efektif '''untuk satu koneksi tertentu''', termasuk blok <code>Match</code>.
 
* 💡 '''Tips:''' jadikan <code>sshd -T</code> sebagai saksi utama. Selama audit, setiap temuan harus bisa dijawab dengan satu baris keluarannya.


=== 🔹 Nilai pertama yang menang ===
=== 🔹 Nilai pertama yang menang ===
<code>sshd_config(5)</code> menulis aturan yang mudah terlewat: untuk setiap kata kunci, '''nilai pertama yang ditemukan itulah yang dipakai'''.
<code>sshd_config(5)</code> menyatakan: untuk setiap kata kunci, '''nilai pertama yang ditemukan itulah yang dipakai'''. Paket Debian dan Ubuntu menaruh <code>Include /etc/ssh/sshd_config.d/*.conf</code> di '''baris paling atas''', sehingga drop-in dibaca lebih dulu dan menimpa berkas utama.


Artinya urutan berkas menentukan hasil. Paket Debian dan Ubuntu menaruh <code>Include /etc/ssh/sshd_config.d/*.conf</code> di '''baris paling atas''' berkas utama. Manpage-nya menyebut terang-terangan: opsi di folder itu akan '''menimpa''' opsi di <code>/etc/ssh/sshd_config</code>.
* ⚠️ '''Hati-hati:''' "sudah saya matikan di berkas utama" bukan bukti. Bukti adalah baris <code>passwordauthentication no</code> pada keluaran <code>sshd -T</code>.
 
* ⚠️ '''Hati-hati:''' kalau kamu menambahkan <code>PasswordAuthentication no</code> di bagian bawah berkas utama, tetapi ada <code>50-cloud-init.conf</code> berisi <code>PasswordAuthentication yes</code>, maka nilai <code>yes</code> yang menang. Berkasnya benar, hasilnya salah.


=== 🔹 Satu berkas, dua kebenaran ===
=== 🔹 Satu berkas, dua kebenaran ===
<code>Match</code> membuat blok bersyarat: jika kriteria terpenuhi, kata kunci di dalamnya '''menimpa''' bagian global. Ini fitur, bukan bug — tetapi berbahaya kalau kamu mengira satu setting berlaku untuk semua orang.
<code>Match</code> membuat blok bersyarat yang '''menimpa''' bagian global untuk user, group, atau alamat tertentu. Satu berkas konfigurasi bisa berarti dua hal berbeda untuk dua orang — dan hanya <code>-C</code> yang bisa memisahkannya.
 
Karena itu <code>sshd -T</code> punya pasangan: <code>-C</code> (connection spec). Dengan <code>-C user=...,addr=...,host=...</code>, kamu bisa bertanya "kalau user ini datang dari alamat ini, konfigurasi efektifnya apa?". Dua user, satu berkas, dua jawaban berbeda.
 
* 📊 '''Angka penting:''' bawaan OpenSSH yang sering jadi sumber kejutan: <code>MaxAuthTries 6</code>, <code>MaxStartups 10:30:100</code>, <code>LoginGraceTime 120</code>, <code>ClientAliveInterval 0</code>, <code>PermitRootLogin prohibit-password</code>, <code>PasswordAuthentication yes</code>, <code>StrictModes yes</code>.


== 🧩 Istilah penting ==
== 🧩 Istilah penting ==
* '''Konfigurasi efektif''' — hasil akhir setelah semua <code>Include</code> dan <code>Match</code> diterapkan, bukan isi mentah satu berkas.
* '''Konfigurasi efektif''' — hasil akhir setelah <code>Include</code> dan <code>Match</code> diterapkan; yang benar-benar dibaca <code>sshd</code>.
* '''Include''' — perintah menyisipkan berkas lain pada posisi baris itu; di Debian diletakkan di awal berkas.
* '''Drop-in''' — berkas di <code>sshd_config.d/</code>; nomor kecil dibaca lebih dulu, jadi lebih kuat.
* '''Drop-in''' — berkas kecil di <code>sshd_config.d/</code> untuk menambah atau menimpa pengaturan tanpa menyentuh berkas utama.
* '''Socket activation''' — mode di mana <code>systemd</code> yang memegang port lewat <code>ssh.socket</code>, bukan <code>sshd</code>.
* '''Match block''' — blok bersyarat berdasarkan <code>User</code>, <code>Group</code>, <code>Address</code>, <code>Host</code>, atau <code>LocalPort</code>.
* '''Match block''' — blok bersyarat berdasarkan <code>User</code>, <code>Group</code>, <code>Address</code>, <code>Host</code>, atau <code>LocalPort</code>.
* '''prohibit-password''' — nilai <code>PermitRootLogin</code> yang mematikan password untuk root, tetapi '''masih mengizinkan kunci'''. Ini bukan "root mati".
* '''prohibit-password''' — root tidak boleh memakai password, tetapi '''masih boleh memakai kunci'''.
* '''StrictModes''' — pemeriksaan izin dan pemilik berkas kunci sebelum login diterima.
* '''StrictModes''' — <code>sshd</code> memeriksa pemilik dan izin berkas kunci sebelum login diterima.
* '''MaxAuthTries''' — batas percobaan autentikasi per koneksi; kegagalan mulai dicatat setelah mencapai separuh nilai.
* '''MaxAuthTries''' — batas percobaan autentikasi per koneksi; kegagalan mulai dicatat setelah separuh nilai.
* '''MaxStartups''' — batas koneksi yang belum terautentikasi, ditulis <code>start:rate:full</code>.
* '''MaxStartups''' — batas koneksi yang belum terautentikasi, ditulis <code>start:rate:full</code>.
* '''AuthenticationMethods''' — daftar metode yang harus berhasil berurutan, misalnya kunci lalu password.
* '''DisableForwarding''' — mematikan semua penerusan port, tunnel, dan agent dalam satu saklar.
* '''authorized_keys''' — berkas kunci publik yang boleh masuk sebagai user tersebut.
* '''auth.log''' — berkas jejak autentikasi di Debian/Ubuntu, biasanya milik <code>syslog:adm</code>.
 
== 🔧 Praktik: audit server warisan tanpa mengunci diri ==
Semua pengujian dilakukan pada '''salinan''' konfigurasi di <code>/tmp/ssh-audit</code> dan instance kedua di port 2222. Layanan asli tidak disentuh sampai kamu yakin.
 
* ⚠️ '''Hati-hati:''' buka '''dua sesi''' sebelum mulai — satu untuk bekerja, satu dibiarkan terbuka sebagai jalan pulang. Audit yang mengunci diri sendiri bukan audit, itu insiden.


== 🔧 Praktik: baseline hardening di instance kedua ==
=== 🔹 Langkah 1 — potret dan simpan sebagai pembanding ===
Lab ini memakai '''instance sshd kedua di port 2222''' dengan berkas konfigurasi sendiri. Layanan SSH asli di port 22 tidak disentuh, jadi kamu tidak bisa terkunci di tengah jalan.
<syntaxhighlight lang="text">
sudo sshd -T | sort > /tmp/audit-awal.txt
sudo sshd -T | grep -Ei '^(port|permitrootlogin|passwordauthentication|pubkeyauthentication|kbdinteractive|allowusers|allowgroups|maxauthtries|logingracetime|loglevel|disableforwarding)'
ss -tlnp | grep -i ssh
systemctl is-enabled ssh ssh.socket 2>&1
</syntaxhighlight>
# Catat juga unit yang aktif. Di Ubuntu 24.04, <code>ssh.socket</code> bisa ikut aktif dan memegang port sendiri.


* ⚠️ '''Hati-hati:''' jangan pernah menguji "matikan password" langsung di server yang hanya bisa kamu akses lewat SSH. Selalu siapkan jalur kedua: konsol VM, snapshot, atau instance uji seperti di lab ini.
* 📊 '''Angka penting:''' saat <code>ssh.socket</code> aktif, <code>systemd</code> yang membuka port. Mengubah <code>Port</code> di <code>sshd_config</code> tidak memindahkan pintu, karena yang mendengarkan bukan <code>sshd</code>.


=== 🔹 Langkah 1 — potret dulu, jangan ubah apa pun ===
=== 🔹 Langkah 2 — petakan berkas yang benar-benar dibaca ===
# Siapkan satu user uji dan satu kunci di VM latihan Debian atau Ubuntu.
# Lihat urutan <code>Include</code> dan isi folder drop-in. Ini peta sumber konflik.
<syntaxhighlight lang="text">
<syntaxhighlight lang="text">
sudo useradd -m -s /bin/bash lab
sudo grep -n '^Include' /etc/ssh/sshd_config
sudo passwd lab
sudo ls -1 /etc/ssh/sshd_config.d/ 2>/dev/null
sudo -u lab mkdir -p /home/lab/.ssh
sudo grep -Hn -Ei 'password|permitrootlogin|allowusers|maxauthtries' /etc/ssh/sshd_config /etc/ssh/sshd_config.d/*.conf 2>/dev/null
sudo -u lab ssh-keygen -t ed25519 -f /home/lab/.ssh/id_lab -N ""
sudo -u lab cp /home/lab/.ssh/id_lab.pub /home/lab/.ssh/authorized_keys
sudo chmod 700 /home/lab/.ssh
sudo chmod 600 /home/lab/.ssh/authorized_keys
</syntaxhighlight>
</syntaxhighlight>
# Potret konfigurasi yang sedang berlaku, sebelum menyentuh apa pun.
# Bandingkan jumlah baris konfigurasi efektif dengan jumlah baris yang kamu baca. Selisihnya berasal dari bawaan dan drop-in.
<syntaxhighlight lang="text">
<syntaxhighlight lang="text">
sudo sshd -T | sort > /tmp/baseline-sshd.txt
sudo sshd -T | wc -l
sudo sshd -T | grep -Ei '^(port|permitrootlogin|passwordauthentication|pubkeyauthentication|maxauthtries|allowusers|usepam)'
</syntaxhighlight>
</syntaxhighlight>
# Catat hasilnya di lembar kerja. '''Tanpa baseline, kamu tidak punya pembanding''' untuk membuktikan perubahanmu bekerja.


* 🧪 '''Uji cepat:''' <code>sudo sshd -T | wc -l</code> memberi jumlah baris konfigurasi efektif. Kalau angkanya berubah setelah edit, ada sesuatu yang benar-benar terbaca — bukan sekadar tersimpan.
* 🧪 '''Uji cepat:''' <code>sudo sshd -T | grep -c .</code> memberi jumlah baris efektif. Kalau kamu baru mengubah satu baris tetapi angka ini tidak berubah, perubahanmu tidak terbaca.


=== 🔹 Langkah 2 — bangun instance kedua di port 2222 ===
=== 🔹 Langkah 3 — lapis 1: apakah sandi masih diterima ===
# Buat salinan konfigurasi terpisah supaya produksi aman.
<syntaxhighlight lang="text">
<syntaxhighlight lang="text">
sudo mkdir -p /tmp/ssh-lab/sshd_config.d
sudo sshd -T | grep -Ei '^(passwordauthentication|kbdinteractiveauthentication|pubkeyauthentication|permitemptypasswords)'
sudo mkdir -p /run/sshd
</syntaxhighlight>
</syntaxhighlight>
# Tulis konfigurasi lab yang mandiri. Perhatikan <code>Include</code> di baris pertama — ini meniru perilaku paket Debian.
# Cari akun yang masih punya sandi aktif. Ini daftar calon pintu masuk kalau lapis 1 jebol.
<syntaxhighlight lang="text">
<syntaxhighlight lang="text">
sudo tee /tmp/ssh-lab/sshd_config > /dev/null <<'EOF'
sudo passwd -S -a | awk '$2=="P" {print $1, $2}'
Include /tmp/ssh-lab/sshd_config.d/*.conf
Port 2222
PidFile /tmp/ssh-lab/sshd.pid
HostKey /etc/ssh/ssh_host_ed25519_key
LogLevel VERBOSE
PasswordAuthentication yes
PubkeyAuthentication yes
PermitRootLogin prohibit-password
UsePAM yes
EOF
</syntaxhighlight>
</syntaxhighlight>
# Validasi, lalu jalankan instance lab di latar belakang dengan berkas log sendiri.
# Inventaris kunci yang tertanam: siapa pun yang punya baris di sini bisa masuk tanpa sandi.
<syntaxhighlight lang="text">
<syntaxhighlight lang="text">
sudo sshd -t -f /tmp/ssh-lab/sshd_config
sudo find /home /root -maxdepth 3 -name authorized_keys -printf '%p %TY-%Tm-%Td\n' 2>/dev/null
sudo /usr/sbin/sshd -f /tmp/ssh-lab/sshd_config -E /tmp/ssh-lab/sshd.log
ss -tlnp | grep 2222
</syntaxhighlight>
</syntaxhighlight>
# Uji dua jalur login sebagai pembanding. Keduanya harus berhasil sebelum kamu mematahkan apa pun.
# Hasil yang diharapkan: tiga daftar yang bisa kamu tunjuk — status sandi, nilai efektif, dan kunci yang ada.
 
=== 🔹 Langkah 4 — lapis 2: siapa yang dibatasi ===
<syntaxhighlight lang="text">
<syntaxhighlight lang="text">
ssh -p 2222 -i /home/lab/.ssh/id_lab lab@127.0.0.1 'echo masuk-dengan-kunci'
sudo sshd -T | grep -Ei '^(allowusers|allowgroups|denyusers|denygroups)' || echo "KOSONG: semua akun boleh masuk"
ssh -p 2222 lab@127.0.0.1 'echo masuk-dengan-password'
</syntaxhighlight>
</syntaxhighlight>
# Keluaran kosong adalah temuan, bukan hasil netral. Artinya tidak ada daftar tamu sama sekali.
<syntaxhighlight lang="text">
sudo sshd -T -C user=nobody,addr=192.168.100.10,host=admin-pc | grep -Ei '^(allowusers|allowgroups|passwordauthentication)'
</syntaxhighlight>
# Hasil yang diharapkan: nilai yang sama persis untuk user yang tidak berhak — bukti bahwa lapis 2 belum bekerja.


=== 🔹 Langkah 3 — buktikan lapis metode (kunci saja) ===
=== 🔹 Langkah 5 — lapis 3: kewenangan setelah masuk ===
# Ubah satu baris di konfigurasi lab, lalu reload instance lab saja, bukan layanan sistem.
<syntaxhighlight lang="text">
<syntaxhighlight lang="text">
sudo sed -i 's/^PasswordAuthentication yes/PasswordAuthentication no/' /tmp/ssh-lab/sshd_config
sudo sshd -T | grep -Ei '^(permitrootlogin|disableforwarding|x11forwarding|allowtcpforwarding|permittunnel|allowagentforwarding)'
sudo sshd -t -f /tmp/ssh-lab/sshd_config
sudo kill -HUP $(sudo cat /tmp/ssh-lab/sshd.pid)
sudo sshd -T -f /tmp/ssh-lab/sshd_config | grep -i passwordauth
</syntaxhighlight>
</syntaxhighlight>
# Minta klien memaksa jalur password. Jawaban yang benar adalah penolakan yang menyebut metode yang tersisa.
# Periksa pengecualian per user. Inilah tempat <code>Match</code> biasanya menyimpan kejutan.
<syntaxhighlight lang="text">
<syntaxhighlight lang="text">
ssh -p 2222 -o PubkeyAuthentication=no lab@127.0.0.1
sudo sshd -T -C user=guru1,addr=192.168.100.20,host=laptop-guru | grep -Ei '^(forcecommand|chrootdirectory|permittty|allowtcpforwarding|disableforwarding)'
</syntaxhighlight>
# Uji nyata: coba buka tunnel ke port lokal. Kalau <code>DisableForwarding yes</code> bekerja, permintaan ditolak.
<syntaxhighlight lang="text">
ssh -p 2222 -N -L 8080:127.0.0.1:80 lab@127.0.0.1
# channel 2: open failed: administratively prohibited: open failed
</syntaxhighlight>
</syntaxhighlight>
# Hasil yang diharapkan: <code>Permission denied (publickey).</code> Perhatikan daftar metodenya — hanya <code>publickey</code>, tanda password benar-benar tidak ditawarkan lagi.


=== 🔹 Langkah 4 — buktikan lapis identitas (root dan AllowUsers) ===
* 💡 '''Tips:''' pesan <code>administratively prohibited</code> adalah bukti lapis 3 yang bekerja. Kalau tunnel justru terbuka, temuanmu berbunyi "kewenangan terlalu luas" — bukan "jaringan bermasalah".
# Matikan root, lalu batasi user yang boleh masuk.
 
=== 🔹 Langkah 6 — lapis 4: batas percobaan dan waktu ===
<syntaxhighlight lang="text">
<syntaxhighlight lang="text">
sudo tee /tmp/ssh-lab/sshd_config.d/10-identitas.conf > /dev/null <<'EOF'
sudo sshd -T | grep -Ei '^(maxauthtries|logingracetime|maxstartups|clientaliveinterval)'
PermitRootLogin no
sudo command -v fail2ban-client && sudo fail2ban-client status sshd
AllowUsers lab@127.0.0.1
</syntaxhighlight>
EOF
# Baca angkanya, bukan status layanannya. Fail2ban yang aktif tetap tidak menolong kalau <code>MaxAuthTries</code> dibiarkan besar dan sandi masih diterima.
sudo sshd -t -f /tmp/ssh-lab/sshd_config
 
sudo kill -HUP $(sudo cat /tmp/ssh-lab/sshd.pid)
* 📊 '''Angka penting:''' bawaan <code>MaxAuthTries 6</code>, <code>LoginGraceTime 120</code> detik, <code>MaxStartups 10:30:100</code>, <code>ClientAliveInterval 0</code>. Kegagalan autentikasi mulai dicatat setelah mencapai separuh <code>MaxAuthTries</code>.
sudo sshd -T -f /tmp/ssh-lab/sshd_config | grep -Ei '^(permitrootlogin|allowusers)'
 
=== 🔹 Langkah 7 — lapis 5: bukti yang tersedia ===
<syntaxhighlight lang="text">
sudo sshd -T | grep -i '^loglevel'
ls -l /var/log/auth.log 2>/dev/null
sudo journalctl --disk-usage
sudo lastb -n 5
</syntaxhighlight>
# Hitung bukti yang benar-benar ada, bukan yang seharusnya ada.
<syntaxhighlight lang="text">
sudo grep -c 'Accepted publickey' /var/log/auth.log
sudo grep -c 'Failed password' /var/log/auth.log
</syntaxhighlight>
</syntaxhighlight>
# Bandingkan arti tiga nilai <code>PermitRootLogin</code> berikut. Ini sumber salah paham paling sering.
# Hasil yang diharapkan: dua angka. Kalau keduanya nol padahal server menghadap internet, curigai <code>LogLevel</code> atau lokasi log, bukan "tidak ada serangan".
 
=== 🔹 Langkah 8 — susun lembar temuan ===
Inilah keluaran utama audit. Setiap baris harus bisa dipertahankan dengan perintah, bukan pendapat.
 
{| class="wikitable"
{| class="wikitable"
! Nilai !! Password root !! Kunci root
! Temuan !! Bukti !! Risiko !! Tindakan
|-
| Sandi masih diterima || <code>passwordauthentication yes</code> || tebakan sandi berhasil || matikan, sisakan kunci
|-
| Tanpa daftar tamu || <code>allowusers</code> kosong || akun lama ikut masuk || <code>AllowGroups</code>
|-
| Root boleh dengan kunci || <code>permitrootlogin without-password</code> || kunci lama tak tercabut || <code>no</code> + akun sudo
|-
|-
| yes || boleh || boleh
| Forwarding terbuka || <code>allowtcpforwarding yes</code> || server jadi jalan pintas || <code>DisableForwarding yes</code>
|-
|-
| prohibit-password || ditolak || boleh
| <code>Port</code> tidak berlaku || <code>ssh.socket</code> aktif || perubahan port sia-sia || ubah di unit socket
|-
|-
| no || ditolak || ditolak
| Log minim || <code>loglevel INFO</code> || sidik jari kunci tak tercatat || <code>LogLevel VERBOSE</code>
|}
|}
# Uji dari akun lain: user yang tidak ada di <code>AllowUsers</code> harus ditolak walau kuncinya sah.
# Beri urutan prioritas: lapis 1 dan 2 dulu, karena keduanya menentukan siapa yang boleh masuk.
<syntaxhighlight lang="text">
sudo useradd -m -s /bin/bash tamu
sudo -u tamu mkdir -p /home/tamu/.ssh
sudo -u tamu ssh-keygen -t ed25519 -f /home/tamu/.ssh/id_tamu -N ""
sudo -u tamu cp /home/tamu/.ssh/id_tamu.pub /home/tamu/.ssh/authorized_keys
sudo chmod 700 /home/tamu/.ssh
sudo chmod 600 /home/tamu/.ssh/authorized_keys
ssh -p 2222 -i /home/tamu/.ssh/id_tamu tamu@127.0.0.1
</syntaxhighlight>
# Hasil yang diharapkan: <code>Permission denied (publickey).</code> Di log server muncul <code>User tamu not allowed because not listed in AllowUsers</code> — bukti lapis 2 yang menolak, bukan lapis 3.


* 💡 '''Tips:''' pola <code>USER@HOST</code> di <code>AllowUsers</code> menerima alamat dalam bentuk CIDR, misalnya <code>lab@192.168.100.0/24</code>. Ini cara murah membatasi akses hanya dari LAN lab tanpa menyentuh firewall.
=== 🔹 Langkah 9 — dua jebakan yang membatalkan temuanmu ===
 
# '''Jebakan urutan Include.''' Buat salinan konfigurasi di <code>/tmp</code> agar produksi aman, lalu buat dua berkas yang bertentangan.
=== 🔹 Langkah 5 — jebakan urutan Include ===
Ini uji paling penting di artikel ini. Kamu akan membuat dua berkas yang saling bertentangan, lalu melihat siapa yang menang.
 
# Tulis <code>no</code> di berkas utama, lalu <code>yes</code> di drop-in. Urutan <code>Include</code> menentukan pemenangnya.
<syntaxhighlight lang="text">
<syntaxhighlight lang="text">
sudo tee /tmp/ssh-lab/sshd_config.d/90-warisan.conf > /dev/null <<'EOF'
sudo mkdir -p /tmp/ssh-audit/sshd_config.d
sudo tee /tmp/ssh-audit/sshd_config > /dev/null <<'EOF'
Include /tmp/ssh-audit/sshd_config.d/*.conf
Port 2222
PidFile /tmp/ssh-audit/sshd.pid
HostKey /etc/ssh/ssh_host_ed25519_key
PasswordAuthentication no
EOF
sudo tee /tmp/ssh-audit/sshd_config.d/99-warisan.conf > /dev/null <<'EOF'
PasswordAuthentication yes
PasswordAuthentication yes
EOF
EOF
sudo sshd -T -f /tmp/ssh-lab/sshd_config | grep -i passwordauth
sudo sshd -T -f /tmp/ssh-audit/sshd_config | grep -i passwordauth
</syntaxhighlight>
# Hasil yang diharapkan: <code>passwordauthentication yes</code>. Padahal berkas utama jelas menulis <code>no</code>. Penyebabnya bukan salah tulis, tetapi '''urutan baca'''.
 
* 🔥 '''Kasus nyata:''' sebuah SMK mematikan login password di <code>/etc/ssh/sshd_config</code> untuk server CBT. Image cloud yang dipakai menyisakan <code>50-cloud-init.conf</code> berisi <code>PasswordAuthentication yes</code>, dan berkas itu dibaca lebih dulu. Selama tujuh bulan password tetap berlaku; akun <code>operator</code> dengan sandi <code>operator123</code> dipakai bergantian oleh empat orang. Nilai dua kelas berubah suatu malam, dan admin sempat menyalahkan siswa karena di berkas yang ia buka, password sudah mati.
 
# Bersihkan drop-in palsu itu, lalu pastikan nilai kembali <code>no</code>.
<syntaxhighlight lang="text">
sudo rm /tmp/ssh-lab/sshd_config.d/90-warisan.conf
sudo sshd -T -f /tmp/ssh-lab/sshd_config | grep -i passwordauth
</syntaxhighlight>
</syntaxhighlight>
 
# Hasil yang diharapkan: <code>passwordauthentication yes</code>. Berkas utama menulis <code>no</code>, tetapi drop-in dibaca lebih dulu. Inilah bentuk persis kegagalan yang tidak terlihat saat membaca berkas utama.
=== 🔹 Langkah 6 — dua kebenaran dari Match ===
# '''Jebakan Match.''' Tambahkan pengecualian untuk satu user, lalu tanyakan dua kali dengan user berbeda.
# Sekarang buat pengecualian yang sah: password hanya untuk user <code>lab</code>, sisanya kunci saja.
<syntaxhighlight lang="text">
<syntaxhighlight lang="text">
sudo tee /tmp/ssh-lab/sshd_config.d/20-pengecualian.conf > /dev/null <<'EOF'
sudo tee /tmp/ssh-audit/sshd_config.d/20-pengecualian.conf > /dev/null <<'EOF'
PasswordAuthentication no
Match User lab
Match User lab
     PasswordAuthentication yes
     PasswordAuthentication yes
    AllowTcpForwarding yes
EOF
EOF
sudo sshd -t -f /tmp/ssh-lab/sshd_config
sudo sshd -T -f /tmp/ssh-audit/sshd_config -C user=lab,addr=192.168.100.30,host=pc-lab | grep -Ei 'passwordauth|allowtcpforwarding'
sudo sshd -T -f /tmp/ssh-audit/sshd_config -C user=tamu,addr=192.168.100.30,host=pc-lab | grep -Ei 'passwordauth|allowtcpforwarding'
</syntaxhighlight>
</syntaxhighlight>
# Tanyakan konfigurasi efektif untuk dua user berbeda. Perhatikan nilai yang berbeda untuk kunci yang sama.
# Hasil yang diharapkan: dua jawaban berbeda untuk berkas yang sama. Audit tanpa <code>-C</code> akan melaporkan satu kebenaran saja.
# '''Konfigurasi rusak.''' Buktikan bahwa rem darurat bekerja sebelum menyentuh layanan asli.
<syntaxhighlight lang="text">
<syntaxhighlight lang="text">
sudo sshd -T -f /tmp/ssh-lab/sshd_config -C user=lab,addr=127.0.0.1,host=laptop | grep -i passwordauth
sudo sh -c 'echo PasswordAuthenticaion no >> /tmp/ssh-audit/sshd_config'
sudo sshd -T -f /tmp/ssh-lab/sshd_config -C user=tamu,addr=127.0.0.1,host=laptop | grep -i passwordauth
sudo sshd -t -f /tmp/ssh-audit/sshd_config; echo "kode keluar: $?"
</syntaxhighlight>
</syntaxhighlight>
# Hasil yang diharapkan: <code>yes</code> untuk <code>lab</code>, <code>no</code> untuk <code>tamu</code>. Satu berkas, dua kebenaran — dan kamu bisa menunjuk buktinya.
# Hasil yang diharapkan: <code>Bad configuration option: passwordauthenticaion</code> dan kode keluar bukan nol.


* ⚠️ '''Hati-hati:''' <code>Match</code> tidak bisa membatalkan keputusan lapis sebelumnya. Kalau user sudah ditolak <code>AllowUsers</code>, pengecualian password tidak akan pernah dievaluasi.
=== 🔹 Langkah 10 — perbaiki, lalu audit ulang ===
 
# Perbaikan ditaruh di drop-in bernomor kecil supaya menang atas berkas bawaan. Nama berkas adalah bagian dari strategi, bukan hiasan.
=== 🔹 Langkah 7 — izin berkas dan StrictModes ===
# Rusak izin direktori home dengan sengaja, lalu coba masuk dengan kunci.
<syntaxhighlight lang="text">
<syntaxhighlight lang="text">
sudo chmod 777 /home/lab
sudo tee /etc/ssh/sshd_config.d/10-hardening.conf > /dev/null <<'EOF'
ssh -p 2222 -i /home/lab/.ssh/id_lab lab@127.0.0.1
PubkeyAuthentication yes
</syntaxhighlight>
PasswordAuthentication no
# Hasil yang diharapkan: penolakan, dan di log server muncul pesan semacam <code>Authentication refused: bad ownership or modes for directory /home/lab</code>.
KbdInteractiveAuthentication no
 
PermitEmptyPasswords no
* 📊 '''Angka penting:''' <code>StrictModes</code> bawaannya <code>yes</code>. Artinya <code>sshd</code> memeriksa pemilik dan izin direktori home serta <code>authorized_keys</code>. Direktori home yang bisa ditulis semua orang dianggap sebagai risiko pembajakan kunci.
PermitRootLogin no
 
AllowGroups ssh-users
# Kembalikan izin yang benar, lalu ulangi. Login harus berhasil lagi tanpa mengubah konfigurasi apa pun.
MaxAuthTries 3
<syntaxhighlight lang="text">
LoginGraceTime 30
sudo chown lab:lab /home/lab
LogLevel VERBOSE
sudo chmod 750 /home/lab
sudo chmod 700 /home/lab/.ssh
sudo chmod 600 /home/lab/.ssh/authorized_keys
ssh -p 2222 -i /home/lab/.ssh/id_lab lab@127.0.0.1 'echo izin-beres'
</syntaxhighlight>
 
=== 🔹 Langkah 8 — batas percobaan dan jejak log ===
# Turunkan <code>MaxAuthTries</code> ke 2, reload instance lab, lalu paksa klien menawarkan beberapa kunci.
<syntaxhighlight lang="text">
sudo tee /tmp/ssh-lab/sshd_config.d/30-batas.conf > /dev/null <<'EOF'
MaxAuthTries 2
EOF
EOF
sudo sshd -t -f /tmp/ssh-lab/sshd_config
sudo sshd -t && echo "konfigurasi sah"
sudo kill -HUP $(sudo cat /tmp/ssh-lab/sshd.pid)
ssh -p 2222 -o IdentitiesOnly=no -i /home/lab/.ssh/id_lab lab@127.0.0.1
</syntaxhighlight>
</syntaxhighlight>
# Perhatikan log server. Dengan <code>LogLevel VERBOSE</code>, <code>sshd</code> mencatat sidik jari kunci dan percobaan yang gagal.
# Reload, lalu bandingkan potret lama dengan yang baru. Perbedaan itulah bukti pekerjaanmu.
<syntaxhighlight lang="text">
<syntaxhighlight lang="text">
sudo tail -n 20 /tmp/ssh-lab/sshd.log
sudo systemctl reload ssh
sudo grep -c 'Failed password' /tmp/ssh-lab/sshd.log
sudo sshd -T | sort > /tmp/audit-akhir.txt
diff /tmp/audit-awal.txt /tmp/audit-akhir.txt
</syntaxhighlight>
</syntaxhighlight>
# Hasil yang diharapkan: baris <code>Accepted publickey for lab</code> lengkap dengan sidik jari <code>SHA256:...</code>, dan hitungan percobaan gagal yang bisa kamu tunjuk angkanya.
# Verifikasi hasil akhir dengan pertanyaan yang sama seperti awal audit: sandi, daftar tamu, kewenangan, batas, bukti.
 
* 🧪 '''Uji cepat:''' <code>sudo journalctl -u ssh -n 30 --no-pager</code> membaca jejak layanan asli. Untuk percobaan gagal dari jaringan, <code>sudo lastb -n 10</code> memberi daftar singkat.
 
=== 🔹 Langkah 9 — validasi sebelum reload ===
# Rusak satu kata kunci dengan sengaja, lalu lihat siapa yang menangkap kesalahan itu.
<syntaxhighlight lang="text">
<syntaxhighlight lang="text">
sudo sh -c 'echo PasswordAuthenticaion no >> /tmp/ssh-lab/sshd_config'
sudo sshd -T | grep -Ei '^(passwordauthentication|permitrootlogin|allowgroups|maxauthtries|loglevel)'
sudo sshd -t -f /tmp/ssh-lab/sshd_config; echo "kode keluar: $?"
sudo sshd -T -C user=tamu,addr=192.168.100.10,host=admin-pc | grep -Ei '^(allowgroups|passwordauthentication)'
</syntaxhighlight>
</syntaxhighlight>
# Hasil yang diharapkan: <code>Bad configuration option: passwordauthenticaion</code> dan kode keluar bukan nol. '''Inilah rem darurat''' yang mencegah server mati karena salah ketik.
# Bersih-bersih bahan audit.
# Buktikan akibatnya kalau rem itu dilewati: hentikan instance lab, jalankan ulang dengan berkas yang rusak.
<syntaxhighlight lang="text">
<syntaxhighlight lang="text">
sudo kill $(sudo cat /tmp/ssh-lab/sshd.pid)
sudo rm -rf /tmp/ssh-audit
sudo /usr/sbin/sshd -f /tmp/ssh-lab/sshd_config -E /tmp/ssh-lab/sshd.log; echo "kode keluar: $?"
ss -tlnp | grep 2222
</syntaxhighlight>
</syntaxhighlight>
# Hasil yang diharapkan: instance gagal start dan port 2222 hilang. Di server produksi, skenario ini berarti kehilangan akses sampai ada orang membetulkan berkas dari konsol.


=== 🔹 Langkah 10 — bersih-bersih dan lembar bukti ===
* ⚠️ '''Hati-hati:''' <code>systemctl reload ssh</code> pada konfigurasi rusak bisa membuat layanan berhenti dan port tertutup. Selalu <code>sshd -t</code> lebih dulu, dan pastikan sesi kedua masih terbuka.
# Perbaiki berkas, tutup instance lab, hapus bahan uji.
<syntaxhighlight lang="text">
sudo sed -i '/PasswordAuthenticaion/d' /tmp/ssh-lab/sshd_config
sudo sshd -t -f /tmp/ssh-lab/sshd_config
sudo kill $(sudo cat /tmp/ssh-lab/sshd.pid) 2>/dev/null
sudo rm -rf /tmp/ssh-lab
sudo userdel -r lab
sudo userdel -r tamu
</syntaxhighlight>
# Tulis lembar bukti berisi tujuh baris: port lab, nilai <code>passwordauthentication</code> per user, nilai <code>permitrootlogin</code>, isi <code>allowusers</code>, pesan penolakan tiap uji, cuplikan log <code>Accepted publickey</code>, dan bukti port 2222 sudah tertutup.


== 🏭 Dipakai di dunia kerja ==
== 🏭 Dipakai di dunia kerja ==
* '''Sekolah:''' server CBT dan e-rapor biasanya diakses admin dari ruang guru. Kunci-saja plus <code>AllowUsers</code> per subnet membuat akun bersama tidak lagi jadi pintu masuk, tanpa mengganggu jadwal ujian.
* '''Sekolah:''' server CBT dan e-rapor sering diwarisi dari tahun sebelumnya. Audit lima lapis menghasilkan daftar akun dan kunci yang bisa dicabut sebelum tahun ajaran baru, tanpa menebak siapa masih aktif.
* '''Kantor distributor:''' vendor aplikasi minta akses remote. Kebijakan <code>PermitRootLogin no</code> dan kunci per-vendor yang bisa dicabut membuat akses berhenti tepat saat kontrak berhenti.
* '''Kantor distributor:''' audit dilakukan sebelum akses vendor diperpanjang. Temuan "sandi masih diterima" dan "root boleh dengan kunci" biasanya cukup untuk menolak perpanjangan sampai diperbaiki.
* '''Klinik dan layanan data pribadi:''' rekam medis hanya boleh dibuka staf tertentu. <code>AllowUsers</code> dan <code>AuthenticationMethods</code> adalah kontrol yang bisa ditunjukkan saat audit, bukan sekadar niat baik.
* '''Klinik dan layanan data pribadi:''' auditor eksternal tidak menerima jawaban "sudah kami amankan". Mereka meminta keluaran konfigurasi efektif dan daftar akun yang boleh masuk.
* '''Hosting dan VPS:''' server yang menghadap internet menerima puluhan ribu percobaan login per hari. Kunci-saja membuat tebakan password tidak lagi punya sasaran.
* '''Hosting dan VPS:''' pemilik layanan perlu tahu apakah image yang dipakai meninggalkan drop-in bawaan yang menimpa hardening mereka. Audit berkas drop-in adalah langkah pertama.
* '''ISP dan warnet:''' perangkat jaringan dikelola dari jarak jauh lewat SSH. Akses berbasis kunci mencegah sandi default perangkat dipakai ulang di semua unit.
* '''ISP dan warnet:''' perangkat dikelola dari jarak jauh; audit memastikan tidak ada akun bersama yang masih memakai sandi default setelah pergantian teknisi.
* '''Industri:''' jaringan operasi dan server HMI tidak boleh diakses dari sembarang host. Batas alamat di <code>AllowUsers</code> menjadi lapis pertama sebelum firewall dalam.
* '''Industri:''' perubahan konfigurasi di jaringan operasi harus bisa dipertanggungjawabkan. Lembar temuan bercap waktu lebih berguna daripada ingatan teknisi.


== ✅ Verifikasi ==
== ✅ Verifikasi ==
{| class="wikitable"
{| class="wikitable"
! Lapis !! Perintah !! Bukti lulus
! Pemeriksaan !! Perintah !! Bukti lulus
|-
|-
| 1. Jaringan || <code>ss -tlnp</code> || hanya port yang direncanakan terbuka
| Konfigurasi sah || <code>sshd -t</code> || kode keluar 0, tanpa pesan
|-
|-
| 2. Identitas || <code>sshd -T -C user=tamu,...</code> || <code>allowusers</code> hanya memuat user sah
| Sandi mati || <code>sshd -T</code> || <code>passwordauthentication no</code>
|-
|-
| 3. Metode || <code>ssh -o PubkeyAuthentication=no</code> || <code>Permission denied (publickey)</code>
| Daftar tamu ada || <code>sshd -T</code> || <code>allowgroups</code> terisi
|-
|-
| 3. Metode || <code>sshd -T -C user=lab,...</code> || nilai sesuai pengecualian <code>Match</code>
| Root tertutup || <code>sshd -T -C user=root,...</code> || <code>permitrootlogin no</code>
|-
|-
| 4. Kewenangan || <code>ssh root@host</code> || ditolak sesuai <code>PermitRootLogin</code>
| Pengecualian terbatas || <code>-C user=lab</code> vs <code>user=tamu</code> || dua nilai berbeda, sesuai rencana
|-
|-
| 4. Kewenangan || <code>sudo -l -U lab</code> || tidak ada hak berlebih
| Tunnel ditolak || <code>ssh -L</code> || <code>administratively prohibited</code>
|-
|-
| 5. Jejak || <code>grep -c 'Failed password'</code> || angka percobaan tercatat
| Batas aktif || <code>sshd -T</code> || <code>maxauthtries 3</code>
|-
|-
| 5. Jejak || <code>grep 'Accepted publickey'</code> || ada sidik jari <code>SHA256:...</code>
| Bukti tersedia || <code>grep -c 'Accepted publickey'</code> || angka bukan nol
|-
|-
| Umum || <code>sshd -t</code> || kode keluar 0, tanpa pesan
| Port sesuai || <code>ss -tlnp</code> || port yang direncanakan, bukan bawaan
|}
|}
Kalau satu baris gagal, jangan lanjut ke baris berikutnya. Perbaiki lapis itu dulu, lalu ulangi dari atas.
Kalau satu baris gagal, jangan menutup audit. Tulis sebagai temuan terbuka dengan bukti perintahnya.


== ⚠️ Kesalahan umum & troubleshooting ==
== ⚠️ Kesalahan umum & troubleshooting ==
Line 313: Line 284:
! Pesan atau gejala !! Artinya !! Tindakan
! Pesan atau gejala !! Artinya !! Tindakan
|-
|-
| Connection refused || tidak ada daemon di port itu || <code>ss -tlnp</code>, cek <code>Port</code>, cek firewall
| Connection refused || tidak ada daemon di port itu || <code>ss -tlnp</code>, cek unit dan firewall
|-
| Port tidak berubah walau <code>Port</code> diedit || <code>ssh.socket</code> memegang port || ubah <code>ListenStream</code> di unit socket
|-
|-
| Permission denied (publickey) || hanya kunci, dan kunci tidak cocok || <code>ssh -vvv</code>, cek <code>AuthorizedKeysFile</code>
| Permission denied (publickey) || kunci tidak cocok atau ditolak lapis 2 || <code>ssh -vvv</code>, cek <code>AllowGroups</code>
|-
|-
| Permission denied (publickey,password) || password masih ditawarkan tapi gagal || cek <code>sshd -T -C</code>, status akun
| Permission denied (publickey,password) || sandi masih ditawarkan tetapi gagal || cek <code>sshd -T -C</code>
|-
|-
| bad ownership or modes for directory || <code>StrictModes</code> menolak izin home || <code>chmod 750</code>, <code>chown user:user</code>
| bad ownership or modes for directory || <code>StrictModes</code> menolak izin home || <code>chmod 750</code>, <code>chown user:user</code>
|-
| administratively prohibited || forwarding dimatikan || ini hasil yang diharapkan saat audit
|-
|-
| Too many authentication failures || <code>MaxAuthTries</code> habis || pakai <code>-o IdentitiesOnly=yes</code>
| Too many authentication failures || <code>MaxAuthTries</code> habis || pakai <code>-o IdentitiesOnly=yes</code>
|-
|-
| User ... not allowed because not listed in AllowUsers || lapis identitas menolak || tambahkan pola di <code>AllowUsers</code>
| Bad configuration option: ... || salah ketik kata kunci || <code>sshd -t</code> lalu perbaiki
|-
| Bad configuration option: ... || salah ketik kata kunci || <code>sshd -t</code> lalu perbaiki barisnya
|-
| no hostkeys available -- exiting || <code>HostKey</code> hilang atau tak terbaca || <code>ssh-keygen -A</code>, cek path <code>HostKey</code>
|-
|-
| Missing privilege separation directory: /run/sshd || direktori runtime belum ada || <code>mkdir -p /run/sshd</code>
| Log kosong padahal ada percobaan || salah lokasi log atau level rendah || cek <code>LogLevel</code>, <code>rsyslog</code>, journal
|-
|-
| Address already in use || port lab sudah dipakai || <code>ss -tlnp</code>, ganti port instance
| Perubahan hilang setelah reboot || drop-in tidak terbaca atau unit menimpa || cek urutan nama berkas dan unit aktif
|}
|}


* ⚠️ '''Hati-hati:''' <code>systemctl restart ssh</code> dengan berkas rusak adalah cara paling cepat kehilangan server. Di Debian, kegagalan start meninggalkan layanan mati dan port tertutup. Selalu <code>sshd -t</code> dulu, dan pastikan kamu punya konsol atau snapshot.
* 💡 '''Tips:''' saat men-debug klien, pakai <code>ssh -v</code> (cukup) atau <code>-vvv</code> (detail). Di sisi server, <code>LogLevel VERBOSE</code> mencatat sidik jari kunci tanpa membocorkan isi sesi; kembalikan ke <code>INFO</code> setelah audit selesai.
 
* 💡 '''Tips:''' saat men-debug klien, tambahkan <code>-v</code> (cukup) atau <code>-vvv</code> (detail). Di sisi server, <code>LogLevel VERBOSE</code> memberi sidik jari kunci tanpa membocorkan isi sesi. Kembalikan ke <code>INFO</code> setelah selesai.


== 🔐 Catatan keamanan & etika ==
== 🔐 Catatan keamanan & etika ==
* '''LogLevel DEBUG bukan alat permanen.''' Manpage <code>sshd_config(5)</code> menyebut level DEBUG melanggar privasi pengguna. Nyalakan sebentar, matikan lagi.
* '''Audit dulu, ubah kemudian.''' Perintah baca tidak mengubah apa pun; setiap perubahan konfigurasi butuh sesi cadangan dan snapshot.
* '''Kunci adalah identitas, bukan berkas biasa.''' Kunci privat mode <code>600</code>, direktori <code>.ssh</code> mode <code>700</code>, dan jangan pernah menyalinnya ke flashdisk bersama.
* '''Jangan mencetak isi berkas rahasia.''' <code>/etc/shadow</code> dan kunci privat tidak perlu dibaca untuk audit; cukup status dan nama berkasnya.
* '''prohibit-password bukan "root mati".''' Kalau ingin root benar-benar tertutup, tulis <code>no</code> dan pastikan ada akun lain dengan <code>sudo</code>.
* '''Hasil audit adalah data pribadi.''' Daftar akun, kunci, dan alamat IP adalah informasi sensitif. Simpan di tempat terbatas, jangan di grup chat.
* '''Cabut akses dengan mencabut kunci.''' Hapus baris di <code>authorized_keys</code> atau pakai <code>AuthorizedKeysCommand</code> terpusat; mengganti password tidak menyentuh kunci yang sudah tertanam.
* '''<code>LogLevel DEBUG</code> bukan alat permanen.''' Manpage <code>sshd_config(5)</code> menyebut level DEBUG melanggar privasi pengguna.
* '''Log menyimpan data pribadi.''' Alamat IP, nama user, dan sidik jari kunci adalah data orang. Jangan menempel log mentah ke grup chat umum.
* '''Cabut akses dengan mencabut kunci.''' Mengganti sandi tidak menyentuh <code>authorized_keys</code> yang sudah tertanam.
* '''Lab di server bersama butuh izin.''' Instance kedua tidak mengganggu produksi, tetapi membuat user dan mengubah izin home tetap terlihat pengguna lain. Kembalikan kondisi awal setelah selesai.
* '''Etika:''' audit hanya pada server milik sendiri atau yang kamu diberi izin tertulis. Memindai server orang lain adalah pelanggaran hukum.
* '''Etika:''' materi ini untuk mengamankan server milik sendiri atau yang kamu diberi izin. Mencoba teknik ini pada server orang lain adalah pelanggaran hukum, bukan latihan.


== 📌 Kesimpulan ==
== 📌 Kesimpulan ==
Hardening SSH bukan daftar baris yang ditempel, tetapi urutan lapis yang harus dibuktikan satu per satu: jaringan, identitas, metode, kewenangan, jejak.
Audit hardening SSH bukan membaca berkas dengan teliti, tetapi '''menunjuk bukti''': nilai efektif, user yang terkena, dan pesan penolakan yang muncul.


Alat paling jujurnya bukan ingatanmu, melainkan <code>sshd -T</code> dan <code>sshd -T -C</code>. Dua perintah itu menunjukkan apa yang benar-benar dipakai <code>sshd</code> untuk user dan alamat tertentu, termasuk saat drop-in menimpa berkas utama.
Dua perintah menjadi tulang punggungnya: <code>sshd -T</code> untuk kebenaran umum, dan <code>sshd -T -C</code> untuk kebenaran per user. Selama keduanya belum dijalankan, "sudah diamankan" masih sekadar kalimat.


Langkah berikutnya: ambil satu server latihan milikmu, potret baseline-nya, lalu jalankan lab ini dari Langkah 2 sampai Langkah 9 tanpa menyentuh layanan di port 22.
Langkah berikutnya: ambil satu server warisan di labmu, jalankan Langkah 1 sampai 8 tanpa mengubah apa pun, lalu presentasikan lembarnya ke teman satu kelompok untuk diuji balik.


== 🔗 Materi terkait ==
== 🔗 Materi terkait ==
* [[Linux : Mengamankan SSH Server dengan Port Custom]] — dasar memindahkan port dan konsekuensi operasionalnya.
* [[Linux : SSH Hardening Lanjutan (Lima Lapis Kunci Akses)]] — artikel konsep pasangan lab ini: memasang lima lapis dari nol.
* [[Linux : Mengamankan SSH Server dengan Port Custom]] — kenapa ganti port bukan hardening.
* [[Linux : Membatasi Percobaan Login SSH dengan Fail2ban]] — lapis tambahan setelah <code>MaxAuthTries</code>.
* [[Linux : Membatasi Percobaan Login SSH dengan Fail2ban]] — lapis tambahan setelah <code>MaxAuthTries</code>.
* [[Linux : Praktikum Audit Akun, Group, dan Hak sudo]] — audit identitas dan kewenangan di sisi sistem.
* [[Mengijinkan User Tertentu Remote SSH]] — versi ringkas pembatasan user.
* [[Mengijinkan User Tertentu Remote SSH]] — versi ringkas pembatasan user.
* [[Merubah Default Port SSH]] — perubahan port dan penyesuaian klien.
* [[Linux : Log dan journalctl untuk Troubleshooting]] — membaca jejak ketika log tidak ada di tempat yang diduga.
* [[Instalasi SSH Server di Debian Linux]] — prasyarat pemasangan layanan.
* [[Linux : Praktikum Audit Akun, Group, dan Hak sudo]] — audit identitas dan kewenangan setelah hardening.


== 📚 Referensi ==
== 📚 Referensi ==
* Debian Manpages — [https://manpages.debian.org/bookworm/openssh-server/sshd_config.5.en.html sshd_config(5)], bookworm.
* Debian Manpages — [https://manpages.debian.org/bookworm/openssh-server/sshd_config.5.en.html sshd_config(5)], bookworm.
* Debian Manpages — [https://manpages.debian.org/bookworm/openssh-server/sshd.8.en.html sshd(8)], termasuk opsi <code>-t</code>, <code>-T</code>, dan <code>-C</code>.
* Debian Manpages — [https://manpages.debian.org/bookworm/openssh-server/sshd.8.en.html sshd(8)], opsi <code>-t</code>, <code>-T</code>, dan <code>-C</code>.
* Debian Manpages — [https://manpages.debian.org/bookworm/openssh-client/ssh.1.en.html ssh(1)] dan [https://manpages.debian.org/bookworm/openssh-client/ssh-keygen.1.en.html ssh-keygen(1)].
* Debian Manpages — [https://manpages.debian.org/bookworm/openssh-client/ssh.1.en.html ssh(1)] dan [https://manpages.debian.org/bookworm/openssh-client/ssh-keygen.1.en.html ssh-keygen(1)].
* Debian Wiki — [https://wiki.debian.org/SSH SSH].
* Debian Wiki — [https://wiki.debian.org/SSH SSH].

Latest revision as of 18:20, 11 November 2026

Lima lapis hardening SSH sudah dipasang. Port diganti, password dimatikan, Fail2ban berjalan, dan log tampak tenang. Lalu datang pertanyaan yang jarang ditanyakan: kapan terakhir kali kamu membuktikan lapis mana yang benar-benar aktif?

Artikel ini adalah lab audit, bukan lab pemasangan. Artikel konsep Linux : SSH Hardening Lanjutan (Lima Lapis Kunci Akses) membangun lima lapis dari nol. Di sini arahnya dibalik: kamu menerima server warisan yang katanya "sudah aman", lalu membuat lembar temuan yang setiap barisnya punya bukti perintah.

🎯 Tujuan

Setelah mengikuti lab ini, kamu bisa:

  • Mengaudit konfigurasi SSH yang sudah berjalan tanpa mengubah apa pun lebih dulu.
  • Menunjuk lapis mana yang menolak sebuah login, bukan menebak.
  • Membaca konfigurasi efektif per user dengan sshd -T -C.
  • Menemukan dua jebakan paling sering: urutan Include dan Match yang bertentangan.
  • Menyusun lembar temuan berisi temuan, bukti, risiko, dan tindakan.
  • Memperbaiki temuan tanpa mengunci diri sendiri di luar server.

📍 Konteks nyata

Bayangkan kamu menerima kunci gedung lab dari admin sebelumnya. Ia bilang: "pintunya sudah diganti nomornya, satpam sudah dipasang, aman."

Tugasmu bukan mempercayai kalimat itu, tetapi berkeliling: mencoba pintu, membaca daftar tamu, mengecek ruang mana yang terbuka, dan menanyakan di mana bukunya. Audit bekerja persis begitu — kecurigaan bukan bukti, dan ingatan bukan catatan.

  • 🔥 Kasus nyata: sebuah SMK memindahkan SSH ke port 2222 dan memasang Fail2ban. Di berkas /etc/ssh/sshd_config tertulis PasswordAuthentication no, dan admin sudah memverifikasinya berkali-kali. Yang tidak dibaca: /etc/ssh/sshd_config.d/50-cloud-init.conf dari image server berisi PasswordAuthentication yes. Karena Include duduk di baris pertama, nilai itu dibaca lebih dulu dan menang. Tujuh bulan kemudian akun operator dengan sandi operator123 dipakai bergantian empat orang, dan nilai dua kelas berubah pada suatu malam.

🧠 Konsep singkat

Audit SSH berarti memeriksa lima lapis yang sama seperti artikel konsep, tetapi dengan urutan terbalik: mulai dari bukti, bukan dari niat.

Lapis Pertanyaan audit Alat bukti
1. Identitas Sandi masih diterima? passwordauthentication efektif
2. Keanggotaan Siapa yang dibatasi? allowusers, allowgroups
3. Kewenangan Boleh apa setelah masuk? permitrootlogin, disableforwarding
4. Batas Berapa lama dan berapa kali? maxauthtries, logingracetime
5. Bukti Apa yang tercatat? loglevel, auth.log

Aturan kerjanya: berhenti di lapis pertama yang gagal. Kalau login ditolak karena AllowUsers, jangan menyimpulkan "kuncinya salah" lalu membuat kunci baru.

🔹 Tiga perintah yang mirip, artinya beda

  • sshd -t — hanya memeriksa keabsahan berkas. Tidak mencetak apa pun kalau sehat. Ini rem darurat sebelum reload.
  • sshd -T — mencetak konfigurasi efektif setelah semua Include diterapkan. Inilah kebenaran yang dipakai daemon.
  • sshd -T -C user=...,addr=...,host=... — konfigurasi efektif untuk satu koneksi tertentu, termasuk blok Match.
  • 💡 Tips: jadikan sshd -T sebagai saksi utama. Selama audit, setiap temuan harus bisa dijawab dengan satu baris keluarannya.

🔹 Nilai pertama yang menang

sshd_config(5) menyatakan: untuk setiap kata kunci, nilai pertama yang ditemukan itulah yang dipakai. Paket Debian dan Ubuntu menaruh Include /etc/ssh/sshd_config.d/*.conf di baris paling atas, sehingga drop-in dibaca lebih dulu dan menimpa berkas utama.

  • ⚠️ Hati-hati: "sudah saya matikan di berkas utama" bukan bukti. Bukti adalah baris passwordauthentication no pada keluaran sshd -T.

🔹 Satu berkas, dua kebenaran

Match membuat blok bersyarat yang menimpa bagian global untuk user, group, atau alamat tertentu. Satu berkas konfigurasi bisa berarti dua hal berbeda untuk dua orang — dan hanya -C yang bisa memisahkannya.

🧩 Istilah penting

  • Konfigurasi efektif — hasil akhir setelah Include dan Match diterapkan; yang benar-benar dibaca sshd.
  • Drop-in — berkas di sshd_config.d/; nomor kecil dibaca lebih dulu, jadi lebih kuat.
  • Socket activation — mode di mana systemd yang memegang port lewat ssh.socket, bukan sshd.
  • Match block — blok bersyarat berdasarkan User, Group, Address, Host, atau LocalPort.
  • prohibit-password — root tidak boleh memakai password, tetapi masih boleh memakai kunci.
  • StrictModes — sshd memeriksa pemilik dan izin berkas kunci sebelum login diterima.
  • MaxAuthTries — batas percobaan autentikasi per koneksi; kegagalan mulai dicatat setelah separuh nilai.
  • MaxStartups — batas koneksi yang belum terautentikasi, ditulis start:rate:full.
  • DisableForwarding — mematikan semua penerusan port, tunnel, dan agent dalam satu saklar.
  • auth.log — berkas jejak autentikasi di Debian/Ubuntu, biasanya milik syslog:adm.

🔧 Praktik: audit server warisan tanpa mengunci diri

Semua pengujian dilakukan pada salinan konfigurasi di /tmp/ssh-audit dan instance kedua di port 2222. Layanan asli tidak disentuh sampai kamu yakin.

  • ⚠️ Hati-hati: buka dua sesi sebelum mulai — satu untuk bekerja, satu dibiarkan terbuka sebagai jalan pulang. Audit yang mengunci diri sendiri bukan audit, itu insiden.

🔹 Langkah 1 — potret dan simpan sebagai pembanding

sudo sshd -T | sort > /tmp/audit-awal.txt
sudo sshd -T | grep -Ei '^(port|permitrootlogin|passwordauthentication|pubkeyauthentication|kbdinteractive|allowusers|allowgroups|maxauthtries|logingracetime|loglevel|disableforwarding)'
ss -tlnp | grep -i ssh
systemctl is-enabled ssh ssh.socket 2>&1
  1. Catat juga unit yang aktif. Di Ubuntu 24.04, ssh.socket bisa ikut aktif dan memegang port sendiri.
  • 📊 Angka penting: saat ssh.socket aktif, systemd yang membuka port. Mengubah Port di sshd_config tidak memindahkan pintu, karena yang mendengarkan bukan sshd.

🔹 Langkah 2 — petakan berkas yang benar-benar dibaca

  1. Lihat urutan Include dan isi folder drop-in. Ini peta sumber konflik.
sudo grep -n '^Include' /etc/ssh/sshd_config
sudo ls -1 /etc/ssh/sshd_config.d/ 2>/dev/null
sudo grep -Hn -Ei 'password|permitrootlogin|allowusers|maxauthtries' /etc/ssh/sshd_config /etc/ssh/sshd_config.d/*.conf 2>/dev/null
  1. Bandingkan jumlah baris konfigurasi efektif dengan jumlah baris yang kamu baca. Selisihnya berasal dari bawaan dan drop-in.
sudo sshd -T | wc -l
  • 🧪 Uji cepat: sudo sshd -T | grep -c . memberi jumlah baris efektif. Kalau kamu baru mengubah satu baris tetapi angka ini tidak berubah, perubahanmu tidak terbaca.

🔹 Langkah 3 — lapis 1: apakah sandi masih diterima

sudo sshd -T | grep -Ei '^(passwordauthentication|kbdinteractiveauthentication|pubkeyauthentication|permitemptypasswords)'
  1. Cari akun yang masih punya sandi aktif. Ini daftar calon pintu masuk kalau lapis 1 jebol.
sudo passwd -S -a | awk '$2=="P" {print $1, $2}'
  1. Inventaris kunci yang tertanam: siapa pun yang punya baris di sini bisa masuk tanpa sandi.
sudo find /home /root -maxdepth 3 -name authorized_keys -printf '%p %TY-%Tm-%Td\n' 2>/dev/null
  1. Hasil yang diharapkan: tiga daftar yang bisa kamu tunjuk — status sandi, nilai efektif, dan kunci yang ada.

🔹 Langkah 4 — lapis 2: siapa yang dibatasi

sudo sshd -T | grep -Ei '^(allowusers|allowgroups|denyusers|denygroups)' || echo "KOSONG: semua akun boleh masuk"
  1. Keluaran kosong adalah temuan, bukan hasil netral. Artinya tidak ada daftar tamu sama sekali.
sudo sshd -T -C user=nobody,addr=192.168.100.10,host=admin-pc | grep -Ei '^(allowusers|allowgroups|passwordauthentication)'
  1. Hasil yang diharapkan: nilai yang sama persis untuk user yang tidak berhak — bukti bahwa lapis 2 belum bekerja.

🔹 Langkah 5 — lapis 3: kewenangan setelah masuk

sudo sshd -T | grep -Ei '^(permitrootlogin|disableforwarding|x11forwarding|allowtcpforwarding|permittunnel|allowagentforwarding)'
  1. Periksa pengecualian per user. Inilah tempat Match biasanya menyimpan kejutan.
sudo sshd -T -C user=guru1,addr=192.168.100.20,host=laptop-guru | grep -Ei '^(forcecommand|chrootdirectory|permittty|allowtcpforwarding|disableforwarding)'
  1. Uji nyata: coba buka tunnel ke port lokal. Kalau DisableForwarding yes bekerja, permintaan ditolak.
ssh -p 2222 -N -L 8080:127.0.0.1:80 lab@127.0.0.1
# channel 2: open failed: administratively prohibited: open failed
  • 💡 Tips: pesan administratively prohibited adalah bukti lapis 3 yang bekerja. Kalau tunnel justru terbuka, temuanmu berbunyi "kewenangan terlalu luas" — bukan "jaringan bermasalah".

🔹 Langkah 6 — lapis 4: batas percobaan dan waktu

sudo sshd -T | grep -Ei '^(maxauthtries|logingracetime|maxstartups|clientaliveinterval)'
sudo command -v fail2ban-client && sudo fail2ban-client status sshd
  1. Baca angkanya, bukan status layanannya. Fail2ban yang aktif tetap tidak menolong kalau MaxAuthTries dibiarkan besar dan sandi masih diterima.
  • 📊 Angka penting: bawaan MaxAuthTries 6, LoginGraceTime 120 detik, MaxStartups 10:30:100, ClientAliveInterval 0. Kegagalan autentikasi mulai dicatat setelah mencapai separuh MaxAuthTries.

🔹 Langkah 7 — lapis 5: bukti yang tersedia

sudo sshd -T | grep -i '^loglevel'
ls -l /var/log/auth.log 2>/dev/null
sudo journalctl --disk-usage
sudo lastb -n 5
  1. Hitung bukti yang benar-benar ada, bukan yang seharusnya ada.
sudo grep -c 'Accepted publickey' /var/log/auth.log
sudo grep -c 'Failed password' /var/log/auth.log
  1. Hasil yang diharapkan: dua angka. Kalau keduanya nol padahal server menghadap internet, curigai LogLevel atau lokasi log, bukan "tidak ada serangan".

🔹 Langkah 8 — susun lembar temuan

Inilah keluaran utama audit. Setiap baris harus bisa dipertahankan dengan perintah, bukan pendapat.

Temuan Bukti Risiko Tindakan
Sandi masih diterima passwordauthentication yes tebakan sandi berhasil matikan, sisakan kunci
Tanpa daftar tamu allowusers kosong akun lama ikut masuk AllowGroups
Root boleh dengan kunci permitrootlogin without-password kunci lama tak tercabut no + akun sudo
Forwarding terbuka allowtcpforwarding yes server jadi jalan pintas DisableForwarding yes
Port tidak berlaku ssh.socket aktif perubahan port sia-sia ubah di unit socket
Log minim loglevel INFO sidik jari kunci tak tercatat LogLevel VERBOSE
  1. Beri urutan prioritas: lapis 1 dan 2 dulu, karena keduanya menentukan siapa yang boleh masuk.

🔹 Langkah 9 — dua jebakan yang membatalkan temuanmu

  1. Jebakan urutan Include. Buat salinan konfigurasi di /tmp agar produksi aman, lalu buat dua berkas yang bertentangan.
sudo mkdir -p /tmp/ssh-audit/sshd_config.d
sudo tee /tmp/ssh-audit/sshd_config > /dev/null <<'EOF'
Include /tmp/ssh-audit/sshd_config.d/*.conf
Port 2222
PidFile /tmp/ssh-audit/sshd.pid
HostKey /etc/ssh/ssh_host_ed25519_key
PasswordAuthentication no
EOF
sudo tee /tmp/ssh-audit/sshd_config.d/99-warisan.conf > /dev/null <<'EOF'
PasswordAuthentication yes
EOF
sudo sshd -T -f /tmp/ssh-audit/sshd_config | grep -i passwordauth
  1. Hasil yang diharapkan: passwordauthentication yes. Berkas utama menulis no, tetapi drop-in dibaca lebih dulu. Inilah bentuk persis kegagalan yang tidak terlihat saat membaca berkas utama.
  2. Jebakan Match. Tambahkan pengecualian untuk satu user, lalu tanyakan dua kali dengan user berbeda.
sudo tee /tmp/ssh-audit/sshd_config.d/20-pengecualian.conf > /dev/null <<'EOF'
Match User lab
    PasswordAuthentication yes
    AllowTcpForwarding yes
EOF
sudo sshd -T -f /tmp/ssh-audit/sshd_config -C user=lab,addr=192.168.100.30,host=pc-lab | grep -Ei 'passwordauth|allowtcpforwarding'
sudo sshd -T -f /tmp/ssh-audit/sshd_config -C user=tamu,addr=192.168.100.30,host=pc-lab | grep -Ei 'passwordauth|allowtcpforwarding'
  1. Hasil yang diharapkan: dua jawaban berbeda untuk berkas yang sama. Audit tanpa -C akan melaporkan satu kebenaran saja.
  2. Konfigurasi rusak. Buktikan bahwa rem darurat bekerja sebelum menyentuh layanan asli.
sudo sh -c 'echo PasswordAuthenticaion no >> /tmp/ssh-audit/sshd_config'
sudo sshd -t -f /tmp/ssh-audit/sshd_config; echo "kode keluar: $?"
  1. Hasil yang diharapkan: Bad configuration option: passwordauthenticaion dan kode keluar bukan nol.

🔹 Langkah 10 — perbaiki, lalu audit ulang

  1. Perbaikan ditaruh di drop-in bernomor kecil supaya menang atas berkas bawaan. Nama berkas adalah bagian dari strategi, bukan hiasan.
sudo tee /etc/ssh/sshd_config.d/10-hardening.conf > /dev/null <<'EOF'
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitEmptyPasswords no
PermitRootLogin no
AllowGroups ssh-users
MaxAuthTries 3
LoginGraceTime 30
LogLevel VERBOSE
EOF
sudo sshd -t && echo "konfigurasi sah"
  1. Reload, lalu bandingkan potret lama dengan yang baru. Perbedaan itulah bukti pekerjaanmu.
sudo systemctl reload ssh
sudo sshd -T | sort > /tmp/audit-akhir.txt
diff /tmp/audit-awal.txt /tmp/audit-akhir.txt
  1. Verifikasi hasil akhir dengan pertanyaan yang sama seperti awal audit: sandi, daftar tamu, kewenangan, batas, bukti.
sudo sshd -T | grep -Ei '^(passwordauthentication|permitrootlogin|allowgroups|maxauthtries|loglevel)'
sudo sshd -T -C user=tamu,addr=192.168.100.10,host=admin-pc | grep -Ei '^(allowgroups|passwordauthentication)'
  1. Bersih-bersih bahan audit.
sudo rm -rf /tmp/ssh-audit
  • ⚠️ Hati-hati: systemctl reload ssh pada konfigurasi rusak bisa membuat layanan berhenti dan port tertutup. Selalu sshd -t lebih dulu, dan pastikan sesi kedua masih terbuka.

🏭 Dipakai di dunia kerja

  • Sekolah: server CBT dan e-rapor sering diwarisi dari tahun sebelumnya. Audit lima lapis menghasilkan daftar akun dan kunci yang bisa dicabut sebelum tahun ajaran baru, tanpa menebak siapa masih aktif.
  • Kantor distributor: audit dilakukan sebelum akses vendor diperpanjang. Temuan "sandi masih diterima" dan "root boleh dengan kunci" biasanya cukup untuk menolak perpanjangan sampai diperbaiki.
  • Klinik dan layanan data pribadi: auditor eksternal tidak menerima jawaban "sudah kami amankan". Mereka meminta keluaran konfigurasi efektif dan daftar akun yang boleh masuk.
  • Hosting dan VPS: pemilik layanan perlu tahu apakah image yang dipakai meninggalkan drop-in bawaan yang menimpa hardening mereka. Audit berkas drop-in adalah langkah pertama.
  • ISP dan warnet: perangkat dikelola dari jarak jauh; audit memastikan tidak ada akun bersama yang masih memakai sandi default setelah pergantian teknisi.
  • Industri: perubahan konfigurasi di jaringan operasi harus bisa dipertanggungjawabkan. Lembar temuan bercap waktu lebih berguna daripada ingatan teknisi.

✅ Verifikasi

Pemeriksaan Perintah Bukti lulus
Konfigurasi sah sshd -t kode keluar 0, tanpa pesan
Sandi mati sshd -T passwordauthentication no
Daftar tamu ada sshd -T allowgroups terisi
Root tertutup sshd -T -C user=root,... permitrootlogin no
Pengecualian terbatas -C user=lab vs user=tamu dua nilai berbeda, sesuai rencana
Tunnel ditolak ssh -L administratively prohibited
Batas aktif sshd -T maxauthtries 3
Bukti tersedia grep -c 'Accepted publickey' angka bukan nol
Port sesuai ss -tlnp port yang direncanakan, bukan bawaan

Kalau satu baris gagal, jangan menutup audit. Tulis sebagai temuan terbuka dengan bukti perintahnya.

⚠️ Kesalahan umum & troubleshooting

Pesan atau gejala Artinya Tindakan
Connection refused tidak ada daemon di port itu ss -tlnp, cek unit dan firewall
Port tidak berubah walau Port diedit ssh.socket memegang port ubah ListenStream di unit socket
Permission denied (publickey) kunci tidak cocok atau ditolak lapis 2 ssh -vvv, cek AllowGroups
Permission denied (publickey,password) sandi masih ditawarkan tetapi gagal cek sshd -T -C
bad ownership or modes for directory StrictModes menolak izin home chmod 750, chown user:user
administratively prohibited forwarding dimatikan ini hasil yang diharapkan saat audit
Too many authentication failures MaxAuthTries habis pakai -o IdentitiesOnly=yes
Bad configuration option: ... salah ketik kata kunci sshd -t lalu perbaiki
Log kosong padahal ada percobaan salah lokasi log atau level rendah cek LogLevel, rsyslog, journal
Perubahan hilang setelah reboot drop-in tidak terbaca atau unit menimpa cek urutan nama berkas dan unit aktif
  • 💡 Tips: saat men-debug klien, pakai ssh -v (cukup) atau -vvv (detail). Di sisi server, LogLevel VERBOSE mencatat sidik jari kunci tanpa membocorkan isi sesi; kembalikan ke INFO setelah audit selesai.

🔐 Catatan keamanan & etika

  • Audit dulu, ubah kemudian. Perintah baca tidak mengubah apa pun; setiap perubahan konfigurasi butuh sesi cadangan dan snapshot.
  • Jangan mencetak isi berkas rahasia. /etc/shadow dan kunci privat tidak perlu dibaca untuk audit; cukup status dan nama berkasnya.
  • Hasil audit adalah data pribadi. Daftar akun, kunci, dan alamat IP adalah informasi sensitif. Simpan di tempat terbatas, jangan di grup chat.
  • LogLevel DEBUG bukan alat permanen. Manpage sshd_config(5) menyebut level DEBUG melanggar privasi pengguna.
  • Cabut akses dengan mencabut kunci. Mengganti sandi tidak menyentuh authorized_keys yang sudah tertanam.
  • Etika: audit hanya pada server milik sendiri atau yang kamu diberi izin tertulis. Memindai server orang lain adalah pelanggaran hukum.

📌 Kesimpulan

Audit hardening SSH bukan membaca berkas dengan teliti, tetapi menunjuk bukti: nilai efektif, user yang terkena, dan pesan penolakan yang muncul.

Dua perintah menjadi tulang punggungnya: sshd -T untuk kebenaran umum, dan sshd -T -C untuk kebenaran per user. Selama keduanya belum dijalankan, "sudah diamankan" masih sekadar kalimat.

Langkah berikutnya: ambil satu server warisan di labmu, jalankan Langkah 1 sampai 8 tanpa mengubah apa pun, lalu presentasikan lembarnya ke teman satu kelompok untuk diuji balik.

🔗 Materi terkait

📚 Referensi