refactor: retire Terraform, migrate to pure ArgoCD GitOps + CI validation
This commit is contained in:
@@ -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 <registration-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 = <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 <commit-hash>
|
||||||
|
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 = <new-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! 🎉
|
||||||
@@ -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
|
||||||
@@ -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"
|
||||||
@@ -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
|
|
||||||
@@ -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"
|
||||||
@@ -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
|
||||||
@@ -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 <commit-hash>
|
||||||
|
git push
|
||||||
|
|
||||||
|
# ArgoCD detects change, syncs back to previous state
|
||||||
|
|
||||||
|
# Rollback single service
|
||||||
|
git checkout <commit-hash> -- k8s/applications/forgejo/
|
||||||
|
git commit -m "revert: forgejo back to <version>"
|
||||||
|
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
|
||||||
@@ -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 <layer-commit>`
|
||||||
|
|
||||||
|
### ✓ 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 <commit-hash>
|
||||||
|
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
|
||||||
@@ -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 <commit-before-migration>
|
||||||
|
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)
|
||||||
Generated
-128
@@ -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",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
-375
@@ -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.
|
|
||||||
BIN
Binary file not shown.
-375
@@ -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.
|
|
||||||
BIN
Binary file not shown.
-375
@@ -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.
|
|
||||||
BIN
Binary file not shown.
-375
@@ -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.
|
|
||||||
BIN
Binary file not shown.
@@ -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 <pv-name> -o json | jq '.status.replicaStatus'
|
|
||||||
# After helmfile apply, must be identical
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **No destructive ops queued:**
|
|
||||||
```bash
|
|
||||||
helmfile -f helmfile.yaml.gotmpl -l name=<app> 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/<app>.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 <name> -n <ns> -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 <vol> -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 <branch>
|
|
||||||
```
|
|
||||||
|
|
||||||
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 <vol> -o json | jq '.status.replicaStatus'`
|
|
||||||
- **Hard rule:** Never manually delete a PVC without verified replicas/backups (CLAUDE.md)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Last updated:** 2026-07-15
|
|
||||||
@@ -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
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
@@ -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 = "[email protected]"
|
|
||||||
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 = "[email protected]"
|
|
||||||
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 = "[email protected]"
|
|
||||||
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"
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
@@ -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."
|
|
||||||
@@ -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
|
|
||||||
@@ -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"
|
|
||||||
@@ -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."
|
|
||||||
@@ -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)."
|
|
||||||
@@ -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."
|
|
||||||
@@ -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"
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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"
|
|
||||||
@@ -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"
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user