dynamic-config-server 0.6.1

An HTTP configuration server for dynamic-config: one document per application and profile, served under per-caller authorisation.
Documentation

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:

cargo install dynamic-config-server
dynamic-config-server server.toml

Or mount its router in a service you already run:

[dependencies]
dynamic-config-server = "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:

cargo install dynamic-config-server --features tls
[server.tls]
certificate = "/etc/dynamic-config/server.pem"
key = "/etc/dynamic-config/server.key"
client_ca = "/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.

cargo run -p dynamic-config-server --features tls --example tls_mutual

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

License

MIT