Server bindings
A binding maps a name (what a client requests) to a ref (what actually gets resolved). Bindings are the whole security model: a client sends a name, never a ref, so a request can never carry file:///etc/shadow or a client-chosen exec: command.
Declare bindings
Bind declares one binding inline; BindFile reads them from YAML.
func Bind(name, ref string) Option
func BindFile(path string) Option
srv, err := server.New(
server.Bind("db-password", "vault://secret/data/db#password"),
server.Bind("api-key", "aws-sm://prod/api-key"),
server.BindFile("/etc/mamori/bindings.yaml"),
// ... policy, auth, transport ...
)
# /etc/mamori/bindings.yaml
bindings:
db-password: vault://secret/data/db#password
api-key: aws-sm://prod/api-key
Bind/BindFile are the only way a binding comes into existence, and the operator calls them in the server’s startup code. A duplicate binding name fails New. All declarations are validated together in one pass after every option applies, so declaration order never matters.
Register providers
Each binding resolves through the provider registered for its ref’s scheme.
func WithProvider(p mamori.Provider) Option
WithProvider registers a Provider for its own Scheme(). Every provider a binding can use is one the operator named explicitly; there is no process-wide registry fallback. A binding whose scheme has no registered provider still constructs cleanly and simply reports a resolve error on lookup, while every other binding keeps working.
Allow exec: and mamori: schemes
Two ref schemes are rejected at construction unless explicitly allowed:
func AllowExec() Option
func AllowChaining() Option
srv, err := server.New(
server.Bind("build-token", "exec://vault-agent-token"),
server.AllowExec(),
server.WithProvider(myExecProvider), // required: core ships no exec provider constructor
// ... policy, auth, transport ...
)
exec:runs an arbitrary command on the server’s host.AllowExec()lifts the construction-time gate, but core’sexec:provider has no exported constructor, so making anexec:binding resolve also requires you to supply your own execProviderviaWithProvider. Two deliberate steps for a scheme that means remote command execution reachable by every authorized consumer.mamori:chains to another config server.AllowChaining()lifts the gate; without it, amamori:binding could quietly wire up a cycle.
Every other scheme (env:, aws-sm:, vault:, file:, gcp-sm:, and so on) needs neither option.
Next
- Server auth and policy - decide who may request which binding.
- Deploy and expose - serve the bindings over a socket or TLS TCP.
- Config server overview - the fan-out model and blast radius.