Add internal ACME CA (step-ca) as a generic acme-ca provision; wire route-proxy to consume it

Piece C of ADR 0056: an internal authority certifies routed names by the same
path a public one would, with the proxy pointed at whichever issuer the mesh
names and trusting that issuer's root.

step-ca (new): provides acme-ca (mesh scope), listens 9000 from mesh, persists
its CA home under uid 1000. The root CA cert reaches consumers as a served
value settled from a per-mesh operator setting (no baked root); the init
password and root key are sealed secrets, not literals. No route-name -> IP
hosts map (that is Piece B). Upstream smallstep/step-ca pinned by Docker Hub
digest.

route-proxy: requires + binds acme-ca. ACME_DIRECTORY is composed on the
consumer side from ${bound:acme-ca:at}:${bound:acme-ca:port}, and ACME_CA_BUNDLE
is a file whose content is ${bound:acme-ca:root} -- both from the binding,
replacing the hardcoded directory and the baked root PEM.

Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF
This commit is contained in:
2026-09-09 23:07:54 +02:00
parent d018f1e16e
commit ff01adaa45
2 changed files with 111 additions and 2 deletions
+32 -2
View File
@@ -16,6 +16,12 @@
"receives": {
"route": "/var/lib/route-proxy/routes/mesh.json"
},
"requires": [
"acme-ca"
],
"binds": {
"acme-ca": "/var/lib/route-proxy/acme-ca.json"
},
"listens": [
{
"port": 80,
@@ -49,22 +55,46 @@
"path": "/var/lib/route-proxy/acme",
"mode": "0700"
},
{
"id": "ca-dir",
"type": "directory",
"path": "/var/lib/route-proxy/ca",
"mode": "0755"
},
{
"id": "ca-bundle",
"type": "file",
"path": "/var/lib/route-proxy/ca/root.crt",
"mode": "0644",
"content": "${bound:acme-ca:root}\n"
},
{
"id": "acme-env",
"type": "file",
"path": "/var/lib/route-proxy/acme.env",
"mode": "0600",
"content": "ACME_DIRECTORY=https://${bound:acme-ca:at}:${bound:acme-ca:port}/acme/acme/directory\n"
},
{
"id": "server",
"type": "container",
"name": "route-proxy",
"image": "mesh-route-proxy@sha256:0000000000000000000000000000000000000000000000000000000000000000",
"network": "host",
"env-file": [
"/var/lib/route-proxy/acme.env"
],
"volumes": [
"/var/lib/route-proxy/routes:/routes:ro",
"/var/lib/route-proxy/acme:/acme"
"/var/lib/route-proxy/acme:/acme",
"/var/lib/route-proxy/ca:/ca:ro"
],
"env": {
"ROUTES": "/routes/mesh.json",
"LISTEN": ":80",
"TLS_LISTEN": ":443",
"ACME_CACHE": "/acme",
"ACME_DIRECTORY": "https://acme-staging-v02.api.letsencrypt.org/directory"
"ACME_CA_BUNDLE": "/ca/root.crt"
}
}
]