- Add optional: true to secretKeyRef so ingress pods start without
the bouncer key (CrowdSec deploys after infrastructure)
- Move ingress bouncer SealedSecret to crowdsec app (creates in
ingress namespace when CrowdSec deploys)
- Ingress starts without CrowdSec, bouncer activates after secret appears
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
SealedSecret CRD doesn't exist when infrastructure kustomization
first applies. Move to post-crds which depends on infrastructure.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace hardcoded bouncer key with SealedSecrets in both crowdsec
and ingress namespaces. CrowdSec LAPI pre-registers the bouncer
via BOUNCER_KEY_ingress env var, ingress-nginx reads the same key
from its namespace's secret.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
CrowdSec agents need hostPath volumes to read container logs, which
requires a privileged PodSecurity namespace. Move from apps to
dedicated crowdsec namespace.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add encrypted Cloudflare DNS API token for Let's Encrypt DNS-01
challenges. Set ACME account email on ClusterIssuers.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add l2announcements.enabled and externalIPs.enabled to the Cilium
helm template used for Talos bootstrap. This ensures LoadBalancer
VIPs work immediately without needing a Cilium agent restart after
FluxCD upgrades the HelmRelease.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cilium with kubeProxyReplacement=true has native LoadBalancer support
with L2 announcements. MetalLB L2 VIPs weren't reachable because
Cilium was handling the service datapath.
- Enable l2announcements and externalIPs in Cilium HelmRelease
- Add CiliumLoadBalancerIPPool (10.2.40.64-95) and L2AnnouncementPolicy
- Remove MetalLB from infrastructure
- Remove MetalLB annotation from ingress-nginx service
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
First app migration to Kubernetes. Gatus monitors all homelab services
via HTTP/TCP/DNS health checks. Deployed as a Deployment with ConfigMap
for endpoints config, 1Gi ceph-block PVC for SQLite, and Ingress on
status.renner.uno with cert-manager TLS.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add cilium-cni.yaml patch that disables flannel/kube-proxy and
includes Cilium 1.19.2 as an inline manifest
- Cilium installs during Talos bootstrap, no manual helm install needed
- Add certSANs for FQDNs to all node patches
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The raw image is only ~8.6GB, leaving too little ephemeral storage
for Kubernetes pods. Specifying size=32G tells the provider to expand
the disk after importing the image.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The custom Talos schematic includes qemu-guest-agent. The agent is
needed for Proxmox DNS to discover VM IPs via the API.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Revert to using the BPG provider's native file_id disk import.
The provider SSH is configured via variable for qm importdisk.
Remove all SSH-based import steps from the CI pipeline.
Images are already downloaded to local:import/ on all nodes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Woodpecker mangles parameter expansion in multi-line scripts. Use a
shell function with explicit arguments instead.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tofu creates VMs with empty disks in stopped state. The CI post-apply
step imports the Talos disk image via qm importdisk over SSH and
starts the VMs. Avoids Install storage reference on VM start.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The BPG provider's file_id disk import fails on this Proxmox version
with 'unable to parse volume ID' errors. Instead:
- Create VMs with empty 32G boot disks
- Post-apply CI step imports Talos image via qm importdisk over SSH
- Skips import if disk is already populated
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When a disk is imported from a file_id, the size comes from the image.
Setting both size and file_id causes the provider to fail with an
invalid volume ID error.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The provider needs SSH access for qm importdisk. Pass the CI SSH key
as a tofu variable instead of reading from file (file doesn't exist
during plan step).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The provider needs SSH access to Proxmox nodes to import disk images
via qm importdisk. Use the CI-provisioned SSH key.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove download_file resource (times out with hardcoded provider limit).
Instead, download the Talos raw image directly via the Proxmox API
download-url endpoint in the CI pipeline before tofu apply runs.
The image is stored on local storage with import content type.
Skips download if image already exists on the node.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Proxmox doesn't support decompression for import content type.
Use the uncompressed .raw URL from Talos factory instead.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
local storage doesn't support 'import' content type. Store the raw
disk image as 'iso' content type — Proxmox accepts any file in the
ISO directory. The VM disk file_id will import from it correctly.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
local-zfs is a ZFS pool (not file-based), can't upload files to it.
Use local storage with import content type instead.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Provider only accepts 'iso', 'vztmpl', or 'import'. Raw disk images
use 'import' content type on local-zfs storage.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Raw disk images belong on disk storage (local-zfs) with content_type
'images', not on ISO storage. Eliminates dependency on Install NFS.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The local storage doesn't accept ISO content type. Use the Install NFS
storage which is configured for ISO content across all nodes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Allows removing orphaned resources from state before plan/apply.
Needed when VMs are destroyed outside tofu (e.g. broken storage)
and state references non-existent resources.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
BPG provider only supports gz/lzo/zst/bz2 decompression, not xz.
Switch to the .raw.zst variant from Talos factory.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace NFS ISO dependency with proxmox_virtual_environment_download_file
that pulls the Talos nocloud image directly from factory.talos.dev to
each Proxmox node's local storage. VMs boot from the raw disk image
instead of CDROM, eliminating the Install NFS storage dependency.
- Add talos_image.tf with download_file resource per node
- Add file_id support to proxmox_vm module disk config
- Remove CDROM from K8s VM definitions
- Boot order changed to virtio0 only
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PodMonitor CRD requires kube-prometheus-stack which isn't installed yet.
Disable monitoring for now, re-enable after monitoring stack is deployed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
IPAddressPool CRD is installed by MetalLB HelmRelease, so the
IPAddressPool resource must be in the post-crds stage.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
FluxCD dry-run fails when CRD-dependent resources (ClusterIssuer,
CephCluster) are in the same Kustomization as the HelmReleases that
install those CRDs. Split into 3 stages:
1. infrastructure/ - namespaces, HelmReleases (installs CRDs)
2. post-crds/ - ClusterIssuer (needs cert-manager CRDs)
3. rook-ceph-cluster/ - CephCluster, StorageClasses (needs Rook CRDs)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Change FluxCD git URL from git@ to gitea@ (Gitea uses 'gitea' user)
- Split Rook-Ceph into operator (infrastructure/) and cluster
(rook-ceph-cluster/) with FluxCD dependency ordering so CRDs exist
before CephCluster and StorageClass resources are applied
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>