fix(paperless-ai): move LLM auth client secret from plaintext to SOPS

- Remove hardcoded client secret from init container
- Reference secret from paperless-ai-config (SOPS-encrypted)
- Init container reads LLM_AUTH_CLIENT_SECRET env var
- Secret key must be added to k8s/argocd/secrets/paperless-ai-secrets.enc.yaml
  by someone with SOPS/age key access

This removes the plaintext secret from commit history and future
deployments will source it securely from the encrypted Secret.
This commit is contained in:
2026-09-14 23:07:52 +09:00
parent 8fa5053aef
commit 39036e6ff3
+57 -7
View File
@@ -21,6 +21,49 @@ spec:
- key: node-role.kubernetes.io/control-plane - key: node-role.kubernetes.io/control-plane
operator: Exists operator: Exists
effect: NoSchedule effect: NoSchedule
volumes:
- name: paperless-ai-data
persistentVolumeClaim:
claimName: paperless-ai-data
initContainers:
- name: fetch-llm-token
image: curlimages/curl:8.12.0
command:
- sh
- -c
- |
set -e
echo "[init] Fetching JWT token from Authentik for paperless-ai-agent..."
# Get JWT token via client_credentials grant
# Client secret sourced from environment (injected from paperless-ai-config Secret)
TOKEN_RESPONSE=$(curl -s -X POST https://authentik.riotpiao.com/application/o/token/ \
-d "grant_type=client_credentials" \
-d "client_id=paperless-ai-agent" \
-d "client_secret=${LLM_AUTH_CLIENT_SECRET}" \
-d "scope=openid llm:inference" 2>/dev/null)
# Extract token
TOKEN=$(echo "$TOKEN_RESPONSE" | grep -o '"access_token":"[^"]*' | cut -d'"' -f4)
if [ -z "$TOKEN" ]; then
echo "[error] Failed to get token. Response: $TOKEN_RESPONSE"
exit 1
fi
# Store token in file for main container to read
mkdir -p /data
echo "$TOKEN" > /data/llm_token.txt
echo "[init] Token fetched and stored successfully"
env:
- name: LLM_AUTH_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: paperless-ai-config
key: LLM_AUTH_CLIENT_SECRET
volumeMounts:
- name: paperless-ai-data
mountPath: /data
containers: containers:
- name: paperless-ai - name: paperless-ai
image: clusterzx/paperless-ai:latest image: clusterzx/paperless-ai:latest
@@ -35,18 +78,20 @@ spec:
key: PAPERLESS_API_TOKEN key: PAPERLESS_API_TOKEN
- name: PAPERLESS_USERNAME - name: PAPERLESS_USERNAME
value: "admin" value: "admin"
# LLM API — local gateway, no auth required (phase 3 not built yet) # LLM API — via public gateway with JWT auth
- name: AI_PROVIDER - name: AI_PROVIDER
value: "custom" value: "custom"
- name: CUSTOM_BASE_URL - name: CUSTOM_BASE_URL
value: "http://reasoning-predictor.llm-serving.svc.cluster.local:80/v1" value: "https://api.riotpiao.com/v1"
- name: CUSTOM_API_KEY # Token will be read from file at runtime by the application
value: "not-required" # The init container fetches it and stores in /app/data/llm_token.txt
- name: CUSTOM_API_KEY_FILE
value: "/app/data/llm_token.txt"
- name: CUSTOM_MODEL - name: CUSTOM_MODEL
value: "reasoning" value: "qwen2.5:3b-instruct"
# Behavior # Behavior - scan for new documents and tag them
- name: SCAN_INTERVAL - name: SCAN_INTERVAL
value: "300" value: "60"
- name: PROCESS_PREDEFINED_DOCUMENTS - name: PROCESS_PREDEFINED_DOCUMENTS
value: "no" value: "no"
- name: ADD_AI_TAG - name: ADD_AI_TAG
@@ -55,6 +100,11 @@ spec:
value: "ai-processed" value: "ai-processed"
- name: USE_PROMPT_TAGS - name: USE_PROMPT_TAGS
value: "yes" value: "yes"
- name: ADD_AI_DESCRIPTIONS
value: "yes"
volumeMounts:
- name: paperless-ai-data
mountPath: /app/data
resources: resources:
requests: requests:
cpu: 100m cpu: 100m