3

Specifically, I want them to run the following: https://django-q.readthedocs.io/en/latest/monitor.html

I am looking to write a minimal wrapper-script which would simply allow them to run a single command, for example, myproject-admin manage qmonitor from their own machines (connecting to live Docker swarm as necessary) and returning the output they need to their machines.

Currently, the networks I have created are not attachable by non-swarm containers.

Is there a security risk to allowing docker swarm networks to become attachable?

The solution I can think about is to reconfigure the network to be attachable so that the wrapper script could via ssh, execute docker run -it --rm --network database --name task-name_2020-05-29_12-51-00 django_image:2020-05-29 /app/manage.py qmonitor

Without changing the network to be attachable, is there another way of accessing the database?

I know I could exec against the running web server but isn't that bad practice?

In the future, if this project generates income, the database would move to Amazon RDS or similar. For security, I would want to limit access of the database to the Docker swarm database network as well so that the database is not accessible via the host (is that possible? If so, the scenario I laid out here still reflects the nature of the problem)

Another possible solution I thought about is creating a temporary network link to the database via ssh port forwarding (or another means), and then getting the admins to run the command locally (Django docker container run locally) but communicating to the database. This is preferable because it would allow the devs to use their own system resources (but might not be ideal if bandwidth becomes the constraint).

Any alternate suggestions on my architecture to circumvent this problem would also be appreciated. Currently, this is a pet project to develop my skills. Docker swarm is probably not yet required, but I require a live project to practice my skills, hence why it is being used in this case.


For context, here is my working docker-compose file which I use for the project (slightly modified):

The only commands done as a pre-requisite are docker secrets create ..., docker network create -d overlay --scope swarm database and docker network create -d overlay --scope swarm traefik

version: "3.8"

networks:
  traefik:
    external: true
    name: traefik
  database:
    external: true
    name: database

secrets:
  DJANGO_SECRETS_FILE:
    external: true
  HASURA_SECRETS_FILE:
    external: true
  POSTGRES_PASSWORD_FILE:
    external: true
  CF_API_EMAIL_FILE:
    external: true
  CF_API_KEY_FILE:
    external: true

volumes:
  staticfiles: {}
  database: {}

services:

  django:
    command: gunicorn config.wsgi:app -w 4 -b 0.0.0.0:8000
    depends_on:
      - postgres
    deploy:
      labels:
        traefik.enable: "true"
        traefik.http.routers.django.entrypoints: http
        traefik.http.routers.django.rule: Host(`admin.myproject.***.dev`)
        traefik.http.routers.django-secure.entrypoints: https
        traefik.http.routers.django-secure.rule: Host(`admin.myproject.***.dev`)
        traefik.http.routers.django-secure.tls.certresolver: dns
        traefik.http.services.django.loadbalancer.server.port: 8000
      restart_policy:
        condition: on-failure
    environment:
      ALLOWED_HOSTS: admin.myproject.***.dev
      DEBUG: "true"
      DJANGO_CONFIGURATION: Staging
      DJANGO_SECRETS_FILE: /run/secrets/DJANGO_SECRETS_FILE
    image: django_image:2020-05-29
    networks:
      - traefik
      - database
    secrets:
      - DJANGO_SECRETS_FILE
    volumes:
      - staticfiles:/static
    working_dir: /app

  hasura:
    command:
      - graphql-engine
      - serve
      - --server-port=5000
    depends_on:
      - postgres
    deploy:
      labels:
        traefik.enable: "true"
        traefik.http.routers.hasura.entrypoints: http
        traefik.http.routers.hasura.rule: Host(`api.myproject.***.dev`)
        traefik.http.routers.hasura-secure.entrypoints: https
        traefik.http.routers.hasura-secure.rule: Host(`api.myproject.***.dev`)
        traefik.http.routers.hasura-secure.tls.certresolver: dns
        traefik.http.services.hasura.loadbalancer.server.port: 5000
      restart_policy:
        condition: on-failure
    entrypoint:
      - sh
      - /hasura-entrypoint.sh
    environment:
      HASURA_GRAPHQL_ENABLE_CONSOLE: "true"
      HASURA_SECRETS_FILE: /run/secrets/HASURA_SECRETS_FILE
    image: hasura/graphql-engine:v1.2.1
    networks:
      - traefik
      - database
    secrets:
      - HASURA_SECRETS_FILE
    volumes:
      - ./scripts/hasura-entrypoint.sh:/hasura-entrypoint.sh

  postgres:
    deploy:
      restart_policy:
        condition: on-failure
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/POSTGRES_PASSWORD_FILE
      POSTGRES_USER: staging
      POSTGRES_DB: staging
    image: postgres:12.3-alpine
    networks:
      - database
    volumes:
      - database:/var/lib/postgresql/data
    secrets:
      - POSTGRES_PASSWORD_FILE

  traefik:
    command:
      - --api.insecure=true
      - --api.dashboard=true
      - --api.debug=true
      - --certificatesResolvers.dns.acme.dnsChallenge.delayBeforeCheck=0
      - --certificatesResolvers.dns.acme.dnsChallenge.provider=cloudflare
      - --entrypoints.http.address=:80
      - --entrypoints.https.address=:443
      - --log.level=DEBUG
      - --providers.docker=true
      - --providers.docker.endpoint=unix:///var/run/docker.sock
      - --providers.docker.exposedbydefault=false
      - --providers.docker.network=traefik
      - --providers.docker.swarmMode=true
    deploy:
      labels:
        traefik.enable: "true"
        traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme: https
        traefik.http.routers.traefik.entrypoints: http
        traefik.http.routers.traefik.middlewares: traefik-https-redirect
        traefik.http.routers.traefik.rule: Host(`dash.myproject.***.dev`)
        traefik.http.routers.traefik-secure.entrypoints: https
        traefik.http.routers.traefik-secure.rule: Host(`dash.myproject.***.dev`)
        traefik.http.routers.traefik-secure.service: api@internal
        traefik.http.routers.traefik-secure.tls: "true"
        traefik.http.routers.traefik-secure.tls.certresolver: dns
        traefik.http.services.traefik.loadbalancer.server.port: 8080
      placement:
        constraints:
          - node.role == manager
      restart_policy:
        condition: on-failure
    environment:
      CF_API_EMAIL_FILE: /run/secrets/CF_API_EMAIL_FILE
      CF_API_KEY_FILE: /run/secrets/CF_API_KEY_FILE
    image: traefik:v2.2.1
    networks:
      - traefik
    ports:
      - 80:80
      - 443:443
    secrets:
      - CF_API_EMAIL_FILE
      - CF_API_KEY_FILE
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./acme.json:/acme.json

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.