hub

package
v0.2.14 Latest Latest
Warning

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

Go to latest
Published: Oct 10, 2026 License: Apache-2.0 Imports: 73 Imported by: 0

Documentation

Overview

Package hub implements the railgrid hub server.

Index

Constants

This section is empty.

Variables

View Source
var ErrAnonymousProviderCaller = errors.New("anonymous caller")

ErrAnonymousProviderCaller is returned by the tenant resolver when the caller carries no bearer token. The backend proxy treats this as a non-error "forward without identity headers" so unauthenticated probes (health checks, smoke tests) work without provider auth.

Functions

func NewScheme

func NewScheme() *runtime.Scheme

NewScheme builds a runtime.Scheme containing all types needed by the multicluster manager: core k8s types, railgrid CRDs, tenancy CRDs, and the kcp SDK types required by multicluster-provider internals.

func WithPortalSecurityHeaders

func WithPortalSecurityHeaders(next http.Handler, frameSources ...string) http.Handler

WithPortalSecurityHeaders wraps a portal handler to set the portal's Content-Security-Policy and related headers.

Provider micro-frontends are not iframes. The portal loads each provider's /ui/providers/{name}/main.js (hub-proxied, so same-origin) as a classic script and mounts the custom element it registers directly in the portal document. A provider bundle therefore executes as fully trusted code in the host document; `script-src 'self'` admits it because it is same-origin, and the portal pins it with the Subresource Integrity hash the hub computed at registration (CatalogEntry status.ui.mainJSIntegrity). There is no 'unsafe-inline' for scripts: the portal ships no inline script (the theme pre-paint bootstrap is a static file), so an injected inline handler or <script> is refused by the browser.

frame-src still lists 'self' plus optional platform-owned sources (App Studio preview hosts): those are the portal's own iframes, not provider bundles.

Applied to both the embedded portal SPA and the --portal-dev-url proxy so the dev experience matches production.

Types

type Options

type Options struct {
	DataDir               string
	ListenAddr            string
	Kubeconfig            string
	ExternalKCPKubeconfig string
	IDPIssuerURL          string
	// IDPBrowserAuthURL optionally overrides only the OIDC authorization
	// endpoint placed in browser redirects. Discovery, token exchange, JWKS,
	// and issuer validation continue to use IDPIssuerURL.
	IDPBrowserAuthURL string
	IDPClientID       string
	// DisableTokenLogin removes the interactive static-token login: the
	// /auth/token-login endpoint is not registered and /healthz advertises
	// tokenLogin=false so the portal hides its token form. Static bearer
	// tokens keep authenticating API/MCP/CLI calls — only the browser login
	// path is disabled. Use with OIDC so humans sign in with a username and
	// password at the IdP.
	DisableTokenLogin bool
	// PublishedAppsDomain is deprecated and ignored. The published-app
	// authorize/exchange endpoints are always mounted, and sign-in redirects
	// are pinned per request to the host stamped on the instance being
	// authorized — so apps under BYO provider zones and customer-owned
	// domains need no hub-side domain configuration. The flag is kept only
	// so existing deployments that pass it keep starting.
	PublishedAppsDomain string
	// IDPCAFile is a path to a PEM-encoded CA bundle used to verify the IdP's
	// TLS certificate. Required when IDPIssuerURL is https and uses a cert
	// not signed by a system trust anchor (e.g. the dev Dex deployment).
	IDPCAFile       string
	ServingCertFile string
	ServingKeyFile  string
	HubExternalURL  string
	// HubInternalURL, when set, is the address in-cluster components use to
	// reach this hub instead of HubExternalURL. It is baked into minted provider
	// kubeconfigs and offered as the "internal" option by the admin kubeconfig
	// download.
	//
	// Without it, a provider pod's calls to the hub resolve the public hostname,
	// leave the cluster, and re-enter through whatever fronts it (CDN, tunnel,
	// load balancer) — for a provider running beside the hub that is a pointless
	// round trip that also makes the whole platform look like one noisy client
	// IP to the edge.
	//
	// Typically the hub's in-cluster Service
	// (https://<release>-railgrid-hub.<namespace>.svc.cluster.local:9443). Also
	// useful when provider pods reach the hub at a different address than
	// browsers do — e.g. a kind pod dialing https://host.docker.internal:9443
	// while browsers use https://localhost:9443. Leave empty when providers run
	// outside the cluster.
	HubInternalURL   string
	DevMode          bool
	StaticAuthTokens []string

	// TrustedProxyCIDRs lists the address ranges of the reverse proxies that
	// front this hub (ingress controller, load balancer, CDN egress). The
	// pre-authentication rate limiters (token-login, /auth/refresh, the
	// published-app code exchange, the aggregate MCP bearer check) key their
	// buckets on the client address, and a proxy's X-Forwarded-For is only
	// believed when the connection peer is inside one of these ranges — see
	// proxy.ClientIP for the exact rule.
	//
	// Empty (the default) means proxy headers are ignored and every request is
	// keyed on its connection peer. A hub deployed behind a proxy without this
	// set therefore sees all of its clients as the proxy's own address and
	// throttles them as one; that is the safe failure, so set it. Never widen
	// it to ranges clients can connect from: any peer inside it can pick its
	// own bucket by sending X-Forwarded-For.
	TrustedProxyCIDRs []string

	// ProviderDelegatedTokens selects which providers receive a short-lived,
	// workspace-scoped ServiceAccount token in place of the caller's own hub
	// bearer on the backend proxy (/services/providers/{name}/*). Org-owned
	// providers always receive the delegated token regardless of this
	// setting; it governs platform providers only:
	//
	//   off      — platform providers receive the caller's bearer as-is
	//              (the historical behaviour).
	//   platform — platform providers receive the delegated token, except
	//              the names in ProviderDelegatedTokensExclude.
	//   all      — every platform provider receives the delegated token;
	//              the exclusion list is ignored.
	//
	// Default "off" for this release. The next release defaults to
	// "platform"; deployments should run "platform" ahead of that to
	// confirm their providers need nothing beyond /clusters/{id} access.
	ProviderDelegatedTokens string
	// ProviderDelegatedTokensExclude names platform providers that keep
	// receiving the caller's bearer under ProviderDelegatedTokens=platform.
	// Defaults to providers.DefaultDelegationExclude.
	ProviderDelegatedTokensExclude []string

	// ProviderHubAccessPlatformDefault lets a platform provider use the hub
	// capabilities it declares (CatalogEntry.spec.hub.access) in a workspace
	// where no tenant decision was recorded yet. Platform providers are
	// operator-installed and, under ProviderDelegatedTokens=off, hold the
	// caller's own bearer anyway; this keeps them working across the upgrade
	// to the hub-access contract. An explicit decision (Enable with or
	// without accepting) always wins, and org-owned providers always need
	// one. Set false to require acceptance for every provider.
	ProviderHubAccessPlatformDefault bool

	// AdminUsers is the allowlist of platform-admin identities permitted to
	// reach the /api/admin/* surface and the portal's /bonkers area. Each entry
	// matches a User CR by name, email, or rbacIdentity (case-insensitive).
	// Empty disables the admin surface entirely.
	AdminUsers []string

	// Providers is the list of first-party builtin providers to materialize
	// into root:railgrid:providers at bootstrap. The flag accepts a comma-
	// separated list or repeats; see cmd/railgrid-hub/main.go for the default.
	// Empty/nil enables every known builtin (kcp.BuiltinProviderNames()).
	// Dependencies between builtins are validated at hub startup — see
	// pkg/hub/kcp.builtinEntries[].Requires.
	Providers []string

	// ProviderHeartbeatAuth is what the hub does with a provider heartbeat
	// whose bearer token does not verify as that provider's own service
	// account: "warn" logs and records the beat, "enforce" rejects it. The
	// default is "warn" for this release so providers installed from charts
	// that predate the authenticated heartbeat keep reporting alive while
	// they are rolled forward; the next release flips the default to
	// "enforce". See providers.HeartbeatAuthMode.
	ProviderHeartbeatAuth string
	// ProviderWorkspaceClusterAdmin selects the role the provider ServiceAccount
	// is bound to inside its own provider workspace: true (the default this
	// release) keeps cluster-admin, false binds the generated, narrower
	// railgrid:provider ClusterRole.
	//
	// The default is the wide one for one release so an operator can stage the
	// change — flip it, watch their providers, flip back if one of them needed
	// a right the narrow role does not grant (the infrastructure provider, which
	// serves its own CRDs from this workspace, is the known case). The NEXT
	// release defaults this to false. Flipping either way replaces the existing
	// binding: RoleRef is immutable, so the hub deletes and recreates it.
	ProviderWorkspaceClusterAdmin bool

	// PortalDevURL, when set, reverse-proxies /ui/* to this URL (typically
	// a Vite dev server, e.g. http://localhost:3000). Takes precedence over the
	// embedded portal dist (if built with -tags portal_embed).
	PortalDevURL string
	// PortalFrameSources are additional CSP frame-src source expressions allowed
	// by the portal. Keep this narrow; provider UIs are still same-origin through
	// the hub, while platform-owned preview hosts can be added explicitly.
	PortalFrameSources []string

	// Embedded kcp options
	EmbeddedKCP         bool   // Enable embedded kcp server
	KCPRootDir          string // Root directory for kcp data (default: <DataDir>/kcp)
	KCPSecurePort       int    // Secure port for kcp API server (default: 6443)
	KCPBindAddress      string // Bind address for kcp API server (default: "127.0.0.1")
	KCPBatteriesInclude string // Comma-separated list of batteries to include (default: "admin,user")
	KCPTLSCertFile      string // TLS certificate file for kcp API server
	KCPTLSKeyFile       string // TLS key file for kcp API server
	// KCPShardExternalURL is the URL kcp publishes into APIExportEndpointSlice
	// and CachedResourceEndpointSlice statuses for outside consumers to dial.
	// Empty defaults to kcp's auto-detected external address, which for an
	// embedded kcp bound to 127.0.0.1 is "https://127.0.0.1:6443" — fine for
	// host-side clients, broken for clients running in a kind pod (they
	// resolve 127.0.0.1 to the pod itself). Override with e.g.
	// "https://host.docker.internal:6443" for kind-based dev setups.
	KCPShardExternalURL string
	// KCPShardVirtualWorkspaceURL must be set alongside KCPShardExternalURL.
	// The two URLs cover different slots in Shard.spec — externalURL feeds
	// generic outside-clients discovery, virtualWorkspaceURL is what
	// APIExportEndpointSlice / CachedResourceEndpointSlice publish in their
	// status.endpoints[]. For a single-shard embedded dev setup both want
	// the same value.
	KCPShardVirtualWorkspaceURL string
}

Options holds configuration for the hub server.

func NewOptions

func NewOptions() *Options

NewOptions returns default Options.

type Server

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

Server is the railgrid hub server orchestrator.

func NewServer

func NewServer(opts *Options) (*Server, error)

NewServer creates a new hub server.

func (*Server) Run

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

Run starts the hub server and blocks until the context is cancelled.

Directories

Path Synopsis
Package actionproof signs the human and tenant context of a kcp custom subresource request so a provider can make a narrowly authorized hub REST call without forwarding the caller's bearer token.
Package actionproof signs the human and tenant context of a kcp custom subresource request so a provider can make a narrowly authorized hub REST call without forwarding the caller's bearer token.
Package admin implements the platform-admin surface mounted at /api/admin/* and surfaced in the portal's gated /bonkers area.
Package admin implements the platform-admin surface mounted at /api/admin/* and surfaced in the portal's gated /bonkers area.
Package appauth is the hub's login-time authorization endpoint for published applications.
Package appauth is the hub's login-time authorization endpoint for published applications.
Package bootstrap embeds bootstrap resources for hub initialization.
Package bootstrap embeds bootstrap resources for hub initialization.
controllers
mcpserver
Package mcpserver reconciles MCPServer objects.
Package mcpserver reconciles MCPServer objects.
membershipindex
Package membershipindex implements the UMI invariant reconciler: a controller that watches UserMembershipIndex CRs in root:railgrid:users and repairs rows that strand a user.
Package membershipindex implements the UMI invariant reconciler: a controller that watches UserMembershipIndex CRs in root:railgrid:users and repairs rows that strand a user.
organization
Package organization gives every new organization the same bootstrap lifecycle.
Package organization gives every new organization the same bootstrap lifecycle.
softdelete
Package softdelete implements roadmap step 8: the soft-delete reconciler that honours the 30-day grace window from docs/organizations.md decisions O-8 (User delete) and O-13 (Org + Workspace delete).
Package softdelete implements roadmap step 8: the soft-delete reconciler that honours the 30-day grace window from docs/organizations.md decisions O-8 (User delete) and O-13 (Org + Workspace delete).
Package hubaccess implements the hub-access half of the provider contract: the hub REST capabilities a provider may exercise with an admitted caller context, supplied either by a delegated user token or a short-lived action proof minted at the authenticated kcp front door.
Package hubaccess implements the hub-access half of the provider contract: the hub REST capabilities a provider may exercise with an admitted caller context, supplied either by a delegated user token or a short-lived action proof minted at the authenticated kcp front door.
Package identity is the hub's scoped-identity service: the one place a runtime credential for a tenant object is created.
Package identity is the hub's scoped-identity service: the one place a runtime credential for a tenant object is created.
Package kcp bootstraps kcp API resources.
Package kcp bootstraps kcp API resources.
Package leaderelection gates the hub's singleton controllers so a hub scaled to multiple replicas still reconciles each object exactly once.
Package leaderelection gates the hub's singleton controllers so a hub scaled to multiple replicas still reconciles each object exactly once.
Package mcpaggregate serves the hub's always-on aggregate MCP endpoint.
Package mcpaggregate serves the hub's always-on aggregate MCP endpoint.
Package providers backs the hub's pluggable-provider extension surface: an in-memory routing table, reverse proxies for /ui/providers/{name}/* and /services/providers/{name}/*, and the controller that keeps the table in sync with ProviderCatalogEntry resources.
Package providers backs the hub's pluggable-provider extension surface: an in-memory routing table, reverse proxies for /ui/providers/{name}/* and /services/providers/{name}/*, and the controller that keeps the table in sync with ProviderCatalogEntry resources.
Package quota implements the quota checks pinned by decisions O-5 (Org quota = soft cap, admin-overridable per User; default 10) and O-6 (Workspace quota = soft cap, admin-overridable per Org; default 50) in docs/organizations.md.
Package quota implements the quota checks pinned by decisions O-5 (Org quota = soft cap, admin-overridable per User; default 10) and O-6 (Workspace quota = soft cap, admin-overridable per Org; default 50) in docs/organizations.md.
Package restapi implements roadmap step 10: the hub-mediated REST surface for Org / Workspace / Membership / User CRUD per docs/organizations.md decision O-10 ("Org workspaces are hub-mediated only"), plus the undelete actions wired to PR #212's soft-delete reconciler, the self-leave / role PATCH from O-12, and the ?cascade=true shortcut from O-9.
Package restapi implements roadmap step 10: the hub-mediated REST surface for Org / Workspace / Membership / User CRUD per docs/organizations.md decision O-10 ("Org workspaces are hub-mediated only"), plus the undelete actions wired to PR #212's soft-delete reconciler, the self-leave / role PATCH from O-12, and the ?cascade=true shortcut from O-9.
Package serviceaccounts implements roadmap step 9 (O-14): bot identity for child Workspaces via native kube `core/v1.ServiceAccount`s marked with railgrid annotations.
Package serviceaccounts implements roadmap step 9 (O-14): bot identity for child Workspaces via native kube `core/v1.ServiceAccount`s marked with railgrid annotations.
Package sharedstore is the hub's cross-replica key/value store for short-lived login state: browser sessions and published-app authorization codes.
Package sharedstore is the hub's cross-replica key/value store for short-lived login state: browser sessions and published-app authorization codes.
Package tenant implements the hub-side tenant middleware described in docs/organizations.md §Switch the active context.
Package tenant implements the hub-side tenant middleware described in docs/organizations.md §Switch the active context.
Package workloadidentity owns the production provider-action workload capability exchange.
Package workloadidentity owns the production provider-action workload capability exchange.

Jump to

Keyboard shortcuts

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