Moby: Modo de enjambre de Docker: los puertos en 127.0.0.1 están expuestos a 0.0.0.0

Creado en 2 abr. 2017  ·  53Comentarios  ·  Fuente: moby/moby

Descripción

En el modo de enjambre de la ventana acoplable, vincular un puerto a 127.0.0.1 da como resultado que el puerto también esté abierto en 0.0.0.0. Esto podría ser un problema de seguridad grave y debería explicarse en la documentación.

Pasos para reproducir el problema:

  1. Cree un servicio, por ejemplo MongoDB, en su archivo docker-compose.swarm.yml y publique el puerto 27017 en 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. Despliega tu enjambre
  2. Compruebe si el puerto está abierto desde fuera de su enjambre con netcat

Describe los resultados que recibiste:

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

Describe los resultados que esperabas:
El puerto solo está disponible en 127.0.0.1, al menos en los nodos de enjambre que ejecutan este servicio.

Información adicional que considere importante (por ejemplo, el problema ocurre solo ocasionalmente):

Salida de docker version :

Docker version 17.03.1-ce, build c6d412e

Salida de docker info :

información de la ventana acoplable para el administrador de enjambres:

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

Detalles adicionales del entorno (AWS, VirtualBox, físico, etc.):
Probado en gotas de Digital Ocean.

areswarm kinbug

Comentario más útil

Realmente decepcionado de que durante casi dos años algunos de los desarrolladores de Docker ignoren un caso de uso válido y muy útil cuando esa funcionalidad es imprescindible: cuando desea vincular una base de datos relacional contenida como servicio de enjambre a la interfaz local para acceder a ella de forma segura a través del túnel SSH . Actualmente ese escenario es imposible de hacer.

Todos 53 comentarios

Sí, esto debería generar un error; servicios (por defecto) "publican" usando la red de "entrada", y no admiten la especificación de una dirección IP, ya que no es posible predecir en qué _nodo_ terminan (por lo tanto, no se sabe qué direcciones IP están disponibles, aunque 127.0 .0.1 podría ser posible). Este problema está rastreando esa característica https://github.com/docker/docker/issues/26696 (y este "épico" rastrea otras opciones que no (todavía) son compatibles con los servicios https://github.com/docker/docker/issues / 25303)

El error aquí es que la ventana acoplable debería producir un error, en lugar de ignorar silenciosamente la opción; reproducible usando este archivo docker-compose mínimo;

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

ping @dnephin @vdemeester

@ fer2d2 En modo enjambre, si publica algo ( ports por stack deploy ), se publica en la red ingress y, por lo tanto, es público. Hay algunas formas de moverse, pero poner kind/bug en eso porque al menos deberíamos advertir a la gente sobre eso al hacer un stack deploy con puertos que tienen esta notación (es decir, host:port:port ).

Para solucionar esto, hay algunas formas:

  • primero, debe publicar mongo ports solo si desea que sea público ; de lo contrario, está disponible a través del paquete de descubrimiento de nombres en la ventana acoplable (otro contenedor / servicio en la misma red podrá acceder a él a través de mongo dns nombre).
  • Si desea publicarlo en el host y no en ingress (para que no sea público enjambre, solo en el host que se está ejecutando, de la misma manera que sin el modo enjambre), debe usar la sintaxis ampliada de los puertos .
    ports:
      - mode: host
        target: 80
        published: 9005

Hará lo mismo que docker run -p 80:9005 … por lo que lo vinculará a 0.0.0.0 , pero limitado al host.

Pero como dijo @thaJeztah , "El error aquí es que la ventana acoplable debería producir un error, en lugar de ignorar silenciosamente la opción" 👼

/ cc @mavenugo @aboch para ver si habría una manera de poder vincularlo a una ip específica. (realmente difícil de lograr porque la IP del nodo será diferente, así que ...)

@vdemeester ¿Puedo especificar localhost como el destino del host usando esta notación?

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

Como es un formato extendido para la configuración de puertos , debería funcionar correctamente.

Gracias por adelantado

Parece que tanto el destino como el publicado se aplican como tipo entero en la sintaxis larga

Creo que este no es el comportamiento deseado si se está conectando a algunos servicios a través de túneles SSH. Por ejemplo, si desea tener su servidor MySQL o MongoDB en 127.0.0.1 y conectarse a través del túnel SSH, con Docker Swarm debe exponer el puerto de la base de datos en 0.0.0.0 o crear un contenedor de base de datos personalizado con SSH ejecutándose dentro (y ambas opciones son muy inseguros).

Hay muchos clientes de bases de datos que utilizan túneles SSH, como SQL Workbench o Robomongo, que no se pueden utilizar debido a esta limitación (enlace de interfaz específico).

Tenemos el mismo problema en nuestra empresa que @ fer2d2 , al intentar conectar Mongobooster con un enjambre de docker a través del túnel ssh. La única solución que encontramos fue abrir el puerto 27017 y proteger la base de datos con usuario y contraseña.

¿Hay noticias?

+1

+1

Otro caso de uso para permitir ip_ address: port pair para el mapeo de puertos de formato largo es para direcciones anycast o cualquier otra dirección que pueda estar asociada al loopback. Estos serían similares a una dirección 127.0.0.1 en el sentido de que solo son visibles en la red de bucle invertido. Un servicio restringido a nodos con esta propiedad puede desear exponer un puerto solo en una dirección anycast para evitar colisiones de puertos y evitar las reglas de iptables para la traducción de puertos.

¿Puede ser una opción cuando especifica:

placement:
        constraints:
          - node.id ==

Salud

+1

+1

+1

por mí mismo resolví este problema así:

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

El acoplador no toca estas reglas. solo agrega el tuyo
-A DOCKER-USER -j RETURN
Como resultado, aunque el puerto escucha en 0.0.0.0 pero no es accesible desde la interfaz externa eth0

Este comportamiento es una violación de "seguro por defecto" y poner una nota en los documentos no será suficiente. Por ahora debería causar un error.

También está relacionado con el modo: ingreso / host (estos dos temas parecen confundirse en la discusión). No hay nada en el modo de ingreso que deba evitar que el servicio esté vinculado a direcciones locales en todos los nodos, pero no a direcciones externas. Por tanto, debería permitirse 127.xxx. (en modo sin enjambre (usando la ventana acoplable) me vinculo a 127.0.0.2:80 y 127.0.0.3:80, etc. Para probar varios servidores localmente en desarrollo).

El otro problema es que el modo de ingreso es el predeterminado. Esto es inesperado y también conduce a un problema de seguridad. Intenté iniciar un servicio en un nodo limitado a estar en una parte privada de la red, con un puerto vinculado a 127.0.0.3:80. Luego, también se vinculó a la interfaz pública del nodo público. (Eso es ignorar silenciosamente la dirección IP y usar silenciosamente el modo de ingreso, y boom, mis datos son públicos).

Casos de uso

  • Casos de uso que me han afectado (definitivamente reales)

    • 1 Enlazar al puerto de un nodo específico, porque el puerto está en uso en otros nodos. Puede usar el modo host para esto, pero el predeterminado es una sorpresa.

    • 2 Enlace al puerto de un nodo específico, porque otros nodos tienen interfaces públicas. Puede usar el modo de host para esto, pero el valor predeterminado es una violación de "seguro por defecto" .

    • 3 Enlaza localmente porque, no quieres que sea visible para otros hosts, el valor predeterminado es una violación de "seguro por defecto"

    • 4 Vínculo a 127.0.0.3, porque su máquina de desarrollo tiene muchas cosas y 127.0.0.1 está en uso por este puerto. Y use /etc/hosts , de modo que cada nombre de dominio se envíe a un contenedor diferente. Esto funciona con docker run , pero no con compose.

  • Otros casos de uso

    • Enlace a una interfaz específica, por ejemplo, 192.168.0.x, porque se trata de una red interna. predeterminado es una violación de "seguro por defecto"

    • Enlazar a un nodo específico específico, pero no restringir el servicio para que se ejecute en este nodo. Este es un caso de uso similar a 1 o 2, pero sin el uso de restricciones. El tráfico se encaminaría a través del enjambre.

Entonces en resumen

  • Ignorar la dirección IP y vincular a 0.0.0.0, y el modo de ingreso predeterminado, son una violación de "seguro por defecto". Se deben emitir errores si se especifica la dirección IP y se actualizan los documentos. Se debe emitir un error si no se especifica el modo (no predeterminado) y se actualizan los documentos. (esto soluciona el problema del modo y detiene los problemas de seguridad inesperados).
  • Luego, se puede agregar soporte para direcciones IP en modo host.
  • Se podría agregar soporte para direcciones IP en modo de ingreso, que está limitado a direcciones locales 127.xxx. (Las diferentes direcciones locales, por ejemplo, 127.0.0.2 y 127.0.0.3 deben tratarse como diferentes (recién pasadas al sistema operativo)).

Permitir enlazar a la dirección local es útil para nodos restringidos. Permitir enlazar a una dirección particular, funcionaría para un nodo restringido o enrutado a través del enjambre a una de las direcciones en uno de los nodos (puede ser solo en modo de ingreso). Este enrutamiento ya está hecho

@ richard-delorenzi Moby ni siquiera acepta una IP de host actualmente. Entonces, fuera de la solicitud de función, esto suena como un problema del lado del cliente ... específicamente cómo se traduce el yaml de redacción en la CLI de Docker.

La forma en que funciona la entrada está bastante bien documentada, pero conviene que se trata de un comportamiento deficiente en la CLI.

+1

+1

+1

Tengo una solución alternativa que utilizo. Ejecuto contenedores independientes y los conecto a una red llamada 'núcleo', que es utilizada por todos nuestros servicios de back-end (mongo, elasticsearch, influxdb, etc.) que se ejecutan dentro de un enjambre.

No veo cómo hacer esto en un archivo de redacción, por lo que solo estamos ejecutando contenedores independientes así:

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

Después de iniciarlos, docker ps muestra que los nuevos contenedores están vinculados a 127.0.0.1. Amén. Luego puedo hacer un túnel al host de la ventana acoplable desde mi estación de trabajo local para un acceso seguro, así:

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

Desde mi navegador, puedo conectarme a http: // localhost : 8888 o http: // localhost : 5601

Funciona para mi.

En el caso de que un socket UNIX pueda reemplazar un socket 127.0.0.1 TCP / IP, una posible solución que he implementado para fluent-bit está disponible aquí

Quizás agregar otra opción a mode podría ayudar. Algo como local además de host y ingress .

Elimine el texto "Seguridad utilizable: Moby proporciona valores predeterminados seguros sin comprometer la facilidad de uso". en el archivo Léame de Moby . Este es definitivamente un anuncio falso, vea el comentario de @ richard-delorenzi.

Los servicios no publican puertos de forma predeterminada, por lo que no se podrá acceder a ellos a menos que especifique que deben publicar un puerto. Actualmente, no se admite la vinculación a una dirección IP específica; si su servicio no debe ser accesible, no publique puertos y conéctese al servicio mediante una red interna (superpuesta).

En https://github.com/moby/moby/issues/26696 se analiza la

Se agregó una advertencia al implementar una pila;

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

Y al intentar implementar un servicio con una dirección IP especificada, no se implementará con un error;

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 su sistema está expuesto a Internet y le dijo a Docker que exponga un servicio en el clúster, no estoy seguro de por qué la expectativa sería otra.

Definitivamente, este formato de redacción que es desarrollo estratégico e implementaciones reales tiene algunos compromisos graves.

@ cpuguy83

Si su sistema está expuesto a Internet y le dijo a Docker que exponga un servicio en el clúster, no estoy seguro de por qué la expectativa sería otra.

No ¿Por qué debería ser accesible al público si alguien lo vincula a una IP no pública como 127.0.0.1 o 10.0.0.0? En realidad, esa es la respuesta correcta:

Actualmente no se admite la vinculación a una dirección IP específica

@dalu

Pero debería ser accesible, pero no públicamente. Y ese es todo el problema aquí.
Eres inseguro por defecto y estás evadiendo una solución con semántica.
El problema ha estado abierto durante casi 2 años sin una resolución adecuada.

Estoy haciendo la transición de swarm a kubernetes porque swarm no se puede usar. Estoy totalmente feliz con esta decisión, incluso esta transición es muy costosa.

@Bessonv Literalmente te dice "Estoy ignorando esto"

El problema es que el formato de redacción está diseñado para dev envs y se ha impulsado para admitir implementaciones de clústeres. "Docker stack" debería aparecer un error, pero luego la gente quiere poder usar un archivo de redacción para gobernarlos a todos y entonces hay este lío.

@ cpuguy83
No estoy seguro de estar cómodo con esta descripción. Al final, el formato de redacción es solo una descripción del estado deseado. Tener algunas diferencias entre una máquina (componer) y clúster (enjambre) está totalmente bien. Desde mi punto de vista, no tiene sentido apoyar la composición en absoluto. Especialmente porque activar el modo enjambre es muy fácil. Pero esto requiere arreglar el enjambre.

El problema no está en swarm en absoluto y 100% en el formato de composición + la implementación en el docker cli.
Tenga en cuenta que las pilas son 100% una implementación del lado del cliente actualmente.

Hemos descubierto que dentro de la pila no es necesario exponer explícitamente ningún puerto para servicios internos como base de datos, redis, etc. Simplemente omitir la configuración ports del servicio interno y hacer referencia por nombre funciona bien .

Ejemplo de servicio de base de datos dentro de la pila

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

... puede ser consumido por Django app servicio por defecto como este:

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

Entonces, en este caso, cuando expone explícitamente solo servicios públicos, esto parece seguro por defecto

El problema no está en swarm en absoluto y 100% en el formato de composición + la implementación en el docker cli.
Tenga en cuenta que las pilas son 100% una implementación del lado del cliente actualmente.

Lo que sea: dejé de usar stack (debido a este problema) y ya no me importa. Culpe a la biblioteca, culpe al estibador, culpe a mi gato.

No he visto este problema al usar Docker directamente o al usar compose.

Parece que este enfoque puede ayudar (debe ejecutarse en todos los nodos del enjambre):

  1. dejar enjambre
  2. eliminar la red docker_gwbridge
  3. recrear la red docker_gwbridge con la opción adicional com.docker.network.bridge.host_binding_ipv4 = IP
  4. unirse al enjambre de nuevo
    Funciona para puertos publicados en modo "host". Sin el modo "host", la red de entrada se utiliza con otro controlador y alcance "enjambre".

Solución 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 Ni siquiera puedo encontrar docker-proxy en la última versión de Docker. ¿Es algún legado? ¿O el nombre es diferente?

Parece que depende ...

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

Este comportamiento debe documentarse de alguna manera en la documentación .
Actualmente, simplemente ignora el host del mapeo de puertos corto. Y silenciosamente no funciona.

Otra cosa extraña es que no puede configurar el host en el esquema de sintaxis largo.

Este comportamiento debe documentarse de alguna manera en la documentación.

Estoy de acuerdo; Pensé que se había mencionado en algún lugar de esa página, pero no puedo encontrarlo; no dude en abrir un problema en el repositorio de documentos; https://github.com/docker/docker.github.io/issues

Actualmente, simplemente ignora el host del mapeo de puertos corto. Y silenciosamente no funciona.

¿Qué versión de Docker estás usando? debería imprimir una advertencia (cuando se usa docker stack deploy ), o un _error_ (cuando se usa docker service create ); ver https://github.com/moby/moby/issues/32299#issuecomment -472793444

¿Qué versión de Docker estás usando? debería imprimir una advertencia (cuando se usa la implementación de la pila de la ventana acoplable) o un error (cuando se usa el servicio de la ventana acoplable create);

Uf, parece que es culpa mía. Realmente lo hace cuando intenté implementar una pila desde la consola.
Anteriormente, lo hice a través de la interfaz de usuario de portainer y no mostraba ningún error ni advertencia.

Realmente decepcionado de que durante casi dos años algunos de los desarrolladores de Docker ignoren un caso de uso válido y muy útil cuando esa funcionalidad es imprescindible: cuando desea vincular una base de datos relacional contenida como servicio de enjambre a la interfaz local para acceder a ella de forma segura a través del túnel SSH . Actualmente ese escenario es imposible de hacer.

Una solución limpia y viable es ejecutar un servidor SSH en un segundo contenedor que está conectado a la misma red acoplable que su base de datos. El puerto SSH se puede publicar en el host (a un puerto diferente del 22 por supuesto), para que pueda reenviar a través del contenedor SSH a su base de datos.

@nartamonov No veo cómo esto podría hacerse de forma segura desde el ingreso a menos que el protocolo en sí sea seguro.
La forma de acceder a él de forma segura sería a través de un plano de datos encriptados ( --opt encrypted para redes excesivas) y hacer girar un contenedor con las herramientas que necesite conectadas a esa red.

Esto probablemente tiene otros efectos secundarios no relacionados, pero configurar "iptables": false en /etc/docker/daemon.json funciona como solución alternativa. Una solución menos drástica es agregar solo la regla personalizada como sugirió @helldweller .

De cualquier manera, me encantaría ver más apoyo para esto después de 3 años.

Parece que este enfoque puede ayudar (debe ejecutarse en todos los nodos del enjambre):

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 no me equivoco, ¿esto hace que todos los puertos publicados se unan a una dirección IP predeterminada determinada? Entonces, para ser claros, esta no es una solución alternativa utilizable si solo desea restringir la interfaz vinculada para algunos puertos de algunos servicios.

Me gustaría informar sobre mi solución.

Caso de uso:
Algunos servicios en swarm deben estar escuchando en todas las interfaces, o al menos en la interfaz pública; este contenedor en mi ejemplo es un proxy inverso
En esos nodos de enjambre también hay una instancia de base de datos en cada nodo, esos usan una red de enjambre definida como:

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

Los servicios web que necesitan conexiones a la base de datos deben unirse a ese NETWORK_NAME por supuesto

Para fines de administración, a veces, es necesario conectarse directamente a la base de datos

Solución:
Solo los servicios que deben exponerse en todas las redes (proxies inversos en mi ejemplo) pueden tener ports: ['SOMEPORT:ANOTHERPORT'] en su definición de servicios

Todos los demás servicios deben tener un contenedor acoplable sin enjambre acoplado en el host.
Ese contenedor sin enjambre tenderá un puente sobre el puerto presente en NETWORK_NAME/nodeXYZ:port a localhost

Ejemplo con 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

Desventaja: debería haber un contenedor sin enjambre para cada nodo de enjambre, por lo que con muchos nodos es realmente aburrido a menos que se adopten scripts ansible / pesados

Mi solución para el problema "si se está conectando a algunos servicios a través de túneles SSH" que mencionó @ fer2d2 fue agregar un servicio ssh con un Dockerfile como:

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

Luego, en el 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]

lo que me permite agregar mis claves_autorizadas a la carpeta ~/.ssh y luego el proxy ssh salta a través del puerto 2223 a mi base de datos usando el nombre db host

Una solución limpia y viable es ejecutar un servidor SSH en un segundo contenedor que está conectado a la misma red acoplable que su base de datos. El puerto SSH se puede publicar en el host (a un puerto diferente del 22 por supuesto), para que pueda reenviar a través del contenedor SSH a su base de datos.

válido

otro ejemplo de por qué esta característica es importante.
Tengo un servidor con plesk instalado, plesk ya tiene sus configuraciones pero puedo agregar otra configuración solo para apuntar a un servicio de enjambre de docker. Este servidor plesk es un nodo de enjambre.
Me gustaría usar plesk para proxy_pass a un puerto. Este puerto debe publicarse porque el contenedor está en la red superpuesta pero necesita un puerto externo para comunicarse con el mundo.

Entonces, el proxypass debe apuntar a una interfaz local como 127.0.0.1: someport
y el contenedor en el enjambre debe publicar el puerto solo en localhost.

De esta manera, el puerto del contenedor es accesible solo por el proxypass y no desde el mundo directamente

Me gusta tu solución @maxisme , pero ¿cómo gestionas la propiedad de authorized_keys ? En OS X me funciona (el montaje pertenece a root ) pero en una máquina Linux de producción obtengo:

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]

El volumen pertenece al UID del usuario del host, que no es root y SSHD se niega a trabajar con él. Una solución alternativa además de la solución alternativa 😬 es usar configs , así:

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

Entiendo que debido al hecho de que no sabe en qué host se implementará un contenedor, no puede decirle al servicio que se vincule a una dirección IP de host específica.

Sin embargo, a menudo los hosts tienen, por ejemplo, interfaces con límites norte y sur. Es posible que desee que los puertos del enjambre se unan solo a las interfaces en dirección norte en todos los hosts del enjambre.

Si los nombres de interfaz de todas las interfaces a las que desea que se vincule un servicio son los mismos (por ejemplo, eth0), podría ser una idea ofrecer una opción para especificar un nombre de interfaz para vincular puertos de enjambre (en la sección de puertos de servicio).

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

Cuando eth0 no está disponible en un nodo de enjambre, el puerto especificado no estará vinculado a ninguna interfaz.

@ tad-lispy Debería poder cambiar el uid y gid del usuario del contenedor para que sea el mismo que el propietario del volumen en el host.
La imagen de linuxserver admite esto estableciendo variables de entorno (consulte https://hub.docker.com/r/linuxserver/openssh-server, User / Group Identifiers ),

¿Fue útil esta página
0 / 5 - 0 calificaciones