Moby: mode essaim docker: les ports sur 127.0.0.1 sont exposés à 0.0.0.0

Créé le 2 avr. 2017  ·  53Commentaires  ·  Source: moby/moby

La description

En mode essaim docker, la liaison d'un port à 127.0.0.1 se traduit par l'ouverture du port sur 0.0.0.0 également. Cela peut être un problème de sécurité grave et doit être expliqué dans la documentation.

Étapes pour reproduire le problème:

  1. Créez un service, par exemple MongoDB, dans votre fichier docker-compose.swarm.yml et publiez le port 27017 sur localhost:
  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. Déployez votre essaim
  2. Vérifiez si le port est ouvert de l'extérieur de votre essaim avec netcat

Décrivez les résultats que vous avez reçus:

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

Décrivez les résultats attendus:
Le port étant disponible uniquement sur 127.0.0.1, au moins dans les noeuds d'essaims en cours d' exécution de ce service.

Informations supplémentaires que vous jugez importantes (par exemple, le problème n'arrive qu'occasionnellement):

Sortie de docker version :

Docker version 17.03.1-ce, build c6d412e

Sortie de docker info :

informations de docker pour le gestionnaire d'essaim:

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

Détails supplémentaires sur l'environnement (AWS, VirtualBox, physique, etc.):
Testé sur les gouttelettes de Digital Ocean.

areswarm kinbug

Commentaire le plus utile

Vraiment déçu que près de deux ans, certains des développeurs Docker ignorent un cas d'utilisation valide et très utile lorsque cette fonctionnalité est indispensable: lorsque vous voulez lier une base de données relationnelle contenue en tant que service swarm à l'interface locale afin d'y accéder en toute sécurité via le tunnel SSH . Actuellement, ce scénario est impossible à réaliser.

Tous les 53 commentaires

Oui, cela devrait générer une erreur; services (par défaut) "publient" en utilisant le réseau "d'entrée", et ne prennent pas en charge la spécification d'une adresse IP, car il n'est pas possible de prédire sur quel _ nœud_ ils se retrouvent (donc on ne sait pas sur quelles adresses IP sont disponibles - bien que 127,0 .0.1 pourrait être possible). Ce problème suit cette fonctionnalité https://github.com/docker/docker/issues/26696 (et cette "épopée" suit d'autres options pas (encore) prises en charge par les services https://github.com/docker/docker/issues / 25303)

Le bogue ici est que docker devrait produire une erreur, au lieu d'ignorer silencieusement l'option; reproductible en utilisant ce fichier docker-compose minimal;

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

ping @dnephin @vdemeester

@ fer2d2 En mode ports pour stack deploy ), il est publié sur le réseau ingress , et donc il est public. Il y a plusieurs façons de se déplacer, mais en mettant kind/bug dessus parce que nous devrions au moins avertir les gens à ce sujet lorsque vous faites un stack deploy avec des ports qui ont cette notation (c'est- host:port:port dire

Pour contourner ce problème, il existe plusieurs façons:

  • Tout d'abord, vous devez publier les ports mongo uniquement si vous voulez qu'ils soient publics , sinon, ils sont disponibles via le bundle de découverte de noms dans docker (un autre conteneur / service sur le même réseau pourra l'atteindre via mongo nom dns).
  • Si vous voulez le publier dans l'hôte et non dans ingress (donc pas de swarm public, juste sur l'hôte qu'il exécute, de la même manière que sans le mode swarm), vous devez utiliser la syntaxe étendue des ports .
    ports:
      - mode: host
        target: 80
        published: 9005

Il fera la même chose que docker run -p 80:9005 … donc il le liera à 0.0.0.0 , mais limité à l'hôte.

Mais comme l' a dit

/ cc @mavenugo @aboch pour voir s'il y aurait un moyen de pouvoir le lier à une adresse IP spécifique? (vraiment difficile à réaliser car l'IP du nœud sera différent donc ..)

@vdemeester Puis-je spécifier localhost comme cible hôte en utilisant cette notation?

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

Comme il s'agit d'un format étendu pour la configuration des ports , il devrait fonctionner correctement.

Merci d'avance

Il semble que la cible et la publication soient appliquées en tant que type entier dans la syntaxe longue

Je pense que ce n'est pas le comportement souhaité si vous vous connectez à certains services via des tunnels SSH. Par exemple, si vous souhaitez avoir votre serveur MySQL ou MongoDB sur 127.0.0.1 et vous connecter via SSH Tunnel, avec Docker Swarm, vous devez exposer le port de base de données sur 0.0.0.0 ou créer un conteneur de base de données personnalisé avec SSH exécuté à l'intérieur (et les deux sont très peu sûrs).

De nombreux clients de base de données utilisant des tunnels SSH, comme SQL Workbench ou Robomongo, ne peuvent pas être utilisés en raison de cette limitation (liaison d'interface spécifique).

Nous avons le même problème dans notre entreprise que @ fer2d2 , en essayant de connecter Mongobooster avec un essaim de docker via le tunnel ssh. La seule solution que nous avons trouvée était d'ouvrir le port 27017 et de protéger la base de données avec un utilisateur et un mot de passe.

Des nouvelles?

+1

+1

Un autre cas d'utilisation pour autoriser la paire adresse_ip : port pour le mappage de ports de longue forme concerne les adresses anycast ou toute autre adresse pouvant être associée au bouclage. Celles-ci seraient similaires à une adresse 127.0.0.1 en ce qu'elles ne sont visibles que sur le réseau de bouclage. Un service limité aux nœuds avec cette propriété peut souhaiter exposer un port uniquement sur une adresse anycast afin d'éviter les collisions de port tout en évitant les règles iptables pour la traduction de port.

Cela peut-il être une option lorsque vous spécifiez:

placement:
        constraints:
          - node.id ==

À votre santé

+1

+1

+1

pour moi, j'ai résolu ce problème ainsi:

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

Le docker ne touche pas à ces règles. ajoute juste le vôtre
-A DOCKER-USER -j RETURN
En conséquence, bien que le port écoute sur 0.0.0.0 mais ne soit pas accessible depuis l'interface externe eth0

Ce comportement est en violation de «sécurisé par défaut», et mettre une note dans la documentation ne sera pas suffisant. Pour l'instant, cela devrait provoquer une erreur.

Il est également lié au mode: entrée / hôte (ces deux problèmes semblent confondus dans la discussion). Il n'y a rien dans le mode d'entrée qui devrait empêcher le service d'être lié aux adresses locales sur tous les nœuds, mais pas aux adresses externes. Par conséquent, 127.xxx devrait être autorisé. (en mode non-swarm (en utilisant docker run) je me lie à 127.0.0.2:80 et 127.0.0.3:80 etc. Pour tester plusieurs serveurs localement en développement.).

L'autre problème est que le mode d'entrée est le mode par défaut. Ceci est inattendu et entraîne également un problème de sécurité. J'ai juste essayé de démarrer un service sur un nœud contraint d'être sur une partie privée du réseau, avec un port lié à 127.0.0.3:80. Il était alors également lié à l'interface publique du nœud public. (C'est ignorer silencieusement l'adresse IP, et utiliser silencieusement le mode d'entrée, et boom mes données sont publiques).

Cas d'utilisation

  • Des cas d'utilisation qui m'ont affecté (certainement réels)

    • 1 Liez au port d'un nœud spécifique, car le port est utilisé sur d'autres nœuds. Vous pouvez utiliser le mode hôte pour cela, mais la valeur par défaut est une surprise.

    • 2 Liez au port d'un nœud spécifique, car d'autres nœuds ont des interfaces publiques. Vous pouvez utiliser le mode hôte pour cela, mais la valeur par défaut est en violation de «sécurisé par défaut» .

    • 3 Liez localement car, vous ne voulez pas qu'il soit visible, pour d'autres hôtes, la valeur par défaut est en violation de «sécurisé par défaut»

    • 4 Liez à 127.0.0.3, parce que votre machine de développement a beaucoup de choses dessus, et 127.0.0.1 est en cours d'utilisation, par ce port. Et utilisez /etc/hosts , de sorte que chaque nom de domaine soit envoyé à un conteneur différent. Cela fonctionne avec docker run , mais pas avec compose.

  • Autres cas d'utilisation

    • Liez à une interface spécifique, par exemple 192.168.0.x, car il s'agit d'un réseau interne. la valeur par défaut est en violation de "sécurisé par défaut"

    • Liez à un nœud spécifique spécifique, mais ne contraignez pas le service à s'exécuter sur ce nœud. C'est un cas d'utilisation similaire à 1 ou 2, mais sans utilisation de contraintes. Le trafic serait acheminé à travers l'essaim.

Donc en résumé

  • Ignorer l'adresse IP et la liaison à 0.0.0.0, et le mode d'entrée par défaut, sont tous deux en violation de «sécurisé par défaut». Des erreurs doivent être émises si l'adresse IP est spécifiée et les documents mis à jour. Une erreur doit être émise si le mode n'est pas spécifié (pas de valeur par défaut) et les documents mis à jour. (cela résout le problème de mode et arrête les problèmes de sécurité surprise.)
  • Le support peut alors être ajouté pour les adresses IP en mode hôte.
  • La prise en charge des adresses IP en mode d'entrée, qui est limitée aux adresses locales 127.xxx, pourrait être ajoutée. (des adresses locales différentes, par exemple 127.0.0.2 et 127.0.0.3 doivent être traitées comme différentes (juste passées au système d'exploitation)).

Autoriser la liaison à l'adresse locale est utile pour les nœuds contraints. Autoriser la liaison à une adresse particulière, fonctionnerait pour un nœud contraint, ou acheminé à travers l'essaim vers l'une des adresses sur l'un des nœuds (peut être en mode entrée uniquement). Ce routage est déjà fait

@ richard-delorenzi Moby n'accepte même pas actuellement une adresse IP hôte. Donc, en dehors de la demande de fonctionnalité, cela ressemble à un problème côté client ... en particulier la façon dont le composant yaml est traduit dans la CLI Docker.

Le fonctionnement de l'entrée est assez bien documenté, mais conviens qu'il s'agit d'un mauvais comportement sur la CLI.

+1

+1

+1

J'ai une sorte de solution de contournement que j'utilise. J'exécute des conteneurs autonomes et je les connecte à un réseau nommé 'core', qui est utilisé par tous nos services back-end (mongo, elasticsearch, influxdb, etc.) qui s'exécutent dans un essaim.

Je ne vois pas comment faire cela dans un fichier de composition, donc nous exécutons simplement des conteneurs autonomes comme ceci:

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

Après leur démarrage, docker ps montre les nouveaux conteneurs comme étant liés à 127.0.0.1. Amen. Je peux ensuite effectuer un tunnel vers l'hôte docker depuis mon poste de travail local pour un accès sécurisé, comme ceci:

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

Depuis mon navigateur, je peux ensuite me connecter à http: // localhost : 8888 ou http: // localhost : 5601

Travaille pour moi.

Dans le cas où un socket UNIX peut remplacer un socket TCP / IP 127.0.0.1, une solution de contournement possible que j'ai implémentée pour fluent-bit est disponible ici

Peut-être que l'ajout d'une autre option à mode pourrait aider. Quelque chose comme local en plus de host et ingress .

Veuillez supprimer le libellé «Sécurité utilisable: Moby fournit des valeurs par défaut sécurisées sans compromettre la convivialité. sur le fichier lisez-moi de moby . C'est définitivement une fausse publicité, voir le commentaire de @ richard-delorenzi.

Les services ne publient pas de ports par défaut et ne seront donc pas accessibles à moins que vous ne spécifiiez qu'ils doivent publier un port. La liaison à une adresse IP spécifique n'est pas prise en charge actuellement; si votre service ne doit pas être accessible, ne publiez pas de ports et connectez-vous au service à l'aide d'un réseau interne (superposé).

L'ajout de la prise en charge de la liaison à une adresse IP est discuté dans https://github.com/moby/moby/issues/26696 , mais pas trivial à implémenter (en tenant compte des adresses IP non "localhost")

Un avertissement a été ajouté lors du déploiement d'une pile;

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

Et lorsque vous tentez de déployer un service avec une adresse IP spécifiée, le déploiement échouera avec une erreur;

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 si votre système est exposé à Internet et que vous avez dit à Docker d'exposer un service sur le cluster, je ne sais pas pourquoi l'attente serait autre chose.

Certainement, ce format de composition qui strattle le développement et les déploiements réels comporte de gros compromis.

@ cpuguy83

si votre système est exposé à Internet et que vous avez dit à Docker d'exposer un service sur le cluster, je ne sais pas pourquoi l'attente serait autre chose.

Nan. Pourquoi devrait-il être accessible au public si quelqu'un le lie à une adresse IP non publique comme 127.0.0.1 ou 10.0.0.0? En fait, c'est la bonne réponse:

La liaison à une adresse IP spécifique n'est pas prise en charge actuellement

@dalu

Mais il devrait être accessible, mais pas publiquement. Et c'est tout le problème ici.
Vous n'êtes pas sûr par défaut et vous éludez un correctif avec la sémantique.
La question est ouverte depuis près de 2 ans maintenant sans résolution appropriée.

Je suis en train de passer de Swarm à Kubernetes parce que Swarm n'est pas utilisable. Je suis totalement satisfait de cette décision, même cette transition est très coûteuse.

@Bessonv Il vous dit littéralement "

Le problème est que le format de composition est conçu pour les environnements de développement et a été poussé pour prendre en charge les déploiements de cluster. "docker stack" devrait juste sortir une erreur, mais alors les gens veulent pouvoir utiliser un fichier de composition pour les gouverner tous et il y a donc ce désordre.

@ cpuguy83
Je ne suis pas sûr d'être à l'aise avec cette description. À la fin, le format de composition n'est qu'une description de l'état souhaité. Avoir des différences entre une machine (composer) et un cluster (essaim) est tout à fait acceptable. De mon point de vue, il ne sert à rien de soutenir la composition. Surtout parce que l'activation du mode essaim est si simple. Mais cela nécessite de réparer l'essaim.

Le problème n'est pas du tout en essaim et 100% dans le format de composition + l'implémentation dans le docker cli.
Notez que les piles sont actuellement à 100% une implémentation côté client.

Nous avons constaté qu'à l'intérieur de la pile, vous n'avez pas à exposer explicitement les ports pour les services internes tels que la base de données, les redis, etc. Il suffit d' omettre la configuration ports du service interne et de référencer par nom fonctionne bien .

Exemple de service de base de données à l'intérieur de la pile

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

... peut être consommé par le service Django app par le port par défaut comme ceci:

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

Donc, dans ce cas, lorsque vous exposez explicitement uniquement les services publics, cela ressemble à secure-by-default

Le problème n'est pas du tout en essaim et 100% dans le format de composition + l'implémentation dans le docker cli.
Notez que les piles sont actuellement à 100% une implémentation côté client.

Quoi qu'il en soit: j'ai arrêté d'utiliser stack (à cause de ce problème), et je m'en fiche. Blâmez la bibliothèque, blâmez docker, blâmez mon chat.

Je n'ai pas vu ce problème lors de l'utilisation directe de docker ou lors de l'utilisation de compose.

On dirait que cette approche peut aider (devrait être exécutée sur chaque nœud de l'essaim):

  1. quitter l'essaim
  2. supprimer le réseau docker_gwbridge
  3. recréer le réseau docker_gwbridge avec l'option supplémentaire com.docker.network.bridge.host_binding_ipv4 = IP
  4. rejoindre l'essaim de retour
    Fonctionne pour les ports publiés en mode "hôte". Sans mode, le réseau d'entrée "hôte" est utilisé avec un autre pilote et une portée "essaim".

Solution horrible:

$ 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 Je ne trouve même pas docker-proxy sur la dernière version de docker. Est-ce un héritage? Ou le nom est différent?

On dirait que ça dépend ...

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

Ce comportement doit être documenté d'une manière ou d'une autre dans la documentation .
Actuellement, il ignore simplement l'hôte du mappage de port court. Et silencieusement ne fonctionne pas.

Une autre chose étrange est que vous ne pouvez pas définir l'hôte dans le schéma de syntaxe long.

Ce comportement doit être documenté d'une manière ou d'une autre dans la documentation.

Je suis d'accord; Je pensais que c'était mentionné quelque part sur cette page, mais je ne peux pas le trouver; n'hésitez pas à ouvrir un problème dans le référentiel de documents; https://github.com/docker/docker.github.io/issues

Actuellement, il ignore simplement l'hôte du mappage de port court. Et silencieusement ne fonctionne pas.

quelle version de docker utilisez-vous? il devrait afficher un avertissement (lors de l'utilisation de docker stack deploy ), ou une _error_ (lors de l'utilisation de docker service create ); voir https://github.com/moby/moby/issues/32299#issuecomment -472793444

quelle version de docker utilisez-vous? il doit afficher un avertissement (lors de l'utilisation de docker stack deploy) ou une erreur (lors de l'utilisation de docker service create);

Ugh, on dirait que c'est de ma faute. C'est vraiment le cas lorsque j'ai essayé de déployer une pile à partir de la console.
Auparavant, je le faisais via l'interface utilisateur de portainer et il ne montrait aucune erreur ou avertissement.

Vraiment déçu que près de deux ans, certains des développeurs Docker ignorent un cas d'utilisation valide et très utile lorsque cette fonctionnalité est indispensable: lorsque vous voulez lier une base de données relationnelle contenue en tant que service swarm à l'interface locale afin d'y accéder en toute sécurité via le tunnel SSH . Actuellement, ce scénario est impossible à réaliser.

Une solution viable et propre exécute un serveur SSH dans un deuxième conteneur qui est connecté au même réseau docker que votre base de données. Le port SSH peut ensuite être publié sur l'hôte (vers un port différent de 22 bien sûr), de sorte que vous pouvez transférer via le conteneur SSH vers votre base de données.

@nartamonov Je ne vois pas comment cela pourrait être fait en toute sécurité depuis l'entrée à moins que le protocole lui-même ne soit sécurisé.
Le moyen d'y accéder en toute sécurité serait via un plan de données crypté ( --opt encrypted pour les réseaux excessifs) et de créer un conteneur avec les outils dont vous avez besoin attachés à ce réseau.

Cela a probablement d'autres effets secondaires non liés, mais définir "iptables": false dans /etc/docker/daemon.json fait également l'affaire comme solution de contournement. Une solution moins drastique consiste à ajouter uniquement la règle personnalisée comme @helldweller l'a suggéré.

Quoi qu'il en soit, j'aimerais voir plus de soutien pour cela après 3 ans.

On dirait que cette approche peut aider (devrait être exécutée sur chaque nœud de l'essaim):

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

@ienovytskyi
Si je ne me trompe pas, tous les ports publiés se lient à une adresse IP par défaut donnée? Donc, pour être clair, ce n'est pas une solution de contournement utilisable si vous souhaitez uniquement contraindre l'interface liée pour certains ports de certains services.

Je voudrais signaler ma solution de contournement.

Cas d'utilisation:
Certains services dans Swarm doivent être à l'écoute sur toutes les interfaces, ou au moins sur l'interface publique - ce conteneur dans mon exemple est un proxy inverse
Dans ces nœuds swarm, il existe également une instance de base de données sur chaque nœud, ceux-ci utilisent un réseau swarm défini comme:

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

Les services Web qui ont besoin d'une connexion à une base de données doivent être joints à ce NETWORK_NAME bien sûr

À des fins d'administration, il est parfois nécessaire de se connecter directement à la base de données

Solution:
Seuls les services qui doivent être exposés sur tous les réseaux (les proxys inverses dans mon exemple) peuvent avoir ports: ['SOMEPORT:ANOTHERPORT'] dans leur définition de services

Tous les autres services doivent avoir un conteneur docker non swarm couplé sur l'hôte.
Ce conteneur non-swarm reliera le port présent sur NETWORK_NAME/nodeXYZ:port à localhost

Exemple avec 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

Inconvénient: il devrait y avoir un conteneur non-swarm pour chaque nœud swarm, donc avec de nombreux nœuds, c'est vraiment ennuyeux à moins d'adopter un script anible / lourd

Ma solution de contournement pour le problème "si vous vous connectez à certains services via des tunnels SSH" que @ fer2d2 a mentionné était d'ajouter un service ssh avec un Dockerfile comme:

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 "$@"

Puis dans le 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]

ce qui me permet d'ajouter mes clés_autorisées au dossier ~/.ssh , puis le proxy ssh passe par le port 2223 vers ma base de données en utilisant le db hostname.

Une solution viable et propre exécute un serveur SSH dans un deuxième conteneur qui est connecté au même réseau docker que votre base de données. Le port SSH peut ensuite être publié sur l'hôte (vers un port différent de 22 bien sûr), de sorte que vous pouvez transférer via le conteneur SSH vers votre base de données.

valide

un autre exemple pourquoi cette fonctionnalité est importante.
J'ai un serveur avec plesk installé, plesk a déjà ses configurations mais je peux ajouter une autre configuration juste pour pointer vers un service docker swarm. Ce serveur plesk est un nœud d'essaim.
Je voudrais utiliser plesk pour proxy_pass vers un port. Ce port doit être publié car le conteneur est dans le réseau de superposition mais il a besoin d'un port externe pour communiquer avec le monde.

Donc, le proxypass doit pointer vers une interface locale comme 127.0.0.1: someport
et le conteneur dans l'essaim devrait publier le port uniquement sur localhost.

De cette façon, le port de conteneurs n'est accessible que par le proxy et non directement depuis le monde

J'aime votre solution de contournement @maxisme , mais comment gérez-vous la propriété authorized_keys ? Sur OS X, cela fonctionne pour moi (le montage appartient à root ) mais sur une machine Linux de production, je reçois:

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]

Le volume appartient à l'UID de l'utilisateur hôte, qui n'est pas root et SSHD refuse de travailler avec lui. Une solution de contournement en plus de votre solution de contournement 😬 consiste à utiliser configs , comme ceci:

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

Je comprends qu'en raison du fait que vous ne savez pas sur quel hôte un conteneur sera déployé, vous ne pouvez pas indiquer au service de se lier à une adresse IP d'hôte spécifique.

Cependant, les hôtes ont souvent par exemple des interfaces nord et sud. Vous souhaiterez peut-être que les ports Swarm se lient uniquement aux interfaces nord de tous les hôtes Swarm.

Si les noms d'interface de toutes les interfaces auxquelles un service doit se lier sont les mêmes (par exemple eth0), il peut être judicieux d'offrir une option pour spécifier un nom d'interface auquel lier les ports swarm (dans la section des ports de service).

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

Lorsque eth0 n'est pas disponible sur un nœud swarm, le port spécifié ne sera lié à aucune interface.

@ tad-lispy Vous devriez pouvoir changer l'uid et le gid de l'utilisateur du conteneur pour qu'ils soient les mêmes que le propriétaire du volume sur l'hôte.
L'image du serveur linux prend en charge cela en définissant des variables d'environnement (voir https://hub.docker.com/r/linuxserver/openssh-server, User / Group Identifiers ),

Cette page vous a été utile?
0 / 5 - 0 notes