Tüm eğitimler
Rehber Linux · Network · OpenSSH OpenSSH

SSH Derinlemesine —
Tunnel, Config, Agent.

Ed25519 key'den ProxyJump'a, port forwarding'den SOCKS proxy'ye — SSH'ın tam potansiyeli.

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)
Transport LayerTCP bağlantısı kurulur. Diffie-Hellman (veya ECDH) ile oturum anahtarı üretilir. Sunucu host key'i ile kimliğini kanıtlar. ChaCha20-Poly1305 veya AES-GCM şifreleme, HMAC ile veri bütünlüğü sağlanır.
Authentication LayerClient kimliğini kanıtlar. Yöntemler: publickey (önerilen), password, keyboard-interactive. Başarılı kimlik doğrulaması connection layer'ı açar.
Connection LayerŞifreli tünel üzerinde birden fazla mantıksal kanal çoğullanır: terminal oturumu (shell), komut çalıştırma (exec), dosya transferi (sftp), port yönlendirme, agent forwarding.

ssh -v ile protokol adımları

ssh -v çıktısı (sadeleştirilmiş)
$ 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

ÖzellikSSHv1SSHv2
DurumObsolete — kullanmayınAktif standart
ŞifrelemeDES, 3DES — zayıfAES-GCM, ChaCha20
BütünlükCRC-32 — zayıfHMAC-SHA2, Poly1305
Kanal çoğullamaYokVar — bağlantı başına N kanal
SFTPYokStandart alt sistem
DİKKAT

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ı

ÖzellikRSA-2048RSA-4096Ed25519
Güvenlik seviyesi~112 bit~140 bit~128 bit
Public key boyutu~370 byte~720 byte68 byte
İmzalama hızıYavaşÇok yavaşÇok hızlı
Doğrulama hızıHızlıOrtaHızlı
Eski sistem desteğiEvrenselEvrenselOpenSSH 6.5+ (2014)
AlgoritmaRSA (PKCS#1)RSA (PKCS#1)Edwards-curve DSA

Ed25519 key üretimi (modern standart)

bash
# 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/id_ed25519Private key. 600 izinle korunmalı. Asla paylaşılmamalı — bu dosyayı kaybetmek veya sızdırmak tüm güvenliği tehlikeye atar.
~/.ssh/id_ed25519.pubPublic key. Sunuculara kopyalanacak dosya. İçerik: ssh-ed25519 AAAA... comment formatında tek satır.

RSA key — eski sistemler için

bash
# 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

bash
# 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
NOT

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

bash
# 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

bash (sunucuda)
# .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)
DİKKAT

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.

bash
# 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ğerDavranışKullanım
askYeni host için onay ister (varsayılan)İnteraktif kullanım
yesBilinmeyen host'u reddederGüvenlik kritik ortamlar
accept-newYeni host'u kabul eder, değişeni reddederAutomation güvenli
noHer host'u kabul eder, doğrulama yokSadece test/debug
bash (CI/CD pipeline örneği)
# 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

bash
# 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.

bash
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)
bash
# 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
DİKKAT

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ı

~/.ssh/config
# ─── Ü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

HostConfig bloğunun adı. ssh prod komutu bu bloğu tetikler. Wildcard destekler: Host *.internal.
HostNameGerçek hostname veya IP adresi. Host alias'ından farklı olabilir.
UserUzak sistemdeki kullanıcı adı.
IdentityFileBu host için kullanılacak private key dosyası.
ServerAliveIntervalSaniye cinsinden keep-alive paketi gönderme aralığı. 60 sn önerilir.
ControlMaster autoAynı host'a ikinci bağlantı açıldığında mevcut TCP bağlantısını yeniden kullanır. İlk bağlantı master channel'dır.
ControlPersist 10mMaster bağlantısını son client kapandıktan sonra 10 dakika daha açık tut. Sonraki bağlantılar anında açılır.

Match direktifi ile koşullu config

~/.ssh/config (Match örnekleri)
# 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

bash
# İ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 prod kı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

bash
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

bash
# İç 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

bash
# 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

bash
# 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

~/.ssh/config
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

bash
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ş

bash
# 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.

/etc/ssh/sshd_config (remote server)
# Remote forward'ı tüm interface'e aç
GatewayPorts yes

# Veya sadece client'ın istediği adresi kabul et
GatewayPorts clientspecified
bash
# 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

bash
# 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:
/etc/systemd/system/ssh-tunnel.service
[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

bash
# 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

bash
# 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

/etc/proxychains4.conf
strict_chain
proxy_dns
[ProxyList]
socks5  127.0.0.1  1080
bash
# 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

~/.ssh/config
Host socks-proxy
    HostName         remote-host.example.com
    User             emirp
    DynamicForward   1080
    RequestTTY       no
    ExitOnForwardFailure yes
bash
# 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"
NOT

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

bash
# 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

~/.ssh/config
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
bash
# Config ile artık doğrudan bağlanabilirsin
ssh web-01
ssh db-01.internal

Eski ProxyCommand yöntemi

~/.ssh/config (eski stil)
# 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

bash
# 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
NOT

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ı

/etc/ssh/sshd_config
# ─── 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

/etc/ssh/sshd_config
# 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
NOT

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

bash
apt install fail2ban
systemctl enable --now fail2ban
/etc/fail2ban/jail.local
[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
bash (fail2ban yönetimi)
# 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

bash
# 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

DirektifVarsayılanGüvenli DeğerAçıklama
PermitRootLoginprohibit-passwordnoRoot erişimini tamamen kapat
PasswordAuthenticationyesnoŞifre ile girişi kapat
MaxAuthTries63Brute-force sınırı
LoginGraceTime12030Auth için saniye
X11ForwardingnonoGUI forwarding gereksizse kapalı
PermitEmptyPasswordsnonoBoş şifreli hesaplara erişim yok
AllowUsers(herkese açık)listeYalnızca belirtilen kullanıcılar
ClientAliveInterval0300Ölü bağlantıları temizle
ClientAliveCountMax32Yanıt gelmezse bağlantıyı kes
DİKKAT

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