gencert/README.md
2018-07-01 16:58:17 +02:00

4.3 KiB

gencert

This script generates x509 server certificate (with all IPs in SAN) signed by a self-signed CA.

Purpose

This script will always produce a self-signed x509 certificate with the IP addresses embedded to x509's SAN.

It will also produce a CA certificate and can be used by other services 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

Testing

I have added a simplistic script testme.sh that helps to test this script in the following Linux distributions:

  • Alpine 3.7
  • Ubuntu Bionic
  • Debian Stretch
  • CentOS 7

Usage example

Minio server with Traefik example

  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 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;