gencert/README.md

138 lines
4.9 KiB
Markdown
Raw Normal View History

2018-06-30 12:42:01 +00:00
# gencert
2018-06-30 18:37:16 +00:00
This script generates x509 server certificate (with all IPs in SAN) signed by a
self-signed CA.
2018-06-30 18:36:28 +00:00
## Purpose
2018-06-30 19:40:36 +00:00
2018-07-11 07:35:42 +00:00
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
2018-06-30 19:40:36 +00:00
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.
2018-06-30 18:36:28 +00:00
2018-06-30 19:41:38 +00:00
- 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
2018-07-11 07:42:57 +00:00
> 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
2018-06-30 19:41:38 +00:00
2018-07-11 07:35:42 +00:00
## Examples
2018-06-30 19:41:38 +00:00
2018-07-11 22:18:50 +00:00
### Minio and Docker Registry services behind Traefik reverse proxy
2018-06-30 19:40:36 +00:00
2018-07-11 07:35:42 +00:00
- docker-compose.yml
2018-06-30 18:36:28 +00:00
2018-07-11 07:35:42 +00:00
> 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
2018-07-01 14:58:17 +00:00
```
services:
minio:
image: minio/minio
volumes:
2018-07-11 07:35:42 +00:00
- /srv/data/minio/certs:/root/.minio/certs
- /srv/services/gencert/gencert.sh:/gencert.sh:ro
2018-07-11 22:26:13 +00:00
entrypoint: sh -c "cd /root/.minio/certs &&
/gencert.sh --cn minio.example.com &&
minio server /data"
2018-07-01 14:58:17 +00:00
environment:
- "MINIO_ACCESS_KEY=redacted"
- "MINIO_SECRET_KEY=redacted"
2018-07-11 07:35:42 +00:00
registry:
image: registry:2.6.2
volumes:
- /srv/services/gencert/gencert.sh:/gencert.sh:ro
- /srv/data/registry/certs:/certs
2018-07-11 22:26:13 +00:00
entrypoint: sh -c "cd /certs &&
/gencert.sh --cn registry.example.com &&
registry serve /etc/docker/registry/config.yml"
2018-07-11 07:35:42 +00:00
environment:
REGISTRY_HTTP_TLS_CERTIFICATE: '/certs/public.crt'
REGISTRY_HTTP_TLS_KEY: '/certs/private.key'
2018-07-01 14:58:17 +00:00
traefik:
image: traefik:1.6-alpine
volumes:
2018-07-11 07:35:42 +00:00
- /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
2018-07-01 14:58:17 +00:00
command: sh -c "update-ca-certificates && traefik"
2018-07-11 07:35:42 +00:00
depends_on:
- minio
- registry
2018-07-01 14:58:17 +00:00
```
2018-06-30 18:36:28 +00:00
2018-07-11 22:18:50 +00:00
### helloworld with socat
2018-07-15 17:07:21 +00:00
socat could be handy when you need to see the TLS flow between the reverse
2018-07-15 17:14:59 +00:00
proxy and a backend.
It may also help you secure the traffic between the reverse proxy and a backend
in case when the latter service does not support TLS on its own.
2018-07-15 17:07:21 +00:00
> Minimum socat version should be [1.7.3.2](https://fossies.org/linux/privat/socat-1.7.3.2.tar.gz/socat-1.7.3.2/CHANGES) so it will work with the
2018-07-11 22:18:50 +00:00
> ECDHE- OpenSSL ciphers.
```
services:
helloworld:
image: dockercloud/hello-world
volumes:
- /srv/services/gencert/gencert.sh:/gencert.sh:ro
2018-07-15 17:07:21 +00:00
entrypoint: sh -c "mkdir /certs && cd /certs &&
2018-07-11 22:26:13 +00:00
/gencert.sh --cn helloworld &&
( nohup /run.sh & ) &&
echo '@edge http://nl.alpinelinux.org/alpine/edge/main' | tee -a /etc/apk/repositories &&
apk --update add socat@edge &&
socat -v -v -d -d OPENSSL-LISTEN:443,reuseaddr,verify=0,cafile=./ca.crt,cert=./public.crt,key=./private.key,fork TCP4-CONNECT:127.0.0.1:80"
2018-07-11 22:18:50 +00:00
labels:
traefik.enable: 'true'
traefik.frontend.rule: 'Host: hello.example.com'
traefik.frontend.entryPoints: 'http,https'
traefik.backend.loadbalancer.stickiness: 'true'
traefik.port: '443'
traefik.protocol: 'https'
```
2018-07-15 17:14:59 +00:00
If you get ``sslv3 alert bad certificate`` error, then make sure you have
either updated the CA bundle with your CA file which was used to sign your x509
certificates at the reverse proxy server or disable TLS verification between
the reverse proxy and your backend (e.g. Traefik has a global option
``insecureSkipVerify = true``)
2018-07-11 07:35:42 +00:00
## 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