Documentation
¶
Overview ¶
Package identity implements the registry's identity, key-lifecycle, and identity-provider handlers. It is extracted from pkg/registry/server as part of the R2.3 registry decomposition.
Thread safety: all exported methods are safe for concurrent use.
Index ¶
- Constants
- Variables
- func DecodeJWT(token string) (*JwtHeader, *JwtClaims, string, error)
- func HashOwner(owner string) string
- func ValidateJWTClaims(claims *JwtClaims, expectedIssuer, expectedAudience string) error
- func VerifyJWTSignatureHS256(signingInput string, signatureB64 string, secret []byte) error
- func VerifyJWTSignatureRS256(signingInput, signatureB64 string, key *JwksKey) error
- type BlueprintAuditExport
- type BlueprintIdentityProvider
- type BlueprintPolicy
- type BlueprintRole
- type BlueprintWebhooks
- type Callbacks
- type JWKSCache
- type JwksKey
- type JwtAud
- type JwtClaims
- type JwtHeader
- type KeyInfo
- type KeyRotationCallback
- type NetworkBlueprint
- type NodeView
- type ProvisionCallbacks
- type ProvisionResult
- type RBACPreAssignCallbacks
- type Store
- func (st *Store) ApplyBlueprint(bp *NetworkBlueprint, adminToken string, pcb ProvisionCallbacks) (*ProvisionResult, error)
- func (st *Store) ApplyRBACPreAssignment(netID uint16, nodeID uint32, rcb RBACPreAssignCallbacks)
- func (st *Store) ClearIDPConfig()
- func (st *Store) GetIDPConfig() *BlueprintIdentityProvider
- func (st *Store) GetWebhookURL() string
- func (st *Store) HandleGetIDPConfig(msg map[string]interface{}) (map[string]interface{}, error)
- func (st *Store) HandleGetIdentity(msg map[string]interface{}) (map[string]interface{}, error)
- func (st *Store) HandleGetKeyInfo(msg map[string]interface{}) (map[string]interface{}, error)
- func (st *Store) HandleGetProvisionStatus(msg map[string]interface{}, networkSummary func() []map[string]interface{}, ...) (map[string]interface{}, error)
- func (st *Store) HandleProvisionNetwork(msg map[string]interface{}, adminToken string, pcb ProvisionCallbacks) (map[string]interface{}, error)
- func (st *Store) HandleRotateKey(msg map[string]interface{}) (map[string]interface{}, error)
- func (st *Store) HandleSetExternalID(msg map[string]interface{}) (map[string]interface{}, error)
- func (st *Store) HandleSetIDPConfig(msg map[string]interface{}) (map[string]interface{}, error)
- func (st *Store) HandleSetIdentityWebhook(msg map[string]interface{}) (map[string]interface{}, error)
- func (st *Store) HandleSetKeyExpiry(msg map[string]interface{}) (map[string]interface{}, error)
- func (st *Store) HandleValidateToken(msg map[string]interface{}) (map[string]interface{}, error)
- func (st *Store) SetIDPConfig(cfg *BlueprintIdentityProvider)
- func (st *Store) SetWebhookURL(url string)
- func (st *Store) VerifyToken(token string) (string, error)
- type WALRecorder
Constants ¶
const JwksCacheTTL = 5 * time.Minute
JwksCacheTTL is the default TTL for cached JWKS keys.
Variables ¶
var ( LoadBlueprint = wire.LoadBlueprint ValidateBlueprint = wire.ValidateBlueprint )
LoadBlueprint and ValidateBlueprint are re-exported for callers that historically imported them from pkg/registry/server.
var ErrKeyRotatedConcurrently = fmt.Errorf("rotate_key: key rotated concurrently, retry")
ErrKeyRotatedConcurrently is returned by NodeView.UpdateNodeKey when a concurrent rotation landed between Phase 1 (snapshot) and Phase 3 (commit).
Functions ¶
func ValidateJWTClaims ¶
func VerifyJWTSignatureHS256 ¶
func VerifyJWTSignatureRS256 ¶
VerifyJWTSignatureRS256 verifies an RS256 JWT signature using the given JwksKey.
Types ¶
type BlueprintAuditExport ¶
type BlueprintAuditExport = wire.BlueprintAuditExport
Blueprint type aliases. The canonical definitions live in pkg/registry/wire so plugin tests and the client can validate blueprints without importing the server. Aliases keep existing callers readable.
type BlueprintIdentityProvider ¶
type BlueprintIdentityProvider = wire.BlueprintIdentityProvider
BlueprintIdentityProvider is a type alias so callers don't need to import wire.
type BlueprintPolicy ¶
type BlueprintPolicy = wire.BlueprintPolicy
Blueprint type aliases. The canonical definitions live in pkg/registry/wire so plugin tests and the client can validate blueprints without importing the server. Aliases keep existing callers readable.
type BlueprintRole ¶
type BlueprintRole = wire.BlueprintRole
Blueprint type aliases. The canonical definitions live in pkg/registry/wire so plugin tests and the client can validate blueprints without importing the server. Aliases keep existing callers readable.
type BlueprintWebhooks ¶
type BlueprintWebhooks = wire.BlueprintWebhooks
Blueprint type aliases. The canonical definitions live in pkg/registry/wire so plugin tests and the client can validate blueprints without importing the server. Aliases keep existing callers readable.
type Callbacks ¶
type Callbacks struct {
// Save triggers a debounced snapshot write.
Save func()
// Audit records an audit-log entry.
Audit func(action string, attrs ...any)
// IncKeyRotations increments the key-rotation counter.
IncKeyRotations func()
// IncIDPVerifications increments the IDP-verification counter.
IncIDPVerifications func()
// RecordWAL writes a key-rotation WAL entry.
RecordWAL WALRecorder
// OnKeyRotated is the callback that updates pubKeyIdx in the parent Server.
OnKeyRotated KeyRotationCallback
// Bus is the event bus used to publish "key.rotated" events.
Bus events.Bus
}
Callbacks bundles the side-effect functions the Store calls on state changes. All functions must be safe for concurrent use.
type JWKSCache ¶
type JWKSCache struct {
Keys []JwksKey
URL string
FetchedAt time.Time
TTL time.Duration
// contains filtered or unexported fields
}
JWKSCache holds a cached set of JWKS keys for a single issuer URL. Fields are exported so that white-box tests in package server can construct a cache with pre-populated state.
func NewJWKSCache ¶
func NewJWKSCache() *JWKSCache
NewJWKSCache returns a new JWKSCache with the default TTL.
type JwksKey ¶
type JwksKey struct {
Kty string `json:"kty"`
Kid string `json:"kid"`
Alg string `json:"alg"`
K string `json:"k,omitempty"`
N string `json:"n,omitempty"`
E string `json:"e,omitempty"`
}
func FetchJWKSKeys ¶
FetchJWKSKeys fetches the list of JWKS keys from the given URL.
type KeyInfo ¶
type KeyInfo struct {
CreatedAt time.Time `json:"created_at"`
RotatedAt time.Time `json:"rotated_at,omitempty"`
RotateCount int `json:"rotate_count"`
ExpiresAt time.Time `json:"expires_at,omitempty"`
}
KeyInfo mirrors server.KeyInfo; we declare it here to keep the sub-package independent of the parent package. The two must stay in sync.
type KeyRotationCallback ¶
KeyRotationCallback is called after a successful key rotation so that the caller (Server) can update its pubKeyIdx index.
nodeID — node whose key was rotated oldPubKey — base64-encoded old public key (key to delete from index) newPubKey — base64-encoded new public key (key to add to index)
type NetworkBlueprint ¶
type NetworkBlueprint = wire.NetworkBlueprint
Blueprint type aliases. The canonical definitions live in pkg/registry/wire so plugin tests and the client can validate blueprints without importing the server. Aliases keep existing callers readable.
type NodeView ¶
type NodeView interface {
// LookupNodeKey returns the current public key for a node.
// ok is false if the node does not exist.
LookupNodeKey(id uint32) (pubKey []byte, ok bool)
// LookupNodeFull returns full identity-related fields for a node.
// ok is false if the node does not exist.
LookupNodeFull(id uint32) (pubKey []byte, keyMeta KeyInfo, networks []uint16, externalID, owner string, ok bool)
// UpdateNodeKey atomically swaps the node's public key if it still matches
// expectedPubKey (stale-check for concurrent-rotation detection).
// Returns the old public key (base64-encoded) and nil on success.
// Returns ErrKeyRotatedConcurrently if the key was rotated concurrently.
// Returns protocol.ErrNodeNotFound if the node was deregistered.
UpdateNodeKey(id uint32, expectedPubKey, newPubKey []byte, rotatedAt time.Time) (oldPubKeyB64 string, err error)
// UpdateNodeKeyExpiry sets/clears the key expiry for a node.
// Returns the old expiry value. ok is false if the node does not exist.
UpdateNodeKeyExpiry(id uint32, expiresAt time.Time) (oldExpiry time.Time, ok bool)
// UpdateNodeExternalID sets the external identity string on a node.
// Returns the old external ID. ok is false if the node does not exist.
UpdateNodeExternalID(id uint32, externalID string) (oldID string, ok bool)
// NodeIsEnterprise returns true if the node belongs to at least one
// enterprise-flagged network.
NodeIsEnterprise(id uint32) bool
// AdminToken returns the global admin token.
AdminToken() string
// CheckAdminToken returns nil if the message carries a valid admin token.
CheckAdminToken(msg map[string]interface{}) error
// VerifyHeartbeatSignature verifies a heartbeat-style Ed25519 signature.
VerifyHeartbeatSignature(pubKey []byte, adminToken string, msg map[string]interface{}, challenge string) error
// Now returns the current time (may be overridden in tests).
Now() time.Time
}
NodeView is the read/write interface the Store uses to access node data. All methods must be safe for concurrent use.
type ProvisionCallbacks ¶
type ProvisionCallbacks struct {
// FindOrCreateNetwork looks up a network by name; if not found it creates
// one using the supplied blueprint fields. Returns (networkID, created, err).
FindOrCreateNetwork func(name string, enterprise bool, joinRule, joinToken, networkAdminToken, adminToken string) (uint16, bool, error)
// EnableEnterprise sets the Enterprise flag on network netID if not already set.
EnableEnterprise func(netID uint16)
// ApplyNetworkPolicy sets the structural policy on a network.
ApplyNetworkPolicy func(netID uint16, pol *BlueprintPolicy) error
// ApplyExprPolicy sets the programmable (expr) policy on a network.
ApplyExprPolicy func(netID uint16, data json.RawMessage) error
// SetAuditWebhookURL configures the server's audit webhook URL.
SetAuditWebhookURL func(url string)
// StoreRBACPreAssignments saves pre-assignments for future node joins.
StoreRBACPreAssignments func(netID uint16, roles []BlueprintRole)
// ConfigureAuditExport sets up the audit exporter.
ConfigureAuditExport func(cfg *BlueprintAuditExport)
// IncProvisionsTotal increments the provisions counter.
IncProvisionsTotal func()
}
ProvisionCallbacks holds the server-owned operations that ApplyBlueprint needs. They are passed per-call rather than stored on the Store so that provisioning can be called with different server contexts in tests.
type ProvisionResult ¶
type ProvisionResult struct {
NetworkID uint16 `json:"network_id"`
Name string `json:"name"`
Created bool `json:"created"` // true if network was created (vs updated)
Actions []string `json:"actions"` // human-readable list of actions taken
}
ProvisionResult describes what the provisioning operation did.
type RBACPreAssignCallbacks ¶
type RBACPreAssignCallbacks struct {
// GetRoles returns the pre-assigned roles for netID and the node's
// ExternalID. found is false if there are no pre-assignments or the
// node doesn't exist.
GetRoles func(netID uint16, nodeID uint32) (roles []BlueprintRole, externalID string, found bool)
// CommitRole sets the member's role in the network.
CommitRole func(netID uint16, nodeID uint32, role string)
// IncCounter increments the RBAC pre-assignment metric counter.
IncCounter func()
}
RBACPreAssignCallbacks holds the state-access callbacks needed by ApplyRBACPreAssignment.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store holds the mutable identity and key-lifecycle state.
Lock ordering:
mu (RWMutex) — protects identityWebhookURL, idpConfig. jwksCache has its own internal mutex.
These are independent of the parent Server's mu. Store methods must not acquire the parent mutex.
func (*Store) ApplyBlueprint ¶
func (st *Store) ApplyBlueprint(bp *NetworkBlueprint, adminToken string, pcb ProvisionCallbacks) (*ProvisionResult, error)
ApplyBlueprint provisions a network from a blueprint. It creates the network if it doesn't exist, then applies policy, RBAC, webhooks, and audit config. adminToken is the global registry admin token.
The provision callbacks (pcb) provide access to server-owned state. Nil callbacks are silently skipped, except FindOrCreateNetwork which is required.
func (*Store) ApplyRBACPreAssignment ¶
func (st *Store) ApplyRBACPreAssignment(netID uint16, nodeID uint32, rcb RBACPreAssignCallbacks)
ApplyRBACPreAssignment checks if a newly joined node matches any pre-assigned roles and applies the first match. Caller must NOT hold the server's global mutex (GetRoles and CommitRole acquire their own locks internally).
func (*Store) ClearIDPConfig ¶
func (st *Store) ClearIDPConfig()
ClearIDPConfig removes the identity provider configuration and webhook URL.
func (*Store) GetIDPConfig ¶
func (st *Store) GetIDPConfig() *BlueprintIdentityProvider
GetIDPConfig returns the current identity provider configuration.
func (*Store) GetWebhookURL ¶
GetWebhookURL returns the currently configured identity webhook URL.
func (*Store) HandleGetIDPConfig ¶
HandleGetIDPConfig implements the "get_idp_config" protocol command.
func (*Store) HandleGetIdentity ¶
HandleGetIdentity implements the "get_identity" protocol command.
func (*Store) HandleGetKeyInfo ¶
HandleGetKeyInfo implements the "get_key_info" protocol command.
func (*Store) HandleGetProvisionStatus ¶
func (st *Store) HandleGetProvisionStatus( msg map[string]interface{}, networkSummary func() []map[string]interface{}, webhookEnabled bool, auditExportFormat string, ) (map[string]interface{}, error)
HandleGetProvisionStatus implements the "get_provision_status" protocol command. The networkSummary callback produces the per-network list so the Store does not need to access s.networks directly.
func (*Store) HandleProvisionNetwork ¶
func (st *Store) HandleProvisionNetwork(msg map[string]interface{}, adminToken string, pcb ProvisionCallbacks) (map[string]interface{}, error)
HandleProvisionNetwork handles the "provision_network" protocol command. adminToken is the global registry admin token (from s.authz.AdminToken()). pcb provides the server-owned operation callbacks.
func (*Store) HandleRotateKey ¶
HandleRotateKey implements the "rotate_key" protocol command.
3-PHASE LOCK PATTERN (delegated through NodeView):
Phase 1: snapshot current pubkey via LookupNodeKey (under NodeView's RLock). Phase 2: Ed25519 verify outside all locks (~28µs). Phase 3: UpdateNodeKey re-checks pubkey and commits (under NodeView's Lock).
func (*Store) HandleSetExternalID ¶
HandleSetExternalID implements the "set_external_id" protocol command.
func (*Store) HandleSetIDPConfig ¶
HandleSetIDPConfig implements the "set_idp_config" protocol command. URL validation (SSRF prevention) must be performed by the caller before invoking this method.
func (*Store) HandleSetIdentityWebhook ¶
func (st *Store) HandleSetIdentityWebhook(msg map[string]interface{}) (map[string]interface{}, error)
HandleSetIdentityWebhook implements the "set_identity_webhook" protocol command. URL validation (SSRF prevention) must be performed by the caller before invoking this method.
func (*Store) HandleSetKeyExpiry ¶
HandleSetKeyExpiry implements the "set_key_expiry" protocol command.
func (*Store) HandleValidateToken ¶
HandleValidateToken implements the "validate_token" protocol command.
func (*Store) SetIDPConfig ¶
func (st *Store) SetIDPConfig(cfg *BlueprintIdentityProvider)
SetIDPConfig stores the identity provider configuration.
func (*Store) SetWebhookURL ¶
SetWebhookURL sets the identity verification webhook URL. An empty string disables identity verification.
type WALRecorder ¶
WALRecorder is called to write a WAL entry after a key rotation.