proxy

package
v0.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 7, 2026 License: MIT Imports: 32 Imported by: 0

Documentation

Overview

Package proxy provides a TLS-intercepting HTTP proxy for credential injection.

Security Model

The proxy intercepts HTTPS traffic via CONNECT tunneling with dynamic certificate generation. It injects credentials (Authorization headers, etc.) for configured hosts without exposing raw tokens to the container.

Firewall Integration

Container firewall rules (iptables) work in conjunction with the proxy:

  • Docker: Proxy binds to 127.0.0.1 (localhost only). Containers reach it via host.docker.internal or host network mode. Firewall allows proxy port only.

  • Apple containers: Proxy binds to 0.0.0.0 with per-run token authentication. Security is maintained via cryptographic tokens in HTTP_PROXY URL, not IP filtering.

The firewall rules intentionally do NOT filter by destination IP for the proxy port. This is because host.docker.internal resolves to different IPs across environments. The security boundaries are:

  1. Random high port assignment (reduces collision with other services)
  2. Token authentication for Apple containers
  3. Container isolation (other containers can't reach host ports by default)

This trade-off prioritizes reliability over defense-in-depth. The proxy validates credentials are only injected for explicitly configured hosts.

Index

Constants

View Source
const MaxBodySize = 8 * 1024

MaxBodySize is the maximum size of request/response bodies to capture (8KB). Only this much is buffered for logging; the full body is always forwarded.

Variables

This section is empty.

Functions

func FilterHeaders

func FilterHeaders(headers http.Header, injectedHeaders map[string]bool) map[string]string

FilterHeaders creates a copy of headers with sensitive values filtered. injectedHeaders is a set of lower-cased header names whose values should be redacted (credential headers the proxy injected).

func GetHostsForGrant

func GetHostsForGrant(grant string) []string

GetHostsForGrant returns the host patterns for a given grant name. Supports scoped grants like "github:repo" by extracting the provider name. Returns an empty slice if the grant is unknown.

func MatchesHostPattern added in v0.5.0

func MatchesHostPattern(pattern HostPattern, host string, port int) bool

MatchesHostPattern reports whether a host:port matches a parsed host pattern.

func RegisterGrantHosts added in v0.3.0

func RegisterGrantHosts(grant string, hosts []string)

RegisterGrantHosts registers host patterns for a grant name. This is used by config-driven providers to register their hosts dynamically. Must be called during initialization only (before concurrent access).

Types

type CA

type CA struct {
	// contains filtered or unexported fields
}

CA represents a certificate authority for TLS interception. The key field is a crypto.Signer so both RSA and EC CA keys are supported.

func LoadCA added in v0.5.0

func LoadCA(certPEM, keyPEM []byte) (*CA, error)

LoadCA loads a CA from PEM-encoded certificate and key bytes. Supports RSA (PKCS1, PKCS8) and EC (PKCS8, EC PRIVATE KEY) key formats.

func NewCA

func NewCA(caDir string) (*CA, error)

NewCA creates or loads a CA certificate. If the CA files exist at the given path, they are loaded. Otherwise, a new CA is generated and saved.

func (*CA) CertPEM

func (ca *CA) CertPEM() []byte

CertPEM returns the CA certificate in PEM format.

func (*CA) GenerateCert

func (ca *CA) GenerateCert(host string) (*tls.Certificate, error)

GenerateCert creates a certificate for the given host signed by the CA.

type ContextResolver added in v0.3.0

type ContextResolver func(token string) (*RunContextData, bool)

ContextResolver resolves a proxy auth token to per-run context data.

type CredentialHeader added in v0.3.0

type CredentialHeader = credentialHeader

CredentialHeader is the exported version of credentialHeader for daemon use.

type CredentialStore added in v0.5.0

type CredentialStore interface {
	GetToken(provider string) (string, error)
}

CredentialStore retrieves tokens by provider name (grant). The proxy uses this for MCP credential injection when credentials are not pre-resolved in RunContextData.

type ExtraHeader added in v0.3.0

type ExtraHeader = extraHeader

ExtraHeader is the exported version of extraHeader for daemon use.

type HostPattern added in v0.3.0

type HostPattern = hostPattern

HostPattern is the exported version of hostPattern.

func ParseHostPattern added in v0.3.0

func ParseHostPattern(pattern string) HostPattern

ParseHostPattern is the exported wrapper for parseHostPattern.

type MCPAuthConfig added in v0.5.0

type MCPAuthConfig struct {
	Grant  string
	Header string
}

MCPAuthConfig defines authentication for an MCP server.

type MCPServerConfig added in v0.5.0

type MCPServerConfig struct {
	Name string
	URL  string
	Auth *MCPAuthConfig
}

MCPServerConfig holds the MCP server configuration needed by the proxy.

type PathRulesChecker added in v0.5.0

type PathRulesChecker func(host string, port int) bool

PathRulesChecker reports whether path-level rules exist for a given host. When true, the proxy intercepts CONNECT tunnels for path-level inspection.

type PolicyLogData added in v0.5.0

type PolicyLogData struct {
	RunID     string
	Scope     string
	Operation string
	Rule      string
	Message   string
}

PolicyLogData contains data for a policy denial event.

type PolicyLogger added in v0.5.0

type PolicyLogger func(data PolicyLogData)

PolicyLogger is called when a policy denial occurs.

type Proxy

type Proxy struct {
	// contains filtered or unexported fields
}

Proxy is an HTTP proxy that injects credentials into outgoing requests.

Security Model

The proxy handles two distinct security concerns:

  1. Credential injection: The proxy injects credential headers for configured hosts (e.g., api.github.com, api.anthropic.com). When CA is set, it performs TLS interception (MITM) to inject headers into HTTPS requests. Supports custom header names (Authorization, x-api-key, etc).

  2. Proxy authentication: When authToken is set, clients must authenticate to the proxy itself via Proxy-Authorization header. This prevents unauthorized access when the proxy binds to all interfaces (0.0.0.0), which is required for Apple containers that access the host via gateway IP rather than localhost.

For Docker containers, the proxy binds to localhost (127.0.0.1) and authentication is not required. For Apple containers, the proxy binds to all interfaces with a cryptographically secure token for authentication.

func NewProxy

func NewProxy() *Proxy

NewProxy creates a new auth proxy.

func (*Proxy) AddExtraHeader

func (p *Proxy) AddExtraHeader(host, headerName, headerValue string)

AddExtraHeader adds an additional header to inject for a host. This is used for headers beyond the main credential header, such as beta feature flags or API version headers. The host must be a valid hostname (not empty, no path components).

func (*Proxy) AddRelay added in v0.3.0

func (p *Proxy) AddRelay(name, targetURL string) error

AddRelay registers a named relay endpoint. Requests to /relay/{name}/{path...} are forwarded to the target URL with credential injection. This is used when the target host would be in NO_PROXY (e.g., a host-side proxy reachable via the same address as the Moat proxy), which would cause direct connections to bypass credential injection.

AddRelay must be called before the proxy starts serving.

func (*Proxy) AddResponseTransformer

func (p *Proxy) AddResponseTransformer(host string, transformer ResponseTransformer)

AddResponseTransformer registers a response transformer for a host. Transformers are called in registration order after receiving the upstream response. Each transformer can inspect and optionally modify the response. The host must be a valid hostname (not empty, no path components).

func (*Proxy) RemoveRequestHeader

func (p *Proxy) RemoveRequestHeader(host, headerName string)

RemoveRequestHeader removes a client-sent header before forwarding.

func (*Proxy) ResolveContext added in v0.3.0

func (p *Proxy) ResolveContext(token string) (*RunContextData, bool)

ResolveContext looks up per-run context data by auth token. Returns nil, false when no resolver is set or the token is not found.

func (*Proxy) ServeHTTP

func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP handles proxy requests.

func (*Proxy) SetAWSHandler

func (p *Proxy) SetAWSHandler(h http.Handler)

SetAWSHandler sets the handler for AWS credential requests.

func (*Proxy) SetAuthToken

func (p *Proxy) SetAuthToken(token string)

SetAuthToken sets the required authentication token for proxy access.

func (*Proxy) SetCA

func (p *Proxy) SetCA(ca *CA)

SetCA sets the CA for TLS interception.

func (*Proxy) SetContextResolver added in v0.3.0

func (p *Proxy) SetContextResolver(resolver ContextResolver)

SetContextResolver sets the per-run context resolver for multi-tenant proxy use. When set, the proxy can resolve auth tokens to per-run credential data.

func (*Proxy) SetCredential

func (p *Proxy) SetCredential(host, authHeader string)

SetCredential sets the credential for a host using the Authorization header.

func (*Proxy) SetCredentialHeader

func (p *Proxy) SetCredentialHeader(host, headerName, headerValue string)

SetCredentialHeader sets a custom credential header for a host. Use this for APIs that use non-standard header names like "x-api-key". The host must be a valid hostname (not empty, no path components).

func (*Proxy) SetCredentialStore

func (p *Proxy) SetCredentialStore(store CredentialStore)

SetCredentialStore sets the credential store for MCP credential retrieval.

func (*Proxy) SetCredentialWithGrant

func (p *Proxy) SetCredentialWithGrant(host, headerName, headerValue, grant string)

SetCredentialWithGrant sets a credential header with grant info for logging. Grant is used for structured logging to identify the credential source. If a credential with the same grant and header name already exists for the host, it is updated in place (upsert). Otherwise, a new entry is appended. Matching on both grant and header name prevents empty-grant collisions when SetCredentialHeader is called multiple times with different headers.

func (*Proxy) SetLogger

func (p *Proxy) SetLogger(logger RequestLogger)

SetLogger sets the request logger.

func (*Proxy) SetMCPServers

func (p *Proxy) SetMCPServers(servers []MCPServerConfig)

SetMCPServers configures MCP servers for credential injection.

func (*Proxy) SetNetworkPolicy

func (p *Proxy) SetNetworkPolicy(policy string, allows []string, grants []string)

SetNetworkPolicy sets the network policy and allowed hosts. policy should be "permissive" or "strict". allows is a list of host patterns like "api.example.com" or "*.example.com". grants is a list of grant names like "github" that will be expanded to host patterns.

func (*Proxy) SetNetworkPolicyWithRules added in v0.4.0

func (p *Proxy) SetNetworkPolicyWithRules(policy string, allows []string, grants []string, checker RequestChecker, pathChecker PathRulesChecker)

SetNetworkPolicyWithRules sets the network policy with per-host request rules. The allows list should include hosts from rules (the caller extracts them). checker evaluates per-request rules; pathChecker reports if path-level rules exist.

func (*Proxy) SetPolicyLogger added in v0.5.0

func (p *Proxy) SetPolicyLogger(logger PolicyLogger)

SetPolicyLogger sets the policy decision logger.

func (*Proxy) SetTokenSubstitution

func (p *Proxy) SetTokenSubstitution(host, placeholder, realToken string)

SetTokenSubstitution replaces placeholder tokens with real tokens in both Authorization headers and request bodies for a specific host.

func (*Proxy) SetUpstreamCAs added in v0.5.0

func (p *Proxy) SetUpstreamCAs(pool *x509.CertPool)

SetUpstreamCAs sets a custom CA pool for verifying upstream (origin server) TLS certificates during CONNECT interception. When nil (the default), the system root certificates are used. This is useful for environments with private PKI or for testing.

type RequestChecker added in v0.5.0

type RequestChecker func(host string, port int, method, path string) bool

RequestChecker checks if a request to host:port with the given method and path is allowed. Provided by the caller to encapsulate network rule evaluation.

type RequestLogData

type RequestLogData struct {
	Method          string
	URL             string
	StatusCode      int
	Duration        time.Duration
	Err             error
	RequestHeaders  http.Header
	ResponseHeaders http.Header
	RequestBody     []byte
	ResponseBody    []byte
	AuthInjected    bool            // True if any credential header was injected for this host
	InjectedHeaders map[string]bool // Lower-cased header names that were injected
	RunID           string          // Run ID from per-run context (daemon mode)
}

RequestLogData contains all data for a logged request.

type RequestLogger

type RequestLogger func(data RequestLogData)

RequestLogger is called for each proxied request.

type ResponseTransformer added in v0.5.0

type ResponseTransformer func(req, resp any) (any, bool)

ResponseTransformer transforms HTTP responses before body capture. Cast to *http.Request and *http.Response in the transformer implementation. Returns the modified response and true if transformed, or original and false.

type RunContextData added in v0.3.0

type RunContextData struct {
	RunID                string
	Credentials          map[string][]credentialHeader
	ExtraHeaders         map[string][]extraHeader
	RemoveHeaders        map[string][]string
	TokenSubstitutions   map[string]*tokenSubstitution
	ResponseTransformers map[string][]ResponseTransformer
	MCPServers           []MCPServerConfig
	Policy               string
	AllowedHosts         []hostPattern
	RequestCheck         RequestChecker
	PathRulesCheck       PathRulesChecker
	AWSHandler           http.Handler
	CredStore            CredentialStore
	KeepEngines          map[string]*keeplib.Engine
	HostGateway          string
	AllowedHostPorts     []int
}

RunContextData holds per-run credential data resolved by ContextResolver.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server wraps a Proxy in an HTTP server.

func NewServer

func NewServer(proxy *Proxy) *Server

NewServer creates a new proxy server.

func (*Server) Addr

func (s *Server) Addr() string

Addr returns the proxy server address (host:port).

func (*Server) Port

func (s *Server) Port() string

Port returns just the port number the proxy is listening on.

func (*Server) Proxy

func (s *Server) Proxy() *Proxy

Proxy returns the underlying proxy.

func (*Server) SetBindAddr

func (s *Server) SetBindAddr(addr string)

SetBindAddr sets the address to bind to. Use "0.0.0.0" to bind to all interfaces (needed for Apple containers which access host via gateway IP). Must be called before Start().

func (*Server) SetPort added in v0.3.0

func (s *Server) SetPort(port int)

SetPort sets the port to bind to. Use 0 (default) for an OS-assigned port. Must be called before Start().

func (*Server) Start

func (s *Server) Start() error

Start starts the proxy server on an available port. By default binds to localhost only to prevent credential exposure to other hosts on the network. Use SetBindAddr("0.0.0.0") before Start() to bind to all interfaces (needed for Apple containers).

func (*Server) Stop

func (s *Server) Stop(ctx context.Context) error

Stop stops the proxy server.

type TokenSubstitution added in v0.3.0

type TokenSubstitution = tokenSubstitution

TokenSubstitution is the exported version of tokenSubstitution for daemon use.

func NewTokenSubstitution added in v0.3.0

func NewTokenSubstitution(placeholder, realToken string) *TokenSubstitution

NewTokenSubstitution creates a TokenSubstitution with the given placeholder and real token.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL