Documentation
¶
Overview ¶
Package configx defines the JSON configuration schema shared by the apic code generator and the generated servers, together with the validation and normalization that enforce a secure-by-default posture. It covers the runtime server settings (bind address, TLS/mTLS mode, timeouts, request-size limits, compression) and the security surface: the default-deny authentication config (api_key/jwt/cookie/mtls/webhook), the CSRF double-submit settings, and signer-key pinning. Helpers resolve secrets from the environment and fail closed when a required value (e.g. a CSRF signing key) is missing or too weak.
Index ¶
- Constants
- Variables
- func ClassifyCaller(rules []CallerKindRule, claim ClaimReader) callerctx.Kind
- func IsChallengeToken(s string) bool
- func IsScopeToken(s string) bool
- func ParseResourceIdentifier(resource string) (*url.URL, error)
- func ParseSPIFFEID(id string) (trustDomain, path string, err error)
- func ResolveCSRFKey(c *CSRFConfig, getenv func(string) string) ([]byte, error)
- func TokenMediaType(typ string) string
- func ValidateMetadataPath(p string) error
- func ValidateTrustDomain(name string) error
- type AuditConfig
- type AuditSinkConfig
- type AuthConfig
- type CORSConfig
- type CSRFConfig
- type CallerKindRule
- type ClaimReader
- type HTTP2Config
- type HeadersConfig
- type HealthCheckConfig
- type HealthConfig
- type HealthPaths
- type LimitConfig
- type LogExportConfig
- type LogFileBlockConfig
- type MCPConfig
- type MetricsEndpointConfig
- type OTELBlockConfig
- type ObservabilityConfig
- type PasswordHashConfig
- type PathRateLimit
- type RateLimitConfig
- type ResourceServerConfig
- type RuntimeConfig
- type SecurityConfig
- type ServerConfig
- type SessionConfig
- type SignerConfig
- type SignerKey
- type TLSConfig
- type TimeoutConfig
- type TracingBlockConfig
- type WebauthnRuntimeConfig
- type WebhookSecretRef
- type WorkloadAuthConfig
Constants ¶
const ( // CallerKindMatchEquals matches a string claim equal to Value. CallerKindMatchEquals = "equals" // CallerKindMatchPrefix matches a string claim that starts with Value. CallerKindMatchPrefix = "prefix" // CallerKindMatchContains matches an array claim with an element equal // to Value, or a string claim equal to it (the single-valued form RFC // 7519 §4.1.3 allows for "aud"). CallerKindMatchContains = "contains" // CallerKindMatchEqualsClaim matches a non-empty string claim equal to // the string claim Value names. CallerKindMatchEqualsClaim = "equals_claim" )
The CallerKindRule.Match operators. Each compares one top-level claim of a verified token, exactly and case-sensitively.
const ( DefaultReadHeaderTimeoutMS = 5000 DefaultReadTimeoutMS = 15000 DefaultWriteTimeoutMS = 30000 DefaultIdleTimeoutMS = 60000 )
Default HTTP server timeouts in milliseconds (PERF-0073). Applied by DecodeRuntimeConfig when a member is absent or non-positive so a generated server never boots with unbounded read/write/idle timeouts (slowloris / idle-connection exhaustion). Values mirror the shipped reference configs (configs/*.json). Operators override per environment in runtime config.
const ( // DefaultCSRFCookieName is the non-HttpOnly double-submit cookie name. DefaultCSRFCookieName = "csrf_token" // DefaultCSRFHeaderName is the request header carrying the token. DefaultCSRFHeaderName = "X-CSRF-Token" // DefaultCSRFEndpointPath is the token issuance endpoint. DefaultCSRFEndpointPath = "/csrf" // DefaultCSRFTTLSeconds is the token lifetime (12 hours). DefaultCSRFTTLSeconds = 43200 // DefaultCSRFSameSite is the cookie SameSite attribute. DefaultCSRFSameSite = "Strict" // DefaultCSRFMintRateLimit caps token issuance per peer per minute. DefaultCSRFMintRateLimit = 60 )
CSRFConfig defaults applied by Normalize. Named, like the sibling Default* constants in config.go and health.go, so the generated client (which stamps the same cookie/header names) and the docs cite one value.
const ( DefaultHealthProbeTimeoutMS = 2000 DefaultHealthCheckTimeoutMS = 1000 DefaultHealthCacheTTLMS = 500 DefaultHealthMaxConcurrency = 4 DefaultHealthDrainDelayMS = 5000 DefaultHealthShutdownTimeoutMS = 30000 DefaultHealthResponseDetails = "summary" DefaultHealthLivenessPath = "/livez" DefaultHealthReadinessPath = "/readyz" DefaultHealthStartupPath = "/startupz" )
Default health subsystem values (docs/HEALTH_CHECK_ENHANCEMENT.md §2), applied by ApplyDefaults when a member is absent/zero.
const ( MinKeyRefreshIntervalSeconds = 15 * 60 MaxKeyRefreshIntervalSeconds = 24 * 60 * 60 )
The bounds of ResourceServerConfig.MaxRefreshIntervalSeconds: no shorter than the key sets' 15-minute minimum refresh interval (oidcx.DefaultMinRefreshInterval), and no longer than their 24-hour default ceiling (oidcx.DefaultMaxRefreshInterval), which the member can only tighten.
const ( // MaxSPIFFEIDBytes is the longest SPIFFE ID accepted. MaxSPIFFEIDBytes = 2048 // MaxSPIFFETrustDomainBytes is the longest trust domain name accepted. MaxSPIFFETrustDomainBytes = 255 )
The SPIFFE ID length bounds (SPIFFE ID specification §2.1 and §2.3).
const DefaultHTTP2MaxConcurrentStreams = 250
DefaultHTTP2MaxConcurrentStreams is the per-connection HTTP/2 stream ceiling applied when server.http2.max_concurrent_streams is absent or non-positive. Bounds CVE-2023-44487 ("HTTP/2 Rapid Reset") exposure: an attacker can open and immediately cancel at most this many streams per connection before the server refuses more. PERF-0106 (#281).
const DefaultLogFileAsyncQueueSize = 1024
DefaultLogFileAsyncQueueSize is the async writer's queue depth when observability.logs.file.async_queue_size is 0/omitted. It is the same value obsx.LogFileConfig.ApplyDefaults installs, restated here so the config schema and docs can cite it without importing obsx.
const DefaultResourceMetadataPath = "/.well-known/oauth-protected-resource"
DefaultResourceMetadataPath is the RFC 9728 §3 well-known path of the protected-resource metadata document, used when ResourceServerConfig.MetadataPath is empty.
const DefaultResponseBufferBytes = 64 << 10 // 64 KiB
DefaultResponseBufferBytes is the response body size, in bytes, up to which the generated REST response writer buffers the marshaled JSON body in a pooled *bytes.Buffer and frames it with an explicit Content-Length, applied when ServerConfig.ResponseBufferBytes is zero (unset). PERF-0074 (#247): a size-stratified benchmark (tests/unit/route_response_bench_test.go) measured the pooled-buffer + Content-Length path -20.63%/-22.74% latency at 16 KiB/256 KiB versus the direct streamed marshal (chunked Transfer-Encoding), at the cost of a full in-memory copy (+1017% B/op at 256 KiB) -- so the generated writer bounds the trade-off two ways: a response body larger than this limit falls back to the direct/chunked path (no Content-Length, matching pre-fix behavior for large bodies), and a pooled buffer whose capacity grows past this limit is dropped instead of retained, so steady-state pool memory never grows past bodies at or under the limit.
const MaxAcceptableSkewSeconds = 300
MaxAcceptableSkewSeconds bounds ResourceServerConfig.AcceptableSkewSeconds: five minutes, RFC 7519 §4.1.4's "a few minutes" of leeway, and the cap the resource verifier itself applies (oidcx.MaxAcceptableSkew).
const MaxCallerKindRules = 32
MaxCallerKindRules bounds security.auth.caller_kind_rules. The rules run in order on every verified request, so the list stays short enough that classifying a caller is a negligible, bounded cost.
const MaxLogFileAsyncQueueSize = 1 << 20
MaxLogFileAsyncQueueSize is the largest explicit observability.logs.file.async_queue_size the generator (and api.WithLogFile) accepts. The async writer grows its queue lazily (a nil slice appended to per record; nothing is allocated at boot -- APPSEC pass-2 F-04 corrected the earlier "allocated eagerly" rationale), so the bound is what keeps a typo'd "1000000000" from letting a stalled disk accumulate an unbounded number of queued records before the drop path sheds load: the ceiling bounds PEAK queued-record memory under a stall, roughly depth x record size (~4 GB at 2^20 slots and ~4 KB records), plus the final shutdown drain that writes whatever is still queued. 2^20 slots is ~1000x the default and far beyond any burst a single disk absorbs.
const MaxResourceNameBytes = 256
MaxResourceNameBytes bounds ResourceServerConfig.ResourceName.
const MinLogFileAsyncQueueSize = 64
MinLogFileAsyncQueueSize is the smallest explicit observability.logs.file.async_queue_size the generator accepts.
Variables ¶
var ( // ErrCSRFSecretRefMissing indicates CSRF is enabled but secret_ref is empty. ErrCSRFSecretRefMissing = errors.New("configx: security.csrf.secret_ref is required when CSRF is enabled") // ErrCSRFKeyTooShort indicates the resolved CSRF key is shorter than 32 bytes. ErrCSRFKeyTooShort = errors.New("configx: CSRF signing key must be at least 32 bytes") )
var ErrInvalidCallerKindRules = errors.New("configx: invalid caller kind rules")
ErrInvalidCallerKindRules is wrapped by every error (*SecurityConfig).ValidateCallerKindRules returns.
var ErrInvalidObservability = errors.New("configx: invalid observability config")
ErrInvalidObservability reports an observability block the operational endpoints cannot be served from safely.
var ErrInvalidResourceServer = errors.New("configx: invalid resource server config")
ErrInvalidResourceServer is wrapped by every error (*ResourceServerConfig).Validate and (*WorkloadAuthConfig).Validate return.
var ErrInvalidSPIFFEID = errors.New("configx: invalid SPIFFE ID")
ErrInvalidSPIFFEID is wrapped by every error ParseSPIFFEID and ValidateTrustDomain return.
var ErrPlaintextPIN = errors.New("configx: literal PKCS#11 pin is not allowed in strict/FIPS mode; use pin_env")
ErrPlaintextPIN is returned by ResolvePIN(strict=true) when a literal PIN is configured instead of the env-indirection PINEnv. SEC-0032.
Functions ¶
func ClassifyCaller ¶ added in v0.24.0
func ClassifyCaller(rules []CallerKindRule, claim ClaimReader) callerctx.Kind
ClassifyCaller returns the Kind of the first rule in rules that matches the token claim reads, or callerctx.KindUnknown when none does.
Only a rule list that passed SecurityConfig.ValidateCallerKindRules is safe to apply. An unvalidated rule can still match every token a verifier accepts (for example "iss" prefix "https://"), or be shadowed by an earlier one. A rule whose Kind is not a rule target, whose Value is empty, or that compares a claim with itself never matches.
func IsChallengeToken ¶ added in v0.24.0
IsChallengeToken reports whether s may be sent as a value, or as one space-delimited token of a value, in a WWW-Authenticate challenge: an RFC 6749 §3.3 scope-token (IsScopeToken) with no "=" or ",". RFC 6749 allows both in a scope, but the MCP TypeScript and Python SDKs read a challenge with an unanchored first-match regex, name=(?:"([^"]+)"|([^\s,]+)), so a scope such as "resource_metadata=https://evil.example/" would be taken for the resource_metadata parameter itself, and parsers that split a challenge at "," would cut the value in two. It is the rule for scopes_supported, the step-up values and the resource identifier here, and for every token and URL pkg/oidcx renders into a challenge, so a value configx accepts is never dropped from a challenge.
func IsScopeToken ¶ added in v0.24.0
IsScopeToken reports whether s is an RFC 6749 §3.3 scope-token: 1*( %x21 / %x23-5B / %x5D-7E ), that is non-empty printable ASCII with no space, double quote or backslash, so it needs no escaping inside a quoted-string and cannot end it early. A value sent in a WWW-Authenticate challenge must also pass IsChallengeToken.
func ParseResourceIdentifier ¶ added in v0.24.0
ParseResourceIdentifier checks resource the way security.resource_server.resource is validated, and returns it parsed: an absolute https URI of RFC 3986 characters, with a lowercase literal scheme and host, no userinfo, query or fragment, no "=" or ",", and a path no client or router rewrites (see checkResourcePath). It is the one definition of a valid resource identifier: configuration validation and the RFC 9728 metadata URL derivation in pkg/oidcx both use it, so a resource configx refuses never yields a metadata URL. Errors wrap ErrInvalidResourceServer.
func ParseSPIFFEID ¶ added in v0.24.0
ParseSPIFFEID splits a SPIFFE ID into its trust domain and path, following the SPIFFE ID specification (§2): the literal scheme "spiffe://", a trust domain name (see ValidateTrustDomain), then either nothing or a path of one or more "/"-separated segments, each non-empty, neither "." nor "..", and made only of ASCII letters, digits, ".", "-" and "_". A trailing "/", percent-encoding, userinfo, a port, a query and a fragment are all refused; the trust-domain and path character sets admit none of them. The returned path is empty or begins with "/". At most MaxSPIFFEIDBytes bytes.
This is apic's one SPIFFE grammar: configuration validation (security.resource_server.workload_auth) and the runtime workload verifier both use it, so an ID the config accepts is an ID the verifier can match. Errors wrap ErrInvalidSPIFFEID.
func ResolveCSRFKey ¶
func ResolveCSRFKey(c *CSRFConfig, getenv func(string) string) ([]byte, error)
ResolveCSRFKey resolves the HMAC signing key from the environment, failing closed. Returns (nil, nil) when CSRF is disabled. getenv is injected for testability (pass os.Getenv at boot).
func TokenMediaType ¶ added in v0.24.0
TokenMediaType returns the media type a JOSE typ header value, or an accepted_token_types entry, names (RFC 7515 §4.1.9): lower-cased, since media types compare without regard to case, and with "application/" prepended when it holds no "/". It is the one comparison form both configuration validation and the resource verifier use.
func ValidateMetadataPath ¶ added in v0.24.0
ValidateMetadataPath reports whether p breaks the rules documented on ResourceServerConfig.MetadataPath, wrapped in ErrInvalidResourceServer, or nil. It is the one definition of a valid metadata path: Validate applies it to a non-empty MetadataPath, and pkg/oidcx's MetadataRoutePath refuses to build a route or URL from a path it rejects. The path becomes an exact-match route, so a value that is not already canonical would silently never match, and it travels in the resource_metadata challenge parameter, so it may hold no character a client parser reads as syntax. An empty p is refused; callers that treat "" as DefaultResourceMetadataPath check that first.
func ValidateTrustDomain ¶ added in v0.24.0
ValidateTrustDomain reports whether name is a SPIFFE trust domain name (SPIFFE ID specification §2.1): 1 to MaxSPIFFETrustDomainBytes bytes of lowercase letters, digits, ".", "-" and "_", with no empty "."-separated label, so no leading, trailing or doubled ".". Errors wrap ErrInvalidSPIFFEID.
Types ¶
type AuditConfig ¶
type AuditConfig struct {
Enabled bool `json:"enabled"`
// SignKeyID is the security.signer.keys[].id used to sign each
// envelope under FIPS profiles (AU-9 integrity). Required when
// security.fips=true.
SignKeyID string `json:"sign_key_id,omitempty"`
Sinks []AuditSinkConfig `json:"sinks,omitempty"`
}
AuditConfig configures the FedRAMP audit pipeline (Plan 05).
type AuditSinkConfig ¶
type AuditSinkConfig struct {
// Kind selects the sink implementation. Only "file" is implemented
// today (pkg/obsx/auditx.FileSink); "syslog" and "cef" are reserved
// future kinds and are rejected by the config validator until a real
// sink exists, so they cannot silently no-op at runtime (GAP-0081).
Kind string `json:"kind"` // "file" (implemented); "syslog"/"cef" reserved
Config map[string]any `json:"config,omitempty"`
}
AuditSinkConfig configures one audit sink.
type AuthConfig ¶
type AuthConfig struct {
APIKey bool `json:"api_key"`
JWT bool `json:"jwt"`
// Cookie is true when at least one REST route resolves to auth:"cookie".
// Derived from resolved route modes (see applyAuthDefaults) and used to
// emit the top-level cookieAuth entry in the generated OpenAPI security
// list, mirroring the APIKey/JWT bools.
Cookie bool `json:"cookie"`
JWTIssuer string `json:"jwt_issuer,omitempty"`
JWTAudience string `json:"jwt_audience,omitempty"`
// Default is the fallback auth mode applied to any REST or WebSocket
// route that omits `auth`. Recognized: "api_key", "jwt",
// "mtls" (REST only), "webhook" (REST only), or "public" (explicitly
// unauthenticated). Empty means NO default: under default-deny a route
// that omits auth and is not explicitly public is a configuration error.
Default string `json:"default,omitempty"`
// DefaultRequiredRoles is the minimum RBAC role set applied to any
// authenticated route (resolved mode != public) that declares no
// required_roles of its own. Role hierarchy: admin > manager > user.
DefaultRequiredRoles []string `json:"default_required_roles,omitempty"`
// DefaultRequiredScopes is the scope set applied to any authenticated
// route that declares no required_scopes of its own.
DefaultRequiredScopes []string `json:"default_required_scopes,omitempty"`
// CookieName is the name of the HttpOnly cookie that carries the session
// JWT for routes using auth:"cookie". Empty defaults to "session" (see
// AuthCookieName). Used by the generated cookie-auth extraction, the CSRF
// auth-source check, and the emitted OpenAPI cookie security scheme.
CookieName string `json:"cookie_name,omitempty"`
// CallerKindRules classifies the principal behind a verified JWT
// (callerctx.Caller.Kind). Configured rules apply to every JWT-verified
// route, whether the plain jwt verifier or the security.resource_server
// verifier accepted the token. Rules are evaluated in order and the first
// match sets the kind; a token no rule matches is "unknown", never
// "human", so a caller is human only when a rule positively identifies it
// as one. With no rules configured, EffectiveCallerKindRules returns the
// documented default, DefaultCallerKindRules (a token whose client_id
// equals its sub is a service, RFC 9068 §2.2), which never yields
// "human"; configuring any rule replaces that default entirely. The
// plain jwt path applies the effective rules as the resource verifier
// does (SONNY-794): there is no "any token with a sub is human" default,
// so a deployment that needs human callers (the WebAuthn owner binding,
// MCP tool ownership) configures a rule that positively identifies them,
// and generation refuses one that enables either without such a rule
// (LegacyHumanSubjects is the deprecated way out on plain jwt routes).
// At most MaxCallerKindRules (32) rules; see CallerKindRule and
// SecurityConfig.ValidateCallerKindRules.
CallerKindRules []CallerKindRule `json:"caller_kind_rules,omitempty"`
// LegacyHumanSubjects restores, on routes the plain jwt verifier
// accepts, the caller classification apic applied before SONNY-794:
// any verified token with a sub is "human" (else one with a client_id
// or azp is "service"). That reads every service token that has a sub,
// a ThreadID machine token among them, as a human (SONNY-2684), which
// hands it a human's standing at the MCP ownership gate and the
// WebAuthn owner binding. It is refused beside caller_kind_rules (the
// rules decide, or the legacy rule does, never both) and beside an
// enabled security.resource_server (a resource-server route always
// applies the rules).
//
// Deprecated: a stopgap while a deployment writes caller_kind_rules
// that positively identify its human callers; it will be removed.
LegacyHumanSubjects bool `json:"legacy_human_subjects,omitempty"`
}
AuthConfig defines the authentication surface and the secure-first default-deny posture (F0). Default/DefaultRequiredRoles/DefaultRequiredScopes are applied by the generator to any route that declares no auth of its own.
func (AuthConfig) AuthCookieName ¶
func (a AuthConfig) AuthCookieName() string
AuthCookieName returns the configured session-cookie name, defaulting to "session".
func (AuthConfig) EffectiveCallerKindRules ¶ added in v0.24.0
func (a AuthConfig) EffectiveCallerKindRules() []CallerKindRule
EffectiveCallerKindRules returns a copy of the configured caller-kind rules, or DefaultCallerKindRules when none are configured: rules configured means the rules decide.
type CORSConfig ¶
CORSConfig defines CORS enablement and origins.
type CSRFConfig ¶
type CSRFConfig struct {
// Enabled is the master switch. When false the generator emits no CSRF
// middleware and no /csrf endpoint.
Enabled bool `json:"enabled"`
// SecretRef names the environment variable holding the HMAC signing key
// (>=32 bytes). Required when Enabled; resolution fails closed at boot.
SecretRef string `json:"secret_ref"`
// CookieName is the non-HttpOnly cookie carrying the token. Default
// "csrf_token".
CookieName string `json:"cookie_name,omitempty"`
// HeaderName is the request header echoing the token. Default
// "X-CSRF-Token".
HeaderName string `json:"header_name,omitempty"`
// EndpointPath is the GET issuance route. Default "/csrf" (joined under
// the API prefix by the generator).
EndpointPath string `json:"endpoint_path,omitempty"`
// TTLSeconds is the token lifetime. Default 43200 (12h).
TTLSeconds int `json:"ttl_seconds,omitempty"`
// SecureCookies sets the Secure attribute on the CSRF cookie. Nil
// defaults to TRUE; set explicit false ONLY for local-dev over plain
// HTTP (otherwise the browser drops the cookie and every write 403s).
SecureCookies *bool `json:"secure_cookies,omitempty"`
// SameSite is the cookie SameSite mode: "Strict" (default), "Lax", or
// "None".
SameSite string `json:"same_site,omitempty"`
// ExemptPaths are additional paths exempt from enforcement. The issuance
// endpoint and any *_login / *_logout / health routes are auto-exempt.
ExemptPaths []string `json:"exempt_paths,omitempty"`
// MintRateLimit bounds requests per minute, PER CLIENT IP, to the
// GET <endpoint_path> issuance route. It is enforced by an
// httpx.PeerLimiter keyed identically to security.rate_limit's global
// per-IP limiter -- same per_ip_source, same trusted_proxy_cidrs -- so a
// forwarded header (X-Forwarded-For / X-Real-IP) is honored, or ignored,
// the same way at every layer. Default 60 (applied by Normalize): 0 means
// "unset", NOT "unlimited" -- there is no setting that disables the
// bound. A negative value is rejected at generation. SEC-0060/0061: an
// unauthenticated caller can hit the mint endpoint repeatedly for free
// (it costs the server an HMAC sign per call and, pre-login, mints a
// token bound to the shared "" session), so it needs its own per-client
// bound rather than none at all.
MintRateLimit int `json:"mint_rate_limit,omitempty"`
}
CSRFConfig configures generated CSRF protection. Defaults (applied by Normalize) follow OWASP guidance: 12h TTL, SameSite=Strict, Secure cookies on.
func (*CSRFConfig) CSRFSecureCookies ¶
func (c *CSRFConfig) CSRFSecureCookies() bool
CSRFSecureCookies reports the effective Secure attribute (default true).
func (*CSRFConfig) Normalize ¶
func (c *CSRFConfig) Normalize()
Normalize applies CSRFConfig defaults in place.
type CallerKindRule ¶ added in v0.24.0
type CallerKindRule struct {
// Claim is the top-level claim the rule reads, for example "sub", "amr"
// or "client_id". Required, with no whitespace or control characters.
Claim string `json:"claim"`
// Match is the comparison: "equals" (the claim is a string equal to
// Value), "prefix" (a string that starts with Value), "contains" (an
// array with an element equal to Value, or a string equal to it) or
// "equals_claim" (a non-empty string equal to the string claim that
// Value names).
Match string `json:"match"`
// Value is the literal Match compares the claim with, or for
// equals_claim the name of the other claim. Required: an empty prefix
// would match every token that carries the claim.
Value string `json:"value"`
// Kind is the caller kind a match assigns: "human", "service",
// "workload" or "device". "unknown" is not a rule target: it is what a
// token no rule matches already gets. A "human" rule may not read
// "client_id" or "azp", as its claim or its equals_claim: a client
// chooses or registers its own identifier (RFC 9700 §4.14).
Kind callerctx.Kind `json:"kind"`
}
CallerKindRule maps one match against a verified token's claims to a caller kind (security.auth.caller_kind_rules[]).
Claim names a top-level claim literally: no nesting, and no aliasing (the "azp" claim is not "client_id"). A claim that is absent, or not of the type Match reads, never matches. Matching is exact and case-sensitive.
func DefaultCallerKindRules ¶ added in v0.24.0
func DefaultCallerKindRules() []CallerKindRule
DefaultCallerKindRules returns the caller-kind rules applied when security.auth.caller_kind_rules is empty: a token whose client_id equals its sub is callerctx.KindService (RFC 9068 §2.2: a token issued with no resource owner involved, such as by the client credentials grant, names the client as its subject). Every other token is callerctx.KindUnknown.
The default never yields callerctx.KindHuman. No claim identifies a human portably across issuers, so a deployment that wants human callers adds a rule that positively identifies them for its own issuer. It applies on every JWT-verified route, the plain jwt verifier's as well as the resource verifier's (SONNY-794). Every call returns a fresh slice.
func (CallerKindRule) Matches ¶ added in v0.24.0
func (r CallerKindRule) Matches(claim ClaimReader) bool
Matches reports whether r matches the token claim reads. A nil reader, an empty Value, an unknown Match, or an equals_claim comparing a claim with itself (true of every token that carries it) matches nothing.
type ClaimReader ¶ added in v0.24.0
ClaimReader reads one top-level claim of a verified token and reports whether the token carries it. The value is the decoded JSON: string, []any (or []string), float64, bool or map[string]any.
type HTTP2Config ¶ added in v0.18.3
type HTTP2Config struct {
// Enabled advertises "h2" ahead of "http/1.1" in the listener's TLS
// ALPN list and configures net/http's bundled HTTP/2 server. Absent
// (nil) means enabled — HTTP/2 is the default. Set false to pin the
// listener to HTTP/1.1 (ALPN advertises only "http/1.1").
//
// Raw WebSocket routes keep working either way: net/http's h2 server
// has no RFC 8441 Extended CONNECT, so WS clients offer only
// "http/1.1" and negotiate down through ALPN on the same listener.
Enabled *bool `json:"enabled,omitempty"`
// MaxConcurrentStreams bounds the number of concurrent HTTP/2 streams
// a single client connection may open (http.HTTP2Config.
// MaxConcurrentStreams). Absent or non-positive means
// DefaultHTTP2MaxConcurrentStreams (250). Ignored when Enabled is
// false.
MaxConcurrentStreams int `json:"max_concurrent_streams,omitempty"`
}
HTTP2Config controls HTTP/2 negotiation on the primary TLS listener.
func (HTTP2Config) ALPNProtocols ¶ added in v0.18.3
func (h HTTP2Config) ALPNProtocols() []string
ALPNProtocols returns the TLS ALPN list this HTTP/2 policy implies: ["h2", "http/1.1"] when enabled, ["http/1.1"] when explicitly disabled.
func (*HTTP2Config) ApplyDefaults ¶ added in v0.18.3
func (h *HTTP2Config) ApplyDefaults()
ApplyDefaults fills a non-positive MaxConcurrentStreams with the package default (PERF-0106). An explicit positive value is preserved. Called by DecodeRuntimeConfig so a generated server never boots with net/http's unbounded-by-config stream ceiling. When HTTP/2 is disabled the field is documented as ignored, so it is left untouched rather than filled with a ceiling that nothing will ever apply.
func (HTTP2Config) On ¶ added in v0.18.3
func (h HTTP2Config) On() bool
On reports whether HTTP/2 negotiation is enabled (the default when the member is omitted).
type HeadersConfig ¶ added in v0.14.3
type HeadersConfig struct {
ContentSecurityPolicy string `json:"content_security_policy,omitempty"`
CrossOriginOpenerPolicy string `json:"cross_origin_opener_policy,omitempty"`
CrossOriginEmbedderPolicy string `json:"cross_origin_embedder_policy,omitempty"`
CrossOriginResourcePolicy string `json:"cross_origin_resource_policy,omitempty"`
PermissionsPolicy string `json:"permissions_policy,omitempty"`
DisableAll bool `json:"disable_all,omitempty"`
}
HeadersConfig configures per-deployment overrides for the SEC-0023 hardened response-header set. Field names and semantics mirror httpx.Config's header-override knob (pkg/httpx/server.go) exactly: for each header, an empty string keeps the httpx secure default, the literal "-" suppresses that single header, and any other value is emitted verbatim. DisableAll drops the whole hardened set at once (the legacy headers -- HSTS/X-Content-Type-Options/X-Frame-Options/Referrer-Policy -- are unaffected either way, matching httpx.Config.DisableSecurityHeaders).
func (*HeadersConfig) Get ¶ added in v0.14.3
func (h *HeadersConfig) Get() HeadersConfig
Get returns *h, or the zero HeadersConfig{} (every field empty/false -- "no overrides, hardened set enabled") when h is nil. Nil-safe accessor, mirroring CSRFConfig's Normalize()/CSRFSecureCookies() pattern, so a generated server's hcfg construction never needs an explicit nil check before reading an override field.
type HealthCheckConfig ¶ added in v0.15.0
type HealthCheckConfig struct {
// Name identifies the check; must match the name passed to
// WithHealthCheck/WithHealthChecker at boot.
Name string `json:"name"`
// Probes lists which probes this check participates in: "startup"
// and/or "readiness". External checks must never be assigned to
// "liveness" (enforced at generation).
Probes []string `json:"probes"`
// Critical controls aggregation: a failing critical check fails the
// overall probe; a failing non-critical check only degrades it to
// "warn".
Critical bool `json:"critical"`
// TimeoutMS is the per-check timeout. Zero inherits
// HealthConfig.DefaultCheckTimeoutMS.
TimeoutMS int `json:"timeout_ms,omitempty"`
}
HealthCheckConfig declares one external dependency check that the generated server requires a hook registration for.
type HealthConfig ¶ added in v0.15.0
type HealthConfig struct {
// Enabled is the master switch. When false (or the block is absent)
// the generator emits no probe endpoints.
Enabled bool `json:"enabled"`
// Service names the process in probe responses (the "service" field).
Service string `json:"service,omitempty"`
// Paths overrides the default probe endpoint paths.
Paths HealthPaths `json:"paths,omitempty"`
// ResponseDetails controls how much a probe response discloses:
// "none", "summary" (default), or "full". "full" is reserved for a
// future authenticated diagnostic endpoint; the generator rejects it
// on the public probe surface.
ResponseDetails string `json:"response_details,omitempty"`
// ProbeTimeoutMS bounds the overall probe evaluation (all checks for
// that probe combined). Default 2000.
ProbeTimeoutMS int `json:"probe_timeout_ms,omitempty"`
// DefaultCheckTimeoutMS is the per-check timeout applied when a check
// declares no timeout_ms of its own. Default 1000.
DefaultCheckTimeoutMS int `json:"default_check_timeout_ms,omitempty"`
// CacheTTLMS is how long a completed check result is reused before
// the next probe request re-invokes the hook. Default 500.
CacheTTLMS int `json:"cache_ttl_ms,omitempty"`
// MaxConcurrency bounds simultaneous in-flight dependency check
// invocations across all probes. Default 4.
MaxConcurrency int `json:"max_concurrency,omitempty"`
// DrainDelayMS is how long readiness reports failure before shutdown
// proceeds, giving load balancers time to stop routing new traffic.
// Default 5000.
DrainDelayMS int `json:"drain_delay_ms,omitempty"`
// ShutdownTimeoutMS bounds the graceful HTTP shutdown once draining
// completes. Default 30000. Must not be shorter than DrainDelayMS
// (enforced at generation).
ShutdownTimeoutMS int `json:"shutdown_timeout_ms,omitempty"`
// PublishOpenAPI is reserved and must be false/omitted: it is not
// implemented in this generator version, and generation fails when true.
// Probes are a control-plane concern and are always omitted from the
// public OpenAPI spec regardless of this flag.
PublishOpenAPI bool `json:"publish_openapi,omitempty"`
// Checks declares the external dependency checks the generated
// server expects a matching WithHealthCheck/WithHealthChecker
// registration for at startup.
Checks []HealthCheckConfig `json:"checks,omitempty"`
}
HealthConfig configures the generated control-plane health subsystem: the /livez, /readyz, and /startupz probe endpoints, their timeouts and caching, drain/shutdown coordination, and the declared set of external dependency checks (see docs/HEALTH_CHECK_ENHANCEMENT.md). Absence (a nil *HealthConfig on RuntimeConfig) means the subsystem is disabled, preserving byte-for-byte behavior for existing configurations.
func (*HealthConfig) ApplyDefaults ¶ added in v0.15.0
func (h *HealthConfig) ApplyDefaults()
ApplyDefaults fills zero-valued members with the package defaults. Explicit non-zero values are preserved.
func (*HealthConfig) EffectivePaths ¶ added in v0.15.0
func (h *HealthConfig) EffectivePaths() HealthPaths
EffectivePaths returns the probe paths that would be in effect, applying the package defaults for any path left unset. Nil-safe: an absent block yields the default paths (/livez, /readyz, /startupz).
func (*HealthConfig) Get ¶ added in v0.15.0
func (h *HealthConfig) Get() HealthConfig
Get is nil-safe: an unconfigured block yields the zero value (disabled, no overrides).
func (*HealthConfig) On ¶ added in v0.15.0
func (h *HealthConfig) On() bool
On reports whether the health subsystem is configured and enabled. Nil-safe: an absent block is never "on".
type HealthPaths ¶ added in v0.15.0
type HealthPaths struct {
Liveness string `json:"liveness,omitempty"`
Readiness string `json:"readiness,omitempty"`
Startup string `json:"startup,omitempty"`
}
HealthPaths overrides the default probe endpoint paths.
type LimitConfig ¶
type LimitConfig struct {
MaxHeaderBytes int `json:"max_header_bytes"`
MaxBodyBytes int64 `json:"max_body_bytes"`
}
LimitConfig defines request-size limits.
type LogExportConfig ¶ added in v0.15.0
type LogExportConfig struct {
// Enabled: nil = env-driven (OTEL_LOGS_EXPORTER / OTLP endpoints);
// true = force on; false = hard off. Governs the OTLP log exporter only;
// on-disk File delivery is controlled by its own block.
Enabled *bool `json:"enabled,omitempty"`
// Endpoint overrides the logs OTLP URL (verbatim, e.g. …/v1/logs).
Endpoint string `json:"endpoint,omitempty"`
// File, when set, enables rotating on-disk log delivery (lumberjack) in
// addition to stdout and any OTLP export. The file sink joins the same
// redaction-wrapped fanout, so on-disk lines are redacted too.
File *LogFileBlockConfig `json:"file,omitempty"`
}
LogExportConfig configures log delivery beyond the always-on stdout JSON logs: OTLP log-aggregation export and (File) rotating on-disk delivery.
func (*LogExportConfig) Get ¶ added in v0.15.0
func (l *LogExportConfig) Get() LogExportConfig
Get is nil-safe.
type LogFileBlockConfig ¶ added in v0.15.0
type LogFileBlockConfig struct {
// Path is the active log file path. Required when the block is present.
Path string `json:"path"`
// MaxSizeMB is the rotation size threshold in megabytes (0 => default).
MaxSizeMB int `json:"max_size_mb,omitempty"`
// MaxBackups is the number of rotated files retained (0 => default).
MaxBackups int `json:"max_backups,omitempty"`
// MaxAgeDays is the maximum retained age of a rotated file (0 => default).
MaxAgeDays int `json:"max_age_days,omitempty"`
// Compress gzips rotated backups.
Compress bool `json:"compress,omitempty"`
// AsyncQueueSize bounds how many pending log records the on-disk sink's
// async writer queues before it drops new records fail-open instead of
// blocking the request goroutine (mirrors obsx.LogFileConfig.AsyncQueueSize;
// PERF-0091). 0/omitted => 1024 (DefaultLogFileAsyncQueueSize). When set
// it must be >= 64 (MinLogFileAsyncQueueSize): a smaller queue drops
// under ordinary burst and is never what an operator means; and
// <= 1048576 (MaxLogFileAsyncQueueSize): the queue grows lazily, one
// record at a time, so the ceiling bounds the PEAK memory queued records
// can occupy while the disk is stalled (at the ceiling with ~4 KB
// records that is ~4 GB of live heap before the first drop sheds load),
// not an allocation made at boot. Raise it when the drop counter
// (obsx_logfile_records_dropped) climbs on a slow disk.
AsyncQueueSize int `json:"async_queue_size,omitempty"`
}
LogFileBlockConfig is the config-file view of obsx.LogFileConfig: rotating on-disk log delivery via lumberjack. Zero size/backup/age members inherit the auditx-mirrored defaults (100 MiB / 7 backups / 365 days) at runtime.
func (*LogFileBlockConfig) Get ¶ added in v0.15.0
func (f *LogFileBlockConfig) Get() LogFileBlockConfig
Get is nil-safe: an unconfigured block yields the zero value.
type MCPConfig ¶
type MCPConfig struct {
Transport []string `json:"transport"`
// Tools is carried in runtime.json (the full config) but consumed only
// at generate time -- the tool surface is baked into the generated MCP
// handlers. Declared, accepted, and ignored so the strict runtime
// decode of the full-config superset succeeds (see DecodeRuntimeConfig).
// The generator's MCPConfigSection models it with a richer type.
Tools any `json:"tools,omitempty"`
// Resources is the opt-in mcp.resources list (SONNY-507). Like Tools it
// is consumed at generate time only (the resource table is baked into
// the generated MCP engine) and is declared here so the strict runtime
// decode accepts a config that sets it.
Resources any `json:"resources,omitempty"`
// MaxBodyBytes, Rate, Burst and JWTAlg are the rest of the generator's
// MCPConfigSection: the MCP HTTP body cap, the per-tool token-bucket
// rate and burst, and the MCP JWT algorithm, all baked into the emitted
// transport at generate time. They ride along in runtime.json like
// Tools and, like Tools, are declared here only so the strict runtime
// decode accepts a config that sets them -- before they existed, any
// config with mcp.max_body_bytes or mcp.rate (configs/fedramp-
// baseline.json) generated cleanly and then failed to boot with
// "unknown object member name ... within /mcp". internal/generator's
// TestRuntimeMCPConfig_DeclaresEveryGeneratorMember keeps the two
// structs' members in step; TestDecodeRuntimeConfig_AcceptsEveryFixture
// (this package) proves it against every shipped fixture.
MaxBodyBytes int64 `json:"max_body_bytes,omitempty"`
Rate float64 `json:"rate,omitempty"`
Burst float64 `json:"burst,omitempty"`
JWTAlg string `json:"jwt_alg,omitempty"`
}
MCPConfig defines enabled MCP transports.
type MetricsEndpointConfig ¶ added in v0.15.0
type MetricsEndpointConfig struct {
Enabled bool `json:"enabled"`
// Path defaults to /metrics.
Path string `json:"path,omitempty"`
// Auth: "inherit" (default) or "bearer".
Auth string `json:"auth,omitempty"`
// BearerTokenEnv names the env var holding the scrape token when
// Auth=="bearer" (default APIC_METRICS_TOKEN; the _FILE variant is
// honored). Minimum 16 bytes; boot fails without it.
BearerTokenEnv string `json:"bearer_token_env,omitempty"`
// DisableGoCollector skips go/process runtime collectors.
DisableGoCollector bool `json:"disable_go_collector,omitempty"`
}
MetricsEndpointConfig exposes Prometheus scraping. There is NO public mode: the endpoint is always authenticated ("inherit" = the server's composite auth surface; "bearer" = constant-time scrape token).
func (MetricsEndpointConfig) EffectiveAuth ¶ added in v0.15.0
func (m MetricsEndpointConfig) EffectiveAuth() string
EffectiveAuth returns the auth mode (default inherit).
func (MetricsEndpointConfig) EffectivePath ¶ added in v0.15.0
func (m MetricsEndpointConfig) EffectivePath() string
EffectivePath returns the scrape path (default /metrics).
func (MetricsEndpointConfig) EffectiveTokenEnv ¶ added in v0.15.0
func (m MetricsEndpointConfig) EffectiveTokenEnv() string
EffectiveTokenEnv returns the bearer-token env var name.
func (*MetricsEndpointConfig) Get ¶ added in v0.15.0
func (m *MetricsEndpointConfig) Get() MetricsEndpointConfig
Get is nil-safe: an unconfigured block yields the zero value (disabled).
type OTELBlockConfig ¶ added in v0.15.0
type OTELBlockConfig struct {
// Enabled: nil = env-driven (any OTLP endpoint env var activates);
// true = force on (default endpoint http://localhost:4318 if no
// endpoint is given anywhere); false = hard off (env vars ignored,
// only the code-level WithOTEL/WithTelemetry options can re-enable).
Enabled *bool `json:"enabled,omitempty"`
// Endpoint is the base OTLP/HTTP URL (…:4318); per-signal /v1/<signal>
// paths are appended. OTEL_EXPORTER_OTLP_ENDPOINT overrides it.
Endpoint string `json:"endpoint,omitempty"`
// Protocol: "http/json" (default). "http/protobuf" is also accepted,
// but downgrades to http/json at runtime with a warning log (otelx has
// no native protobuf encoder; collectors listening on :4318 accept
// both). "grpc" fails validation.
Protocol string `json:"protocol,omitempty"`
// ServiceName seeds service.name (OTEL_SERVICE_NAME overrides).
ServiceName string `json:"service_name,omitempty"`
// HeadersEnv names an env var holding "k=v,k2=v2" export headers
// (e.g. collector auth). Never inline secrets in config files.
HeadersEnv string `json:"headers_env,omitempty"`
// TracesSampler / TracesSamplerArg mirror OTEL_TRACES_SAMPLER(_ARG).
TracesSampler string `json:"traces_sampler,omitempty"`
TracesSamplerArg string `json:"traces_sampler_arg,omitempty"`
// MetricExportIntervalMS mirrors OTEL_METRIC_EXPORT_INTERVAL, in
// milliseconds (0 => default (60s)).
MetricExportIntervalMS int `json:"metric_export_interval_ms,omitempty"`
}
OTELBlockConfig is the config-file baseline for the OTEL bootstrap.
func (*OTELBlockConfig) Get ¶ added in v0.15.0
func (o *OTELBlockConfig) Get() OTELBlockConfig
Get is nil-safe: an unconfigured block yields the zero value.
type ObservabilityConfig ¶
type ObservabilityConfig struct {
EnableDebug bool `json:"enable_debug"`
// OTEL configures the OpenTelemetry bootstrap baseline. Env vars
// (OTEL_EXPORTER_OTLP_ENDPOINT, ...) override these values; the
// generated WithOTEL option overrides both.
OTEL *OTELBlockConfig `json:"otel,omitempty"`
// Metrics exposes the authenticated Prometheus scrape endpoint.
Metrics *MetricsEndpointConfig `json:"metrics,omitempty"`
// Logs configures OTLP log-aggregation delivery (in addition to the
// always-on stdout JSON logs).
Logs *LogExportConfig `json:"logs,omitempty"`
// Tracing configures the correlation-ID surface: the header propagated
// end-to-end and whether trace/span IDs are threaded into request logs.
Tracing *TracingBlockConfig `json:"tracing,omitempty"`
// RequiredScopes lists the OAuth scopes an access token must carry to
// read the operational endpoints of a server with an enabled
// security.resource_server (SONNY-794): the metrics endpoint when
// metrics.auth is "inherit", and /debug/vars and /debug/pprof/ when
// enable_debug is set. There those endpoints admit only an access token
// the resource verifier accepts that carries every scope listed, and
// answer any other request with the resource's WWW-Authenticate
// challenge (403 insufficient_scope naming these scopes for a token that
// lacks one, 503 when the key set is unavailable). It is required when
// the resource server is enabled and either endpoint is on that way:
// otherwise any valid access token, issued to any client for any
// purpose, could read process metrics and pprof profiles. Each entry is
// a challenge token (IsChallengeToken), listed once. It is refused
// without an enabled resource server, which alone can check it. Metrics
// with auth "bearer" (a static scrape token) do not read it.
// ValidateRequiredScopes is the check.
RequiredScopes []string `json:"required_scopes,omitempty"`
}
ObservabilityConfig controls debug endpoints and the built-in observability delivery: env-first OTEL bootstrap, the authenticated Prometheus /metrics endpoint, and OTLP log delivery. Precedence at runtime: code options (WithOTEL/WithPrometheus) > OTEL_* env vars > this block > built-in defaults.
func (ObservabilityConfig) ValidateRequiredScopes ¶ added in v0.24.0
func (o ObservabilityConfig) ValidateRequiredScopes(resourceServerOn bool) error
ValidateRequiredScopes checks RequiredScopes for a server whose security.resource_server is enabled (resourceServerOn) or not: each entry a challenge token, listed once; none without an enabled resource server; and, with one, at least one when enable_debug is set or the metrics endpoint is enabled with auth "inherit" (see RequiredScopes).
type PasswordHashConfig ¶
type PasswordHashConfig struct {
// Default algorithm for fields that declare hash:"default".
Default string `json:"default,omitempty"`
// PepperEnv names an environment variable holding a server-side pepper
// (optional defense-in-depth; applied via HMAC-SHA-256 before hashing).
PepperEnv string `json:"pepper_env,omitempty"`
}
PasswordHashConfig is the global password-hashing policy block.
type PathRateLimit ¶
type PathRateLimit struct {
PathPrefix string `json:"path_prefix"`
PerIPRPS float64 `json:"per_ip_rps"`
PerIPBurst int `json:"per_ip_burst"`
// TrustedProxyCIDRs lists the reverse-proxy networks whose forwarded
// headers (X-Forwarded-For / X-Real-IP) this path's limiter honors when
// the global PerIPSource selects a proxy-header source. Empty (the
// default) INHERITS the global RateLimitConfig.TrustedProxyCIDRs set, so a
// forwarded PerIPSource keys the same way at every layer; set this field
// to override the global set for this path only. (Only an empty GLOBAL set
// trusts no proxy — see RateLimitConfig.TrustedProxyCIDRs.) Threaded into
// httpx.PathLimit at generation. T-06 / GAP-0094 / GAP-0095.
TrustedProxyCIDRs []string `json:"trusted_proxy_cidrs,omitempty"`
}
PathRateLimit is a stricter per-IP rate-limit bucket scoped to a path prefix (F3) — e.g. a tighter ceiling on /v1/auth/* to blunt credential stuffing. Applied IN ADDITION TO the global per-IP limiter.
type RateLimitConfig ¶
type RateLimitConfig struct {
GlobalRPS int `json:"global_rps"`
Burst int `json:"burst"`
PerIPRPS float64 `json:"per_ip_rps,omitempty"`
PerIPBurst int `json:"per_ip_burst,omitempty"`
PerIPSource string `json:"per_ip_source,omitempty"`
// TrustedProxyCIDRs lists the reverse-proxy networks whose forwarded
// headers (X-Forwarded-For / X-Real-IP) the global per-IP limiter honors
// when PerIPSource is a proxy-header source. Empty (the default) trusts no
// proxy. Each entry must be a valid CIDR (e.g. "10.0.0.0/8"); malformed
// entries are rejected at config validation. T-06 / GAP-0094.
TrustedProxyCIDRs []string `json:"trusted_proxy_cidrs,omitempty"`
// PathOverrides install stricter per-IP buckets for matching path
// prefixes, checked before the route handler. Longest-prefix match wins.
PathOverrides []PathRateLimit `json:"path_overrides,omitempty"`
}
RateLimitConfig defines global rate-limit defaults.
GlobalRPS / Burst (-> APIOptions.GlobalRate / GlobalBurst) configure a single server-wide aggregate token bucket shared by every generated route. It is a coarse ceiling: it is checked once per request (after auth/authz, just before the per-route bucket) in addition to -- not instead of -- the per-route rateLimit buckets (which remain the tighter per-endpoint ceiling) and the per-IP limiter. When GlobalRPS is 0 (or Burst is 0) the aggregate limiter is disabled. Note: a route that declares no rateLimit of its own still falls back to GlobalRPS as its *per-route* default rate -- that pre-existing behavior is unchanged and is separate from the aggregate ceiling described here. PerIPRPS / PerIPBurst configure a coarser ceiling applied to every route, partitioned by client IP (the key source is PerIPSource: "remote_addr" (default, safe), "x-forwarded-for", "x-real-ip", or "tls-subject"). A PerIPRPS of zero disables the per-IP layer (opt-in).
When PerIPSource selects a forwarded-header source ("x-forwarded-for" or "x-real-ip"), the limiter honors that header ONLY for peers within TrustedProxyCIDRs. With no trusted CIDRs configured (the default) no proxy is trusted: forged forwarded headers are ignored and keying falls back to the peer's RemoteAddr. Set TrustedProxyCIDRs to the reverse-proxy networks in front of the server, otherwise a forwarded-header source silently collapses every client behind the proxy into a single bucket. T-06 / GAP-0094.
type ResourceServerConfig ¶ added in v0.24.0
type ResourceServerConfig struct {
// Enabled is the master switch. When false, or when the block is absent,
// the block has no effect. A disabled block is still validated: a
// malformed value is refused whether or not it is in effect.
Enabled bool `json:"enabled,omitempty"`
// Resource is the canonical resource identifier: the https URI a client
// names in the token request's "resource" parameter (RFC 8707) and that
// an accepted token must carry as an audience. Required when enabled. It
// must be an absolute https URI of RFC 3986 characters with a lowercase
// host and no userinfo, query or fragment (RFC 9728 §1.2, RFC 8707 §2),
// and a path no client or router rewrites: not "/" alone (write the
// origin without it), no encoded "/" (%2F), and no empty, "." or ".."
// segment, even percent-encoded; one trailing "/" after a path is kept.
// It must not contain "=" or ",": the metadata URL built from it travels
// as resource_metadata in WWW-Authenticate challenges, where client
// parsers read both as parameter syntax (IsChallengeToken).
// ParseResourceIdentifier is the check.
Resource string `json:"resource,omitempty"`
// AuthorizationServers lists the issuer identifiers (RFC 8414 §2) of the
// authorization servers whose access tokens this resource accepts. At
// least one is required when enabled. Each must be an https URI of RFC
// 3986 characters with a host and no query, fragment or userinfo, spelled
// exactly as its tokens' iss claim (verification compares iss exactly,
// RFC 8414 §3.3), and no issuer may repeat, even under another spelling
// (host case, a default :443 port, a trailing "/").
AuthorizationServers []string `json:"authorization_servers,omitempty"`
// TokenJWKSURI is the https URL of the JWK Set whose keys verify the
// access tokens the configured authorization server issues. Optional;
// when set it must be an absolute https URI with a host and no fragment
// or userinfo, and exactly one authorization server may be configured:
// one key set cannot stand for several issuers, whose keys come from
// per-issuer discovery instead. When unset, the key set is discovered
// from the issuer. It is never published in the RFC 9728 metadata
// document: RFC 9728's jwks_uri member names a resource's own signing
// keys, which apic does not support.
TokenJWKSURI string `json:"token_jwks_uri,omitempty"`
// ResourceName is the human-readable name of the protected resource,
// published as resource_name in the RFC 9728 metadata document for
// display to end users (RFC 9728 §2 recommends it). Optional; left out of
// the document when empty. At most MaxResourceNameBytes (256) bytes of
// UTF-8, with no leading or trailing whitespace and no invisible or
// formatting character (Unicode Cc, Cf, Zl or Zp: bidirectional controls,
// zero-width characters, the BOM, the soft hyphen, tag characters) that
// could make it display, or read to an agent, as something else.
ResourceName string `json:"resource_name,omitempty"`
// ScopesSupported lists the OAuth scopes this resource understands,
// published as scopes_supported (RFC 9728 §2). Each must be an RFC 6749
// §3.3 scope-token: non-empty printable ASCII with no space, double
// quote or backslash. It must not contain "=" or "," either, although
// RFC 6749 allows them: a scope travels in WWW-Authenticate challenges,
// where client parsers read "name=" and "," as parameter syntax
// (IsChallengeToken). None may repeat.
ScopesSupported []string `json:"scopes_supported,omitempty"`
// BearerMethods lists how a client may present a bearer token, published
// as bearer_methods_supported (RFC 9728 §2). Only "header" (the
// Authorization header, RFC 6750 §2.1) is supported. "body" (a
// form-encoded access_token parameter, RFC 6750 §2.2) is refused because
// nothing reads a form-body token, so advertising it would be false
// metadata; "query" (RFC 6750 §2.3) is refused because a token in a URL
// leaks through access logs, Referer headers and browser history.
BearerMethods []string `json:"bearer_methods_supported,omitempty"`
// MetadataPath is the well-known path of the protected-resource metadata
// document; RFC 9728 §3.1 appends the resource identifier's own path, if
// any. Empty means DefaultResourceMetadataPath
// (/.well-known/oauth-protected-resource). When set it must be a
// well-known path (RFC 8615): "/.well-known/" followed by a name, made
// only of letters, digits, ".", "_", "~", "-" and "/" (so no
// percent-escape, ";", query, fragment, wildcard or whitespace), with no
// ".." and already in path.Clean canonical form.
MetadataPath string `json:"metadata_path,omitempty"`
// RequireResourceClaim, when true, also requires an accepted token to
// name Resource in its "resource" claim, not only in "aud", so a token
// one issuer minted for another resource is refused even when the
// audiences overlap.
RequireResourceClaim bool `json:"require_resource_claim,omitempty"`
// StepUpACRValues lists authentication context class references, one of
// which an accepted token's "acr" must be; a token that carries none is
// answered with an RFC 9470 insufficient_user_authentication challenge
// naming these values. Each must be an RFC 6749 §3.3 scope-token
// (non-empty printable ASCII with no space, double quote or backslash:
// acr_values is a space-delimited list inside a quoted challenge
// parameter) with no "=" or ",", which client parsers read as parameter
// syntax (IsChallengeToken), and none may repeat.
StepUpACRValues []string `json:"step_up_acr_values,omitempty"`
// StepUpAMRValues lists authentication method references (RFC 8176), at
// least one of which an accepted token's "amr" must contain. Same
// grammar and no-repeat rule as StepUpACRValues.
StepUpAMRValues []string `json:"step_up_amr_values,omitempty"`
// AcceptedTokenTypes widens the JOSE "typ" header values an accepted
// access token may carry. Empty (the default) is the strict RFC 9068 §4
// policy: a token with no typ, or with "at+jwt" / "application/at+jwt",
// is accepted, and any other typ is refused, so an ID token, a logout
// token or a security event token from the same issuer cannot pass for
// an access token. An authorization server that labels its access tokens
// with the generic "JWT" (Keycloak, Microsoft Entra ID, Auth0's classic
// profile, Google, ThreadID) needs ["JWT"]; its access tokens are then
// told from its other tokens by aud and, with require_resource_claim,
// resource alone. Each entry is a media type (RFC 7515 §4.1.9), compared
// without regard to case and with "application/" implied when it holds
// no "/": an RFC 6838 subtype, or type "/" subtype, of letters, digits
// and "!#$&-^_.+", each part at most 127 characters, with no parameters.
// Only a JWT type is accepted, an allowlist: "jwt" itself, or a subtype
// with the "+jwt" structured suffix (RFC 8417 §2.3), each under
// "application/"; anything else ("JOSE", "application/json",
// "text/jwt") is refused. Of the "+jwt" types, one that names another
// kind of token (id_token+jwt, logout+jwt, secevent+jwt,
// token-introspection+jwt, oauth-authz-req+jwt, dpop+jwt,
// entity-statement+jwt, jwk-set+jwt) is refused too, and so is an entry
// that repeats another under any spelling ("JWT" and "application/jwt"
// are one type).
AcceptedTokenTypes []string `json:"accepted_token_types,omitempty"`
// AcceptableSkewSeconds is the clock difference, in seconds, tolerated
// between this server and an authorization server when an access token's
// exp, nbf and iat are checked. 0 (or absent) keeps the verifier's
// default of 30 seconds; at most MaxAcceptableSkewSeconds (300, five
// minutes). Negative values are refused.
AcceptableSkewSeconds int `json:"acceptable_skew_seconds,omitempty"`
// MaxRefreshIntervalSeconds is the longest, in seconds, each
// authorization server's key set goes without a background refresh,
// whatever its Cache-Control or Expires header says. 0 (or absent) keeps
// the default of 86400 (24 hours); otherwise it must be between
// MinKeyRefreshIntervalSeconds (900) and MaxKeyRefreshIntervalSeconds
// (86400): it can only tighten the default. A key the authorization
// server rotates in is picked up on first sight either way (a token
// naming an unknown kid triggers a refresh); this bounds how long a key
// it retired stays trusted.
MaxRefreshIntervalSeconds int `json:"max_refresh_interval_seconds,omitempty"`
// APIKeyCompatOnly accepts every api_key surface beside the enabled
// block as compatibility-only, outside this block's guarantees: any
// api_key leaf, single-mode or in a composite expression, on a REST or
// WebSocket route (and the GraphQL fields that authorize with such a
// route), and the MCP transports when they authenticate with the key.
// Without it, generation refuses any of them beside an enabled resource
// server. A shared HMAC key identifies a deployment, not a principal, so
// a request it authenticates carries no subject, tenant, scope, role or
// step-up assertion.
APIKeyCompatOnly bool `json:"api_key_compatibility_only,omitempty"`
// TLSClientAuth configures workload identity from verified TLS client
// certificates (mTLS, SPIFFE X.509-SVIDs).
TLSClientAuth *WorkloadAuthConfig `json:"workload_auth,omitempty"`
// TLSClientCertificateBoundAccessTokens requires every access token to
// be bound to the TLS client certificate the request presents (RFC 8705
// §3): its cnf claim must carry an x5t#S256 thumbprint equal to the
// base64url SHA-256 thumbprint of that certificate, or the token is
// refused as invalid_token. The RFC 9728 metadata document then
// advertises tls_client_certificate_bound_access_tokens: true. A token
// that carries a cnf binding is checked whether or not this is set (and
// one whose cnf names a confirmation method apic does not verify, such
// as DPoP's jkt, is refused); setting it refuses a token without one
// too. The listener must request client certificates
// (server.tls.mtls_ca_path), or no token could ever pass, and the
// block must be enabled: only the resource verifier binds a token.
TLSClientCertificateBoundAccessTokens bool `json:"tls_client_certificate_bound_access_tokens,omitempty"`
}
ResourceServerConfig is the OAuth 2.0 protected-resource posture of a generated server: the resource identifier clients request tokens for (RFC 8707), the authorization servers whose access tokens it accepts, the RFC 9728 metadata document it publishes, the RFC 6750 / RFC 9470 challenge parameters it returns, and workload identity from TLS client certificates. How a verified token's claims classify the caller is security.auth.caller_kind_rules (AuthConfig.CallerKindRules), which applies to every JWT-verified route.
Validate enforces the shape fail-closed. An absent block has no effect.
func (*ResourceServerConfig) EffectiveMetadataPath ¶ added in v0.24.0
func (rs *ResourceServerConfig) EffectiveMetadataPath() string
EffectiveMetadataPath returns MetadataPath, or DefaultResourceMetadataPath when it is empty. Nil-safe.
func (*ResourceServerConfig) On ¶ added in v0.24.0
func (rs *ResourceServerConfig) On() bool
On reports whether the resource server is configured and enabled. Nil-safe: an absent block is never on.
func (*ResourceServerConfig) Validate ¶ added in v0.24.0
func (rs *ResourceServerConfig) Validate() error
Validate reports the first way rs is malformed, wrapped in ErrInvalidResourceServer, or nil. Nil-safe: an absent block is valid.
Every member that is set is checked whether or not the block is enabled; Resource and at least one AuthorizationServers entry are required only when it is enabled. Each rule prevents a metadata document or a challenge that would mislead a client about where to get a token, and for which resource.
type RuntimeConfig ¶
type RuntimeConfig struct {
Server ServerConfig `json:"server"`
Security SecurityConfig `json:"security"`
MCP MCPConfig `json:"mcp"`
Observability ObservabilityConfig `json:"observability"`
// Health configures the control-plane health subsystem (/livez,
// /readyz, /startupz). Nil means disabled, preserving byte-for-byte
// behavior for existing configurations that predate this block.
Health *HealthConfig `json:"health,omitempty"`
// The following members are present in runtime.json (the full
// generator config) but are consumed only at generate time -- the
// runtime behaviour they describe is already baked into the generated
// handlers/types. They are declared here, accepted, and ignored so the
// strict DecodeRuntimeConfig decode of the full-config superset
// succeeds while still rejecting genuinely unknown members. The
// generator's Config type shadows each with its richly-typed
// equivalent (the same embedded-vs-outer pattern already used for
// MCP), so this raw view is used only by the runtime decoder.
// (api/websocket/schemas/graphql/shared)
API any `json:"api,omitempty"`
Websocket any `json:"websocket,omitempty"`
Schemas any `json:"schemas,omitempty"`
GraphQL any `json:"graphql,omitempty"`
// (ENG-1424); it selects whether this generation vendors its own
// pkg/ copy or imports a shared apic runtime tree. Accepted and
// ignored here for the same reason as api/websocket/schemas/graphql.
Shared any `json:"shared,omitempty"`
// Client selects which client SDKs (react_query/react_ui/python/
// rust/zig) to emit at generate time; the runtime never consults it.
// Accepted and ignored here for the same reason as
// api/websocket/schemas/graphql/shared -- without this field, any
// config declaring a top-level "client" block (11 of the 39
// configs/*.json fixtures) fails DecodeRuntimeConfig at boot with
// "unknown object member name \"client\"" even though generation
// itself succeeds cleanly.
Client any `json:"client,omitempty"`
}
RuntimeConfig is the canonical runtime config contract used by generator and server.
func DecodeRuntimeConfig ¶
func DecodeRuntimeConfig(raw []byte) (RuntimeConfig, error)
DecodeRuntimeConfig decodes the embedded runtime.json into RuntimeConfig with strict member checking. runtime.json is the FULL generator config (it also carries api/websocket/schemas/graphql so a single artifact reproduces the build); those generate-time-only members are declared as ignored fields on RuntimeConfig below so the strict decode accepts the superset while still rejecting genuinely unknown members (typo protection). Rejecting the superset previously made the generated server fail to boot ("unknown object member name \"api\"").
type SecurityConfig ¶
type SecurityConfig struct {
Auth AuthConfig `json:"auth"`
CORS CORSConfig `json:"cors"`
RateLimit RateLimitConfig `json:"rate_limit"`
Roles []string `json:"roles,omitempty"`
// FIPS, when true, requires the generated binary to operate inside
// the Go 1.27 FIPS 140-3 Cryptographic Module. The apic generator
// rejects HS256-only JWT operations under this mode (NIST 800-53
// SC-13). Hardware-backed JWT signing comes from the security.signer
// block (see Plan 04). Default false preserves backward compatibility.
FIPS bool `json:"fips,omitempty"`
// UnsafeAllowSymmetricOIDCAlg, when true, suppresses the generator
// hard-error that fires when any route in an OIDC profile (oidc_*)
// declares auth: "jwt" with a symmetric algorithm (HS* family) or
// with no jwt_alg at all (legacy HS256 default). The classic
// "OIDC capability gap" footgun — the resource-server verifier
// defaults to HS256 against an IdP that publishes a JWKS and signs
// with RS256, producing either a silent functional regression or
// (in deployments where the symmetric secret leaks) an alg-confusion
// forgery primitive. Defaults to false so the generator fails closed.
// Mirrors the OIDCRefreshTokenPolicy.UnsafeAllowStatelessJWT
// "explicit opt-in for known-unsafe configurations" pattern.
UnsafeAllowSymmetricOIDCAlg bool `json:"unsafe_allow_symmetric_oidc_alg,omitempty"`
// Signer configures the hardware- or KMS-backed crypto.Signer used
// for TLS server certs and JWT signing (Plan 04). When nil, the
// generator emits HS256 (forbidden under FIPS) or relies on the
// listener's PEM-loaded key.
Signer *SignerConfig `json:"signer,omitempty"`
// Webauthn configures the Plan 06 WebAuthn ceremony surface when any
// operation references a profileWebauthn* profile.
Webauthn *WebauthnRuntimeConfig `json:"webauthn,omitempty"`
// Audit configures the FedRAMP audit pipeline (Plan 05). Nil means
// "no audit emit"; legacy obsx.LogAudit slog records continue to
// flow unconditionally.
Audit *AuditConfig `json:"audit,omitempty"`
// Session configures AC-7 / AC-11 / AC-12 enforcement (Plan 05).
// Nil means "no session policy enforced"; the runtime falls back to
// stateless JWT semantics.
Session *SessionConfig `json:"session,omitempty"`
// Webhooks resolves named webhook secrets at boot. Keyed by the
// WebhookContract.SecretRef value the generator emits per-route.
// Entries with an empty SecretEnv are rejected by the runtime
// helper at startup (fail-closed).
Webhooks map[string]WebhookSecretRef `json:"webhooks,omitempty"`
// CSRF configures generated CSRF protection (signed double-submit,
// session-bound). Nil or Enabled=false means no CSRF enforcement.
CSRF *CSRFConfig `json:"csrf,omitempty"`
// PasswordHash configures default password-hashing policy for fields that
// declare hash:"default". Optional; when absent the generator uses the
// FIPS-aware built-in default (argon2id, or pbkdf2-sha256 under FIPS).
PasswordHash *PasswordHashConfig `json:"password_hash,omitempty"`
// Headers configures per-deployment overrides for the SEC-0023 hardened
// response-header set that httpx applies by default
// (Content-Security-Policy, Cross-Origin-Opener/Embedder/Resource-Policy,
// Permissions-Policy). Nil (the default) applies the httpx secure
// defaults unmodified -- a pure-JSON API gets `default-src 'none'`. A
// browser-facing service (an HTML SPA's same-origin API) sets this block
// to publish a working CSP instead of being stuck on the hardened
// default. GENERATOR_BUGS.md L-35.
Headers *HeadersConfig `json:"headers,omitempty"`
// ResourceServer configures this server's OAuth 2.0 protected-resource
// posture (RFC 9728): the resource identifier clients must request tokens
// for, the authorization servers it trusts, the metadata document it
// publishes, and the 401 challenge it returns. Nil (the default) or
// disabled means no protected-resource posture. See ResourceServerConfig.
ResourceServer *ResourceServerConfig `json:"resource_server,omitempty"`
}
SecurityConfig defines top-level security options.
func (*SecurityConfig) ValidateCallerKindRules ¶ added in v0.24.0
func (s *SecurityConfig) ValidateCallerKindRules() error
ValidateCallerKindRules reports the first way security.auth.caller_kind_rules is malformed, wrapped in ErrInvalidCallerKindRules, or nil. Nil-safe.
It refuses more than MaxCallerKindRules rules; a rule with an empty or malformed claim, an unknown match, an empty value, a claim compared with itself or client_id compared with azp, or a kind that is not a rule target; a human rule that reads client_id or azp (a client names itself); a rule an earlier rule shadows (see shadows); and a rule that would classify every accepted token, because under some verifier's pins it matches every combination of pinned values (see callerKindPinSets). When nothing is pinned that last check is skipped, and every other check still applies.
type ServerConfig ¶
type ServerConfig struct {
Bind string `json:"bind"`
TLS TLSConfig `json:"tls"`
Timeouts TimeoutConfig `json:"timeouts"`
Limits LimitConfig `json:"limits"`
// HTTP2 controls HTTP/2 (h2) negotiation on the primary TLS listener.
// Omitted means enabled with DefaultHTTP2MaxConcurrentStreams.
HTTP2 HTTP2Config `json:"http2,omitempty"`
EnableCompression bool `json:"enable_compression,omitempty"`
// ResponseBufferBytes caps, in bytes, how large a JSON response body may
// be while still getting pooled-buffer + Content-Length framing from the
// generated REST response writer. Zero (the default) resolves to
// DefaultResponseBufferBytes (64 KiB) via EffectiveResponseBufferBytes.
// A response body larger than the effective limit falls back to a
// direct write with no Content-Length (chunked Transfer-Encoding),
// exactly as every response was framed before PERF-0074. Must be >= 0;
// generation rejects a negative value and, when server.limits.max_body_bytes
// is set (>0), a value exceeding it -- a response-buffer cap larger than
// the request-body cap is virtually always a misconfiguration. PERF-0074
// (#247).
ResponseBufferBytes int64 `json:"response_buffer_bytes,omitempty"`
// SpecHashHeader controls whether the generated server advertises the
// deterministic spec-identity hash of the config it was generated from
// as the X-Apic-Spec-Hash response header. Absent (nil) means enabled —
// advertising is the default. Set false to suppress the header; the hash
// remains available on the public /api-spec.json document (the
// "x-apic-spec-hash" member) and in every generated client's embedded
// constant either way. GAP-0121 (#259).
SpecHashHeader *bool `json:"spec_hash_header,omitempty"`
}
ServerConfig defines runtime server bind/tls/timeout/limit settings.
EnableCompression turns on transparent gzip of text-ish JSON responses (>=1 KiB, client must send Accept-Encoding: gzip). It is off unless the config opts in so the wire shape stays byte-identical for callers that have not requested it.
func (ServerConfig) EffectiveResponseBufferBytes ¶ added in v0.18.3
func (s ServerConfig) EffectiveResponseBufferBytes() int64
EffectiveResponseBufferBytes returns the configured response-buffer limit, defaulting to DefaultResponseBufferBytes when ResponseBufferBytes is zero (unset). Callers needing a validated value should validate ResponseBufferBytes >= 0 first (the generator's validateResponseBufferBytes does this at generation time); this helper does not re-validate.
func (ServerConfig) SpecHashHeaderEnabled ¶ added in v0.18.3
func (s ServerConfig) SpecHashHeaderEnabled() bool
SpecHashHeaderEnabled reports whether the generated server should set the X-Apic-Spec-Hash response header. Absent (nil) means enabled, so a config written before the knob existed keeps advertising by default.
type SessionConfig ¶
type SessionConfig struct {
MaxFailures int `json:"max_failures,omitempty"` // AC-7
LockoutDurationSeconds int `json:"lockout_duration_seconds,omitempty"` // AC-7
InactivitySeconds int `json:"inactivity_seconds,omitempty"` // AC-11
AbsoluteLifetimeSeconds int `json:"absolute_lifetime_seconds,omitempty"` // AC-12
}
SessionConfig configures AC-7 / AC-11 / AC-12 enforcement (Plan 05).
type SignerConfig ¶
type SignerConfig struct {
// Backend is the registered backend name (e.g. "softfile", "pkcs11",
// "awskms", "azurekv"). Each backend lives behind its own build tag
// in pkg/securex/signerx/<backend>.
Backend string `json:"backend"`
// Config is the raw backend-specific config blob (path, region,
// vault_url, library_path, etc.).
Config map[string]any `json:"config,omitempty"`
// Keys are the keys this binary will open. Each entry pairs a
// signerx.KeyRef.ID with a "use" tag ("tls", "jwt", "client-assertion").
Keys []SignerKey `json:"keys,omitempty"`
}
SignerConfig configures a hardware-/KMS-backed crypto.Signer.
type SignerKey ¶
type SignerKey struct {
ID string `json:"id"`
Use string `json:"use,omitempty"` // "tls" | "jwt" | "client-assertion"
Alg string `json:"alg,omitempty"` // "RS256" | "ES256" | "PS256"
// PINEnv names the env var the PKCS#11 PIN is read from at boot
// (e.g. "APIC_HSM_PIN"). SEC-0032: production-safe path that keeps
// the secret out of config files. When set it takes precedence over
// PIN and a literal PIN alongside it is rejected.
PINEnv string `json:"pin_env,omitempty"`
// PIN is a literal PKCS#11 PIN. SEC-0032: accepted only for local
// dev/test; ResolvePIN rejects it when strict (FIPS/prod) is requested.
PIN string `json:"pin,omitempty"`
}
SignerKey binds one backend key to a runtime role.
func (SignerKey) ResolvePIN ¶
ResolvePIN returns the PKCS#11 PIN, preferring the PINEnv env-var indirection over a literal PIN (SEC-0032). When strict is true (FIPS or production posture) a literal PIN is refused fail-closed; a PINEnv naming an unset/empty var is also an error so misconfiguration cannot silently fall through to an empty PIN.
type TLSConfig ¶
type TLSConfig struct {
CertPath string `json:"cert_path"`
KeyPath string `json:"key_path"`
// Mode is the listener TLS mode. The empty string (default) means TLS
// is required: the generated server refuses to boot without a cert.
// "off" is the EXPLICIT opt-in to serve plain HTTP for deployments that
// terminate TLS upstream (ingress/mesh); it is the config-driven
// equivalent of server.WithInsecureHTTP(). Any other value is treated
// as TLS-required (secure by default).
Mode string `json:"mode,omitempty"`
MTLSCAPath *string `json:"mtls_ca_path"`
}
TLSConfig defines TLS paths and optional mTLS CA bundle.
type TimeoutConfig ¶
type TimeoutConfig struct {
ReadHeaderMS int `json:"read_header_ms"`
ReadMS int `json:"read_ms"`
WriteMS int `json:"write_ms"`
IdleMS int `json:"idle_ms"`
}
TimeoutConfig defines HTTP server timeout values in milliseconds.
func (*TimeoutConfig) ApplyDefaults ¶
func (t *TimeoutConfig) ApplyDefaults()
ApplyDefaults fills non-positive timeout members with the package defaults (PERF-0073). Explicit positive values are preserved.
type TracingBlockConfig ¶ added in v0.15.0
type TracingBlockConfig struct {
// Enabled: nil = on by default; explicit false disables W3C
// trace-context propagation only (traceparent/tracestate header
// parsing/forwarding, see PropagationOn). The correlation-ID
// middleware is always-on by design and does not honor this flag — a
// correlation id is minted/echoed on every request regardless of
// Enabled.
Enabled *bool `json:"enabled,omitempty"`
// CorrelationHeader names the operator-controlled log/header token,
// validated against the correlation grammar at generation time. Empty
// defaults to "X-Correlation-ID".
CorrelationHeader string `json:"correlation_header,omitempty"`
// LogTraceIDs: nil or true = thread trace_id/span_id into request
// logs; explicit false omits them. Gates trace_id/span_id only:
// correlation_id is emitted unconditionally whenever the request
// carries one, independent of this flag.
LogTraceIDs *bool `json:"log_trace_ids,omitempty"`
}
TracingBlockConfig configures the correlation-ID surface: the header propagated end-to-end between services and whether trace/span IDs are threaded into request logs.
func (TracingBlockConfig) EffectiveHeader ¶ added in v0.15.0
func (t TracingBlockConfig) EffectiveHeader() string
EffectiveHeader returns the correlation header name (default X-Correlation-ID).
func (*TracingBlockConfig) Get ¶ added in v0.15.0
func (t *TracingBlockConfig) Get() TracingBlockConfig
Get is nil-safe: an unconfigured block yields the zero value.
func (TracingBlockConfig) LogTraceIDsOn ¶ added in v0.15.0
func (t TracingBlockConfig) LogTraceIDsOn() bool
LogTraceIDsOn reports whether trace/span IDs are threaded into request logs (nil or true = on; explicit false = off).
func (TracingBlockConfig) PropagationOn ¶ added in v0.15.0
func (t TracingBlockConfig) PropagationOn() bool
PropagationOn reports whether correlation-ID propagation is active (nil or true = on; explicit false = off).
type WebauthnRuntimeConfig ¶
type WebauthnRuntimeConfig struct {
RPID string `json:"rp_id"`
RPDisplayName string `json:"rp_display_name"`
Origins []string `json:"origins"`
AAGUIDAllowList []string `json:"aaguid_allow_list,omitempty"` // hex strings
AttestationPreference string `json:"attestation_preference,omitempty"`
UserVerification string `json:"user_verification,omitempty"`
RequireResidentKey bool `json:"require_resident_key,omitempty"`
// AttestationRootsPath is the filesystem path to a PEM bundle of
// trusted attestation root certificates, loaded at server boot
// (mirroring server.tls.mtls_ca_path) and passed through to
// webauthnx.Config.AttestationRoots. REQUIRED whenever
// AAGUIDAllowList is non-empty (R10-2 / APPSEC-14): an allow-list
// with no trust anchor to verify attestation chains against cannot
// distinguish a genuinely vendor-attested authenticator from a
// trivially self-signed forgery, and webauthnx.NewServer refuses to
// boot in that combination. Populate from your accepted FIDO vendor
// attestation root certificates. See docs/WEBAUTHN_MODE.md.
AttestationRootsPath string `json:"attestation_roots_path,omitempty"`
}
WebauthnRuntimeConfig configures the apic WebAuthn surface (Plan 06).
type WebhookSecretRef ¶
type WebhookSecretRef struct {
// SecretEnv is the env var name (e.g. "APIC_WEBHOOK_STRIPE_SECRET")
// the runtime reads. Required; the boot helper refuses to start
// with an empty value when any route references this entry.
SecretEnv string `json:"secret_env"`
// SecretFileEnv is an optional env var pointing at a file path
// the runtime reads instead of taking the secret from an env var
// directly. Use for FIPS / k8s-secrets-volume deployments where
// the secret must live on disk under operator-controlled ACLs.
// When both SecretEnv and SecretFileEnv are set the file wins.
SecretFileEnv string `json:"secret_file_env,omitempty"`
}
WebhookSecretRef configures one inbound-webhook secret source. The runtime resolves SecretEnv at boot to fetch the HMAC key the per-route VerifyWebhook call uses. Mirrors SignerKey's env-var-named-by-operator pattern.
type WorkloadAuthConfig ¶ added in v0.24.0
type WorkloadAuthConfig struct {
// Enabled is the master switch. It needs the resource server enabled
// too, since workload identity is part of it. When enabled, TrustDomains
// or AllowedSPIFFEIDs must constrain which peers are accepted: without
// either, any client certificate the TLS layer accepts would become a
// workload principal.
Enabled bool `json:"enabled,omitempty"`
// TrustDomains lists the SPIFFE trust domains (for example
// "example.org") whose workloads are accepted. Each must be a SPIFFE
// trust domain name (ValidateTrustDomain): lowercase letters, digits,
// ".", "-" and "_", with no empty "."-separated label.
TrustDomains []string `json:"trust_domains,omitempty"`
// AllowedSPIFFEIDs lists the exact SPIFFE IDs
// (spiffe://<trust-domain>[/<path>]) whose workloads are accepted. Each
// must follow the SPIFFE ID specification (ParseSPIFFEID): no trailing
// "/", no empty, "." or ".." path segment, and no percent-escape. Each
// must also carry a path: a bare spiffe://<trust-domain> names the trust
// domain, never a workload, so list it in TrustDomains instead.
AllowedSPIFFEIDs []string `json:"allowed_spiffe_ids,omitempty"`
// SubjectFrom selects the certificate field the workload subject is read
// from: "spiffe" (the SPIFFE ID URI SAN), "cn" (the subject common name),
// "upn" (the UPN otherName SAN) or "san_uri" (the first URI SAN). Empty
// selects "spiffe". The trust constraint (TrustDomains,
// AllowedSPIFFEIDs) always applies to the certificate's SPIFFE ID, which
// it must carry as its one URI SAN whatever this selects: "cn" and "upn"
// name a field the constraint does not cover, read from a certificate
// whose SPIFFE ID passed it, so two workloads of one trusted trust
// domain can share that subject. Authorize on the SPIFFE ID when that
// matters.
SubjectFrom string `json:"subject_from,omitempty"`
// TrustBundles maps a SPIFFE trust domain to the path of the PEM CA
// bundle its workloads' certificates must chain to (SPIFFE Trust Domain
// and Bundle §4): a workload is accepted only when its certificate
// chains to the bundle of its SPIFFE ID's OWN trust domain, so a CA of
// one trust domain cannot assert another's workloads. Each key must be a
// trust domain the block accepts (AcceptedTrustDomains: one of
// TrustDomains, or the trust domain of an AllowedSPIFFEIDs entry), and
// each value a non-empty path without leading or trailing whitespace.
// With more than one accepted trust domain, every one of them needs an
// entry. With exactly one and no entry, its bundle is the listener's
// client CA pool (server.tls.mtls_ca_path): every CA in that file can
// then assert the trust domain, and generation warns. The listener
// still verifies every client certificate against
// server.tls.mtls_ca_path first, so each bundle's CAs (or the CAs that
// issued them) must be in that file too.
TrustBundles map[string]string `json:"trust_bundles,omitempty"`
}
WorkloadAuthConfig configures workload identity derived from a verified TLS client certificate.
func (*WorkloadAuthConfig) AcceptedTrustDomains ¶ added in v0.24.0
func (w *WorkloadAuthConfig) AcceptedTrustDomains() []string
AcceptedTrustDomains returns the SPIFFE trust domains whose workloads w can accept, sorted and without repeats: every TrustDomains entry and the trust domain of every AllowedSPIFFEIDs entry (a malformed entry, which Validate refuses, is skipped). Nil-safe.
func (*WorkloadAuthConfig) Validate ¶ added in v0.24.0
func (w *WorkloadAuthConfig) Validate() error
Validate reports the first way w is malformed, wrapped in ErrInvalidResourceServer, or nil. Nil-safe: an absent block is valid. Every member that is set is checked whether or not the block is enabled; the TrustDomains-or-AllowedSPIFFEIDs constraint applies when it is enabled. Trust domains and SPIFFE IDs are checked by ValidateTrustDomain and ParseSPIFFEID, whose errors are wrapped too.