From 7ea305424c02f09ff81ad44560f2e64b689b4b0b Mon Sep 17 00:00:00 2001 From: Justin Palpant <jpalpant@varmour.com> Date: Tue, 22 Aug 2017 12:29:44 -0700 Subject: [PATCH 1/9] Initial cut on switching to traefik and docker stack A basic traefik image with customization is defined under /traefik. The docker-compose file describes a registry and traefik proxy. The registry exposes :5000 and is insecure. It has to come up first, and then other images can be pulled from it. --- Dockerfile | 2 -- README.md | 1 - README.rst | 9 ++++++ docker-compose.yml | 76 ++++++++++++++++++++++++++++++++++++++++++++ traefik/Dockerfile | 4 +++ traefik/static.toml | 40 +++++++++++++++++++++++ traefik/traefik.toml | 69 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 198 insertions(+), 3 deletions(-) delete mode 100644 Dockerfile delete mode 100644 README.md create mode 100644 README.rst create mode 100644 docker-compose.yml create mode 100644 traefik/Dockerfile create mode 100644 traefik/static.toml create mode 100644 traefik/traefik.toml diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 765bbe3..0000000 --- a/Dockerfile +++ /dev/null @@ -1,2 +0,0 @@ -FROM jwilder/nginx-proxy:alpine -LABEL maintainer Justin Palpant <justin@palpant.us> diff --git a/README.md b/README.md deleted file mode 100644 index c9598b3..0000000 --- a/README.md +++ /dev/null @@ -1 +0,0 @@ -Initial commit with README for what will be come the lab NGINX configuration diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..0a4d887 --- /dev/null +++ b/README.rst @@ -0,0 +1,9 @@ +What Is It? +----------- +This project will hold the files I use to describe the infrastructure for hosting applications in my homelab. + +Copyright and License +--------------------- +Copyright 2017 Justin Palpant + +All rights reserved. diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..a81f935 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,76 @@ +version: '3.3' +services: + registry: + image: registry:latest + networks: + - registry-net + ports: + - 5000:5000 + volumes: + - swarm-registry:/var/lib/registry + deploy: + mode: replicated + replicas: 1 + placement: + constraints: + - node.labels.persist-registry == true + + traefik: + image: registry.palpant.us/traefik-public + networks: + - traefik-net + deploy: + mode: replicated + replicas: 1 + labels: + - "traefik.port=8080" + - "traefik.docker.network=traefik-net" + - "traefik.frontend.rule=Host:traefik.palpant.us" + - "traefik.enable=true" + placement: + constraints: + - node.role == manager + ports: + - 9080:80 + volumes: + - /var/run/docker.sock:/var/run/docker.sock + + visualizer: + image: dockersamples/visualizer:stable + volumes: + - "/var/run/docker.sock:/var/run/docker.sock" + deploy: + mode: replicated + replicas: 1 + placement: + constraints: + - node.role == manager + labels: + - "traefik.port=8080" + - "traefik.docker.network=traefik-net" + - "traefik.frontend.rule=Host:visualizer.palpant.us" + - "traefik.enable=true" + networks: + - traefik-net + + test: + image: appropriate/nc:latest + command: sleep 10000 + networks: + - traefik-net + deploy: + mode: replicated + replicas: 1 + placement: + constraints: + - node.role == manager + +networks: + traefik-net: + external: true + registry-net: + external: true + +volumes: + swarm-registry: + external: true diff --git a/traefik/Dockerfile b/traefik/Dockerfile new file mode 100644 index 0000000..4ed5a95 --- /dev/null +++ b/traefik/Dockerfile @@ -0,0 +1,4 @@ +FROM traefik +LABEL maintainer justin@palpant.us + +COPY traefik.toml /etc/traefik/traefik.toml diff --git a/traefik/static.toml b/traefik/static.toml new file mode 100644 index 0000000..621fef3 --- /dev/null +++ b/traefik/static.toml @@ -0,0 +1,40 @@ +# static.toml +[backends] + [backends.backend1] + [backends.backend1.circuitbreaker] + expression = "NetworkErrorRatio() > 0.5" + [backends.backend1.servers.server1] + url = "http://172.17.0.2:80" + weight = 10 + [backends.backend1.servers.server2] + url = "http://172.17.0.3:80" + weight = 1 + [backends.backend2] + [backends.backend1.maxconn] + amount = 10 + extractorfunc = "request.host" + [backends.backend2.LoadBalancer] + method = "drr" + [backends.backend2.servers.server1] + url = "http://172.17.0.4:80" + weight = 1 + [backends.backend2.servers.server2] + url = "http://172.17.0.5:80" + weight = 2 + +[frontends] + [frontends.frontend1] + backend = "backend2" + [frontends.frontend1.routes.test_1] + rule = "Host:test.localhost" + [frontends.frontend2] + backend = "backend1" + passHostHeader = true + priority = 10 + entrypoints = ["https"] # overrides defaultEntryPoints + [frontends.frontend2.routes.test_1] + rule = "Host:{subdomain:[a-z]+}.localhost" + [frontends.frontend3] + entrypoints = ["http", "https"] # overrides defaultEntryPoints + backend = "backend2" + rule = "Path:/test" \ No newline at end of file diff --git a/traefik/traefik.toml b/traefik/traefik.toml new file mode 100644 index 0000000..f935375 --- /dev/null +++ b/traefik/traefik.toml @@ -0,0 +1,69 @@ +# traefik.toml +logLevel = "DEBUG" +defaultEntryPoints = ["http"] +[entryPoints] + [entryPoints.http] + address = ":80" + +[web] +address = ":8080" + +# [file] +# filename = "static.toml" + +################################################################ +# Docker configuration backend +################################################################ + +# Enable Docker configuration backend +# +# Optional +# +[docker] + +# Docker server endpoint. Can be a tcp or a unix socket endpoint. +# +# Required +# +endpoint = "unix:///var/run/docker.sock" + +# Default domain used. +# Can be overridden by setting the "traefik.domain" label on a container. +# +# Required +# +domain = "palpant.us" + +# Enable watch docker changes +# +# Optional +# +watch = true + +# Override default configuration template. For advanced users :) +# +# Optional +# +# filename = "docker.tmpl" + +# Expose containers by default in traefik +# If set to false, containers that don't have `traefik.enable=true` will be ignored +# +# Optional +# Default: true +# +exposedbydefault = false + +# Use the IP address from the binded port instead of the inner network one. For specific use-case :) + +# +# Optional +# Default: false +# +# usebindportip = false +# Use Swarm Mode services as data provider +# +# Optional +# Default: false +# +swarmmode = true \ No newline at end of file -- GitLab From 97b2ec0ca4fe2b6a81cb1a2b492ad25f7a503767 Mon Sep 17 00:00:00 2001 From: Justin Palpant <jpalpant@varmour.com> Date: Tue, 22 Aug 2017 12:44:57 -0700 Subject: [PATCH 2/9] Update to use non-overlapping resource names --- docker-compose.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index a81f935..e06ed1a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,7 +3,7 @@ services: registry: image: registry:latest networks: - - registry-net + - registry-public ports: - 5000:5000 volumes: @@ -13,18 +13,18 @@ services: replicas: 1 placement: constraints: - - node.labels.persist-registry == true + - node.labels.registry == true traefik: image: registry.palpant.us/traefik-public networks: - - traefik-net + - traefik-public deploy: mode: replicated replicas: 1 labels: - "traefik.port=8080" - - "traefik.docker.network=traefik-net" + - "traefik.docker.network=traefik-public" - "traefik.frontend.rule=Host:traefik.palpant.us" - "traefik.enable=true" placement: @@ -47,17 +47,17 @@ services: - node.role == manager labels: - "traefik.port=8080" - - "traefik.docker.network=traefik-net" + - "traefik.docker.network=traefik-public" - "traefik.frontend.rule=Host:visualizer.palpant.us" - "traefik.enable=true" networks: - - traefik-net + - traefik-public test: image: appropriate/nc:latest command: sleep 10000 networks: - - traefik-net + - traefik-public deploy: mode: replicated replicas: 1 @@ -66,9 +66,9 @@ services: - node.role == manager networks: - traefik-net: + traefik-public: external: true - registry-net: + registry-public: external: true volumes: -- GitLab From beef9c6d29b4ad2c9a4cc22ecb36fd70e3e8c468 Mon Sep 17 00:00:00 2001 From: Justin Palpant <jpalpant@varmour.com> Date: Tue, 22 Aug 2017 13:05:01 -0700 Subject: [PATCH 3/9] Change port to avoid conflict with previous service --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index e06ed1a..b668f8d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -31,7 +31,7 @@ services: constraints: - node.role == manager ports: - - 9080:80 + - 11080:80 volumes: - /var/run/docker.sock:/var/run/docker.sock -- GitLab From 48651c43160f56f05a8b15296f1252a9a7b3ff69 Mon Sep 17 00:00:00 2001 From: Justin Palpant <jpalpant@varmour.com> Date: Tue, 22 Aug 2017 16:55:03 -0700 Subject: [PATCH 4/9] Secure the registry with LDAP and break up compose files --- registry/docker-compose.yml | 35 ++++++++ registry/registry-ldap-auth/Dockerfile | 5 ++ registry/registry-ldap-auth/ldap.conf | 6 ++ registry/registry-ldap-auth/nginx.conf | 83 +++++++++++++++++++ spaceshooter/docker-compose.yml | 18 ++++ timpalpantus/docker-compose.yml | 18 ++++ .../docker-compose.yml | 33 -------- 7 files changed, 165 insertions(+), 33 deletions(-) create mode 100644 registry/docker-compose.yml create mode 100644 registry/registry-ldap-auth/Dockerfile create mode 100644 registry/registry-ldap-auth/ldap.conf create mode 100644 registry/registry-ldap-auth/nginx.conf create mode 100644 spaceshooter/docker-compose.yml create mode 100644 timpalpantus/docker-compose.yml rename docker-compose.yml => traefik/docker-compose.yml (63%) diff --git a/registry/docker-compose.yml b/registry/docker-compose.yml new file mode 100644 index 0000000..4f605b4 --- /dev/null +++ b/registry/docker-compose.yml @@ -0,0 +1,35 @@ +version: '3.3' +services: + registry: + image: registry:latest + networks: + - registry-public + volumes: + - swarm-registry:/var/lib/registry + deploy: + mode: replicated + replicas: 1 + placement: + constraints: + - node.labels.registry == true + + registry-ldap-auth: + image: palpantlab-registry-ldap + networks: + - registry-public + ports: + - 12080:80 + deploy: + mode: replicated + replicas: 1 + placement: + constraints: + - node.labels.registry == true + +networks: + registry-public: + external: true + +volumes: + swarm-registry: + external: true diff --git a/registry/registry-ldap-auth/Dockerfile b/registry/registry-ldap-auth/Dockerfile new file mode 100644 index 0000000..cdebea9 --- /dev/null +++ b/registry/registry-ldap-auth/Dockerfile @@ -0,0 +1,5 @@ +FROM h3nrik/registry-ldap-auth +LABEL maintainer Justin Palpant <justin@palpant.us> + +COPY nginx.conf /etc/nginx/nginx.conf +COPY ldap.conf /etc/nginx/ldap.conf diff --git a/registry/registry-ldap-auth/ldap.conf b/registry/registry-ldap-auth/ldap.conf new file mode 100644 index 0000000..74fbab0 --- /dev/null +++ b/registry/registry-ldap-auth/ldap.conf @@ -0,0 +1,6 @@ +url "ldaps://ldap.palpant.us/DC=palpant,DC=us?uid?sub?(&(objectClass=person))"; +group_attribute member; +group_attribute_is_dn on; +require valid_user; +satisfy all; +ssl_check_cert on; \ No newline at end of file diff --git a/registry/registry-ldap-auth/nginx.conf b/registry/registry-ldap-auth/nginx.conf new file mode 100644 index 0000000..036039e --- /dev/null +++ b/registry/registry-ldap-auth/nginx.conf @@ -0,0 +1,83 @@ +worker_processes 1; + +events { + worker_connections 1024; +} + +http { + upstream docker-registry { + server registry:5000; + } + + ## Set a variable to help us decide if we need to add the + ## 'Docker-Distribution-Api-Version' header. + ## The registry always sets this header. + ## In the case of nginx performing auth, the header will be unset + ## since nginx is auth-ing before proxying. + map $upstream_http_docker_distribution_api_version $docker_distribution_api_version { + 'registry/2.0' ''; + default registry/2.0; + } + + ldap_server ldapserver { + include ldap.conf; + } + + server { + listen 80; + server_name docker-registry-proxy; + + # disable any limits to avoid HTTP 413 for large image uploads + client_max_body_size 0; + + # required to avoid HTTP 411: see Issue #1486 (https://github.com/docker/docker/issues/1486) + chunked_transfer_encoding on; + + # For possible locations have a look at https://docs.docker.com/registry/spec/api/#detail + + location /v2/_catalog { + include docker-client.conf; + include docker-registry.conf; + } + + location ~* /v2/(?<namespace>([^/]*))/ { + + include docker-client.conf; + + auth_ldap "Forbidden"; + auth_ldap_servers ldapserver; + + set $deny_write_request ""; + if ($request_method = PUT) { + set $deny_write_request "W"; + } + if ($request_method = POST) { + set $deny_write_request "W"; + } + if ($request_method = PATCH) { + set $deny_write_request "W"; + } + if ($request_method = DELETE) { + set $deny_write_request "W"; + } + if ($remote_user != $namespace) { + set $deny_write_request "${deny_write_request}A"; + } + if ($deny_write_request = 'WA') { + return 401; + } + + include docker-registry.conf; + + } + + location /v2/ { + include docker-client.conf; + auth_ldap "Forbidden"; + auth_ldap_servers ldapserver; + include docker-registry.conf; + } + + } + +} \ No newline at end of file diff --git a/spaceshooter/docker-compose.yml b/spaceshooter/docker-compose.yml new file mode 100644 index 0000000..87b5bae --- /dev/null +++ b/spaceshooter/docker-compose.yml @@ -0,0 +1,18 @@ +version: '3.3' +services: + spaceshooter: + image: registry.palpant.us/spaceshooter + networks: + - traefik-public + deploy: + mode: replicated + replicas: 1 + labels: + - "traefik.port=80" + - "traefik.docker.network=traefik-public" + - "traefik.frontend.rule=Host:spaceshooter.palpant.us" + - "traefik.enable=true" + +networks: + traefik-public: + external: true diff --git a/timpalpantus/docker-compose.yml b/timpalpantus/docker-compose.yml new file mode 100644 index 0000000..64ceb2f --- /dev/null +++ b/timpalpantus/docker-compose.yml @@ -0,0 +1,18 @@ +version: '3.3' +services: + timpalpantus: + image: registry.palpant.us/timpalpant-website + networks: + - traefik-public + deploy: + mode: replicated + replicas: 1 + labels: + - "traefik.port=80" + - "traefik.docker.network=traefik-public" + - "traefik.frontend.rule=Host:tim.palpant.us" + - "traefik.enable=true" + +networks: + traefik-public: + external: true diff --git a/docker-compose.yml b/traefik/docker-compose.yml similarity index 63% rename from docker-compose.yml rename to traefik/docker-compose.yml index b668f8d..1088aa5 100644 --- a/docker-compose.yml +++ b/traefik/docker-compose.yml @@ -1,20 +1,5 @@ version: '3.3' services: - registry: - image: registry:latest - networks: - - registry-public - ports: - - 5000:5000 - volumes: - - swarm-registry:/var/lib/registry - deploy: - mode: replicated - replicas: 1 - placement: - constraints: - - node.labels.registry == true - traefik: image: registry.palpant.us/traefik-public networks: @@ -53,24 +38,6 @@ services: networks: - traefik-public - test: - image: appropriate/nc:latest - command: sleep 10000 - networks: - - traefik-public - deploy: - mode: replicated - replicas: 1 - placement: - constraints: - - node.role == manager - networks: traefik-public: external: true - registry-public: - external: true - -volumes: - swarm-registry: - external: true -- GitLab From 7d6f61db07ca3ecc559cc9d0790cc9addb9697ec Mon Sep 17 00:00:00 2001 From: Justin Palpant <jpalpant@varmour.com> Date: Tue, 22 Aug 2017 19:04:38 -0700 Subject: [PATCH 5/9] Switch to private network --- registry/docker-compose.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/registry/docker-compose.yml b/registry/docker-compose.yml index 4f605b4..92615e1 100644 --- a/registry/docker-compose.yml +++ b/registry/docker-compose.yml @@ -3,7 +3,7 @@ services: registry: image: registry:latest networks: - - registry-public + - registry-private volumes: - swarm-registry:/var/lib/registry deploy: @@ -14,11 +14,11 @@ services: - node.labels.registry == true registry-ldap-auth: - image: palpantlab-registry-ldap + image: palpantlab-registry-ldap # not a registry image! Must be built without registry on registry host networks: - - registry-public + - registry-private ports: - - 12080:80 + - 12080:80 # not a Traefik port! Must run before traefik deploy: mode: replicated replicas: 1 @@ -27,7 +27,7 @@ services: - node.labels.registry == true networks: - registry-public: + registry-private: external: true volumes: -- GitLab From 9a3c2b693c3860414ffe660b1f571ce35c7f5258 Mon Sep 17 00:00:00 2001 From: Justin Palpant <jpalpant@varmour.com> Date: Tue, 22 Aug 2017 19:34:21 -0700 Subject: [PATCH 6/9] Remove registry LDAP authenticator and expose registry --- registry/docker-compose.yml | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/registry/docker-compose.yml b/registry/docker-compose.yml index 92615e1..f1cef98 100644 --- a/registry/docker-compose.yml +++ b/registry/docker-compose.yml @@ -6,19 +6,8 @@ services: - registry-private volumes: - swarm-registry:/var/lib/registry - deploy: - mode: replicated - replicas: 1 - placement: - constraints: - - node.labels.registry == true - - registry-ldap-auth: - image: palpantlab-registry-ldap # not a registry image! Must be built without registry on registry host - networks: - - registry-private ports: - - 12080:80 # not a Traefik port! Must run before traefik + - 12080:5000 deploy: mode: replicated replicas: 1 @@ -26,6 +15,19 @@ services: constraints: - node.labels.registry == true + # registry-ldap-auth: + # image: palpantlab-registry-ldap # not a registry image! Must be built without registry on registry host + # networks: + # - registry-private + # ports: + # - 12080:80 # not a Traefik port! Must run before traefik + # deploy: + # mode: replicated + # replicas: 1 + # placement: + # constraints: + # - node.labels.registry == true + networks: registry-private: external: true -- GitLab From 64f169870c37ef2d9f1eb180e70f548ae29a3758 Mon Sep 17 00:00:00 2001 From: Justin Palpant <jpalpant@varmour.com> Date: Fri, 25 Aug 2017 22:37:05 -0700 Subject: [PATCH 7/9] Traefik doesn't support SSL Passthrough To get around this I will expose one more port and server any services that require SSL passthrough with SNI behind that port, using docker-flow-proxy as my dynamically reconfiguring proxy. docker-flow-proxy listens to swarm and updates HAProxy, and supports SNI-based SSL passthrough. For now, I will use docker-flow-proxy for registry and auth server, and traefik for http services or services where I want https termination. --- auth/Dockerfile | 9 +++ auth/config/auth_config.yml | 54 +++++++++++++++++ auth/docker-compose.yml | 32 ++++++++++ auth/start.sh | 17 ++++++ flowproxy/Dockerfile | 3 + flowproxy/docker-compose.yml | 36 +++++++++++ registry/Dockerfile | 4 ++ registry/conf/config.yml | 30 ++++++++++ registry/docker-compose.yml | 35 +++++------ registry/registry-ldap-auth/Dockerfile | 5 -- registry/registry-ldap-auth/ldap.conf | 6 -- registry/registry-ldap-auth/nginx.conf | 83 -------------------------- 12 files changed, 201 insertions(+), 113 deletions(-) create mode 100644 auth/Dockerfile create mode 100644 auth/config/auth_config.yml create mode 100644 auth/docker-compose.yml create mode 100644 auth/start.sh create mode 100644 flowproxy/Dockerfile create mode 100644 flowproxy/docker-compose.yml create mode 100644 registry/Dockerfile create mode 100644 registry/conf/config.yml delete mode 100644 registry/registry-ldap-auth/Dockerfile delete mode 100644 registry/registry-ldap-auth/ldap.conf delete mode 100644 registry/registry-ldap-auth/nginx.conf diff --git a/auth/Dockerfile b/auth/Dockerfile new file mode 100644 index 0000000..865bf32 --- /dev/null +++ b/auth/Dockerfile @@ -0,0 +1,9 @@ +FROM cesanta/docker_auth +LABEL maintainer Justin Palpant <justin@palpant.us> + +COPY start.sh /start.sh +RUN chmod +x /start.sh +RUN chmod 777 /start.sh +COPY config /config + +ENTRYPOINT /start.sh diff --git a/auth/config/auth_config.yml b/auth/config/auth_config.yml new file mode 100644 index 0000000..c8a9035 --- /dev/null +++ b/auth/config/auth_config.yml @@ -0,0 +1,54 @@ +# . See reference.yml for explanation for explanation of all options. +# +# auth: +# token: +# realm: "https://127.0.0.1:5001/auth" +# service: "Docker registry" +# issuer: "Acme auth server" +# rootcertbundle: "/path/to/server.pem" + +server: + addr: ":5001" + certificate: "/run/secrets/auth-cert" + key: "/run/secrets/auth-key" + +token: + issuer: "Acme auth server" # Must match issuer in the Registry config. + expiration: 900 + +# LDAP authentication. +# Authentication is performed by first binding to the server, looking up the user entry +# by using the specified filter, and then re-binding using the matched DN and the password provided. +# ldap_auth: +# addr: "ldaps://ldap.palpant.us" +# #tls: true +# # In case bind DN and password is required for querying user information, +# # specify them here. Plain text password is read from the file. +# base: "dc=palpant,dc=us" +# filter: "(&(uid=${account})(objectClass=organizationalPerson))" + +users: + # Password is specified as a BCrypt hash. Use htpasswd -B to generate. + "admin": + password: "$2y$05$LO.vzwpWC5LZGqThvEfznu8qhb5SGqvBSWY1J3yZ4AxtMRZ3kN5jC" # badmin + "test": + password: "$2y$05$WuwBasGDAgr.QCbGIjKJaep4dhxeai9gNZdmBnQXqpKly57oNutya" # 123 + +acl: + # Admin has full access to everything. + - match: {account: "admin"} + actions: ["*"] + + # User "user" can pull stuff. + - match: {account: "test"} + actions: ["pull"] + + # This will allow authenticated users to pull/push + - match: + account: /.+/ + actions: ['*'] + + # The user "serviceaccount" (from LDAP) may not perform any docker actions + # like push or pull. + - match: {account: "serviceaccount"} + actions: [] diff --git a/auth/docker-compose.yml b/auth/docker-compose.yml new file mode 100644 index 0000000..cee03b2 --- /dev/null +++ b/auth/docker-compose.yml @@ -0,0 +1,32 @@ +version: '3.3' +services: + auth: + image: palpantlab-auth + # ports: + # - 5001:5001 + networks: + - flowproxy + secrets: + - auth-cert + - auth-key + deploy: + mode: replicated + replicas: 1 + labels: + - com.df.notify=true + - com.df.distribute=true + - com.df.serviceDomain=auth.palpant.us + - com.df.port=5001 + - com.df.srcPort=9669 + - com.df.reqMode=sni + +networks: + flowproxy: + external: true + +secrets: + auth-cert: + external: true + auth-key: + external: true + diff --git a/auth/start.sh b/auth/start.sh new file mode 100644 index 0000000..5d17626 --- /dev/null +++ b/auth/start.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +# Copy over certificates to correct place and update certificate storage +# find "/config/ldap_certificates" -type f -exec cp -fv {} /usr/local/share/ca-certificates/ \; +# update-ca-certificates + +# # Replace newline and carriage returns in password file +# cat /config/ldap_password.txt | tr -d '\r\n' > /tmp/ldap_password.txt.clean + +# # If we see a custom config file, we load that instead of the default one +CONF_PATH=/config/auth_config.yml +if [ -f $CONF_PATH.custom ]; then + CONF_PATH=$CONF_PATH.custom +fi + +# Start the auth server +/docker_auth/auth_server -v=5 $CONF_PATH diff --git a/flowproxy/Dockerfile b/flowproxy/Dockerfile new file mode 100644 index 0000000..1929676 --- /dev/null +++ b/flowproxy/Dockerfile @@ -0,0 +1,3 @@ +FROM vfarcic/docker-flow-proxy:beta + +HEALTHCHECK --interval=5s --timeout=5s CMD wget -qO- "http://localhost:8080/v1/docker-flow-proxy/ping" diff --git a/flowproxy/docker-compose.yml b/flowproxy/docker-compose.yml new file mode 100644 index 0000000..ff1381e --- /dev/null +++ b/flowproxy/docker-compose.yml @@ -0,0 +1,36 @@ +version: "3.3" +services: + proxy: + image: palpantlab-flowproxy + ports: + - 8080:8080 + - 9669:9669 + networks: + - flowproxy + environment: + - LISTENER_ADDRESS=swarm-listener + - MODE=swarm + - DEBUG=true + deploy: + replicas: 1 + + swarm-listener: + image: vfarcic/docker-flow-swarm-listener + networks: + - flowproxy + environment: + - DF_NOTIFY_CREATE_SERVICE_URL=http://proxy:8080/v1/docker-flow-proxy/reconfigure + - DF_NOTIFY_REMOVE_SERVICE_URL=http://proxy:8080/v1/docker-flow-proxy/remove + - DF_INTERVAL=1 + volumes: + - /var/run/docker.sock:/var/run/docker.sock + deploy: + mode: replicated + replicas: 1 + placement: + constraints: + - node.role == manager + +networks: + flowproxy: + external: true diff --git a/registry/Dockerfile b/registry/Dockerfile new file mode 100644 index 0000000..73ce35a --- /dev/null +++ b/registry/Dockerfile @@ -0,0 +1,4 @@ +FROM registry:latest +LABEL maintainer Justin Palpant <justin@palpant.us> + +COPY conf /etc/docker/registry diff --git a/registry/conf/config.yml b/registry/conf/config.yml new file mode 100644 index 0000000..2adac53 --- /dev/null +++ b/registry/conf/config.yml @@ -0,0 +1,30 @@ +version: 0.1 +log: + fields: + service: registry +storage: + cache: + blobdescriptor: inmemory + filesystem: + rootdirectory: /var/lib/registry +http: + addr: :5000 + host: https://registry.palpant.us + headers: + X-Content-Type-Options: [nosniff] + tls: + certificate: /run/secrets/registry_cert + key: /run/secrets/registry_key + http2: + disabled: false +health: + storagedriver: + enabled: true + interval: 10s + threshold: 3 +auth: + token: + realm: "https://auth.palpant.us/auth" + service: "registry.palpant.us" + issuer: "Acme auth server" + rootcertbundle: /run/secrets/auth_cert diff --git a/registry/docker-compose.yml b/registry/docker-compose.yml index f1cef98..e6b4a94 100644 --- a/registry/docker-compose.yml +++ b/registry/docker-compose.yml @@ -1,35 +1,32 @@ version: '3.3' services: registry: - image: registry:latest - networks: - - registry-private + image: palpantlab-registry volumes: - swarm-registry:/var/lib/registry - ports: - - 12080:5000 + networks: + - flowproxy + # ports: + # - 5000:5000 + secrets: + - registry_cert + - registry_key deploy: + labels: + - com.df.notify=true + - com.df.distribute=true + - com.df.serviceDomain=registry.palpant.us + - com.df.port=5000 + - com.df.srcPort=9669 + - com.df.reqMode=sni mode: replicated replicas: 1 placement: constraints: - node.labels.registry == true - # registry-ldap-auth: - # image: palpantlab-registry-ldap # not a registry image! Must be built without registry on registry host - # networks: - # - registry-private - # ports: - # - 12080:80 # not a Traefik port! Must run before traefik - # deploy: - # mode: replicated - # replicas: 1 - # placement: - # constraints: - # - node.labels.registry == true - networks: - registry-private: + flowproxy: external: true volumes: diff --git a/registry/registry-ldap-auth/Dockerfile b/registry/registry-ldap-auth/Dockerfile deleted file mode 100644 index cdebea9..0000000 --- a/registry/registry-ldap-auth/Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM h3nrik/registry-ldap-auth -LABEL maintainer Justin Palpant <justin@palpant.us> - -COPY nginx.conf /etc/nginx/nginx.conf -COPY ldap.conf /etc/nginx/ldap.conf diff --git a/registry/registry-ldap-auth/ldap.conf b/registry/registry-ldap-auth/ldap.conf deleted file mode 100644 index 74fbab0..0000000 --- a/registry/registry-ldap-auth/ldap.conf +++ /dev/null @@ -1,6 +0,0 @@ -url "ldaps://ldap.palpant.us/DC=palpant,DC=us?uid?sub?(&(objectClass=person))"; -group_attribute member; -group_attribute_is_dn on; -require valid_user; -satisfy all; -ssl_check_cert on; \ No newline at end of file diff --git a/registry/registry-ldap-auth/nginx.conf b/registry/registry-ldap-auth/nginx.conf deleted file mode 100644 index 036039e..0000000 --- a/registry/registry-ldap-auth/nginx.conf +++ /dev/null @@ -1,83 +0,0 @@ -worker_processes 1; - -events { - worker_connections 1024; -} - -http { - upstream docker-registry { - server registry:5000; - } - - ## Set a variable to help us decide if we need to add the - ## 'Docker-Distribution-Api-Version' header. - ## The registry always sets this header. - ## In the case of nginx performing auth, the header will be unset - ## since nginx is auth-ing before proxying. - map $upstream_http_docker_distribution_api_version $docker_distribution_api_version { - 'registry/2.0' ''; - default registry/2.0; - } - - ldap_server ldapserver { - include ldap.conf; - } - - server { - listen 80; - server_name docker-registry-proxy; - - # disable any limits to avoid HTTP 413 for large image uploads - client_max_body_size 0; - - # required to avoid HTTP 411: see Issue #1486 (https://github.com/docker/docker/issues/1486) - chunked_transfer_encoding on; - - # For possible locations have a look at https://docs.docker.com/registry/spec/api/#detail - - location /v2/_catalog { - include docker-client.conf; - include docker-registry.conf; - } - - location ~* /v2/(?<namespace>([^/]*))/ { - - include docker-client.conf; - - auth_ldap "Forbidden"; - auth_ldap_servers ldapserver; - - set $deny_write_request ""; - if ($request_method = PUT) { - set $deny_write_request "W"; - } - if ($request_method = POST) { - set $deny_write_request "W"; - } - if ($request_method = PATCH) { - set $deny_write_request "W"; - } - if ($request_method = DELETE) { - set $deny_write_request "W"; - } - if ($remote_user != $namespace) { - set $deny_write_request "${deny_write_request}A"; - } - if ($deny_write_request = 'WA') { - return 401; - } - - include docker-registry.conf; - - } - - location /v2/ { - include docker-client.conf; - auth_ldap "Forbidden"; - auth_ldap_servers ldapserver; - include docker-registry.conf; - } - - } - -} \ No newline at end of file -- GitLab From 6fe8bf10e2e2a64376692bd386e5345c950200cc Mon Sep 17 00:00:00 2001 From: Justin Palpant <jpalpant@varmour.com> Date: Sat, 26 Aug 2017 18:19:17 -0700 Subject: [PATCH 8/9] Manually configure HAProxy to support registry, auth, and NAS --- auth/config/auth_config.yml | 10 ++-- auth/docker-compose.yml | 7 --- flowproxy/Dockerfile | 6 +-- flowproxy/docker-compose.yml | 25 +--------- flowproxy/haproxy.cfg | 94 +++++++++++++++++++++++++++++++++++ registry/conf/config.yml | 6 +-- registry/docker-compose.yml | 20 ++++---- traefik/docker-compose.yml | 18 ------- visualizer/docker-compose.yml | 23 +++++++++ 9 files changed, 141 insertions(+), 68 deletions(-) create mode 100644 flowproxy/haproxy.cfg create mode 100644 visualizer/docker-compose.yml diff --git a/auth/config/auth_config.yml b/auth/config/auth_config.yml index c8a9035..a400bea 100644 --- a/auth/config/auth_config.yml +++ b/auth/config/auth_config.yml @@ -21,11 +21,11 @@ token: # by using the specified filter, and then re-binding using the matched DN and the password provided. # ldap_auth: # addr: "ldaps://ldap.palpant.us" -# #tls: true +# tls: true # # In case bind DN and password is required for querying user information, # # specify them here. Plain text password is read from the file. # base: "dc=palpant,dc=us" -# filter: "(&(uid=${account})(objectClass=organizationalPerson))" +# filter: "(&(uid=${uid})(objectClass=person))" users: # Password is specified as a BCrypt hash. Use htpasswd -B to generate. @@ -44,9 +44,9 @@ acl: actions: ["pull"] # This will allow authenticated users to pull/push - - match: - account: /.+/ - actions: ['*'] + # - match: + # account: /.+/ + # actions: ['*'] # The user "serviceaccount" (from LDAP) may not perform any docker actions # like push or pull. diff --git a/auth/docker-compose.yml b/auth/docker-compose.yml index cee03b2..010f3fa 100644 --- a/auth/docker-compose.yml +++ b/auth/docker-compose.yml @@ -12,13 +12,6 @@ services: deploy: mode: replicated replicas: 1 - labels: - - com.df.notify=true - - com.df.distribute=true - - com.df.serviceDomain=auth.palpant.us - - com.df.port=5001 - - com.df.srcPort=9669 - - com.df.reqMode=sni networks: flowproxy: diff --git a/flowproxy/Dockerfile b/flowproxy/Dockerfile index 1929676..5d3e2dc 100644 --- a/flowproxy/Dockerfile +++ b/flowproxy/Dockerfile @@ -1,3 +1,3 @@ -FROM vfarcic/docker-flow-proxy:beta - -HEALTHCHECK --interval=5s --timeout=5s CMD wget -qO- "http://localhost:8080/v1/docker-flow-proxy/ping" +FROM haproxy:1.7-alpine +LABEL maintainer Justin Palpant <justin@palpant.us> +COPY haproxy.cfg /usr/local/etc/haproxy/haproxy.cfg diff --git a/flowproxy/docker-compose.yml b/flowproxy/docker-compose.yml index ff1381e..01eefe0 100644 --- a/flowproxy/docker-compose.yml +++ b/flowproxy/docker-compose.yml @@ -1,35 +1,14 @@ version: "3.3" services: proxy: - image: palpantlab-flowproxy + image: palpantlab-haproxy ports: - - 8080:8080 - - 9669:9669 + - 443:443 networks: - flowproxy - environment: - - LISTENER_ADDRESS=swarm-listener - - MODE=swarm - - DEBUG=true - deploy: - replicas: 1 - - swarm-listener: - image: vfarcic/docker-flow-swarm-listener - networks: - - flowproxy - environment: - - DF_NOTIFY_CREATE_SERVICE_URL=http://proxy:8080/v1/docker-flow-proxy/reconfigure - - DF_NOTIFY_REMOVE_SERVICE_URL=http://proxy:8080/v1/docker-flow-proxy/remove - - DF_INTERVAL=1 - volumes: - - /var/run/docker.sock:/var/run/docker.sock deploy: mode: replicated replicas: 1 - placement: - constraints: - - node.role == manager networks: flowproxy: diff --git a/flowproxy/haproxy.cfg b/flowproxy/haproxy.cfg new file mode 100644 index 0000000..00c1f84 --- /dev/null +++ b/flowproxy/haproxy.cfg @@ -0,0 +1,94 @@ +# Adjust the timeout to your needs +global + pidfile /var/run/haproxy.pid + tune.ssl.default-dh-param 2048 + log 127.0.0.1:1514 local0 + + # disable sslv3, prefer modern ciphers + ssl-default-bind-options no-sslv3 + ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS + + ssl-default-server-options no-sslv3 + ssl-default-server-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS + +resolvers docker + nameserver dns 127.0.0.11:53 + +defaults + balance roundrobin + + maxconn 5000 + timeout connect 5s + timeout client 20s + timeout server 20s + timeout queue 30s + timeout tunnel 3600s + +frontend sni_redirect + bind *:443 + mode tcp + + option tcplog + log global + + tcp-request inspect-delay 5s + tcp-request content accept if { req_ssl_hello_type 1 } + + acl registry_sni req.ssl_sni -i registry.palpant.us + use_backend registry_backend if registry_sni + + acl auth_sni req.ssl_sni -i auth.palpant.us + use_backend auth_backend if auth_sni + + default_backend bk_ssl_default + +backend registry_backend + mode tcp + # maximum SSL session ID length is 32 bytes. + stick-table type binary len 32 size 30k expire 30m + + acl clienthello req_ssl_hello_type 1 + acl serverhello rep_ssl_hello_type 2 + + # use tcp content accepts to detects ssl client and server hello. + tcp-request inspect-delay 5s + tcp-request content accept if clienthello + + # no timeout on response inspect delay by default. + tcp-response content accept if serverhello + + stick on payload_lv(43,1) if clienthello + + # Learn on response if server hello. + stick store-response payload_lv(43,1) if serverhello + + server registry registry:5000 + +backend auth_backend + mode tcp + + # maximum SSL session ID length is 32 bytes. + stick-table type binary len 32 size 30k expire 30m + + acl clienthello req_ssl_hello_type 1 + acl serverhello rep_ssl_hello_type 2 + + # use tcp content accepts to detects ssl client and server hello. + tcp-request inspect-delay 5s + tcp-request content accept if clienthello + + # no timeout on response inspect delay by default. + tcp-response content accept if serverhello + + stick on payload_lv(43,1) if clienthello + + # Learn on response if server hello. + stick store-response payload_lv(43,1) if serverhello + + option ssl-hello-chk + server auth auth:5001 + +backend bk_ssl_default + mode tcp + + server nas_rproxy nas.sfo.palpant.us:443 \ No newline at end of file diff --git a/registry/conf/config.yml b/registry/conf/config.yml index 2adac53..dace61c 100644 --- a/registry/conf/config.yml +++ b/registry/conf/config.yml @@ -13,8 +13,8 @@ http: headers: X-Content-Type-Options: [nosniff] tls: - certificate: /run/secrets/registry_cert - key: /run/secrets/registry_key + certificate: /run/secrets/registry-cert + key: /run/secrets/registry-key http2: disabled: false health: @@ -27,4 +27,4 @@ auth: realm: "https://auth.palpant.us/auth" service: "registry.palpant.us" issuer: "Acme auth server" - rootcertbundle: /run/secrets/auth_cert + rootcertbundle: /run/secrets/auth-cert diff --git a/registry/docker-compose.yml b/registry/docker-compose.yml index e6b4a94..cd99e8b 100644 --- a/registry/docker-compose.yml +++ b/registry/docker-compose.yml @@ -9,16 +9,10 @@ services: # ports: # - 5000:5000 secrets: - - registry_cert - - registry_key + - registry-cert + - registry-key + - auth-cert deploy: - labels: - - com.df.notify=true - - com.df.distribute=true - - com.df.serviceDomain=registry.palpant.us - - com.df.port=5000 - - com.df.srcPort=9669 - - com.df.reqMode=sni mode: replicated replicas: 1 placement: @@ -32,3 +26,11 @@ networks: volumes: swarm-registry: external: true + +secrets: + registry-cert: + external: true + registry-key: + external: true + auth-cert: + external: true diff --git a/traefik/docker-compose.yml b/traefik/docker-compose.yml index 1088aa5..f0f487e 100644 --- a/traefik/docker-compose.yml +++ b/traefik/docker-compose.yml @@ -20,24 +20,6 @@ services: volumes: - /var/run/docker.sock:/var/run/docker.sock - visualizer: - image: dockersamples/visualizer:stable - volumes: - - "/var/run/docker.sock:/var/run/docker.sock" - deploy: - mode: replicated - replicas: 1 - placement: - constraints: - - node.role == manager - labels: - - "traefik.port=8080" - - "traefik.docker.network=traefik-public" - - "traefik.frontend.rule=Host:visualizer.palpant.us" - - "traefik.enable=true" - networks: - - traefik-public - networks: traefik-public: external: true diff --git a/visualizer/docker-compose.yml b/visualizer/docker-compose.yml new file mode 100644 index 0000000..7821e88 --- /dev/null +++ b/visualizer/docker-compose.yml @@ -0,0 +1,23 @@ +version: '3.3' +services: + visualizer: + image: dockersamples/visualizer:stable + volumes: + - "/var/run/docker.sock:/var/run/docker.sock" + deploy: + mode: replicated + replicas: 1 + placement: + constraints: + - node.role == manager + labels: + - "traefik.port=8080" + - "traefik.docker.network=traefik-public" + - "traefik.frontend.rule=Host:visualizer.palpant.us" + - "traefik.enable=true" + networks: + - traefik-public + +networks: + traefik-public: + external: true -- GitLab From cd9f02630fe4b791b35b289b426d868d93ea3c38 Mon Sep 17 00:00:00 2001 From: Justin Palpant <jpalpant@varmour.com> Date: Sat, 26 Aug 2017 19:39:18 -0700 Subject: [PATCH 9/9] Constraint auth and haproxy to nodes where those images are built. --- auth/docker-compose.yml | 3 +++ flowproxy/docker-compose.yml | 3 +++ 2 files changed, 6 insertions(+) diff --git a/auth/docker-compose.yml b/auth/docker-compose.yml index 010f3fa..3dd4b21 100644 --- a/auth/docker-compose.yml +++ b/auth/docker-compose.yml @@ -12,6 +12,9 @@ services: deploy: mode: replicated replicas: 1 + placement: + constraints: + - node.labels.auth == true networks: flowproxy: diff --git a/flowproxy/docker-compose.yml b/flowproxy/docker-compose.yml index 01eefe0..4ecb3cb 100644 --- a/flowproxy/docker-compose.yml +++ b/flowproxy/docker-compose.yml @@ -9,6 +9,9 @@ services: deploy: mode: replicated replicas: 1 + placement: + constraints: + - node.labels.haproxy == true networks: flowproxy: -- GitLab