dynamic-config-server
An HTTP configuration server for dynamic-config: one resolved document
per application and profile, handed to a caller that presented a
credential scoped to that application.
Run it as a service:
Or mount its router in a service you already run:
[]
= "0.6.1"
What it serves
| Endpoint | Returns |
|---|---|
GET /{application}/{profile} |
the resolved document — values, secrets included |
GET /{application}/{profile}/paths |
which keys exist; no values |
GET /{application}/{profile}/explain/{path} |
every layer's answer, every value *** |
GET /{application}/{profile}/check |
would the next load succeed; key paths and origins |
GET /{application}/{profile}/status |
generation, health, staleness |
GET /metrics |
Prometheus text, for the sections this caller may read |
GET /healthz, GET /readyz |
liveness and readiness. Unauthenticated, and they say nothing else |
Every route is a GET. A config server that can be written to is a
different product with a different threat model.
It is a security boundary
Everything else in this workspace hands configuration to the process that called it; this crate hands it over a socket. So it refuses to start rather than start permissively — no clients, a token under 32 characters, an anonymous client without an explicit opt-in, two clients sharing a token, a private key that anything but its owner can read, or a non-loopback bind that neither terminates TLS nor acknowledges a terminator in front are each a refusal naming the key that fixes it.
A credential is scoped to applications rather than to the server, and "not yours" and "no such thing" are the same 404, the same body and the same work — so a caller cannot enumerate what it may not read.
TLS and client certificates
Opt-in twice — the tls feature and a [server.tls] section — because
a second TLS stack is CVE surface in the one program that holds every
service's secrets, and a deployment with a terminator in front should
carry none of it:
[]
= "/etc/dynamic-config/server.pem"
= "/etc/dynamic-config/server.key"
= "/etc/dynamic-config/clients-ca.pem" # optional
With client_ca, every caller must present a certificate that chains
to it, verified during the handshake by rustls — a second, independent
factor beside the bearer token. It is a gate, not an identity: the
token still names the caller and still scopes what it may read, so a
valid certificate with no token is a 401 and a valid certificate with the
wrong grant is the same 404 as anybody else's.
The private key is the sharpest secret here, and is treated like it: no
error, log, Debug or audit line carries a byte of it, and a key file
readable by more than its owner refuses to start with the chmod in the
message.
generates a CA, a server certificate and a client certificate, runs the server over TLS, and shows all three cases end to end.
The threat model, in full, is in the book.
Documentation
- The Config Server — configuration, deployment, and what each endpoint is for
dynamic-config— the library it serves
License
MIT