Deskripsi masalah
Untuk kebutuhan remote control Docker, Docker dapat menyediakan API web.
API ini mungkin tidak memerlukan otentikasi sama sekali (yang sangat tidak disarankan), atau menggunakan otentikasi sertifikat.
Masalahnya adalah bahwa otentikasi sertifikat asli tidak menyediakan untuk pemeriksaan pencabutan sertifikat. Dan ini dapat memiliki konsekuensi serius.
Saya ingin memberi tahu bagaimana saya memecahkan masalah ini.
Pemecahan masalah
Pertama-tama, saya akan mengatakan apa yang akan saya bicarakan tentang Docker untuk Windows. Linux mungkin tidak terlalu buruk, tetapi sekarang tidak begitu.
Apa yang kita miliki Kami memiliki Docker, dengan konfigurasi seperti ini:
{ "hosts": ["tcp://0.0.0.0:2376", "npipe://"], "tlsverify": true, "tlscacert": "C:\\ssl\\ca.cer", "tlscert": "C:\\ssl\\server.cer", "tlskey": "C:\\ssl\\server.key" }
Klien dapat terhubung dengan sertifikat mereka, tetapi sertifikat ini tidak diperiksa untuk pencabutan.
Gagasan untuk menyelesaikan masalah adalah menulis layanan proxy Anda sendiri, yang akan bertindak sebagai perantara. Layanan kami akan diinstal pada server yang sama dengan Docker, ia akan mengambil port 2376, dan akan berkomunikasi dengan Docker melalui //./pipe/docker_engine.
Tanpa berpikir dua kali, saya membuat proyek Core ASP.NET dan melakukan proxy sederhana:
Kode Proxy Paling Sederhana app.Run(async (context) => { var certificate = context.Connection.ClientCertificate; if (certificate != null) { logger.LogInformation($"Certificate subject: {certificate.Subject}, serial: {certificate.SerialNumber}"); } var handler = new ManagedHandler(async (host, port, cancellationToken) => { var stream = new NamedPipeClientStream(".", "docker_engine", PipeDirection.InOut, PipeOptions.Asynchronous); var dockerStream = new DockerPipeStream(stream); await stream.ConnectAsync(NamedPipeConnectTimeout.Milliseconds, cancellationToken); return dockerStream; }); using (var client = new HttpClient(handler, true)) { var method = new HttpMethod(context.Request.Method); var builder = new UriBuilder("http://dockerengine") { Path = context.Request.Path, Query = context.Request.QueryString.ToUriComponent() }; using (var request = new HttpRequestMessage(method, builder.Uri)) { request.Version = new Version(1, 11); request.Headers.Add("User-Agent", "proxy"); if (method != HttpMethod.Get) { request.Content = new StreamContent(context.Request.Body); request.Content.Headers.ContentType = new MediaTypeHeaderValue(context.Request.ContentType); } using (var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, context.RequestAborted)) { context.Response.ContentType = response.Content.Headers.ContentType.ToString(); var output = await response.Content.ReadAsStreamAsync(); await output.CopyToAsync(context.Response.Body, 4096, context.RequestAborted); } } } });
Ini cukup untuk permintaan GET dan POST sederhana dari Docker API. Tetapi ini tidak cukup, karena untuk operasi yang lebih kompleks (membutuhkan input pengguna), Docker menggunakan sesuatu yang mirip dengan WebSocket. Serangan itu adalah bahwa Kestrel dengan tegas menolak untuk menerima permintaan yang datang dari Docker Client, mengutip fakta bahwa tidak ada badan dalam permintaan dengan header Connection: Upgrade. Tapi ternyata begitu.
Saya harus meninggalkan Kestrel dan menulis kode lagi. Bahkan - server web Anda sendiri. Buka porta secara independen, buat koneksi TLS, parsing HTTP header, buat koneksi internal dengan Docker dan tukar input / output stream. Dan itu berhasil.
Sumber dapat ditemukan di sini .
Jadi, aplikasi ini ditulis dan perlu untuk menjalankannya. Idenya adalah membuat wadah dengan aplikasi kita, melempar npine: // di dalam dan menerbitkan port 2376
Bangun gambar Docker
Untuk membangun gambar, kita memerlukan sertifikat publik dari otoritas sertifikasi (ca.cer), yang akan menerbitkan sertifikat kepada pengguna.
Sertifikat ini akan dipasang di otoritas sertifikat akar tepercaya dari wadah tempat proksi kami akan diluncurkan.
Menginstalnya diperlukan untuk prosedur verifikasi sertifikat.
Saya tidak repot menulis file Docker sehingga saya akan membangun aplikasi sendiri.
Karena itu, harus dirakit secara independen. Dari folder dengan dockerfile, jalankan:
dotnet publish -c Release -o ..\publish .\DockerTLS\DockerTLS.csproj
Kita sekarang harus memiliki: Dockerfile
, publish
, ca.cer
. Kami mengumpulkan gambar:
docker build -t vitaliyorg.azurecr.io/docker/proxy:1809 . docker push vitaliyorg.azurecr.io/docker/proxy:1809
Tentu saja, nama gambarnya bisa apa saja.
Luncurkan
Untuk memulai wadah, kita memerlukan sertifikat server certificate.pfx
dan file dengan kata password.txt
. Semua konten file dianggap sebagai kata sandi. Oleh karena itu, tidak boleh ada feed baris tambahan.
Biarkan semua ini berada di folder: c:\data
di server tempat Docker diinstal.
Di server yang sama, jalankan:
docker run --name docker-proxy -d -v "c:/data:c:/data" -v \\.\pipe\docker_engine:\\.\pipe\docker_engine --restart always -p 2376:2376 vitaliyorg.azurecr.io/docker/proxy:1809
Penebangan
Dengan docker logs
Anda dapat melihat siapa yang melakukan apa. Anda juga dapat melihat upaya koneksi yang gagal.