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:
@@ -16,6 +16,12 @@
|
|||||||
"receives": {
|
"receives": {
|
||||||
"route": "/var/lib/route-proxy/routes/mesh.json"
|
"route": "/var/lib/route-proxy/routes/mesh.json"
|
||||||
},
|
},
|
||||||
|
"requires": [
|
||||||
|
"acme-ca"
|
||||||
|
],
|
||||||
|
"binds": {
|
||||||
|
"acme-ca": "/var/lib/route-proxy/acme-ca.json"
|
||||||
|
},
|
||||||
"listens": [
|
"listens": [
|
||||||
{
|
{
|
||||||
"port": 80,
|
"port": 80,
|
||||||
@@ -49,22 +55,46 @@
|
|||||||
"path": "/var/lib/route-proxy/acme",
|
"path": "/var/lib/route-proxy/acme",
|
||||||
"mode": "0700"
|
"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",
|
"id": "server",
|
||||||
"type": "container",
|
"type": "container",
|
||||||
"name": "route-proxy",
|
"name": "route-proxy",
|
||||||
"image": "mesh-route-proxy@sha256:0000000000000000000000000000000000000000000000000000000000000000",
|
"image": "mesh-route-proxy@sha256:0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
"network": "host",
|
"network": "host",
|
||||||
|
"env-file": [
|
||||||
|
"/var/lib/route-proxy/acme.env"
|
||||||
|
],
|
||||||
"volumes": [
|
"volumes": [
|
||||||
"/var/lib/route-proxy/routes:/routes:ro",
|
"/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": {
|
"env": {
|
||||||
"ROUTES": "/routes/mesh.json",
|
"ROUTES": "/routes/mesh.json",
|
||||||
"LISTEN": ":80",
|
"LISTEN": ":80",
|
||||||
"TLS_LISTEN": ":443",
|
"TLS_LISTEN": ":443",
|
||||||
"ACME_CACHE": "/acme",
|
"ACME_CACHE": "/acme",
|
||||||
"ACME_DIRECTORY": "https://acme-staging-v02.api.letsencrypt.org/directory"
|
"ACME_CA_BUNDLE": "/ca/root.crt"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
{
|
||||||
|
"module": "step-ca",
|
||||||
|
"version": "1",
|
||||||
|
"capabilities": [
|
||||||
|
"container-runtime"
|
||||||
|
],
|
||||||
|
"provides": [
|
||||||
|
{
|
||||||
|
"name": "acme-ca",
|
||||||
|
"scope": "mesh"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"serves": {
|
||||||
|
"acme-ca": {}
|
||||||
|
},
|
||||||
|
"listens": [
|
||||||
|
{
|
||||||
|
"port": 9000,
|
||||||
|
"protocol": "tcp",
|
||||||
|
"from": "mesh",
|
||||||
|
"why": "the ACME directory and step-ca API; a proxy on any node reaches it here over the mesh to obtain certificates, and its single listen is what the consumer is told the port is"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"own-secrets": {
|
||||||
|
"password": "/var/lib/mesh/step-ca/password",
|
||||||
|
"root-key": "/var/lib/mesh/step-ca/root-key"
|
||||||
|
},
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"id": "mesh-state",
|
||||||
|
"type": "directory",
|
||||||
|
"path": "/var/lib/mesh/step-ca",
|
||||||
|
"mode": "0700"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "home",
|
||||||
|
"type": "directory",
|
||||||
|
"path": "/var/lib/step-ca",
|
||||||
|
"mode": "0700",
|
||||||
|
"owner": "1000:1000"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "config",
|
||||||
|
"type": "file",
|
||||||
|
"path": "/var/lib/mesh/step-ca/config.json",
|
||||||
|
"mode": "0644",
|
||||||
|
"content": "{}",
|
||||||
|
"merge": "json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "init-env",
|
||||||
|
"type": "file",
|
||||||
|
"path": "/var/lib/mesh/step-ca/init.env",
|
||||||
|
"mode": "0600",
|
||||||
|
"content": "DOCKER_STEPCA_INIT_PASSWORD=${secret:password}\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "server",
|
||||||
|
"type": "container",
|
||||||
|
"name": "step-ca",
|
||||||
|
"image": "smallstep/step-ca@sha256:a2b17872915c193259b75a5474c398326f41bd199f0842093e52cf4182bc8270",
|
||||||
|
"network": "host",
|
||||||
|
"env-file": [
|
||||||
|
"/var/lib/mesh/step-ca/init.env"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"DOCKER_STEPCA_INIT_NAME": "Mesh Internal CA",
|
||||||
|
"DOCKER_STEPCA_INIT_DNS_NAMES": "localhost,127.0.0.1",
|
||||||
|
"DOCKER_STEPCA_INIT_ACME": "true",
|
||||||
|
"DOCKER_STEPCA_INIT_REMOTE_MANAGEMENT": "false"
|
||||||
|
},
|
||||||
|
"volumes": [
|
||||||
|
"/var/lib/step-ca:/home/step",
|
||||||
|
"/var/lib/mesh/step-ca/root-key:/run/secrets/root-key:ro",
|
||||||
|
"/var/lib/mesh/step-ca/config.json:/run/config/config.json:ro"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user