Banyak siswa dan teknisi menganggap SSH sudah aman begitu port 22 diganti jadi 2222. Padahal port itu cuma nomor pintu. Yang menentukan siapa benar-benar bisa masuk adalah kunci, daftar tamu, ruang yang boleh dibuka, batas waktu kunjungan, dan buku tamunya.

Artikel ini membahas hardening SSH sebagai lima lapis yang saling menutup. Satu lapis jebol, lapis lain masih menahan. Dan sebaliknya, satu lapis yang dilewati bisa membuat empat lapis lainnya tidak ada artinya.

🎯 Tujuan

Setelah membaca dan mempraktikkan artikel ini, kamu bisa:

  • menjelaskan beda mengganti pintu dan mengunci pintu pada layanan SSH;
  • memasang lima lapis pengaman: identitas, keanggotaan, kewenangan, batas, dan bukti;
  • membaca konfigurasi yang benar-benar berlaku dengan sshd -T, bukan menebak dari isi file;
  • mempersempit akun yang boleh masuk sampai level alamat IP dan group;
  • mematikan fitur yang tidak dipakai (forwarding, tunnel, X11) tanpa memutus kebutuhan sah seperti SFTP;
  • meninggalkan jejak yang cukup untuk menjawab pertanyaan "siapa yang masuk semalam?".

πŸ“ Konteks nyata

Bayangkan gedung lab sekolahmu. Untuk masuk ke ruang server, ada lima hal yang harus kamu lewati: kunci pintu, daftar tamu di pos satpam, daftar ruang yang boleh kamu masuki, jam kunjungan, dan buku tamu yang mencatat kedatanganmu.

SSH bekerja dengan urutan yang sama. Port adalah nomor pintu. Kunci publik adalah kuncinya. AllowGroups adalah daftar tamu. ForceCommand dan DisableForwarding adalah daftar ruang. LoginGraceTime dan MaxAuthTries adalah jam kunjungan. LogLevel VERBOSE dan auth.log adalah buku tamu.

Masalahnya, banyak orang hanya mengganti nomor pintu lalu menganggap gedungnya aman. Di dalam gedung itu, pintunya masih bisa dibuka dengan sandi yang ditempel di monitor.

πŸ”₯ Kasus nyata: Sebuah SMK memindahkan SSH ke port 2222 dan memasang Fail2ban. Keduanya berjalan benar, log bersih, dan tim yakin servernya "sudah dikunci". Yang tidak dicek: akun operator masih memakai sandi yang sama sejak dua tahun lalu, dan tidak ada AllowUsers sama sekali. Suatu pagi muncul login sukses dari alamat IP di luar negeri. Nilai tiga kelas berubah, dan panitia menghabiskan dua minggu merekap ulang dari kertas. Port sudah diganti, tapi pintunya tetap terbuka lebar.

🧠 Konsep singkat

Hardening SSH bukan menambah satu baris ajaib di konfigurasi. Ini pekerjaan mengurangi jumlah cara masuk sampai tinggal cara yang benar-benar kamu butuhkan, lalu memastikan cara itu tercatat.

πŸ”Ή Lima lapis, satu arah

Lapis Pertanyaan Setelan kunci Kalau dilewati
1. Identitas Siapa kamu? PubkeyAuthentication, PasswordAuthentication sandi lemah jadi jalan masuk utama
2. Keanggotaan Siapa yang diizinkan? AllowUsers, AllowGroups, DenyUsers akun lama dan akun layanan tetap bisa masuk
3. Kewenangan Boleh apa setelah masuk? DisableForwarding, ForceCommand, chroot dapat shell penuh padahal cuma butuh unggah file
4. Batas Berapa banyak dan berapa lama? MaxAuthTries, LoginGraceTime, MaxStartups percobaan sandi leluasa, koneksi menggantung
5. Bukti Apa yang tercatat? LogLevel VERBOSE, auth.log tidak bisa membuktikan siapa masuk kapan

Urutannya penting. Kalau lapis 1 masih menerima sandi, memperketat lapis 4 hanya memperlambat penyerang, tidak menghentikannya. Perbaiki dari kiri ke kanan.

πŸ”Ή Kenapa ganti port bukan hardening

Mengganti port 22 ke 2222 mengurangi jumlah pemindaian otomatis, dan itu ada gunanya. Tapi secara keamanan, port hanya mengubah alamat pintu, bukan kunci pintu.

  • Pemindai yang serius tetap menemukan port SSH dalam hitungan menit, karena mereka memindai semua port.
  • Sandi lemah tetap lemah di port mana pun.
  • Akun yang tidak seharusnya ada tetap bisa masuk di port mana pun.

Jadi ganti port boleh, tapi letakkan sebagai pelengkap lapis 1 dan 2, bukan penggantinya.

πŸ”Ή Nilai pertama yang menang

Ini aturan yang paling sering bikin bingung. sshd_config(5) menulis dengan jelas: untuk setiap keyword, nilai pertama yang ditemukan yang dipakai. Bukan yang terakhir.

Paket Debian dan Ubuntu menaruh baris berikut di awal /etc/ssh/sshd_config:

Include /etc/ssh/sshd_config.d/*.conf

Artinya semua file di folder itu dibaca lebih dulu, sehingga isinya mengalahkan isi file utama. Di dalam folder, file dibaca berurutan sesuai abjad. Maka 10-hardening.conf menang atas 50-cloud-init.conf, tapi kalah kalau kamu menamainya 99-lupa.conf.

⚠️ Hati-hati: Inilah penyebab paling umum dari kalimat "sudah saya set PasswordAuthentication no tapi masih bisa login pakai sandi". File utama sudah benar, tapi drop-in lain menimpanya. Selalu buktikan dengan sshd -T, jangan dengan grep di satu file.

πŸ”Ή Tiga perintah uji yang mirip tapi beda

Perintah Gunanya Catatan
sshd -t uji sintaks konfigurasi tidak membuktikan nilai akhir
sshd -T cetak konfigurasi efektif butuh root, karena membaca include dan host key
sshd -T -C user=x,addr=y terapkan blok Match lebih dulu meniru koneksi tertentu

sshd -T adalah satu-satunya cara jujur menjawab "setelan apa yang benar-benar dipakai layanan ini sekarang". Kalau dijalankan sebagai user biasa, ia gagal dengan Permission denied saat membaca file drop-in β€” dan itu bukan tanda konfigurasimu rusak, hanya kurang hak baca.

πŸ”Ή Socket dan service: dua pintu yang harus dibereskan bersama

Di Ubuntu 22.10 ke atas, SSH bisa dijalankan lewat socket activation: ssh.socket yang membuka port, lalu menyerahkan koneksi ke ssh.service. Akibatnya, mengubah Port di sshd_config saja tidak memindahkan pintunya.

πŸ“Š Angka penting: Pada VM latihan yang dipakai artikel ini (OpenSSH 9.6p1), ssh.service dan ssh.socket sama-sama aktif. Port 2290 baru benar-benar terbuka setelah unit socket diberi ListenStream= kosong untuk menghapus daftar bawaan, lalu ListenStream=0.0.0.0:2290. Tanpa baris kosong itu, port 22 lama ikut tertinggal.

Cara memeriksanya cuma satu baris:

systemctl cat ssh.socket | grep ListenStream
ss -tlnp | grep -E ':22|:2222|:2290'

🧩 Istilah penting

Istilah Arti singkat
Public key auth Login memakai pasangan kunci, bukan sandi. Server menyimpan kunci publik, klien memegang kunci privat.
Drop-in File tambahan di sshd_config.d/ yang dibaca lebih dulu karena baris Include.
Match block Blok konfigurasi bersyarat, misalnya hanya berlaku untuk group atau alamat tertentu.
Chroot Mengurung user di dalam satu folder, sehingga / miliknya adalah folder itu.
Forwarding Kemampuan meneruskan port lewat koneksi SSH, sering dipakai untuk menerobos firewall.
Grace time Batas waktu untuk menyelesaikan login sebelum koneksi diputus.
StrictModes Pemeriksaan izin file kunci dan home directory sebelum login diterima.
Socket activation Layanan dijalankan saat ada koneksi, port dibuka oleh unit .socket.
Restrict Opsi di authorized_keys yang mematikan semua fasilitas tambahan pada satu kunci.
ForceCommand Perintah yang dipaksa berjalan saat kunci dipakai, mengabaikan perintah dari klien.

πŸ”§ Praktik: Memasang Lima Lapis di VM Latihan

Siapkan satu VM Debian atau Ubuntu dengan akses konsol (bukan hanya SSH). Ini wajib, karena kesalahan pada lapis 2 bisa mengunci kamu sendiri di luar.

πŸ’‘ Tips: beri nama file drop-in dengan angka kecil, misalnya 10-hardening.conf. Angka kecil dibaca lebih dulu, jadi setelanmu menang atas file bawaan yang bernomor besar. Ganti nama file setelah terpasang berarti setelanmu bisa tiba-tiba kalah.

  1. Ambil snapshot dulu, lalu buka dua sesi SSH. Sesi pertama untuk bekerja, sesi kedua dibiarkan terbuka sebagai jalan pulang kalau konfigurasi baru salah.
  2. Potret konfigurasi awal sebelum mengubah apa pun.
sudo sshd -T | sort > /root/sshd-awal.txt
sudo sshd -T | grep -E '^(port|permitrootlogin|passwordauthentication|kbdinteractive|pubkeyauthentication|allowusers|allowgroups|maxauthtries|logingracetime|maxstartups|x11forwarding|loglevel)'
ss -tlnp | grep sshd
  1. Lapis 1 - pasang kunci, matikan sandi. Buat kunci di komputer klien, lalu salin ke server.
ssh-keygen -t ed25519 -a 100 -C "lab-admin@smk"
ssh-copy-id -p 2222 lab@192.168.100.50
ssh -p 2222 -o PreferredAuthentications=publickey lab@192.168.100.50 'whoami; id'
  1. Pastikan login dengan kunci berhasil sebelum mematikan sandi. Setelah itu buat drop-in berikut, dengan nama yang urutannya paling awal.
sudo tee /etc/ssh/sshd_config.d/10-hardening.conf >/dev/null <<'EOF'
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitEmptyPasswords no
PermitRootLogin no
EOF

sudo sshd -t && sudo sshd -T | grep -E '^(passwordauthentication|permitrootlogin|kbdinteractive)'
sudo systemctl reload ssh
  1. Lapis 2 - batasi siapa yang boleh masuk. Buat group khusus, isi hanya akun yang benar-benar perlu.
sudo groupadd -f ssh-users
sudo usermod -aG ssh-users lab
sudo tee -a /etc/ssh/sshd_config.d/10-hardening.conf >/dev/null <<'EOF'
AllowGroups ssh-users
MaxAuthTries 3
EOF

sudo sshd -t && sudo sshd -T | grep -E '^(allowgroups|maxauthtries)'
  1. Uji dengan akun yang tidak masuk group tersebut. Hasil yang benar adalah penolakan, bukan prompt sandi.
ssh -p 2222 tamu@192.168.100.50 whoami
# Permission denied (publickey).
  1. Lapis 3 - batasi apa yang boleh dilakukan. Akun yang hanya perlu mengunggah file tidak perlu shell penuh.
sudo tee -a /etc/ssh/sshd_config.d/10-hardening.conf >/dev/null <<'EOF'
X11Forwarding no
PermitTunnel no
AllowAgentForwarding no
ClientAliveInterval 300
ClientAliveCountMax 2

Match Group sftp-guru
    ChrootDirectory /srv/sftp/%u
    ForceCommand internal-sftp
    DisableForwarding yes
    AllowTcpForwarding no
    PermitTTY no
EOF

sudo sshd -t && sudo sshd -T -C user=guru1,addr=192.168.100.60 | grep -E 'chrootdirectory|forcecommand|allowtcpforwarding|permittty'
  1. Folder chroot harus milik root dan tidak boleh bisa ditulis user β€” ini syarat yang diperiksa sshd tanpa kompromi.
sudo mkdir -p /srv/sftp/guru1/unggah
sudo chown root:root /srv/sftp/guru1 && sudo chmod 755 /srv/sftp/guru1
sudo chown guru1:guru1 /srv/sftp/guru1/unggah && sudo chmod 750 /srv/sftp/guru1/unggah
sftp -P 2222 guru1@192.168.100.50 <<< 'pwd; ls'
  1. Lapis 4 - batasi banyaknya dan lamanya. Tambahkan batas koneksi yang belum terautentikasi, lalu ukur efeknya.
sudo tee -a /etc/ssh/sshd_config.d/10-hardening.conf >/dev/null <<'EOF'
LoginGraceTime 20
MaxStartups 10:30:60
MaxSessions 3
EOF

sudo sshd -t && sudo systemctl reload ssh
time nc -w 30 192.168.100.50 2222
# koneksi diputus sekitar 20 detik, bukan menggantung
  1. Lapis 5 - tinggalkan bukti. Nyalakan log yang mencatat sidik jari kunci, lalu baca hasilnya.
sudo sed -i 's/^#\?LogLevel .*/LogLevel VERBOSE/' /etc/ssh/sshd_config.d/10-hardening.conf
sudo sshd -t && sudo systemctl reload ssh
sudo journalctl -u ssh -n 20 --no-pager
sudo grep -E 'Accepted|Failed|refused' /var/log/auth.log | tail -5
  1. Rekap akhir. Bandingkan potret awal dan akhir, lalu simpan sebagai bukti pekerjaan.
sudo sshd -T | sort > /root/sshd-akhir.txt
diff /root/sshd-awal.txt /root/sshd-akhir.txt

πŸ”Ή Enam uji rusak terkendali

Lakukan di VM latihan, bukan di server produksi.

  • A. Drop-in menimpa file utama β€” set PasswordAuthentication no di sshd_config, tapi buat 50-cloud-init.conf berisi yes. Status: login sandi tetap diterima. Bukti: sshd -T menampilkan yes. Artinya: yang berlaku bukan yang kamu baca.
  • B. Izin home terlalu terbuka β€” chmod 777 ~lab. Status: kunci ditolak. Bukti: Authentication refused: bad ownership or modes. Artinya: StrictModes melindungi, tapi juga bisa mengunci orang yang berhak.
  • C. Port di config, socket tidak β€” ubah Port 2222 tanpa menyentuh ssh.socket. Status: port 22 masih terbuka. Bukti: ss -tlnp menunjukkan dua port. Artinya: ada dua pintu, dan yang lama adalah yang paling sering dipindai.
  • D. AllowGroups dengan nama salah β€” tulis AllowGroups ssh-user. Status: semua login ditolak, termasuk admin. Bukti: log User lab not allowed because none of user's groups are listed in AllowGroups. Artinya: lapis 2 harus diuji dari sesi kedua.
  • E. Terlalu banyak kunci di agent β€” MaxAuthTries 3 dan klien membawa enam kunci. Status: Too many authentication failures untuk user yang sah. Bukti: log percobaan beruntun dengan sidik jari berbeda. Artinya: batas ketat butuh IdentitiesOnly yes di sisi klien.
  • F. Chroot bukan milik root β€” chown guru1 /srv/sftp/guru1. Status: SFTP mati total. Bukti: fatal: bad ownership or modes for chroot directory component. Artinya: kenyamanan user tidak boleh mengalahkan syarat keamanan chroot.

🏭 Dipakai di dunia kerja

  • Sekolah dan kampus: server nilai, CBT, dan e-rapor diakses dari lab, ruang guru, dan kadang dari rumah. AllowGroups plus kunci per guru membuat satu akun bocor tidak otomatis membuka semua data.
  • Kantor dan UMKM: satu server dipakai untuk aplikasi kasir, file sharing, dan backup. Memisahkan group admin dan sftp mencegah staf yang hanya perlu unggah laporan mendapat shell penuh.
  • Hosting dan VPS: penyedia menyediakan akses root lewat kunci, bukan sandi. PermitRootLogin no dan akun sudo terpisah membuat jejak audit tetap bisa ditunjuk saat insiden.
  • Industri dan manufaktur: mesin produksi diakses vendor lewat jalur terbatas. Match Address dan ForceCommand menjaga agar vendor hanya bisa menjalankan perintah uji yang disepakati, bukan menjelajah jaringan pabrik.
  • ISP dan NOC: perangkat dipantau 24 jam. Batas MaxStartups dan LoginGraceTime mencegah koneksi menggantung menghabiskan slot saat gangguan massal.
  • Remote worker dan developer: banyak kunci di laptop. Kebiasaan IdentitiesOnly yes dan passphrase kunci membuat MaxAuthTries ketat tetap nyaman dipakai.

βœ… Verifikasi

Yang dicek Perintah Hasil benar
Konfigurasi efektif sudo sshd -T nilai sesuai keinginan, bukan tebakan
Group yang diizinkan grep allowgroups hanya group yang kamu buat
Port yang benar-benar terbuka grep sshd satu port, pemiliknya jelas
Efek blok Match sudo sshd -T -C user=guru1,addr=192.168.100.60 chroot dan forcecommand muncul
Sandi benar-benar mati ssh -o PreferredAuthentications=password lab@host ditolak, bukan prompt sandi
Jejak login sudo journalctl -u ssh -n 20 ada baris Accepted publickey dan sidik jari
Konfigurasi tidak rusak sudo sshd -t keluar tanpa pesan

πŸ§ͺ Uji cepat: jalankan sudo sshd -T | grep -E 'passwordauthentication|allowgroups|maxauthtries'. Kalau tiga baris itu belum sesuai rencanamu, hardening belum selesai β€” sekeras apa pun kelihatannya file konfigurasimu.

⚠️ Kesalahan umum & troubleshooting

Gejala Penyebab Perbaikan
Masih bisa login pakai sandi drop-in lain menimpa cari dengan sshd -T, rapikan urutan nama file
sshd -T: Permission denied dijalankan tanpa root pakai sudo
Semua user ditolak AllowGroups salah nama perbaiki dari konsol, bukan SSH
bad ownership or modes home atau kunci terlalu terbuka chmod 700 ~/.ssh, chmod 600 authorized_keys
Port lama masih terbuka ssh.socket belum diubah edit unit socket, daemon-reload, restart socket
Too many authentication failures agent membawa banyak kunci IdentitiesOnly yes di klien
SFTP gagal setelah chroot folder chroot bisa ditulis user milik root, mode 755, subfolder untuk unggahan
Forwarding tetap jalan hanya AllowTcpForwarding no tambah DisableForwarding yes pada blok yang sama
Log tidak menunjukkan siapa masuk LogLevel masih INFO naikkan ke VERBOSE, lalu reload

πŸ” Catatan keamanan & etika

  • Jangan pernah menutup sesi terakhir sebelum sesi baru terbukti bisa masuk. Aturan ini menyelamatkan banyak server dari reinstall.
  • Kunci privat tidak boleh berpindah mesin lewat chat. Kalau terlanjur, cabut dari authorized_keys dan anggap bocor.
  • Beri passphrase pada kunci pribadi. Kunci tanpa passphrase di laptop yang hilang sama dengan sandi yang ditempel di monitor.
  • authorized_keys adalah daftar kunci, bukan tempat sampah. Kunci lama milik teknisi yang sudah keluar harus dihapus, bukan diabaikan.
  • Log SSH memuat data pribadi: nama user, alamat IP, sidik jari kunci. Jangan tempel log mentah ke grup pesan.
  • Uji hanya di lab sendiri. Mencoba MaxAuthTries atau brute force ke server orang lain adalah pelanggaran hukum, bukan latihan.
  • Kunci yang bocor bukan urusan teknis saja. Di sekolah, akun yang dipakai bersama berarti tidak ada nama yang bisa ditunjuk saat data berubah.

πŸ“Œ Kesimpulan

Hardening SSH adalah pekerjaan mempersempit pintu, bukan menghiasinya. Ganti port boleh, tapi itu lapis paling tipis. Yang menentukan adalah kunci yang dipakai, daftar orang yang diizinkan, ruang yang boleh dibuka, batas waktu, dan catatan yang ditinggalkan.

Kalau kamu hanya punya waktu untuk satu perbaikan hari ini, matikan login sandi dan pastikan kuncimu bekerja. Kalau punya waktu satu jam, tambahkan AllowGroups dan buktikan dengan sshd -T.

Langkah berikutnya: buka /etc/ssh/sshd_config.d/, baca semua file di dalamnya, lalu catat siapa yang sebenarnya berhak masuk ke servermu. Jawaban jujur dari pertanyaan itu biasanya lebih mengejutkan daripada isi konfigurasinya.

πŸ”— Materi terkait

πŸ“š Referensi