6 puan yazan GN⁺ 2024-09-20 | 1 yorum | WhatsApp'ta paylaş
  • SSH tünelleme, güvenli bir SSH bağlantısı üzerinden TCP trafiği taşıyarak eski protokolleri şifrelemek, yönetim panellerine erişmek ve NAT arkasındaki sunuculara bağlanmak gibi kısıtlı yolları güvenli biçimde açmak için kullanılır
  • Sunucu tarafında AllowTcpForwarding yes gerekir; loopback olmayan bir arayüzde port açmak için GatewayPorts yes ayarı ve SSH sunucusunun yeniden başlatılması gerekir
  • ssh -J, ssh -L, ssh -R, ssh -D sırasıyla jump host, yerel yönlendirme, uzak yönlendirme ve SOCKS5 tabanlı dinamik yönlendirmeden sorumludur
  • Tüneli arka planda tutmak için ssh -fN kullanılır; kopma algılama ise ClientAliveInterval ve ClientAliveCountMax gibi heartbeat ayarlarıyla düzenlenir
  • SSH tünelleme UDP’yi doğrudan desteklemez ve TCP-over-TCP’de gecikme ile bant genişliği sorunları oluşabilir; bu yüzden VPN alternatifi olmaktan çok belirli TCP yollarını açan bir araca daha yakındır

SSH tünellemenin kullanıldığı durumlar

  • SSH tünelleme ve port yönlendirme, TCP trafiğini bir SSH bağlantısı üzerinden istemciden sunucuya veya sunucudan istemciye iletir
  • TCP portları ve UNIX soketleri kullanılabilir, ancak örnekler TCP portları odaklıdır
  • Başlıca kullanım biçimleri güvenlik, sorun giderme ve bağlantı etrafında toplanır
    • Güvenlik
      • FTP gibi güvenli olmayan bağlantıları veya eski protokolleri şifreler
      • Açık anahtar kimlik doğrulamasına dayalı SSH tüneliyle web yönetim paneline erişir
      • 80/443 gibi ek portları dışa açmadan yalnızca 22 numaralı portu açmayı sağlar
    • Sorun giderme
      • Güvenlik duvarlarını veya içerik filtrelerini aşar
      • Farklı bir ağ rotası seçer
    • Bağlantı
      • NAT arkasındaki sunucuya erişir
      • Bir jump host üzerinden internetten iç sunucuya girer
      • Yerel portu internete açar

Port yönlendirmeden önce kontrol edilecek ayarlar

  • Örneklerdeki seçenekler ortama göre birleştirilerek yapılandırılabilir
  • bind_address belirtilmezse varsayılan değer localhost olur
  • Yerel ve uzak kullanıcıların ilgili makinelerde port açma yetkisi olmalıdır
    • 0-1024 arası portlar, özel bir ayar yoksa root yetkisi gerektirir
    • Diğer portlar normal kullanıcılar tarafından da ayarlanabilir
    • İstemci ve ağ güvenlik duvarları da yönlendirme yoluna uygun şekilde açık olmalıdır
  • SSH sunucusunda port yönlendirme etkin olmalıdır
    • AllowTcpForwarding yes
    • Çoğu durumda varsayılan olarak etkin olsa da sunucu ayarlarının kontrol edilmesi gerekir
  • Bir portu 127.0.0.1 dışındaki bir arayüze yönlendirmek için SSH sunucusunda GatewayPorts etkinleştirilir
    • GatewayPorts yes
    • Ayardan sonra SSH sunucu servisi yeniden başlatılmalıdır

SSH jump host ve çok aşamalı tünel

  • ssh -J, bir veya daha fazla host üzerinden geçerek uzak host’a şeffaf biçimde bağlanmak için kullanılır
ssh -J user@REMOTE-MACHINE:22 -p 22 user@10.99.99.1
  • Varsayılan port 22 kullanılırken port gösterimi atlanabilir
  • REMOTE-MACHINE jump host olarak kullanıldığında bağlantı şu şekilde doğrulanır
[user@REMOTE-MACHINE]$ ss | grep -i ssh
tcp ESTAB 0 0 167.135.173.108:ssh 192.160.140.207:45960
tcp ESTAB 0 0 10.99.99.2:49770 10.99.99.1:ssh
  • Örnek adreslerin rolleri şöyledir
    • 167.135.173.108: REMOTE-MACHINE’in genel IP’si
    • 192.160.140.207: LOCAL-MACHINE’in genel IP’si
    • 10.99.99.2: REMOTE-MACHINE’in iç IP’si
    • 10.99.99.1: REMOTE-WEBAPP’in iç IP’si
  • Birden fazla jump host kullanırken virgülle ayrılır
ssh -J user@REMOTE-MACHINE:22,user@ANOTHER-REMOTE-MACHINE:22 -p 22 user@10.99.99.1

Yerel port yönlendirme

  • Yerel port yönlendirme ssh -L seçeneğini kullanır
  • İlk örnek, LOCAL-MACHINE üzerindeki 10.10.10.1:8001 adresini REMOTE-MACHINE üzerindeki localhost:8000 adresine iletir
ssh -L 10.10.10.1:8001:localhost:8000 user@REMOTE-MACHINE
  • REMOTE-MACHINE üzerinde yalnızca 127.0.0.1 adresine bind edilmiş web sunucusunun erişim günlüğü şöyle görünür
127.0.0.1 - - [30/Dec/2022 18:05:15] "GET / HTTP/1.1" 200
  • Bu istek LOCAL-MACHINE’den başlatılır
  • İkinci örnek, yerel 8001 portunu REMOTE-MACHINE üzerinden 10.99.99.1:8000 adresine iletir
ssh -L 8001:10.99.99.1:8000 user@REMOTE-MACHINE
  • REMOTE-WEBAPP’in web sunucusu erişim günlüğünde istek REMOTE-MACHINE’in iç IP’sinden gelmiş olarak kalır
10.99.99.2 - - [30/Dec/2022 21:28:42] "GET / HTTP/1.1" 200

Uzak port yönlendirme

  • Uzak port yönlendirme ssh -R seçeneğini kullanır
  • Örnek, REMOTE-MACHINE üzerindeki 8000 portunu yerel taraftaki localhost:8001 veya 10.10.10.2:8001 adresine iletir
ssh -R 8000:localhost:8001 user@REMOTE-MACHINE
ssh -R 8000:10.10.10.2:8001 user@REMOTE-MACHINE
  • Belirli bir uzak arayüz olan 10.99.99.2:8000 üzerinde dinleyecek şekilde de ayarlanabilir
ssh -R 10.99.99.2:8000:10.10.10.2:8001 user@REMOTE-MACHINE
  • Loopback arayüzü dışında bir yerde dinlemek için SSH sunucusunda GatewayPorts yes etkin olmalıdır

Dinamik port yönlendirme ve SOCKS5

  • Birden fazla port iletilirken SSH SOCKS protokolünü kullanır
  • SOCKS şeffaf bir proxy protokolüdür ve SSH en yeni sürüm olan SOCKS5’i kullanır
  • SOCKS5 sunucusunun varsayılan portu RFC 1928 içinde tanımlanan 1080’dir
  • İstemcinin uygulama katmanında veya OS katmanında SOCKS proxy kullanacak şekilde ayarlanması gerekir
  • ssh -D örneği 10.10.10.1:5555 üzerinde bir SOCKS proxy açar
ssh -D 10.10.10.1:5555 user@REMOTE-MACHINE
  • LOCAL istemcisinde bağlantı rotası curl ile test edilebilir
curl -L -x socks5://10.10.10.1:5555 brrl.net/ip
  • Doğru çalışırsa REMOTE-MACHINE’in genel IP’si döndürülür

SSH TUN/TAP tünelleme

  • -w bayrağıyla çift yönlü tünel oluşturulabilir
  • Arayüzler önceden oluşturulmuş olmalıdır
  • Bu yöntem için test edilmediğine dair bir caveat kalır
-w local_tun[:remote_tun]

Arka planda çalıştırma ve kapatma

  • Tüneli yerel yöntemle arka planda çalıştırmak için -fN kullanılır
    • -f: Arka planda çalıştırma
    • -N: Kabuk açmaz
ssh -fN -L 8001:127.0.0.1:8000 user@REMOTE-MACHINE
  • Bunun dışında screen veya başka araçlar kullanılabilir
  • Arka planda çalışan SSH için süreç bulunur ve PID ile sonlandırılır
user@pleasejustwork:~$ ps -ef | grep ssh
[...]
user 19255 1 0 11:40 ? 00:00:00 ssh -fN -L 8001:127.0.0.1:8000 user@REMOTE-MACHINE
[...]
kill 19255

SSH bağlantısını sürdürme ve yeniden bağlanma

  • SSH bağlantısını canlı tutmanın çeşitli yolları vardır
  • Zaman aşımı işleme için heartbeat seçenekleri istemcide, sunucuda veya her ikisinde ayarlanabilir
  • ClientAliveInterval, bağlantıyı sürdürmek için her n saniyede bir istek gönderir
ClientAliveInterval 15
  • ClientAliveCountMax, karşı taraftan yanıt alınamadıktan sonra bağlantıyı sonlandırmadan önce gönderilecek heartbeat isteği sayısıdır
ClientAliveCountMax 3
  • 3 varsayılan değerdir; 0 olarak ayarlanırsa bağlantı sonlandırma devre dışı bırakılır
  • Örnek ayarda yanıt yoksa bağlantı yaklaşık 45 saniye sonra kesilir
  • Bağlantı sonlandıktan sonra yeniden bağlanmak için autossh, betikler, cronjob vb. kullanılabilir

Sınırlamalar ve güvenlik açısından dikkat edilmesi gerekenler

  • UDP

    • SSH, doğru şifre çözme için güvenilir aktarıma dayanır
    • UDP güvenilirlik sağlamadığı için SSH tünellerinde desteklenmez ve önerilmez
    • UDP over SSH tunneling ele alan bir yöntem vardır, ancak test edilmediğine dair bir caveat bulunur
  • TCP-over-TCP

    • Ek yük nedeniyle bant genişliği düşer ve gecikme artar
    • Paket kaybı veya yüksek gecikme olan bağlantılarda TCP meltdown yaşanabilir
    • TCP over TCP ile ilgili yazıya bakılabilir
    • OpenVPN-over-TCP bir süre kullanıldığında bant genişliği UDP’ye göre daha düşüktü, ancak kararlı çalıştı; sonuçlar yapılandırmaya büyük ölçüde bağlıdır
  • VPN alternatifi olarak kullanıldığında sınırlamalar

    • SSH tünelleme VPN gibi kullanılabilir, ancak daha iyi performans için VPN daha uygundur
  • Güvenlik riskleri

    • Bu özelliğe ihtiyaç yoksa devre dışı bırakılması önerilir
    • Saldırganlar SSH tünelleme ve port yönlendirmeyi kullanarak güvenlik duvarlarını ve diğer güvenlik önlemlerini aşabilir
  • Referans belgeler

1 yorum

 
GN⁺ 2024-09-20
Hacker News yorumları
  • 2024'te SSH komutlarını uzun uzun elle yazmak yerine ~/.ssh/config içinde LocalForward, RemoteForward, ProxyJump tanımlamak daha iyi
    Birden fazla ara SSH bağlantısından geçilmesi gereken uzak sunuculara ssh, scp, rsync ile erişirken ciddi zaman kazandırıyor
    Örneğin jump-host-1, jump-host-2, jump-host-3 zincirini ProxyJump ile kurup target-servera bir takma adla bağlanabilirsiniz
    LocalForward 0.0.0.0:8080 0.0.0.0:80, uzaktaki 80 numaralı portu yereldeki 8080'e yönlendirir; RemoteForward 0.0.0.0:9022 0.0.0.0:22 ise uzak tarafta 9022'ye gelen SSH isteklerini yereldeki 22 numaralı porta iletir
    LocalForward ve RemoteForward içinde soldaki hedef sunucu, sağdaki ise yereldir; ayrıca localhost ya da 127.0.0.1 yerine 0.0.0.0 kullanılması yönünde bir ipucu da var

    • ssh_config ipucu paylaşacak olursam, evde ya da kendi barındırdığınız VPN içindeyken her cihaza doğrudan SSH ile bağlanıp, dışarıdayken jump host üzerinden otomatik dallanan bir yapı kullanışlı oluyor
      Match host *.example.org exec "getent ahosts router.example.org | grep -q ^10.0.0.1" gibi bir yöntemle önce yönlendirici adresinden ev/VPN durumunu algılayıp, arp ile MAC adresi beklenen değerle eşleşmiyorsa ProxyJump jump.example.org kullanılmasını sağlayabilirsiniz
      Sıra önemli; önce VPN/ev ağı algılanmalı, sonra dışarıdaysanız jump host uygulanmalı
    • Bazen iş tek seferliktir ve bunun için yapılandırma dosyası oluşturmak istemezsiniz
      Kısa süreli bir VPS açıp SSH'ı SOCKS proxy olarak kullanarak bölgesel kısıtlamaları aşmak ya da başka bir takıma kısa süre yardım ederken normalde erişmediğiniz bir sunucuya bir kez girmeniz gerektiğinde komut satırı seçenekleri daha iyi olabilir
    • 0.0.0.0 kullanmak riskli olabilir
      Tüm ağ arayüzlerinde port açabilir ve özellikle uzak sunucuda güvenlik duvarı yoksa bir şeyi tüm internete açık hale getirebilir
      Sık kullanılan tünelleme ya da port yönlendirme için yapılandırma dosyası iyidir ama tek seferlik veya seyrek işler için komut satırı seçenekleri daha iyi olabilir
    • Bu tür SSH yapılandırmalarını birden fazla yerel makineye standartlaştırarak dağıtmak istiyorsanız bunu nasıl yönettiğinizi merak ediyorum
      Tek kullanıcı/çok makine senaryosuna uyan, ayrı bir sunucuyu sürekli açık tutmayı gerektirmeyen ve GitHub benzeri bir yerden yapılandırma çekebilen GitOps benzeri bir çözüm arıyorum
    • Her zaman bir kabuk açılmasını istemediğim için, yalnızca en az sayıda argümanı hatırlamanın yeterli olduğu temel bash/fish işlevleri oluşturdum
      Unutursam, belgelediğim işlev tanımlarına bakmam yeterli oluyor
  • Çalıştığım saçma kurumsal ortamda SSH tünelleme vazgeçilmez
    Erişim izni almak, port açtırmak ya da güvenlik duvarı/VPN istisnası elde etmek bazen bürokrasi yüzünden haftalar sürüyor
    Bu yazı -D seçeneğinden bahsediyor ama gücünü yeterince açıklamıyor
    ssh -D 8888 someserver çalıştırıp tarayıcının SOCKS proxy ayarını localhost:8888 yaparsanız, tüm tarayıcı trafiği someserver üzerinden yönlendirilir
    Firefox bunu hâlâ sistem varsayılanlarını değiştirmeden yapabildiği için çok kullanışlı

    • 2000'lerin ortasında ev dışından web'e erişirken bunu neredeyse standart yöntem olarak kullanıyordum
      Ama şirkete girince IP izin listeleri yüzünden internetteki rastgele sunuculara SSH bağlantısı bile kuramıyordum; o kadar bunaldım ki HTTP tüneli kurup kontrol ettiğim bir sunucuyu izin listesine ekletmenin yollarını araştırdım, sonra da sonunda iş değiştirdim
    • Kurumsal ağı atlatmak iyi bir fikir değil
      Bu tür kısıtlamaların bir nedeni vardır ve bunları aşmaya çalışmak, kurum süreçlerine ve güvenlik uzmanlığına saygısızlık ve onları önemsememe olarak görülebilir
      Erişim almak haftalar ya da aylar sürüyorsa beklemeniz gerekir; gizli bilgilere bir arka kapı açmanın ya da güvenliği zayıflatmanın sorumluluğunu üstlenmek istemezsiniz
  • Sabah 3'te yaptığım en dağınık SSH tünelleme işi, üç veri merkezi arasında bağlantı kurmaktı
    Aynı metro bölgede bulunan üç tesis internette üst ağa bağlıydı ama garip yönlendirme politikaları yüzünden A yalnızca B'ye, B de yalnızca C'ye bağlanabiliyordu
    Sonunda A'daki veriyi B üzerinden C'ye taşımak için rsync + SSH tüneli + anahtarlar + yönlendirme hileleri karışımı bir çözüm kurmak zorunda kaldım; sipariş formülü gibi komutları birkaç kez düzelttikten sonra her şeyin tek seferde çalıştığını görmek sihir gibiydi
    Bugün dönüp bakınca nasıl yapılacağı çok açık geliyor ama o zamanlar acemiydim; bu büyük bir başarıydı ve senkronizasyonun bittiğini doğruladığımdaki heyecanı hâlâ hatırlıyorum

    • ~/.ssh/config ve ProxyJump ile A, B, C, D, E gibi kaç adım olursa olsun fiilen sıçrayarak ilerleyebilirsiniz
  • Görselleştirmenin ayrıntıları güzel
    Özellikle ağ tarafında, daha düşük seviyeli bağlantılarda trafiği görsel olarak ifade eden çok daha fazla araç olmasını isterdim

  • Linux sunucunuz ya da IoT cihazınız güvenlik duvarının arkasındaysa ve sabit IP'si yoksa ama SSH ile erişmek istiyorsanız, https://sshreach.me gibi bir tünelleme hizmeti kullanabilirsiniz

  • Birkaç yıldır tünellemeyi epey kullandım ama -J seçeneğini bilmiyordum
    Birkaç ayda bir tünel gerektiğinde her seferinde 30 dakika uğraşmak yerine, tüneli sizin yerinize kuran görsel bir araç olsaydı keşke

  • TCP-over-TCP'nin ek yükü artırarak aktarım hızını düşürebileceği, gecikmeyi yükseltebileceği ve paket kaybı ya da uydu ağı gibi gecikmesi yüksek bağlantılarda TCP meltdown'a yol açabileceğine dair bir açıklama var
    Ancak SSH tünelinde, TAP/TUN kullanılmadığı sürece pratikte bu bir sorun olmuyor
    Çünkü SSH, TCP akışını açıp iletiyor
    Yine de birden çok kanal kullanıldığında head-of-line blocking nedeniyle performans düşebilir

  • Yaklaşık 15 yıl önce üniversite ağındaki güvenlik duvarını aşmak için SSH tünellemeyi öğrendim ve varsayılan portu 443 olarak değiştirmem gerekiyordu
    O zamandan beri de bunu sadece güvenlik duvarını aşmak için değil, çok daha çeşitli amaçlarla kullanmaya devam ediyorum

    • Güvenlik duvarını aşmak veya yerel servisleri ağın ötesine açmak dışında, başka hangi kullanım alanlarında faydasını gördüğünüzü merak ediyorum
  • sshuttle kullanırsanız tünelleme çok daha kolay olur
    sshuttle -r user@host 10.0.0.0/8 gibi kullanıldığında 10/8 aralığı otomatik olarak tünellenir ve fiilen SSH üzerinde bir VPN gibi çalışır

  • SSH'nin kendisinde bir yönlendirme özelliği olup olmadığını merak ediyorum
    Örneğin A, B'ye SSH ile bağlanmaya çalıştığında B'nin "C'ye bağlan" demesi ve A'nın saydam biçimde doğrudan C'ye bağlanması, böylece B'nin artık ana veri yolunda kalmaması gibi bir işlev var mı diye soruyorum

    • Sanal IP ile benzer bir şey yapılabiliyor gibi görünüyor
      Benim güvenlik duvarım/yönlendiricim DHCP option 67'yi düzgün iletmiyor ve her zaman kendi adresini gönderiyordu; bu yüzden ilgili porttaki PXE önyükleme trafiği yönlendirici IP'sine gittiğinde bunun gerçek PXE önyükleme sunucusuna yönlenmesi için sanal IP/kurallar tanımlamam gerekti
    • A, asıl hedefin C olduğunu bilmiyorsa bu yanıltıcı olabilir
      Öyle değilse sıçrama özelliği kullanılabilir: ssh -J B C
      B'nin yol üzerinde olması gerekmiyor ve C'ye doğrudan bağlanılabiliyorsa zaten doğrudan C'ye bağlanmak gerekir; bu mümkün değilse B zaten bir atlama noktası olarak işin içinde olmak zorundadır
    • B, C'ye port forwarding yani paket yönlendirme yapabilir, ancak HTTP'deki kalıcı yönlendirmeye denk bir özellik yok gibi görünüyor
      Sorunu biraz daha ayrıntılı anlatırsanız daha uygun bir çözüm bulunabilir
      Bir ölçüde gömülü bir host söz konusuysa DNS'in “yönlendirme” işini üstlenmesi sağlanabilir, ancak bu durumda host key fingerprint doğrulamasını kendiniz yapmanız gerekir