Files
poimen-memory/k8s/app/deployment.yaml
T
rock 16e3ff16f1
CI / CI (pull_request) Successful in 3m40s
feat: authentik jwt + sops encryption for prod secrets & llm auth
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
2026-09-08 13:58:39 -07:00

118 lines
3.4 KiB
YAML

# Poimen Memory API Server
# Serves 7 HTTP endpoints for memory ingest, query, and management.
# Connects to memory-db (pgvector) for persistent storage.
apiVersion: apps/v1
kind: Deployment
metadata:
name: poimen-memory
namespace: poimen
labels:
app.kubernetes.io/name: poimen-memory
app.kubernetes.io/component: api-server
spec:
replicas: 2
selector:
matchLabels:
app.kubernetes.io/name: poimen-memory
template:
metadata:
labels:
app.kubernetes.io/name: poimen-memory
spec:
serviceAccountName: poimen-memory
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 999
fsGroup: 999
seccompProfile:
type: RuntimeDefault
containers:
- name: memory
image: forgejo.riotpiao.com/riotpiao-poimen/poimen-memory:latest
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
imagePullPolicy: Always
ports:
- containerPort: 8080
name: http
env:
# Database connection (from CNPG auto-generated secret)
- name: DATABASE_HOST
value: "memory-db-rw.poimen.svc.cluster.local"
- name: DATABASE_PORT
value: "5432"
- name: DATABASE_NAME
value: "memory"
- name: DATABASE_USER
valueFrom:
secretKeyRef:
name: memory-db-app
key: username
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: memory-db-app
key: password
- name: DATABASE_URL
value: "postgresql://$(DATABASE_USER):$(DATABASE_PASSWORD)@$(DATABASE_HOST):$(DATABASE_PORT)/$(DATABASE_NAME)?sslmode=disable"
# LLM Gateway API key
- name: MEM_API_KEY
valueFrom:
secretKeyRef:
name: poimen-memory-secrets
key: llm-api-key
# Server config (from ConfigMap)
- name: MEM_PORT
value: "8080"
- name: MEM_HOME
value: "/tmp"
envFrom:
- configMapRef:
name: poimen-memory-config
- secretRef:
name: poimen-memory-auth
- secretRef:
name: poimen-memory-secrets
args:
- serve
- --port
- "8080"
- --api-key
- "$(MEM_API_KEY)"
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
livenessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 5
periodSeconds: 10
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir:
sizeLimit: 64Mi
# Tolerate control-plane nodes
tolerations:
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule