cluster

Infrastructure files for Nordgedanken and Midnightthoughts.
git clone git://archive.git.mtrnord.blog/MTRNord/cluster.git
Log | Files | Refs | README

commit 2bd7fb534aed4f615bac034a5a0289107c666617
parent 59a29b8d8150d7ede97280582d74ff7e38489a02
Author: MTRNord <MTRNord@users.noreply.github.com>
Date:   Sun,  7 Dec 2025 21:08:10 +0100

meow?

Signed-off-by: MTRNord <MTRNord@users.noreply.github.com>

Diffstat:
M.github/renovate.json | 133++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
A.github/workflows/renovate.yaml | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
A.github/workflows/validate.yaml | 191+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MREADME.md | 116++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
4 files changed, 483 insertions(+), 8 deletions(-)

diff --git a/.github/renovate.json b/.github/renovate.json @@ -1,11 +1,130 @@ { + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:base", + ":dependencyDashboard", + ":semanticCommits", + ":separateMultipleMinorReleases" + ], "prConcurrentLimit": 4, "prHourlyLimit": 5, - "semanticCommits": "enabled", - "enabledManagers": [ - "github-actions", - "helm-values", - "helmv3", - "flux" - ] + "suppressNotifications": ["prIgnoreNotification"], + "rebaseWhen": "conflicted", + "enabledManagers": ["github-actions", "helm-values", "helmv3", "flux"], + "flux": { + "fileMatch": [ + "(^|/)clusters/.+\\.ya?ml$", + "(^|/)infrastructure_talos/.+\\.ya?ml$", + "(^|/)apps/.+\\.ya?ml$" + ] + }, + "helm-values": { + "fileMatch": [ + "(^|/)apps/.+/values\\.ya?ml$", + "(^|/)infrastructure_talos/.+/values\\.ya?ml$" + ] + }, + "kubernetes": { + "fileMatch": [ + "(^|/)clusters/.+\\.ya?ml$", + "(^|/)infrastructure_talos/.+\\.ya?ml$", + "(^|/)apps/.+\\.ya?ml$" + ] + }, + "packageRules": [ + { + "description": "Auto-merge patch updates", + "matchUpdateTypes": ["patch"], + "matchCurrentVersion": "!/^0/", + "automerge": true, + "automergeType": "pr", + "platformAutomerge": true + }, + { + "description": "Auto-merge minor updates for non-breaking changes", + "matchUpdateTypes": ["minor"], + "matchCurrentVersion": "!/^0/", + "automerge": false, + "groupName": "minor-updates" + }, + { + "description": "Group Flux component updates", + "matchDatasources": ["docker", "github-releases"], + "matchPackagePatterns": ["^fluxcd/"], + "groupName": "flux-components", + "automerge": false + }, + { + "description": "Group cert-manager updates", + "matchDatasources": ["docker", "helm"], + "matchPackagePatterns": ["cert-manager"], + "groupName": "cert-manager", + "automerge": false + }, + { + "description": "Group monitoring stack updates", + "matchDatasources": ["docker", "helm"], + "matchPackagePatterns": [ + "prometheus", + "grafana", + "alertmanager", + "kube-state-metrics", + "node-exporter" + ], + "groupName": "monitoring-stack", + "automerge": false + }, + { + "description": "Group security updates and auto-merge", + "matchDatasources": ["docker"], + "matchUpdateTypes": ["patch"], + "vulnerabilityAlerts": { + "enabled": true + }, + "groupName": "security-updates", + "automerge": true, + "schedule": ["at any time"] + }, + { + "description": "Pin GitHub Actions digests", + "matchManagers": ["github-actions"], + "pinDigests": true + }, + { + "description": "Group GitHub Actions updates", + "matchManagers": ["github-actions"], + "groupName": "github-actions", + "automerge": true, + "automergeType": "pr" + }, + { + "description": "Separate major updates", + "matchUpdateTypes": ["major"], + "automerge": false, + "labels": ["type/major-update"] + }, + { + "description": "Label minor updates", + "matchUpdateTypes": ["minor"], + "labels": ["type/minor-update"] + }, + { + "description": "Label patch updates", + "matchUpdateTypes": ["patch"], + "labels": ["type/patch-update"] + } + ], + "regexManagers": [ + { + "description": "Update _VERSION variables in shell scripts", + "fileMatch": ["\\.sh$"], + "matchStrings": [ + "datasource=(?<datasource>\\S+) depName=(?<depName>\\S+)( versioning=(?<versioning>\\S+))?\n.*?_VERSION=\"(?<currentValue>.*)\"" + ] + } + ], + "vulnerabilityAlerts": { + "enabled": true, + "labels": ["security", "type/security-update"] + } } diff --git a/.github/workflows/renovate.yaml b/.github/workflows/renovate.yaml @@ -0,0 +1,51 @@ +--- +name: Renovate + +on: + schedule: + # Run every day at 2:00 AM UTC + - cron: '0 2 * * *' + workflow_dispatch: + inputs: + logLevel: + description: 'Log level' + required: false + default: 'info' + type: choice + options: + - info + - debug + - trace + dryRun: + description: 'Dry run' + required: false + default: 'false' + type: choice + options: + - 'true' + - 'false' + +permissions: + contents: write + pull-requests: write + issues: write + +jobs: + renovate: + name: Renovate Dependencies + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Self-hosted Renovate + uses: renovatebot/github-action@v40.1.12 + with: + configurationFile: .github/renovate.json + token: ${{ secrets.RENOVATE_TOKEN || secrets.GITHUB_TOKEN }} + env: + LOG_LEVEL: ${{ inputs.logLevel || 'info' }} + RENOVATE_DRY_RUN: ${{ inputs.dryRun || 'false' }} + RENOVATE_AUTODISCOVER: 'false' + RENOVATE_BASE_BRANCHES: 'main' + RENOVATE_GIT_AUTHOR: 'Renovate Bot <bot@renovateapp.com>' diff --git a/.github/workflows/validate.yaml b/.github/workflows/validate.yaml @@ -0,0 +1,191 @@ +--- +name: Validate GitOps Manifests + +on: + pull_request: + branches: ["*"] + paths: + - "apps/**" + - "clusters/**" + - "infrastructure_talos/**" + - "scripts/validate.sh" + push: + branches: ["main"] + paths: + - "apps/**" + - "clusters/**" + - "infrastructure_talos/**" + - "scripts/validate.sh" + workflow_dispatch: + +permissions: + contents: read + +jobs: + validate-manifests: + name: Validate Kubernetes Manifests + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Flux CLI + uses: fluxcd/flux2/action@main + + - name: Setup tools + run: | + # Install yq + sudo wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 + sudo chmod +x /usr/local/bin/yq + + # Install kustomize + curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash + sudo mv kustomize /usr/local/bin/ + + # Install kubeconform + curl -LO https://github.com/yannh/kubeconform/releases/latest/download/kubeconform-linux-amd64.tar.gz + tar xzf kubeconform-linux-amd64.tar.gz + sudo mv kubeconform /usr/local/bin/ + + # Verify installations + yq --version + kustomize version + kubeconform -v + + - name: Run validation script + run: | + chmod +x scripts/validate.sh + ./scripts/validate.sh + + - name: Validate Flux sources + run: | + flux check --pre + + security-scan: + name: Security Scanning + runs-on: ubuntu-latest + permissions: + contents: read + security-events: write + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Run gitleaks + uses: gitleaks/gitleaks-action@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Setup tools for manifest extraction + run: | + # Install yq + sudo wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 + sudo chmod +x /usr/local/bin/yq + + # Install kustomize + curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash + sudo mv kustomize /usr/local/bin/ + + - name: Extract container images + id: extract-images + run: | + set +e + mkdir -p /tmp/manifests + + # Build all kustomizations and extract images + find . -type f -name 'kustomization.yaml' | while read -r file; do + dir=$(dirname "$file") + echo "Building $dir" + kustomize build "$dir" --load-restrictor=LoadRestrictionsNone > /tmp/manifests/$(echo "$dir" | tr '/' '_').yaml 2>/dev/null || true + done + + # Extract unique images + cat /tmp/manifests/*.yaml | yq eval 'select(.spec.template.spec.containers != null) | .spec.template.spec.containers[].image' - 2>/dev/null | sort -u > /tmp/images.txt || true + cat /tmp/manifests/*.yaml | yq eval 'select(.spec.template.spec.initContainers != null) | .spec.template.spec.initContainers[].image' - 2>/dev/null | sort -u >> /tmp/images.txt || true + + # Extract images from HelmRelease values + find . -type f -name '*.yaml' -exec grep -l "kind: HelmRelease" {} \; | while read -r file; do + yq eval '.spec.values | .. | select(. == "*image*" or . == "*repository*") | select(type == "!!str")' "$file" 2>/dev/null || true + done >> /tmp/images.txt || true + + sort -u /tmp/images.txt > /tmp/images_final.txt + + echo "Found images:" + cat /tmp/images_final.txt + + - name: Run Trivy vulnerability scanner + uses: aquasecurity/trivy-action@master + with: + scan-type: 'config' + scan-ref: '.' + format: 'sarif' + output: 'trivy-results.sarif' + severity: 'CRITICAL,HIGH' + + - name: Upload Trivy results to GitHub Security + uses: github/codeql-action/upload-sarif@v3 + if: always() + with: + sarif_file: 'trivy-results.sarif' + + kubeaudit: + name: Kubernetes Security Audit + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup tools + run: | + # Install kustomize + curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash + sudo mv kustomize /usr/local/bin/ + + # Install kubeaudit + curl -LO https://github.com/Shopify/kubeaudit/releases/latest/download/kubeaudit_linux_amd64.tar.gz + tar xzf kubeaudit_linux_amd64.tar.gz + sudo mv kubeaudit /usr/local/bin/ + + - name: Run kubeaudit + continue-on-error: true + run: | + mkdir -p /tmp/manifests + + # Build all kustomizations + find . -type f -name 'kustomization.yaml' | while read -r file; do + dir=$(dirname "$file") + echo "Building $dir" + kustomize build "$dir" --load-restrictor=LoadRestrictionsNone > /tmp/manifests/$(echo "$dir" | tr '/' '_').yaml 2>/dev/null || true + done + + # Run kubeaudit on each manifest + for manifest in /tmp/manifests/*.yaml; do + echo "Auditing $manifest" + if [ -f kubeaudit-config.yml ]; then + kubeaudit all -f "$manifest" --minseverity warning -c kubeaudit-config.yml || true + else + kubeaudit all -f "$manifest" --minseverity warning || true + fi + done + + lint: + name: Lint YAML Files + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: YAML Lint + uses: ibiqlik/action-yamllint@v3 + with: + config_data: | + extends: default + rules: + line-length: + max: 120 + level: warning + document-start: disable + truthy: + check-keys: false diff --git a/README.md b/README.md @@ -1 +1,115 @@ -TODO: Rewrite this file +# Talos Kubernetes GitOps Repository + +GitOps configuration for Kubernetes on [Talos Linux](https://www.talos.dev/) using [Flux CD](https://fluxcd.io/). + +## Stack + +- **OS**: Talos Linux +- **GitOps**: Flux CD +- **Secrets**: SOPS + age +- **CNI**: Cilium +- **Updates**: Renovate + +## Structure + +``` +├── clusters/talos_cluster/ # Flux bootstrap +├── infrastructure_talos/ # Controllers, monitoring +├── apps/ # Applications +└── .github/workflows/ # CI (validation, renovate) +``` + +## Quick Start + +```bash +# Bootstrap Talos +talosctl gen config my-cluster https://CONTROL_PLANE_IP:6443 +talosctl apply-config --insecure --nodes CONTROL_PLANE_IP --file controlplane.yaml +talosctl bootstrap --nodes CONTROL_PLANE_IP +talosctl kubeconfig --nodes CONTROL_PLANE_IP + +# Install Flux +flux check --pre +kubectl apply -k clusters/talos_cluster/flux-system + +# Setup SOPS (generate NEW key, never use the one in repo!) +age-keygen -o age.key +kubectl create secret generic sops-age --namespace=flux-system --from-file=age.agekey=age.key +# Update .sops.yaml with your public key, store age.key securely + +# Deploy +flux reconcile kustomization flux-system --with-source +``` + +## Secrets + +```bash +# Encrypt +sops --encrypt --encrypted-regex '^(data|stringData)$' secret.yaml > secret.enc.yaml + +# Edit +sops secret.enc.yaml +``` + +**Never commit:** `age.key`, `age.agekey`, decrypted secrets + +## Common Tasks + +```bash +# Deploy changes +git commit -am "update" && git push + +# Force reconcile +flux reconcile kustomization flux-system --with-source + +# Check status +flux get all -A +flux logs --level=error + +# Rollback +git revert COMMIT && git push +``` + +## CI/CD + +- **validate.yaml**: Validates manifests, runs security scans (gitleaks, trivy, kubeaudit) +- **renovate.yaml**: Automated dependency updates (daily 2 AM UTC) + +Run locally: `./scripts/validate.sh` + +## Troubleshooting + +```bash +# Flux +flux check +flux logs --all-namespaces + +# SOPS +kubectl get secret sops-age -n flux-system + +# Apps +kubectl describe pod POD -n NAMESPACE +kubectl logs POD -n NAMESPACE + +# Talos +talosctl health --nodes NODE_IP +talosctl logs -n NODE_IP +``` + +## Security Notes + +**Critical**: The `age.agekey` in this repo is exposed and must be rotated immediately. + +Remove sensitive files: `age.agekey`, `gerrit_key*`, `*.log`, `audit.txt`, `bak_*` + +Apply security policies: + +- Pod Security Standards (restricted mode) +- LimitRanges for resource defaults +- ResourceQuotas for namespace limits +- NetworkPolicies (default-deny) + +## Resources + +- [Flux Docs](https://fluxcd.io/docs/) +- [Talos Docs](https://www.talos.dev/docs/)