From 5826928abe9fedec91becddcc0ebcb2536a8fe4f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 5 Jul 2026 20:13:42 +0200 Subject: [PATCH] Import ungleich-certbot --- ungleich-certbot/Dockerfile_1.1.6 | 12 ++ ungleich-certbot/README.md | 145 +++++++++++++++++++++++++ ungleich-certbot/build.sh | 15 +++ ungleich-certbot/entrypoint.sh | 81 ++++++++++++++ ungleich-certbot/get_cert.sh | 19 ++++ ungleich-certbot/nginx-http-redir.conf | 16 +++ ungleich-certbot/renew_cert.sh | 21 ++++ 7 files changed, 309 insertions(+) create mode 100644 ungleich-certbot/Dockerfile_1.1.6 create mode 100644 ungleich-certbot/README.md create mode 100755 ungleich-certbot/build.sh create mode 100755 ungleich-certbot/entrypoint.sh create mode 100755 ungleich-certbot/get_cert.sh create mode 100644 ungleich-certbot/nginx-http-redir.conf create mode 100755 ungleich-certbot/renew_cert.sh diff --git a/ungleich-certbot/Dockerfile_1.1.6 b/ungleich-certbot/Dockerfile_1.1.6 new file mode 100644 index 0000000..d421634 --- /dev/null +++ b/ungleich-certbot/Dockerfile_1.1.6 @@ -0,0 +1,12 @@ +FROM nginx:1.21.4-alpine + +RUN mkdir -p /nginx /www_http +COPY nginx-http-redir.conf /nginx/default.conf + +# For renewing the certificates +COPY renew_cert.sh /etc/periodic/daily/renew_cert + +RUN apk update && apk add certbot bind-tools + +COPY entrypoint.sh / +CMD ["/entrypoint.sh"] diff --git a/ungleich-certbot/README.md b/ungleich-certbot/README.md new file mode 100644 index 0000000..18ac2c5 --- /dev/null +++ b/ungleich-certbot/README.md @@ -0,0 +1,145 @@ +## ungleich-certbot + +This container is made for getting **real world** certificates +for your kubernetes cluster. + +The assumption is that you can point the DNS name to the container +from outside. This is by default given for **IPv6 only kubernetes +services**. + +The source of this image can be found on +[code.ungleich.ch](https://code.ungleich.ch/ungleich-public/ungleich-certbot). + +## Usage + +* Set the environment variable DOMAIN to specify the domain for which + to get a certificate +* Set the environment variable EMAIL (this is where letsencrypt sends + warnings to) +* Set the environment variable STAGING to "no" if you want to have + proper certificates - this is to prevent you from asking the real + letsencrypt service accidently by default +* By default the container allows world read access to the + certificates, so that non-root users can access the certificates. + Set the LEAVE_PERMISSIONS_AS_IS environment variable to instruct the + container not to change permissions +* If you setup the variable NO_NGINX to any value, the container will + NOT start nginx and use certbot in standalone mode + + +``` +docker run -e DOMAIN=example.com \ + -e EMAIL=root@example.com \ + ungleich/ungleich-certbot:1.1.1 +``` + +### Production certificate + +Use + +``` +docker run -e DOMAIN=example.com \ + -e EMAIL=root@example.com \ + -e STAGING=no \ + ungleich/ungleich-certbot:1.1.1 +``` + +you will get a proper, real world usable nginx server. Inject the +nginx configuration by meains of a volume to /etc/nginx/conf.d + +### Adding or overriding nginx configurations + +To add your own nginx configurations, create the directory +/nginx-configs and add your configurations in there: + +``` +docker run -e DOMAIN=example.com \ + -e EMAIL=root@example.com \ + -v /path/to/config:/nginx-configs \ + ungleich/ungleich-certbot:1.1.1 +``` + +By default this image is deploying the *default.conf*. If you want to +override the default image nginx configuration, you can supply your +own default.conf. + +### Exiting after getting the certificate + +By default, the container will stay alive and try to renew the +certificate every day. If you set the environment variable +`ONLYGETCERT`, then it will only get the certificates and exit. + +This mode can be used +as a [kubernetes Job](https://kubernetes.io/docs/concepts/workloads/controllers/job/). + +### Only renewing the certificate once + +If you only want to trigger renewing existing certificates and skip +getting the certificates initially, you can set the variable +`RENEWCERTSONCE`, then it will only renew all certificates and exit. + +* If `ONLYRENEWCERTSONCE` is set, renew will be run once and then the + container exits + +This mode can be used +as a [kubernetes Job](https://kubernetes.io/docs/concepts/workloads/controllers/job/). + +## Volumes + +If you want to keep / use your certificates, you are advised to create +a volume below /etc/letsencrypt. + +## Changelog + +### 0.1.0 + + +Usable with automatic renewal + +### 0.2.0 + +Added support for nginx webserver, based on official nginx image + +### 1.0.0 + +- Start nginx in foreground, if not opted out + - Nicely shows erros of nginx starting, which is what we need +- Starting nginx by default on port 80 +- Removed variable NGINX to start nginx +- Introducted variable NO_NGINX to prevent nginx from starting +- Changed the wait time for domain resolution test to every 2 seconds + - helps to startup faster +- Added directory /nginx from which configuration files are sourced + - can be used to overwrite built-in configurations +- Create file /tmp/last_renew for checking when +- Dropped support for NGINX_HTTP_REDIRECT (always enabled with nginx + now) -- can be overwritten by overriding /nginx directory +- Dropped support for ONLYRENEWCERTS - this is covered by NO_NGINX already + +### 1.1.0 + +- Allow better way to inject configurations + +### 1.1.1 + +- Fix incorrect configuration sourcing + +### 1.1.2 + +- Add missing crond invocation + +### 1.1.3 + +- Add missing http directory + +### 1.1.4 + +- change renew_cert.sh file name for run-parts + +### 1.1.5 + +- update renew_cert.sh for periodic renew + +## Kubernetes + +See https://code.ungleich.ch/ungleich-public/ungleich-k8s/. diff --git a/ungleich-certbot/build.sh b/ungleich-certbot/build.sh new file mode 100755 index 0000000..fc65465 --- /dev/null +++ b/ungleich-certbot/build.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +set -e + +docker build -t ungleich-certbot . + +while [ $# -ge 1 ]; do + tag=$1; shift + git tag -a -m "Version $tag" $tag + git push --tags + docker tag ungleich-certbot:latest ungleich/ungleich-certbot:${tag} + docker tag ungleich-certbot:latest harbor.ungleich.svc.p10.k8s.ooo/ungleich-public/ungleich-certbot:${tag} + docker push ungleich/ungleich-certbot:${tag} + docker push harbor.ungleich.svc.p10.k8s.ooo/ungleich-public/ungleich-certbot:${tag} +done diff --git a/ungleich-certbot/entrypoint.sh b/ungleich-certbot/entrypoint.sh new file mode 100755 index 0000000..f7f7799 --- /dev/null +++ b/ungleich-certbot/entrypoint.sh @@ -0,0 +1,81 @@ +#!/bin/sh + + +if [ -z "$DOMAIN" -o -z "$EMAIL" ]; then + echo Missing DOMAIN or EMAIL parameter - aborting. >&2 + exit 1 +fi + +# Check that the domain exists, if not wait for it +ipv6_addr="" +ipv4_addr="" + +while [ -z "$ipv6_addr" -a -z "$ipv4_addr" ]; do + echo "Trying to resolve $DOMAIN via DNS ..." + # Resolve for IPv6 and for IPv6 + ipv6_addr=$(dig +short "$DOMAIN" aaaa) + ipv4_addr=$(dig +short "$DOMAIN" a) + + if [ "$ipv6_addr" -o "$ipv4_addr" ]; then + echo "Resolved domain $DOMAIN: ipv6: $ipv6_addr ipv4: $ipv4_addr" + else + echo "Resolving $DOMAIN failed, waiting 2 seconds before retrying ..." + sleep 2 + fi +done + +if [ "$STAGING" = no ]; then + STAGING="" +else + STAGING="--staging" +fi + +# Skip getting certs if requested +if [ -z "$ONLYRENEWCERTS" -a -z "$ONLYRENEWCERTSONCE" ]; then + # Try to get a certificate, accept failures + while [ ! -f "/etc/letsencrypt/live/${DOMAIN}/fullchain.pem" ]; do + certbot certonly --agree-tos --cert-name "${DOMAIN}" \ + --email "$EMAIL" --expand --non-interactive \ + --domain "$DOMAIN" --standalone $STAGING + + # If it failed, sleep before next try + if [ ! -f "/etc/letsencrypt/live/${DOMAIN}/fullchain.pem" ]; then + sleep 30 + fi + + # Correct permissions for multi user container/pod deployments + # if not indicated otherwise + if [ -z "$LEAVE_PERMISSIONS_AS_IS" ]; then + find /etc/letsencrypt -type d -exec chmod 0755 {} \; + find /etc/letsencrypt -type f -exec chmod 0644 {} \; + fi + done +fi + +if [ "$ONLYGETCERT" ]; then + exit 0 +fi + +# Before starting nginx, try to renew to ensure we are up-to-date +# This is necessary for container restarts not to delay a needed renew +/usr/bin/certbot renew --standalone + +# If it requested to renew once only we are done here +[ "$ONLYRENEWCERTSONCE" ] && exit 0 + +# Start cron for automatic certificate renewal +crond + +if [ "$NO_NGINX" ]; then + sleep infinity +else + # First builtin + cp /nginx/* /etc/nginx/conf.d + + # Then user provided + if [ -d /nginx-configs ]; then + cp /nginx-configs/* /etc/nginx/conf.d + fi + + nginx -g "daemon off;" +fi diff --git a/ungleich-certbot/get_cert.sh b/ungleich-certbot/get_cert.sh new file mode 100755 index 0000000..1ec2a36 --- /dev/null +++ b/ungleich-certbot/get_cert.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +while [ ! -f "/etc/letsencrypt/live/${DOMAIN}/fullchain.pem" ]; do + certbot certonly --agree-tos --cert-name "${DOMAIN}" \ + --email "$EMAIL" --expand --non-interactive \ + --domain "$DOMAIN" --standalone $STAGING + + # If it failed, sleep before next try + if [ ! -f "/etc/letsencrypt/live/${DOMAIN}/fullchain.pem" ]; then + sleep 30 + fi + + # Correct permissions for multi user container/pod deployments + # if not indicated otherwise + if [ -z "$LEAVE_PERMISSIONS_AS_IS" ]; then + find /etc/letsencrypt -type d -exec chmod 0755 {} \; + find /etc/letsencrypt -type f -exec chmod 0644 {} \; + fi +done diff --git a/ungleich-certbot/nginx-http-redir.conf b/ungleich-certbot/nginx-http-redir.conf new file mode 100644 index 0000000..7251e56 --- /dev/null +++ b/ungleich-certbot/nginx-http-redir.conf @@ -0,0 +1,16 @@ +server { + listen *:80; + listen [::]:80; + + server_name _; + root /www_http; + + location /.well-known/acme-challenge/ { + root /www_http; + } + + # Everything else -> ssl + location / { + return 301 https://$host$request_uri; + } +} diff --git a/ungleich-certbot/renew_cert.sh b/ungleich-certbot/renew_cert.sh new file mode 100755 index 0000000..8196910 --- /dev/null +++ b/ungleich-certbot/renew_cert.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +if [ "$NO_NGINX" ]; then + /usr/bin/certbot renew --standalone +elif [ -n "`grep -r standalone /etc/letsencrypt/renewal`" ]; then + /usr/bin/certbot renew --standalone + /usr/bin/certbot renew --force-renew --webroot --webroot-path /www_http +else + /usr/bin/certbot renew --webroot --webroot-path /www_http +fi + +# Correct permissions if not told otherwise +if [ -z "$LEAVE_PERMISSIONS_AS_IS" ]; then + find /etc/letsencrypt -type d -exec chmod 0755 {} \; + find /etc/letsencrypt -type f -exec chmod 0644 {} \; +fi + +# Reload certs +pkill -1 nginx + +echo "Last renew: $(date)" > /tmp/last_renew \ No newline at end of file