Commit Graph
315 Commits
Author SHA1 Message Date
rock 449c2a9109 gitops: add secret-rotation controller ArgoCD Application
- Syncs k8s/apps/secret-rotation-controller/ kustomization
- Auto-prune and self-heal enabled
- Creates secret-rotation namespace
- ArgoCD will deploy CRD, RBAC, ExternalSecret, Deployment
2026-09-04 13:51:26 -07:00
rock 667bca0f44 feat: automated secret rotation controller
- ExternalSecret syncs age key from Vault to pod
- CRD defines rotation schedule for each secret
- Controller watches CRD, rotates on schedule:
  * Call provider API (Authentik/Forgejo/MinIO) for new secret
  * Update k8s Secret
  * Update .enc.yaml via sops (uses age key from Vault)
  * Git commit and push
- Vault is source of truth for age key (never on disk)
- Examples: minio-oidc (90d), portfolio-agent (90d), forgejo-token (90d), minio-root (180d)
2026-09-03 23:37:24 -07:00
rock f9654986ad fix(minio): use in-cluster URL for OIDC config fetch
MinIO pod was getting 503 from public URL at startup. Use in-cluster
authentik-server.iam.svc for metadata fetch; browser redirects still
use public URLs from OIDC metadata response.
2026-09-03 23:15:19 -07:00
rock 8f7004c946 iam: switch service accounts to roles-based auth
- Roles stored in user attributes, not groups
- Property mapping looks up roles by client_id for client_credentials
- Service account apps have no policy bindings (client_secret = access control)
- Cleanup stale bindings on re-provision
- JWT claims: azp (service identity) + roles (capabilities)
2026-09-03 19:23:06 -07:00
rock f1e5fe58f4 iam: move provisioning script to scripts/iam, remove k8s job
- Move authentik-provision.py to scripts/iam/ (manual-only)
- Remove job/RBAC resources (not needed for local runs)
- Use public URL directly (no sed substitution needed)
- Add app password support via set_key endpoint
- Support both password grant and client_credentials
2026-09-03 19:03:58 -07:00
rock 20513c8b3b iam: add memory scope, service accounts, manual provisioning
- Add 'memory' scope property mapping (memory_projects, memory_visibility, memory_role)
- Add capability groups: llm-users, memory-users, memory-writers
- Add service account provisioning for portfolio-agent, memory-agent
- Fix sops-secrets kustomization (generatorOptions)
- Add RoleBindings for portfolio, poimen, dashboard namespaces
- Remove PostSync hook - IAM provisioning is now manual-only
2026-09-03 18:07:22 -07:00
rock 87786d8733 messaging: remove queue-crd/management-service (moved to kmsvc-manage)
- Applications now managed by kmsvc-root from kmsvc-manage.git
- Added ServerSideApply to homelab-root for proper annotation sync
- Avoids duplicate Application conflicts with Image Updater
2026-09-03 08:28:38 -07:00
rock 17a98afa3f image-updater: filter to SHA tags only (skip :latest)
allow-tags: regexp:^[0-9a-f]{7}$ ensures newest-build strategy
compares commit SHA tags, not the stale :latest tag
2026-09-03 08:07:19 -07:00
rock 7e9ef86826 appproject: allow argo-helm repo for image-updater 2026-09-02 20:32:28 -07:00
rock c6032cc354 argocd: add Image Updater for auto-deploy on image push
- Install argocd-image-updater via Helm (wave 1)
- Configure Forgejo registry (anonymous pulls)
- Annotate apps for auto-update: api-gw, portfolio, management-service, queue-crd
- Uses newest-build strategy for commit SHA tags
2026-09-02 20:31:09 -07:00
rock f21cc4721a kmsvc: migrate image from GHCR to Forgejo registry
Consolidate all internal images to forgejo.riotpiao.com for ArgoCD Image Updater
2026-09-02 20:12:35 -07:00
rock 51c66299e9 forgejo-runner: gc every 30min instead of daily
- Fix template to use .Values.gc.schedule instead of hardcoded cron
- Change schedule from daily 03:00 UTC to every 30 minutes
- Prevents DinD PVC fill-up (was at 93% before manual prune)
2026-09-02 19:52:41 -07:00
rock 77683ec7c6 fix: add poimen-memory and poimen-workflows Forgejo repos to sourceRepos 2026-09-02 09:52:41 -07:00
rock 88c9f3047a fix: disable name suffix hash for portfolio-secrets to match deployment reference 2026-09-01 10:38:05 -07:00
rock a6c3fdf786 feat: add portfolio LLM_API_TOKEN to ksops secrets
- portfolio-secrets.enc.env: FORGEJO_TOKEN + LLM_API_TOKEN for api.riotpiao.com
- kustomization: secretGenerator for ksops handling at deploy time
- Will be SOPS encrypted with homelab age key before merge
2026-09-01 09:42:02 -07:00
rock bfc376d032 feat(iam): add llm:inference permission to llm-admins group 2026-08-31 23:02:33 -07:00
rock 4a1a60104d feat: add portfolio SOPS secret for CI status 2026-08-31 22:33:00 -07:00
rock f3c88c0d9d chore: remove nextjs integration folder 2026-08-31 20:45:45 -07:00
rock 4af000c6ae feat(integrations): add NextJS LLM/Grafana integration + enable dashboard embedding 2026-08-31 20:22:26 -07:00
rock 1af9232613 feat: add tempo and otel-collector for distributed tracing 2026-08-31 15:02:15 -07:00
rock be55d68571 feat(argocd): add portfolio app, explicit sourceRepos, coredns rewrite for riotpiao.com
- Add Application for rock/riotpiao.com repo (portfolio site)
- Replace wildcard sourceRepos with explicit repo list
- Add CoreDNS rewrite for root domain riotpiao.com
2026-08-31 14:18:57 -07:00
rock 2038253d48 feat(security): add Kyverno for image scanning and Pod security policies
- Install Kyverno policy engine for admission control
- Add ClusterPolicies:
  * Disallow 'latest' tags (require explicit versions)
  * Restrict to trusted registries (docker.io, ghcr.io, quay.io, etc.)
  * Require non-root containers
  * Drop all Linux capabilities by default
  * Require securityContext on all containers
  * Require read-only root filesystem (audit only)
  * Require resource requests/limits (prevent starvation)
- All policies in audit mode initially (failurePolicy: ignore)
- Ready to graduate to enforce after testing
- Fixes: missing image scanning from security audit
2026-08-31 11:43:04 -07:00
rock c4a302c3d1 feat(iam): add local-llm Authentik application with JWT auth
- Add local-llm OAuth2 provider and application to Authentik provisioning
- Configure JWT-compatible OAuth2 provider (client_id: local-llm)
- Generate client secret on first run, stored in llm-serving/local-llm-jwt Secret
- Bind llm-admins group to local-llm application for admin access
- Add RBAC for provisioning job to create secrets in llm-serving namespace
- Output JWT issuer URL and certificate for local-llm token validation
2026-08-30 20:13:41 -07:00
rock 3b26d4435e refactor(ci): move forgejo-runners from worker-1 to talos-cp-2
Schedule runners on az-b (talos-cp-2) which has more Longhorn storage
and breathing room (367Gi available vs worker-1's 369Gi but over-provisioned).

PVCs deleted and will recreate on new zone. Runners will re-register.
2026-08-30 09:29:38 -07:00
rock 686c962ea9 fix(ci): aggressive GC for heavy Rust cargo builds
- GC CronJob runs 2x daily (02:00 & 05:00 UTC) instead of once (03:00)
- Delete incomplete actcache uploads immediately (tmp/ dirs from failed writes)
- Reduce actcache retention from 3 days to 1 day
- Prevents cargo cache backlog on rust runner under heavy commit load
- Incomplete entries were accumulating 900MB+ each, filling 1Gi PVC instantly
2026-08-30 09:23:09 -07:00
rock 136bfaf0f2 feat(ops): add cluster-wide stale job/pod cleanup CronJob
Daily 04:00 UTC sweeper in kube-system:
- Delete failed Jobs older than 24h (any namespace)
- Delete completed standalone Jobs older than 72h (no CronJob owner)
- Delete orphan Error/Evicted pods older than 1h
- Self-cleans via ttlSecondsAfterFinished
2026-08-30 07:27:50 -07:00
rock 91729f65e9 feat(ci): add GC CronJob for runner cleanup, expand reg PVCs to 20Gi
- Add gc-cronjob.yaml: daily prune of DinD Docker images/volumes/build-cache
  and actcache across all forgejo-runner pods. Keeps :latest tagged images,
  deletes non-latest older than 72h.
- Expand runner reg PVCs from 1Gi to 20Gi (all three runners) to prevent
  action tool cache from filling disk.
- Rust runner gets explicit 20Gi persistence override.
- GC only renders from golang (default) values to avoid duplicate resources.
2026-08-30 07:08:59 -07:00
rock bde6c740ec fix: remove obsidian ingress (UI retired) 2026-08-29 09:37:12 -07:00
rock 854549d06e fix: add websocket support to obsidian ingress (noVNC needs it) 2026-08-28 21:04:33 -07:00
rock 6d09f896f3 feat: add obsidian-vault PVC (RWX) to infra/databases
Shared by obsidian-server (REST API) and obsidian-ui (noVNC).
ReadWriteMany so both pods can mount on different nodes.
2026-08-28 20:42:13 -07:00
rock b1f73562a2 fix: obsidian ingress points to obsidian-ui (noVNC) instead of REST API 2026-08-28 17:20:40 -07:00
rock 56be73ad3a fix: obsidian ingress needs backend-protocol HTTPS (self-signed) 2026-08-28 16:48:43 -07:00
rock a5bf8dc06b feat: add obsidian.riotpiao.com ingress for poimen vault UI 2026-08-28 16:43:29 -07:00
rock 422ae3cf04 fix: update runner golang image from 1.25 to 1.26
kmsvc-manage, kmsvc-cli require Go 1.26.0 in go.mod but runner was
using golang:1.25-bookworm container. Update to golang:1.26-bookworm
to match project requirements.
2026-08-28 15:41:23 -07:00
Story Crater Bot 27907387f6 docs: remove outdated docs describing the retired core/talos CLI workflow 2026-08-27 13:11:47 -07:00
Story Crater Bot 33e36f1d4d docs: Add JWT auth rollout status 2026-08-27 12:29:39 -07:00
Story Crater Bot d055483aa2 feat: add poimen-memory as an Authentik service-to-service client
Client credentials + device code grant, no browser redirect (empty
redirect_uris) - unlike every other SERVICES entry which is
authorization_code web SSO. First real step toward replacing
poimen-memory's static API key with a proper JWT flow.
2026-08-27 11:51:02 -07:00
Story Crater Bot e4de366d2a feat: add ServiceAccounts for poimen-memory/kmsvc/immich operator Roles
Bind each service's operator Role to a ServiceAccount alongside the
existing oidc:*-admins Group, and wire serviceAccountName into the
pods we control (immich-server, immich-machine-learning,
management-service). poimen-memory's Deployment lives in its own
repo/ArgoCD app, so its SA is created here but not yet wired to a pod.
2026-08-26 19:51:05 -07:00
Story Crater Bot 7e648d2251 feat: add vault-service-api group for non-human Vault access
Separate from homelab-admins' blanket grant - target for a future
Vault Identity Group alias scoping service/API tokens narrower than
full admin.
2026-08-26 19:42:12 -07:00
Story Crater Bot a5c7381c11 feat: add Vault as an Authentik OIDC app for human/CLI login
Confidential client for 'vault login -method=oidc' and the Vault UI's
oidc auth method. homelab-admins gets bound automatically like every
other app in SERVICES. Client secret generated on first provision run
into iam/vault-oidc.
2026-08-26 16:42:44 -07:00
Story Crater Bot aaa728bab4 fix: rotate vault unseal keys after vault-0 wipe/reinit
Old root token and unseal keys were dead (lost access to the previous
Vault store). Wiped the S3 backend and vault-0, re-initialized fresh,
rotated these to match the new live unseal keys so ArgoCD's next sync
doesn't clobber them back to the dead ones.
2026-08-26 16:33:35 -07:00
Story Crater Bot 6c758e3606 feat: add poimen-memory-admins group/permissions and k8s RBAC role
Follows the portainer/kmsvc/temporal pattern - group + "permissions"
claim entry only, no Authentik Application/OAuth provider, since
poimen-memory is an internal API-key service, not browser OIDC login.
rock gets it automatically (already in every service_admin_group).
2026-08-25 21:50:05 -07:00
Story Crater Bot 7f0541a8dc fix: shrink paperless-media to 500Gi, give immich the bigger share (2000Gi) - photo libraries grow faster than scanned docs 2026-08-25 19:23:07 -07:00
Story Crater Bot bebbd3a690 fix: add CoreDNS rewrite for img.riotpiao.com
Cloudflare Tunnel's origin service for img.riotpiao.com self-references
the same public hostname (same pattern as paperless/forgejo/authentik) -
without this rewrite, cloudflared's in-cluster DNS resolution has
nowhere to loop back to, and TLS to the raw ingress-nginx service name
fails cert validation (cert is only valid for *.riotpiao.com).
2026-08-25 18:53:52 -07:00
Story Crater Bot 2b01e7c5f3 fix: add cube+earthdistance to postInitApplicationSQL, immich needs them for geo queries 2026-08-25 18:50:09 -07:00
Story Crater Bot abed329636 fix: add postInitApplicationSQL for pgvector, app role isn't superuser
immich-server crash-looped on "permission denied to create extension
vector" - pgvector's control file isn't marked trusted, and CNPG's
app owner role isn't superuser (enableSuperuserAccess: false).
Documents the fix for future cluster rebuilds; the live cluster
already had CREATE EXTENSION run manually via the postgres pod's
local socket.
2026-08-25 18:49:09 -07:00
Story Crater Bot 0e57444909 fix: use img.riotpiao.com instead of immich.riotpiao.com for hostname 2026-08-25 18:46:58 -07:00
Story Crater Bot d0f79871c7 fix: shrink immich-media to 1400Gi, real disk headroom smaller than assumed
2000Gi didn't schedule - "insufficient storage; tags not fulfilled".
The cp-3 HDD's real usable capacity (~3724GiB) minus paperless-media's
2000Gi and ~231GiB of other apps' default-class replicas that Longhorn
placed here anyway (tags only pull matching volumes in, don't exclude
others when the untagged pool elsewhere is full) only leaves ~1493Gi
of real scheduling headroom. 1400Gi fits with margin.
2026-08-25 18:34:22 -07:00
Story Crater Bot 61a1975669 feat: deploy Immich with Authentik OIDC, rock as admin
Self-hosted photo backup (Google Photos replacement) - raw manifests,
no Helm chart, self-contained under k8s/apps/immich including its own
CNPG Postgres. Media PVC shares the cp-3 HDD 2TB/2TB with
paperless-media.

Postgres is pg18, not this repo's usual 16.2: CNPG's official pgvector
extension image (ghcr.io/cloudnative-pg/pgvector) is only published
for pg18, loaded via CNPG's ImageVolume extension mechanism (operator
1.30.0 / k8s 1.36.1 both support it). Immich auto-manages CREATE
EXTENSION itself at startup.

OIDC via a new "immich_role" Authentik scope mapping (homelab-admins/
immich-admins -> "admin" claim, else "user"), consumed by Immich's
OAuth roleClaim setting which re-syncs isAdmin on every login - more
reliable than Immich's racy first-user-is-admin fallback. Config
composed into an immich-oidc Secret and mounted as IMMICH_CONFIG_FILE,
matching the paperless-oidc pattern. k8s RBAC (immich-operator Role +
oidc:immich-admins binding) mirrors paperless/rbac.yaml.

immich namespace pre-created in k8s/infra/databases/namespaces.yaml
(not just immich's own CreateNamespace=true) since the iam PostSync
job's RoleBinding needs it to exist before wave 8.
2026-08-25 18:21:28 -07:00
Story Crater Bot 1518ebc2dd fix: shrink paperless-media to 2TB, split cp-3 HDD with Immich
4TB disk on cp-3 was single-tenant for paperless (3500Gi). Splitting
2TB/2TB with the new Immich media PVC on the same disk/tag. Live PVC
and Longhorn volume already deleted+recreated manually (data was
outdated test uploads only, nightly MinIO backup covers it).
2026-08-25 18:09:23 -07:00