Commit Graph
93 Commits
Author SHA1 Message Date
Story Crater Bot 15b1ec6ad4 feat(terraform): restructure control planes into a 3-node map with LAN etcd advertise and live machine CA — enables talos-cp-1/2/3 HA and drops worker configs 2026-07-20 08:22:53 -07:00
Story Crater Bot f7a8df0514 chore: remove GITOPS_ARCHITECTURE.md — scratch planning doc, not meant for the repo 2026-07-19 09:30:48 -07:00
Story Crater Bot 32281ee923 chore: remove scratch planning docs — not meant for the repo 2026-07-19 09:30:25 -07:00
Story Crater Bot 578a707867 feat(gitops): migrate domain to riotpiao.com, add CNPG + Forgejo HA on Redis/Postgres, wire ArgoCD apps — enables cluster rebuild after etcd wipe and unblocks the git-source chicken-egg via standalone Helm-source Applications 2026-07-19 09:29:17 -07:00
Story Crater Bot c6493f14ae feat(ci,iac): Consolidate Forgejo CI workflows and add Talos Terraform IaC
Consolidate three separate Forgejo Actions (argocd-sync, security-scan, validate-k8s) into single cluster-ci workflow for cleaner CI/CD pipeline with proper job sequencing and reduced auth overhead.

Add Terraform configuration for Talos cluster machine configs:
- Provider setup for Talos
- Centralized variables for CP and worker configs
- Template-based config generation for controlplane.yaml and worker-*.yaml
- Sensitive data separated in terraform.tfvars (gitignored)
- Local state tracking for infrastructure
2026-07-17 23:44:08 -07:00
Story Crater Bot 7437078f23 fix(ci): Correct Forgejo Actions template syntax for git clone auth
Use proper Forgejo variables: gitea.server_url, gitea.repository
Construct CLONE_URL correctly: https://user:token@host/repo.git
Use bash parameter expansion to strip https:// prefix

Removes invalid Forgejo filter syntax (| replace)
2026-07-17 12:27:40 -07:00
Story Crater Bot f8b19d9f55 fix(ci): Replace GitHub actions/checkout with Forgejo auth
Use CI_RUNNER and CI_RUNNER_SECRET for repo clone authentication.
Embed credentials in git clone URL: https://user:token@host/repo.git

Removes dependency on GITHUB_TOKEN (GitHub-specific) and improves Forgejo compatibility.
2026-07-17 12:19:23 -07:00
Story Crater Bot c000ddb402 fix(ci): Remove stale kustomize before reinstall in validate-k8s workflow
Prevent 'kustomize exists' error when downloading tools in CI runner.
Use -f flag on mv commands to force overwrite.
2026-07-17 11:31:44 -07:00
Story Crater Bot 888c4f5493 fix(ingress): Add nginx LoadBalancer service to GitOps — removes 503 error
Remove manual nginx-controller-svc.yaml (duplicate with Helm-managed service).
Helm chart creates LoadBalancer service automatically. Manual manifest caused conflicts.

Ingress controller now solely managed by Helm chart values.
2026-07-17 00:46:27 -07:00
Story Crater Bot 403e495fe9 fix(ingress): Add nginx LoadBalancer service to GitOps — fixes 503 error
Recreate ingress-nginx-controller LoadBalancer service that was deleted.
Add to k8s/bootstrap/ingress/ kustomization for ArgoCD management.

LoadBalancer assigned IP: 192.168.1.160 (via MetalLB)
ArgoCD now accessible via: https://192.168.1.160/ (or update DNS)
2026-07-16 23:35:02 -07:00
Story Crater Bot f30771a78a feat(minio): Expand CRDs to include Policies and Users — full YAML-driven resource creation
Add MinIO Policies and Users via CRD alongside Buckets.

Resources now declarative:
- Bucket: riotpiao-models (versioning enabled)
- Policy: policy-ollama (scoped bucket access)
- User: user-ollama (service account for Ollama/LLM)

Access keys can be overridden via SOPS or kustomize overlays.
All MinIO resource creation now git-tracked and version controlled.
2026-07-16 14:55:50 -07:00
Story Crater Bot e2e17ae0fb feat(data): Add CNPG cluster + database schema initialization
Create production PostgreSQL cluster via CNPG (3-node HA, Longhorn storage).

Schema initialization Job creates schemas for:
- Authentik (identity provider)
- Temporal (workflow engine)
- Vault (secrets management)
- App (generic application databases)

Database layer now captures complete IaC for stateful infrastructure.
Services find ready schemas when deployed.
2026-07-16 14:53:59 -07:00
Story Crater Bot c230b3ee45 feat(minio): Add MinIO Bucket CRD for riotpiao-models — replaces shell script setup 2026-07-16 14:31:33 -07:00
Story Crater Bot 2d7330798b refactor(k8s): Reorganize into 5-layer structure with production kustomizations 2026-07-16 14:28:19 -07:00
Story Crater Bot a81b9b6169 refactor(ci-cd): Replace Terraform pipeline with GitOps validation and ArgoCD sync
Delete old terraform-apply.yml (terraform fmt/init/validate/plan/apply).

Create new GitOps CI/CD:
- validate-k8s.yaml: YAML lint, kubeval, kustomize build, ArgoCD validation
- argocd-sync.yaml: Auto-sync homelab-root on main branch
- security-scan.yaml: Trivy, Polaris, secret detection
- .yamllint.yaml: YAML linting configuration

Add documentation (.forgejo/CI-CD.md) and architecture guides.

Git is now single source of truth. CI validates, ArgoCD deploys.
2026-07-16 12:52:25 -07:00
Story Crater Bot a860de94da refactor: remove terraform entirely, migrate to pure GitOps (ArgoCD)
Delete entire terraform/ directory.

Architecture: Terraform + ArgoCD → ArgoCD only
- Single tool: ArgoCD manages all infrastructure and applications
- Source of truth: git only (k8s/ directory)
- Continuous reconciliation: no manual apply needed
- Simpler state: no tfstate backend, no state files

Next: Migrate all Terraform resources to k8s/ YAML manifests
and ArgoCD Applications (namespaces, storage classes, Helm releases,
RBAC, network policies, Authentik config).
2026-07-16 11:04:52 -07:00
Story Crater Bot 94a2bd648c fix: remove kubeconfig references, use try() for pod runtime files
- main.tf: remove kubeconfig_path local (no longer used with direct auth)
- providers.tf: wrap file() with try() to handle plan-time on non-pod systems

try() allows terraform plan to work locally; at runtime in pod, files exist and are used.
2026-07-15 21:36:05 -07:00
Story Crater Bot be2e5c321f fix: use direct in-cluster kubernetes auth instead of kubeconfig file
- providers.tf: use host + token + ca_crt from mounted service account secrets
- workflow: remove kubeconfig generation step (no longer needed)
- variables.tf: remove unused kubeconfig_path variable

This is the standard pattern for running terraform inside k8s pods.
2026-07-15 21:26:09 -07:00
Story Crater Bot 9d1d79b774 fix: kubeconfig path default for runner container — use /tmp/kubeconfig not local path 2026-07-15 21:03:11 -07:00
Story Crater Bot 72ab6b6973 fix: terraform fmt — normalize formatting across all files 2026-07-15 21:01:55 -07:00
Story Crater Bot 7114fc8fc9 fix:Update the home lab repo 2026-07-15 20:40:02 -07:00
Story Crater Bot fe7b749951 fix: terraform init backend config — use endpoint with inline credentials 2026-07-15 19:18:17 -07:00
Story Crater Bot 694350634b fix: use endpoints.s3 for S3 backend (endpoint deprecated in TF 1.8+) 2026-07-15 19:16:13 -07:00
Story Crater Bot ab103f00f0 fix: core-cli OAuth2 + S3 backend + admin group
- Link core-cli app to OAuth2 provider (was hardcoded to 0)
- Add core-cli user to authentik_admins for CI access
- Fix terraform init: use 'endpoint' not 'endpoints.s3' for S3 backend
  (Terraform 1.9.4 compatibility, matches state.tf config)
2026-07-15 19:09:59 -07:00
Story Crater Bot e4d645eae9 feat: Terraform CI via Forgejo Actions + MinIO S3 state backend
- ArgoCD manages MinIO (phase 0), Terraform manages infrastructure
- Runner workflow: pulls state from S3, validates, plans, applies
- 34 resources imported to state, S3 backend operational
- Fixed AppProject repos, S3 endpoint deprecation, runner package manager
2026-07-15 18:48:32 -07:00
Story Crater Bot ab76e40d05 revert(phase4): Remove Pod Job approach for Terraform apply
Reverting Phase 4 Pod Job implementation in favor of CI runner (Forgejo Actions).

Deleted:
- k8s/argocd/apps/phase4-terraform-0.yaml
- k8s/hooks/phase4/ (terraform-apply-hook.yaml, terraform-rbac.yaml, terraform-s3-secrets.enc.yaml)

Reason: Pod Job approach had limitations (eviction, timeouts, pod security policies).
Next: Implement Forgejo Actions CI workflow for terraform apply.
2026-07-15 18:07:54 -07:00
Story Crater Bot b568c015e2 feat(phase4): ArgoCD-driven Terraform with PVC imports
Phase 4 implementation (true IaC):
- ArgoCD Application: terraform-apply (PostSync Hook Job)
- Hook Job runs: terraform init && terraform apply -auto-approve
- ServiceAccount + ClusterRole for cluster-admin
- SOPS-encrypted S3 credentials (terraform-s3-secrets.enc.yaml)
- Pre-commit hook blocks local 'terraform apply'
- In-cluster kubeconfig for Kubernetes provider
- AWS credentials file with minio profile

State imports:
- Imported kubernetes_persistent_volume_claim.portainer (dashboard/portainer)
- Imported kubernetes_persistent_volume_claim.grafana (logging/grafana)
- Imported kubernetes_persistent_volume_claim.loki (logging/storage-loki-0)

Workflow:
1. Edit terraform/*.tf files
2. git push to main
3. ArgoCD detects changes in k8s/hooks/phase4
4. Hook Job automatically runs terraform apply
5. No manual 'terraform apply' needed ever again
2026-07-15 17:48:18 -07:00
Story Crater Bot e71c7ad37e feat(phase4): ArgoCD-driven Terraform apply via PostSync Hook Job
- Create Phase 4 ArgoCD Application (terraform-apply)
- PostSync Hook Job runs: terraform init && terraform apply -auto-approve
- ServiceAccount + ClusterRole for cluster-admin RBAC
- S3 credentials encrypted with SOPS (terraform-s3-secrets.enc.yaml)
- Pre-commit hook blocks local 'terraform apply' — all changes via git push
- True IaC: modify terraform/*.tf → git push → ArgoCD applies automatically
2026-07-15 16:39:27 -07:00
Story Crater Bot 842360288d docs(terraform): add state management script and best practices guide 2026-07-15 16:31:55 -07:00
Story Crater Bot f18f96eb5b chore(phase4): stub helmfile — all releases managed by Terraform + ArgoCD 2026-07-15 16:27:13 -07:00
Story Crater Bot d655726eca feat(helmfile): remove phase3 releases (authentik, vault, story-crater, ollama) — ArgoCD-managed. Keep temporal 2026-07-15 16:26:30 -07:00
Story Crater Bot ff22027c7a refactor(argocd): phase3 reduced to authentik only (remove vault, temporal, ollama, story-crater) 2026-07-15 16:24:45 -07:00
Story Crater Bot f158512261 feat(argocd): create phase3 Applications (authentik, vault, temporal, ollama, story-crater) with SOPS secrets and Hook Jobs 2026-07-15 16:23:30 -07:00
Story Crater Bot 69d2240cf4 fix(argocd): use homelab-ca wildcard TLS instead of --insecure mode 2026-07-15 16:21:31 -07:00
Story Crater Bot 543105bf46 feat(helmfile): remove phase2 releases (cloudnative-pg, loki, grafana, prometheus, forgejo, forgejo-runner) — ArgoCD-managed 2026-07-15 16:07:42 -07:00
Story Crater Bot 7d1eb09486 feat(argocd): add phase2 Hook Jobs (CNPG, Prometheus, Forgejo-Runner) and update Applications to multi-source 2026-07-15 16:05:34 -07:00
Story Crater Bot 0dddf15dc8 feat(argocd): add SOPS-encrypted secrets for phase2 releases (loki, grafana, forgejo) 2026-07-15 16:02:20 -07:00
Story Crater Bot 37ee3dc5b1 feat(argocd): create phase2 Applications (prometheus, cloudnative-pg, loki, grafana, forgejo, forgejo-runner) 2026-07-15 15:12:36 -07:00
Story Crater Bot f864e3dc51 feat(argocd): remove claude-terminal and blackbox-exporter from phase1 2026-07-15 15:11:30 -07:00
Story Crater Bot 96e40916e3 feat(phase1): remove 9 hookless releases from helmfile — now ArgoCD-managed
Removed releases (all now managed via ArgoCD Applications):
- strimzi-operator
- kafka-cluster
- kmsvc-redis
- queue-crd
- management-service
- promtail
- blackbox-exporter
- portainer
- claude-terminal

Helmfile now contains only hook-heavy releases (phases 2-3) + argocd (self-referential, never migrates).

Next: Verify helmfile diff is clean, then confirm all 9 apps Synced/Healthy in ArgoCD.
2026-07-15 15:07:39 -07:00
Story Crater Bot 04100232ef feat(phase1): create ArgoCD Applications for 9 hookless releases
Created Applications for Phase 1 migration (no presync/postsync hooks):
- strimzi-operator (strimzi/strimzi-kafka-operator v0.46.0)
- kmsvc-redis (bitnami/redis v20.6.0)
- kafka-cluster (local chart k8s/sqs/charts/kafka-cluster)
- queue-crd (local chart k8s/sqs/charts/queue-crd)
- management-service (local chart k8s/sqs/charts/management-service)
- promtail (grafana/promtail)
- blackbox-exporter (prometheus-community/prometheus-blackbox-exporter ~11)
- portainer (portainer/portainer)
- claude-terminal (local chart k8s/dev-tools)

Organized by sync wave: 0 (bootstrap), 1 (messaging/observability), 3 (dashboards/tools).
All configured with auto-sync, CreateNamespace, prune, selfHeal.

Next: Remove corresponding release blocks from helmfile.yaml.gotmpl per migration guide
(one release at a time, verify helmfile diff is clean).

Applications applied to cluster; awaiting helmfile cleanup to finalize migration.
2026-07-15 15:06:02 -07:00
Story Crater Bot 09980aa41d docs(phase1): create migration guide for 9 hookless releases
Detailed Phase 1 workflow:
- Template Application spec (Helm source, values, sync policy)
- Per-release migration pattern (create → test → remove → commit)
- Helmfile ↔ ArgoCD mapping table
- Local chart handling (source.path vs source.chart)
- Verification checklist
- Rollback instructions

Reference: execute one release at a time, verify before next.
2026-07-15 15:05:12 -07:00
Story Crater Bot 5144ab732d feat(phase0): configure ArgoCD SOPS decryption + update encrypted secrets
Phase 0 continuation: enable ArgoCD to decrypt SOPS-encrypted secrets on sync.

1. Update ArgoCD Helm values (terraform/argocd-bootstrap.tf):
   - Add SOPS_AGE_KEY_FILE env var to repoServer
   - Mount sops-age K8s Secret at /home/argocd/.sops
   - Add ConfigManagementPlugin for SOPS (detects *.enc.yaml files)

2. Update encrypted secrets with real values:
   - k8s/base/secrets.enc.yaml: encrypted with actual service credentials
   - All secret values encrypted at rest in git
   - ArgoCD decrypts on sync using K8s Secret + AGE key

Prerequisites:
  - K8s Secret created: kubectl create secret generic sops-age -n argocd --from-file=keys.txt=/Users/rockliang/.sops/key.txt
  - SOPS_AGE_KEY_FILE env var set in ArgoCD repoServer (done above)

Next: Phase 1 — migrate 9 hookless releases to ArgoCD + create Applications that reference encrypted secrets.
2026-07-15 15:04:26 -07:00
Story Crater BotandClaude Haiku 4.5 4379f3cb21 feat(phase0): setup SOPS for encrypted secret management
Phase 0 groundwork for helmfile→ArgoCD migration using SOPS (Secrets Operations):

1. Install SOPS + AGE encryption
   - AGE key generated and stored locally at ~/.sops/key.txt
   - Public key embedded in .sops.yaml for file encryption rules

2. Create K8s Secret for AGE private key
   - kubectl: create secret generic sops-age -n argocd --from-file=keys.txt=~/.sops/key.txt
   - ArgoCD will use this key to decrypt secrets at sync time

3. Encrypt initial secrets
   - k8s/base/secrets.enc.yaml: AES256_GCM encrypted secrets for all services
   - Placeholder values (will be replaced with real values per environment)
   - Secrets never visible in git (encrypted at rest)

4. Configure SOPS
   - .sops.yaml: creation rules for k8s/*/secrets.enc.yaml files
   - All future secret files auto-encrypt on edit (sops -e)

Setup: Store AGE key as K8s Secret in argocd namespace:
  export KUBECONFIG=cluster-config/kubeconfig
  kubectl create secret generic sops-age -n argocd --from-file=keys.txt=~/.sops/key.txt

Next: Configure ArgoCD Helm plugin to decrypt secrets on sync (Phase 0 continuation).

Co-Authored-By: Claude Haiku 4.5 <[email protected]>
2026-07-15 15:00:06 -07:00
Story Crater Bot d2f4b3c7e4 Revert "feat(phase0): bootstrap External Secrets Operator and fix helmfile dual-ownership"
This reverts commit e7f3409d0f.
2026-07-15 14:59:54 -07:00
Story Crater BotandClaude Haiku 4.5 e7f3409d0f feat(phase0): bootstrap External Secrets Operator and fix helmfile dual-ownership
Phase 0 groundwork for helmfile→ArgoCD migration:

1. Remove 3 bootstrap releases from helmfile (cert-manager, reloader, ingress-nginx)
   — already managed by terraform/bootstrap-releases.tf; eliminates dual-ownership

2. Bootstrap ESO (External Secrets Operator) as TF-managed release
   — required for all ExternalSecret resources in phases 1-3
   — added to bootstrap-releases.tf + helm-repositories.tf

3. Create ClusterSecretStore connecting ESO to Vault (K8s auth)
   — enables per-namespace/per-release secret injection
   — vault config documented in docs/PHASE0-ESO-VAULT-SETUP.md (manual setup)

4. Fix argocd-bootstrap.tf CA cert copy: use jq instead of sed for cleaner metadata handling

Changes:
- helmfile.yaml.gotmpl: remove cert-manager/reloader/ingress-nginx blocks
- terraform/bootstrap-releases.tf: add external-secrets release
- terraform/helm-repositories.tf: add external-secrets Helm repo
- k8s/external-secrets/clustersecretstore.yaml: ESO→Vault ClusterSecretStore
- k8s/argocd/apps/0-wave-0.yaml: stub wave 0 applications (schema fix, rewrite pending Phase 1)
- docs/PHASE0-ESO-VAULT-SETUP.md: manual ESO-Vault auth setup procedure

Next: Phase 1 will incrementally rewrite ArgoCD Applications + migrate helmfile releases.

Co-Authored-By: Claude Haiku 4.5 <[email protected]>
2026-07-15 14:53:16 -07:00
Story Crater BotandClaude Haiku 4.5 23ec31bd6d feat(terraform): import Longhorn StorageClasses and app PVCs to Terraform state
- Phase 1: longhorn, longhorn-kafka StorageClasses (cluster-wide defaults)
- Phase 2 pilot: grafana, loki, portainer, forgejo PVCs
- All imports protected by lifecycle.prevent_destroy
- Removes Helm annotations (meta.helm.sh/*) to prevent dual-ownership conflicts
- Remote state backend (MinIO S3) syncs automatically on plan/apply
- Import-only approach: zero data loss, existing volumes untouched
- See terraform/LONGHORN_PVC_IMPORT.md for execution record

Co-Authored-By: Claude Haiku 4.5 <[email protected]>
2026-07-15 12:22:35 -07:00
Story Crater Bot 421086f845 docs(iac): enforce single source of truth for infrastructure
Add IaC practice section to coding-standards.md:
- All infrastructure state via Terraform or Helm (never ad-hoc scripts)
- Clear division: Terraform owns helm releases/namespaces/storage/state
- Anti-pattern: split bucket definitions across multiple files
- Bootstrap-only exception: document one-time setup with rationale

Rationale: prevents state drift, credential duplication, and unclear ownership.
2026-07-14 23:37:54 -07:00
Story Crater Bot bd00bca9bf chore: remove terraform cache from git tracking 2026-07-14 23:34:01 -07:00
Story Crater Bot 397edf632f fix: correct gitignore patterns for terraform state and cache
Remove malformed line and clarify rules:
- terraform/.terraform/ (local provider cache)
- terraform/*.tfstate* (local state backups)
- skills-lock.json (lock file)

All TF state now remote (MinIO S3), local files safe to exclude.
2026-07-14 23:33:50 -07:00