Author SHA1 Message Date
rock 44d5207622 fix(gotify): remove configuration-snippet annotation blocking nginx ingress
nginx-ingress v1.15.1 blocks configuration-snippet by default as a
security risk, silently dropping the entire Ingress resource. WebSocket
upgrade headers are handled natively with proxy-http-version 1.1.
2026-09-15 18:01:48 +09:00
rock 7a239b2469 feat: add gotify.riotpiao.com coredns rewrite for mobile app access 2026-09-15 17:23:21 +09:00
rock 795cef5a85 feat(prometheus): scale up storage to 100Gi and move to worker-1
- Increase PVC from 20Gi to 100Gi (talos-cp-1 disk full)
- Move from az-a (talos-cp-1) to worker-1 (648GB available)
- Increase retention from 15d to 30d (95GB limit)
- Fixes Prometheus pod restarts due to disk pressure
2026-09-15 08:16:01 +09:00
rock c1a2dbf52a fix(minio): add BROWSER_REDIRECT_URL to enable SSO button in Console
- Add MINIO_BROWSER_REDIRECT_URL pointing to public URL
- Add MINIO_BROWSER_LOGIN_ANIMATION=off
- Enables Console to show OIDC/Authentik SSO button on login page
2026-09-15 02:44:09 +09:00
rock 0f854f2bfa feat(minio): use groups claim for OIDC auth instead of policy
- Change MINIO_IDENTITY_OPENID_CLAIM_NAME from 'policy' to 'groups'
- Add MINIO_IDENTITY_OPENID_CLAIM_PREFIX (empty) to use raw group names
- Update scopes to 'openid,profile,email,groups'
- Enables Authentik group-based access (homelab-admins, minio-admins, etc)
- Users in homelab-admins group will get admin access to MinIO
2026-09-15 02:40:02 +09:00
rock 283d30b422 fix(paperless): use correct env var PAPERLESS_SOCIAL_AUTO_SIGNUP for auto-linking
The correct env var is PAPERLESS_SOCIAL_AUTO_SIGNUP not PAPERLESS_SOCIALACCOUNT_AUTO_SIGNUP
This enables automatic linking of Authentik social accounts to existing Paperless users
2026-09-15 02:30:12 +09:00
rock 2b2ceab2d1 fix(paperless): enable OIDC auto-linking to existing users by email
- Add SOCIALACCOUNT_AUTO_SIGNUP for automatic social account creation
- Enable ACCOUNT_ALLOW_SIGNUPS for OIDC users
- Add SOCIALACCOUNT_EMAIL_AUTHENTICATION_AUTO_CONNECT to link existing users
- Fixes 'An account already exists with this email' error
- Allows Authentik login to auto-link to existing Paperless users
2026-09-15 02:00:36 +09:00
rock 6243ac40b7 feat(paperless-ai): enable intelligent timeline tagging with date extraction
- Add ENABLE_INTELLIGENT_TAGGING for advanced AI-powered tagging
- Add ENABLE_DATE_EXTRACTION for automatic date/timeline parsing
- Add ENABLE_TIMELINE_TAGGING to create temporal tags (YYYY, Q#-YYYY, Last-Month, etc)
- Set TAG_EXTRACTION_MODEL to reasoning for sophisticated analysis
- Configure timeline granularity (year, quarter, month)
- Add custom prompt for temporal context extraction
- Auto-create tags for historical and recent documents
2026-09-15 00:53:30 +09:00
rock d6fca68f33 chore(paperless-ai): switch LLM model to reasoning for document processing 2026-09-15 00:38:37 +09:00
rock e12327f963 fix(grafana): re-enable org role sync for OAuth groups
Re-enable skip_org_role_sync=false to sync Admin role from grafana-admins group.
User creation worked with skip_org_role_sync=true, now restore role sync.
2026-09-15 00:37:06 +09:00
rock b03098aa1c fix(grafana): skip_org_role_sync on first login
Set skip_org_role_sync=true to allow user creation on first OAuth signin.
When false, Grafana tries to sync org roles before user exists, causing creation to fail.
2026-09-15 00:32:41 +09:00
rock f61e8f1f68 fix(grafana): use preferred_username for OAuth login lookup
Reverts to standard OpenID 'preferred_username' claim which is guaranteed to be present in all userinfo responses. The 'email' claim requires explicit scope mapping in Authentik that may not be consistently returned.

Authentik user 'rock' has preferred_username='rock' which matches the existing Grafana user login.
2026-09-15 00:17:50 +09:00
rock 7016f764e6 infrastructure(paperless): add paperless-ai production ConfigMap to git
- Commit paperless-ai-config.yaml with production environment variables
- Configure Paperless API endpoint and token
- Enable AI processing with qwen2.5:3b model
- Set up auto-tagging, correspondent/document type extraction
- Configure 60s scan interval for document processing
- Add ConfigMap to kustomization.yaml for GitOps deployment
2026-09-15 00:14:42 +09:00
rock d826510a98 feat(paperless-ai): configure for production with Paperless API + LLM integration
- Add ConfigMap with production paperless-ai config
- Mount .env config file for app startup
- Enable auto-tagging, correspondent extraction, document type detection
- Set LLM API endpoint and token file location
- Configure 60s scan interval for document processing
2026-09-15 00:13:02 +09:00
rock 467b3441c9 fix(grafana): use email for OAuth login lookup instead of preferred_username
- Change login_attribute_path from preferred_username to email for stable user matching
- Enable allow_sign_up to permit OAuth user sync with existing local users
- Root cause: Authentik's 'rock' user matches existing Grafana 'rock' by email, not by preferred_username claim
2026-09-15 00:01:10 +09:00
rock 7e91262257 fix(paperless-ai): write token to /tmp as fallback (PVC mount perms) 2026-09-14 23:58:41 +09:00
rock 0edd6bc73a fix(paperless-ai): use /app/data mount path consistently for init + main container 2026-09-14 23:57:44 +09:00
rock 4ad0102260 fix(paperless-ai): fix sed token extraction to handle JSON spaces 2026-09-14 23:56:33 +09:00
rock e0c08a90b3 Grafana OAuth: disable allow_sign_up to debug user.sync failure 2026-09-14 23:56:04 +09:00
rock dfbe2cc920 fix(paperless-ai): use sed for JWT token extraction (jq not available) 2026-09-14 23:55:53 +09:00
rock ae93c7ca0d fix(paperless-ai): use jq for JWT token extraction instead of grep 2026-09-14 23:54:57 +09:00
rock 91ce48ffae fix(sops): add LLM_AUTH_CLIENT_SECRET for paperless-ai-agent Authentik auth 2026-09-14 23:19:43 +09:00
10 changed files with 107 additions and 35 deletions
+2 -4
View File
@@ -6,11 +6,9 @@ metadata:
annotations:
nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
# WebSocket support for Gotify client connections
# WebSocket support for Gotify client connections (/stream endpoint)
# nginx-ingress handles Upgrade/Connection headers natively with http/1.1
nginx.ingress.kubernetes.io/proxy-http-version: "1.1"
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
spec:
ingressClassName: nginx
rules:
+4
View File
@@ -20,3 +20,7 @@ data:
# wire up allauth's confirm-email view, so signup 500s with NoReverseMatch
# on 'account_confirm_email' without this.
PAPERLESS_ACCOUNT_EMAIL_VERIFICATION: "none"
# Auto-connect social accounts to existing users with matching email
PAPERLESS_SOCIAL_AUTO_SIGNUP: "true"
# Allow automatic linking of social accounts to existing users
PAPERLESS_ACCOUNT_ALLOW_SIGNUPS: "true"
+1
View File
@@ -4,6 +4,7 @@ namespace: paperless
resources:
- pvc.yaml
- configmap.yaml
- paperless-ai-config.yaml
- redis.yaml
- deployment.yaml
- service.yaml
@@ -0,0 +1,49 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: paperless-ai-env
namespace: paperless
data:
paperless-ai-config.env: |
# Paperless-NGX API configuration
PAPERLESS_URL=http://paperless.paperless.svc.cluster.local:8000
PAPERLESS_API_TOKEN=7b89463e04c141f4172fbcddf78d623547d327ec
# AI Processing settings
ENABLE_AI_PROCESSING=yes
AI_MODEL=reasoning
LLM_API_URL=https://api.riotpiao.com/v1
LLM_API_TOKEN_FILE=/app/data/llm_token.txt
# Auto-tagging configuration
ENABLE_AUTO_TAGGING=yes
ENABLE_CORRESPONDENT_EXTRACTION=yes
ENABLE_DOCUMENT_TYPE_EXTRACTION=yes
ENABLE_TITLE_GENERATION=yes
# Advanced tagging with AI
ENABLE_INTELLIGENT_TAGGING=yes
ENABLE_DATE_EXTRACTION=yes
ENABLE_TIMELINE_TAGGING=yes
AUTO_CREATE_TAGS=yes
# Tagging prompts for custom extraction
CUSTOM_EXTRACTION_PROMPT=Extract document date, time period, financial year, and temporal context. Create tags like YYYY, Q1-YYYY, Last-Month, Current-Year, Historic
TAG_EXTRACTION_MODEL=reasoning
# Scanning behavior
SCAN_INTERVAL_SECONDS=60
PROCESS_EXISTING_DOCUMENTS=no
ADD_AI_TAG=yes
AI_TAG_NAME=ai-processed
# Date/Timeline tagging configuration
DATE_EXTRACTION_FORMAT=iso8601
TIMELINE_TAG_GRANULARITY=year,quarter,month
AUTO_TAG_HISTORICAL=yes
AUTO_TAG_RECENT=yes
# Performance
MAX_CONCURRENT_REQUESTS=2
REQUEST_TIMEOUT=60
DATE_EXTRACTION_TIMEOUT=30
+19 -6
View File
@@ -25,9 +25,15 @@ spec:
- name: paperless-ai-data
persistentVolumeClaim:
claimName: paperless-ai-data
- name: paperless-ai-env-config
configMap:
name: paperless-ai-env
initContainers:
- name: fetch-llm-token
image: curlimages/curl:8.12.0
securityContext:
runAsUser: 0
fsGroup: 0
command:
- sh
- -c
@@ -43,8 +49,8 @@ spec:
-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)
# Extract token from JSON response using sed (handles spaces after colons)
TOKEN=$(echo "$TOKEN_RESPONSE" | sed -n 's/.*"access_token"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')
if [ -z "$TOKEN" ]; then
echo "[error] Failed to get token. Response: $TOKEN_RESPONSE"
@@ -52,9 +58,13 @@ spec:
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"
# Write to both locations for compatibility
mkdir -p /tmp/llm-token /app/data 2>/dev/null || true
echo "$TOKEN" | tee /tmp/llm-token/llm_token.txt > /dev/null 2>&1
echo "$TOKEN" > /app/data/llm_token.txt 2>/dev/null || true
echo "[init] Token fetched and stored"
[ -f /tmp/llm-token/llm_token.txt ] && echo " -> /tmp/llm-token/llm_token.txt"
[ -f /app/data/llm_token.txt ] && echo " -> /app/data/llm_token.txt"
env:
- name: LLM_AUTH_CLIENT_SECRET
valueFrom:
@@ -63,7 +73,7 @@ spec:
key: LLM_AUTH_CLIENT_SECRET
volumeMounts:
- name: paperless-ai-data
mountPath: /data
mountPath: /app/data
containers:
- name: paperless-ai
image: clusterzx/paperless-ai:latest
@@ -105,6 +115,9 @@ spec:
volumeMounts:
- name: paperless-ai-data
mountPath: /app/data
- name: paperless-ai-env-config
mountPath: /app/data/.env
subPath: paperless-ai-config.env
resources:
requests:
cpu: 100m
@@ -1,23 +1,24 @@
apiVersion: ENC[AES256_GCM,data:l7I=,iv:NZY7r3JVW3zVwxeiScvWKpAQUDa9+nckHd0qWVrGU88=,tag:qpowp5OILdYKtTux/nlWpg==,type:str]
kind: ENC[AES256_GCM,data:6oeEbuIk,iv:5flI9TtcYQ961wOYPBPhvQpitHFYAf8yMdNBXqytbJs=,tag:WNhlbKmSeZEqZ9ZgiB/BYg==,type:str]
apiVersion: v1
kind: Secret
metadata:
name: ENC[AES256_GCM,data:fvJMsgy+wPZqMCdxm9hoV3n/+Q==,iv:I3rVtHIJBOME+bxhPws58Zjhj5i+KT5UtB9o7Vus5EU=,tag:6h4FnUu7PGxlQPIQxPYCRg==,type:str]
namespace: ENC[AES256_GCM,data:CDriLoLovROW,iv:rHXcN1xm5+t2D/Tq/2sx9lQFF8anD5jH24ZntPuBA8U=,tag:XstJAz6S8IM1c/pp9Cg0Ww==,type:str]
type: ENC[AES256_GCM,data:JdTwBbag,iv:9Ys15Ketl0ghNK0u0N8IOpUt7+KoloutiG5M9zHPXxw=,tag:teau/udf41Ty34A5wLAm6Q==,type:str]
name: paperless-ai-config
namespace: paperless
type: Opaque
stringData:
PAPERLESS_API_TOKEN: ENC[AES256_GCM,data:TuQeDx8po3h4loTRABlItVYQJ7gFjnmIn3zQQGtUcoNFMKpkqLK/GQ==,iv:TDg0stpca5pDtatqu8DFU7R0Bm/S/BI9ZoiG4K8mCT4=,tag:BfjX25V5gL7AeIsscClRAg==,type:str]
PAPERLESS_API_TOKEN: ENC[AES256_GCM,data:wlBC85ep6zioWLhfhNczkKfTMR8tmciN+4r3of8GpQoJmKyE2r7pOg==,iv:Rem/UJl5wUNi8G+uEV7f2eCLabaY26sZ7+AsKYiOZ4I=,tag:bGS1fu13Mwsrr+5NUEzzLw==,type:str]
LLM_AUTH_CLIENT_SECRET: ENC[AES256_GCM,data:co7FfmRXKgrz9fNgR10KtlHL/iG4F5WKJgjcKem1H5hF5FviVi4+CQNekA==,iv:ADtBHiI6BtrkuH1iIfKV3I5odNLMQe5y/9GGTJrPNN0=,tag:j6wX6zO5VhKoLzdr7BQZCw==,type:str]
sops:
age:
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBKVDN3aFVqVmFXY1VQVXZP
OUsrNHdNdlRvRFgvTDQrNE5uL2xaazVENTBjCkNPbGR5Vk16RXNDOW15OGNTRmFR
U0JOeTllaWU1dzNVY3lBbEVyVG5tOEkKLS0tIEZvajlvcUtJdFNNUkkzV3FKOFRj
UUE2TDBzT0xVc2E1NlUvQXAyZytMZEUKBv+ChaoQCstA742L3Bq5mBJlW/UC4Pyw
ZvFAyYbs1NaEqhjtHq+4T62jTWcH/St/vKgUuFQ9LCUQhYd8DUzAow==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBJWDZwTE1haUY5ZkgybnBx
WEFVSzQvNjlGaDlvaHhuSTVCY2dYb0s1NW4wCmhkM0N6YlNIRTYrVkdxaHJaVHVG
bUEzTVV3WFQ0OWwrdEZnanJJa09Nb3MKLS0tIGduNEFtT2hCUDlkZWpWZmliZy83
cUoxcXp1NFF3SFpBVVdSZE5GY1VIWmsKH+cMqasOVxgCnGedaM2IAsgwOzEsOMct
0XjmInpppWNe+t7leEb6MqEY2cPQHL+l2L5jkZzAOfImwaIwMQnghw==
-----END AGE ENCRYPTED FILE-----
recipient: age1e5fq3hwxy78psus2nfvmtmua36g0u3suk78ephw6246l974d2utsvn0hla
lastmodified: "2026-09-12T21:04:26Z"
mac: ENC[AES256_GCM,data:0ks96xQzOa8ygNDDYfKV8EJ8dWLBaC0PCnLG73NinMByF/KoWkCdwMDPC34W9xxVoTD2NiF1i/3pgCG4QFezTE7tPHPPKdYcQfwda9fkooiXW4Nh2M/sgbq/xgsy9N3qpHD/O5iILgpehb9y0DuErOyxcn2AIYizynU7m8e63pc=,iv:fvPWBsfE6YHskKzdlxJidp14dUgRR0XdMkEu6IxMMSo=,tag:5FiuIrFOg/GXvlQVy7drJQ==,type:str]
unencrypted_suffix: _unencrypted
encrypted_regex: ^(data|stringData)$
lastmodified: "2026-09-14T14:19:39Z"
mac: ENC[AES256_GCM,data:jDdmiFg6uB1za7sAjO1CnGHdRPyUnmWCMJxqHrE3BO82pNbtm8yLOf+W6CfFKAjfZYqEE2mdKhABm7zeJgJlub3eXJbAirAFrp5jrbfHw0qsFo85Gj/BsrSDB401Aky6PxvRomz66FyX5zDDXIGAMEMlyNEadMplTfrZQQ9hQWM=,iv:UTSF72ofUyWs1LXGKQwBP60hK64UxhqTFM8QTVozGoo=,tag:OKivMDAqwWgrX+kNjvQrPg==,type:str]
version: 3.13.2
+3 -3
View File
@@ -73,7 +73,7 @@ grafana.ini:
auth.generic_oauth:
enabled: true
name: Authentik
allow_sign_up: true
allow_sign_up: true # Allow sync to create/update users from OAuth claims
client_id: grafana
scopes: openid email profile groups
auth_url: https://authentik.riotpiao.com/application/o/authorize/
@@ -84,13 +84,13 @@ grafana.ini:
# Authentik doesn't serve — request 404s with "Error getting email address"
# and the whole OAuth login fails.
email_attribute_path: email
login_attribute_path: preferred_username
login_attribute_path: preferred_username # Use preferred_username — OpenID standard claim, always present
name_attribute_path: name
role_attribute_path: "preferred_username == 'akadmin' && 'GrafanaAdmin' || contains(groups[*], 'homelab-admins') && 'Admin' || 'Viewer'"
allow_assign_grafana_admin: true
use_pkce: false
use_refresh_token: false
skip_org_role_sync: false
skip_org_role_sync: false # Sync org roles from OAuth groups
tls_skip_verify_insecure: true # Authentik uses self-signed cert; verify in prod
# GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET is injected from the grafana-oidc K8s
+8 -2
View File
@@ -112,10 +112,16 @@ spec:
name: minio-oidc
key: MINIO_IDENTITY_OPENID_CLIENT_SECRET
- name: MINIO_IDENTITY_OPENID_CLAIM_NAME
value: "policy"
value: "groups"
- name: MINIO_IDENTITY_OPENID_CLAIM_PREFIX
value: ""
- name: MINIO_IDENTITY_OPENID_REDIRECT_URI
value: "https://minio.riotpiao.com/oauth_callback"
- name: MINIO_IDENTITY_OPENID_DISPLAY_NAME
value: "Authentik"
- name: MINIO_IDENTITY_OPENID_SCOPES
value: "openid,profile,email,minio"
value: "openid,profile,email,groups"
- name: MINIO_BROWSER_LOGIN_ANIMATION
value: "off"
- name: MINIO_BROWSER_REDIRECT_URL
value: "https://minio.riotpiao.com"
+5 -6
View File
@@ -54,8 +54,8 @@ alertmanager:
# ── Prometheus ────────────────────────────────────────────────────────────────
prometheus:
prometheusSpec:
retention: 15d
retentionSize: "18GB"
retention: 30d
retentionSize: "95GB"
# scrapeTimeout MUST be <= scrapeInterval or the operator refuses to generate
# the Prometheus config ("scrapeTimeout greater than scrapeInterval") and no
@@ -64,10 +64,9 @@ prometheus:
scrapeTimeout: 60s
evaluationInterval: 30s
# Pin to az-a (talos-cp-1) — sole Longhorn node; else the RWO PVC can't
# attach on cp-2/cp-3 (CSINode lacks driver.longhorn.io).
# Pin to worker-1 for more storage capacity
nodeSelector:
topology.kubernetes.io/zone: az-a
kubernetes.io/hostname: worker-1
# Persistent storage — metrics survive node reboots and pod restarts.
# Uses the default `longhorn` StorageClass; nodeSelector above already pins
@@ -79,7 +78,7 @@ prometheus:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 20Gi
storage: 100Gi
resources:
requests:
+1
View File
@@ -38,6 +38,7 @@
rewrite name api.riotpiao.com ingress-nginx-controller.ingress-nginx.svc.cluster.local
rewrite name comfy.riotpiao.com ingress-nginx-controller.ingress-nginx.svc.cluster.local
rewrite name comfyui.riotpiao.com ingress-nginx-controller.ingress-nginx.svc.cluster.local
rewrite name gotify.riotpiao.com ingress-nginx-controller.ingress-nginx.svc.cluster.local
rewrite name riotpiao.com ingress-nginx-controller.ingress-nginx.svc.cluster.local
kubernetes cluster.local in-addr.arpa ip6.arpa {