Files
homelab-frontend/tasks/3.1-auth-sqs-jwt-validation.md
T
Admin Bot 55b32b97e0
CI / Vet, test, build (push) Successful in 2m11s
CI / Build and push image (push) Successful in 42s
mark: Phase 8.2, 8.10 GREEN; create Phase 3 auth tasks
PHASE 8 COMPLETE (10/10 tasks):
- 8.2: X-Service/X-Resource dispatcher 
- 8.10: Phase gate - all 5 services routing 

Architecture decisions documented:
- Gateway = dumb pipe (Option B)
- SQS: gateway validates JWT (code unverified)
- MinIO, Temporal: native JWT support
- Memory, IAM: service-owned validation
- ConfigMap-based config with Stakater Reloader
- Real integration tests with cluster services

PHASE 3 (Auth) TASKS CREATED (0/3 TODO):
- 3.1: SQS JWT validation vs Authentik JWKS
- 3.2: MinIO native JWT load-test
- 3.3: Temporal JWT jwtKeyProvider configuration

Updates:
- tasks/8.2-x-service-dispatcher.md: marked GREEN
- tasks/8.10-serviceadapter-gate.md: marked GREEN with notes
- tasks/3.1-3.3: new Phase 3 auth tasks
- tasks/INDEX.md: Phase 8 complete, Phase 3 active
2026-08-27 11:36:13 -07:00

2.3 KiB

3.1 — SQS: Gateway JWT validation against Authentik JWKS

Phase: 3 — Authentication & Authorization Stage: TODO Depends on: 8.2 (X-Service dispatcher), 8.10 (gate)

Context

SQS (kmsvc management-service) has placeholder env vars for JWT validation:

  • KMSVC_AUTHENTIK_ISSUER_URL
  • KMSVC_AUTHENTIK_AUDIENCE

But kmsvc code is unverified — we don't know if it actually validates JWTs. Phase 8.2 decision: Gateway validates SQS JWTs at ingress (not pushing to kmsvc).

Requirements

  • Gateway extracts Authorization: Bearer <token> from SQS requests
  • Validates JWT signature against Authentik JWKS endpoint:
    • Issuer: https://authentik.riotpiao.com/application/o/sqs/
    • JWKS: https://authentik.riotpiao.com/application/o/sqs/jwks/
    • Algorithm: RS256 only (no alg confusion)
  • Verifies claims:
    • iss matches expected issuer
    • aud equals sqs
    • exp not exceeded
    • nbf not in future (60s clock skew)
  • Checks permissions claim contains sqs:read or sqs:write (or wildcard *)
  • Returns 403 with details on validation failure
  • Caches JWKS with 15min TTL, refreshes on kid miss (key rotation)
  • Integration test: Get real JWT from Authentik, call SQS endpoint, confirm 200

Implementation

  1. Add JWT validator to internal/auth/jwt.go (was removed, restore as Phase 3 work)
  2. Wire into internal/serviceadapter/router.go Dispatcher for SQS only
  3. Update k8s/configmap.yaml SQS auth.required: true + capability check
  4. Add test to internal/serviceadapter/real_integration_test.go

Verification

# Get JWT from Authentik
export JWT=$(curl -s -X POST https://authentik.riotpiao.com/application/o/token/ \
  -d "grant_type=client_credentials&client_id=<id>&client_secret=<secret>&scope=openid" \
  | jq -r '.access_token')

# Should succeed
curl -w '%{http_code}' -H "Authorization: Bearer $JWT" \
  -H 'X-Service: sqs' -H 'X-Resource: send-message' \
  https://api.riotpiao.com/

# Should 403
curl -w '%{http_code}' -H 'X-Service: sqs' -H 'X-Resource: send-message' \
  https://api.riotpiao.com/
# expected: 403

Notes

  • Not Phase 8.2: Phase 8 was about routing & dispatcher architecture
  • Phase 3 scope: Full auth integration & JWT validation
  • MinIO/Temporal: Have native JWT support, tested in Phase 3 separately
  • Memory/IAM: Services validate own JWTs (dumb pipe)