Taruh klien VPN di dalam kontainer dan Anda mendapatkan satu ruang nama dengan tunnel di dalamnya, bukan host yang merutekan seluruh trafiknya melalui VPN. Itu proyek yang terpisah, dan memperlakukannya sebagai satu proyek adalah cara kontainer berakhir dengan hak istimewa secara tidak sengaja. Panduan ini hanya mencakup yang pertama: satu image yang ditinjau, satu profil terlindungi, dan proses klien yang dibatasi pada ruang nama jaringannya sendiri.

Mulailah dari artefak yang sudah disetujui seseorang. Langkah-langkah di bawah mengasumsikan image yang berisi berkas eksekusi openvpn dan profil klien lengkap dengan sertifikat serta materi kunci yang sudah diselesaikan di dalam mount. Langkah ini tidak membangun perangkat lunak, tidak menerbitkan kredensial, dan tidak mencakup runtime tanpa root maupun kontainer Windows native, yang masing-masing mengubah jawabannya.

Apa yang didapat kontainer dan apa yang tidak

Simpan profil dan semua yang dirujuknya di direktori lokal dengan izin terbatas, di-mount sebagai hanya-baca. Path relatif di dalam profil harus diselesaikan di dalam mount tersebut; ini detail yang orang lewatkan ketika sertifikat berada satu direktori di atas profil dan kontainer tidak pernah melihatnya.

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"]

Berkas itu memberikan tiga hal dan tidak meminta apa pun lagi. Referensi image sebaiknya dipatok dengan digest jika kebijakan penerapan Anda mengatakannya, dan profilnya harus yang ditinjau, bukan salinan yang diedit seseorang di host.

Hanya-baca di sini berarti kontainer tidak dapat mengubah berkas Anda di host; bukan berarti kontainer tidak dapat membaca kunci privat yang Anda mount. Itulah inti dari mount, dan itulah sebabnya izin berkas, kepemilikan, dan bagaimana rahasia itu sampai ke host masih penting. Jangan pernah meneruskan kata sandi di baris perintah atau memanggangnya ke lapisan image, karena keduanya bertahan di tempat yang tidak dapat Anda bersihkan nanti.

Kapabilitas, entrypoint, dan jebakan di antaranya

Dua pengaturan diperlukan dan keduanya melakukan pekerjaan yang tidak saling terkait. NET_ADMIN memungkinkan manipulasi antarmuka dan rute di dalam ruang nama kontainer. Entri perangkat /dev/net/tun memungkinkan proses membuka perangkat tunnel sama sekali. Memberikan salah satunya tanpa yang lain menghasilkan kegagalan yang jelas, yang praktis: perangkat TUN yang hilang gagal saat dibuka, sedangkan kapabilitas yang hilang gagal ketika klien mencoba mengonfigurasi antarmuka.

Tidak satu pun dari itu membenarkan privileged: true. Kontainer dengan hak istimewa mendapat semua kapabilitas plus akses perangkat, dan itu jauh lebih besar daripada yang dibutuhkan beban kerja ini. referensi hak istimewa dan kapabilitas runtime menjelaskan sejauh mana pemberian itu menjangkau. Jika sebuah chart atau pos blog memintanya, periksa dulu apakah persyaratannya sebenarnya path perangkat yang hilang atau kapabilitas yang hilang.

Mengganti entrypoint adalah bagian yang menggigit. Memanggil openvpn secara langsung benar untuk image biasa dan salah untuk image produk apa pun yang skrip mulainya menyiapkan aturan firewall, berkas resolver, atau kredensial sebelum menjalankan daemon. Mengganti skrip itu melewati persiapan dan meninggalkan Anda men-debug tunnel yang muncul di ruang nama yang setengah dikonfigurasi.

Jalankan klien di latar depan dan biarkan ia menjadi proses utama kontainer. Proses yang menjadi daemon langsung keluar, kontainer restart dalam loop, dan log yang Anda butuhkan tersebar di seluruh restart yang semuanya tampak sama.

Verifikasi dari dalam ruang nama, bukan dari host

Naikkan stack, pastikan di log bahwa klien mencapai status terhubung, lalu periksa ruang nama yang benar-benar menampung tunnel.

docker compose up -d
docker compose logs --tail 40 vpn
docker compose exec vpn ip -br addr
docker compose exec vpn ip route

Daftar alamat seharusnya menunjukkan antarmuka tunnel dengan alamat dari pool, dan tabel rute seharusnya menunjukkan tujuan yang di-push mengarah ke sana. Jika antarmukanya tidak ada, klien tidak pernah mencapai titik membuatnya. Jika ada tetapi tidak ada rute yang memakainya, tempat mencarinya adalah push atau opsi rute.

Lalu uji tujuan yang Anda pedulikan, dari ruang nama yang seharusnya memakai tunnel, dengan aplikasi dan bukan hanya ping. Resolusi nama adalah kegagalan terpisah yang layak diuji secara eksplisit: alamat DNS yang di-push tidak memperbarui resolver kontainer dengan sendirinya, dan klien mandiri yang mengabaikan push akan menyelesaikan nama melalui apa pun yang dikonfigurasi image.

Status terputus adalah bagian dari kontrak

Perilaku sambung ulang memerlukan pemeriksaan sendiri, karena kebijakan restart membuktikan proses restart dan tidak mengatakan apa pun tentang apa yang dilakukan trafik di antaranya. Hentikan tunnel, coba tujuan yang dimaksudkan, dan perhatikan apakah koneksi ditolak, macet, atau diam-diam berhasil melalui rute biasa kontainer. Hasil terakhir itulah yang penting, dan itu tidak terlihat di log yang sehat.

Jika beban kerja tidak boleh pernah memakai jalur biasa, rancang itu secara eksplisit dengan aturan firewall dan sinyal kesiapan di dalam ruang nama. Kill switch adalah kebijakan yang Anda tulis dan uji, bukan properti yang Anda warisi dari menjalankan klien di kontainer.

Terakhir, ingat batasnya: rute ini hidup di ruang nama kontainer dan tidak menggantikan tabel perutean host. Aturan penerusan, penerjemahan, dan firewall milik Docker tetap menjadi bagian dari jalur luar, dan port yang dipublikasikan bukan antarmuka VPN.

Artikel terkait