feat: allow an API token to be restricted to servers by tag

This commit is contained in:
2026-09-08 13:34:58 +00:00
parent e8e41f197a
commit f9df426e6c
5 changed files with 164 additions and 5 deletions
+12 -3
View File
@@ -14,9 +14,10 @@ import (
// full-entropy random rather than a chosen password, and a per-token salt would
// force a collection scan where an indexed lookup is wanted.
//
// Role and Scopes are immutable after creation. There is no update endpoint:
// editing what a credential already deployed in CI can do, with no record of
// what it could do before, is worse than requiring a rotation.
// Role, Scopes and TagSelector are immutable after creation. There is no
// update endpoint: editing what a credential already deployed in CI can do,
// with no record of what it could do before, is worse than requiring a
// rotation.
type APIToken struct {
ID bson.ObjectID `bson:"_id,omitempty" json:"-"`
TokenID string `bson:"token_id" json:"token_id"`
@@ -33,6 +34,14 @@ type APIToken struct {
Role string `bson:"role" json:"role"`
Scopes []string `bson:"scopes" json:"scopes"`
// TagSelector restricts this token to servers carrying every tag in the
// map. Empty or nil means the whole fleet.
//
// Immutable after creation for the same reason as Role and Scopes: changing
// what a credential already deployed in CI can reach, with no record of what
// it could reach before, is worse than requiring a rotation.
TagSelector map[string]string `bson:"tag_selector,omitempty" json:"tag_selector,omitempty"`
// ExpiresAt nil means the token never expires. Whether that is allowed is
// a per-instance policy, settings.api_token_max_days.
ExpiresAt *time.Time `bson:"expires_at,omitempty" json:"expires_at,omitempty"`