feat: authentik jwt + sops encryption for prod secrets & llm auth
CI / CI (pull_request) Successful in 3m40s

SECURITY:
- Add authentik_jwt.rs: OAuth2 client credentials flow with caching
- SOPS encrypt secrets with age key (SOPS_AGE_KEY_FILE)
- JWT tokens for LLM gateway, S3, and API gateway access
- Token auto-refresh when expired (60s before expiry)
- No hardcoded credentials in code or config

ENTITY EXTRACTION:
- LlmEntityExtractor now uses Authentik JWT instead of mock
- Fallback to env var if Authentik not configured
- Reflection verification still enabled
- WikiLink extraction as Stage 0 (always active)

DEPLOYMENT:
- ConfigMap: LLM_ENDPOINT, LLM_MODEL, timeouts
- Secret: AUTHENTIK_ISSUER, CLIENT_ID, CLIENT_SECRET, S3 keys
- envFrom mounts both ConfigMap and Secret
- KSOPS plugin for ArgoCD auto-decryption

DOCUMENTATION:
- docs/AUTHENTIK_SOPS_SETUP.md: Complete integration guide
- Service account creation in Authentik
- SOPS encryption/decryption workflow
- JWT token exchange flow
- Troubleshooting guide

FILES:
- crates/mem-ingest/src/authentik_jwt.rs (new, 180 LOC)
- crates/mem-ingest/src/entity_extractor.rs (updated, JWT auth)
- crates/mem-ingest/Cargo.toml (add reqwest)
- k8s/app/poimen-memory-secrets.yaml (new, unencrypted template)
- k8s/app/deployment.yaml (add secrets envFrom)
- k8s/app/config.yaml (add LLM config)
- k8s/.sops.yaml (encryption rules)
- docs/AUTHENTIK_SOPS_SETUP.md (new, 350 LOC)

NEXT:
1. Create Authentik service account (manual)
2. Encrypt secrets with SOPS
3. Deploy to poimen namespace
4. Test JWT token exchange with LLM endpoint
This commit is contained in:
2026-09-08 13:58:39 -07:00
parent 800d9d8ae2
commit 16e3ff16f1
11 changed files with 607 additions and 7 deletions
+5
View File
@@ -21,3 +21,8 @@ data:
OPENSEARCH_HOST: "opensearch.poimen.svc.cluster.local:9200"
# Obsidian
OBSIDIAN_URL: "http://obsidian-server.poimen.svc.cluster.local:8080"
# LLM Configuration (for entity extraction)
LLM_ENDPOINT: "http://api-internal.riotpiao.com:8000/v1/chat/completions"
LLM_MODEL: "qwen:7b"
LLM_TIMEOUT_SECS: "30"
ENABLE_LLM_EXTRACTION: "true"
+2
View File
@@ -76,6 +76,8 @@ spec:
name: poimen-memory-config
- secretRef:
name: poimen-memory-auth
- secretRef:
name: poimen-memory-secrets
args:
- serve
- --port
+24
View File
@@ -0,0 +1,24 @@
apiVersion: v1
kind: Secret
metadata:
name: poimen-memory-auth
namespace: poimen
labels:
app.kubernetes.io/name: poimen-memory
type: Opaque
stringData:
# Authentik Service Account - OAuth2 client credentials
# These are obtained from Authentik admin panel:
# Settings → Applications → poimen-memory → Service Account
AUTHENTIK_ISSUER: "https://authentik.riotpiao.com/application/o/memory"
AUTHENTIK_AUDIENCE: "poimen-memory"
AUTHENTIK_CLIENT_ID: "${AUTHENTIK_SERVICE_ACCOUNT_CLIENT_ID}"
AUTHENTIK_CLIENT_SECRET: "${AUTHENTIK_SERVICE_ACCOUNT_SECRET}"
# LLM API Key
# Generated by Authentik service account with permissions to LLM gateway
LLM_API_KEY: "${LLM_API_KEY_FROM_AUTHENTIK}"
# S3 Credentials for backups (Velero)
S3_ACCESS_KEY: "${MINIO_ACCESS_KEY}"
S3_SECRET_KEY: "${MINIO_SECRET_KEY}"