Docker'da OpenVPN: minimal bir istemcinin ihtiyaç duyduğu çalışma zamanı sözleşmesi
İncelenmiş bir imaj, korunan tek profil, TUN erişimi ve NET_ADMIN. Kapsayıcının ne aldığı, neyi almaması gerektiği ve tünelin çalıştığının nasıl kanıtlanacağı.
Bir VPN istemcisini kapsayıcıya koyun ve içinde tünel bulunan tek bir ad alanı elde edin; tüm trafiğini VPN üzerinden yönlendiren bir ana makine değil. Bunlar ayrı projelerdir ve onları tek gibi ele almak, kapsayıcıların kazara ayrıcalıklı hale gelmesinin yoludur. Bu kılavuz yalnızca ilkini kapsar: incelenmiş tek imaj, korunan tek profil ve kendi ağ ad alanına hapsedilmiş bir istemci süreci.
Birinin zaten onayladığı bir yapıttan başlayın. Aşağıdaki adımlar, openvpn çalıştırılabilir dosyasını ve sertifikası ile anahtar malzemesi montaj içinde çözülmüş eksiksiz bir istemci profilini içeren bir imaj varsayar. Yazılım derlemezler, kimlik bilgisi yayımlamazlar ve root olmayan çalışma zamanlarını ya da yerel Windows kapsayıcılarını kapsamazlar; bunların her biri yanıtı değiştirir.
Kapsayıcının ne aldığı ve ne almadığı
Profili ve ona başvuran her şeyi kısıtlı izinlere sahip yerel bir dizinde tutun, salt okunur olarak bağlayın. Profil içindeki göreli yollar bu bağlama içinde çözülmelidir; bu, sertifika profilin bir dizin üstünde olduğunda ve kapsayıcı onu hiç görmediğinde insanların gözden kaçırdığı ayrıntıdır.
services:
vpn:
image: ${VPN_CLIENT_IMAGE:?set the reviewed image reference}
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
volumes:
- ./vpn:/vpn:ro
working_dir: /vpn
entrypoint: ["openvpn"]
command: ["--config", "/vpn/client.ovpn"]
Bu dosya üç şey verir ve başka bir şey istemez. Dağıtım politikanız öyle diyorsa imaj referansı digest ile sabitlenmelidir ve profil incelenmiş olan olmalıdır, birinin ana makinede yerinde düzenlediği kopya değil.
Burada salt okunur, kapsayıcının ana makinedeki dosyalarınızı değiştiremeyeceği anlamına gelir; bağladığınız özel anahtarı okuyamayacağı anlamına gelmez. Bağlamanın bütün amacı budur ve bu yüzden dosya izinleri, sahiplik ve sırrın ana makineye nasıl geldiği hâlâ önemlidir. Parolayı asla komut satırında geçirmeyin ve imaj katmanına gömmeyin, çünkü ikisi de sonradan temizleyemeyeceğiniz yerlerde kalır.
Yetenekler, entrypoint ve aralarındaki tuzak
İki ayar gerekir ve ilgisiz işler yaparlar. NET_ADMIN kapsayıcının ad alanı içinde arayüz ve yol işlemlerine izin verir. /dev/net/tun aygıt girdisi, sürecin tünel aygıtını en azından açmasına izin verir. Birini diğeri olmadan vermek net bir hataya yol açar, bu da kullanışlıdır: eksik TUN aygıtı açılışta başarısız olur, eksik yetenek ise istemci arayüzü yapılandırmaya çalıştığında başarısız olur.
Bunlardan hiçbiri privileged: true ayarını haklı çıkarmaz. Ayrıcalıklı bir kapsayıcı tüm yetenekleri ve aygıt erişimini alır; bu, bu iş yükünün ihtiyaç duyduğundan çok daha büyük bir izindir. çalışma zamanı ayrıcalıkları ve yetenekleri başvurusu bu iznin nereye kadar uzandığını açıklar. Bir chart veya blog yazısı bunu istiyorsa, önce gereksinimin gerçekten eksik bir aygıt yolu mu yoksa eksik bir yetenek mi olduğunu kontrol edin.
entrypoint ayarını geçersiz kılmak, ısıran kısımdır. openvpn programını doğrudan çağırmak sıradan bir imaj için doğru, başlangıç betiği arka plan hizmetini çalıştırmadan önce güvenlik duvarı kuralları, çözümleyici dosyaları veya kimlik bilgileri hazırlayan her ürün imajı için yanlıştır. O betiği geçersiz kılmak hazırlığı atlar ve sizi yarı yapılandırılmış bir ad alanında ayağa kalkan tünelde hata ayıklamaya bırakır.
İstemciyi ön planda çalıştırın ve kapsayıcının ana süreci olmasına izin verin. Arka plan hizmetine dönüşen bir süreç hemen çıkar, kapsayıcı döngüde yeniden başlar ve ihtiyaç duyduğunuz günlükler hepsi aynı görünen yeniden başlatmalara dağılır.
Ad alanının içinden doğrulayın, ana makineden değil
Yığını kaldırın, günlükte istemcinin bağlı duruma ulaştığını doğrulayın, ardından tüneli gerçekten tutan ad alanını inceleyin.
docker compose up -d
docker compose logs --tail 40 vpn
docker compose exec vpn ip -br addr
docker compose exec vpn ip route
Adres listesi havuzdan bir adrese sahip tünel arayüzünü göstermeli, yol tablosu ise ona işaret eden itilen hedefleri göstermelidir. Arayüz yoksa istemci onu oluşturma noktasına hiç ulaşmamıştır. Varsa ama hiçbir yol onu kullanmıyorsa bakılacak yer push veya yol seçenekleridir.
Sonra önemsediğiniz hedefi, tüneli kullanması gereken ad alanından, yalnızca ping ile değil uygulama ile test edin. Ad çözümleme ayrı bir hatadır ve açıkça test edilmeye değer: itilen bir DNS adresi bir kapsayıcının çözümleyicisini kendiliğinden güncellemez ve push'u yok sayan bağımsız bir istemci adları imajın yapılandırdığı şey üzerinden çözer.
Bağlantısız durum sözleşmenin bir parçasıdır
Yeniden bağlanma davranışı kendi kontrolünü gerektirir, çünkü yeniden başlatma politikası sürecin yeniden başladığını kanıtlar ve bu arada trafiğin ne yaptığı hakkında hiçbir şey söylemez. Tüneli durdurun, amaçlanan hedefi deneyin ve bağlantının reddedildiğini, askıda kaldığını veya kapsayıcının olağan yolu üzerinden sessizce başarılı olduğunu gözlemleyin. Önemli olan son sonuçtur ve sağlıklı bir günlükte görünmez.
İş yükü olağan yolu asla kullanmamalıysa, bunu güvenlik duvarı kuralları ve ad alanı içinde bir hazır olma sinyaliyle açıkça tasarlayın. Kill switch, yazdığınız ve test ettiğiniz bir politikadır; kapsayıcıda istemci çalıştırarak devraldığınız bir özellik değildir.
Son olarak sınırı hatırlayın: bu yollar kapsayıcının ad alanında yaşar ve ana makinenin yönlendirme tablosunu değiştirmez. Docker'ın yönlendirme, çeviri ve güvenlik duvarı kuralları dış yolun parçası olarak kalır ve yayımlanan bağlantı noktası bir VPN arayüzü değildir.