auth

package
v0.6.0 Latest Latest
Warning

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

Go to latest
Published: Jan 16, 2026 License: BSD-2-Clause Imports: 19 Imported by: 0

Documentation

Index

Constants

View Source
const (
	ScopeZonesRead    = "zones:read"
	ScopeZonesWrite   = "zones:write"
	ScopeRecordsRead  = "records:read"
	ScopeRecordsWrite = "records:write"
	ScopeDNSSECRead   = "dnssec:read"
	ScopeDNSSECWrite  = "dnssec:write"
	ScopeTSIGRead     = "tsig:read"
	ScopeTSIGWrite    = "tsig:write"
	ScopeAPIKeysRead  = "apikeys:read"
	ScopeAPIKeysWrite = "apikeys:write"
	ScopeAdmin        = "admin"
)

Scope constants define the permission scopes for API keys.

View Source
const (
	TokenPrefix  = "mdn_"
	IDLength     = 6  // base32 characters
	SecretLength = 32 // base32 characters

)

Token format constants

Variables

View Source
var (
	ErrKeyNotFound    = errors.New("api key not found")
	ErrKeyExists      = errors.New("api key already exists")
	ErrKeyRevoked     = errors.New("api key has been revoked")
	ErrKeyExpired     = errors.New("api key has expired")
	ErrInvalidScope   = errors.New("invalid scope")
	ErrInvalidZone    = errors.New("invalid zone")
	ErrAccessDenied   = errors.New("access denied")
	ErrZoneNotAllowed = errors.New("zone not allowed")
)

APIKey errors

View Source
var (
	ErrInvalidTokenFormat = errors.New("invalid token format")
	ErrInvalidTokenPrefix = errors.New("token must start with mdn_")
	ErrInvalidTokenID     = errors.New("invalid token ID")
	ErrInvalidTokenSecret = errors.New("invalid token secret")
)

Token errors

AllScopes is the list of all valid scopes (excluding admin).

View Source
var MethodScopes = map[string][]string{

	serviceName + "CreateZone": {ScopeZonesWrite},
	serviceName + "GetZone":    {ScopeZonesRead},
	serviceName + "UpdateZone": {ScopeZonesWrite},
	serviceName + "DeleteZone": {ScopeZonesWrite},
	serviceName + "ListZones":  {ScopeZonesRead},

	serviceName + "GetRRset":    {ScopeRecordsRead},
	serviceName + "SetRRset":    {ScopeRecordsWrite},
	serviceName + "DeleteRRset": {ScopeRecordsWrite},
	serviceName + "ListRRsets":  {ScopeRecordsRead},
	serviceName + "BatchUpdate": {ScopeRecordsWrite},

	serviceName + "ListDNSSECKeys":      {ScopeDNSSECRead},
	serviceName + "GenerateDNSSECKey":   {ScopeDNSSECWrite},
	serviceName + "ImportDNSSECKey":     {ScopeDNSSECWrite},
	serviceName + "DeleteDNSSECKey":     {ScopeDNSSECWrite},
	serviceName + "ActivateDNSSECKey":   {ScopeDNSSECWrite},
	serviceName + "RetireDNSSECKey":     {ScopeDNSSECWrite},
	serviceName + "ScheduleKeyRollover": {ScopeDNSSECWrite},

	serviceName + "ListTSIGKeys":  {ScopeTSIGRead},
	serviceName + "CreateTSIGKey": {ScopeTSIGWrite},
	serviceName + "DeleteTSIGKey": {ScopeTSIGWrite},

	serviceName + "CreateAPIKey": {ScopeAPIKeysWrite},
	serviceName + "GetAPIKey":    {ScopeAPIKeysRead},
	serviceName + "ListAPIKeys":  {ScopeAPIKeysRead},
	serviceName + "UpdateAPIKey": {ScopeAPIKeysWrite},
	serviceName + "RotateAPIKey": {ScopeAPIKeysWrite},
	serviceName + "RevokeAPIKey": {ScopeAPIKeysWrite},
}

MethodScopes maps gRPC method names to required scopes. A method may require any one of the listed scopes.

View Source
var SkipAuthMethods = map[string]bool{

	"/grpc.reflection.v1alpha.ServerReflection/ServerReflectionInfo": true,
	"/grpc.reflection.v1.ServerReflection/ServerReflectionInfo":      true,

	"/grpc.health.v1.Health/Check": true,
	"/grpc.health.v1.Health/Watch": true,
}

SkipAuthMethods lists methods that don't require authentication. Typically health checks and reflection endpoints.

View Source
var ZoneScopedMethods = map[string]bool{
	serviceName + "GetZone":    true,
	serviceName + "UpdateZone": true,
	serviceName + "DeleteZone": true,

	serviceName + "GetRRset":    true,
	serviceName + "SetRRset":    true,
	serviceName + "DeleteRRset": true,
	serviceName + "ListRRsets":  true,
	serviceName + "BatchUpdate": true,

	serviceName + "ListDNSSECKeys":      true,
	serviceName + "GenerateDNSSECKey":   true,
	serviceName + "ImportDNSSECKey":     true,
	serviceName + "DeleteDNSSECKey":     true,
	serviceName + "ActivateDNSSECKey":   true,
	serviceName + "RetireDNSSECKey":     true,
	serviceName + "ScheduleKeyRollover": true,

	serviceName + "ListTSIGKeys":  true,
	serviceName + "CreateTSIGKey": true,
	serviceName + "DeleteTSIGKey": true,
}

ZoneScopedMethods lists methods that operate on specific zones. These methods require zone authorization in addition to scope authorization. Methods not in this map either don't require zone auth (e.g., ListZones) or extract the zone differently.

Functions

func BuildToken

func BuildToken(id, secret string) string

BuildToken constructs a token from id and secret.

func CanAccessZone

func CanAccessZone(ctx context.Context, zone string) bool

CanAccessZone checks if the identity in the context can access the given zone. Returns false if no identity is present.

func ContextWithIdentity

func ContextWithIdentity(ctx context.Context, id *Identity) context.Context

ContextWithIdentity returns a new context with the identity attached.

func GenerateToken

func GenerateToken() (token, id string, err error)

GenerateToken creates a new token with random ID and secret. Returns the full token and the extracted ID.

func GenerateTokenWithID

func GenerateTokenWithID(id string) (token, secret string, err error)

GenerateTokenWithID creates a token with a specific ID. Returns the full token and the secret portion.

func HasScope

func HasScope(ctx context.Context, scope string) bool

HasScope checks if the identity in the context has the given scope. Returns false if no identity is present.

func HashToken

func HashToken(token string) ([]byte, error)

HashToken returns an argon2id hash of the token. The returned bytes include the salt prepended to the hash.

func IsValidScope

func IsValidScope(scope string) bool

IsValidScope checks if a scope string is valid.

func IsZoneScoped

func IsZoneScoped(method string) bool

IsZoneScoped returns true if the method requires zone authorization.

func ParseToken

func ParseToken(token string) (id, secret string, err error)

ParseToken extracts id and secret from a token.

func RecordAudit

func RecordAudit(ctx context.Context, event *AuditEvent)

RecordAudit records an audit event to both traces and logs.

func RequiredScopes

func RequiredScopes(method string) []string

RequiredScopes returns the scopes required for a method. Returns nil if the method is not in the map (unknown method).

func ShouldSkipAuth

func ShouldSkipAuth(method string) bool

ShouldSkipAuth returns true if the method should skip authentication.

func StartAuthSpan

func StartAuthSpan(ctx context.Context, method string) (context.Context, trace.Span)

StartAuthSpan starts a new span for authentication processing.

func ValidateID

func ValidateID(id string) error

ValidateID checks if an ID is valid. Rules: 1-32 chars, alphanumeric + hyphen, lowercase.

func ValidateScopes

func ValidateScopes(scopes []string) error

ValidateScopes checks if all provided scopes are valid.

func VerifyToken

func VerifyToken(token string, hashedToken []byte) bool

VerifyToken checks if a token matches a hash.

Types

type APIKey

type APIKey struct {
	ID          string     // Unique identifier (from token)
	HashedToken []byte     // argon2id hash of full token
	Scopes      []string   // Permission scopes
	Zones       []string   // Authorized zones (or ["*"] for all)
	Description string     // Human-readable description
	CreatedAt   time.Time  // Creation timestamp
	ExpiresAt   *time.Time // Optional expiry (nil = no expiry)
	LastUsedAt  *time.Time // Last usage timestamp
	Revoked     bool       // Soft-delete flag
}

APIKey represents an authenticated principal.

func (*APIKey) CanAccessAnyZone

func (k *APIKey) CanAccessAnyZone() bool

CanAccessAnyZone checks if the key has access to all zones ("*").

func (*APIKey) CanAccessZone

func (k *APIKey) CanAccessZone(zone string) bool

CanAccessZone checks if the key authorizes access to the given zone. A zone list containing "*" grants access to all zones.

func (*APIKey) Clone

func (k *APIKey) Clone() *APIKey

Clone creates a deep copy of the APIKey.

func (*APIKey) HasAnyScope

func (k *APIKey) HasAnyScope(scopes []string) bool

HasAnyScope checks if the key has any of the required scopes.

func (*APIKey) HasScope

func (k *APIKey) HasScope(scope string) bool

HasScope checks if the key has the required scope. The "admin" scope grants access to all scopes.

func (*APIKey) IsValid

func (k *APIKey) IsValid() bool

IsValid checks if the key is not revoked and not expired.

func (*APIKey) ValidationError

func (k *APIKey) ValidationError() error

ValidationError returns a specific error if the key is invalid.

type AuditEvent

type AuditEvent struct {
	Method     string    // gRPC method name
	Identity   *Identity // Authenticated identity (nil if unauthenticated)
	Zone       string    // Target zone (if applicable)
	Authorized bool      // Whether the request was authorized
	Error      string    // Error message if authorization failed
}

AuditEvent represents an auditable authentication/authorization event.

type Identity

type Identity struct {
	KeyID       string   // The API key ID
	Scopes      []string // The scopes granted to this key
	Zones       []string // The zones this key can access
	Description string   // Human-readable key description
}

Identity represents the authenticated principal from a request. This is injected into the context after successful authentication.

func IdentityFromContext

func IdentityFromContext(ctx context.Context) (*Identity, bool)

IdentityFromContext retrieves the identity from the context. Returns nil and false if no identity is present.

func MustIdentityFromContext

func MustIdentityFromContext(ctx context.Context) *Identity

MustIdentityFromContext retrieves the identity from the context. Panics if no identity is present.

type Interceptor

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

Interceptor provides gRPC authentication and authorization interceptors.

func NewInterceptor

func NewInterceptor(store *Store) *Interceptor

NewInterceptor creates a new auth interceptor.

func (*Interceptor) Stream

Stream returns a gRPC stream server interceptor for authentication.

func (*Interceptor) Unary

Unary returns a gRPC unary server interceptor for authentication.

type Store

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

Store provides persistent storage for API keys using BadgerDB.

func NewStore

func NewStore(db *badger.DB) *Store

NewStore creates a new auth store using the provided BadgerDB instance.

func (*Store) Create

func (s *Store) Create(ctx context.Context, key *APIKey) error

Create stores a new API key. Returns ErrKeyExists if a key with the same ID already exists.

func (*Store) Delete

func (s *Store) Delete(ctx context.Context, id string) error

Delete removes an API key by ID. Returns ErrKeyNotFound if the key doesn't exist.

func (*Store) Exists

func (s *Store) Exists(ctx context.Context, id string) (bool, error)

Exists checks if an API key with the given ID exists.

func (*Store) Get

func (s *Store) Get(ctx context.Context, id string) (*APIKey, error)

Get retrieves an API key by ID. Returns ErrKeyNotFound if the key doesn't exist.

func (*Store) List

func (s *Store) List(ctx context.Context) ([]*APIKey, error)

List returns all API keys.

func (*Store) Revoke

func (s *Store) Revoke(ctx context.Context, id string) (*APIKey, error)

Revoke marks an API key as revoked without deleting it (for audit trail).

func (*Store) Update

func (s *Store) Update(ctx context.Context, key *APIKey) error

Update updates an existing API key. Returns ErrKeyNotFound if the key doesn't exist.

func (*Store) UpdateLastUsed

func (s *Store) UpdateLastUsed(ctx context.Context, id string, t time.Time) error

UpdateLastUsed updates the LastUsedAt timestamp for a key. This is a lightweight operation that only updates the timestamp.

Jump to

Keyboard shortcuts

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