From b6ee6d3ce27ff685f11c48ac614a57120a132eee Mon Sep 17 00:00:00 2001 From: Andrey Arapov Date: Wed, 11 Jul 2018 09:35:42 +0200 Subject: [PATCH] update readme and tests --- README.md | 142 +++++++++++++++++++++--------------------------------- testme.sh | 2 +- 2 files changed, 55 insertions(+), 89 deletions(-) diff --git a/README.md b/README.md index 25942fe..fba72ad 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,18 @@ self-signed CA. ## Purpose +The whole idea is to run the ``gencert.sh`` script right before starting the +service and then, making sure the reverse proxy updates its main CA bundle +right before starting. + +Some services require the certificate on their backend and would not be +satisfied with the TLS termination elsewhere. + +For example, one of such services is Minio. It [requires](https://github.com/minio/minio/issues/6093) its certificate in order +to enable SSE-C (Server Side Encryption with Customer provided keys). + +## How does this script work + This script will always produce a self-signed x509 certificate with the IP addresses embedded to x509's SAN. @@ -14,121 +26,75 @@ which may need to authenticate against this self-signed certificate. The authentication works in a way that a public CA certificate will be used by the client in order to validate the server's certificate. -## Application - -### Backend requiring x509 running behind reverse proxy - -This script has been created in order to ease the Minio's SSE-C -(Server Side Encryption - Customer provided keys) enablement when -Minio server is running as a backend behind a reverse proxy like Traefik. - -Minio server enables SSE-C only when it detects the x509 certificates. - -Traefik (running with docker service provider or similar) is talking to the -backend using the IP address rather than a hostname. - -Usually, the IP address is not static, hence this script comes handy. - -## Script logic - - generate CA certificate if does not find any - always generate server certificate on startup to ensure all IP addresses are in x509 SAN - warn if the CA certificate is about to expire (<30 days till expiration) - regenerate the CA certificate if it finds it has expired -## Notes +> - The CA certificate will be valid for 3650 days (10 years) +> - The server certifcate will be valid for 365 days (1 year) +> - The x509 certs are ECDSA with prime256v1 curve and SHA256 signatures -- The CA certificate will be valid for 3650 days (10 years) -- The server certifcate will be valid for 365 days (1 year) -- The x509 certs are ECDSA with prime256v1 curve and SHA256 signatures - -## Testing - -I have added a simplistic script [testme.sh](testme.sh) that helps to test this -script in the following Linux distributions: - -- Alpine 3.7 -- Ubuntu Bionic -- Debian Stretch -- CentOS 7 +## Examples -## Usage example +### Minio and Docker Registry services with Traefik reverse proxy -### Minio server with Traefik example +- docker-compose.yml -1. Replace ``minio server`` command with the following one: - ``cd /root/.minio/certs && ./gencert.sh --cn minio.example.com && minio server /data`` -2. Copy the CA certificate ``ca.crt`` file to ``/usr/local/share/ca-certificates/`` and - run ``update-ca-certificates`` command which will update - ``/etc/ssl/certs/ca-certificates.crt`` file; -3. Restart Traefik. - -With the Step 1. Minio server will get the certificate it needs, hence SSE-C -will be enabled. - -Steps 2. and 3. will need to be repeated each time you get a new CA -certificate. -These steps can be automated this way: -Start Traefik with this command: -``sh -c "update-ca-certificates && traefik"`` -while ``/usr/local/share/ca-certificates`` container path is mounted from the -host with the CA certificate produced by this script. - -I am using Alpine Traefik image, the correct ca certificates path is -``/usr/local/share/ca-certificates/``, otherwise one of these -https://golang.org/src/crypto/x509/root_linux.go - -- ``docker-compose.yml`` example with the gencert script: +> I intentionally left only the gencert-related lines. +> +> If you are using Alpine based image, the correct CA certificates path is +> ``/usr/local/share/ca-certificates/``, otherwise one of these +> https://golang.org/src/crypto/x509/root_linux.go ``` -version: '3' - -networks: - oasis: {} - services: minio: - restart: unless-stopped image: minio/minio - networks: - - oasis volumes: - - /srv/data/minio:/data - - /srv/data/minio/start/gencert.sh:/gencert.sh:ro + - /srv/data/minio/certs:/root/.minio/certs + - /srv/services/gencert/gencert.sh:/gencert.sh:ro entrypoint: sh -c "cd /root/.minio/certs && /gencert.sh --cn minio.example.com && minio server /data" environment: - "MINIO_ACCESS_KEY=redacted" - "MINIO_SECRET_KEY=redacted" - labels: - - "traefik.enable=true" - - "traefik.frontend.rule=Host: minio.example.com" - - "traefik.frontend.passHostHeader=true" - - "traefik.port=9000" + + registry: + image: registry:2.6.2 + volumes: + - /srv/services/gencert/gencert.sh:/gencert.sh:ro + - /srv/data/registry/certs:/certs + entrypoint: sh -c "cd /certs && /gencert.sh --cn registry.example.com && registry serve /etc/docker/registry/config.yml" + environment: + REGISTRY_HTTP_TLS_CERTIFICATE: '/certs/public.crt' + REGISTRY_HTTP_TLS_KEY: '/certs/private.key' traefik: - restart: unless-stopped image: traefik:1.6-alpine volumes: - - /srv/data/traefik/acme:/etc/traefik/acme - - /srv/data/traefik/traefik.toml:/etc/traefik/traefik.toml:ro - - /var/run/docker.sock:/var/run/docker.sock:ro # listen to the Docker events. - - /srv/data/traefik/ca-certs:/usr/local/share/ca-certificates:ro + - /srv/data/minio/certs/ca.crt:/usr/local/share/ca-certificates/minio_ca.crt:ro + - /srv/data/registry/certs/ca.crt:/usr/local/share/ca-certificates/registry_ca.crt:ro command: sh -c "update-ca-certificates && traefik" - networks: - - oasis - ports: - - "127.0.0.1:8080:8080" - - "80:80" - - "443:443" + depends_on: + - minio + - registry ``` -### Drawbacks +## Testing + +I have added a simplistic script [testme.sh](testme.sh) that helps to test this +script in the following Linux distributions: + +- Alpine 3.4 +- Alpine 3.7 +- Ubuntu Bionic +- Debian Stretch +- CentOS 7 + +> Alpine 3.4 - as it has old getent which [misses](https://git.alpinelinux.org/cgit/aports/commit/?id=2e4493888fff74afc6a6ef6257aeea469df32af5) ahostsv4 + +## Drawbacks - [operational] it requires self-signed CA certs shared when running multiple Minio (or any other) servers; -- [operational] every X years it requires updating the CA certificate in the -Traefik's (or any other reverse proxy) container; -- [security] the CA key will have to be spread all over the environment. -Theoretically, this could be solved by HashiCorp's Vault, but that won't be -nice & small way of running things; diff --git a/testme.sh b/testme.sh index 735815a..8a1df84 100755 --- a/testme.sh +++ b/testme.sh @@ -5,7 +5,7 @@ TMPDIR="$(mktemp -d)" cp -v gencert.sh "${TMPDIR}/" pushd "${TMPDIR}" -for DISTRO in alpine:3.7 ubuntu:bionic debian:stretch centos:7; do +for DISTRO in alpine:3.4 alpine:3.7 ubuntu:bionic debian:stretch centos:7; do printf "\n\n\nTesting the script with ${DISTRO} ...\n\n\n" rm -vf openssl.cnf private.key public.crt ca.crt ca.key ca.srl docker run --rm -ti -v ${PWD}:/w -w /w ${DISTRO} sh gencert.sh --cn test.example.com