accessgate

package
v0.55.15 Latest Latest
Warning

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

Go to latest
Published: Nov 4, 2026 License: Apache-2.0 Imports: 13 Imported by: 0

Documentation

Overview

Package accessgate is the StackKits Access Gate (homelab identity target §7): the forward-auth decision every server runs in front of TinyAuth and, on the remote listener, in front of every route including endpoints with native authentication.

The listener class is fixed by the router, never by the request: the LAN router calls the gate at /v1/gate/lan from its forward-auth middleware, the remote router binds /v1/gate/remote to its only entrypoint. A request through the remote listener is never treated as home, forwarded headers do not change that, and TinyAuth's parent-domain cookie is never consulted there. The route table contract lives in internal/accessgatetable.

Index

Constants

View Source
const (
	// LaunchPath is reserved on every gated host for the launch exchange.
	LaunchPath = "/.well-known/stackkit/launch"
	// SessionCookie is the gate's per-host browser session.
	SessionCookie = "__Host-stackkit-session"
	// LaunchStateCookie binds a launch to the browser the gate sent to the Hub.
	LaunchStateCookie = "__Host-stackkit-launch"
)

Browser sessions and app passes (homelab identity target §6.3, §12). A browser carries no per-request proof: the gate sends a navigation without a session to the Hub with a fresh launch state, the Hub signs a 60 second launch proof with the device key, and the gate exchanges it at LaunchPath on the same host for a host-only session cookie recorded against the device. A third-party app sends its per-device app pass in HeaderAppPass on the routes the Owner opened to apps away.

View Source
const (
	PathLAN    = "/v1/gate/lan"
	PathRemote = "/v1/gate/remote"
)

Gate paths. The LAN router's forward-auth middleware calls PathLAN; the remote router binds PathRemote to its only entrypoint.

View Source
const (
	RoutesSchema = accessgatetable.RoutesSchema

	ListenerLAN    = accessgatetable.ListenerLAN
	ListenerRemote = accessgatetable.ListenerRemote

	ExposureLocalOnly     = accessgatetable.ExposureLocalOnly
	ExposureRemotePrivate = accessgatetable.ExposureRemotePrivate
	ExposurePublic        = accessgatetable.ExposurePublic

	AuthenticationNone        = accessgatetable.AuthenticationNone
	AuthenticationHuman       = accessgatetable.AuthenticationHuman
	AuthenticationHumanDevice = accessgatetable.AuthenticationHumanDevice
	AuthenticationAgent       = accessgatetable.AuthenticationAgent
	AuthenticationWorkload    = accessgatetable.AuthenticationWorkload

	PrivilegeUser     = accessgatetable.PrivilegeUser
	PrivilegeSignIn   = accessgatetable.PrivilegeSignIn
	PrivilegeAdmin    = accessgatetable.PrivilegeAdmin
	PrivilegeIdentity = accessgatetable.PrivilegeIdentity
	PrivilegeSecrets  = accessgatetable.PrivilegeSecrets
	PrivilegeVault    = accessgatetable.PrivilegeVault
	PrivilegeRecovery = accessgatetable.PrivilegeRecovery

	IngressForwardAuth = accessgatetable.IngressForwardAuth
	IngressNative      = accessgatetable.IngressNative
	IngressNone        = accessgatetable.IngressNone

	IdentityAdministrationPocketID = accessgatetable.IdentityAdministrationPocketID

	HeaderListener      = accessgatetable.HeaderListener
	HeaderSubject       = accessgatetable.HeaderSubject
	HeaderDevice        = accessgatetable.HeaderDevice
	HeaderAuthorization = accessgatetable.HeaderAuthorization
	HeaderDPoP          = accessgatetable.HeaderDPoP
	HeaderAgentEnvelope = accessgatetable.HeaderAgentEnvelope
	// HeaderAppPass carries an app pass; the router strips it before the backend.
	HeaderAppPass = accessgatetable.HeaderAppPass
)

Variables

View Source
var (
	// LANBoundPrivileges stay on the LAN listener unless the Owner opts in.
	LANBoundPrivileges = accessgatetable.LANBoundPrivileges
	// ResponseHeaders is the exact authResponseHeaders list of both gate
	// middlewares.
	ResponseHeaders = accessgatetable.ResponseHeaders
	// ErrInvalidTable rejects a table the gate cannot enforce exactly.
	ErrInvalidTable = accessgatetable.ErrInvalidTable
)
View Source
var ErrNoPinnedGatewayKey = errors.New("accessgate: no Gateway key is pinned at linking")

ErrNoPinnedGatewayKey is the agent class's fail-closed state: no linking step pins a Gateway key on this server yet.

Functions

This section is empty.

Types

type AgentEnvelopeVerifier

type AgentEnvelopeVerifier interface {
	VerifyAgentEnvelope(ctx context.Context, request AgentRequest) (Principal, error)
}

AgentEnvelopeVerifier verifies a Gateway-signed envelope (subject, agent instance, lease, body hash) against the Gateway key pinned at linking and maps it to the Homelab account it acts for (igti.12).

type AgentRequest

type AgentRequest struct {
	Method   string
	Target   string
	Envelope string
}

AgentRequest is what the gate can bind an agent envelope to. Forward-auth carries no body, so the body hash is verified by the endpoint.

type AppPassVerifier

type AppPassVerifier interface {
	VerifyAppPass(ctx context.Context, host, pass string) (Principal, error)
}

AppPassVerifier verifies an app pass for one host.

type BrowserLauncher

type BrowserLauncher interface {
	// LaunchURL is the Hub page a browser without a session is sent to.
	LaunchURL(target, state string) (string, error)
	// CompleteLaunch admits a launch proof and returns the session value and
	// its lifetime: four hours when the launch came through the LAN
	// listener (Home), one hour otherwise.
	CompleteLaunch(ctx context.Context, launch LaunchRequest) (string, time.Duration, error)
}

BrowserLauncher is the gate's seam to the Hub launch (internal/identity).

type BrowserSessionVerifier

type BrowserSessionVerifier interface {
	VerifyBrowserSession(ctx context.Context, host string, request *http.Request) (Principal, error)
}

BrowserSessionVerifier verifies the per-host __Host- session the gate sets after a Hub launch proof (homelab identity target §6.3, igti.10). Until it exists a browser carries no accepted remote session.

type Decision

type Decision struct {
	Allow    bool
	Status   int
	Reason   string
	Headers  http.Header
	Redirect string
	Cookies  []*http.Cookie
}

Decision is the gate's answer. Headers are set only on allow; Redirect and Cookies only on the browser launch answers (a 302 the router relays).

type DeviceProof

type DeviceProof struct {
	Method      string
	RouteOrigin string
	Path        string
	Header      http.Header
}

DeviceProof is the per-request proof a kombify client carries, as the router observed the request: RouteOrigin is the https origin of the matched route from the gate's own route table, never a request header; Path is the request target in origin form (the verifier drops the query); Header holds "Authorization: DPoP <credential>" and the "DPoP" proof.

type DeviceProofVerifier

type DeviceProofVerifier interface {
	VerifyDeviceProof(ctx context.Context, proof DeviceProof) (Principal, error)
}

DeviceProofVerifier is the seam to the device verifier (internal/identity, reworked by igti.2). It returns the account, the device and the account's groups, or an error; the gate never inspects the credential itself.

type Gate

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

Gate decides per route from the compiler-owned table.

func New

func New(table Table, options Options) (*Gate, error)

New returns a gate for a validated table.

func (*Gate) Decide

func (g *Gate) Decide(ctx context.Context, request Request) Decision

Decide is the decision table of homelab identity target §7 and §8.

func (*Gate) ServeHTTP

func (g *Gate) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP answers one forward-auth call. The router sends the original method, host and request URI as X-Forwarded-Method, X-Forwarded-Host and X-Forwarded-Uri derived from the request itself (trustForwardHeader is off on both gate middlewares); everything else about the request is read from its own headers.

type LaunchRequest

type LaunchRequest struct {
	Host       string
	Credential string
	Proof      string
	State      string
	Target     string
	Home       bool
}

LaunchRequest is one launch exchange as the gate observed it.

type Options

type Options struct {
	Devices   DeviceProofVerifier
	Browsers  BrowserSessionVerifier
	Launcher  BrowserLauncher
	AppPasses AppPassVerifier
	Agents    AgentEnvelopeVerifier
	Now       func() time.Time
}

Options are the gate's verifier seams. A nil seam denies its class.

type PinnedGatewayKeyMissing

type PinnedGatewayKeyMissing struct{}

PinnedGatewayKeyMissing denies every agent request.

func (PinnedGatewayKeyMissing) VerifyAgentEnvelope

VerifyAgentEnvelope always fails closed.

type Principal

type Principal struct {
	Subject     string
	Device      string
	Groups      []string
	GroupsKnown bool
	ExpiresAt   time.Time
}

Principal is a verified Homelab account, with its enrolled device where one was proven. Groups are the account's household groups when the verifier knows them (GroupsKnown); a device credential carries none.

type RateLimit

type RateLimit = accessgatetable.RateLimit

The route table contract, re-exported for the gate's callers.

type Request

type Request struct {
	Listener string
	Method   string
	Host     string
	URI      string
	Header   http.Header
	HTTP     *http.Request
}

Request is one forward-auth call: the listener class the router bound, and the method, host and request URI the router derived from the request.

type Route

type Route = accessgatetable.Route

The route table contract, re-exported for the gate's callers.

type Table

type Table = accessgatetable.Table

The route table contract, re-exported for the gate's callers.

func ParseTable

func ParseTable(raw []byte) (Table, error)

ParseTable decodes and validates a route table strictly.

Jump to

Keyboard shortcuts

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