Documentation
¶
Index ¶
- Constants
- Variables
- func BuildToken(id, secret string) string
- func CanAccessZone(ctx context.Context, zone string) bool
- func ContextWithIdentity(ctx context.Context, id *Identity) context.Context
- func GenerateToken() (token, id string, err error)
- func GenerateTokenWithID(id string) (token, secret string, err error)
- func HasScope(ctx context.Context, scope string) bool
- func HashToken(token string) ([]byte, error)
- func IsValidScope(scope string) bool
- func IsZoneScoped(method string) bool
- func ParseToken(token string) (id, secret string, err error)
- func RecordAudit(ctx context.Context, event *AuditEvent)
- func RequiredScopes(method string) []string
- func ShouldSkipAuth(method string) bool
- func StartAuthSpan(ctx context.Context, method string) (context.Context, trace.Span)
- func ValidateID(id string) error
- func ValidateScopes(scopes []string) error
- func VerifyToken(token string, hashedToken []byte) bool
- type APIKey
- type AuditEvent
- type Identity
- type Interceptor
- type Store
- func (s *Store) Create(ctx context.Context, key *APIKey) error
- func (s *Store) Delete(ctx context.Context, id string) error
- func (s *Store) Exists(ctx context.Context, id string) (bool, error)
- func (s *Store) Get(ctx context.Context, id string) (*APIKey, error)
- func (s *Store) List(ctx context.Context) ([]*APIKey, error)
- func (s *Store) Revoke(ctx context.Context, id string) (*APIKey, error)
- func (s *Store) Update(ctx context.Context, key *APIKey) error
- func (s *Store) UpdateLastUsed(ctx context.Context, id string, t time.Time) error
Constants ¶
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.
const ( TokenPrefix = "mdn_" IDLength = 6 // base32 characters SecretLength = 32 // base32 characters )
Token format constants
Variables ¶
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
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
var AllScopes = []string{ ScopeZonesRead, ScopeZonesWrite, ScopeRecordsRead, ScopeRecordsWrite, ScopeDNSSECRead, ScopeDNSSECWrite, ScopeTSIGRead, ScopeTSIGWrite, ScopeAPIKeysRead, ScopeAPIKeysWrite, }
AllScopes is the list of all valid scopes (excluding admin).
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.
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.
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 ¶
BuildToken constructs a token from id and secret.
func CanAccessZone ¶
CanAccessZone checks if the identity in the context can access the given zone. Returns false if no identity is present.
func ContextWithIdentity ¶
ContextWithIdentity returns a new context with the identity attached.
func GenerateToken ¶
GenerateToken creates a new token with random ID and secret. Returns the full token and the extracted ID.
func GenerateTokenWithID ¶
GenerateTokenWithID creates a token with a specific ID. Returns the full token and the secret portion.
func HasScope ¶
HasScope checks if the identity in the context has the given scope. Returns false if no identity is present.
func HashToken ¶
HashToken returns an argon2id hash of the token. The returned bytes include the salt prepended to the hash.
func IsValidScope ¶
IsValidScope checks if a scope string is valid.
func IsZoneScoped ¶
IsZoneScoped returns true if the method requires zone authorization.
func ParseToken ¶
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 ¶
RequiredScopes returns the scopes required for a method. Returns nil if the method is not in the map (unknown method).
func ShouldSkipAuth ¶
ShouldSkipAuth returns true if the method should skip authentication.
func StartAuthSpan ¶
StartAuthSpan starts a new span for authentication processing.
func ValidateID ¶
ValidateID checks if an ID is valid. Rules: 1-32 chars, alphanumeric + hyphen, lowercase.
func ValidateScopes ¶
ValidateScopes checks if all provided scopes are valid.
func VerifyToken ¶
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 ¶
CanAccessAnyZone checks if the key has access to all zones ("*").
func (*APIKey) CanAccessZone ¶
CanAccessZone checks if the key authorizes access to the given zone. A zone list containing "*" grants access to all zones.
func (*APIKey) HasAnyScope ¶
HasAnyScope checks if the key has any of the required scopes.
func (*APIKey) HasScope ¶
HasScope checks if the key has the required scope. The "admin" scope grants access to all scopes.
func (*APIKey) ValidationError ¶
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 ¶
IdentityFromContext retrieves the identity from the context. Returns nil and false if no identity is present.
func MustIdentityFromContext ¶
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 ¶
func (i *Interceptor) Stream() grpc.StreamServerInterceptor
Stream returns a gRPC stream server interceptor for authentication.
func (*Interceptor) Unary ¶
func (i *Interceptor) Unary() grpc.UnaryServerInterceptor
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 (*Store) Create ¶
Create stores a new API key. Returns ErrKeyExists if a key with the same ID already exists.
func (*Store) Delete ¶
Delete removes an API key by ID. Returns ErrKeyNotFound if the key doesn't exist.
func (*Store) Get ¶
Get retrieves an API key by ID. Returns ErrKeyNotFound if the key doesn't exist.