Moby: وضع سرب الرصيف: تتعرض المنافذ في 127.0.0.1 إلى 0.0.0.0

تم إنشاؤها على ٢ أبريل ٢٠١٧  ·  53تعليقات  ·  مصدر: moby/moby

وصف

في وضع Docker swarm ، ينتج عن ربط منفذ بـ 127.0.0.1 فتح المنفذ عند 0.0.0.0 أيضًا. قد تكون هذه مشكلة أمنية خطيرة ويجب شرحها في الوثائق.

خطوات إعادة إظهار المشكلة:

  1. قم بإنشاء خدمة ، على سبيل المثال MongoDB ، في ملف docker-compose.swarm.yml ، وانشر المنفذ 27017 إلى المضيف المحلي:
  mongodb:
    image: mongo:3.2
    volumes:
      - ./persistent-data/mongodb:/data
      - ./persistent-data/mongodb/db:/data/db
    networks:
      data:
        aliases:
          - mongo.docker
    logging:
      driver: syslog
      options:
        syslog-address: "udp://10.129.26.80:5514"
        tag: "docker[mongodb]"
    ports:
      - "127.0.0.1:27017:27017"
    deploy:
      placement:
        constraints: [node.labels.purpose == main-data]
  1. انشر سربك
  2. تحقق مما إذا كان المنفذ مفتوحًا من خارج سربك باستخدام netcat

صِف النتائج التي تلقيتها:

nc -vz PUBLIC_NODE_IP 27017
found 0 associations
found 1 connections:
[...]
Connection to PUBLIC_NODE_IP port 27017 [tcp/*] succeeded!

صف النتائج التي توقعتها:
يكون المنفذ متاحًا فقط على 127.0.0.1 ، على الأقل في عقد السرب التي تشغل هذه الخدمة.

معلومات إضافية تعتبرها مهمة (على سبيل المثال ، تحدث المشكلة من حين لآخر فقط):

ناتج docker version :

Docker version 17.03.1-ce, build c6d412e

الناتج docker info :

معلومات عامل الميناء لمدير السرب:

Containers: 0
 Running: 0
 Paused: 0
 Stopped: 0
Images: 1
Server Version: 17.03.1-ce
Storage Driver: aufs
 Root Dir: /var/lib/docker/aufs
 Backing Filesystem: extfs
 Dirs: 3
 Dirperm1 Supported: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins: 
 Volume: local
 Network: bridge host macvlan null overlay
Swarm: active
 NodeID: pk7ulemi0z0chgtsg0azfrjz5
 Is Manager: true
 ClusterID: 27etomlyjvtmygrm6rcdgr2ni
 Managers: 1
 Nodes: 6
 Orchestration:
  Task History Retention Limit: 5
 Raft:
  Snapshot Interval: 10000
  Number of Old Snapshots to Retain: 0
  Heartbeat Tick: 1
  Election Tick: 3
 Dispatcher:
  Heartbeat Period: 5 seconds
 CA Configuration:
  Expiry Duration: 3 months
 Node Address: 10.129.26.165
 Manager Addresses:
  10.129.26.165:2377
Runtimes: runc
Default Runtime: runc
Init Binary: docker-init
containerd version: 4ab9917febca54791c5f071a9d1f404867857fcc
runc version: 54296cf40ad8143b62dbcaa1d90e520a2136ddfe
init version: 949e6fa
Security Options:
 apparmor
 seccomp
  Profile: default
Kernel Version: 4.4.0-64-generic
Operating System: Ubuntu 16.04.2 LTS
OSType: linux
Architecture: x86_64
CPUs: 1
Total Memory: 992.4 MiB
Name: <HIDDEN>
ID: IMOK:QIR7:WU5Y:WTPP:EPRQ:F77G:ULGE:WOG4:O7S7:6AFE:V7QG:2XEK
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Username: <HIDDEN>
Registry: https://index.docker.io/v1/
WARNING: No swap limit support
Experimental: false
Insecure Registries:
 127.0.0.0/8
Live Restore Enabled: false

تفاصيل إضافية عن البيئة (AWS و VirtualBox والمادية وما إلى ذلك):
تم اختباره على قطرات المحيط الرقمي.

areswarm kinbug

التعليق الأكثر فائدة

محبط حقًا لأن بعض مطوري Docker يتجاهلون عامين تقريبًا حالة استخدام صالحة ومفيدة للغاية عندما تكون هذه الوظيفة ضرورية: عندما تريد ربط قاعدة البيانات العلائقية المحتوية كخدمة سرب إلى الواجهة المحلية من أجل الوصول إليها بأمان عبر نفق SSH . حاليا هذا السيناريو من المستحيل القيام به.

ال 53 كومينتر

نعم يجب أن ينتج عن هذا خطأ ؛ الخدمات (افتراضيًا) "تنشر" باستخدام شبكة "دخول" ، ولا تدعم تحديد عنوان IP ، حيث لا يمكن التنبؤ بأي عقدة ينتهي بها الأمر (وبالتالي لا تعرف ما هي عناوين IP المتاحة - على الرغم من 127.0 .0.1 ممكن). هذه المشكلة تتعقب هذه الميزة https://github.com/docker/docker/issues/26696 (وهذه "الملحمية" تتعقب خيارات أخرى غير مدعومة (حتى الآن) بواسطة الخدمات https://github.com/docker/docker/issues / 25303)

الخطأ هنا هو أن عامل الإرساء يجب أن ينتج خطأ ، بدلاً من تجاهل الخيار بصمت ؛ قابل للتكرار باستخدام هذا الحد الأدنى من ملف إنشاء عامل الإرساء ؛

version: "3.2"
services:
  mongodb:
    image: nginx:alpine
    ports:
      - "127.0.0.1:27017:80"

تضمين التغريدة pingdnephin vemeester

@ fer2d2 في وضع السرب ، إذا نشرت شيئًا ما ( ports مقابل stack deploy ) ، يتم نشره على شبكة ingress ، وبالتالي فهو متاح للجميع. هناك عدة طرق للالتفاف ، ولكن وضع kind/bug على ذلك لأنه يجب علينا على الأقل تحذير الناس من ذلك عند القيام بـ stack deploy مع المنافذ التي تحتوي على هذا الترميز (أي host:port:port ).

للتغلب على هذا ، هناك عدة طرق:

  • أولاً ، يجب عليك نشر منافذ mongo فقط إذا كنت تريدها أن تكون عامة ، وإلا فهي متاحة من خلال حزمة اكتشاف الاسم في docker (حاوية / خدمة أخرى على نفس الشبكة ستكون قادرة على الوصول إليها من خلال mongo dns name).
  • إذا كنت ترغب في نشره في المضيف وليس في ingress (لذلك ليس سربًا عامًا ، فقط على المضيف يعمل ، بنفس الطريقة كما هو الحال بدون وضع السرب) ، فأنت بحاجة إلى استخدام بناء جملة المنافذ الموسعة .
    ports:
      - mode: host
        target: 80
        published: 9005

سيفعل نفس الشيء مثل docker run -p 80:9005 … لذا فإنه سيربطه بـ 0.0.0.0 ، لكنه يقتصر على المضيف.

ولكن كما قال thaJeztah ، "الخطأ هنا هو أن عامل التحميل يجب أن ينتج خطأ ، بدلاً من تجاهل الخيار بصمت" 👼

/ ccmavenugoaboch لمعرفة ما إذا كانت هناك طريقة بالفعل من ربطها بملكية الفكرية معينة؟ (من الصعب حقًا تحقيقه لأن عنوان IP الخاص بالعقدة سيكون مختلفًا جدًا ..)

@ vemeester هل يمكنني تحديد المضيف المحلي باعتباره الهدف المضيف باستخدام هذا الترميز؟

    ports:
      - mode: host
        target: 127.0.0.1:80
        published: 9005

نظرًا لأنه تنسيق موسع لتكوين المنافذ ، يجب أن يعمل بشكل صحيح.

شكرا لك مقدما

يبدو أن كلاً من الهدف والمنشور يتم فرضهما كنوع عدد صحيح في بناء الجملة الطويل

أعتقد أن هذا ليس السلوك المرغوب إذا كنت تتصل ببعض الخدمات عبر أنفاق SSH. على سبيل المثال ، إذا كنت ترغب في الحصول على خادم MySQL أو MongoDB على 127.0.0.1 والاتصال عبر SSH Tunnel ، باستخدام Docker Swarm ، يجب عليك كشف منفذ قاعدة البيانات على 0.0.0.0 أو إنشاء حاوية قاعدة بيانات مخصصة مع تشغيل SSH بالداخل (وكلا الخيارين غير آمنين للغاية).

هناك العديد من عملاء قاعدة البيانات الذين يستخدمون أنفاق SSH ، مثل SQL Workbench أو Robomongo والتي لا يمكن استخدامها بسبب هذا القيد (ربط واجهة محدد).

لدينا نفس المشكلة في شركتنا مثل @ fer2d2 ، محاولة توصيل Mongobooster بسرب عامل التحميل عبر نفق ssh. الحل الوحيد الذي وجدناه هو فتح منفذ 27017 وحماية قاعدة البيانات بالمستخدم وكلمة المرور.

أى اخبار؟

+1

+1

حالة استخدام أخرى للسماح لعنوان IP_

هل يمكن أن يكون خيارًا عندما تحدد:

placement:
        constraints:
          - node.id ==

في صحتك

+1

+1

+1

بنفسي قمت بحل هذه المشكلة لذلك:

iptables -I DOCKER-USER -i eth0 -j DROP
iptables -I DOCKER-USER -m state --state RELATED,ESTABLISHED -j ACCEPT

لا يمس عامل الميناء هذه القواعد. فقط يضيف خاصتك
-A DOCKER-USER -j RETURN
نتيجة لذلك ، على الرغم من أن المنفذ يستمع إلى 0.0.0.0 إلا أنه لا يمكن الوصول إليه من الواجهة الخارجية eth0

هذا السلوك ينتهك "آمن افتراضيًا" ، ولن يكون وضع ملاحظة في المستندات جيدًا بما يكفي. في الوقت الحالي يجب أن يسبب خطأ.

كما أنها مرتبطة بالنمط: الدخول / المضيف (يبدو أن هاتين المسألتين مرتبكتان في المناقشة). لا يوجد شيء بخصوص وضع الدخول يجب أن يوقف ارتباط الخدمة بالعناوين المحلية على جميع العقد ، ولكن ليس بالعناوين الخارجية. لذلك يجب السماح بـ 127.xxx. (في الوضع غير السرب (باستخدام Docker run) ، أقوم بالربط بـ 127.0.0.2:80 و 127.0.0.3:80 وما إلى ذلك لاختبار عدة خوادم محليًا قيد التطوير.).

المشكلة الأخرى هي أن وضع الدخول هو الوضع الافتراضي. هذا غير متوقع ، ويؤدي أيضًا إلى مشكلة أمنية. لقد حاولت للتو بدء خدمة على عقدة مقيدة لتكون في جزء خاص من الشبكة ، مع منفذ مرتبط بـ 127.0.0.3:80. ثم تم ربطه أيضًا بالواجهة العامة للعقدة العامة. (هذا يتجاهل بصمت عنوان IP ، ويستخدم بصمت وضع الدخول ، وتزدهر بياناتي بشكل عام).

استخدم حالات

  • استخدام الحالات التي أثرت علي (حقيقية بالتأكيد)

    • 1 ربط بمنفذ عقدة معينة ، لأن المنفذ قيد الاستخدام على العقد الأخرى. يمكنك استخدام وضع المضيف لهذا ، ولكن الافتراضي هو مفاجأة.

    • 2 ربط بمنفذ عقدة معينة ، لأن العقد الأخرى لها واجهات عامة. يمكنك استخدام وضع المضيف لهذا ، ولكن الافتراضي ينتهك "آمن بشكل افتراضي" .

    • 3 قم بالربط محليًا لأنك لا تريده مرئيًا للمضيفين الآخرين ، افتراضيًا ينتهك "آمن افتراضيًا"

    • 4 اربط بـ 127.0.0.3 ، لأن آلة التطوير لديك بها الكثير من الأشياء ، و 127.0.0.1 قيد الاستخدام ، بواسطة هذا المنفذ. واستخدم /etc/hosts ، بحيث يتم إرسال كل اسم مجال إلى حاوية مختلفة. يعمل هذا مع docker run ، لكن ليس مع الإنشاء.

  • حالات استخدام أخرى

    • الارتباط بواجهة محددة مثل 192.168.0.x ، لأن هذه شبكة داخلية. الافتراضي ينتهك "آمن بشكل افتراضي"

    • الارتباط بعقدة معينة ، ولكن لا تقيد الخدمة للتشغيل على هذه العقدة. هذه حالة استخدام مماثلة لـ 1 أو 2 ، ولكن بدون استخدام القيود. سيتم توجيه حركة المرور من خلال السرب.

إذن باختصار

  • إن تجاهل عنوان IP والربط بـ 0.0.0.0 ، ووضع الدخول الافتراضي ، ينتهكان "آمنًا افتراضيًا". يجب إصدار الأخطاء إذا تم تحديد عنوان IP وتحديث المستندات. يجب إصدار خطأ إذا لم يتم تحديد الوضع (غير افتراضي) ، وتم تحديث المستندات. (يعمل هذا على إصلاح مشكلة الوضع ، وإيقاف مشكلات الأمان المفاجئة.)
  • يمكن بعد ذلك إضافة الدعم لعناوين IP في وضع المضيف.
  • يمكن إضافة دعم عناوين IP في وضع الإدخال ، الذي يقتصر على العناوين المحلية 127.xxx. (يجب التعامل مع العناوين المحلية المختلفة مثل 127.0.0.2 و 127.0.0.3 على أنها مختلفة (تم تمريرها للتو إلى نظام التشغيل)).

السماح بالربط بالعنوان المحلي مفيد للعقد المقيدة. السماح بالربط بعنوان معين ، سيعمل مع عقدة مقيدة ، أو يتم توجيهه عبر السرب إلى أحد العناوين الموجودة على إحدى العقد (قد يكون وضع الدخول فقط). تم هذا التوجيه بالفعل

@ richard-delorenzi لا يقبل موبي حتى عنوان IP مضيف حاليًا. لذلك خارج طلب الميزة ، يبدو هذا وكأنه مشكلة من جانب العميل ... على وجه التحديد كيف تتم ترجمة yaml في Docker CLI.

إن طريقة عمل ingress موثقة جيدًا ، لكن توافق على أن هذا سلوك سيء في CLI.

+1

+1

+1

لدي حل من الأنواع التي أستخدمها. أقوم بتشغيل حاويات مستقلة وربطها بشبكة تسمى "core" ، والتي تستخدمها جميع خدماتنا الخلفية (mongo ، elasticsearch ، influxdb ، إلخ) التي تعمل داخل سرب.

لا يمكنني رؤية كيفية القيام بذلك في ملف إنشاء ، لذلك نحن نشغل فقط حاويات مستقلة مثل:

docker run --name kibana --rm -d -v /var/lib/kibana:/usr/share/kibana/config -p 127.0.0.1:5601:5601 --network core docker.elastic.co/kibana/kibana:6.1.2

docker run --name chronograf --rm -d -v /var/lib/chronograf:/var/lib/chronograf -p 127.0.0.1:8888:8888 --network core chronograf:1.4 chronograf --influxdb-url=http://influxdb:8086

بعد البدء في ذلك ، يُظهر docker ps الحاويات الجديدة على أنها مرتبطة بـ 127.0.0.1. آمين. يمكنني بعد ذلك توجيه نفق إلى مضيف عامل الإرساء من محطة العمل المحلية الخاصة بي للوصول الآمن ، مثل:

ssh -i my_ssh_key.pem [email protected]  -L 8888:localhost:8888  -L 5601:localhost:5601 -N

من المستعرض الخاص بي ، يمكنني الاتصال بـ http: // localhost : 8888 أو http: // localhost : 5601

يعمل لدي.

في حالة إمكانية استبدال مأخذ UNIX بمقبس 127.0.0.1 TCP / IP ، يتوفر هنا حل بديل محتمل قمت بتطبيقه للبت بطلاقة

ربما تساعد إضافة خيار آخر إلى mode . شيء مثل local بالإضافة إلى host و ingress .

يرجى إزالة الصياغة "الأمان القابل للاستخدام: يوفر Moby إعدادات افتراضية آمنة دون المساس بقابلية الاستخدام." في ملف moby readme . هذا بالتأكيد إعلان كاذب ، انظر تعليق @ richard-delorenzi.

لا تنشر الخدمات المنافذ افتراضيًا ، لذلك لن يمكن الوصول إليها ما لم تحدد أنه يجب عليها نشر منفذ. الارتباط بعنوان IP محدد غير معتمد حاليًا ؛ إذا كان يجب ألا تكون خدمتك قابلة للوصول ، فلا تنشر المنافذ والاتصال بالخدمة باستخدام شبكة داخلية (تراكب).

تمت مناقشة إضافة دعم للربط بعنوان IP في https://github.com/moby/moby/issues/26696 ، ولكن ليس من السهل تنفيذها (مع مراعاة عناوين IP غير "المضيف المحلي")

تمت إضافة تحذير عند نشر مكدس ؛

docker stack deploy -c- test <<'EOF'
version: '3'
services:
  web:
    image: nginx:alpine
    ports:
      - "127.0.0.1:8080:80"
EOF

WARN[0000] ignoring IP-address (127.0.0.1:8080:80/tcp) service will listen on '0.0.0.0' 
Creating network test_default
Creating service test_web

وعند محاولة نشر خدمة بعنوان IP محدد ، ستفشل في النشر مع وجود خطأ ؛

docker service create -p 127.0.0.1:9090:80 nginx:alpine
invalid argument "127.0.0.1:9090:80" for "-p, --publish" flag: hostip is not supported
See 'docker service create --help'.

dalu إذا تعرض نظامك للإنترنت وأخبرت Docker بكشف خدمة على الكتلة ، لست متأكدًا من سبب كون التوقع شيئًا آخر.

بالتأكيد يحتوي تنسيق الإنشاء هذا على بعض التنازلات الجسيمة.

يارب

إذا تعرض نظامك للإنترنت وأخبرت Docker بكشف خدمة على الكتلة ، فأنا لست متأكدًا من سبب كون التوقع شيئًا آخر.

لا. لماذا يجب أن يكون متاحًا للجمهور إذا ربطه شخص ما بملكية الفكرية غير عامة مثل 127.0.0.1 أو 10.0.0.0؟ في الواقع ، هذه هي الإجابة الصحيحة:

الربط بعنوان IP محدد غير مدعوم حاليًا

dalu

لكن يجب أن يكون متاحًا ، ولكن ليس علنًا. وهذه هي الصفقة الكاملة هنا.
أنت غير آمن بشكل افتراضي وتتهرب من الإصلاح باستخدام الدلالات.
ظلت القضية مفتوحة منذ ما يقرب من عامين حتى الآن دون حل مناسب.

أنا أنتقل من سرب إلى kubernetes لأن السرب غير قابل للاستخدام. أنا سعيد تمامًا بهذا القرار حتى أن هذا الانتقال مكلف للغاية.

Bessonv يخبرك بشكل أتجاهل هذا"

تكمن المشكلة في أن تنسيق الإنشاء مصمم خصيصًا لمنسقي التطوير وتم دفعه لدعم عمليات النشر العنقودية. يجب أن يكون هناك خطأ في "حزمة عامل الإرساء" ، ولكن بعد ذلك يريد الأشخاص أن يكونوا قادرين على استخدام ملف إنشاء واحد للحكم عليهم جميعًا ، وبالتالي هناك هذه الفوضى.

يارب
لست متأكدًا من أنني مرتاح لهذا الوصف. في نهاية تنسيق الإنشاء هو مجرد وصف للحالة المطلوبة. الحصول على بعض الاختلافات بين آلة واحدة (تكوين) والكتلة (سرب) أمر جيد تمامًا. من وجهة نظري ، لا فائدة من دعم التأليف على الإطلاق. خاصة لأن تنشيط وضع السرب سهل للغاية. لكن هذا يتطلب إصلاح السرب.

المشكلة ليست في السرب على الإطلاق و 100٪ في تنسيق الإنشاء + التنفيذ في docker cli.
لاحظ أن المداخن هي تطبيق من جانب العميل بنسبة 100٪ حاليًا.

لقد وجدنا أنه داخل المكدس ، لا يتعين عليك الكشف صراحةً عن أي منافذ للخدمات الداخلية مثل قاعدة البيانات و redis وما إلى ذلك. مجرد حذف تكوين الخدمة الداخلية ports والإشارة إليه بالاسم يعمل بشكل جيد .

مثال على خدمة db داخل المكدس

services:
  db:
    image: postgres:11-alpine
  networks:
    - backend

... يمكن استهلاكها بواسطة خدمة Django app بواسطة المنفذ الافتراضي مثل هذا:

DATABASES = {
    'default': env.db(default='postgres://user:pass<strong i="13">@db</strong>:5432/catalog'),
}

لذلك في هذه الحالة ، عندما تكشف صراحةً الخدمات العامة فقط ، يبدو هذا آمنًا افتراضيًا

المشكلة ليست في السرب على الإطلاق و 100٪ في تنسيق الإنشاء + التنفيذ في docker cli.
لاحظ أن المداخن هي تطبيق من جانب العميل بنسبة 100٪ حاليًا.

مهما يكن: توقفت عن استخدام المكدس (بسبب هذه المشكلة) ، ولم أعد أهتم. إلقاء اللوم على المكتبة ، إلقاء اللوم على عامل النقل ، إلقاء اللوم على قطتي.

لم أر هذه المشكلة عند استخدام عامل الإرساء مباشرةً ، أو عند استخدام الإنشاء.

يبدو أن هذا النهج يمكن أن يساعد (يجب تنفيذه على كل عقدة في سرب):

  1. ترك سرب
  2. إزالة شبكة docker_gwbridge
  3. أعد إنشاء docker_gwbridge مع خيار إضافي com.docker.network.bridge.host_binding_ipv4 = IP
  4. الانضمام إلى سرب العودة
    يعمل على المنافذ المنشورة في وضع "المضيف". بدون وضع "المضيف" يتم استخدام الشبكة مع السائق الآخر ونطاق "سرب".

حل رهيب:

$ mv /usr/bin/docker-proxy /usr/bin/docker-proxy-original
$ cat << 'EOF' > /usr/bin/docker-proxy
#!/bin/sh
exec /usr/bin/docker-proxy-original `echo $* | sed s/0.0.0.0/127.0.0.1/g`
EOF
$ chmod 755 /usr/bin/docker-proxy
$ service docker restart

jsmouret لا يمكنني حتى العثور على وكيل عامل ميناء في أحدث إصدار عامل عامل ميناء. هل هو إرث؟ أو الاسم مختلف؟

يبدو أن ذلك يعتمد ...

$ apt-file search docker-proxy
docker-ce: /usr/bin/docker-proxy
docker.io: /usr/sbin/docker-proxy

يجب توثيق هذا السلوك بطريقة ما في الوثائق .
حاليًا ، يتجاهل المضيف فقط من تعيين المنفذ القصير. وبصمت لا يعمل.

شيء غريب آخر هو أنه لا يمكنك تعيين المضيف في مخطط بناء الجملة الطويل.

يجب توثيق هذا السلوك بطريقة ما في الوثائق.

أنا موافق؛ اعتقدت أنه مذكور في مكان ما في تلك الصفحة ، لكن لا يمكنني العثور عليه ؛ لا تتردد في فتح مشكلة في مستودع المستندات ؛ https://github.com/docker/docker.github.io/issues

حاليًا ، يتجاهل المضيف فقط من تعيين المنفذ القصير. وبصمت لا يعمل.

ما هو إصدار عامل الإرساء الذي تستخدمه؟ يجب أن يطبع تحذيرًا (عند استخدام docker stack deploy ) ، أو خطأ _ (عند استخدام docker service create ) ؛ انظر https://github.com/moby/moby/issues/32299#issuecomment -472793444

ما هو إصدار عامل الإرساء الذي تستخدمه؟ يجب أن تطبع تحذيرًا (عند استخدام نشر مكدس عامل الإرساء) ، أو خطأ (عند استخدام إنشاء خدمة عامل الإرساء) ؛

آه ، يبدو أنه خطأي. إنه يفعل ذلك حقًا عندما حاولت نشر مكدس من وحدة التحكم.
لقد قمت بذلك سابقًا عبر Portainer UI ولم تظهر أي أخطاء أو تحذيرات.

محبط حقًا لأن بعض مطوري Docker يتجاهلون عامين تقريبًا حالة استخدام صالحة ومفيدة للغاية عندما تكون هذه الوظيفة ضرورية: عندما تريد ربط قاعدة البيانات العلائقية المحتوية كخدمة سرب إلى الواجهة المحلية من أجل الوصول إليها بأمان عبر نفق SSH . حاليا هذا السيناريو من المستحيل القيام به.

هناك حل عملي ونظيف هو تشغيل خادم SSH في حاوية ثانية متصلة بنفس شبكة عامل الإرساء مثل قاعدة البيانات الخاصة بك. يمكن بعد ذلك نشر منفذ SSH على المضيف (إلى منفذ مختلف عن 22 بالطبع) ، حتى تتمكن من إعادة التوجيه عبر حاوية SSH إلى قاعدة البيانات الخاصة بك.

nartamonov لا أرى كيف يمكن القيام بذلك بأمان من الدخول ما لم يكن البروتوكول نفسه آمنًا.
ستكون طريقة الوصول إليها بأمان من خلال مستوى بيانات مشفر ( --opt encrypted للشبكات الزائدة) وتدوير حاوية مع أي أدوات تحتاج إلى توصيلها بهذه الشبكة.

من المحتمل أن يكون لهذا آثار جانبية أخرى غير ذات صلة ، لكن تعيين "iptables": false في /etc/docker/daemon.json يؤدي إلى الحيلة كحل بديل أيضًا. الحل الأقل جذرية هو إضافة القاعدة المخصصة فقط مثل helldweller المقترح.

في كلتا الحالتين ، أود أن أرى المزيد من الدعم لهذا بعد 3 سنوات.

يبدو أن هذا النهج يمكن أن يساعد (يجب تنفيذه على كل عقدة في سرب):

1. leave swarm

2. remove network docker_gwbridge

3. recreate network docker_gwbridge with additional option com.docker.network.bridge.host_binding_ipv4=IP

4. join swarm back
   Works for ports published in mode "host". Without mode "host" ingress network is used with other driver and scope "swarm".

تضمين التغريدة
إذا لم أكن مخطئًا ، فهذا يجعل جميع المنافذ المنشورة مرتبطة بعنوان افتراضي معين IP ؟ لكي نكون واضحين ، هذا ليس حلاً قابلاً للاستخدام إذا كنت تريد فقط تقييد الواجهة المرتبطة لبعض منافذ بعض الخدمات.

أود الإبلاغ عن الحل الخاص بي.

حالة الاستخدام:
تحتاج بعض الخدمات الموجودة في السرب إلى الاستماع على جميع الواجهات ، أو على الأقل على الواجهة العامة - هذه الحاوية في المثال الخاص بي هي وكيل عكسي
في عقد السرب هذه ، يوجد أيضًا مثيل قاعدة بيانات على كل عقدة ، يستخدم هؤلاء شبكة سرب محددة على النحو التالي:

docker network create --scope swarm NETWORK_NAME --attachable -d overlay

تحتاج خدمات الويب التي تحتاج إلى اتصالات قاعدة بيانات إلى الانضمام إلى هذا NETWORK_NAME بالطبع

لأغراض الإدارة ، في بعض الأحيان ، من الضروري الاتصال مباشرة بقاعدة البيانات

المحلول:
فقط الخدمات التي تحتاج إلى الكشف عنها على جميع الشبكات (الوكلاء العكسيون في المثال الخاص بي) يمكن أن يكون لها ports: ['SOMEPORT:ANOTHERPORT'] في تعريف خدماتهم

تحتاج جميع الخدمات الأخرى إلى حاوية مزدوجة غير سرب من عامل الإرساء على المضيف.
ستعمل هذه الحاوية التي لا تحتوي على سرب على جسر الميناء الموجود على NETWORK_NAME/nodeXYZ:port إلى localhost

مثال مع mongodb:

docker run --rm -it --net=NETWORK_NAME -d --name expose-mongo -p 127.0.0.1:27017:47017 alpine/socat tcp-listen:47017,fork,reuseaddr tcp-connect:mongo01:27017

الجانب السلبي: يجب أن يكون هناك حاوية غير سرب لكل عقدة سرب ، لذلك مع وجود العديد من العقد يكون مملاً حقًا ما لم يتم اعتماد برمجة نصية غير مرئية / ثقيلة

كان الحل البديل لمشكلة "إذا كنت تتصل ببعض الخدمات عبر أنفاق SSH" التي ذكرها @ fer2d2 هو إضافة خدمة ssh مع Dockerfile مثل:

FROM alpine

RUN apk add --no-cache openssh
RUN mkdir ~/.ssh
RUN ssh-keygen -A
RUN echo "root:root" | chpasswd
RUN echo 'PasswordAuthentication no' >> /etc/ssh/sshd_config
RUN echo 'Port 22' >> /etc/ssh/sshd_config
RUN echo -e " \
Match User root \n\
  AllowTcpForwarding yes\n\
  X11Forwarding no\n\
  AllowAgentForwarding no\n\
  ForceCommand /bin/false\n\
" >> /etc/ssh/sshd_config

EXPOSE 22
CMD /usr/sbin/sshd -D -e "$@"

ثم في docker-compose.yml:

...
  db:
    image: mysql:5.6
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:?err}
      MYSQL_ROOT_HOST: '%'
    volumes:
      - "./mysql:/var/lib/mysql"
    deploy:
      placement:
        constraints: [node.role == manager]

  sshd:
    image: maxisme/sshd:latest
    volumes:
      - "~/.ssh:/root/.ssh"
    ports:
      - "2223:22"
    deploy:
      placement:
        constraints: [node.role == manager]

مما يسمح لي بإضافة مفاتيح_المخولة إلى المجلد ~/.ssh ثم ينتقل وكيل ssh عبر المنفذ 2223 إلى قاعدة البيانات الخاصة بي باستخدام اسم المضيف db .

هناك حل عملي ونظيف هو تشغيل خادم SSH في حاوية ثانية متصلة بنفس شبكة عامل الإرساء مثل قاعدة البيانات الخاصة بك. يمكن بعد ذلك نشر منفذ SSH على المضيف (إلى منفذ مختلف عن 22 بالطبع) ، حتى تتمكن من إعادة التوجيه عبر حاوية SSH إلى قاعدة البيانات الخاصة بك.

صالح

مثال آخر على أهمية هذه الميزة.
لدي خادم مثبت عليه plesk ، يحتوي plesk بالفعل على تكويناته ولكن يمكنني إضافة تكوين آخر فقط للإشارة إلى خدمة سرب عامل التحميل. خادم plesk هذا هو عقدة سرب.
أود استخدام plesk لتجاوز proxy_pass إلى منفذ. يجب نشر هذا المنفذ لأن الحاوية موجودة في شبكة التراكب ولكنها تحتاج إلى منفذ خارجي للتواصل مع العالم.

لذلك يجب أن يشير proxypass إلى واجهة محلية مثل 127.0.0.1: someport
ويجب أن تنشر الحاوية الموجودة في السرب المنفذ على المضيف المحلي فقط.

وبهذه الطريقة ، لا يمكن الوصول إلى ميناء الحاويات إلا عن طريق proxypass وليس من العالم مباشرةً

يعجبني الحل البديل الخاص بك maxisme ، لكن كيف تدير ملكية authorized_keys ؟ في OS X ، يعمل بالنسبة لي (ينتمي الحامل إلى root ) ولكن على جهاز إنتاج Linux أحصل عليه:

Authentication refused: bad ownership or modes for file /root/.ssh/authorized_keys
Connection closed by authenticating user root 85.145.195.174 port 60535 [preauth]

وحدة التخزين تنتمي إلى UID الخاص بالمستخدم المضيف ، وهو ليس root و SSHD يرفض العمل معه. الحل البديل أعلى الحل البديل الخاص بك 😬 هو استخدام configs ، مثل هذا:

services:
  sshd:
    image: [...]/sshd:${version}
    configs:
      # FIXME: It would be much better to use a bind volume for this, as it
      # would always be in sync with the host configuration. So revoking a key
      # in the host machine would automatically revoke it in the container. But
      # I can't figure out how to give the volume right ownership. It keeps UID
      # from the host which doesn't align with the container user.
      - source: authorized_keys
        target: /root/.ssh/authorized_keys
        mode: 0600

configs:
  authorized_keys:
    file: ~/.ssh/authorized_keys

أفهم أنه نظرًا لحقيقة أنك لا تعرف المضيف الذي سيتم نشر الحاوية عليه ، فلا يمكنك إخبار الخدمة بالالتزام بعنوان IP مضيف معين.

ومع ذلك ، غالبًا ما يكون للمضيفين واجهات متجهة شمالًا وجنوبًا. قد ترغب في أن ترتبط منافذ السرب فقط بالواجهات المتجهة شمالًا على جميع مضيفات السرب.

إذا كانت أسماء الواجهة لجميع الواجهات التي تريد ربط الخدمة بها هي نفسها (على سبيل المثال eth0) ، فقد يكون من الأفضل تقديم خيار لتحديد اسم واجهة لربط منافذ السرب بها (في قسم منافذ الخدمة).

    nginx:
      image: nvbeta/swarm_nginx
      networks:
        - demonet1
      ports:
        - "eth0:8088:80"

عندما لا يتوفر eth0 على عقدة سرب ، فلن يكون المنفذ المحدد مرتبطًا بأي واجهة.

@ tad-lispy يجب أن تكون قادرًا على تغيير uid و gid لمستخدم الحاوية ليكون هو نفسه مالك وحدة التخزين على المضيف.
تدعم صورة linuxserver هذا عن طريق تعيين متغيرات البيئة (راجع https://hub.docker.com/r/linuxserver/openssh-server، User / Group Identifiers ) ،

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات