وصف المشكلة
لتلبية احتياجات التحكم عن بعد من Docker ، يمكن Docker توفير API على شبكة الإنترنت.
قد لا تتطلب واجهة برمجة التطبيقات هذه المصادقة على الإطلاق (وهو أمر محبط للغاية) ، أو تستخدم مصادقة الشهادة.
المشكلة هي أن مصادقة الشهادة الأصلية لا توفر التحقق من إلغاء الشهادة. وهذا يمكن أن يكون لها عواقب وخيمة.
أريد أن أخبر كيف حلت هذه المشكلة.
حل المشكلات
بادئ ذي بدء ، سأقول ما سأتحدث عن Docker for Windows. قد لا يكون Linux سيئًا للغاية ، ولكن ليس هذا الآن.
ماذا لدينا؟ لدينا عامل الميناء ، مع هذا النوع من التكوين:
{ "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" }
يمكن للعملاء الاتصال بشهاداتهم ، ولكن لم يتم التحقق من هذه الشهادات لإلغائها.
فكرة حل المشكلة هي كتابة خدمة البروكسي الخاصة بك ، والتي ستكون بمثابة وسيط. سيتم تثبيت خدمتنا على نفس الخادم مثل Docker ، وسوف تلتقط المنفذ 2376 ، وسوف تتواصل مع Docker عبر //./pipe/docker_engine.
بدون تفكير مرتين ، قمت بإنشاء مشروع ASP.NET Core وقمت بأبسط وكلاء:
أبسط رمز الوكيل 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); } } } });
كان هذا كافيًا للحصول على طلبات GET و POST البسيطة من Docker API. لكن هذا لا يكفي ، لأن لعمليات أكثر تعقيدًا (تتطلب إدخال المستخدم) ، يستخدم Docker شيئًا مشابهًا لـ WebSocket. كان الكمين هو رفض Kestrel رفضًا قاطعًا قبول الطلبات التي جاءت من عميل Docker ، مع الإشارة إلى أنه لا يمكن أن يكون هناك نص في الطلب مع رأس Connection: Upgrade. لكنه كان كذلك.
اضطررت إلى التخلي عن كيستريل وكتابة رمز أكثر بقليل. في الواقع - خادم الويب الخاص بك. افتح منفذًا بشكل مستقل ، وقم بإنشاء اتصال TLS ، وتحليل رؤوس HTTP ، وإنشاء اتصال داخلي مع Docker وتبادل تدفقات الإدخال / الإخراج. وانها عملت.
المصادر يمكن العثور عليها هنا .
لذلك ، تتم كتابة التطبيق وسيكون من الضروري تشغيله بطريقة أو بأخرى. والفكرة هي إنشاء حاوية مع تطبيقنا ، ورمي npine: // الداخل ونشر المنفذ 2376
بناء صورة عامل الميناء
لبناء الصورة ، نحتاج إلى شهادة عامة من المرجع المصدق (ca.cer) ، والتي ستصدر الشهادات للمستخدمين.
سيتم تثبيت هذه الشهادة في المراجع المصدقة لشهادات الجذر الموثوق بها للحاوية التي سيتم تشغيل وكيلنا بها.
تثبيته ضروري لإجراء التحقق من الشهادة.
لم أكن عناء كتابة مثل ملف Docker الذي أقوم ببناء التطبيق بنفسي.
لذلك ، يجب أن يتم تجميعها بشكل مستقل. من المجلد مع dockerfile ، قم بتشغيل:
dotnet publish -c Release -o ..\publish .\DockerTLS\DockerTLS.csproj
يجب أن يكون لدينا الآن: Dockerfile
، publish
، ca.cer
. نحن نجمع الصورة:
docker build -t vitaliyorg.azurecr.io/docker/proxy:1809 . docker push vitaliyorg.azurecr.io/docker/proxy:1809
بالطبع ، يمكن أن يكون اسم الصورة أي.
إطلاق
لبدء الحاوية ، نحتاج إلى شهادة الخادم certificate.pfx
وملف بكلمة password.txt
. جميع محتويات الملف تعتبر كلمة مرور. لذلك ، يجب ألا يكون هناك موجزات سطر إضافية.
دع كل هذه الأشياء موجودة في المجلد: c:\data
على الخادم حيث تم تثبيت Docker.
على نفس الخادم ، قم بتشغيل:
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
تسجيل
مع docker logs
يمكنك معرفة من فعل ما. يمكنك أيضًا رؤية محاولات الاتصال التي فشلت.