00 SSH mimarisi
SSH, üç katmanlı bir protokol ailesidir: transport layer şifreleme ve kimlik doğrulamayı, authentication layer kimlik kanıtlamayı, connection layer ise çok kanallı veri akışını yönetir.
Secure Shell (SSH), 1995'te Tatu Ylönen tarafından geliştirildi. Bugün pratik olarak her Linux yöneticisinin, gömülü sistem geliştiricisinin ve DevOps mühendisinin kullandığı bu protokol, yalnızca uzak terminal erişimi sağlamakla kalmaz; aynı zamanda güvenli dosya transferi, port yönlendirme, agent forwarding ve tünel altyapısı için sağlam bir temel oluşturur.
Üç katman
┌─────────────────────────────────────────────────────────┐
│ Connection Layer — shell, exec, sftp, port-forward │
├─────────────────────────────────────────────────────────┤
│ Authentication Layer — publickey, password, kbd-inter │
├─────────────────────────────────────────────────────────┤
│ Transport Layer — TCP, key exchange, şifreleme, MAC │
└─────────────────────────────────────────────────────────┘
TCP (port 22)
ssh -v ile protokol adımları
$ ssh -v user@host
OpenSSH_9.6p1, OpenSSL 3.2.0
# 1. TCP bağlantısı
debug1: Connecting to host [192.168.1.10] port 22.
debug1: Connection established.
# 2. Protokol sürüm müzakeresi
debug1: Remote protocol version 2.0, remote software version OpenSSH_9.6
# 3. Anahtar değişimi (key exchange)
debug1: kex: algorithm: curve25519-sha256
debug1: kex: host key algorithm: ssh-ed25519
# 4. Host key doğrulama
debug1: Server host key: ssh-ed25519 SHA256:...
debug1: Host 'host' is known and matches the ED25519 host key.
# 5. Kimlik doğrulama
debug1: Authenticating to host:22 as 'user'
debug1: Trying private key: ~/.ssh/id_ed25519
debug1: Authentication succeeded (publickey).
# 6. Kanal açılışı
debug1: channel 0: new session
SSHv1 vs SSHv2
| Özellik | SSHv1 | SSHv2 |
|---|---|---|
| Durum | Obsolete — kullanmayın | Aktif standart |
| Şifreleme | DES, 3DES — zayıf | AES-GCM, ChaCha20 |
| Bütünlük | CRC-32 — zayıf | HMAC-SHA2, Poly1305 |
| Kanal çoğullama | Yok | Var — bağlantı başına N kanal |
| SFTP | Yok | Standart alt sistem |
SSHv1, MITM saldırılarına karşı savunmasızdır ve modern OpenSSH tarafından tamamen kaldırılmıştır. Eski cihazlarda SSHv1 gören bir sshd varsa derhal kapatın veya firmware güncelleyin.
Bu bölümde
- Transport, Authentication, Connection katmanlarının rolleri
- -v ile TCP → kex → host key → auth → channel akışını izleme
- SSHv1 (obsolete) ve SSHv2 farkları
01 Anahtar üretimi
Modern SSH kimlik doğrulaması için Ed25519 tercih edilir: RSA-4096'ya eşdeğer güvenlik ile çok daha küçük key boyutu ve hızlı imzalama.
RSA vs Ed25519 karşılaştırması
| Özellik | RSA-2048 | RSA-4096 | Ed25519 |
|---|---|---|---|
| Güvenlik seviyesi | ~112 bit | ~140 bit | ~128 bit |
| Public key boyutu | ~370 byte | ~720 byte | 68 byte |
| İmzalama hızı | Yavaş | Çok yavaş | Çok hızlı |
| Doğrulama hızı | Hızlı | Orta | Hızlı |
| Eski sistem desteği | Evrensel | Evrensel | OpenSSH 6.5+ (2014) |
| Algoritma | RSA (PKCS#1) | RSA (PKCS#1) | Edwards-curve DSA |
Ed25519 key üretimi (modern standart)
# Ed25519 key çifti üret
ssh-keygen -t ed25519 -C "emirp@workstation"
# -C: yorum alanı — genellikle user@host veya tarih
# Dosya yolu belirt
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -C "prod server key"
# Passphrase ile (önerilen)
Enter passphrase (empty for no passphrase): güçlü-bir-parola
Enter same passphrase again: güçlü-bir-parola
Üretim sonucunda iki dosya oluşur:
ssh-ed25519 AAAA... comment formatında tek satır.RSA key — eski sistemler için
# RSA 4096 bit — Ed25519 desteklemeyen eski OpenSSH sürümleri için
ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa_legacy -C "legacy-device"
Fingerprint doğrulama
# Public key fingerprint'i göster (SHA-256)
ssh-keygen -l -f ~/.ssh/id_ed25519.pub
# → 256 SHA256:xXxXxX... emirp@workstation (ED25519)
# MD5 formatında (eski araçlar için)
ssh-keygen -l -E md5 -f ~/.ssh/id_ed25519.pub
# Mevcut tüm key'lerin fingerprint'i
for f in ~/.ssh/*.pub; do
ssh-keygen -l -f "$f"
done
Passphrase olmayan key, private key dosyasını ele geçiren herkesin tüm sunuculara doğrudan erişmesini sağlar. Passphrase kullanın ve ssh-agent ile günlük kullanım konforunu koruyun. Private key dosyasını asla bulut depolama veya versiyon kontrolüne eklemeyin.
Bu bölümde
- Ed25519: 68 byte public key, ~128 bit güvenlik, çok hızlı imzalama
- -t ed25519 -C "yorum" ile modern key üretimi
- ~/.ssh/id_ed25519 (private) ve ~/.ssh/id_ed25519.pub (public)
- -l -f ile fingerprint doğrulama
02 Sunucuya key kopyalama ve authorized_keys
Public key'i sunucuya taşımak için ssh-copy-id kullanın; izin sorunları ve known_hosts yönetimi bu bölümde ele alınmaktadır.
ssh-copy-id ile otomatik kopyalama
# Public key'i uzak sunucuya ekle (password ile kimlik doğrular, sonra key'i ekler)
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@192.168.1.10
# Özel port için
ssh-copy-id -i ~/.ssh/id_ed25519.pub -p 2222 user@host
# Başarılı çıktı:
# Number of key(s) added: 1
# Now try logging into the machine: ssh 'user@192.168.1.10'
Manuel kopyalama
# .ssh dizini ve authorized_keys dosyasını oluştur
mkdir -p ~/.ssh
chmod 700 ~/.ssh
# Public key'i ekle (>> ile var olanı silme)
cat ~/.ssh/id_ed25519.pub >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
# Sahiplik kontrolü
ls -la ~/.ssh/
# drwx------ .ssh/ (700)
# -rw------- authorized_keys (600)
SSH daemon, ~/.ssh dizini veya authorized_keys dosyası için izinler yanlışsa key authentication'ı sessizce reddeder. Dizin 700 (rwx------), dosya 600 (rw-------) olmalıdır. Dosyanın sahibi login eden kullanıcı olmalıdır.
known_hosts: host key parmak izi
İlk kez bağlandığınızda SSH, sunucunun host key'ini ~/.ssh/known_hosts dosyasına kaydeder. Sonraki bağlantılarda bu key değişmişse MITM uyarısı verilir.
# Script ile known_hosts'u önceden doldur (CI/CD pipeline için)
ssh-keyscan -H 192.168.1.10 >> ~/.ssh/known_hosts
ssh-keyscan -H host.example.com >> ~/.ssh/known_hosts
# -H: hostname'i hash'le (known_hosts okunabilirliğini azaltır, güvenliği artırır)
# Değişen host key temizleme (sunucu yeniden kuruldu ise)
ssh-keygen -R 192.168.1.10
ssh-keygen -R host.example.com
StrictHostKeyChecking seçenekleri
| Değer | Davranış | Kullanım |
|---|---|---|
ask | Yeni host için onay ister (varsayılan) | İnteraktif kullanım |
yes | Bilinmeyen host'u reddeder | Güvenlik kritik ortamlar |
accept-new | Yeni host'u kabul eder, değişeni reddeder | Automation güvenli |
no | Her host'u kabul eder, doğrulama yok | Sadece test/debug |
# Pipeline'da güvenli yeni host kabul etme
ssh -o StrictHostKeyChecking=accept-new user@deploy-host "./deploy.sh"
# Veya known_hosts'u önceden doldur + strict kullan
ssh-keyscan -H deploy-host >> ~/.ssh/known_hosts
ssh -o StrictHostKeyChecking=yes user@deploy-host "./deploy.sh"
Bu bölümde
- ssh-copy-id -i key.pub user@host ile otomatik key kurulumu
- ~/.ssh 700 ve authorized_keys 600 izin gereksinimleri
- ~/.ssh/known_hosts ve host key doğrulama
- ssh-keyscan -H ile script tabanlı pre-population
- StrictHostKeyChecking: ask / yes / accept-new / no
03 ssh-agent ve key forwarding
ssh-agent, private key'i bellekte şifresiz olarak tutar; passphrase'i bir kez girerek tüm oturum boyunca kullanırsınız.
Agent başlatma ve key ekleme
# Yeni bir shell'de agent başlat
eval $(ssh-agent -s)
# → Agent pid 1234
# Ed25519 key'i agent'a ekle (passphrase bir kez sorulur)
ssh-add ~/.ssh/id_ed25519
# Enter passphrase for /home/user/.ssh/id_ed25519: ...
# Identity added: /home/user/.ssh/id_ed25519 (emirp@workstation)
# TTL ile ekle: 3600 saniye sonra agent'tan silinir
ssh-add -t 3600 ~/.ssh/id_ed25519
# Yüklü key'leri listele
ssh-add -l
# → 256 SHA256:... emirp@workstation (ED25519)
# Tüm key'leri agent'tan kaldır
ssh-add -D
SSH_AUTH_SOCK ortam değişkeni
Agent, SSH_AUTH_SOCK ortam değişkeniyle iletişim kuracak Unix socket'in yolunu dışa aktarır. SSH client bu değişkeni okuyarak agent'a ulaşır.
echo $SSH_AUTH_SOCK
# → /tmp/ssh-XXXXXX/agent.1234
# Agent çalışıyor mu kontrol et
if [[ -z "$SSH_AUTH_SOCK" ]]; then
echo "Agent yok, başlatılıyor..."
eval $(ssh-agent -s)
ssh-add ~/.ssh/id_ed25519
fi
Agent forwarding: -A ile zincirleme bağlantı
Agent forwarding, uzak bir sunucudayken başka bir sunucuya kendi local key'inizi kullanarak bağlanmanızı sağlar. Uzak sunucuya private key kopyalamaya gerek kalmaz.
local (key burada) ──ssh -A──▶ bastion ──ssh──▶ internal-server
│
agent forward socket
(SSH_AUTH_SOCK bastion'da da çalışır)
# Agent forwarding ile bastion'a bağlan
ssh -A user@bastion.example.com
# Bastion'dan internal-server'a geç (local agent kullanılır)
user@bastion:~$ ssh user@internal-server.local
Agent forwarding, bastion sunucusundaki root veya başka kullanıcıların agent socket'inizi kötüye kullanmasına izin verebilir. Sadece tam güvendiğiniz sunucularda -A kullanın. Alternatif: ProxyJump (Bölüm 08) — key'inizi hiç uzak sunucudan geçirmez.
Bu bölümde
- eval $(ssh-agent -s) ile agent başlatma
- ssh-add -t 3600 ile TTL'li key ekleme
- SSH_AUTH_SOCK: agent-client iletişim socket'i
- -A ile agent forwarding ve güvenlik riski
04 ~/.ssh/config dosyası
SSH config dosyası, sık kullanılan bağlantı parametrelerini alias'larla tanımlar; uzun komut satırı seçenekleri yazmak yerine ssh prod gibi kısa isimlerle bağlanabilirsiniz.
Temel yapı
# ─── Üretim sunucusu ───────────────────────────────────────────
Host prod
HostName 10.20.30.40
User ubuntu
IdentityFile ~/.ssh/prod_ed25519
Port 22
ForwardAgent no
# ─── Geliştirme sunucusu ──────────────────────────────────────
Host dev
HostName dev.company.internal
User emirp
IdentityFile ~/.ssh/id_ed25519
Port 22
# ─── Bastion (jump host) ──────────────────────────────────────
Host bastion
HostName bastion.example.com
User emirp
IdentityFile ~/.ssh/id_ed25519
# ─── İç ağ sunucuları (bastion üzerinden) ─────────────────────
Host internal-*
User emirp
ProxyJump bastion
IdentityFile ~/.ssh/id_ed25519
# ─── Tüm bağlantılar için genel ayarlar ───────────────────────
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
ControlMaster auto
ControlPath ~/.ssh/cm_%h_%p_%r
ControlPersist 10m
AddKeysToAgent yes
Direktifler
ssh prod komutu bu bloğu tetikler. Wildcard destekler: Host *.internal.Match direktifi ile koşullu config
# Sadece belirli bir kullanıcı için geçerli
Match User deploy
IdentityFile ~/.ssh/deploy_key
ForwardAgent no
# Belirli bir network'te (exec ile)
Match exec "ip route | grep -q '10.20.0.0/16'"
ProxyJump none
Connection multiplexing — performans
# İlk bağlantı — master channel oluşturulur
ssh prod
# → Yeni TCP bağlantısı, kex, auth (normal süre: ~300ms)
# İkinci bağlantı — mevcut channel'ı paylaşır
ssh prod
# → Anında bağlantı (~10ms) — kex ve auth tekrar yok
# Aktif ControlMaster socket'lerini listele
ls ~/.ssh/cm_*
Bu bölümde
- Host alias ile
ssh prodkısayolları - ServerAliveInterval + ServerAliveCountMax ile keep-alive
- ControlMaster auto + ControlPersist 10m ile bağlantı multiplexing
- Match direktifi ile koşullu konfigürasyon
05 Port forwarding — Local (-L)
Local forwarding, uzak bir ağdaki servisi yerel bir port üzerinden erişilebilir kılar; güvenli tünel içinden geçer.
Sözdizimi
ssh -L [bind_address:]local_port:target_host:target_port user@jump_host
local:local_port ──SSH tünel──▶ jump_host ──TCP──▶ target_host:target_port localhost:5432 ──────────────▶ jump ──────▶ db.internal:5432
Pratik senaryo 1: uzak veritabanına yerel erişim
# İç ağdaki PostgreSQL'e yerel erişim
ssh -L 5432:db.internal:5432 -N -f emirp@jump.example.com
# -N: shell açma, sadece forward
# -f: background'a gönd
# Artık local 5432'ye bağlanarak db.internal'a ulaşırsın:
psql -h localhost -p 5432 -U dbuser mydb
Pratik senaryo 2: iç ağ Grafana'sına yerel erişim
# Grafana iç ağda 3000 portunda çalışıyor
ssh -L 8080:grafana.internal:3000 -N emirp@jump.example.com
# Tarayıcıda: http://localhost:8080 → grafana.internal:3000
# Veya config üzerinden (arka planda):
ssh -L 8080:grafana.internal:3000 -N -f jump
Diğer makinelere açma: GatewayPorts
# 0.0.0.0 ile tüm interface'e bind et (aynı subnet'teki makineler erişebilir)
ssh -L 0.0.0.0:8080:target.internal:80 -N emirp@jump
# sshd_config'de şu ayar gerekli:
# GatewayPorts yes ← veya clientspecified
# NOT: varsayılan sadece localhost'a bind eder
~/.ssh/config ile local forward
Host grafana-tunnel
HostName jump.example.com
User emirp
LocalForward 8080 grafana.internal:3000
LocalForward 5432 db.internal:5432
RequestTTY no
ExitOnForwardFailure yes
Bu bölümde
- -L local_port:target:target_port sözdizimi
- -N (shell açma) ve -f (background) kombinasyonu
- PostgreSQL ve Grafana tünel senaryoları
- GatewayPorts ile tüm interface'e bind
06 Port forwarding — Remote (-R)
Remote forwarding, yerel makinenizdeki bir servisi uzak sunucu üzerinden dışarıya açar; NAT arkasındaki uygulamaları internet'e sunmak için kullanılır.
Sözdizimi
ssh -R [bind_address:]remote_port:local_host:local_port user@remote_server
local:local_port ◀──SSH tünel── remote_server:remote_port ◀── dış dünya localhost:3000 ◀───────────── public-server:8080 ◀── browser
Pratik senaryo: yerel geliştirme sunucusunu paylaş
# Yerel 3000 portundaki dev server'ı public-server:8080'den eriştir
ssh -R 8080:localhost:3000 -N emirp@public-server.example.com
# public-server'ı ziyaret eden kullanıcı http://public-server:8080'e girebilir
# trafik SSH tüneli üzerinden yerel 3000'e gelir
GatewayPorts: tüm interface'e açma
Varsayılan olarak remote forward sadece uzak sunucunun 127.0.0.1 adresine bind olur. Tüm internet'e açmak için /etc/ssh/sshd_config düzenlenmesi gerekir.
# Remote forward'ı tüm interface'e aç
GatewayPorts yes
# Veya sadece client'ın istediği adresi kabul et
GatewayPorts clientspecified
# 0.0.0.0 ile tüm interface'e bind (GatewayPorts clientspecified gerekli)
ssh -R 0.0.0.0:8080:localhost:3000 -N emirp@public-server
autossh ile kalıcı tünel
# autossh: tünel koparsa otomatik yeniden bağlan
autossh -M 20000 -N -R 8080:localhost:3000 emirp@public-server
# -M 20000: monitoring port (0 ile devre dışı, ServerAlive kullan)
# systemd service olarak çalıştırmak için:
[Unit]
Description=SSH Remote Tunnel
After=network.target
[Service]
ExecStart=/usr/bin/autossh -M 0 -N \
-o ServerAliveInterval=30 \
-o ServerAliveCountMax=3 \
-R 8080:localhost:3000 \
emirp@public-server.example.com
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
Bu bölümde
- -R remote_port:local_host:local_port sözdizimi
- NAT arkasındaki servisi internet'e açma senaryosu
- GatewayPorts yes ile tüm interface'e bind
- autossh ve systemd ile kalıcı reverse tunnel
07 Dynamic forwarding: SOCKS proxy
Dynamic forwarding, SSH bağlantısını genel amaçlı bir SOCKS5 proxy'ye dönüştürür; tüm uygulama trafiğini şifreli SSH tünelinden geçirmenizi sağlar.
SOCKS proxy başlatma
# localhost:1080'de SOCKS5 proxy aç
ssh -D 1080 emirp@remote-host.example.com
# Arka planda çalıştır (shell yok, background)
ssh -D 1080 -N -f emirp@remote-host.example.com
# Farklı port ile
ssh -D 8888 -N -f emirp@remote-host.example.com
curl ile SOCKS proxy test
# SOCKS5 proxy üzerinden HTTP isteği
curl --socks5 localhost:1080 https://example.com
# DNS çözümleme de proxy üzerinden (SOCKS5h)
curl --socks5-hostname localhost:1080 https://internal-service.local
# IP adresini doğrula (proxy üzerinden ne görünüyor)
curl --socks5 localhost:1080 https://ifconfig.me
proxychains ile herhangi bir uygulamayı tünelden geçir
strict_chain
proxy_dns
[ProxyList]
socks5 127.0.0.1 1080
# Herhangi bir uygulamayı SOCKS proxy üzerinden çalıştır
proxychains4 -q nmap 10.20.30.0/24 -p 22,80,443
proxychains4 -q wget http://internal.host/file.tar.gz
proxychains4 -q python3 my_scanner.py
~/.ssh/config ile SOCKS proxy daemon
Host socks-proxy
HostName remote-host.example.com
User emirp
DynamicForward 1080
RequestTTY no
ExitOnForwardFailure yes
# Config ile başlat
ssh -N -f socks-proxy
# Tüm bağlantıları listele
ss -tlnp | grep 1080
# → 0.0.0.0:1080 ... ssh
# Proxy'yi durdur
pkill -f "ssh -N -f socks-proxy"
Tarayıcı proxy ayarı: Firefox → Ağ Ayarları → Manuel proxy → SOCKS Host: 127.0.0.1, Port: 1080, SOCKS v5. "Proxy DNS with SOCKS v5" seçeneğini işaretleyin — böylece DNS sorguları da tünel üzerinden gider.
Bu bölümde
- -D 1080 ile SOCKS5 proxy açma
- -N -f kombinasyonu: background daemon
- curl --socks5 ve curl --socks5-hostname ile test
- proxychains4 ile proxy-agnostic uygulama tünellemesi
08 ProxyJump ve bastion host
Bastion host pattern, iç ağa doğrudan erişim olmadan güvenli geçiş noktası sağlar; ProxyJump bunu tek komutla ve agent forwarding gerekmeksizin yapar.
Bastion host nedir
İnternet ──22──▶ bastion.example.com (public IP)
│
iç ağ geçidi
│
┌──────────────┼──────────────┐
▼ ▼ ▼
web-01.internal db-01.internal ci.internal
(private IP) (private IP) (private IP)
ProxyJump: tek adımda iç ağa
# bastion üzerinden internal-server'a bağlan
ssh -J emirp@bastion.example.com emirp@web-01.internal
# Kısa syntax (aynı user ise)
ssh -J bastion.example.com web-01.internal
# Çoklu hop: bastion1 → bastion2 → hedef
ssh -J bastion1.example.com,bastion2.internal emirp@final-target.internal
~/.ssh/config ile ProxyJump
Host bastion
HostName bastion.example.com
User emirp
IdentityFile ~/.ssh/id_ed25519
Host web-01
HostName web-01.internal
User emirp
ProxyJump bastion
IdentityFile ~/.ssh/id_ed25519
Host *.internal
User emirp
ProxyJump bastion
IdentityFile ~/.ssh/id_ed25519
# Config ile artık doğrudan bağlanabilirsin
ssh web-01
ssh db-01.internal
Eski ProxyCommand yöntemi
# ProxyJump desteklemeyen eski OpenSSH için
Host legacy-internal
HostName 10.20.30.50
User emirp
ProxyCommand ssh -W %h:%p emirp@bastion.example.com
# %h → hedef hostname, %p → hedef port
SCP ve SFTP ile ProxyJump
# Bastion üzerinden dosya kopyalama (scp)
scp -J bastion.example.com \
emirp@web-01.internal:/var/log/app.log \
./local-copy/
# Config tanımlıysa doğrudan:
scp web-01:/var/log/app.log ./
# SFTP ile
sftp -J bastion.example.com emirp@web-01.internal
ProxyJump, agent forwarding'in aksine private key'i bastion üzerinden geçirmez. SSH client, bastion'a bir TCP tüneli açar ve iç sunucuyla doğrudan el sıkışır. Bu nedenle ProxyJump, -A agent forwarding'den çok daha güvenlidir.
Bu bölümde
- Bastion host mimarisi: tek giriş noktası, iç ağ yalıtımı
- -J jump_host ile ProxyJump
- Çoklu hop: -J host1,host2
- Config'de ProxyJump ve wildcard host pattern
- Eski ProxyCommand -W %h:%p alternatifi
09 sshd hardening
Varsayılan SSH konfigürasyonu, üretim sunucuları için yeterince kısıtlayıcı değildir; temel güvenlik adımları ile saldırı yüzeyini önemli ölçüde azaltabilirsiniz.
Kritik sshd_config ayarları
# ─── Temel güvenlik ───────────────────────────────────────────
# Root login: key ile bile olsa kapatın — sudo ile yönetin
PermitRootLogin no
# Alternatif: PermitRootLogin prohibit-password (şifre yok, key olabilir)
# Şifre kimlik doğrulamasını kapat — sadece key kabul
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM yes
# ─── Erişim kısıtlaması ───────────────────────────────────────
# İzin verilen kullanıcılar (space-separated)
AllowUsers emirp deploy
# veya grup bazlı:
AllowGroups sshusers sudo
# ─── Brute-force koruma ───────────────────────────────────────
MaxAuthTries 3
LoginGraceTime 30
# ─── Gereksiz özellikleri kapat ───────────────────────────────
X11Forwarding no
PermitEmptyPasswords no
PrintMotd no
# ─── Keepalive (dead connection temizle) ─────────────────────
ClientAliveInterval 300
ClientAliveCountMax 2
# ─── Modern kriptografi ───────────────────────────────────────
KexAlgorithms curve25519-sha256,diffie-hellman-group16-sha512
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
# Değişiklikleri uygula:
# sudo sshd -t → config syntax kontrolü
# sudo systemctl reload sshd
Port değişikliği
# Varsayılan 22 yerine özel port (otomatik tarama trafiğini azaltır)
Port 2222
# SELinux/AppArmor varsa port için ek konfigürasyon gerekebilir
# Firewall güncelleme: ufw allow 2222/tcp
Port değiştirmek "güvenlik yoluyla gizlilik" (security through obscurity) değildir; gerçek güvenlik sağlamaz. Ancak 22 portundaki otomatik tarayıcı trafiğini ve log kirliliğini ciddi ölçüde azaltır. Gerçek güvenlik: PasswordAuthentication no + key only.
fail2ban kurulumu ve konfigürasyonu
apt install fail2ban
systemctl enable --now fail2ban
[DEFAULT]
bantime = 3600 # 1 saat ban
findtime = 600 # 10 dakika penceresi
maxretry = 5 # 5 başarısız denemede ban
ignoreip = 127.0.0.1/8 ::1 10.0.0.0/8
[sshd]
enabled = true
port = ssh
logpath = /var/log/auth.log
maxretry = 3 # SSH için daha katı
bantime = 86400 # 24 saat
# fail2ban durumu
fail2ban-client status sshd
# Banlı IP'leri listele
fail2ban-client status sshd | grep "Banned IP"
# IP ban kaldır
fail2ban-client set sshd unbanip 1.2.3.4
# Log izle
tail -f /var/log/fail2ban.log
ssh-audit ile konfigürasyon denetimi
# ssh-audit kurulumu
pip install ssh-audit
# veya: apt install ssh-audit
# Uzak sunucuyu denetle
ssh-audit host.example.com
# Yerel sshd konfigürasyonunu denetle (client mode)
ssh-audit -c
# JSON çıktısı (CI/CD entegrasyonu için)
ssh-audit --json host.example.com
Güvenli değer özet tablosu
| Direktif | Varsayılan | Güvenli Değer | Açıklama |
|---|---|---|---|
| PermitRootLogin | prohibit-password | no | Root erişimini tamamen kapat |
| PasswordAuthentication | yes | no | Şifre ile girişi kapat |
| MaxAuthTries | 6 | 3 | Brute-force sınırı |
| LoginGraceTime | 120 | 30 | Auth için saniye |
| X11Forwarding | no | no | GUI forwarding gereksizse kapalı |
| PermitEmptyPasswords | no | no | Boş şifreli hesaplara erişim yok |
| AllowUsers | (herkese açık) | liste | Yalnızca belirtilen kullanıcılar |
| ClientAliveInterval | 0 | 300 | Ölü bağlantıları temizle |
| ClientAliveCountMax | 3 | 2 | Yanıt gelmezse bağlantıyı kes |
PasswordAuthentication no yapmadan önce key authentication'ın çalıştığını doğrulayın. Yeni bir terminal oturumu açıp key ile bağlanabildiğinizden emin olun, sonra mevcut oturumunuzda sshd reload yapın. Aksi takdirde kendinizi kilitleyebilirsiniz.
Bu bölümde
- PermitRootLogin no ve PasswordAuthentication no zorunlu iki adım
- AllowUsers ile kullanıcı kısıtlaması
- MaxAuthTries 3, LoginGraceTime 30 brute-force önlemi
- fail2ban: /etc/fail2ban/jail.local ile SSH koruması
- ssh-audit ile konfigürasyon güvenlik denetimi