Skip to content

Add Kubernetes Status Updates and Authentication Event Tracking - #81

Merged
KrisSimon merged 15 commits into
mainfrom
feature/kubectl-improvements
Nov 27, 2025
Merged

Add Kubernetes Status Updates and Authentication Event Tracking#81
KrisSimon merged 15 commits into
mainfrom
feature/kubectl-improvements

Conversation

@KrisSimon

Copy link
Copy Markdown
Contributor

Summary

This PR adds comprehensive Kubernetes status subresource support for both Tenant and Client CRDs, along with a centralized authentication event handling system. Key improvements include:

  • Kubernetes Tenant Status - Real-time metrics in kubectl get tenants showing client count, active sessions, and tenant phase
  • Kubernetes Client Status - Real-time metrics in kubectl get clients showing active sessions, denied attempts, and last authentication timestamp
  • Centralized Authentication Events - New AuthEventActor consolidates Prometheus metrics and status updates for login/logout events
  • Session Tracking for Interceptor Mode - Interceptor logins now create session entries for accurate counting
  • Enhanced AuthCodeStorage Protocol - Added tenant-specific session counting methods

Changes

New Features

  • Tenant CRD status subresource with automatic updates on authentication events
  • Client CRD status subresource with session tracking and denied attempts counter
  • AuthEventActor for centralized event handling (fixes Refactoring – Consolidate Auth Events in Actor #78)
  • Session storage for interceptor mode authentication flows
  • E2E test --hold option for debugging failed tests

Bug Fixes

  • Fixed Redis session counting to handle LoginSession objects gracefully
  • Fixed denied login attempts tracking to properly record failed authentications
  • Fixed client session counting to use client_id instead of name
  • Fixed Client.find call with correct parameter name

Infrastructure

  • Added RBAC permissions for clients/status and tenants/status updates
  • Enhanced CRD schemas with status subresources
  • Added diagnostic logging for Kubernetes status updates

Test Plan

  • Unit tests for tenant status updates (TenantStatusUpdateTest)
  • Unit tests for client status updates (ClientStatusUpdateTest)
  • Unit tests for client status initialization (ClientStatusInitializationTest)
  • Unit tests for AuthEventActor (AuthEventActorTests)
  • E2E tests pass with new status updates
  • Verified kubectl get tenants shows real-time metrics
  • Verified kubectl get clients shows real-time metrics
  • Manual testing of login/logout flows with status verification

Documentation

Changelog entries added in CHANGELOG.md for version 0.10.2.

Files Changed

28 files changed with 1,916 insertions and 27 deletions:

  • New: AuthEventActor.swift - Centralized authentication event handling
  • New: AuthCodeStorage.swift - Protocol enhancements for session counting
  • Modified: LoginController.swift, LogoutController.swift - Integrated with AuthEventActor
  • Modified: EntityCRDLoader.swift, EntityLoader.swift - Status update logic
  • Modified: CRD templates and RBAC configuration
  • New: Comprehensive test suite for status updates

This commit implements status tracking for Tenant CRDs in Kubernetes,
displaying client count and active user sessions in kubectl output.

Features:
- Added status subresource to Tenant CRD with additionalPrinterColumns
- Extended AuthCodeStorage with tenant-specific session counting
- Implemented session tracking for interceptor mode logins
- Automatic status updates on token creation, logout, and client changes
- Added RBAC permissions for status subresource updates

Fixes:
- Fixed Redis session counting to handle mixed key types gracefully
- RedisAuthCodeStorage.count() now skips LoginSession objects correctly

Testing:
- Added comprehensive TenantStatusUpdateTest suite with 4 test cases
- Verified session counting accuracy across different scenarios
This commit fixes a critical issue where tenant session counts
were not decremented after user logout, causing incorrect active
session reporting in Kubernetes CRD status.

Root Cause:
- Redis wipe() and count() functions attempted to decode ALL Redis
  keys as AuthSession objects, including loginid~ keys which are
  LoginSession objects
- LoginSession lacks the 'type' field, causing decoding to fail
- Silent error handling prevented session deletion
- Race condition: triggerStatusUpdate ran asynchronously

Changes:
- AuthCodeStorage+RedisImpl.swift:
  * Add prefix check to skip loginid~ keys before decoding
  * Add comprehensive debug logging for wipe and count operations
  * Track sessions being wiped and counted

- AuthCodeStorage+MemoryImpl.swift:
  * Add debug logging for session storage, wipe, and count
  * Log session details (type, tenant, subject) for debugging

- LogoutController.swift:
  * Add session count logging before and after wipe
  * Track session count changes during logout flow

- EntityLoader.swift:
  * Make triggerStatusUpdate() async (was creating detached Task)
  * Ensure status update waits for wipe completion
  * Fix race condition between wipe and count

Result:
- Session counts now correctly decrement to 0 after logout
- Kubernetes CRD status reflects accurate active session counts
- All 344 tests pass
Implement comprehensive status tracking for Client CRDs, displaying:
- Active session counts per client (based on audience claim)
- Denied login attempts per client
- Status phase and last update timestamp

Changes:
- Update Client CRD YAML with status subresource and printer columns
  - Added Tenant, Sessions, Denied, Status, Age columns to kubectl output
  - Defined status schema with phase, activeSessions, deniedAttempts fields

- Add ClientStatus struct and StatusHavingResource conformance
  - Implement status update mechanism in EntityCRDLoader
  - Extract namespace from tenant name for K8s operations

- Implement session counting by client identifier
  - Add count(client:type:) to AuthCodeStorageProtocol
  - Implement for both Memory and Redis storage backends
  - Match sessions by audience claim (client_id in OAuth2)
  - Support multiple clients in single session audience

- Add denied login tracking system in EntityStorage
  - Track failed login attempts per client name
  - Provide increment and query methods

- Trigger status updates when clients are added/modified
  - Update client status after creation
  - Update parent tenant status when client changes

- Add comprehensive test suite (6 tests)
  - Session count increases after token creation
  - Session count is client-specific
  - Multiple clients in audience handling
  - Refresh vs authorization code filtering
  - Denied login attempts tracking
  - Client-specific denied attempts isolation

All 789 tests passing. No linter violations.
Add status updates for all Kubernetes entities after authCodeStorage is set.

Problem:
- EntityLoader starts loading entities immediately on creation
- authCodeStorage is set afterwards in configure.swift
- Initial status updates fail because authCodeStorage is nil
- Result: Client status columns remain empty on startup

Solution:
- Add updateAllKubernetesStatuses() method to EntityLoader
- Triggered automatically when setAuthCodeStorage() is called
- Iterates through all existing Kubernetes tenants and clients
- Updates their status with current session counts and metrics

Changes:
- Add isKubernetes property to EntityResourceReference
- Add updateAllKubernetesStatuses() to EntityLoader
- Call status updates in setAuthCodeStorage()

This ensures clients show correct session counts and status
immediately after startup, not just after configuration changes.
Add unit tests to verify client status tracking works correctly:
- Session counting per client based on audience claim
- Denied login attempts tracking per client
- Multiple clients with different session counts

All 791 tests passing.
Allow keeping the Kubernetes cluster running after e2e tests complete
for manual inspection and testing.

Usage:
  ./tooling.sh e2e --dirty --fast --hold

When --hold is used:
- Tests run normally
- Cluster stays up after tests complete
- User gets instructions for kubectl commands
- User must press ENTER to delete cluster

This is useful for:
- Debugging failed tests
- Manual verification of deployments
- Inspecting Kubernetes resources after tests
- Testing kubectl commands against live cluster
The Uitsmijter service account needs permission to update the clients/status
subresource in order to populate client metrics (sessions, denied, status).

This adds clients/status to the ClusterRole alongside the existing
tenants/status permission.
The count() method was incorrectly matching sessions by client.name instead
of client_id (UUID). The audience in JWT payloads contains the client_id,
not the client name.

This fixes client session counting in both Memory and Redis implementations,
which is required for displaying accurate SESSIONS counts in kubectl output.

Fixed in:
- AuthCodeStorage+MemoryImpl.swift
- AuthCodeStorage+RedisImpl.swift
Remove verbose diagnostic logging that was added for debugging.
Keep only essential INFO and DEBUG level logs.
Previously, status updates were only triggered for interceptor mode logins
and only updated tenant status. Now:

1. Status updates are triggered for ALL login modes (both interceptor and OAuth)
2. Both tenant AND client status are updated on login/logout/token creation
3. Added convenience method triggerStatusUpdate(for:client:) to EntityLoader

This ensures that client session counts are accurately reflected in kubectl
output for all authentication flows.

Changes:
- EntityLoader.swift: Add triggerStatusUpdate(for:client:) overload
- LoginController.swift: Move status update outside interceptor-only block
- LogoutController.swift: Pass client to status update
- TokenController+TokenGrantTypeRequestHandler.swift: Find and pass client
Use clientId: instead of withId:for: to match the actual method signature.
This commit introduces a new AuthEventActor that consolidates authentication
event handling (login success/failure, logout) by combining Prometheus metrics
recording and entity status updates into a single, reusable component.

Changes:
- Add AuthEventActor with three methods:
  - recordLoginSuccess(): Records login success metrics and triggers status updates
  - recordLoginFailure(): Records login failure metrics, increments denied attempts counter, and triggers client status updates
  - recordLogout(): Records logout metrics and triggers status updates

- Add Application+AuthEventActor extension for dependency injection via Vapor's storage system

- Refactor LoginController to use AuthEventActor:
  - Replace duplicate Prometheus + status update calls in canNotLoginResponse()
  - Replace duplicate calls in renderSuccess()

- Refactor LogoutController to use AuthEventActor:
  - Replace Prometheus metric call in doLogout()

- Add comprehensive unit tests in AuthEventActorTests covering all event types

- Update CHANGELOG.md with feature documentation

This eliminates code duplication across LoginController and LogoutController
while ensuring consistent event tracking throughout the authentication flow.

Fixes #78
This commit fixes test cases to use the correct client identifier (client_id/UUID)
instead of client name when creating JWT payloads for session tracking.

Changes:
- Update ClientStatusInitializationTest to use client.config.ident.uuidString in audience claims
- Update ClientStatusUpdateTest to use client.config.ident.uuidString in audience claims
- Fix trailing whitespace in Cheese tenant YAML configuration

The audience claim in JWT tokens must contain the client's UUID (client_id) rather
than the client's name, as this is what the session counting logic uses to match
sessions to clients.
@KrisSimon KrisSimon linked an issue Nov 27, 2025 that may be closed by this pull request
5 tasks
@KrisSimon KrisSimon self-assigned this Nov 27, 2025
@KrisSimon KrisSimon linked an issue Nov 27, 2025 that may be closed by this pull request
@KrisSimon KrisSimon added the enhancement New feature or request label Nov 27, 2025
@KrisSimon KrisSimon added this to the 0.10.2 milestone Nov 27, 2025
@KrisSimon
KrisSimon merged commit 50eeea9 into main Nov 27, 2025
15 of 16 checks passed
@KrisSimon
KrisSimon deleted the feature/kubectl-improvements branch November 27, 2025 11:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Kubernetes CRDs: More information on resources Refactoring – Consolidate Auth Events in Actor

1 participant