Documentation
¶
Overview ¶
Package resourceproxy is the machinery of cmd/resource-proxy: a sidecar that puts a sluis resource server's front door on a stock MCP server (or any HTTP service) that knows nothing about sluis.
Two sides, independent:
- Inbound faces the gateway. It verifies the caller's access token (identity/resource), serves the resource's RFC 9728 metadata, writes one audit line per request, and reverse-proxies to the stock server with the caller's Authorization header removed.
- Outbound is optional and faces the stock server, on loopback only. The stock server points its backend URL at it; it adds a bearer token this workload's OWN identity earned by an RFC 8693 exchange. The caller's token is never forwarded anywhere (the MCP spec forbids passing it through), so the stock server holds no credential at all.
Index ¶
Constants ¶
const ( DefaultMaxRequestBytes = 4 << 20 DefaultBodyTimeout = 30 * time.Second DefaultUpstreamTimeout = 2 * time.Minute DefaultRefreshBefore = time.Minute )
Default limits.
Variables ¶
This section is empty.
Functions ¶
func IsLoopbackListen ¶
IsLoopbackListen reports whether a listen address binds loopback only. A bare port (":8429") binds every interface and is not loopback.
Types ¶
type Config ¶
type Config struct {
// Listen is the inbound listener.
Listen string
// Upstream is the stock server. Its path, if any, is where the
// resource's own path maps to: upstream http://127.0.0.1:8081/mcp for
// resource https://h/metrics sends /metrics to /mcp and /metrics/x to
// /mcp/x.
Upstream string
// IssuerURL, ResourceURL and Scope configure identity/resource.
IssuerURL string
ResourceURL string
Scope string
// MaxRequestBytes caps a request body; more is refused with 413.
MaxRequestBytes int64
// BodyReadTimeout bounds reading one request body.
BodyReadTimeout time.Duration
// UpstreamTimeout bounds the wait for the stock server's response
// headers. A streamed response is not bounded by it.
UpstreamTimeout time.Duration
// Outbound side. Empty OutboundListen turns it off.
OutboundListen string
OutboundTarget string
OutboundTokenEndpoint string
OutboundClientID string
OutboundAudience string
OutboundSATokenFile string
// OutboundCAFile is a PEM bundle appended to the system roots for the
// outbound forwarder's connection to OutboundTarget, and only that
// one: the issuer and the token exchange keep the system roots alone.
OutboundCAFile string
// OutboundAllowNonLoopback lets the outbound listener bind anything
// but loopback. Anyone who can reach it borrows this workload's
// identity, so it is refused unless asked for by name.
OutboundAllowNonLoopback bool
// RefreshBefore is how long before expiry a token is exchanged again.
RefreshBefore time.Duration
}
Config is everything the proxy is told. cmd/resource-proxy fills it from flags, each defaulting to an environment variable.
func (Config) OutboundEnabled ¶
OutboundEnabled reports whether the outbound side runs.
type Inbound ¶
type Inbound struct {
// contains filtered or unexported fields
}
Inbound is the public side.
func NewInbound ¶
NewInbound builds the inbound side from a validated Config.
type Outbound ¶
type Outbound struct {
// contains filtered or unexported fields
}
Outbound is the loopback forwarder: whatever reaches it is sent to the target with this workload's own bearer token.
func NewOutbound ¶
NewOutbound builds the forwarder from a validated Config.
type TokenSource ¶
type TokenSource struct {
// contains filtered or unexported fields
}
TokenSource is this workload's own identity, as a bearer token: its projected ServiceAccount token traded at the issuer (RFC 8693) for one audienced at the backend. The kubelet rotates the ServiceAccount token under the pod, so it is read afresh for every exchange, never cached.
func NewTokenSource ¶
NewTokenSource builds the source from a validated Config. client is the transport to the issuer; nil uses tokens' default.
func (*TokenSource) Obtained ¶
func (s *TokenSource) Obtained() bool
Obtained reports whether a token has ever been obtained: what readiness means for the outbound side.
func (*TokenSource) Token ¶
func (s *TokenSource) Token(ctx context.Context) (string, error)
Token returns a bearer token with at least the refresh margin left, exchanging when it has none. One exchange at a time: a burst of calls that all find the token stale waits for one answer rather than making one each.
A failed exchange while the previous token is still valid serves the previous token and tries again next call: a blip at the issuer is not an outage of the backend.
func (*TokenSource) Warm ¶
func (s *TokenSource) Warm(ctx context.Context)
Warm tries until the first token is obtained, so readiness does not wait for the first request, and stops on ctx.