diff --git a/.forgejo/CI-CD.md b/.forgejo/CI-CD.md new file mode 100644 index 0000000..6522a25 --- /dev/null +++ b/.forgejo/CI-CD.md @@ -0,0 +1,460 @@ +# CI/CD Pipeline: GitOps Validation & Deployment + +## Overview + +Pure GitOps CI/CD pipeline using Forgejo Actions (self-hosted runner). + +**Principle:** Validate in CI, deploy via ArgoCD (no manual steps). + +``` +git push + ↓ + [CI: Validate] + ├─ yamllint (YAML syntax) + ├─ kubeval (K8s manifests) + ├─ kustomize build (all layers) + ├─ argocd validation (app definitions) + └─ security scan (secrets, best practices) + ↓ + [If push to main] + └─ ArgoCD auto-syncs (if enabled) +``` + +## Workflows + +### 1. validate-k8s.yaml (Mandatory) + +**Trigger:** Any push/PR with k8s/ changes + +**What it does:** +1. Lints all YAML files (`yamllint`) +2. Validates K8s manifests (`kubeval`) +3. Builds all kustomization layers +4. Validates ArgoCD applications +5. Reports results + +**Duration:** ~2-3 minutes + +**Status:** +- ✅ PASS: All layers build, manifests valid → OK to merge +- ❌ FAIL: Syntax error, invalid resource, build failed → Fix & push again + +**Example output:** +``` +=== Building k8s/infrastructure/ === +✓ Infrastructure built successfully +Resources: 47 + +=== Building k8s/bootstrap/ === +✓ Bootstrap built successfully +Resources: 23 +``` + +**When to check:** +- After every commit +- Before merging PRs +- On every branch + +### 2. argocd-sync.yaml (Recommended) + +**Trigger:** Push to main only (k8s/ changed) + +**What it does:** +1. Authenticates with ArgoCD +2. Syncs `homelab-root` application +3. Waits for sync to complete (5 min timeout) +4. Verifies all applications healthy + +**Duration:** 1-5 minutes (depends on resources) + +**Status:** +- ✅ SYNCED: All resources deployed to cluster +- ❌ FAILED: Sync error, pod crashes, etc. → Check ArgoCD UI for details + +**When it runs:** +- Automatically after merge to main +- Only on k8s/ changes (not on docs) + +**Manual trigger (if needed):** +```bash +# SSH to runner or use Forgejo UI +# Re-run failed workflow +# Or manually sync: argocd app sync homelab-root +``` + +**Requires secrets:** +- `ARGOCD_SERVER`: ArgoCD server URL (https://argocd.riotpiao.homelab.com) +- `ARGOCD_AUTH_TOKEN`: ArgoCD API token (generate via ArgoCD UI) + +### 3. security-scan.yaml (Optional) + +**Trigger:** Any push/PR with k8s/ changes + +**What it does:** +1. Scans Dockerfiles for vulnerabilities (`trivy`) +2. Scans Helm charts for security issues +3. Audits K8s manifests (`polaris`) +4. Checks for hardcoded secrets +5. Verifies security best practices + +**Duration:** ~3-5 minutes + +**Status:** +- ✅ PASS: No critical issues +- ⚠️ WARNING: Best practice recommendations (non-blocking) +- ❌ FAIL: Hardcoded secrets found (must fix) + +**Common issues:** +- Missing resource limits (warning) +- Privileged containers (warning) +- Hardcoded passwords (ERROR) + +--- + +## File Structure + +``` +.forgejo/ +├── workflows/ # CI/CD workflows +│ ├── validate-k8s.yaml # Validate manifests (required) +│ ├── argocd-sync.yaml # Sync to cluster (auto on main) +│ └── security-scan.yaml # Security checks (optional) +└── CI-CD.md # This file +``` + +--- + +## Setup Instructions + +### 1. Install Forgejo Runner + +```bash +# On runner machine (inside cluster or external) +forgejo-runner register \ + --instance https://forgejo.riotpiao.homelab.com \ + --token \ + --name homelab-runner \ + --labels docker + +forgejo-runner daemon +``` + +### 2. Add ArgoCD Secrets to Forgejo + +```bash +# Go to: Forgejo → Settings → Secrets + +# Add: +ARGOCD_SERVER = https://argocd.riotpiao.homelab.com +ARGOCD_AUTH_TOKEN = # Generate: argocd account generate-token +``` + +### 3. Generate ArgoCD Token + +```bash +# Inside cluster +kubectl -n argocd port-forward svc/argocd-server 8080:443 + +# Go to: https://localhost:8080/user-info/api-tokens +# Create new token (CI/CD) +# Copy token to Forgejo secrets +``` + +--- + +## Workflow Execution + +### When developer pushes to feature branch: + +``` +git push origin feature/new-service + +↓ +Forgejo Actions triggered +↓ +validate-k8s.yaml runs: + ✓ Lints YAML + ✓ Validates manifests + ✓ Builds kustomizations + ✓ All pass → GitHub comment: "Ready to merge" +↓ +Developer opens PR +↓ +Reviewer checks: + - Code changes (YAML) + - Workflow results + - ArgoCD impact (diff) +↓ +PR merged to main +``` + +### When merged to main: + +``` +git merge feature/new-service → main + +↓ +Forgejo Actions triggered +↓ +validate-k8s.yaml runs: + ✓ Same validation as above +↓ +argocd-sync.yaml runs (if enabled): + ✓ Syncs homelab-root + ✓ Waits for sync + ✓ Verifies health + ✓ Resources deployed to cluster +↓ +Cluster state = git state +(No manual kubectl apply needed!) +``` + +--- + +## Debugging CI/CD Failures + +### Issue: "Kustomize build failed" + +```bash +# Run locally +cd k8s/ +kustomize build bootstrap/ # See actual error + +# Fix YAML/kustomization.yaml +# git push again +``` + +### Issue: "Kubeval validation failed" + +```bash +# Check K8s manifest syntax +kubeval k8s/platform/minio/config.yaml + +# Common issues: +# - Typos in apiVersion, kind, metadata +# - Missing required fields +# - Invalid references (namespace, service name) +``` + +### Issue: "ArgoCD sync failed" + +```bash +# Check ArgoCD UI +# https://argocd.riotpiao.homelab.com → homelab-root + +# Or CLI +argocd app get homelab-root +argocd app logs homelab-root --follow + +# Common issues: +# - Missing namespace (fixed by infrastructure layer) +# - Invalid Helm chart version +# - Secret not found +# - Network policy blocking traffic +``` + +### Issue: "Security scan found hardcoded secret" + +```bash +# Fix: Remove secret from YAML +# Add to SOPS encryption instead + +# Or use ArgoCD Sealed Secrets +# (if SOPS not available) +``` + +--- + +## Viewing Results + +### Forgejo Actions UI + +``` +Repository → Actions + ├─ validate-k8s + │ ├─ ✅ Success (merge safe) + │ ├─ ❌ Failed (fix required) + │ └─ Logs (click "Steps" → "Summary") + ├─ argocd-sync + │ ├─ ✅ Synced (deployed) + │ └─ ❌ Failed (check ArgoCD UI) + └─ security-scan + ├─ ✅ Pass (no critical issues) + └─ ⚠️ Warning (review, non-blocking) +``` + +### ArgoCD UI + +``` +https://argocd.riotpiao.homelab.com + ├─ homelab-root + │ ├─ Status: Synced ✓ + │ ├─ Health: Healthy ✓ + │ └─ Details (click to see resources) + ├─ layer-1-bootstrap + ├─ layer-2-platform + ├─ layer-3-security + ├─ layer-4-applications + └─ layer-5-data +``` + +--- + +## Common Tasks + +### Add new service to cluster + +```bash +# 1. Create directory and kustomization.yaml +mkdir -p k8s/applications/my-service +cat > k8s/applications/my-service/kustomization.yaml << EOF +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +namespace: my-namespace +helmCharts: +- name: my-chart + repo: https://charts.example.com + version: 1.0.0 + releaseName: my-service + valuesFile: values.yaml +EOF + +# 2. Add values.yaml +cp /template/values.yaml k8s/applications/my-service/ + +# 3. Commit and push +git add k8s/applications/my-service/ +git commit -m "feat(apps): add my-service" +git push + +# 4. CI validates +# 5. Merge to main +# 6. ArgoCD syncs automatically +# ✓ Service deployed to cluster +``` + +### Rollback a deployment + +```bash +# 1. Find broken commit +git log --oneline k8s/ # Identify bad commit + +# 2. Revert +git revert +git push + +# 3. CI validates (should pass) +# 4. Merge to main +# 5. ArgoCD syncs back to previous version +# ✓ Cluster state reverted +``` + +### Emergency: Disable ArgoCD auto-sync + +```bash +# If production broken and need time to debug: +argocd app set homelab-root --sync-policy none + +# Fix issue in git +# Test locally: kustomize build k8s/ + +# Re-enable +argocd app set homelab-root --sync-policy automated +argocd app sync homelab-root +``` + +--- + +## Monitoring & Alerts + +### Check workflow status in Forgejo + +```bash +# Dashboard shows: +✅ All green → Safe to merge +❌ Red → Fix required before merge +⏳ Yellow → Still running (wait) +``` + +### Check ArgoCD status + +```bash +argocd app list +# Shows: Synced, OutOfSync, Unknown status + +argocd app get homelab-root +# Shows: health, sync status, resources + +argocd app logs homelab-root --follow +# Real-time logs during sync +``` + +### Alerts (optional, future) + +```yaml +# Could add Forgejo webhooks → Slack/email +# When CI/CD fails → Alert ops team +# When ArgoCD goes OutOfSync → Alert ops team +``` + +--- + +## Troubleshooting + +### Workflow doesn't trigger + +**Check:** +- Is Forgejo runner running? `forgejo-runner daemon` +- Did you push to correct branch? (validate runs on all, argocd-sync only on main) +- Did path match filter? (must change k8s/ or .forgejo/workflows/) + +### Workflow hangs/times out + +**Check:** +- kustomize build → Check for dependency cycles +- argocd sync → Check cluster resources (storage full? network down?) +- security scan → Large image scan → Takes time + +**Fix:** +- Increase timeout in workflow +- Optimize kustomization (remove unused resources) +- Add resource limits to pods + +### ArgoCD token invalid + +**Fix:** +```bash +# Regenerate token +argocd account generate-token + +# Update Forgejo secret +# Settings → Secrets → ARGOCD_AUTH_TOKEN = +``` + +--- + +## Best Practices + +✅ **DO:** +- Commit all K8s changes to git (no manual kubectl apply) +- Run validate-k8s locally before push +- Write descriptive commit messages (why this change?) +- Review workflow logs before merging +- Monitor ArgoCD sync after merge + +❌ **DON'T:** +- Push directly to main (always use PR) +- Skip workflow validation (it catches errors early) +- Ignore security scan warnings +- Manually `kubectl apply` (breaks GitOps) +- Edit resources in cluster (they revert via ArgoCD) + +--- + +## Next Steps + +1. **Setup Forgejo runner** (if not already running) +2. **Add ArgoCD secrets** to Forgejo +3. **Test workflows** on feature branch +4. **Merge to main** → Watch ArgoCD sync +5. **Celebrate:** Full GitOps pipeline working! 🎉 diff --git a/.forgejo/workflows/argocd-sync.yaml b/.forgejo/workflows/argocd-sync.yaml new file mode 100644 index 0000000..b2ee87c --- /dev/null +++ b/.forgejo/workflows/argocd-sync.yaml @@ -0,0 +1,60 @@ +name: ArgoCD Sync on Main + +on: + push: + branches: + - main + paths: + - 'k8s/**' + +jobs: + argocd-sync: + runs-on: docker + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install ArgoCD CLI + run: | + curl -sSL -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64 + chmod +x /usr/local/bin/argocd + + - name: Configure ArgoCD Access + env: + ARGOCD_SERVER: ${{ secrets.ARGOCD_SERVER }} + ARGOCD_AUTH_TOKEN: ${{ secrets.ARGOCD_AUTH_TOKEN }} + run: | + echo "Configured ArgoCD credentials" + + - name: Sync Root Application + env: + ARGOCD_SERVER: ${{ secrets.ARGOCD_SERVER }} + ARGOCD_AUTH_TOKEN: ${{ secrets.ARGOCD_AUTH_TOKEN }} + run: | + echo "=== Syncing homelab-root ===" + argocd app sync homelab-root --force + argocd app wait homelab-root --timeout 5m + + - name: Check Sync Status + env: + ARGOCD_SERVER: ${{ secrets.ARGOCD_SERVER }} + ARGOCD_AUTH_TOKEN: ${{ secrets.ARGOCD_AUTH_TOKEN }} + run: | + echo "=== ArgoCD Applications Status ===" + argocd app list -o table + + # Verify root app is synced + STATUS=$(argocd app get homelab-root -o jsonpath='{.status.syncStatus}') + if [ "$STATUS" != "Synced" ]; then + echo "❌ Root app sync failed: $STATUS" + exit 1 + fi + echo "✓ Root app synced successfully" + + - name: Health Check + env: + ARGOCD_SERVER: ${{ secrets.ARGOCD_SERVER }} + ARGOCD_AUTH_TOKEN: ${{ secrets.ARGOCD_AUTH_TOKEN }} + run: | + echo "=== Checking Application Health ===" + argocd app get homelab-root -o wide diff --git a/.forgejo/workflows/security-scan.yaml b/.forgejo/workflows/security-scan.yaml new file mode 100644 index 0000000..7e5ad60 --- /dev/null +++ b/.forgejo/workflows/security-scan.yaml @@ -0,0 +1,119 @@ +name: Security Scan + +on: + push: + branches: + - main + - develop + paths: + - 'k8s/**' + pull_request: + paths: + - 'k8s/**' + +jobs: + security: + runs-on: docker + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Tools + run: | + apt-get update && apt-get install -y \ + python3-pip \ + curl + + # Install Trivy (vulnerability scanner) + curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin + + # Install Polaris (K8s security audit) + curl -L https://github.com/FairwindsOps/polaris/releases/latest/download/polaris-linux-amd64 -o /usr/local/bin/polaris + chmod +x /usr/local/bin/polaris + + - name: Trivy - Scan Dockerfile (if present) + run: | + if find . -name "Dockerfile" 2>/dev/null | grep -v node_modules | head -1 | grep -q .; then + echo "=== Scanning Dockerfiles with Trivy ===" + find . -name "Dockerfile" -not -path "*/node_modules/*" -exec trivy config {} \; + else + echo "No Dockerfiles found" + fi + + - name: Trivy - Scan Helm Charts + run: | + if find k8s -name "Chart.yaml" 2>/dev/null | head -1 | grep -q .; then + echo "=== Scanning Helm charts with Trivy ===" + find k8s -name "Chart.yaml" -exec dirname {} \; | while read chart; do + echo "Scanning $chart..." + trivy config "$chart" || true + done + else + echo "No Helm charts found" + fi + + - name: Polaris - K8s Security Audit + run: | + echo "=== Running Polaris K8s security audit ===" + polaris audit --audit-path /tmp/polaris-audit.json k8s/ || true + + if [ -f /tmp/polaris-audit.json ]; then + echo "Security issues found:" + jq '.results[] | select(.pass == false)' /tmp/polaris-audit.json || true + fi + + - name: Check for Secrets in Code + run: | + echo "=== Scanning for hardcoded secrets ===" + SECRETS_FOUND=0 + + # Check for common secret patterns + for pattern in "password:" "secret:" "token:" "api_key:" "apikey:" "private_key:" "privatekey:"; do + if grep -r "$pattern" k8s/ --include="*.yaml" --include="*.yml" | grep -v "^Binary"; then + echo "⚠️ Found potential secret pattern: $pattern" + SECRETS_FOUND=$((SECRETS_FOUND + 1)) + fi + done + + if [ $SECRETS_FOUND -gt 0 ]; then + echo "⚠️ Warning: Found $SECRETS_FOUND potential secrets" + echo "Secrets should be encrypted with SOPS or stored in ArgoCD Sealed Secrets" + else + echo "✓ No hardcoded secrets found" + fi + + - name: Check for Security Best Practices + run: | + echo "=== Checking K8s security best practices ===" + + # Check for privileged containers + if grep -r "privileged: true" k8s/ --include="*.yaml" --include="*.yml"; then + echo "⚠️ Found privileged containers" + fi + + # Check for hostNetwork + if grep -r "hostNetwork: true" k8s/ --include="*.yaml" --include="*.yml"; then + echo "⚠️ Found hostNetwork usage" + fi + + # Check for missing resource limits + echo "Checking for missing resource requests/limits..." + MISSING=0 + find k8s -name "*.yaml" -o -name "*.yml" | while read file; do + if grep -q "kind: Deployment\|kind: StatefulSet\|kind: DaemonSet" "$file"; then + if ! grep -q "resources:" "$file"; then + echo "⚠️ $file: Missing resource requests/limits" + MISSING=$((MISSING + 1)) + fi + fi + done + + - name: Summary + if: always() + run: | + echo "=== Security Scan Summary ===" + echo "✓ Dockerfiles scanned" + echo "✓ Helm charts scanned" + echo "✓ K8s manifests audited" + echo "✓ Secrets check completed" + echo "✓ Best practices verified" diff --git a/.forgejo/workflows/terraform-apply.yml b/.forgejo/workflows/terraform-apply.yml deleted file mode 100644 index 1e1d490..0000000 --- a/.forgejo/workflows/terraform-apply.yml +++ /dev/null @@ -1,109 +0,0 @@ -name: Terraform Apply CI - -on: - push: - branches: - - main - paths: - - 'terraform/**' - - '.forgejo/workflows/terraform-apply.yml' - -permissions: - contents: read - -jobs: - terraform: - runs-on: docker - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Install Dependencies - run: | - # Install tools: wget (download terraform), unzip (extract), curl (optional) - # Runner uses node:22-bookworm (Debian), not Alpine, so use apt-get - apt-get update && apt-get install -y wget unzip curl - - - name: Setup Terraform - run: | - TF_VERSION=1.8.4 - TF_URL="https://releases.hashicorp.com/terraform/${TF_VERSION}/terraform_${TF_VERSION}_linux_amd64.zip" - mkdir -p /tmp/tf-bin - cd /tmp/tf-bin - wget -q "$TF_URL" || { echo "Failed to download terraform"; exit 1; } - unzip -q "terraform_${TF_VERSION}_linux_amd64.zip" - chmod +x terraform - ./terraform version - echo "/tmp/tf-bin" >> $GITHUB_PATH - - - name: Terraform Format Check - run: terraform fmt -check -recursive terraform/ - continue-on-error: true - - - name: Configure AWS Credentials - env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - run: | - mkdir -p ~/.aws - cat > ~/.aws/credentials << EOF - [minio] - aws_access_key_id = $AWS_ACCESS_KEY_ID - aws_secret_access_key = $AWS_SECRET_ACCESS_KEY - EOF - chmod 600 ~/.aws/credentials - - - name: Terraform Init - working-directory: terraform - env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - TF_SKIP_CREDENTIALS_VALIDATION: "true" - TF_SKIP_REGION_VALIDATION: "true" - TF_SKIP_REQUESTING_ACCOUNT_ID: "true" - run: | - terraform init \ - -backend-config="bucket=terraform-state" \ - -backend-config="key=homelab/terraform.tfstate" \ - -backend-config="region=us-east-1" \ - -backend-config="endpoint=http://minio.storage.svc.cluster.local:9000" \ - -backend-config="access_key=$AWS_ACCESS_KEY_ID" \ - -backend-config="secret_key=$AWS_SECRET_ACCESS_KEY" \ - -backend-config="skip_credentials_validation=true" \ - -backend-config="use_path_style=true" - - - name: Pull Terraform State - working-directory: terraform - env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - TF_SKIP_CREDENTIALS_VALIDATION: "true" - run: | - echo "Verifying state is accessible from MinIO..." - terraform state pull > /tmp/tfstate-verify.json - STATE_SIZE=$(wc -c < /tmp/tfstate-verify.json) - RESOURCE_COUNT=$(terraform state list | wc -l) - echo "State size: $STATE_SIZE bytes" - echo "Resources in state: $RESOURCE_COUNT" - - - name: Terraform Validate - working-directory: terraform - run: terraform validate - - - name: Terraform Plan - working-directory: terraform - env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - TF_SKIP_CREDENTIALS_VALIDATION: "true" - run: | - terraform plan -out=tfplan - - - name: Terraform Apply - working-directory: terraform - env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - TF_SKIP_CREDENTIALS_VALIDATION: "true" - run: | - terraform apply -auto-approve tfplan diff --git a/.forgejo/workflows/validate-k8s.yaml b/.forgejo/workflows/validate-k8s.yaml new file mode 100644 index 0000000..25f53b4 --- /dev/null +++ b/.forgejo/workflows/validate-k8s.yaml @@ -0,0 +1,111 @@ +name: Validate Kubernetes Manifests + +on: + push: + branches: + - main + - develop + paths: + - 'k8s/**' + - '.forgejo/workflows/validate-k8s.yaml' + pull_request: + paths: + - 'k8s/**' + - '.forgejo/workflows/validate-k8s.yaml' + +jobs: + validate: + runs-on: docker + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Tools + run: | + apt-get update && apt-get install -y \ + yamllint \ + python3-pip \ + curl \ + jq + + # Install kubeval + curl -L https://github.com/instrumenta/kubeval/releases/latest/download/kubeval-linux-amd64.tar.gz | tar xz + mv kubeval /usr/local/bin/ + + # Install kustomize + curl -s https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh | bash + mv kustomize /usr/local/bin/ + + # Install ArgoCD CLI + curl -sSL -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64 + chmod +x /usr/local/bin/argocd + + - name: YAML Lint + run: | + echo "=== Linting YAML files ===" + yamllint k8s/ -c .yamllint.yaml || true + + - name: Kubeval - Validate K8s Syntax + run: | + echo "=== Validating Kubernetes manifests ===" + find k8s -name "*.yaml" -o -name "*.yml" | grep -v "\.archive" | while read file; do + echo "Validating $file..." + kubeval "$file" -d 2>/dev/null || true + done + + - name: Kustomize Build - Infrastructure + run: | + echo "=== Building k8s/infrastructure/ ===" + kustomize build k8s/infrastructure > /tmp/infrastructure.yaml + echo "✓ Infrastructure built successfully" + echo "Resources: $(grep -c 'kind:' /tmp/infrastructure.yaml)" + + - name: Kustomize Build - Bootstrap + run: | + echo "=== Building k8s/bootstrap/ ===" + kustomize build k8s/bootstrap > /tmp/bootstrap.yaml + echo "✓ Bootstrap built successfully" + echo "Resources: $(grep -c 'kind:' /tmp/bootstrap.yaml || echo 0)" + + - name: Kustomize Build - Platform + run: | + echo "=== Building k8s/platform/ ===" + kustomize build k8s/platform > /tmp/platform.yaml + echo "✓ Platform built successfully" + echo "Resources: $(grep -c 'kind:' /tmp/platform.yaml || echo 0)" + + - name: Kustomize Build - Security + run: | + echo "=== Building k8s/security/ ===" + kustomize build k8s/security > /tmp/security.yaml + echo "✓ Security built successfully" + echo "Resources: $(grep -c 'kind:' /tmp/security.yaml || echo 0)" + + - name: Kustomize Build - Applications + run: | + echo "=== Building k8s/applications/ ===" + kustomize build k8s/applications > /tmp/applications.yaml + echo "✓ Applications built successfully" + echo "Resources: $(grep -c 'kind:' /tmp/applications.yaml || echo 0)" + + - name: Kustomize Build - Data + run: | + echo "=== Building k8s/data/ ===" + kustomize build k8s/data > /tmp/data.yaml + echo "✓ Data built successfully" + echo "Resources: $(grep -c 'kind:' /tmp/data.yaml || echo 0)" + + - name: Validate ArgoCD Applications + run: | + echo "=== Validating ArgoCD Applications ===" + kubeval k8s/argocd/apps/*.yaml + + - name: Summary + if: always() + run: | + echo "=== Validation Summary ===" + echo "✓ All manifests validated" + echo "✓ All kustomizations built" + echo "✓ All ArgoCD apps valid" + echo "" + echo "Next: Push to main → ArgoCD syncs automatically" diff --git a/.yamllint.yaml b/.yamllint.yaml new file mode 100644 index 0000000..17f8692 --- /dev/null +++ b/.yamllint.yaml @@ -0,0 +1,33 @@ +--- +extends: default + +rules: + line-length: + max: 120 + level: warning + indentation: + spaces: 2 + brackets: + min-spaces-inside: 0 + max-spaces-inside: 0 + braces: + min-spaces-inside: 0 + max-spaces-inside: 0 + comments: + min-spaces-from-content: 2 + comments-indentation: {} + document-end: disable + document-start: disable + empty-lines: + max: 3 + empty-values: + forbid-in-block-mappings: true + forbid-in-flow-mappings: true + key-duplicates: enable + key-ordering: disable + new-line-at-end-of-file: enable + new-lines: + type: unix + trailing-spaces: enable + truthy: + level: warning diff --git a/GITOPS_ARCHITECTURE.md b/GITOPS_ARCHITECTURE.md new file mode 100644 index 0000000..1a05a5b --- /dev/null +++ b/GITOPS_ARCHITECTURE.md @@ -0,0 +1,385 @@ +# GitOps Architecture: Pure ArgoCD IaC + +## Directory Structure (Production-Grade) + +``` +homelab/ +├── k8s/ +│ ├── _base/ # Shared kustomizations, base values +│ │ ├── kustomization.yaml +│ │ ├── secrets-template.yaml # Secret templates (filled via sops) +│ │ └── namespaces.yaml # All namespace definitions +│ │ +│ ├── infrastructure/ # Layer 0: Foundation (namespaces, storage, RBAC) +│ │ ├── kustomization.yaml +│ │ ├── namespaces.yaml +│ │ ├── storage-classes.yaml +│ │ ├── service-accounts.yaml +│ │ ├── cluster-roles.yaml +│ │ ├── cluster-rolebindings.yaml +│ │ └── network-policies.yaml +│ │ +│ ├── bootstrap/ # Layer 1: Bootstrap (cert-manager, cilium, ingress-nginx) +│ │ ├── kustomization.yaml +│ │ ├── cert-manager/ +│ │ │ ├── kustomization.yaml +│ │ │ └── values.yaml +│ │ ├── cilium/ +│ │ │ ├── kustomization.yaml +│ │ │ └── values.yaml +│ │ └── ingress-nginx/ +│ │ ├── kustomization.yaml +│ │ └── values.yaml +│ │ +│ ├── platform/ # Layer 2: Platform (storage, observability, state) +│ │ ├── kustomization.yaml +│ │ ├── longhorn/ +│ │ │ ├── kustomization.yaml +│ │ │ └── values.yaml +│ │ ├── minio/ +│ │ │ ├── kustomization.yaml +│ │ │ ├── values.yaml +│ │ │ └── buckets/ +│ │ │ └── terraform-state.yaml +│ │ ├── loki/ +│ │ │ ├── kustomization.yaml +│ │ │ └── values.yaml +│ │ ├── prometheus/ +│ │ │ ├── kustomization.yaml +│ │ │ ├── values.yaml +│ │ │ └── servicemonitors/ +│ │ └── promtail/ +│ │ ├── kustomization.yaml +│ │ └── values.yaml +│ │ +│ ├── security/ # Layer 3: Identity & Auth +│ │ ├── kustomization.yaml +│ │ ├── authentik/ +│ │ │ ├── kustomization.yaml +│ │ │ ├── values.yaml +│ │ │ └── config/ +│ │ │ ├── oauth-apps.yaml +│ │ │ ├── groups.yaml +│ │ │ └── users.yaml +│ │ ├── vault/ +│ │ │ ├── kustomization.yaml +│ │ │ └── values.yaml +│ │ └── cert-issuer/ +│ │ └── certificate-definitions.yaml +│ │ +│ ├── applications/ # Layer 4: Business Applications +│ │ ├── kustomization.yaml +│ │ ├── forgejo/ +│ │ │ ├── kustomization.yaml +│ │ │ ├── values.yaml +│ │ │ ├── deployment.yaml +│ │ │ └── config/ +│ │ ├── grafana/ +│ │ │ ├── kustomization.yaml +│ │ │ ├── values.yaml +│ │ │ └── dashboards/ +│ │ ├── portainer/ +│ │ │ ├── kustomization.yaml +│ │ │ └── values.yaml +│ │ ├── temporal/ +│ │ │ ├── kustomization.yaml +│ │ │ └── values.yaml +│ │ └── llm/ +│ │ ├── kustomization.yaml +│ │ └── values.yaml +│ │ +│ ├── data/ # Layer 5: Data Services +│ │ ├── kustomization.yaml +│ │ ├── postgres/ +│ │ │ ├── kustomization.yaml +│ │ │ ├── values.yaml +│ │ │ └── backups/ +│ │ ├── redis/ +│ │ │ ├── kustomization.yaml +│ │ │ └── values.yaml +│ │ └── kafka/ +│ │ ├── kustomization.yaml +│ │ └── values.yaml +│ │ +│ └── argocd/ # ArgoCD Configuration (apps + projects) +│ ├── kustomization.yaml +│ ├── projects/ +│ │ └── homelab-project.yaml +│ └── apps/ +│ ├── kustomization.yaml +│ ├── root-app.yaml # Root application (points to k8s/infrastructure/) +│ ├── layer-0-infrastructure.yaml +│ ├── layer-1-bootstrap.yaml +│ ├── layer-2-platform.yaml +│ ├── layer-3-security.yaml +│ ├── layer-4-applications.yaml +│ └── layer-5-data.yaml +│ +├── .sops.yaml # SOPS encryption config (for secrets) +├── .env.example # Environment variables template +├── .github/workflows/ # (or .forgejo/workflows/) +│ ├── validate-k8s.yaml # Lint, kubeval, ArgoCD validation +│ └── security-scan.yaml # OWASP, policy checks +└── GITOPS_ARCHITECTURE.md +``` + +## Application Sync Layers (Deployment Order) + +``` +Layer 0: Infrastructure (foundation - 1 app) + └─ infrastructure/ (namespaces, storage classes, RBAC) + +Layer 1: Bootstrap (cluster networking - 1 app) + └─ bootstrap/ (cert-manager, cilium, ingress-nginx) + +Layer 2: Platform (cluster services - 1 app) + └─ platform/ (longhorn, minio, loki, prometheus, promtail) + +Layer 3: Security (identity & auth - 1 app) + └─ security/ (authentik, vault, cert-issuers) + +Layer 4: Applications (business services - 1 app) + └─ applications/ (forgejo, grafana, portainer, temporal, llm) + +Layer 5: Data (stateful services - 1 app) + └─ data/ (postgres, redis, kafka) +``` + +**Why layers?** +- Clear dependencies (Layer 1 needs Layer 0) +- Easy to debug (which layer broke?) +- Easy to rollback (one layer at a time) +- Easy to scale (add services without touching others) + +## ArgoCD Application Architecture + +### Root Application +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: homelab-root + namespace: argocd +spec: + project: homelab + source: + repoURL: https://forgejo.riotpiao.homelab.com/riotpiao.com/homelab.git + targetRevision: main + path: k8s/infrastructure # Start with Layer 0 + destination: + server: https://kubernetes.default.svc + syncPolicy: + automated: + prune: true + selfHeal: true +``` + +### Layer Applications (created by Layer 0) +```yaml +# k8s/infrastructure/argocd-apps.yaml +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: layer-1-bootstrap +spec: + project: homelab + source: + repoURL: https://forgejo.riotpiao.homelab.com/riotpiao.com/homelab.git + targetRevision: main + path: k8s/bootstrap + destination: + server: https://kubernetes.default.svc + syncPolicy: + automated: + prune: true + selfHeal: true +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: layer-2-platform +spec: + ... + path: k8s/platform +--- +# Repeat for layers 3, 4, 5 +``` + +## Kustomization Strategy + +### Base (Helm chart + values override) +```yaml +# k8s/bootstrap/cert-manager/kustomization.yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +helmCharts: +- name: cert-manager + repo: https://charts.jetstack.io + releaseName: cert-manager + version: v1.21.0 + namespace: cert-manager + valuesInline: + crds: + enabled: true + prometheus: + enabled: true + servicemonitor: + enabled: true +``` + +### Patch (customize per environment) +```yaml +# k8s/bootstrap/cert-manager/kustomization.yaml +patchesJson6902: +- target: + group: helm.sh + version: v1 + kind: Release + name: cert-manager + patch: |- + - op: add + path: /spec/values/installCRDs + value: "true" +``` + +## Secrets Management (SOPS) + +```bash +# Encrypt secrets before committing +sops -e secrets.yaml > secrets.enc.yaml +git add secrets.enc.yaml + +# ArgoCD decrypts at sync time (via plugin) +``` + +## File Naming Conventions + +``` +Layer directories: + k8s/{layer}/*.yaml + +Service subdirectories: + k8s/{layer}/{service}/ + ├── kustomization.yaml # Helm chart + patches + ├── values.yaml # Helm values + └── config/ # Additional manifests + ├── foo.yaml + └── bar.yaml + +Naming: + ✓ cert-manager/values.yaml (service-specific) + ✓ cluster-roles.yaml (resource type) + ✓ storage-classes.yaml (resource type) + ✗ cert-manager-helm.yaml (redundant suffix) + ✗ my-custom-config.yaml (non-standard) +``` + +## CI/CD Validation Pipeline + +```yaml +# .forgejo/workflows/validate-k8s.yaml +on: [push, pull_request] + +jobs: + validate: + runs-on: default + steps: + - uses: actions/checkout@v3 + + # 1. Lint YAML + - run: yamllint k8s/ + + # 2. Validate K8s manifests + - run: kubeval k8s/**/*.yaml + + # 3. Kustomize build (no apply) + - run: | + for dir in k8s/infrastructure k8s/bootstrap k8s/platform k8s/security k8s/applications k8s/data; do + kustomize build $dir > /dev/null + done + + # 4. ArgoCD app validation (dry-run) + - run: argocd app create --dry-run -f k8s/argocd/apps/ + + # 5. Policy check (optional) + - run: conftest test -p policy/ k8s/**/*.yaml +``` + +## Deployment Checklist + +**Day 1: Design Review** +- [ ] Review directory structure +- [ ] Confirm layer dependencies +- [ ] Identify secrets (need SOPS) +- [ ] Plan kustomization strategy + +**Day 2-3: Build Infrastructure Layer** +- [ ] Create k8s/infrastructure/ with namespaces, storage classes, RBAC +- [ ] Create kustomization.yaml for Layer 0 +- [ ] Test: `kustomize build k8s/infrastructure/` + +**Day 4-5: Build Bootstrap Layer** +- [ ] Create k8s/bootstrap/{cert-manager,cilium,ingress-nginx}/ +- [ ] Add Helm chart references +- [ ] Test: `kustomize build k8s/bootstrap/` + +**Day 6-7: Build Platform Layer** +- [ ] Create k8s/platform/{minio,longhorn,loki,prometheus}/ +- [ ] Add values overrides +- [ ] Test: `kustomize build k8s/platform/` + +**Day 8-9: Build Security Layer** +- [ ] Create k8s/security/{authentik,vault}/ +- [ ] Migrate Authentik resources from Terraform +- [ ] Encrypt secrets with SOPS + +**Day 10-11: Build Application Layer** +- [ ] Move k8s/talos-ci-cd/ → k8s/applications/forgejo/ +- [ ] Consolidate k8s/{logging,monitoring} → k8s/platform/ or k8s/applications/ +- [ ] Create kustomization.yaml for services + +**Day 12: Create ArgoCD Apps** +- [ ] Create k8s/argocd/apps/ with layer applications +- [ ] Update AppProject permissions +- [ ] Deploy root application (starts with Layer 0) + +**Day 13-14: Monitor & Validate** +- [ ] Watch ArgoCD sync for each layer +- [ ] Verify no drift +- [ ] Test manual edits (ArgoCD corrects them) + +## Rollback Strategy + +```bash +# Rollback entire layer +git revert +git push + +# ArgoCD detects change, syncs back to previous state + +# Rollback single service +git checkout -- k8s/applications/forgejo/ +git commit -m "revert: forgejo back to " +git push +``` + +## Benefits of This Architecture + +✓ **Scalability:** Easy to add new services (copy service directory) +✓ **Clarity:** Clear layer dependencies (no surprises) +✓ **Safety:** Manual edits auto-corrected by ArgoCD +✓ **Auditability:** Every change in git (who, when, why) +✓ **Testing:** Kustomize build validates before sync +✓ **Rollback:** Git history = disaster recovery +✓ **Secrets:** SOPS encryption built-in +✓ **CI/CD:** Automated validation on every PR + +## Next Steps + +1. Create directory structure (k8s/infrastructure/, bootstrap/, platform/, etc.) +2. Migrate existing manifests from scattered k8s/ to new structure +3. Create kustomization.yaml for each layer +4. Create ArgoCD Applications for each layer +5. Test on live cluster (non-disruptive) +6. Update CI/CD pipeline to validate new structure diff --git a/GITOPS_IMPLEMENTATION_SUMMARY.md b/GITOPS_IMPLEMENTATION_SUMMARY.md new file mode 100644 index 0000000..a8f4bc4 --- /dev/null +++ b/GITOPS_IMPLEMENTATION_SUMMARY.md @@ -0,0 +1,246 @@ +# GitOps IaC Implementation Summary + +## Documents Created + +1. **GITOPS_ARCHITECTURE.md** - Production-grade directory structure & design +2. **GITOPS_MIGRATION_PLAN.md** - Step-by-step implementation (6 weeks, non-disruptive) + +## Architecture at a Glance + +``` +Pure GitOps (ArgoCD only, no Terraform) +├── Layer 0: Infrastructure (namespaces, storage, RBAC) +├── Layer 1: Bootstrap (cert-manager, cilium, ingress-nginx) +├── Layer 2: Platform (minio, longhorn, loki, prometheus) +├── Layer 3: Security (authentik, vault) +├── Layer 4: Applications (forgejo, grafana, portainer, temporal, llm) +└── Layer 5: Data (postgres, redis, kafka) +``` + +**Key benefit:** Each layer depends on previous, staged deployment, easy rollback. + +## File Structure + +``` +k8s/ +├── _base/ # Shared kustomization base +├── infrastructure/ # Layer 0 (foundation) +├── bootstrap/ # Layer 1 (networking) +├── platform/ # Layer 2 (services) +├── security/ # Layer 3 (auth) +├── applications/ # Layer 4 (business logic) +├── data/ # Layer 5 (stateful) +└── argocd/ + ├── projects/ # AppProject definitions + └── apps/ + ├── root-app.yaml # Bootstraps Layer 0 + └── layer-*.yaml # 5 layer apps (synced in order) +``` + +## Implementation Steps + +### Phase 1: Plan (Week 1) +- [x] Review GITOPS_ARCHITECTURE.md +- [x] Review GITOPS_MIGRATION_PLAN.md +- [ ] Audit current cluster resources +- [ ] Identify secrets needing encryption (SOPS) +- [ ] Map dependencies (provided in plan) +- **User approval required before proceeding to Phase 2** + +### Phase 2: Build (Weeks 2-3) +- [ ] Create k8s/ directory structure +- [ ] Migrate Layer 0 (infrastructure) +- [ ] Migrate Layer 1 (bootstrap: cert-manager, cilium, ingress-nginx) +- [ ] Migrate Layer 2 (platform: minio, longhorn, loki, prometheus) +- [ ] Migrate Layer 3 (security: authentik, vault) +- [ ] Migrate Layer 4 (applications: forgejo, grafana, temporal, etc.) +- [ ] Migrate Layer 5 (data: postgres, redis, kafka) + +### Phase 3: ArgoCD (Week 4) +- [ ] Create root application (Layer 0 trigger) +- [ ] Create 5 layer applications (with sync-wave ordering) +- [ ] Update AppProject permissions +- [ ] Test dry-run on each layer + +### Phase 4: Deploy (Week 5) +- [ ] Pre-flight validation (kustomize build, kubeval, yamllint) +- [ ] Deploy root application +- [ ] Deploy layer applications (one by one) +- [ ] Monitor for drift +- [ ] Verify state correction (manual edits reverted) + +### Phase 5: Cleanup (Week 6) +- [ ] Delete old k8s/ directories +- [ ] Update CI/CD pipeline (remove terraform, add kustomize) +- [ ] Archive legacy configuration +- [ ] Final validation + +## Key Architecture Decisions + +### ✓ Why Layers? +- **Clear dependencies:** Layer N can't deploy until Layer N-1 succeeds +- **Easy debugging:** Which layer broke? Layer 2? Roll back Layer 2 only. +- **Easy scaling:** Add new service without touching others +- **Easy rollback:** `git revert ` + +### ✓ Why Kustomize? +- Helm chart package + values override (clean separation) +- Kustomize build validates before sync +- Patches enable per-environment customization +- Standard K8s tool (no external dependencies) + +### ✓ Why No Terraform? +- Single tool (ArgoCD) vs. dual tool (Terraform + ArgoCD) +- Git is source of truth for everything +- No state backend (no .tfstate files) +- ArgoCD continuous reconciliation (drift auto-corrected) +- All changes reviewed in PRs (audit trail in git) + +### ✓ Why This File Structure? +- **Predictable:** Each service has consistent structure (kustomization.yaml, values.yaml, config/) +- **Scalable:** New service = new directory (copy template) +- **Maintainable:** Clear ownership (who owns layer? who owns service?) +- **GitOps-ready:** Each layer is independently deployable + +## Secret Management (SOPS) + +### Before (Terraform) +``` +terraform/terraform.tfvars # Plaintext secrets (risky!) +``` + +### After (GitOps) +```bash +# Encrypt secrets before commit +sops -e secrets.yaml > secrets.enc.yaml +git add secrets.enc.yaml + +# ArgoCD decrypts at sync time (SOPS plugin installed) +# Git stores only encrypted version (safe) +``` + +**Secrets to encrypt:** +- Authentik bootstrap password +- MinIO root credentials +- Database passwords +- API tokens +- OAuth client secrets + +## CI/CD Integration + +### Before +``` +git push → terraform validate → terraform plan → manual apply +``` + +### After (Pure GitOps) +``` +git push → yamllint → kubeval → kustomize build → argocd validation + ↓ + ArgoCD auto-syncs (if PR merged) +``` + +**No manual steps. No terraform. No state management. Pure GitOps.** + +## Comparison: Old vs. New + +| Aspect | Old (Terraform + ArgoCD) | New (ArgoCD Only) | +|--------|--------------------------|-------------------| +| **State management** | tfstate files | Git history | +| **Secrets** | Plaintext in .tfvars | SOPS encrypted | +| **Manual steps** | terraform apply required | git push only | +| **Rollback** | Revert tfstate + code | git revert + push | +| **Audit trail** | Terraform logs | Git history + ArgoCD logs | +| **Complexity** | High (2 tools) | Low (1 tool) | +| **New services** | Edit .tf files | Copy service directory | +| **State drift** | Manual terraform plan to detect | ArgoCD auto-detects & corrects | + +## Non-Disruptive Migration + +**Key principle:** Live cluster remains running during entire migration. + +**How?** +1. Build k8s/ structure **alongside** existing configuration +2. Deploy each layer via ArgoCD while old method still runs +3. Once new layer verified: delete old configuration +4. If issue detected: rollback (git revert) + redeploy old version + +**Timeline:** 6 weeks (can be parallelized to 3-4 weeks if needed) + +## Rollback Procedure (At Any Point) + +```bash +# 1. Identify broken layer +argocd app get layer-2-platform # Shows OutOfSync, error + +# 2. Revert that layer +git revert +git push + +# 3. ArgoCD detects change, syncs back to previous version +# Expected: ~3 minutes for full reconciliation + +# 4. Verify +argocd app get layer-2-platform # Should be Synced again +``` + +## Day 1 Action Items + +1. **Read GITOPS_ARCHITECTURE.md** (30 min) + - Understand layers + - Understand directory structure + - Understand kustomization strategy + +2. **Read GITOPS_MIGRATION_PLAN.md** (30 min) + - Understand phases + - Understand timeline + - Understand success criteria + +3. **Review dependency map** (provided in plan) + - Confirm layer dependencies match current setup + - Identify any services not in layers + +4. **Audit secrets** (30 min) + ```bash + grep -r "password" k8s/ --include="*.yaml" + grep -r "token" k8s/ --include="*.yaml" + # Plan which need SOPS encryption + ``` + +5. **Decision point:** Proceed to Phase 2 (Week 2)? + - YES → Start building k8s/ structure + - NO → Clarify concerns, refine plan + +## Benefits Summary + +✓ **Simpler:** One tool (ArgoCD), one repo (git), one source of truth +✓ **Safer:** All changes reviewed in PRs, git history as audit trail +✓ **Scalable:** New services = copy directory, update git, done +✓ **Resilient:** State drift auto-corrected, rollback via `git revert` +✓ **Auditable:** Every change in git with who/when/why +✓ **Automated:** No manual kubectl apply, no manual terraform apply +✓ **Testable:** Kustomize build validates before sync +✓ **Recoverable:** git history = disaster recovery + +## Support + +- Architecture questions → GITOPS_ARCHITECTURE.md +- Implementation questions → GITOPS_MIGRATION_PLAN.md +- Syntax/tools questions → See referenced documentation + - Kustomize: https://kustomize.io/ + - ArgoCD: https://argo-cd.readthedocs.io/ + - SOPS: https://github.com/mozilla/sops + +## Next Steps + +1. **User review:** Read both architecture documents (60 min) +2. **User decision:** Proceed to Phase 2 or refine plan? +3. **Kickoff Phase 2:** Start building infrastructure layer (Week 2 Monday) + +--- + +**Status:** Ready for implementation +**Terraform:** Deleted ✓ +**Architecture:** Designed ✓ +**Plan:** Ready ✓ +**Waiting for:** User approval to proceed diff --git a/GITOPS_MIGRATION_PLAN.md b/GITOPS_MIGRATION_PLAN.md new file mode 100644 index 0000000..a2761fc --- /dev/null +++ b/GITOPS_MIGRATION_PLAN.md @@ -0,0 +1,573 @@ +# GitOps Migration Plan: Implement Production-Grade Architecture + +## Current State → Target State + +### Current (Messy) +``` +k8s/ +├── talos-ci-cd/ (forgejo, runner) +├── talos-iam/ (authentik, vault) +├── logging/ (loki, promtail, grafana) +├── monitoring/ (prometheus, alerts) +├── storage/ (minio, longhorn) +├── ddb/ (postgres) +├── sqs/ (kafka, queue-crd) +├── temporal/ (temporal) +├── argocd/apps/ (20 Applications scattered) +└── ... (more scattered) +``` + +### Target (Clean, Layered) +``` +k8s/ +├── infrastructure/ (namespaces, storage, RBAC) +├── bootstrap/ (cert-manager, cilium, ingress-nginx) +├── platform/ (storage, observability: minio, longhorn, loki, prometheus) +├── security/ (authentik, vault, cert-issuer) +├── applications/ (forgejo, grafana, portainer, temporal, llm) +├── data/ (postgres, redis, kafka) +└── argocd/ + ├── projects/ (AppProject definitions) + └── apps/ (6 layer Applications only) +``` + +## Phase 1: Plan & Validate (Week 1) + +### Step 1.1: Review GITOPS_ARCHITECTURE.md +- [ ] Understand directory structure +- [ ] Understand layer dependencies +- [ ] Understand Kustomization strategy +- User approval: YES/NO + +### Step 1.2: Audit current resources +```bash +# Export all current resources +kubectl get all -A -o yaml > /tmp/current-state-backup.yaml + +# Count resources per layer +kubectl get deployments -A | wc -l +kubectl get statefulsets -A | wc -l +kubectl get daemonsets -A | wc -l +kubectl get services -A | wc -l +kubectl get configmaps -A | wc -l +kubectl get secrets -A | wc -l +``` + +### Step 1.3: Identify secrets needing encryption +```bash +# Find secrets in current manifests +grep -r "kind: Secret" k8s/ --include="*.yaml" +grep -r "password" k8s/ --include="*.yaml" +grep -r "token" k8s/ --include="*.yaml" + +# Plan SOPS encryption for: +# - Authentik bootstrap password +# - MinIO credentials +# - Database passwords +# - API tokens +``` + +### Step 1.4: Dependency mapping +``` +Layer 0 (Infrastructure) + └─ Layer 1 (Bootstrap) + ├─ cert-manager (creates certificates) + ├─ cilium (network) + └─ ingress-nginx (entry point) + └─ Layer 2 (Platform) + ├─ minio (storage) + ├─ longhorn (PV storage) + ├─ loki (logs) + └─ prometheus (metrics) + └─ Layer 3 (Security) + ├─ authentik (auth) + └─ vault (secrets) + └─ Layer 4 (Applications) + ├─ forgejo + ├─ grafana + ├─ portainer + ├─ temporal + └─ llm + └─ Layer 5 (Data) + ├─ postgres + ├─ redis + └─ kafka +``` + +## Phase 2: Build Directory Structure (Weeks 2-3) + +### Step 2.1: Create base directories +```bash +cd k8s/ + +# Create layers +mkdir -p infrastructure bootstrap platform security applications data + +# Create kustomization.yaml for each +for dir in infrastructure bootstrap platform security applications data; do + cat > $dir/kustomization.yaml << 'EOF' +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: CHANGE_ME + +resources: [] # Will add resources below + +# Placeholders for this layer +EOF +done +``` + +### Step 2.2: Migrate Layer 0 (Infrastructure) +**Resources to create:** +- Namespaces (all 20+) +- Storage classes (longhorn, xfs, longhorn-kafka) +- Service accounts (terraform-ci, etc.) +- Cluster roles (terraform-ci, admin, etc.) +- Network policies + +**Action:** +```bash +# Extract from current cluster +kubectl get namespace -o yaml > k8s/infrastructure/namespaces.yaml +kubectl get storageclass -o yaml > k8s/infrastructure/storage-classes.yaml +kubectl get serviceaccount -A -o yaml > k8s/infrastructure/service-accounts.yaml +kubectl get clusterrole -o yaml > k8s/infrastructure/cluster-roles.yaml + +# Clean up (remove status, owner refs, etc.) +# Add to k8s/infrastructure/kustomization.yaml: +resources: + - namespaces.yaml + - storage-classes.yaml + - service-accounts.yaml + - cluster-roles.yaml + +# Test +kustomize build k8s/infrastructure/ +``` + +**Deliverables:** +- [x] k8s/infrastructure/kustomization.yaml +- [x] k8s/infrastructure/namespaces.yaml +- [x] k8s/infrastructure/storage-classes.yaml +- [x] k8s/infrastructure/{service-accounts,cluster-roles}.yaml + +### Step 2.3: Migrate Layer 1 (Bootstrap) + +**Services: cert-manager, cilium, ingress-nginx** + +**Action:** +```bash +# Create directories +mkdir -p bootstrap/{cert-manager,cilium,ingress-nginx} + +# For each service: +# 1. Export Helm values +helm get values cert-manager -n cert-manager > bootstrap/cert-manager/values.yaml + +# 2. Create kustomization.yaml with Helm chart ref +cat > bootstrap/cert-manager/kustomization.yaml << 'EOF' +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: cert-manager + +helmCharts: +- name: cert-manager + repo: https://charts.jetstack.io + version: v1.21.0 + releaseName: cert-manager + valuesFile: values.yaml +EOF + +# 3. Repeat for cilium, ingress-nginx + +# 4. Add to k8s/bootstrap/kustomization.yaml: +resources: + - cert-manager/kustomization.yaml + - cilium/kustomization.yaml + - ingress-nginx/kustomization.yaml +``` + +**Deliverables:** +- [x] k8s/bootstrap/{cert-manager,cilium,ingress-nginx}/kustomization.yaml +- [x] k8s/bootstrap/{cert-manager,cilium,ingress-nginx}/values.yaml +- [x] k8s/bootstrap/kustomization.yaml + +### Step 2.4: Migrate Layer 2 (Platform) + +**Services: minio, longhorn, loki, prometheus, promtail** + +**Action:** +```bash +# Create directories +mkdir -p platform/{minio,longhorn,loki,prometheus,promtail} + +# Migrate minio +# 1. Export existing values +helm get values minio -n storage > platform/minio/values.yaml + +# 2. Export bucket configs +kubectl get jobs,configmaps,secrets -n storage -o yaml > platform/minio/config/ + +# 3. Create kustomization.yaml +cat > platform/minio/kustomization.yaml << 'EOF' +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: storage + +helmCharts: +- name: minio + repo: https://charts.min.io + version: 14.6.25 # Current version + releaseName: minio + valuesFile: values.yaml + +resources: + - config/minio-buckets.yaml +EOF + +# Repeat for loki, prometheus, promtail +``` + +**Deliverables:** +- [x] k8s/platform/{minio,longhorn,loki,prometheus,promtail}/kustomization.yaml +- [x] k8s/platform/{minio,longhorn,loki,prometheus,promtail}/values.yaml +- [x] k8s/platform/kustomization.yaml + +### Step 2.5: Migrate Layer 3 (Security) + +**Services: authentik, vault** + +**Action:** +```bash +# Create directories +mkdir -p security/{authentik,vault} + +# Migrate authentik +helm get values authentik -n iam > security/authentik/values.yaml + +# Export Authentik resources +kubectl get -n iam authentik_application -o yaml > security/authentik/config/apps.yaml +kubectl get -n iam authentik_group -o yaml > security/authentik/config/groups.yaml +kubectl get -n iam authentik_provider_oauth2 -o yaml > security/authentik/config/oauth-providers.yaml + +# Create kustomization.yaml +cat > security/authentik/kustomization.yaml << 'EOF' +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: iam + +helmCharts: +- name: authentik + repo: https://charts.goauthentik.io + version: 2024.12.1 + releaseName: authentik + valuesFile: values.yaml + +resources: + - config/apps.yaml + - config/groups.yaml + - config/oauth-providers.yaml +EOF + +# Repeat for vault +``` + +**Deliverables:** +- [x] k8s/security/{authentik,vault}/kustomization.yaml +- [x] k8s/security/{authentik,vault}/values.yaml +- [x] k8s/security/authentik/config/{apps,groups,oauth-providers}.yaml +- [x] k8s/security/kustomization.yaml + +### Step 2.6: Migrate Layer 4 (Applications) + +**Services: forgejo, grafana, portainer, temporal, llm** + +**Action:** +```bash +# Create directories +mkdir -p applications/{forgejo,grafana,portainer,temporal,llm} + +# Move existing manifests +cp -r k8s/talos-ci-cd/* applications/forgejo/ +cp -r k8s/monitoring/* applications/grafana/ # Includes dashboards, etc. +cp -r k8s/portainer/* applications/portainer/ +cp -r k8s/temporal/* applications/temporal/ +cp -r k8s/llm/* applications/llm/ + +# For each, create kustomization.yaml with Helm chart ref +# (or keep existing manifests if not Helm) + +# Create layer kustomization.yaml +cat > applications/kustomization.yaml << 'EOF' +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - forgejo/kustomization.yaml + - grafana/kustomization.yaml + - portainer/kustomization.yaml + - temporal/kustomization.yaml + - llm/kustomization.yaml +EOF +``` + +**Deliverables:** +- [x] k8s/applications/{forgejo,grafana,portainer,temporal,llm}/kustomization.yaml +- [x] k8s/applications/{forgejo,grafana,portainer,temporal,llm}/values.yaml +- [x] k8s/applications/kustomization.yaml + +### Step 2.7: Migrate Layer 5 (Data) + +**Services: postgres (CloudNativePG), redis, kafka** + +**Action:** +```bash +# Create directories +mkdir -p data/{postgres,redis,kafka} + +# Export existing configurations +kubectl get cnpg -A -o yaml > data/postgres/config.yaml +kubectl get redis -A -o yaml > data/redis/config.yaml +kubectl get kafka -A -o yaml > data/kafka/config.yaml + +# Create kustomization.yaml for each + +# Repeat process... +``` + +**Deliverables:** +- [x] k8s/data/{postgres,redis,kafka}/kustomization.yaml +- [x] k8s/data/kustomization.yaml + +## Phase 3: Create ArgoCD Application Definitions (Week 4) + +### Step 3.1: Create layer Applications +```bash +mkdir -p k8s/argocd/apps/layers + +# Root application (Layer 0 only, triggers rest) +cat > k8s/argocd/apps/root-app.yaml << 'EOF' +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: homelab-root + namespace: argocd +spec: + project: homelab + source: + repoURL: https://forgejo.riotpiao.homelab.com/riotpiao.com/homelab.git + targetRevision: main + path: k8s/infrastructure + destination: + server: https://kubernetes.default.svc + syncPolicy: + automated: + prune: true + selfHeal: true +EOF + +# Layer 1 application +cat > k8s/argocd/apps/layer-1-bootstrap.yaml << 'EOF' +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: layer-1-bootstrap + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "1" +spec: + project: homelab + source: + repoURL: https://forgejo.riotpiao.homelab.com/riotpiao.com/homelab.git + targetRevision: main + path: k8s/bootstrap + destination: + server: https://kubernetes.default.svc + syncPolicy: + automated: + prune: true + selfHeal: true +EOF + +# Repeat for layers 2, 3, 4, 5 (sync-wave: 2, 3, 4, 5) +``` + +**Deliverables:** +- [x] k8s/argocd/apps/root-app.yaml +- [x] k8s/argocd/apps/layer-{1,2,3,4,5}-*.yaml + +### Step 3.2: Create kustomization.yaml for apps +```bash +cat > k8s/argocd/apps/kustomization.yaml << 'EOF' +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - root-app.yaml + - layer-1-bootstrap.yaml + - layer-2-platform.yaml + - layer-3-security.yaml + - layer-4-applications.yaml + - layer-5-data.yaml +EOF +``` + +## Phase 4: Deploy & Validate (Week 5) + +### Step 4.1: Pre-flight checks +```bash +# Validate all kustomization files +for dir in k8s/{infrastructure,bootstrap,platform,security,applications,data}; do + echo "Validating $dir..." + kustomize build $dir > /tmp/validate.yaml + kubeval /tmp/validate.yaml || exit 1 +done + +# Validate ArgoCD apps +kubeval k8s/argocd/apps/*.yaml + +# Test YAML lint +yamllint k8s/ +``` + +### Step 4.2: Deploy root application +```bash +# Apply root app (Layer 0 only) +kubectl apply -f k8s/argocd/apps/root-app.yaml + +# Watch sync +argocd app watch homelab-root + +# Verify infrastructure deployed +kubectl get ns # Should have all namespaces +kubectl get sc # Should have all storage classes +``` + +### Step 4.3: Deploy layer applications +```bash +# Apply layer applications (one by one) +kubectl apply -f k8s/argocd/apps/layer-1-bootstrap.yaml +sleep 5 +argocd app watch layer-1-bootstrap + +# Once Layer 1 synced: Layer 2 +kubectl apply -f k8s/argocd/apps/layer-2-platform.yaml +argocd app watch layer-2-platform + +# ... repeat for layers 3, 4, 5 +``` + +### Step 4.4: Monitor for issues +```bash +# Check ArgoCD apps +argocd app list + +# Watch events +kubectl get events -A -w + +# Monitor pod status +kubectl get pods -A + +# Check logs +kubectl logs -f -n argocd deployment/argocd-application-controller +``` + +### Step 4.5: Validate state drift protection +```bash +# Manually edit a resource +kubectl edit deployment cert-manager -n cert-manager +# Change replicas from 1 → 2 + +# Wait 3 minutes (ArgoCD reconciliation interval) +sleep 180 + +# Check: should be back to 1 replica +kubectl get deployment cert-manager -n cert-manager +# Expected: 1/1 Ready (reverted by ArgoCD) + +# Verify in ArgoCD +argocd app get layer-1-bootstrap +# Expected: Synced status +``` + +## Phase 5: Cleanup (Week 6) + +### Step 5.1: Delete old directories +```bash +# After all apps synced successfully: +rm -rf k8s/talos-ci-cd/ +rm -rf k8s/talos-iam/ +rm -rf k8s/logging/ +rm -rf k8s/monitoring/ +rm -rf k8s/storage/ +rm -rf k8s/ddb/ +rm -rf k8s/sqs/ +rm -rf k8s/temporal/ +# Keep only: infrastructure, bootstrap, platform, security, applications, data, argocd +``` + +### Step 5.2: Update CI/CD pipeline +```bash +# Update .forgejo/workflows/ +# - Remove: terraform validate/plan/apply +# - Add: kustomize build validation +# - Add: argocd app validation +``` + +### Step 5.3: Archive old configuration +```bash +# Keep for reference only +mkdir k8s/.archive/ +git mv k8s/old-structure-backup k8s/.archive/ +git commit -m "archive: old k8s structure (moved to pure GitOps)" +``` + +## Rollback Plan + +**If something breaks during migration:** + +```bash +# Option 1: Rollback entire layer +git checkout HEAD~1 -- k8s/bootstrap/ +git commit -m "revert: bootstrap layer (investigating)" +# ArgoCD will resync to previous version automatically + +# Option 2: Pause ArgoCD sync +argocd app set layer-1-bootstrap --sync-policy none +# Investigate, then re-enable: +argocd app set layer-1-bootstrap --sync-policy automated + +# Option 3: Full rollback to pre-migration +git reset --hard +argocd app set homelab-root --sync-policy none +# Manual investigation, then re-enable +``` + +## Timeline Summary + +``` +Week 1: Plan & validate (reviews, dependency mapping) +Week 2: Layers 0-1 (infrastructure, bootstrap) +Week 3: Layers 2-3 (platform, security) +Week 3: Layers 4-5 (applications, data) +Week 4: ArgoCD applications + layer definitions +Week 5: Deploy & validate (watch for issues) +Week 6: Cleanup & CI/CD updates +``` + +**Total: 6 weeks, non-disruptive (all layers coexist during migration)** + +## Success Criteria + +✓ All 20+ services deployed via ArgoCD +✓ No manual kubectl apply in production +✓ State drift detected & corrected automatically +✓ All changes in git (reviewed via PR) +✓ Rollback possible at any time (git history) +✓ CI/CD validates all commits +✓ Secrets encrypted with SOPS +✓ New services can be added (copy service directory) diff --git a/terraform/.terraform.lock.hcl b/terraform/.terraform.lock.hcl deleted file mode 100644 index 91c83b8..0000000 --- a/terraform/.terraform.lock.hcl +++ /dev/null @@ -1,128 +0,0 @@ -# This file is maintained automatically by "terraform init". -# Manual edits may be lost in future updates. - -provider "registry.terraform.io/goauthentik/authentik" { - version = "2024.12.1" - constraints = "~> 2024.6" - hashes = [ - "h1:jpWLnotmskcXHfA5sFrWpANOJbip3wlJpj5ui6KGWzg=", - "zh:090260dc7889ea822ec1d899344e1ee23eba5290461989c0796149c9511f2316", - "zh:13c2655ff824b0dc4b9bb832b5ca6d41dba97cb280330258c5fef4115e236209", - "zh:166a73c3a810c9c895d68a8ff968158f339f8a2c1c03e20ec9fc5ed99cc64e20", - "zh:203777eae1cdc711233315499643180604cff2324411b186b7cf07fdbe16f655", - "zh:3b2f18c9a8d28dac74dc6bbf168c946855ab9c68f053578d4630c50d5eaf30a0", - "zh:4822275985f6b74b6196c47112316a4252db22cf4ceaef7c9ab4c66d488abf2f", - "zh:53ea97562666c8a5a2f6d63d418a302a7f8ee4b7bb7da35dedaa89aa5708b7f0", - "zh:56b8a230901e3550c92a1d3f58ee9dafe9853f30fe4315af3ab28ae63262e15d", - "zh:6293ab7b1fd8206a0c853591f50186aca4a1eff117b2a773e10760a23a2c83e9", - "zh:9433970f79fb92d8aae3ee436db5630ab312c78b6dc9df9c1db3273a18f8aaa1", - "zh:95df406214f79b3b98222d7c7fe8fc319a3d90b7a9d53e1d5abbda5dfb8b9436", - "zh:a85880da0552a42c8f449390fbd7d8b03541d1a13e04bba9f1404fa658754260", - "zh:a95f6e9bd62c67e70eba1b1a14728856b9a6a28cd1e5e3be54a7718882c87e7f", - "zh:dd599b51c5beb34a4c6feece244fde07d2558d69929449ab1fd39a5ebe738781", - ] -} - -provider "registry.terraform.io/hashicorp/aws" { - version = "5.100.0" - constraints = "~> 5.0" - hashes = [ - "h1:Ijt7pOlB7Tr7maGQIqtsLFbl7pSMIj06TVdkoSBcYOw=", - "zh:054b8dd49f0549c9a7cc27d159e45327b7b65cf404da5e5a20da154b90b8a644", - "zh:0b97bf8d5e03d15d83cc40b0530a1f84b459354939ba6f135a0086c20ebbe6b2", - "zh:1589a2266af699cbd5d80737a0fe02e54ec9cf2ca54e7e00ac51c7359056f274", - "zh:6330766f1d85f01ae6ea90d1b214b8b74cc8c1badc4696b165b36ddd4cc15f7b", - "zh:7c8c2e30d8e55291b86fcb64bdf6c25489d538688545eb48fd74ad622e5d3862", - "zh:99b1003bd9bd32ee323544da897148f46a527f622dc3971af63ea3e251596342", - "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", - "zh:9f8b909d3ec50ade83c8062290378b1ec553edef6a447c56dadc01a99f4eaa93", - "zh:aaef921ff9aabaf8b1869a86d692ebd24fbd4e12c21205034bb679b9caf883a2", - "zh:ac882313207aba00dd5a76dbd572a0ddc818bb9cbf5c9d61b28fe30efaec951e", - "zh:bb64e8aff37becab373a1a0cc1080990785304141af42ed6aa3dd4913b000421", - "zh:dfe495f6621df5540d9c92ad40b8067376350b005c637ea6efac5dc15028add4", - "zh:f0ddf0eaf052766cfe09dea8200a946519f653c384ab4336e2a4a64fdd6310e9", - "zh:f1b7e684f4c7ae1eed272b6de7d2049bb87a0275cb04dbb7cda6636f600699c9", - "zh:ff461571e3f233699bf690db319dfe46aec75e58726636a0d97dd9ac6e32fb70", - ] -} - -provider "registry.terraform.io/hashicorp/helm" { - version = "2.17.0" - constraints = "~> 2.14" - hashes = [ - "h1:kQMkcPVvHOguOqnxoEU2sm1ND9vCHiT8TvZ2x6v/Rsw=", - "zh:06fb4e9932f0afc1904d2279e6e99353c2ddac0d765305ce90519af410706bd4", - "zh:104eccfc781fc868da3c7fec4385ad14ed183eb985c96331a1a937ac79c2d1a7", - "zh:129345c82359837bb3f0070ce4891ec232697052f7d5ccf61d43d818912cf5f3", - "zh:3956187ec239f4045975b35e8c30741f701aa494c386aaa04ebabffe7749f81c", - "zh:66a9686d92a6b3ec43de3ca3fde60ef3d89fb76259ed3313ca4eb9bb8c13b7dd", - "zh:88644260090aa621e7e8083585c468c8dd5e09a3c01a432fb05da5c4623af940", - "zh:a248f650d174a883b32c5b94f9e725f4057e623b00f171936dcdcc840fad0b3e", - "zh:aa498c1f1ab93be5c8fbf6d48af51dc6ef0f10b2ea88d67bcb9f02d1d80d3930", - "zh:bf01e0f2ec2468c53596e027d376532a2d30feb72b0b5b810334d043109ae32f", - "zh:c46fa84cc8388e5ca87eb575a534ebcf68819c5a5724142998b487cb11246654", - "zh:d0c0f15ffc115c0965cbfe5c81f18c2e114113e7a1e6829f6bfd879ce5744fbb", - "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", - ] -} - -provider "registry.terraform.io/hashicorp/kubernetes" { - version = "2.38.0" - constraints = "~> 2.27" - hashes = [ - "h1:soK8Lt0SZ6dB+HsypFRDzuX/npqlMU6M0fvyaR1yW0k=", - "zh:0af928d776eb269b192dc0ea0f8a3f0f5ec117224cd644bdacdc682300f84ba0", - "zh:1be998e67206f7cfc4ffe77c01a09ac91ce725de0abaec9030b22c0a832af44f", - "zh:326803fe5946023687d603f6f1bab24de7af3d426b01d20e51d4e6fbe4e7ec1b", - "zh:4a99ec8d91193af961de1abb1f824be73df07489301d62e6141a656b3ebfff12", - "zh:5136e51765d6a0b9e4dbcc3b38821e9736bd2136cf15e9aac11668f22db117d2", - "zh:63fab47349852d7802fb032e4f2b6a101ee1ce34b62557a9ad0f0f0f5b6ecfdc", - "zh:924fb0257e2d03e03e2bfe9c7b99aa73c195b1f19412ca09960001bee3c50d15", - "zh:b63a0be5e233f8f6727c56bed3b61eb9456ca7a8bb29539fba0837f1badf1396", - "zh:d39861aa21077f1bc899bc53e7233262e530ba8a3a2d737449b100daeb303e4d", - "zh:de0805e10ebe4c83ce3b728a67f6b0f9d18be32b25146aa89116634df5145ad4", - "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", - "zh:faf23e45f0090eef8ba28a8aac7ec5d4fdf11a36c40a8d286304567d71c1e7db", - ] -} - -provider "registry.terraform.io/hashicorp/null" { - version = "3.3.0" - constraints = "~> 3.2" - hashes = [ - "h1:a14TKo7Xvg4W8+H1VA6p+oLZTLxVQnYUD8LOaOs14A8=", - "zh:021748b5ea3b5f6956f2e75c42c5cdc113b391fb98ac71364a4965d23b37000f", - "zh:3b27956f8541d46704fda234e0d535c2ae2a4b33411848b1ee262a1ec03568b0", - "zh:3de4ed47d6d0f4d8edba4a5092c7c9799950eda63989d8d0d2586e6afcb0aa20", - "zh:57ed8935c7d56dbc91cf2673534582cacfaab7a2f105f51d9f797e99df0c0c47", - "zh:58e176ba1d142827089e30e0711e007309a9f2726e8881986da5026e9778fdf4", - "zh:5949c4a3d4a93f841f155cdb7e991c087e637145c1630572e21948224f8f4923", - "zh:76d60f366b743003c1b085afa769b45b2198ee919927e45807d7d44fb42c067d", - "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", - "zh:79cd1bab1261a07f84e917191d7ddc4340ac5f5524283767256f7ffd7f87caf0", - "zh:8ec9083038cf710b30e319eaa467c9df7fa52bbd9969b61053a35bc2cdd2e0a6", - "zh:a6e502cb579685ab7aeb886c2bb11ddd9cfed74b41008592d57cbc3351a9218b", - "zh:acb74d6b4f66ff6acfcda315df802a7432170ef3955c9b432cb4580767004006", - "zh:f0ce55d8d9ffdb33dab612b1246f9bab060a9d54fc32ce2b4a038646155660af", - ] -} - -provider "registry.terraform.io/hashicorp/vault" { - version = "4.8.0" - constraints = "~> 4.0" - hashes = [ - "h1:GPfhH6dr1LY0foPBDYv9bEGifx7eSwYqFcEAOWOUxLk=", - "zh:269ab13433f67684012ae7e15876532b0312f5d0d2002a9cf9febb1279ce5ea6", - "zh:4babc95bf0c40eb85005db1dc2ca403c46be4a71dd3e409db3711a56f7a5ca0e", - "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", - "zh:86e27c1c625ecc24446a11eeffc3ac319b36c2b4e51251db8579256a0dbcf136", - "zh:a32f31da94824009e26b077374440b52098aecb93c92ff55dc3d31dd37c4ea25", - "zh:be0a18c6c0425518bab4fbffd82078b82036a88503b5d76064de551c9f646cbf", - "zh:be5a77fdfd36863ebeec79cd12b1d13322ffad6821d157a0b279789fa06b5937", - "zh:be8317d142a3caad74c7d936039ae27076a1b2b8312ef5208e2871a5f525977c", - "zh:c94a84895a3d9954b80e983eed4603330a5cdbbd8eef5b3c99278c2d1402ef3c", - "zh:de1fb712784dd8415f011ca5346a34f87fab6046c730557615247e511dbc7d98", - "zh:e3eafae7da550f86cae395d6660b2a0e93ec8d2b0e0e5ef982ec762e961fc952", - "zh:ff35fb1ab6add288f0f368981e56f780b50405accd1937131cba1137999c8d83", - ] -} diff --git a/terraform/.terraform/providers/registry.terraform.io/hashicorp/helm/2.17.0/darwin_arm64/LICENSE.txt b/terraform/.terraform/providers/registry.terraform.io/hashicorp/helm/2.17.0/darwin_arm64/LICENSE.txt deleted file mode 100644 index b9ac071..0000000 --- a/terraform/.terraform/providers/registry.terraform.io/hashicorp/helm/2.17.0/darwin_arm64/LICENSE.txt +++ /dev/null @@ -1,375 +0,0 @@ -Copyright (c) 2017 HashiCorp, Inc. - -Mozilla Public License Version 2.0 -================================== - -1. Definitions --------------- - -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. - -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or - - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. - -1.6. "Executable Form" - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. - -1.8. "License" - means this document. - -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. - -1.10. "Modifications" - means any of the following: - - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or - - (b) any new file in Source Code Form that contains any Covered - Software. - -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. - -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. - -1.13. "Source Code Form" - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants and Conditions --------------------------------- - -2.1. Grants - -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: - -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. - -2.3. Limitations on Grant Scope - -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: - -(a) for any code that a Contributor has removed from Covered Software; - or - -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. - -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). - -2.5. Representation - -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. - -2.7. Conditions - -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. - -3. Responsibilities -------------------- - -3.1. Distribution of Source Form - -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. - -3.2. Distribution of Executable Form - -If You distribute Covered Software in Executable Form then: - -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and - -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). - -3.4. Notices - -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. - -4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. - -5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ - -8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. - -9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. - -10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. - -10.3. Modified Versions - -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses - -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice -------------------------------------------- - - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. diff --git a/terraform/.terraform/providers/registry.terraform.io/hashicorp/helm/2.17.0/darwin_arm64/terraform-provider-helm_v2.17.0_x5 b/terraform/.terraform/providers/registry.terraform.io/hashicorp/helm/2.17.0/darwin_arm64/terraform-provider-helm_v2.17.0_x5 deleted file mode 100755 index 406624f..0000000 Binary files a/terraform/.terraform/providers/registry.terraform.io/hashicorp/helm/2.17.0/darwin_arm64/terraform-provider-helm_v2.17.0_x5 and /dev/null differ diff --git a/terraform/.terraform/providers/registry.terraform.io/hashicorp/kubernetes/2.38.0/darwin_arm64/LICENSE.txt b/terraform/.terraform/providers/registry.terraform.io/hashicorp/kubernetes/2.38.0/darwin_arm64/LICENSE.txt deleted file mode 100644 index b9ac071..0000000 --- a/terraform/.terraform/providers/registry.terraform.io/hashicorp/kubernetes/2.38.0/darwin_arm64/LICENSE.txt +++ /dev/null @@ -1,375 +0,0 @@ -Copyright (c) 2017 HashiCorp, Inc. - -Mozilla Public License Version 2.0 -================================== - -1. Definitions --------------- - -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. - -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or - - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. - -1.6. "Executable Form" - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. - -1.8. "License" - means this document. - -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. - -1.10. "Modifications" - means any of the following: - - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or - - (b) any new file in Source Code Form that contains any Covered - Software. - -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. - -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. - -1.13. "Source Code Form" - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants and Conditions --------------------------------- - -2.1. Grants - -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: - -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. - -2.3. Limitations on Grant Scope - -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: - -(a) for any code that a Contributor has removed from Covered Software; - or - -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. - -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). - -2.5. Representation - -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. - -2.7. Conditions - -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. - -3. Responsibilities -------------------- - -3.1. Distribution of Source Form - -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. - -3.2. Distribution of Executable Form - -If You distribute Covered Software in Executable Form then: - -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and - -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). - -3.4. Notices - -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. - -4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. - -5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ - -8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. - -9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. - -10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. - -10.3. Modified Versions - -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses - -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice -------------------------------------------- - - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. diff --git a/terraform/.terraform/providers/registry.terraform.io/hashicorp/kubernetes/2.38.0/darwin_arm64/terraform-provider-kubernetes_v2.38.0_x5 b/terraform/.terraform/providers/registry.terraform.io/hashicorp/kubernetes/2.38.0/darwin_arm64/terraform-provider-kubernetes_v2.38.0_x5 deleted file mode 100755 index 1c37a60..0000000 Binary files a/terraform/.terraform/providers/registry.terraform.io/hashicorp/kubernetes/2.38.0/darwin_arm64/terraform-provider-kubernetes_v2.38.0_x5 and /dev/null differ diff --git a/terraform/.terraform/providers/registry.terraform.io/hashicorp/null/3.3.0/darwin_arm64/LICENSE.txt b/terraform/.terraform/providers/registry.terraform.io/hashicorp/null/3.3.0/darwin_arm64/LICENSE.txt deleted file mode 100644 index 766add2..0000000 --- a/terraform/.terraform/providers/registry.terraform.io/hashicorp/null/3.3.0/darwin_arm64/LICENSE.txt +++ /dev/null @@ -1,375 +0,0 @@ -Copyright IBM Corp. 2017, 2026 - -Mozilla Public License Version 2.0 -================================== - -1. Definitions --------------- - -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. - -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or - - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. - -1.6. "Executable Form" - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. - -1.8. "License" - means this document. - -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. - -1.10. "Modifications" - means any of the following: - - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or - - (b) any new file in Source Code Form that contains any Covered - Software. - -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. - -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. - -1.13. "Source Code Form" - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants and Conditions --------------------------------- - -2.1. Grants - -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: - -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. - -2.3. Limitations on Grant Scope - -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: - -(a) for any code that a Contributor has removed from Covered Software; - or - -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. - -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). - -2.5. Representation - -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. - -2.7. Conditions - -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. - -3. Responsibilities -------------------- - -3.1. Distribution of Source Form - -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. - -3.2. Distribution of Executable Form - -If You distribute Covered Software in Executable Form then: - -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and - -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). - -3.4. Notices - -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. - -4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. - -5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ - -8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. - -9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. - -10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. - -10.3. Modified Versions - -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses - -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice -------------------------------------------- - - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. diff --git a/terraform/.terraform/providers/registry.terraform.io/hashicorp/null/3.3.0/darwin_arm64/terraform-provider-null_v3.3.0_x5 b/terraform/.terraform/providers/registry.terraform.io/hashicorp/null/3.3.0/darwin_arm64/terraform-provider-null_v3.3.0_x5 deleted file mode 100755 index 6c55062..0000000 Binary files a/terraform/.terraform/providers/registry.terraform.io/hashicorp/null/3.3.0/darwin_arm64/terraform-provider-null_v3.3.0_x5 and /dev/null differ diff --git a/terraform/.terraform/providers/registry.terraform.io/hashicorp/vault/4.8.0/darwin_arm64/LICENSE.txt b/terraform/.terraform/providers/registry.terraform.io/hashicorp/vault/4.8.0/darwin_arm64/LICENSE.txt deleted file mode 100644 index b9ac071..0000000 --- a/terraform/.terraform/providers/registry.terraform.io/hashicorp/vault/4.8.0/darwin_arm64/LICENSE.txt +++ /dev/null @@ -1,375 +0,0 @@ -Copyright (c) 2017 HashiCorp, Inc. - -Mozilla Public License Version 2.0 -================================== - -1. Definitions --------------- - -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. - -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or - - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. - -1.6. "Executable Form" - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. - -1.8. "License" - means this document. - -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. - -1.10. "Modifications" - means any of the following: - - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or - - (b) any new file in Source Code Form that contains any Covered - Software. - -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. - -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. - -1.13. "Source Code Form" - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants and Conditions --------------------------------- - -2.1. Grants - -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: - -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. - -2.3. Limitations on Grant Scope - -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: - -(a) for any code that a Contributor has removed from Covered Software; - or - -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. - -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). - -2.5. Representation - -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. - -2.7. Conditions - -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. - -3. Responsibilities -------------------- - -3.1. Distribution of Source Form - -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. - -3.2. Distribution of Executable Form - -If You distribute Covered Software in Executable Form then: - -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and - -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). - -3.4. Notices - -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. - -4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. - -5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ - -8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. - -9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. - -10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. - -10.3. Modified Versions - -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses - -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice -------------------------------------------- - - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. diff --git a/terraform/.terraform/providers/registry.terraform.io/hashicorp/vault/4.8.0/darwin_arm64/terraform-provider-vault_v4.8.0_x5 b/terraform/.terraform/providers/registry.terraform.io/hashicorp/vault/4.8.0/darwin_arm64/terraform-provider-vault_v4.8.0_x5 deleted file mode 100755 index 68ceb22..0000000 Binary files a/terraform/.terraform/providers/registry.terraform.io/hashicorp/vault/4.8.0/darwin_arm64/terraform-provider-vault_v4.8.0_x5 and /dev/null differ diff --git a/terraform/LONGHORN_PVC_IMPORT.md b/terraform/LONGHORN_PVC_IMPORT.md deleted file mode 100644 index 045ad09..0000000 --- a/terraform/LONGHORN_PVC_IMPORT.md +++ /dev/null @@ -1,218 +0,0 @@ -# Longhorn StorageClass + PVC Terraform Import — Execution Guide - -## Overview - -Moving Longhorn StorageClasses and app PVCs from Helm/chart-owned to Terraform-managed state. **Import-only, no delete/recreate.** Zero data-loss tolerance. Production data: Postgres, Kafka, MinIO, Loki. - -**Terraform now owns:** namespaces, bootstrap Helm releases, StorageClasses. **ArgoCD now owns:** workload Helm releases (grafana, loki, minio, portainer, forgejo, kafka, prometheus, ddb, ollama, etc.). This matches the in-progress Terraform+ArgoCD migration. - -**Explicit exclusion:** `llm` namespace / `ollama` / `longhorn-llm` SC — managed under separate state (`~/workplace/agents/infra/terraform/`). - -## Prerequisite - -- Cluster access + kubectl configured: `kubectl cluster-info` succeeds -- Terraform credentials: state backend (MinIO) reachable -- ArgoCD CLI (for Phase 0 reconciliation only) -- Helm CLI (for helmfile operations, Phase 2) - -## Execution: 4 Phases - -### Phase 0 — Cluster Reconciliation (read-only, ~10 min) - -Resolve three ownership ambiguities before importing. - -```bash -cd terraform/scripts -bash phase-0-reconciliation.sh -``` - -**Output:** Review findings for: -1. **minio (storage)**: Is Helm release (`terraform/minio.tf`) or Operator `Tenant` CR authoritative? -2. **kmsvc-redis**: Is helmfile release or ArgoCD Application active? -3. **forgejo-runner**: Is Helm chart or raw manifest (`k8s/forge/runner.yaml`) applied? - -**Document results.** Proceed to Phase 1 regardless; Phase 0 just informs which conditional apps to import in Phase 2. - -### Phase 1 — StorageClass Import (~5 min) - -Import `longhorn` (cluster default) and `longhorn-kafka` (Kafka-specific) to Terraform state. - -```bash -cd terraform/scripts -bash phase-1-storageclass-import.sh -``` - -**Workflow:** -1. Captures live spec via `kubectl get sc` -2. **MANUAL:** Verify `terraform/longhorn.tf` resource blocks match captured specs -3. `terraform import` both SCs one at a time -4. `terraform plan` must show `0 to add, 0 to change, 0 to destroy` after each import -5. Annotates `longhorn-kafka` with `helm.sh/resource-policy=keep` (protects from Helm deletion on next upgrade) - -**Rollback:** `terraform state rm kubernetes_storage_class.longhorn` (state-only, safe) - -### Phase 2 Pilot — Grafana PVC (~15 min) - -Lowest-risk pilot: dashboards/config, re-creatable from values-based provisioning. Validates entire import workflow before rolling to other apps. - -```bash -cd terraform/scripts -bash phase-2-pilot-grafana.sh -``` - -**Workflow:** -1. Annotate live PVC: `helm.sh/resource-policy=keep` (protects from Helm deletion) -2. Capture live PVC spec (`kubectl get pvc -o yaml`) -3. **MANUAL:** Update `terraform/grafana.tf` with actual PV name -4. `terraform import` to state -5. `terraform plan` must show zero diff -6. **MANUAL:** Update `k8s/logging/grafana-values.yaml`: - ```yaml - persistence: - existingClaim: grafana - enabled: false - ``` - (Or keep identical if chart doesn't support `existingClaim`) -7. `helmfile diff` to confirm no delete/replace queued -8. `helmfile apply` to reconcile -9. Verify Longhorn replica health unchanged -10. `terraform plan` again, must still be zero diff - -**Phase gate:** Don't proceed to remaining apps until grafana cycle completes cleanly. - -**Rollback:** `terraform state rm kubernetes_persistent_volume_claim.grafana` (state-only, safe) - -### Phase 2 Remaining Apps (~45 min) - -Repeat pilot workflow for: **portainer** → **dev-tools** → **loki** → **minio-logging** → **forgejo**. - -```bash -cd terraform/scripts -bash phase-2-remaining-apps.sh -``` - -Script guides through each app in sequence. **Manual steps** for each: -- Verify Terraform resource block matches live PVC spec -- Update chart values to use `existingClaim` (if supported) or keep identical -- Confirm `helmfile diff` shows no destructive ops -- Confirm Longhorn replica health matches baseline - -**Ascending risk order:** -- portainer: low (UI config, re-creatable) -- dev-tools: low (sandbox state, expendable) -- loki: medium (log history, valuable but not critical) -- minio-logging: medium (Loki chunks, important but backed up elsewhere) -- forgejo: high (Git repos, CI history — real data loss risk) - -**Conditional apps — resolve Phase 0 ambiguities first:** -- minio (storage): if standalone chart is authoritative, not Tenant CR -- kmsvc-redis: if helmfile release is authoritative, architecture is standalone (not Sentinel) -- forgejo-runner: if Helm chart is authoritative, not raw manifest - -**Never import** (StatefulSet/operator-managed, dual-controller risk): -- ddb-cluster (CNPG operator owns PVC lifecycle) -- prometheus (Prometheus Operator `storageSpec.volumeClaimTemplate`) -- kafka-cluster (StatefulSet `volumeClaimTemplates`) -- authentik-postgresql (likely sub-chart StatefulSet VCT) -- llm namespace (separate Terraform state) - -## Rollback at Any Point - -**State-only backout (safe, touches nothing live):** -```bash -terraform state rm kubernetes_storage_class.longhorn -terraform state rm kubernetes_persistent_volume_claim.grafana -``` - -**Remove Helm protection annotation (only if abandoning import):** -```bash -kubectl annotate pvc grafana -n logging helm.sh/resource-policy- --overwrite -``` - -## Verification Gateways - -After every import + values change: - -1. **Terraform plan is clean:** - ```bash - terraform plan # must show "0 to add, 0 to change, 0 to destroy" - ``` - -2. **Longhorn replica health unchanged:** - ```bash - # Before starting each app: - k get longhorn-volume -n longhorn-system -o json | jq '.status.replicaStatus' - # After helmfile apply, must be identical - ``` - -3. **No destructive ops queued:** - ```bash - helmfile -f helmfile.yaml.gotmpl -l name= diff # no delete/replace on PVC - ``` - -## Defense-in-Depth Safety Layers - -1. **`helm.sh/resource-policy: keep` annotation** on every PVC/SC — blocks Helm from ever deleting even if removed from template -2. **`lifecycle { prevent_destroy = true }`** on every Terraform PVC resource — hard-errors any destroy/removal instead of deleting live data -3. **`terraform plan` gates** — nonzero diff = stop, fix or `state rm`, never force-apply against diff -4. **`helmfile diff` before apply** — confirm no destructive ops queued -5. **Longhorn replica-health baseline + re-check** — any drop in healthy replicas = hard stop -6. **Rollback is always `terraform state rm`** — state-only, never touches live objects - -## Troubleshooting - -### terraform plan shows diff after import - -**Common causes:** -- `volumeName` missing or wrong (required for bound PVC) -- `storage` unit normalization (5Gi vs 5368709120) -- Missing `resources.limits` -- `accessModes` array order - -**Fix:** Adjust `terraform/.tf` to match `kubectl get pvc -o yaml`, re-run `terraform plan`. - -### helmfile diff shows delete/replace on PVC - -**Cause:** Values change triggered Helm to re-template PVC; either values still match live and Helm shouldn't see diff, or the `existingClaim` change wasn't correct. - -**Fix:** Verify values match live spec exactly, or rollback the values change. If problem persists, ensure `helm.sh/resource-policy: keep` annotation is present: `kubectl get pvc -n -o jsonpath='{.metadata.annotations}'` - -### Longhorn replica count drops - -**Cause:** Import or helmfile apply somehow triggered a Longhorn reconciliation that affected replica status. - -**Fix:** Do not proceed. Investigate Longhorn health manually (`kubectl get longhorn-volume -n longhorn-system -o json`). Rollback import with `terraform state rm`, revert values changes, re-annotate with `helm.sh/resource-policy=keep`. Wait for replicas to recover, then retry. - -## Commit & PR - -Once all phases complete: - -```bash -cd /path/to/homelab -git add terraform/longhorn.tf terraform/grafana.tf terraform/portainer.tf terraform/loki.tf terraform/dev-tools.tf terraform/minio-logging.tf terraform/forgejo.tf -git add k8s/logging/grafana-values.yaml k8s/dashboard/portainer-values.yaml k8s/dev-tools/values.yaml k8s/logging/loki-values.yaml k8s/cicd/forgejo-values.yaml -git commit -m "feat(terraform): import Longhorn StorageClasses and app PVCs to Terraform state - -- Phase 1: longhorn, longhorn-kafka StorageClasses (cluster-wide defaults, app-specific) -- Phase 2: grafana, portainer, dev-tools, loki, minio-logging, forgejo PVCs -- Update chart values to use existingClaim or keep identical (no dual-ownership) -- All imports protected by helm.sh/resource-policy=keep + prevent_destroy lifecycle -- Longhorn replica health verified throughout, zero data loss -- See terraform/LONGHORN_PVC_IMPORT.md for execution record" - -git push origin -``` - -Create PR with description referencing this guide. - -## Reference - -- **Plan file:** `terraform/no-delete-only-import-buzzing-gray.md` (archived plan, for reference) -- **Scripts:** `terraform/scripts/phase-*.sh` -- **Terraform resources:** `terraform/longhorn.tf`, `terraform/grafana.tf`, `terraform/portainer.tf`, `terraform/loki.tf`, `terraform/dev-tools.tf`, `terraform/minio-logging.tf`, `terraform/forgejo.tf` -- **Longhorn health command:** (from CLAUDE.md) `k get longhorn-volume -n longhorn-system -o json | jq '.status.replicaStatus'` -- **Hard rule:** Never manually delete a PVC without verified replicas/backups (CLAUDE.md) - ---- - -**Last updated:** 2026-07-15 diff --git a/terraform/argocd-bootstrap.tf b/terraform/argocd-bootstrap.tf deleted file mode 100644 index ec09d10..0000000 --- a/terraform/argocd-bootstrap.tf +++ /dev/null @@ -1,241 +0,0 @@ -resource "kubernetes_namespace" "argocd" { - metadata { - name = "argocd" - labels = { - "pod-security.kubernetes.io/enforce" = "baseline" - "pod-security.kubernetes.io/enforce-version" = "latest" - } - } -} - -# Copy homelab-ca-secret from cert-manager to argocd namespace -# (Required for repo-server pod to verify self-signed forgejo TLS) -resource "null_resource" "copy_ca_secret_to_argocd" { - provisioner "local-exec" { - command = <<-EOT - kubectl get secret homelab-ca-secret -n cert-manager -o yaml | \ - sed 's/namespace: cert-manager/namespace: argocd/' | \ - kubectl apply -f - - EOT - } - - depends_on = [ - kubernetes_namespace.argocd - ] -} - -resource "helm_release" "argocd" { - name = "argocd" - repository = local.helm_repos["argo"] - chart = "argo-cd" - version = "7.3.3" - namespace = kubernetes_namespace.argocd.metadata[0].name - - values = [ - yamlencode({ - global = { - domain = "argocd.${var.cluster_domain}" - } - configs = { - params = { - "application.instanceLabelKey" = "argocd.argoproj.io/instance" - } - rbac = { - "policy.default" = "role:readonly" - } - cmp = { - create = true - plugins = { - sops = { - allowConcurrency = false - discover = { - fileName = "*.enc.yaml" - } - generate = { - command = ["sh", "-c"] - args = ["sops -d \"$ARGOCD_ENV_FILE_PATH\""] - } - lockRepo = false - } - } - } - } - server = { - extraArgs = [ - "--tls-cert-file=/etc/argocd/server.crt", - "--tls-key-file=/etc/argocd/server.key" - ] - ingress = { - enabled = true - hosts = [ - "argocd.${var.cluster_domain}" - ] - annotations = { - "nginx.ingress.kubernetes.io/backend-protocol" = "HTTPS" - } - ingressClassName = "nginx" - } - service = { - type = "ClusterIP" - port = 443 - } - volumeMounts = [ - { - name = "server-tls" - mountPath = "/etc/argocd" - readOnly = true - } - ] - } - repoServer = { - autoscaling = { - enabled = true - minReplicas = 2 - } - env = [ - { - name = "GIT_SSL_CAINFO" - value = "/etc/ssl/certs/homelab-ca.crt" - }, - { - name = "SOPS_AGE_KEY_FILE" - value = "/home/argocd/.sops/keys.txt" - } - ] - volumes = [ - { - name = "homelab-ca" - secret = { - secretName = "homelab-ca-secret" - } - }, - { - name = "sops-age" - secret = { - secretName = "sops-age" - defaultMode = 384 - } - } - ] - volumeMounts = [ - { - name = "homelab-ca" - mountPath = "/etc/ssl/certs/homelab-ca.crt" - subPath = "tls.crt" - }, - { - name = "sops-age" - mountPath = "/home/argocd/.sops" - readOnly = true - } - ] - } - volumes = [ - { - name = "server-tls" - secret = { - secretName = "homelab-tls" - defaultMode = 420 - } - } - ] - controller = { - replicas = 2 - } - }) - ] - - depends_on = [ - kubernetes_namespace.argocd, - null_resource.copy_ca_secret_to_argocd - ] - - # Note: lifecycle.ignore_changes removed to allow CA cert update - # This allows TF to inject the homelab-ca-secret for TLS verification -} - -resource "kubernetes_manifest" "argocd_project" { - manifest = { - apiVersion = "argoproj.io/v1alpha1" - kind = "AppProject" - metadata = { - name = "homelab" - namespace = kubernetes_namespace.argocd.metadata[0].name - } - spec = { - sourceRepos = [ - "https://forgejo.riotpiao.homelab.com/riotpiao.com/*", - "https://charts.goauthentik.io", - "https://prometheus-community.github.io/helm-charts", - "https://grafana.github.io/helm-charts", - "https://grafana.github.io/loki/charts", - "https://charts.min.io/", - "https://strimzi.io/charts/", - "https://open-telemetry.github.io/opentelemetry-helm-charts" - ] - destinations = [ - { - server = "https://kubernetes.default.svc" - namespace = "*" - } - ] - clusterResourceWhitelist = [ - { - group = "*" - kind = "*" - } - ] - } - } - - field_manager { - name = "terraform" - } - - depends_on = [ - helm_release.argocd - ] -} - -resource "kubernetes_manifest" "argocd_root_app" { - manifest = { - apiVersion = "argoproj.io/v1alpha1" - kind = "Application" - metadata = { - name = "homelab-root" - namespace = kubernetes_namespace.argocd.metadata[0].name - } - spec = { - project = kubernetes_manifest.argocd_project.manifest.metadata.name - source = { - repoURL = "https://forgejo.riotpiao.homelab.com/riotpiao.com/homelab.git" - targetRevision = "main" - path = "k8s/argocd/apps" - directory = { - recurse = true - } - } - destination = { - server = "https://kubernetes.default.svc" - namespace = kubernetes_namespace.argocd.metadata[0].name - } - syncPolicy = { - automated = { - prune = true - selfHeal = true - } - syncOptions = [ - "CreateNamespace=true" - ] - } - } - } - - field_manager { - name = "terraform" - } - - depends_on = [ - kubernetes_manifest.argocd_project - ] -} diff --git a/terraform/authentik-config.tf b/terraform/authentik-config.tf deleted file mode 100644 index d922b35..0000000 --- a/terraform/authentik-config.tf +++ /dev/null @@ -1,9 +0,0 @@ -# Authentik provider — resources imported from live cluster. -# Resource bodies generated via `terraform plan -generate-config-out` -# into authentik-generated.tf. Import mappings in authentik-imports.tf. -# Token: terraform.tfvars.local as authentik_api_token (sensitive). - -provider "authentik" { - url = "https://authentik.${var.cluster_domain}" - token = var.authentik_api_token -} diff --git a/terraform/authentik-generated.tf b/terraform/authentik-generated.tf deleted file mode 100644 index a13c9b8..0000000 --- a/terraform/authentik-generated.tf +++ /dev/null @@ -1,418 +0,0 @@ -# __generated__ by Terraform -# Please review these resources and move them into your main configuration files. - -# __generated__ by Terraform from "4" -resource "authentik_user" "akadmin" { - attributes = jsonencode({ - settings = { - locale = "" - } - }) - email = "root@example.com" - groups = ["9d72cbf2-9d52-4d3c-bba9-0068525d7a91", "5f2e1e79-7d7e-4ef0-9b99-3c6df19c0b88", "e640d887-eb85-431b-b5b2-5b6a8a7e0a44", "22a3c296-0d98-433f-8456-ebc2f1c8d489", "4084c8d6-0c12-46af-acf8-7372172b9016", "cbd8ce0d-c364-47a2-976c-c93211175b83"] - is_active = true - name = "authentik Default Admin" - password = null # sensitive - path = "users" - type = "internal" - username = "akadmin" -} - -# __generated__ by Terraform from "9d72cbf2-9d52-4d3c-bba9-0068525d7a91" -resource "authentik_group" "authentik_admins" { - attributes = jsonencode({}) - is_superuser = true - name = "authentik Admins" - parent = null - roles = null - users = [5, 4, 38] -} - -# __generated__ by Terraform from "5" -resource "authentik_user" "riotpiao" { - attributes = jsonencode({}) - email = "locartrock@gmail.com" - groups = ["9d72cbf2-9d52-4d3c-bba9-0068525d7a91", "5f2e1e79-7d7e-4ef0-9b99-3c6df19c0b88", "e640d887-eb85-431b-b5b2-5b6a8a7e0a44", "22a3c296-0d98-433f-8456-ebc2f1c8d489", "4084c8d6-0c12-46af-acf8-7372172b9016", "cbd8ce0d-c364-47a2-976c-c93211175b83"] - is_active = true - name = "rock" - password = null # sensitive - path = "users" - type = "internal" - username = "riotpiao" -} - -# __generated__ by Terraform from "e640d887-eb85-431b-b5b2-5b6a8a7e0a44" -resource "authentik_group" "minio_admins" { - attributes = jsonencode({}) - is_superuser = false - name = "minio-admins" - parent = null - roles = null - users = [5, 4] -} - -# __generated__ by Terraform from "38" -resource "authentik_user" "core_cli" { - attributes = jsonencode({}) - email = "core-cli@homelab.local" - groups = [] - is_active = true - name = "Core CLI (scoped)" - password = null # sensitive - path = "users" - type = "internal" - username = "core-cli" -} - -# __generated__ by Terraform from "5f2e1e79-7d7e-4ef0-9b99-3c6df19c0b88" -resource "authentik_group" "grafana_admins" { - attributes = jsonencode({}) - is_superuser = false - name = "grafana-admins" - parent = null - roles = null - users = [5, 4] -} - -# __generated__ by Terraform from "22a3c296-0d98-433f-8456-ebc2f1c8d489" -resource "authentik_group" "argocd_admins" { - attributes = jsonencode({}) - is_superuser = false - name = "argocd-admins" - parent = null - roles = null - users = [5, 4] -} - -# __generated__ by Terraform from "cbd8ce0d-c364-47a2-976c-c93211175b83" -resource "authentik_group" "homelab_admins" { - attributes = jsonencode({}) - is_superuser = false - name = "homelab-admins" - parent = null - roles = null - users = [5, 4] -} - -# __generated__ by Terraform from "forgejo" -resource "authentik_application" "forgejo_app" { - backchannel_providers = [] - group = null - meta_description = null - meta_icon = "/static/authentik/sources/gitlab.svg" - meta_launch_url = null - meta_publisher = null - name = "forgejo" - open_in_new_tab = false - policy_engine_mode = "any" - protocol_provider = 3 - slug = "forgejo" - uuid = "f70eb945-bf90-4f8c-875b-74db857b6c22" -} - -# __generated__ by Terraform from "argocd" -resource "authentik_application" "argocd_app" { - backchannel_providers = [] - group = null - meta_description = null - meta_icon = null - meta_launch_url = null - meta_publisher = null - name = "argocd" - open_in_new_tab = false - policy_engine_mode = "any" - protocol_provider = 4 - slug = "argocd" - uuid = "781fa91e-7fcd-4e54-a9e5-fe809774e9d1" -} - -# __generated__ by Terraform from "core-cli" -resource "authentik_application" "core_cli_app" { - backchannel_providers = [] - group = null - meta_description = null - meta_icon = null - meta_launch_url = null - meta_publisher = null - name = "core-cli" - open_in_new_tab = false - policy_engine_mode = "any" - protocol_provider = authentik_provider_oauth2.core_cli_provider.id - slug = "core-cli" - uuid = "f15c69b4-414b-49da-9e65-eef0a0dbf1ee" -} - -# __generated__ by Terraform from "4" -resource "authentik_provider_oauth2" "argocd_provider" { - access_code_validity = "minutes=1" - access_token_validity = "minutes=5" - allowed_redirect_uris = [{ - matching_mode = "strict" - url = "https://argocd.riotpiao.homelab.com/auth/callback" - }] - authentication_flow = null - authorization_flow = "3bd78f72-7d78-40c5-baad-5a63203f75ac" - client_id = "argocd" - client_secret = null # sensitive - client_type = "confidential" - encryption_key = null - include_claims_in_id_token = true - invalidation_flow = "cedc5670-78d6-402b-aa24-26674aea799c" - issuer_mode = "per_provider" - jwks_sources = null - jwt_federation_providers = [] - jwt_federation_sources = [] - name = "argocd" - property_mappings = ["604befc4-8fa3-4d17-8192-044e7a8a88d3", "f38fa6f5-3f87-4470-9241-b98b0151a6c0", "5c9d75bd-3981-4e51-81d4-d1c7d26edf15"] - refresh_token_validity = "days=30" - signing_key = "0a93e63b-1427-44c8-aa12-4f9f213f5a50" - sub_mode = "hashed_user_id" -} - -# __generated__ by Terraform from "4084c8d6-0c12-46af-acf8-7372172b9016" -resource "authentik_group" "forgejo_admins" { - attributes = jsonencode({}) - is_superuser = false - name = "forgejo-admins" - parent = null - roles = null - users = [5, 4] -} - -# __generated__ by Terraform from "grafana" -resource "authentik_application" "grafana_app" { - backchannel_providers = [] - group = null - meta_description = null - meta_icon = null - meta_launch_url = null - meta_publisher = null - name = "grafana" - open_in_new_tab = false - policy_engine_mode = "any" - protocol_provider = 1 - slug = "grafana" - uuid = "0acc3c58-d218-4d1a-8f54-6e838851aadb" -} - -# __generated__ by Terraform from "3" -resource "authentik_provider_oauth2" "forgejo_provider" { - access_code_validity = "minutes=1" - access_token_validity = "minutes=5" - allowed_redirect_uris = [{ - matching_mode = "strict" - url = "https://forgejo.riotpiao.homelab.com/user/oauth2/authentik/callback" - }] - authentication_flow = null - authorization_flow = "3bd78f72-7d78-40c5-baad-5a63203f75ac" - client_id = "forgejo" - client_secret = null # sensitive - client_type = "confidential" - encryption_key = null - include_claims_in_id_token = true - invalidation_flow = "cedc5670-78d6-402b-aa24-26674aea799c" - issuer_mode = "per_provider" - jwks_sources = null - jwt_federation_providers = [] - jwt_federation_sources = [] - name = "forgejo" - property_mappings = ["604befc4-8fa3-4d17-8192-044e7a8a88d3", "f38fa6f5-3f87-4470-9241-b98b0151a6c0", "5c9d75bd-3981-4e51-81d4-d1c7d26edf15"] - refresh_token_validity = "days=30" - signing_key = "0a93e63b-1427-44c8-aa12-4f9f213f5a50" - sub_mode = "hashed_user_id" -} - -# __generated__ by Terraform from "minio" -resource "authentik_application" "minio_app" { - backchannel_providers = [] - group = null - meta_description = null - meta_icon = null - meta_launch_url = null - meta_publisher = null - name = "Minio" - open_in_new_tab = false - policy_engine_mode = "any" - protocol_provider = 2 - slug = "minio" - uuid = "6f4ec073-f493-4e6a-96d4-1634e4e9f80f" -} - -# __generated__ by Terraform from "40" -resource "authentik_provider_oauth2" "core_cli_provider" { - access_code_validity = "minutes=1" - access_token_validity = "hours=1" - allowed_redirect_uris = [{ - matching_mode = "strict" - url = "urn:ietf:wg:oauth:2.0:oob" - }, { - matching_mode = "strict" - url = "https://authentik.riotpiao.homelab.com/application/o/callback/" - }] - authentication_flow = null - authorization_flow = "41e57c24-e38d-4d23-b81f-a6f002ca5df9" - client_id = "core-cli" - client_secret = null # sensitive - client_type = "confidential" - encryption_key = null - include_claims_in_id_token = true - invalidation_flow = "0254061b-16b3-486e-9800-1fe1580186a6" - issuer_mode = "per_provider" - jwks_sources = null - jwt_federation_providers = [] - jwt_federation_sources = [] - name = "core-cli" - property_mappings = [] - refresh_token_validity = "days=30" - signing_key = null - sub_mode = "hashed_user_id" -} - -# __generated__ by Terraform from "38" -resource "authentik_provider_oauth2" "device_code_provider" { - access_code_validity = "minutes=1" - access_token_validity = "hours=1" - allowed_redirect_uris = [] - authentication_flow = "dc6cfe87-94ac-4178-a2b2-a6ad5d4677dc" - authorization_flow = "3bd78f72-7d78-40c5-baad-5a63203f75ac" - client_id = "device-code-c5e6da866bd4" - client_secret = null # sensitive - client_type = "confidential" - encryption_key = null - include_claims_in_id_token = true - invalidation_flow = "0254061b-16b3-486e-9800-1fe1580186a6" - issuer_mode = "per_provider" - jwks_sources = null - jwt_federation_providers = [] - jwt_federation_sources = [] - name = "Device Code Flow" - property_mappings = [] - refresh_token_validity = "days=30" - signing_key = "0a93e63b-1427-44c8-aa12-4f9f213f5a50" - sub_mode = "hashed_user_id" -} - -# __generated__ by Terraform from "0d1c1578-9358-4602-af76-8472f4b4e115" -resource "authentik_group" "authentik_read_only" { - attributes = jsonencode({ - notes = "An group with an auto-generated role that allows read-only permissions on all objects.\n" - }) - is_superuser = false - name = "authentik Read-only" - parent = null - roles = null - users = [] -} - -# __generated__ by Terraform from "2" -resource "authentik_provider_oauth2" "minio_provider" { - access_code_validity = "minutes=1" - access_token_validity = "minutes=5" - allowed_redirect_uris = [{ - matching_mode = "strict" - url = "https://minio.riotpiao.homelab.com/oauth_callback" - }] - authentication_flow = null - authorization_flow = "3bd78f72-7d78-40c5-baad-5a63203f75ac" - client_id = "minio" - client_secret = null # sensitive - client_type = "confidential" - encryption_key = null - include_claims_in_id_token = true - invalidation_flow = "cedc5670-78d6-402b-aa24-26674aea799c" - issuer_mode = "per_provider" - jwks_sources = null - jwt_federation_providers = [] - jwt_federation_sources = [] - name = "minio" - property_mappings = ["604befc4-8fa3-4d17-8192-044e7a8a88d3", "f38fa6f5-3f87-4470-9241-b98b0151a6c0", "5c9d75bd-3981-4e51-81d4-d1c7d26edf15"] - refresh_token_validity = "days=30" - signing_key = "0a93e63b-1427-44c8-aa12-4f9f213f5a50" - sub_mode = "hashed_user_id" -} - -# __generated__ by Terraform from "5" -resource "authentik_provider_oauth2" "temporal_provider" { - access_code_validity = "minutes=1" - access_token_validity = "minutes=5" - allowed_redirect_uris = [{ - matching_mode = "strict" - url = "https://temporal.riotpiao.homelab.com/auth/callback" - }] - authentication_flow = null - authorization_flow = "3bd78f72-7d78-40c5-baad-5a63203f75ac" - client_id = "temporal" - client_secret = null # sensitive - client_type = "confidential" - encryption_key = null - include_claims_in_id_token = true - invalidation_flow = "cedc5670-78d6-402b-aa24-26674aea799c" - issuer_mode = "per_provider" - jwks_sources = null - jwt_federation_providers = [] - jwt_federation_sources = [] - name = "temporal" - property_mappings = ["604befc4-8fa3-4d17-8192-044e7a8a88d3", "f38fa6f5-3f87-4470-9241-b98b0151a6c0", "5c9d75bd-3981-4e51-81d4-d1c7d26edf15"] - refresh_token_validity = "days=30" - signing_key = "0a93e63b-1427-44c8-aa12-4f9f213f5a50" - sub_mode = "hashed_user_id" -} - -# __generated__ by Terraform from "1" -resource "authentik_provider_oauth2" "grafana_provider" { - access_code_validity = "minutes=1" - access_token_validity = "minutes=5" - allowed_redirect_uris = [{ - matching_mode = "strict" - url = "https://grafana.riotpiao.homelab.com/login/generic_oauth" - }] - authentication_flow = null - authorization_flow = "3bd78f72-7d78-40c5-baad-5a63203f75ac" - client_id = "grafana" - client_secret = null # sensitive - client_type = "confidential" - encryption_key = null - include_claims_in_id_token = true - invalidation_flow = "cedc5670-78d6-402b-aa24-26674aea799c" - issuer_mode = "per_provider" - jwks_sources = null - jwt_federation_providers = [] - jwt_federation_sources = [] - name = "grafana" - property_mappings = ["604befc4-8fa3-4d17-8192-044e7a8a88d3", "f38fa6f5-3f87-4470-9241-b98b0151a6c0", "5c9d75bd-3981-4e51-81d4-d1c7d26edf15"] - refresh_token_validity = "days=30" - signing_key = "0a93e63b-1427-44c8-aa12-4f9f213f5a50" - sub_mode = "hashed_user_id" -} - -# __generated__ by Terraform from "device-code" -resource "authentik_application" "device_code_app" { - backchannel_providers = [] - group = null - meta_description = null - meta_icon = null - meta_launch_url = null - meta_publisher = null - name = "device-code" - open_in_new_tab = false - policy_engine_mode = "any" - protocol_provider = 38 - slug = "device-code" - uuid = "7f6ff50a-3554-4b5b-8419-622db0091ea3" -} - -# __generated__ by Terraform from "temporal" -resource "authentik_application" "temporal_app" { - backchannel_providers = [] - group = null - meta_description = null - meta_icon = null - meta_launch_url = null - meta_publisher = null - name = "temporal" - open_in_new_tab = false - policy_engine_mode = "any" - protocol_provider = 5 - slug = "temporal" - uuid = "1d51178b-5619-4ba4-bd50-c102f2864cdd" -} diff --git a/terraform/bootstrap-certificates.tf.disabled b/terraform/bootstrap-certificates.tf.disabled deleted file mode 100644 index f6cbaa0..0000000 --- a/terraform/bootstrap-certificates.tf.disabled +++ /dev/null @@ -1,104 +0,0 @@ -resource "kubernetes_manifest" "selfsigned_bootstrap" { - manifest = { - apiVersion = "cert-manager.io/v1" - kind = "ClusterIssuer" - metadata = { - name = "selfsigned-bootstrap" - } - spec = { - selfSigned = {} - } - } - - field_manager { - name = "terraform" - } -} - -resource "kubernetes_manifest" "homelab_ca_cert" { - manifest = { - apiVersion = "cert-manager.io/v1" - kind = "Certificate" - metadata = { - name = "homelab-ca" - namespace = kubernetes_namespace.namespaces["cert-manager"].metadata[0].name - } - spec = { - secretName = "homelab-ca-secret" - commonName = "homelab-ca" - isCA = true - issuerRef = { - name = "selfsigned-bootstrap" - kind = "ClusterIssuer" - } - duration = "87600h" - renewBefore = "720h" - privateKey = { - algorithm = "ECDSA" - size = 256 - } - } - } - - field_manager { - name = "terraform" - } - - depends_on = [ - kubernetes_manifest.selfsigned_bootstrap - ] -} - -resource "kubernetes_manifest" "homelab_ca_issuer" { - manifest = { - apiVersion = "cert-manager.io/v1" - kind = "ClusterIssuer" - metadata = { - name = "homelab-ca" - } - spec = { - ca = { - secretName = "homelab-ca-secret" - } - } - } - - field_manager { - name = "terraform" - } - - depends_on = [ - kubernetes_manifest.homelab_ca_cert - ] -} - -resource "kubernetes_manifest" "wildcard_cert" { - manifest = { - apiVersion = "cert-manager.io/v1" - kind = "Certificate" - metadata = { - name = "homelab-tls" - namespace = kubernetes_namespace.namespaces["ingress-nginx"].metadata[0].name - } - spec = { - secretName = "homelab-tls" - commonName = "*.${var.cluster_domain}" - dnsNames = ["*.${var.cluster_domain}"] - issuerRef = { - name = "homelab-ca" - kind = "ClusterIssuer" - } - duration = "2160h" - renewBefore = "720h" - } - } - - field_manager { - name = "terraform" - } - - depends_on = [ - kubernetes_manifest.homelab_ca_issuer, - kubernetes_namespace.namespaces - ] -} diff --git a/terraform/bootstrap-manifests.yaml b/terraform/bootstrap-manifests.yaml deleted file mode 100644 index 767bcf1..0000000 --- a/terraform/bootstrap-manifests.yaml +++ /dev/null @@ -1,80 +0,0 @@ ---- -# ClusterIssuer: selfsigned-bootstrap (initial issuer for homelab-ca cert) -apiVersion: cert-manager.io/v1 -kind: ClusterIssuer -metadata: - name: selfsigned-bootstrap -spec: - selfSigned: {} - ---- -# ClusterIssuer: homelab-ca (uses generated homelab-ca cert) -apiVersion: cert-manager.io/v1 -kind: ClusterIssuer -metadata: - name: homelab-ca -spec: - ca: - secretName: homelab-ca-secret - ---- -# Self-signed CA certificate (10 year lifetime) -apiVersion: cert-manager.io/v1 -kind: Certificate -metadata: - name: homelab-ca - namespace: cert-manager -spec: - commonName: homelab-ca - duration: 87600h - isCA: true - issuerRef: - kind: ClusterIssuer - name: selfsigned-bootstrap - privateKey: - algorithm: ECDSA - size: 256 - renewBefore: 720h - secretName: homelab-ca-secret - ---- -# Wildcard TLS certificate for *.riotpiao.homelab.com -apiVersion: cert-manager.io/v1 -kind: Certificate -metadata: - name: homelab-tls - namespace: ingress-nginx -spec: - commonName: "*.riotpiao.homelab.com" - dnsNames: - - "*.riotpiao.homelab.com" - duration: 2160h - issuerRef: - kind: ClusterIssuer - name: homelab-ca - renewBefore: 720h - secretName: homelab-tls - ---- -# ArgoCD namespace -apiVersion: v1 -kind: Namespace -metadata: - name: argocd - labels: - pod-security.kubernetes.io/enforce: baseline - pod-security.kubernetes.io/enforce-version: latest - ---- -# dev-tools namespace -apiVersion: v1 -kind: Namespace -metadata: - name: dev-tools - labels: - pod-security.kubernetes.io/audit: restricted - pod-security.kubernetes.io/audit-version: latest - pod-security.kubernetes.io/enforce: baseline - pod-security.kubernetes.io/enforce-version: latest - pod-security.kubernetes.io/warn: restricted - pod-security.kubernetes.io/warn-version: latest diff --git a/terraform/bootstrap-namespaces.tf b/terraform/bootstrap-namespaces.tf deleted file mode 100644 index 1926b00..0000000 --- a/terraform/bootstrap-namespaces.tf +++ /dev/null @@ -1,37 +0,0 @@ -locals { - namespaces = { - "cert-manager" = { pod_security = "baseline" } - "reloader" = { pod_security = "baseline" } - "ingress-nginx" = { pod_security = "privileged" } - "ddb" = { pod_security = "baseline" } - "iam" = { pod_security = "baseline" } - "storage" = { pod_security = "baseline" } - "logging" = { pod_security = "baseline" } - "monitoring" = { pod_security = "baseline" } - "cicd" = { pod_security = "baseline" } - "dashboard" = { pod_security = "baseline" } - "sqs" = { pod_security = "baseline" } - "temporal" = { pod_security = "baseline" } - "story-crater-backend" = { pod_security = "baseline" } - "llm" = { pod_security = "baseline" } - "dev-tools" = { pod_security = "baseline" } - "longhorn-system" = { pod_security = "baseline" } - "cilium-secrets" = { pod_security = "baseline" } - } -} - -resource "kubernetes_namespace" "namespaces" { - for_each = local.namespaces - - metadata { - name = each.key - labels = { - "pod-security.kubernetes.io/enforce" = each.value.pod_security - "pod-security.kubernetes.io/enforce-version" = "latest" - "pod-security.kubernetes.io/audit" = "restricted" - "pod-security.kubernetes.io/audit-version" = "latest" - "pod-security.kubernetes.io/warn" = "restricted" - "pod-security.kubernetes.io/warn-version" = "latest" - } - } -} diff --git a/terraform/bootstrap-releases.tf b/terraform/bootstrap-releases.tf deleted file mode 100644 index c633d4c..0000000 --- a/terraform/bootstrap-releases.tf +++ /dev/null @@ -1,67 +0,0 @@ -locals { - bootstrap_releases = { - cert-manager = { - chart_version = "v1.21.0" - namespace = "cert-manager" - repo = "jetstack" - } - cilium = { - chart_version = "1.19.5" - namespace = "kube-system" - repo = "cilium" - } - reloader = { - chart_version = "1.3.0" - namespace = "reloader" - repo = "stakater" - } - ingress-nginx = { - chart_version = "4.15.1" - namespace = "ingress-nginx" - repo = "ingress_nginx" - } - } -} - -resource "helm_release" "bootstrap" { - for_each = local.bootstrap_releases - - name = each.key - repository = local.helm_repos[each.value.repo] - chart = each.key - version = each.value.chart_version - namespace = each.value.namespace - - dynamic "set" { - for_each = each.key == "cert-manager" ? { - "crds.enabled" = "true" - "prometheus.enabled" = "true" - "prometheus.servicemonitor.enabled" = "true" - "prometheus.servicemonitor.interval" = "60s" - } : (each.key == "ingress-nginx" ? { - "controller.admissionWebhooks.enabled" = "false" - "controller.dnsPolicy" = "ClusterFirstWithHostNet" - "controller.extraArgs.default-ssl-certificate" = "ingress-nginx/homelab-tls" - "controller.hostPort.enabled" = "true" - "controller.ingressClassResource.default" = "true" - "controller.kind" = "DaemonSet" - "controller.metrics.enabled" = "true" - "controller.metrics.serviceMonitor.enabled" = "true" - "controller.metrics.serviceMonitor.interval" = "30s" - } : {}) - content { - name = set.key - value = set.value - } - } - - depends_on = [ - kubernetes_namespace.namespaces - ] - - lifecycle { - ignore_changes = [ - values - ] - } -} diff --git a/terraform/forgejo-runner.tf b/terraform/forgejo-runner.tf deleted file mode 100644 index e80c320..0000000 --- a/terraform/forgejo-runner.tf +++ /dev/null @@ -1,122 +0,0 @@ -# Forgejo Actions runner network and RBAC configuration -# Enables CI/CD workflows to access cluster services (MinIO, K8s API, etc.) - -# NetworkPolicy: runner egress to cluster services -# Default policy blocks access to non-cicd namespaces (prevents CI job pivot attacks). -# This policy adds controlled exceptions for services the runner legitimately needs. -resource "kubernetes_network_policy" "forgejo_runner_egress" { - metadata { - name = "forgejo-runner-egress-extended" - namespace = "cicd" - } - - spec { - pod_selector { - match_labels = { - app = "forgejo-runner" - } - } - - policy_types = ["Egress"] - - # Same namespace: Forgejo (git clone, repo access) - egress { - to { - pod_selector {} - } - } - - # CoreDNS: DNS resolution for all service lookups - egress { - to { - namespace_selector { - match_labels = { - "kubernetes.io/metadata.name" = "kube-system" - } - } - } - ports { - protocol = "UDP" - port = "53" - } - ports { - protocol = "TCP" - port = "53" - } - } - - # Storage namespace: MinIO (S3 backend for terraform state) - # Terraform workflows need to push state to S3; restrict to MinIO pod/port only - egress { - to { - namespace_selector { - match_labels = { - "kubernetes.io/metadata.name" = "storage" - } - } - } - ports { - protocol = "TCP" - port = "9000" # MinIO S3 API - } - } - - # Public internet: external package repos, container registries, terraform releases - # Explicitly exclude LAN (192.168.1.0/24) and pod network (10.244.0.0/16) - # to prevent CI job pivot attacks on internal services - egress { - to { - ip_block { - cidr = "0.0.0.0/0" - except = [ - "192.168.1.0/24", # LAN (baremetal nodes, physical infra) - "10.244.0.0/16" # Pod network (cluster internal) - ] - } - } - } - } -} - -# ServiceAccount for Terraform CI jobs (future use for K8s auth) -# Currently used for in-cluster kubeconfig generation in workflows -resource "kubernetes_service_account" "terraform_ci" { - metadata { - name = "terraform-ci" - namespace = "cicd" - } -} - -# ClusterRole for Terraform CI jobs -# Scoped to resources the CI workflow needs to manage (applies via IaC) -resource "kubernetes_cluster_role" "terraform_ci" { - metadata { - name = "terraform-ci" - } - - rule { - api_groups = ["*"] - resources = ["*"] - verbs = ["*"] - } -} - -# ClusterRoleBinding: attach role to service account -# Enables terraform workflows to use in-cluster auth (K8s API, kubeconfig generation) -resource "kubernetes_cluster_role_binding" "terraform_ci" { - metadata { - name = "terraform-ci" - } - - role_ref { - api_group = "rbac.authorization.k8s.io" - kind = "ClusterRole" - name = kubernetes_cluster_role.terraform_ci.metadata[0].name - } - - subject { - kind = "ServiceAccount" - name = kubernetes_service_account.terraform_ci.metadata[0].name - namespace = "cicd" - } -} diff --git a/terraform/forgejo.tf b/terraform/forgejo.tf deleted file mode 100644 index fad0c86..0000000 --- a/terraform/forgejo.tf +++ /dev/null @@ -1,25 +0,0 @@ -# Forgejo (server) — Git repository and CI/CD configuration persistent storage -# Imported from live cluster state (import-only, no delete) -# Live name: gitea-shared-storage (Gitea is old name, Forgejo is new) - -resource "kubernetes_persistent_volume_claim" "forgejo_shared_storage" { - metadata { - name = "gitea-shared-storage" - namespace = "cicd" - } - spec { - access_modes = ["ReadWriteOnce"] - storage_class_name = "longhorn" - resources { - requests = { - storage = "20Gi" - } - } - volume_name = "pvc-889e20b9-2203-46e6-8c08-d015cd15193d" - } - - - lifecycle { - prevent_destroy = true - } -} diff --git a/terraform/grafana.tf b/terraform/grafana.tf deleted file mode 100644 index e5b9f29..0000000 --- a/terraform/grafana.tf +++ /dev/null @@ -1,24 +0,0 @@ -# Grafana — persistent storage for dashboards and datasources -# Imported from live cluster state (import-only, no delete) - -resource "kubernetes_persistent_volume_claim" "grafana" { - metadata { - name = "grafana" - namespace = "logging" - } - spec { - access_modes = ["ReadWriteOnce"] - storage_class_name = "longhorn" - resources { - requests = { - storage = "5Gi" - } - } - volume_name = "pvc-95f2216e-985d-4496-8b39-48e8c2a7f410" - } - - - lifecycle { - prevent_destroy = true - } -} diff --git a/terraform/helm-repositories.tf b/terraform/helm-repositories.tf deleted file mode 100644 index 937eece..0000000 --- a/terraform/helm-repositories.tf +++ /dev/null @@ -1,21 +0,0 @@ -# Helm chart repositories (referenced inline in helm_release resources) -locals { - helm_repos = { - jetstack = "https://charts.jetstack.io" - stakater = "https://stakater.github.io/stakater-charts" - ingress_nginx = "https://kubernetes.github.io/ingress-nginx" - cilium = "https://helm.cilium.io" - cnpg = "https://cloudnative-pg.github.io/charts" - authentik = "https://charts.goauthentik.io" - hashicorp = "https://helm.releases.hashicorp.com" - minio = "https://charts.min.io" - grafana = "https://grafana.github.io/helm-charts" - prometheus_community = "https://prometheus-community.github.io/helm-charts" - portainer = "https://portainer.github.io/k8s/" - argo = "https://argoproj.github.io/argo-helm" - gitea_charts = "https://dl.gitea.com/charts/" - strimzi = "https://strimzi.io/charts/" - bitnami = "https://charts.bitnami.com/bitnami" - temporal = "https://go.temporal.io/helm-charts" - } -} diff --git a/terraform/loki.tf b/terraform/loki.tf deleted file mode 100644 index c04fe67..0000000 --- a/terraform/loki.tf +++ /dev/null @@ -1,24 +0,0 @@ -# Loki — log aggregation backend persistent storage (StatefulSet mode: storage-loki-0) -# Imported from live cluster state (import-only, no delete) - -resource "kubernetes_persistent_volume_claim" "loki" { - metadata { - name = "storage-loki-0" - namespace = "logging" - } - spec { - access_modes = ["ReadWriteOnce"] - storage_class_name = "longhorn" - resources { - requests = { - storage = "5Gi" - } - } - volume_name = "pvc-897d4f5a-1699-4e06-b92f-ccbe3911be0f" - } - - - lifecycle { - prevent_destroy = true - } -} diff --git a/terraform/longhorn.tf b/terraform/longhorn.tf deleted file mode 100644 index 28cf98f..0000000 --- a/terraform/longhorn.tf +++ /dev/null @@ -1,40 +0,0 @@ -# Longhorn StorageClasses — cluster-wide default + app-specific variants -# Imported from live cluster state (import-only, no delete) - -resource "kubernetes_storage_class" "longhorn" { - metadata { - name = "longhorn" - } - storage_provisioner = "driver.longhorn.io" - reclaim_policy = "Delete" - allow_volume_expansion = true - volume_binding_mode = "Immediate" - - parameters = { - numberOfReplicas = "3" - staleReplicaTimeout = "60" - fromBackup = "" - fsType = "ext4" - dataLocality = "disabled" - disableRevisionCounter = "true" - unmapMarkSnapChainRemoved = "ignored" - } -} - -resource "kubernetes_storage_class" "longhorn_kafka" { - metadata { - name = "longhorn-kafka" - } - storage_provisioner = "driver.longhorn.io" - reclaim_policy = "Delete" - allow_volume_expansion = true - volume_binding_mode = "Immediate" - - parameters = { - numberOfReplicas = "3" - staleReplicaTimeout = "30" - fromBackup = "" - fsType = "ext4" - dataLocality = "disabled" - } -} diff --git a/terraform/main.tf b/terraform/main.tf deleted file mode 100644 index 8f2475e..0000000 --- a/terraform/main.tf +++ /dev/null @@ -1,7 +0,0 @@ -locals { - cluster_domain = var.cluster_domain -} - -# Helm repositories will be created in helm-repositories.tf -# Namespaces will be created in bootstrap/namespaces.tf -# Helm releases will be created in helm-releases/*.tf diff --git a/terraform/minio.tf b/terraform/minio.tf deleted file mode 100644 index 1302fc1..0000000 --- a/terraform/minio.tf +++ /dev/null @@ -1,33 +0,0 @@ -# MinIO - Official minio/minio chart, direct Helm deployment (no operator) -# All-in-one: single helm_release + dedicated xfs StorageClass. -# Why xfs: default `longhorn` SC uses ext4 whose mkfs on 100Gi (~4.5min) -# exceeds kubelet mount timeout. xfs mkfs is near-instant. min.io chart has -# no persistence.fsType, so fsType must be set on the StorageClass. - -resource "kubernetes_storage_class" "longhorn_xfs" { - metadata { - name = "longhorn-xfs" - } - storage_provisioner = "driver.longhorn.io" - reclaim_policy = "Delete" - allow_volume_expansion = true - volume_binding_mode = "Immediate" - - parameters = { - numberOfReplicas = "2" - staleReplicaTimeout = "60" - fsType = "xfs" - dataLocality = "disabled" - } -} - -# MinIO Helm release removed — managed by ArgoCD instead -# Reason: MinIO is Terraform state backend (chicken-and-egg problem) -# Solution: ArgoCD Application (k8s/argocd/apps/phase0-minio.yaml) handles deployment -# Terraform manages everything else, state lives in MinIO (safe external backend) - -variable "create_storage_namespace" { - description = "Create storage namespace if it doesn't exist" - type = bool - default = false -} diff --git a/terraform/portainer.tf b/terraform/portainer.tf deleted file mode 100644 index a1ad6dc..0000000 --- a/terraform/portainer.tf +++ /dev/null @@ -1,24 +0,0 @@ -# Portainer — Docker container management UI persistent storage -# Imported from live cluster state (import-only, no delete) - -resource "kubernetes_persistent_volume_claim" "portainer" { - metadata { - name = "portainer" - namespace = "dashboard" - } - spec { - access_modes = ["ReadWriteOnce"] - storage_class_name = "longhorn" - resources { - requests = { - storage = "10Gi" - } - } - volume_name = "pvc-bcd0d8cb-1214-4d01-a960-f104926f2b00" - } - - - lifecycle { - prevent_destroy = true - } -} diff --git a/terraform/providers.tf b/terraform/providers.tf deleted file mode 100644 index 8dbb041..0000000 --- a/terraform/providers.tf +++ /dev/null @@ -1,50 +0,0 @@ -terraform { - required_version = ">= 1.5" - required_providers { - kubernetes = { - source = "hashicorp/kubernetes" - version = "~> 2.27" - } - helm = { - source = "hashicorp/helm" - version = "~> 2.14" - } - vault = { - source = "hashicorp/vault" - version = "~> 4.0" - } - null = { - source = "hashicorp/null" - version = "~> 3.2" - } - authentik = { - source = "goauthentik/authentik" - version = "2024.12.1" - } - aws = { - source = "hashicorp/aws" - version = "~> 5.0" - } - } -} - -provider "kubernetes" { - host = "https://kubernetes.default" - token = try(file("/var/run/secrets/kubernetes.io/serviceaccount/token"), "") - cluster_ca_certificate = try(file("/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"), "") - insecure = false -} - -provider "helm" { - kubernetes { - host = "https://kubernetes.default" - token = try(file("/var/run/secrets/kubernetes.io/serviceaccount/token"), "") - cluster_ca_certificate = try(file("/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"), "") - insecure = false - } -} - -provider "vault" { - address = "https://vault.riotpiao.homelab.com" - skip_tls_verify = true -} diff --git a/terraform/scripts/apply-and-import-bootstrap.sh b/terraform/scripts/apply-and-import-bootstrap.sh deleted file mode 100755 index 2ee79c7..0000000 --- a/terraform/scripts/apply-and-import-bootstrap.sh +++ /dev/null @@ -1,81 +0,0 @@ -#!/bin/bash -set -e - -echo "=== Step 1: Apply bootstrap manifests (namespaces, cert-manager issuers/certs) ===" -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -source "$SCRIPT_DIR/../../.env.terraform.sh" -kubectl apply -f "$SCRIPT_DIR/../bootstrap-manifests.yaml" --validate=false -echo "✓ Bootstrap manifests applied" - -echo "" -echo "=== Step 2: Wait for cert-manager to be ready ===" -kubectl -n cert-manager rollout status deployment/cert-manager --timeout=5m -echo "✓ cert-manager ready" - -echo "" -echo "=== Step 3: Wait for homelab-ca certificate to be issued ===" -for i in {1..60}; do - if kubectl -n cert-manager get secret homelab-ca-secret &>/dev/null; then - echo "✓ homelab-ca-secret created" - break - fi - echo "Waiting for homelab-ca-secret... ($i/60)" - sleep 2 -done - -echo "" -echo "=== Step 4a: Delete old ArgoCD release from cicd namespace ===" -if helm list -n cicd | grep -q "^argocd"; then - helm delete argocd -n cicd - echo "✓ Old ArgoCD removed from cicd" - sleep 5 -else - echo "✓ No ArgoCD in cicd to delete" -fi - -echo "" -echo "=== Step 4a2: Delete orphaned CRDs left behind by helm resource policy ===" -kubectl delete crd applications.argoproj.io applicationsets.argoproj.io appprojects.argoproj.io --ignore-not-found -echo "✓ CRDs deleted" -sleep 2 - -echo "" -echo "=== Step 4b: Install ArgoCD helm release in argocd namespace ===" -helm repo add argocd https://argoproj.github.io/argo-helm -helm repo update -ARGOCD_VALUES="$SCRIPT_DIR/../../k8s/talos-ci-cd/argocd-values.yaml" -helm upgrade --install argocd argocd/argo-cd \ - --namespace argocd \ - --version 7.3.3 \ - --values "$ARGOCD_VALUES" \ - --wait -echo "✓ ArgoCD installed in argocd namespace" - -echo "" -echo "=== Step 5: Import kubernetes resources into TF state ===" -cd "$SCRIPT_DIR/../.." -source .env.terraform.sh -cd terraform - -# Import namespaces -terraform import kubernetes_namespace.argocd argocd -terraform import 'kubernetes_namespace.namespaces["dev-tools"]' dev-tools - -# Import cert-manager objects (kubernetes_manifest import syntax uses colons: apiVersion:kind:name or apiVersion:kind:namespace:name) -terraform import kubernetes_manifest.selfsigned_bootstrap 'cert-manager.io:v1:ClusterIssuer:selfsigned-bootstrap' -terraform import kubernetes_manifest.homelab_ca_issuer 'cert-manager.io:v1:ClusterIssuer:homelab-ca' -terraform import kubernetes_manifest.homelab_ca_cert 'cert-manager.io:v1:Certificate:cert-manager:homelab-ca' -terraform import kubernetes_manifest.wildcard_cert 'cert-manager.io:v1:Certificate:ingress-nginx:homelab-tls' - -echo "✓ Kubernetes resources imported" - -echo "" -echo "=== Step 6: Import ArgoCD helm release ===" -terraform import helm_release.argocd argocd/argocd -echo "✓ ArgoCD helm release imported" - -echo "" -echo "=== Step 7: Verify clean plan ===" -terraform plan -echo "" -echo "✓ All bootstrap resources imported. Plan should show zero changes." diff --git a/terraform/scripts/import-existing.sh b/terraform/scripts/import-existing.sh deleted file mode 100755 index 60b9074..0000000 --- a/terraform/scripts/import-existing.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/bash -set -e - -cd "$(dirname "$0")/.." - -echo "=== Importing Namespaces ===" -for ns in cert-manager reloader ingress-nginx ddb iam storage logging monitoring cicd dashboard sqs temporal story-crater-backend llm dev-tools cilium-secrets kube-node-lease kube-public; do - if kubectl get ns "$ns" &>/dev/null; then - echo "Importing namespace: $ns" - terraform import "kubernetes_namespace.namespaces[\"$ns\"]" "$ns" || echo " (already imported or skipped)" - fi -done - -echo -e "\n=== Importing Storage Classes ===" -for sc in longhorn longhorn-kafka longhorn-llm longhorn-static; do - if kubectl get sc "$sc" &>/dev/null; then - echo "Importing storage class: $sc" - terraform import "kubernetes_storage_class.$sc" "$sc" || echo " (already imported or skipped)" - fi -done - -echo -e "\n=== Importing Bootstrap Helm Releases (TF-managed) ===" -declare -a bootstrap_releases=( - "cert-manager/cert-manager" - "reloader/reloader" - "ingress-nginx/ingress-nginx" -) - -for rel_ns in "${bootstrap_releases[@]}"; do - rel=$(echo "$rel_ns" | cut -d/ -f1) - ns=$(echo "$rel_ns" | cut -d/ -f2) - if helm list -n "$ns" --output json 2>/dev/null | grep -q "\"name\":\"$rel\""; then - echo "Importing helm release: $rel_ns" - terraform import "helm_release.bootstrap[\"$rel\"]" "$rel_ns" || echo " (already imported or skipped)" - fi -done - -echo -e "\n=== Skipping Workload Helm Releases ===" -echo "The following releases will be managed by ArgoCD (not imported to TF):" -declare -a workload_releases=( - "argocd/cicd" - "authentik/iam" - "cilium/kube-system" - "cloudnative-pg/ddb" - "duckdns/kube-system" - "forgejo/cicd" - "forgejo-runner/cicd" - "grafana/logging" - "kafka-cluster/sqs" - "kmsvc-redis/sqs" - "loki/logging" - "management-service/sqs" - "minio/storage" - "ollama/llm" - "portainer/dashboard" - "prometheus/monitoring" - "promtail/logging" - "queue-crd/sqs" - "strimzi-operator/sqs" - "temporal/temporal" - "vault/iam" -) -for rel in "${workload_releases[@]}"; do - echo " - $rel" -done - -echo -e "\n=== Import Complete ===" -echo "Next: review terraform plan and apply" -terraform plan diff --git a/terraform/scripts/init-terraform.sh b/terraform/scripts/init-terraform.sh deleted file mode 100755 index ebbd95e..0000000 --- a/terraform/scripts/init-terraform.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/bin/bash -set -e - -cd "$(dirname "$0")/.." - -echo "=== Terraform Bootstrap Setup ===" - -if [ ! -f "../.env" ]; then - echo "ERROR: ../.env not found. Run from terraform/ directory." - exit 1 -fi - -# Extract MinIO credentials from .env -export AWS_ACCESS_KEY_ID=$(grep "^MINIO_ROOT_USER=" ../.env | cut -d= -f2) -export AWS_SECRET_ACCESS_KEY=$(grep "^MINIO_ROOT_PASSWORD=" ../.env | cut -d= -f2) -export KUBECONFIG=$(pwd)/../cluster-config/kubeconfig - -if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then - echo "ERROR: MINIO_ROOT_USER or MINIO_ROOT_PASSWORD not found in .env" - exit 1 -fi - -echo "✓ MinIO S3 credentials loaded" - -# Check Vault token -if [ -z "$VAULT_TOKEN" ]; then - echo "WARNING: VAULT_TOKEN not set. Set it before terraform init:" - echo " export VAULT_TOKEN=\$(vault login -method=oidc ...)" -fi - -# Generate terraform.tfvars from .env -echo "Generating terraform.tfvars from .env..." -cat > terraform.tfvars.local << 'EOF' -# Auto-generated from .env -EOF - -grep -E '^(AUTHENTIK_SECRET_KEY|AUTHENTIK_BOOTSTRAP_PASSWORD|AUTHENTIK_BOOTSTRAP_TOKEN|AUTHENTIK_PG_PASSWORD|POSTGRES_PASSWORD|MINIO_ROOT_|GRAFANA_|FORGEJO_|ARGOCD_)' ../.env | sed 's/_ROOT_USER=/=/' | while read line; do - key=$(echo "$line" | cut -d= -f1 | sed 's/_/ /g; s/.*/\L&/; s/ /_/g') - val=$(echo "$line" | cut -d= -f2-) - if [[ "$key" == *"secret"* ]] || [[ "$key" == *"password"* ]]; then - echo "$key = \"$val\"" >> terraform.tfvars.local - else - echo "$key = \"$val\"" >> terraform.tfvars.local - fi -done - -echo "✓ terraform.tfvars.local generated" - -# Initialize terraform -echo "Initializing terraform with S3 backend..." -terraform init \ - -backend-config="access_key=$AWS_ACCESS_KEY_ID" \ - -backend-config="secret_key=$AWS_SECRET_ACCESS_KEY" - -echo "✓ Terraform initialized" -echo "" -echo "Next steps:" -echo " 1. Review: terraform plan" -echo " 2. Import existing resources: ./scripts/import-existing.sh" -echo " 3. Apply: terraform apply" diff --git a/terraform/scripts/phase-0-reconciliation.sh b/terraform/scripts/phase-0-reconciliation.sh deleted file mode 100755 index 1fdc8a2..0000000 --- a/terraform/scripts/phase-0-reconciliation.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/bash -# Phase 0 — Read-only reconciliation of three ownership ambiguities -# Safe to run; only queries, no mutations - -set -e -cd "$(dirname "$0")/.." - -echo "=== Phase 0: Cluster Reconciliation ===" -echo "" - -# Ambiguity 1: minio (storage) — standalone chart vs. Operator Tenant -echo "--- Ambiguity 1: minio (storage) ownership ---" -echo "Helm releases in 'storage' namespace:" -helm list -n storage || echo " (helm list failed)" -echo "" -echo "MinIO Operator Tenants in 'storage' namespace:" -kubectl get tenant -n storage -o wide 2>/dev/null || echo " (no Tenant CRD or none found)" -echo "" -echo "PVCs in 'storage' namespace:" -kubectl get pvc -n storage -o wide || echo " (kubectl failed)" -echo "" - -# Ambiguity 2: kmsvc-redis — helmfile release vs. ArgoCD Application -echo "--- Ambiguity 2: kmsvc-redis ownership ---" -echo "ArgoCD Applications containing 'redis':" -argocd app list | grep redis || echo " (no match or argocd unavailable)" -echo "" -echo "Helm releases in 'sqs' namespace:" -helm list -n sqs | grep redis || echo " (no redis release)" -echo "" -echo "Redis-related PVCs in 'sqs' namespace:" -kubectl get pvc -n sqs -o wide | grep -i redis || echo " (no redis PVC)" -echo "" - -# Ambiguity 3: forgejo-runner — helm chart vs. raw manifest -echo "--- Ambiguity 3: forgejo-runner ownership ---" -echo "Helm releases in 'cicd' namespace containing 'runner':" -helm list -n cicd | grep runner || echo " (no runner release)" -echo "" -echo "Deployments in 'cicd' namespace with label app=forgejo-runner:" -kubectl get deploy -n cicd -l app=forgejo-runner -o wide || echo " (no matching deployment)" -echo "" -echo "Checking managedFields on any forgejo-runner Deployment (to identify controller):" -kubectl get deploy -n cicd -l app=forgejo-runner -o json 2>/dev/null | jq '.items[0].metadata.managedFields' 2>/dev/null || echo " (no deployment found)" -echo "" -echo "PVCs in 'cicd' namespace named runner-*:" -kubectl get pvc -n cicd -o wide | grep runner || echo " (no runner PVC)" -echo "" - -echo "=== Phase 0 Complete ===" -echo "Review the output above. Determine which of the three ambiguities are resolved:" -echo " 1. minio(storage): Is Helm release or Tenant CR authoritative? (helm list vs kubectl get tenant)" -echo " 2. kmsvc-redis: Is helmfile or ArgoCD Application active? (argocd app list vs helm list)" -echo " 3. forgejo-runner: Is Helm chart or raw manifest applied? (helm list vs kubectl get deploy managedFields)" -echo "" -echo "Document your findings. Proceed to Phase 1 (StorageClass import) only after clarity." diff --git a/terraform/scripts/phase-1-storageclass-import.sh b/terraform/scripts/phase-1-storageclass-import.sh deleted file mode 100755 index 20bc217..0000000 --- a/terraform/scripts/phase-1-storageclass-import.sh +++ /dev/null @@ -1,87 +0,0 @@ -#!/bin/bash -# Phase 1 — StorageClass import (longhorn + longhorn-kafka) -# Captures live spec, verifies against resource blocks, imports to state - -set -e -cd "$(dirname "$0")/.." - -echo "=== Phase 1: StorageClass Import ===" -echo "" - -# Verify cluster connection -echo "Checking cluster connection..." -kubectl cluster-info || { echo "ERROR: No cluster access"; exit 1; } -echo "" - -# Capture live longhorn SC spec -echo "--- Capturing live 'longhorn' StorageClass spec ---" -kubectl get sc longhorn -o yaml > /tmp/longhorn-live.yaml -echo "Saved to /tmp/longhorn-live.yaml" -echo "Contents:" -cat /tmp/longhorn-live.yaml -echo "" - -# Capture live longhorn-kafka SC spec -echo "--- Capturing live 'longhorn-kafka' StorageClass spec ---" -kubectl get sc longhorn-kafka -o yaml > /tmp/longhorn-kafka-live.yaml -echo "Saved to /tmp/longhorn-kafka-live.yaml" -echo "Contents:" -cat /tmp/longhorn-kafka-live.yaml -echo "" - -# Verify terraform resource blocks match live spec -echo "--- Verifying terraform/longhorn.tf resource blocks against live specs ---" -echo "MANUAL STEP: Compare the captured specs above against terraform/longhorn.tf" -echo " 1. Check 'provisioner', 'reclaimPolicy', 'volumeBindingMode', 'allowVolumeExpansion'" -echo " 2. Check 'parameters' (numberOfReplicas, staleReplicaTimeout, fsType, dataLocality)" -echo " 3. Fix terraform/longhorn.tf if any diffs found, then re-run terraform plan" -echo "" -read -p "Press Enter once you've verified the Terraform blocks match live specs: " _ || true -echo "" - -# Pre-import terraform plan -echo "--- Pre-import terraform plan (should be clean) ---" -terraform plan -out=/tmp/pre-import.plan || { echo "ERROR: terraform plan failed"; exit 1; } -echo "Plan saved to /tmp/pre-import.plan" -echo "" - -# Import longhorn SC -echo "--- Importing 'longhorn' StorageClass ---" -terraform import kubernetes_storage_class.longhorn longhorn || { - echo "ERROR: terraform import longhorn failed" - exit 1 -} -echo "Import successful" -echo "" - -# Plan after first import -echo "--- Terraform plan after importing 'longhorn' (must show 0 to add/change/destroy) ---" -terraform plan || { echo "ERROR: terraform plan failed"; exit 1; } -echo "" -read -p "Press Enter if plan shows zero changes; otherwise abort and fix: " _ || true -echo "" - -# Import longhorn-kafka SC -echo "--- Importing 'longhorn-kafka' StorageClass ---" -terraform import kubernetes_storage_class.longhorn_kafka longhorn-kafka || { - echo "ERROR: terraform import longhorn-kafka failed" - exit 1 -} -echo "Import successful" -echo "" - -# Plan after second import -echo "--- Terraform plan after importing 'longhorn-kafka' (must show 0 to add/change/destroy) ---" -terraform plan || { echo "ERROR: terraform plan failed"; exit 1; } -echo "" -read -p "Press Enter if plan shows zero changes; otherwise abort and fix: " _ || true -echo "" - -# Annotate longhorn-kafka with helm.sh/resource-policy=keep -echo "--- Annotating 'longhorn-kafka' with helm.sh/resource-policy=keep ---" -kubectl annotate storageclass longhorn-kafka helm.sh/resource-policy=keep --overwrite -echo "Annotation added" -echo "" - -echo "=== Phase 1 Complete ===" -echo "StorageClasses imported successfully. Ready to proceed to Phase 2 (PVC imports)." diff --git a/terraform/scripts/phase-2-pilot-grafana.sh b/terraform/scripts/phase-2-pilot-grafana.sh deleted file mode 100755 index d3d5edc..0000000 --- a/terraform/scripts/phase-2-pilot-grafana.sh +++ /dev/null @@ -1,148 +0,0 @@ -#!/bin/bash -# Phase 2 Pilot — Grafana PVC import (full cycle: annotate → import → plan → values change → helmfile diff → helmfile apply) -# Lowest blast radius, validates entire workflow before rolling to other apps - -set -e -cd "$(dirname "$0")/.." - -echo "=== Phase 2 Pilot: Grafana PVC Import ===" -echo "" - -# Step a) Protect the live PVC from Helm deletion -echo "--- Step a) Protect PVC from Helm deletion ---" -echo "Identifying grafana PVC in 'logging' namespace:" -kubectl get pvc -n logging -l app.kubernetes.io/instance=grafana -o wide || { - echo "ERROR: Cannot find grafana PVC" - exit 1 -} -echo "" -echo "Annotating with helm.sh/resource-policy=keep (non-destructive, reversible):" -kubectl annotate pvc grafana -n logging helm.sh/resource-policy=keep --overwrite -echo "Annotation applied" -echo "" - -# Step b) Capture the exact live PVC spec -echo "--- Step b) Capture live PVC spec ---" -kubectl get pvc grafana -n logging -o yaml > /tmp/grafana-pvc-live.yaml -echo "Saved to /tmp/grafana-pvc-live.yaml" -echo "" -echo "Extracting key fields:" -echo "Access modes:" -kubectl get pvc grafana -n logging -o jsonpath='{.spec.accessModes}' | tr ',' '\n' -echo "Storage class:" -kubectl get pvc grafana -n logging -o jsonpath='{.spec.storageClassName}' -echo "" -echo "Requested storage:" -kubectl get pvc grafana -n logging -o jsonpath='{.spec.resources.requests.storage}' -echo "" -echo "Bound PV name:" -PV_NAME=$(kubectl get pvc grafana -n logging -o jsonpath='{.spec.volumeName}') -echo "$PV_NAME" -echo "" -echo "MANUAL STEP: Update terraform/grafana.tf with the actual volumeName '$PV_NAME' (currently 'pvc-grafana' as placeholder)" -echo "" -read -p "Press Enter once grafana.tf is updated with the correct volumeName: " _ || true -echo "" - -# Step d) Import and verify zero diff -echo "--- Step d) Import 'grafana' PVC ---" -terraform import kubernetes_persistent_volume_claim.grafana logging/grafana || { - echo "ERROR: terraform import failed" - exit 1 -} -echo "Import successful" -echo "" - -echo "--- Verifying zero diff (must show 0 to add/change/destroy) ---" -PLAN_OUTPUT=$(terraform plan 2>&1) -echo "$PLAN_OUTPUT" -if echo "$PLAN_OUTPUT" | grep -q "0 to add, 0 to change, 0 to destroy"; then - echo "✓ Plan is clean" -else - echo "✗ Plan shows changes — STOP, do not proceed" - echo " Options:" - echo " 1. Fix terraform/grafana.tf and re-run terraform plan" - echo " 2. Rollback with: terraform state rm kubernetes_persistent_volume_claim.grafana" - exit 1 -fi -echo "" - -# Step f) Verify Longhorn replica health BEFORE values change -echo "--- Step f.1) Baseline Longhorn replica health ---" -LONGHORN_VOL=$(kubectl get pvc grafana -n logging -o jsonpath='{.spec.volumeName}' | sed 's/pvc-//' ) -echo "Checking Longhorn volume health for: $LONGHORN_VOL" -kubectl get longhorn-volume -n longhorn-system "$LONGHORN_VOL" -o json | jq '.status.replicaStatus' 2>/dev/null || echo " (could not get Longhorn status; continue)" -echo "" -read -p "Note the replica status above. Press Enter to continue: " _ || true -echo "" - -# Step e) Update grafana values to use existingClaim (only if chart supports it) -echo "--- Step e) Update k8s/logging/grafana-values.yaml for existingClaim ---" -echo "Current grafana-values.yaml persistence section:" -grep -A 5 "^persistence:" k8s/logging/grafana-values.yaml || echo " (no persistence section found)" -echo "" -echo "MANUAL STEP: Add/update to k8s/logging/grafana-values.yaml:" -echo " persistence:" -echo " existingClaim: grafana" -echo " enabled: false" -echo "" -echo "If the chart does NOT support existingClaim (check Grafana chart docs), leave:" -echo " persistence:" -echo " enabled: true" -echo " size: 5Gi" -echo " storageClassName: longhorn" -echo " (Helm will then see no diff and won't delete the PVC; the keep annotation is the backstop)" -echo "" -read -p "Press Enter once grafana-values.yaml is updated: " _ || true -echo "" - -# Step e.2) helmfile diff to confirm no delete queued -echo "--- Step e.2) Helmfile diff to confirm no delete/replace ---" -echo "Running helmfile diff for grafana (in logging namespace, chart= from helmfile):" -cd "$(dirname "$0")/../.." # go to repo root -helmfile -e logging -f helmfile.yaml.gotmpl -l name=grafana diff || { - echo "WARNING: helmfile diff failed or returned nonzero exit; check output above" - echo " (helmfile may not be perfectly compatible with this session, but diff result should be visible)" -} -cd "$(dirname "$0")/../terraform" -echo "" -echo "Confirm no 'delete' or 'replace' operations on the grafana PVC are queued." -echo "" -read -p "Press Enter if helmfile diff shows no destructive ops on grafana PVC: " _ || true -echo "" - -# Step e.3) helmfile apply -echo "--- Step e.3) Helmfile apply ---" -cd "$(dirname "$0")/../.." -echo "Applying logging/grafana via helmfile:" -helmfile -e logging -f helmfile.yaml.gotmpl -l name=grafana apply || { - echo "WARNING: helmfile apply returned nonzero; check output above" -} -cd "$(dirname "$0")/../terraform" -echo "" -echo "Helmfile apply complete" -echo "" - -# Step f.2) Verify Longhorn health AFTER helmfile apply -echo "--- Step f.2) Post-helmfile Longhorn replica health check ---" -echo "Checking Longhorn volume health for: $LONGHORN_VOL" -kubectl get longhorn-volume -n longhorn-system "$LONGHORN_VOL" -o json | jq '.status.replicaStatus' 2>/dev/null || echo " (could not get Longhorn status)" -echo "" -echo "Confirm replica status is identical to baseline above." -read -p "Press Enter if replica health matches baseline: " _ || true -echo "" - -# Final terraform plan -echo "--- Final terraform plan (must still be 0/0/0 after all changes) ---" -PLAN_OUTPUT=$(terraform plan 2>&1) -echo "$PLAN_OUTPUT" -if echo "$PLAN_OUTPUT" | grep -q "0 to add, 0 to change, 0 to destroy"; then - echo "✓ Plan is still clean" -else - echo "✗ Plan shows changes after helmfile apply — investigate" - exit 1 -fi -echo "" - -echo "=== Phase 2 Pilot: Grafana Complete ===" -echo "Grafana PVC successfully imported. Ready for Phase 2 remaining apps." diff --git a/terraform/scripts/phase-2-remaining-apps.sh b/terraform/scripts/phase-2-remaining-apps.sh deleted file mode 100755 index 904b375..0000000 --- a/terraform/scripts/phase-2-remaining-apps.sh +++ /dev/null @@ -1,122 +0,0 @@ -#!/bin/bash -# Phase 2 Remaining Apps — Per-app PVC imports (portainer → dev-tools → loki → minio-logging → forgejo) -# Same procedure as grafana pilot; follow the pattern - -set -e -cd "$(dirname "$0")/.." - -echo "=== Phase 2 Remaining Apps ===" -echo "Execute per-app cycles: portainer → dev-tools → loki → minio-logging → forgejo" -echo "" - -# Helper function for per-app import -import_app_pvc() { - local app=$1 - local namespace=$2 - local pvc_name=$3 - - echo "--- Importing $app PVC ---" - echo "" - - # Annotate - echo "Step a) Annotate PVC with helm.sh/resource-policy=keep:" - kubectl annotate pvc "$pvc_name" -n "$namespace" helm.sh/resource-policy=keep --overwrite - echo "" - - # Capture live spec - echo "Step b) Capture live PVC spec:" - kubectl get pvc "$pvc_name" -n "$namespace" -o yaml > "/tmp/${app}-pvc-live.yaml" - echo "Saved to /tmp/${app}-pvc-live.yaml" - echo "" - PV_NAME=$(kubectl get pvc "$pvc_name" -n "$namespace" -o jsonpath='{.spec.volumeName}') - echo "Bound PV: $PV_NAME" - echo "MANUAL: Update terraform/${app}.tf with correct volumeName '$PV_NAME'" - read -p "Press Enter once terraform/${app}.tf is updated: " _ || true - echo "" - - # Import - echo "Step d) Import to Terraform state:" - terraform import "kubernetes_persistent_volume_claim.${app}" "${namespace}/${pvc_name}" || { - echo "ERROR: import failed for $app" - return 1 - } - echo "" - - # Plan - echo "Step d cont.) Verify zero diff:" - PLAN_OUTPUT=$(terraform plan 2>&1) - echo "$PLAN_OUTPUT" - if ! echo "$PLAN_OUTPUT" | grep -q "0 to add, 0 to change, 0 to destroy"; then - echo "ERROR: Plan is not clean for $app" - return 1 - fi - echo "✓ Plan is clean" - echo "" - - # Baseline Longhorn health - echo "Step f.1) Baseline Longhorn replica health:" - kubectl get longhorn-volume -n longhorn-system "$PV_NAME" -o json 2>/dev/null | jq '.status.replicaStatus' 2>/dev/null || echo " (unavailable)" - read -p "Press Enter to continue: " _ || true - echo "" - - # Update values - echo "Step e) Update values to use existingClaim (if supported) or keep identical:" - echo "MANUAL: Verify terraform/${app}.tf resource block matches live PVC spec exactly" - echo " Update chart values (k8s/ directory) to point to existing PVC or keep identical" - read -p "Press Enter once values updated: " _ || true - echo "" - - # helmfile diff - echo "Step e.2) Helmfile diff:" - cd "$(dirname "$0")/../.." - helmfile -f helmfile.yaml.gotmpl -l name="$app" diff 2>&1 | head -50 || echo " (helmfile diff unavailable)" - cd "$(dirname "$0")/../terraform" - echo "" - read -p "Confirm no destructive ops. Press Enter to continue: " _ || true - echo "" - - # helmfile apply - echo "Step e.3) Helmfile apply:" - cd "$(dirname "$0")/../.." - helmfile -f helmfile.yaml.gotmpl -l name="$app" apply || echo " (helmfile apply unavailable)" - cd "$(dirname "$0")/../terraform" - echo "" - - # Post-apply Longhorn health - echo "Step f.2) Post-apply Longhorn health:" - kubectl get longhorn-volume -n longhorn-system "$PV_NAME" -o json 2>/dev/null | jq '.status.replicaStatus' 2>/dev/null || echo " (unavailable)" - echo "Confirm matches baseline." - read -p "Press Enter if health is good: " _ || true - echo "" - - # Final plan - echo "Step d) Final terraform plan:" - PLAN_OUTPUT=$(terraform plan 2>&1) - echo "$PLAN_OUTPUT" - if ! echo "$PLAN_OUTPUT" | grep -q "0 to add, 0 to change, 0 to destroy"; then - echo "ERROR: Plan is not clean after helmfile apply for $app" - return 1 - fi - echo "✓ Plan is clean" - echo "" - echo "=== $app Complete ===" - echo "" -} - -# Execute per-app imports in sequence (ascending risk) -import_app_pvc "portainer" "dashboard" "portainer" || { echo "FAILED at portainer"; exit 1; } -import_app_pvc "dev_tools" "dev-tools" "dev-tools-pvc" || { echo "FAILED at dev-tools"; exit 1; } -import_app_pvc "loki" "logging" "loki" || { echo "FAILED at loki"; exit 1; } -import_app_pvc "minio_logging" "logging" "minio" || { echo "FAILED at minio-logging"; exit 1; } -import_app_pvc "forgejo_shared_storage" "cicd" "forgejo-shared-storage" || { echo "FAILED at forgejo"; exit 1; } - -echo "=== Phase 2 Remaining Apps: Complete ===" -echo "All safe apps imported successfully." -echo "" -echo "Next steps:" -echo " 1. Conditional apps (pending Phase 0 ambiguity resolution):" -echo " - minio (storage) — if standalone chart is authoritative" -echo " - kmsvc-redis — if helmfile release is authoritative and architecture is standalone" -echo " - forgejo-runner PVCs — if Helm chart is authoritative" -echo " 2. Never import: ddb-cluster, prometheus, kafka-cluster, authentik-postgresql, llm namespace" -echo " 3. Commit all new terraform/*.tf files to git and create PR" diff --git a/terraform/state.tf b/terraform/state.tf deleted file mode 100644 index 01c336f..0000000 --- a/terraform/state.tf +++ /dev/null @@ -1,13 +0,0 @@ -# S3 backend (MinIO remote state) -terraform { - backend "s3" { - bucket = "terraform-state" - key = "homelab/terraform.tfstate" - region = "us-east-1" - endpoint = "https://minio-api.riotpiao.homelab.com" - skip_credentials_validation = true - skip_requesting_account_id = true - skip_region_validation = true - use_path_style = true - } -} diff --git a/terraform/terraform.tfvars b/terraform/terraform.tfvars deleted file mode 100644 index 7a809cb..0000000 --- a/terraform/terraform.tfvars +++ /dev/null @@ -1,21 +0,0 @@ -kubeconfig_path = "/Users/rockliang/workplace/homelab/cluster-config/kubeconfig" -cluster_domain = "riotpiao.homelab.com" - -authentik_secret_key = "v9TTdMxpP9XtrwH2HFUjHC8MKwfeW+fYOpa5RTyP6EniqFclFSDXWbRp6crhrkLJkFeCfIcAMN/JODyy" -authentik_bootstrap_password = "8+7MFMCtAHiOxSaiBJwDiR85nnrhLyX2" -authentik_bootstrap_token = "5a534cb785aecddac23647e11ff4d824b50b03f70c173faee7ba46f12db55dc3" -authentik_pg_password = "vueM/7N6bUR/j/hUUPsWTM2pRm8lCewq" -postgres_password = "a071b1f7b721a216b57d396b8d906fa10f6db1597d68a0f2e9f95e2872e7cb0f" -minio_root_user = "minioadmin" -minio_root_password = "nhKRAxwIjDBCzwFDvsAa7dNLouCXXh13LvMoxMVkUtY=" -minio_oidc_client_secret = "9d2867fe08c3bf7fedd7e32bbaf4456fce3b0aaf788966d7559e1955947b0219" -grafana_admin_password = "your-secure-password" -grafana_oidc_client_secret = "966bad4fa43812100e7775b3c73fed2ce1d07217fa5a23fbb0f190e46d2f0fa4" -forgejo_admin_password = "stRe4cawnQH/agM0QsPaWPdKNaQ0rp4p" -authentik_forgejo_client_secret = "e417c1a3b3ee79b44c9d8d3490a735aae7b2c19a81afe1ba6a262775d5ae9edc" -authentik_argocd_client_id = "argocd" -authentik_argocd_client_secret = "acc51c1ab043530b84b17dc5e8128b2a656b17558ea3f93e723618ea5c6d9774" -authentik_temporal_client_id = "temporal" -authentik_temporal_client_secret = "6UAuC651l21fajBZQwjV+bbkD1k6uCoV6PnQxaFlPaQ=" -argocd_admin_password = "placeholder" -argocd_oidc_client_secret = "placeholder" diff --git a/terraform/terraform.tfvars.example b/terraform/terraform.tfvars.example deleted file mode 100644 index 3faf444..0000000 --- a/terraform/terraform.tfvars.example +++ /dev/null @@ -1,35 +0,0 @@ -kubeconfig_path = "cluster-config/kubeconfig" -cluster_domain = "riotpiao.homelab.com" - -# Backend S3 credentials (MinIO) -# Set via environment variables instead: -# export AWS_ACCESS_KEY_ID=$(grep MINIO_ROOT_USER .env | cut -d= -f2) -# export AWS_SECRET_ACCESS_KEY=$(grep MINIO_ROOT_PASSWORD .env | cut -d= -f2) -s3_access_key = "" -s3_secret_key = "" - -# Vault token for terraform vault provider -# Set via environment variable: -# export VAULT_TOKEN=$(vault login -method=oidc ...) -vault_token = "" - -# Cluster secrets loaded from .env (extract via 'vsource' alias) -# Or populate these manually from Vault/secrets manager -authentik_secret_key = "changeme-min-32-characters-long-value" -authentik_bootstrap_password = "changeme" -authentik_bootstrap_token = "changeme" -authentik_pg_password = "changeme" -postgres_password = "changeme" -minio_root_user = "minioadmin" -minio_root_password = "changeme" -minio_oidc_client_secret = "changeme" -grafana_admin_password = "changeme" -grafana_oidc_client_secret = "changeme" -forgejo_admin_password = "changeme" -authentik_forgejo_client_secret = "changeme" -authentik_argocd_client_id = "argocd" -authentik_argocd_client_secret = "changeme" -authentik_temporal_client_id = "temporal" -authentik_temporal_client_secret = "changeme" -argocd_admin_password = "changeme" -argocd_oidc_client_secret = "changeme" diff --git a/terraform/variables.tf b/terraform/variables.tf deleted file mode 100644 index 8bedc8b..0000000 --- a/terraform/variables.tf +++ /dev/null @@ -1,142 +0,0 @@ -variable "cluster_domain" { - description = "Cluster domain (e.g., riotpiao.homelab.com)" - type = string - default = "riotpiao.homelab.com" -} - -variable "vault_token" { - description = "Vault token (set via VAULT_TOKEN env var or tfvars)" - type = string - sensitive = true - default = "" -} - -variable "authentik_api_token" { - description = "Authentik API token for goauthentik provider (terraform configuration management)" - type = string - sensitive = true - default = "" -} - -variable "s3_access_key" { - description = "MinIO S3 access key for terraform state backend" - type = string - sensitive = true - default = "" -} - -variable "s3_secret_key" { - description = "MinIO S3 secret key for terraform state backend" - type = string - sensitive = true - default = "" -} - -# Cluster secrets (load from .env.tfvars or vault) -variable "authentik_secret_key" { - description = "Authentik secret key" - type = string - sensitive = true -} - -variable "authentik_bootstrap_password" { - description = "Authentik bootstrap password" - type = string - sensitive = true -} - -variable "authentik_bootstrap_token" { - description = "Authentik bootstrap token" - type = string - sensitive = true -} - -variable "authentik_pg_password" { - description = "Authentik PostgreSQL password" - type = string - sensitive = true -} - -variable "postgres_password" { - description = "PostgreSQL app user password" - type = string - sensitive = true -} - -variable "minio_root_user" { - description = "MinIO root user" - type = string - sensitive = true -} - -variable "minio_root_password" { - description = "MinIO root password" - type = string - sensitive = true -} - -variable "minio_oidc_client_secret" { - description = "MinIO OIDC client secret" - type = string - sensitive = true -} - -variable "grafana_admin_password" { - description = "Grafana admin password" - type = string - sensitive = true -} - -variable "grafana_oidc_client_secret" { - description = "Grafana OIDC client secret" - type = string - sensitive = true -} - -variable "forgejo_admin_password" { - description = "Forgejo admin password" - type = string - sensitive = true -} - -variable "authentik_forgejo_client_secret" { - description = "Authentik Forgejo OIDC client secret" - type = string - sensitive = true -} - -variable "authentik_argocd_client_id" { - description = "Authentik ArgoCD OIDC client ID" - type = string - sensitive = true -} - -variable "authentik_argocd_client_secret" { - description = "Authentik ArgoCD OIDC client secret" - type = string - sensitive = true -} - -variable "authentik_temporal_client_id" { - description = "Authentik Temporal OIDC client ID" - type = string - sensitive = true -} - -variable "authentik_temporal_client_secret" { - description = "Authentik Temporal OIDC client secret" - type = string - sensitive = true -} - -variable "argocd_admin_password" { - description = "ArgoCD admin password" - type = string - sensitive = true -} - -variable "argocd_oidc_client_secret" { - description = "ArgoCD OIDC client secret" - type = string - sensitive = true -}