apikey

package
v0.0.1 Latest Latest
Warning

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

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

Documentation

Index

Constants

View Source
const (
	// RoleAdmin is the admin role string.
	RoleAdmin = "admin"
	// RoleTenant is the tenant role string.
	RoleTenant = "tenant"
)
View Source
const (
	// LabelType marks Secrets managed by agentbox API key store.
	LabelType = "agentbox.io/type"
	// LabelTypeValue is the label value for API key secrets.
	LabelTypeValue = "api-key"
	// LabelNamespace stores the tenant namespace in the secret label.
	LabelNamespace = "agentbox.io/namespace"
	// LabelUser stores the user in the secret label.
	LabelUser = "agentbox.io/user"
	// LabelTeam stores the team in the secret label.
	LabelTeam = "agentbox.io/team"
	// LabelTokenHashPrefix is the first 16 hex chars of SHA-256(rawToken) for label selector.
	LabelTokenHashPrefix = "agentbox.io/token-hash"

	// LabelSyncSource marks the origin of the API key Secret.
	// "global" means the key was created/synced via ws-proxy (global key manager).
	// Resources without this label (locally-created or legacy) are treated as non-global.
	LabelSyncSource       = "agentbox.io/sync-source"
	LabelSyncSourceGlobal = "global"

	// Token prefix for all API keys.
	TokenPrefix = "agbx_"
)

Variables

View Source
var (
	// ErrTokenNotFound is returned when the provided token does not match any stored key.
	ErrTokenNotFound = errors.New("api key not found")
	// ErrTokenExpired is returned when the token is found but has passed its expiry time.
	ErrTokenExpired = errors.New("api key expired")
)

Functions

This section is empty.

Types

type AdminKeyManager

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

AdminKeyManager handles constant-time comparison of the admin API key.

func NewAdminKeyManager

func NewAdminKeyManager(adminKey string) *AdminKeyManager

NewAdminKeyManager creates a new AdminKeyManager. adminKey is the raw admin key string. When empty, IsAdminKey always returns false.

func (*AdminKeyManager) IsAdminKey

func (m *AdminKeyManager) IsAdminKey(key string) bool

IsAdminKey reports whether the provided key equals the admin key using constant-time comparison to prevent timing attacks.

type KeyMetadata

type KeyMetadata struct {
	// KeyID is the fully qualified secret identifier: "<namespace>/<name>".
	KeyID       string    `json:"keyId"`
	Namespace   string    `json:"namespace"`
	Role        string    `json:"role"`
	User        string    `json:"user"`
	Team        string    `json:"team"`
	QuotaURL    string    `json:"quotaURL"`
	Description string    `json:"description"`
	IssuedAt    time.Time `json:"issuedAt"`
	ExpiresAt   time.Time `json:"expiresAt"` // zero = never expires
	// SyncSource is "global" when the key was created/synced via ws-proxy.
	// Empty means locally-created or a legacy resource — both are treated as non-global.
	SyncSource string `json:"syncSource,omitempty"`
	// TokenHash is the full SHA-256 hex hash of the raw token, extracted from
	// the Secret data. It is needed for sync (CreateFromHash) but MUST NOT be
	// exposed via any external API — hence json:"-".
	TokenHash string `json:"-"`
	// RawToken is the full opaque token (agbx_...) stored in the Secret's "apikey"
	// data field. Populated only for keys created after plaintext storage was
	// introduced. Empty for legacy keys. MUST NOT be exposed in JSON — json:"-".
	RawToken string `json:"-"`
}

KeyMetadata holds the full metadata stored in a Kubernetes Secret for one API key.

type KeyStore

type KeyStore interface {
	// Create generates a new random token, stores its metadata as a K8s Secret,
	// and returns the raw token (shown only once) plus the secret name (KeyID short form).
	Create(ctx context.Context, meta KeyMetadata) (rawToken, keyID string, err error)

	// CreateFromHash writes a Secret using an already-computed tokenHash/hashPrefix
	// (e.g. when importing a key from another cluster). It is idempotent:
	// if the Secret already exists the call returns nil.
	CreateFromHash(ctx context.Context, meta KeyMetadata, tokenHash, hashPrefix string) error

	// Validate resolves rawToken to its KeyMetadata, using an in-memory cache.
	// Returns ErrTokenNotFound if no matching secret exists.
	// Returns ErrTokenExpired if the key has passed its ExpiresAt time.
	Validate(ctx context.Context, rawToken string) (*KeyMetadata, error)

	// List returns all API key metadata.
	List(ctx context.Context) ([]KeyMetadata, error)

	// ListByTeamAndUser returns API key metadata filtered by team and/or user
	// labels. Pass empty strings to skip a filter dimension.
	ListByTeamAndUser(ctx context.Context, team, user string) ([]KeyMetadata, error)

	// Get returns the metadata for the secret identified by keyID (secret name,
	// without namespace prefix).
	Get(ctx context.Context, keyID string) (*KeyMetadata, error)

	// Delete revokes the API key identified by keyID (secret name).
	Delete(ctx context.Context, keyID string) error
}

KeyStore defines the operations for managing opaque API keys backed by Kubernetes Secrets.

type SecretKeyStore

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

SecretKeyStore implements KeyStore backed by Kubernetes Secrets.

func NewSecretKeyStore

func NewSecretKeyStore(cfg SecretKeyStoreConfig) *SecretKeyStore

NewSecretKeyStore creates a new SecretKeyStore.

func (*SecretKeyStore) CountUserKeys

func (s *SecretKeyStore) CountUserKeys(ctx context.Context, namespace, user string) (int, error)

CountUserKeys returns the number of API key Secrets for the given namespace+user pair.

func (*SecretKeyStore) Create

func (s *SecretKeyStore) Create(ctx context.Context, meta KeyMetadata) (rawToken, keyID string, err error)

Create generates a new opaque token "agbx_<base64url>", stores its SHA-256 hash and all metadata in a Kubernetes Secret, then returns the raw token. The raw token is shown only once; the caller must persist it.

func (*SecretKeyStore) CreateFromHash

func (s *SecretKeyStore) CreateFromHash(ctx context.Context, meta KeyMetadata, tokenHash, hashPrefix string) error

CreateFromHash writes a Secret using an already-computed tokenHash/hashPrefix (e.g. when syncing a key created by the master cluster BFF). It is idempotent: if the Secret already exists the call returns nil.

func (*SecretKeyStore) Delete

func (s *SecretKeyStore) Delete(ctx context.Context, keyID string) error

Delete revokes the API key by deleting its Kubernetes Secret. It reads the secret first to evict the cache entry precisely.

func (*SecretKeyStore) Get

func (s *SecretKeyStore) Get(ctx context.Context, keyID string) (*KeyMetadata, error)

Get returns metadata for a single API key secret by its name (without namespace prefix).

func (*SecretKeyStore) List

func (s *SecretKeyStore) List(ctx context.Context) ([]KeyMetadata, error)

List returns metadata for all API key secrets.

func (*SecretKeyStore) ListByTeamAndUser

func (s *SecretKeyStore) ListByTeamAndUser(ctx context.Context, team, user string) ([]KeyMetadata, error)

ListByTeamAndUser returns API key metadata filtered by team and/or user labels at the Kubernetes level (label selector). Pass empty strings to skip a filter dimension.

func (*SecretKeyStore) Validate

func (s *SecretKeyStore) Validate(ctx context.Context, rawToken string) (*KeyMetadata, error)

Validate resolves rawToken → KeyMetadata via in-memory cache, falling back to a Kubernetes Secret lookup.

type SecretKeyStoreConfig

type SecretKeyStoreConfig struct {
	// Client is the Kubernetes client used to read/write Secrets.
	Client client.Client
	// SecretsNamespace is the namespace where API key secrets are stored.
	// Defaults to "agentbox-system" if empty.
	SecretsNamespace string
	// CacheTTL is how long a successful Validate result is cached in memory.
	// Defaults to 1 minute if zero.
	CacheTTL time.Duration
}

SecretKeyStoreConfig configures the SecretKeyStore.

Jump to

Keyboard shortcuts

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