# Authentication & Authorization Implementation Summary ## What Was Implemented This document summarizes the Phase 1 authentication and authorization implementation for the Notifier service. ## New Files & Modules Created ### Core Authentication Package (`internal/auth/`) 1. **auth.go** - Core API key management - `APIKeyStore`: In-memory storage and validation of API keys - `APIKey`: Key metadata (client_id, roles, rate_limit, expiration, etc.) - `RateLimiter`: Per-key rate limiting with sliding window - `AuthContext`: Request context for authenticated calls - Key generation, validation, deactivation, and introspection 2. **rest_middleware.go** - REST API authentication - `RESTAuthMiddleware`: Middleware for HTTP requests - Supports `Authorization: Bearer ` and `X-API-Key: ` headers - Rate limit checking - Automatic audit logging 3. **grpc_middleware.go** - gRPC authentication - `GRPCAuthMiddleware`: Unary and stream interceptors - Extracts API key from gRPC metadata - Rate limit enforcement - Audit logging for all auth events 4. **authz.go** - Role-based access control - `NotifierAuthz`: Authorization rule management - Per-notifier type/account role restrictions - Flexible RBAC: empty allowed_roles = any authenticated user - Built-in role checking ### Configuration Updates 1. **internal/config/config.go** - Added `AuthConfig` struct with: - `enabled`: Toggle auth on/off (default: false) - `default_rate_limit`: Default rate limit for new keys (100 req/min) 2. **Notifier Config Structs** - Added role support to all notifiers: - `SMTPConfig.AllowedRoles` - `SlackConfig.AllowedRoles` - `NtfyConfig.AllowedRoles` - Each notifier can now restrict which roles can use it ### Integration Points 1. **api/rest/router.go** - New `NewRouterWithAuth()` function - Backward compatible: `NewRouter()` still works without auth - Auth middleware applied to all `/api/v1/*` routes except `/health` 2. **cmd/server/main.go** - Auth initialization on startup (if enabled) - Authorization rules registration from config - Pass auth store to both gRPC and REST servers - Graceful handling when auth is disabled ## Key Features ### 1. API Key Management ```go // Create API keys with: store := auth.NewAPIKeyStore() key, _ := store.CreateKey( "client-id", []string{"role1", "role2"}, 100, // rate limit: 100 req/min &expirationTime, // optional expiration ) // Validate keys key, err := store.ValidateKey(apiKeyString) // Check rate limits allowed, _ := store.CheckRateLimit(apiKeyString) // Manage keys store.UpdateLastUsed(apiKeyString) store.DeactivateKey(apiKeyString) store.ListKeys(clientID) ``` ### 2. Role-Based Access Control ```yaml # In config.yaml notifiers: smtp: default: ...config... allowed_roles: - "notify-email" - "admin" slack: default: ...config... allowed_roles: - "notify-slack" - "notify-all" ``` If `allowed_roles` is empty, any authenticated user can use the notifier. ### 3. Rate Limiting - Per-key rate limiting with sliding window - Configurable on per-key basis (0 = unlimited) - Automatically enforced at middleware level - Returns `429 Too Many Requests` when exceeded - Resets every 60 seconds ### 4. Audit Logging All auth events are logged: ```json { "timestamp": "2025-10-25T10:30:00Z", "event": "auth_success", "client_id": "billing-service", "method": "SendNotification", "remote_addr": "192.168.1.100" } ``` ## API Usage ### REST API ```bash # Request curl -X POST http://localhost:8080/api/v1/notifications \ -H "Authorization: Bearer nk_abc123..." \ -H "Content-Type: application/json" \ -d '{ "type": "email", ... }' # Or use X-API-Key header curl -X POST http://localhost:8080/api/v1/notifications \ -H "X-API-Key: nk_abc123..." \ -d '{ ... }' # Error responses 401 Unauthorized # Missing/invalid key 403 Forbidden # Role not allowed 429 Too Many Requests # Rate limit exceeded 401 Unauthorized (API key expired) # Key expiration check ``` ### gRPC API ```go import "google.golang.org/grpc/metadata" md := metadata.New(map[string][]string{ "authorization": {"bearer nk_abc123..."}, }) ctx := metadata.NewOutgoingContext(context.Background(), md) client.SendNotification(ctx, &pb.SendNotificationRequest{...}) // Error codes codes.Unauthenticated # Missing/invalid key codes.ResourceExhausted # Rate limit exceeded codes.PermissionDenied # Role not allowed ``` ## Configuration Examples ### Minimal (Auth Disabled - Default) ```yaml auth: enabled: false # Default behavior, no auth enforced notifiers: smtp: default: host: smtp.example.com ... ``` ### Basic (Auth Enabled, No Role Restrictions) ```yaml auth: enabled: true default_rate_limit: 100 notifiers: smtp: default: host: smtp.example.com ... allowed_roles: [] # All authenticated users slack: default: webhook_url: ... allowed_roles: [] # All authenticated users ``` ### Advanced (Multi-Tenant with Role Restrictions) ```yaml auth: enabled: true default_rate_limit: 100 notifiers: smtp: default: host: smtp.example.com ... allowed_roles: ["notify-email", "admin"] tenant-a: host: smtp-tenant-a.com ... allowed_roles: ["tenant-a-admin"] tenant-b: host: smtp-tenant-b.com ... allowed_roles: ["tenant-b-admin"] slack: default: webhook_url: ... allowed_roles: ["notify-all"] ``` ## Backward Compatibility - Auth is **disabled by default** - existing deployments continue to work unchanged - `NewRouter()` function still works without auth - All changes are additive - no existing APIs were modified - Notifier configs are backward compatible (allowed_roles is optional) ## Security Properties ### What's Protected - ✅ API endpoint access (all `/api/v1/*` routes) - ✅ gRPC service calls - ✅ Rate limit enforcement per key - ✅ Role-based notifier access - ✅ Expiration checking - ✅ Deactivation support - ✅ Audit logging ### What's Not Protected (Phase 1) - ❌ Health check endpoint (`/health`) - intentionally open - ❌ Key creation/management endpoints - requires external management - ❌ Admin operations - not implemented in Phase 1 - ❌ Key rotation - manual implementation required ### Credential Security - API keys are cryptographically random (32 bytes = 64 hex chars) - Recommended: store in environment variables or secrets manager - Not stored in plaintext in config files - Supports key expiration and deactivation - Per-key audit trail available via logs ## Testing the Implementation ### 1. Enable Auth in Config ```yaml auth: enabled: true default_rate_limit: 100 notifiers: stdout: true ``` ### 2. Create an API Key ```go store := auth.NewAPIKeyStore() key, _ := store.CreateKey("test-client", []string{"notify-all"}, 100, nil) fmt.Println(key.Key) ``` ### 3. Test REST API ```bash # With auth curl -H "Authorization: Bearer nk_" \ http://localhost:8080/api/v1/notifications # Without auth (should fail) curl http://localhost:8080/api/v1/notifications # 401 Unauthorized # Invalid key (should fail) curl -H "Authorization: Bearer invalid" \ http://localhost:8080/api/v1/notifications # 401 Unauthorized ``` ### 4. Test gRPC ```bash grpcurl -plaintext \ -H "authorization: bearer nk_" \ localhost:50051 notifier.v1.NotifierService/HealthCheck # Should return 200 OK if key is valid ``` ## Next Steps (Phase 2+) Recommended future enhancements: 1. **JWT Tokens** - Replace API keys with short-lived JWTs 2. **Key Rotation** - Automatic key rotation mechanism 3. **OAuth2 Integration** - Support OAuth2 for client credentials flow 4. **Admin API** - Key creation/management via API endpoints 5. **Vault Integration** - Direct HashiCorp Vault integration 6. **Metrics** - Prometheus metrics for auth events 7. **mTLS** - Mutual TLS authentication for gRPC 8. **Scopes** - Fine-grained permission scopes 9. **WebAuthn** - Hardware key support 10. **Audit Webhooks** - Send auth events to external systems ## File Structure ``` notifier/ ├── internal/ │ ├── auth/ │ │ ├── auth.go # Core API key management │ │ ├── rest_middleware.go # REST authentication │ │ ├── grpc_middleware.go # gRPC authentication │ │ └── authz.go # Authorization rules │ ├── config/ │ │ └── config.go # Updated with AuthConfig │ └── notifier/ │ ├── smtp.go # Updated with allowed_roles │ ├── slack.go # Updated with allowed_roles │ └── ntfy.go # Updated with allowed_roles ├── api/ │ └── rest/ │ └── router.go # Updated with auth support ├── cmd/ │ └── server/ │ └── main.go # Updated with auth initialization └── docs/ ├── AUTH.md # Comprehensive auth documentation ├── AUTH_QUICK_START.md # Quick start guide ├── CLIENT_RECOMMENDATIONS.md # Best practices for client developers └── IMPLEMENTATION_SUMMARY.md # This file ``` ## Code Statistics - **New files**: 4 (auth package) - **Modified files**: 5 (config, routers, main, notifier configs) - **Lines added**: ~700 (auth implementation) - **Lines added**: ~300 (documentation) - **Build status**: ✅ Compiles successfully - **Backward compatible**: ✅ Yes (auth disabled by default) ## Known Limitations 1. **In-Memory Storage** - API keys are lost on restart - Workaround: Re-create keys on startup or implement persistence 2. **No Key Management API** - Keys must be created programmatically - Phase 2: Implement admin API for key management 3. **No Token Revocation** - Only deactivation available - Keys can be deactivated but not selectively revoked 4. **Basic Rate Limiting** - Simple sliding window, not distributed - Not suitable for multi-instance deployments - Workaround: Use single instance or implement Redis-backed rate limiter 5. **No Metrics Export** - Auth events only logged, not exported - Phase 2: Add Prometheus metrics ## Support & Maintenance ### Troubleshooting 1. **Auth not working?** - Check `auth.enabled: true` in config - Verify API key format: `nk_<32-hex>` - Check role names match notifier `allowed_roles` 2. **Rate limit errors?** - Increase `default_rate_limit` in config - Create new key with higher rate limit - Wait 60 seconds for window to reset 3. **Key expired?** - Check `key.ExpiresAt` timestamp - Create new key with `expiresIn` parameter or nil ## References - **Authentication Package**: `internal/auth/` - **REST Router**: `api/rest/router.go:NewRouterWithAuth()` - **gRPC Server**: `cmd/server/main.go:startGRPCServer()` - **Full Documentation**: `docs/AUTH.md` - **Quick Start**: `docs/AUTH_QUICK_START.md` - **Client Guide**: `docs/CLIENT_RECOMMENDATIONS.md` ## Summary Phase 1 provides a solid foundation for authentication and authorization in the Notifier service: ✅ **Simple API Key Authentication** - Easy to implement and use ✅ **Rate Limiting** - Prevent abuse ✅ **Role-Based Access** - Fine-grained control ✅ **Audit Logging** - Security visibility ✅ **Backward Compatible** - Auth is optional ✅ **Well Documented** - Comprehensive guides for users and developers The implementation is production-ready for single-instance deployments and can be extended to support more advanced scenarios in future phases.