|
|
||
|---|---|---|
| .forgejo/workflows | ||
| src | ||
| Dockerfile | ||
| LICENSE | ||
| README.md | ||
docker-traefik-vault-sync
A container that reads TLS certificates from HashiCorp Vault (KV v2) and periodically updates the files used by Traefik through the file provider (dynamic tls configuration).
Expected Vault structure (configurable prefix, default secret/acme):
kv liston the base path returns domain names (folders).- For each domain
example.com:${VAULT_ACME_PREFIX}/example.com/fullchain.pem-> certificate value (valuefield in.data.data)${VAULT_ACME_PREFIX}/example.com/cert.key-> private key value
Script-specific variables:
| Variable | Default | Description |
|---|---|---|
SLEEP_SECONDS |
300 |
Interval in seconds between sync cycles. |
VAULT_ACME_PREFIX |
secret/acme |
KV v2 path (without secret/data/...) where certificate secrets live. |
Vault CLI variables (hashicorp/vault image), typically required:
| Variable | Description |
|---|---|
VAULT_ADDR |
Vault server URL (for example, https://vault:8200). |
VAULT_TOKEN |
Token with read permissions on the target KV paths. |
Common optional variables: VAULT_NAMESPACE, VAULT_SKIP_VERIFY (test environments only), VAULT_CACERT, etc. (Vault documentation)
Docker Compose (Traefik v3)
Minimal example: Traefik and the sync container share certs and dynamic volumes; the sync writes certificates and tls.yml, Traefik reads them.
services:
traefik:
image: traefik:v3
user: "10001:10001"
cap_add:
- NET_BIND_SERVICE
command:
- --api.dashboard=true
- --providers.file.directory=/dynamic
- --providers.file.watch=true
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- certs:/certs
- dynamic:/dynamic:ro
vault-sync:
image: docker.asperti.com/paspo/traefik-vault-sync:latest
user: "10001:10001"
environment:
VAULT_ADDR: https://vault.example.com:8200
VAULT_TOKEN: ${VAULT_TOKEN}
VAULT_ACME_PREFIX: secret/acme
SLEEP_SECONDS: 300
volumes:
- certs:/certs
- dynamic:/dynamic
restart: unless-stopped
volumes:
certs:
dynamic:
Set VAULT_TOKEN in a local .env file (do not commit it) or via your orchestrator secret mechanism.
The generated /dynamic/tls.yml file uses tls.certificates with certFile / keyFile under /certs/..., matching the mounts above.
NET_BIND_SERVICE allows Traefik to bind to :80 and :443 even when running as non-root.
Align vault-sync user: with Traefik (UID:GID must match).
For each domain, the script compares the Vault timestamp (.data.metadata.created_time) with local mtime: it updates /certs/<domain>.crt and /certs/<domain>.key only if the file does not exist or the timestamp changed, and logs updates to stdout.
User and Permissions (runtime)
The image uses a non-root user by default (1001:1001) and does not run runtime chown. If needed, override UID:GID in docker-compose via user:.
Local Build
docker build -t docker-traefik-vault-sync:local .
Healthcheck
The container uses HEALTHCHECK and directly runs the binary with the health subcommand. No health file is written.