update readme and tests
This commit is contained in:
parent
c17a7b98b6
commit
b6ee6d3ce2
158
README.md
158
README.md
@ -5,6 +5,18 @@ self-signed CA.
|
|||||||
|
|
||||||
## Purpose
|
## 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
|
This script will always produce a self-signed x509 certificate with the IP
|
||||||
addresses embedded to x509's SAN.
|
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
|
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.
|
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
|
- generate CA certificate if does not find any
|
||||||
- always generate server certificate on startup to ensure all IP addresses
|
- always generate server certificate on startup to ensure all IP addresses
|
||||||
are in x509 SAN
|
are in x509 SAN
|
||||||
- warn if the CA certificate is about to expire (<30 days till expiration)
|
- warn if the CA certificate is about to expire (<30 days till expiration)
|
||||||
- regenerate the CA certificate if it finds it has expired
|
- 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)
|
## Examples
|
||||||
- The server certifcate will be valid for 365 days (1 year)
|
|
||||||
- The x509 certs are ECDSA with prime256v1 curve and SHA256 signatures
|
### Minio and Docker Registry services with Traefik reverse proxy
|
||||||
|
|
||||||
|
- docker-compose.yml
|
||||||
|
|
||||||
|
> 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
|
||||||
|
|
||||||
|
```
|
||||||
|
services:
|
||||||
|
minio:
|
||||||
|
image: minio/minio
|
||||||
|
volumes:
|
||||||
|
- /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"
|
||||||
|
|
||||||
|
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:
|
||||||
|
image: traefik:1.6-alpine
|
||||||
|
volumes:
|
||||||
|
- /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"
|
||||||
|
depends_on:
|
||||||
|
- minio
|
||||||
|
- registry
|
||||||
|
```
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
I have added a simplistic script [testme.sh](testme.sh) that helps to test this
|
I have added a simplistic script [testme.sh](testme.sh) that helps to test this
|
||||||
script in the following Linux distributions:
|
script in the following Linux distributions:
|
||||||
|
|
||||||
|
- Alpine 3.4
|
||||||
- Alpine 3.7
|
- Alpine 3.7
|
||||||
- Ubuntu Bionic
|
- Ubuntu Bionic
|
||||||
- Debian Stretch
|
- Debian Stretch
|
||||||
- CentOS 7
|
- CentOS 7
|
||||||
|
|
||||||
## Usage example
|
> Alpine 3.4 - as it has old getent which [misses](https://git.alpinelinux.org/cgit/aports/commit/?id=2e4493888fff74afc6a6ef6257aeea469df32af5) ahostsv4
|
||||||
|
|
||||||
### Minio server with Traefik example
|
## Drawbacks
|
||||||
|
|
||||||
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:
|
|
||||||
|
|
||||||
```
|
|
||||||
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
|
|
||||||
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"
|
|
||||||
|
|
||||||
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
|
|
||||||
command: sh -c "update-ca-certificates && traefik"
|
|
||||||
networks:
|
|
||||||
- oasis
|
|
||||||
ports:
|
|
||||||
- "127.0.0.1:8080:8080"
|
|
||||||
- "80:80"
|
|
||||||
- "443:443"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Drawbacks
|
|
||||||
|
|
||||||
- [operational] it requires self-signed CA certs shared when running multiple
|
- [operational] it requires self-signed CA certs shared when running multiple
|
||||||
Minio (or any other) servers;
|
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;
|
|
||||||
|
@ -5,7 +5,7 @@ TMPDIR="$(mktemp -d)"
|
|||||||
cp -v gencert.sh "${TMPDIR}/"
|
cp -v gencert.sh "${TMPDIR}/"
|
||||||
pushd "${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"
|
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
|
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
|
docker run --rm -ti -v ${PWD}:/w -w /w ${DISTRO} sh gencert.sh --cn test.example.com
|
||||||
|
Loading…
Reference in New Issue
Block a user