Skip to content

v3.0.0

Latest

Choose a tag to compare

@github-actions github-actions released this 06 Jul 20:51
fdec703

⚠️ v3.0.0 Upgrade Notes

This is the v3 major-release line. Before upgrading from any v2.x release:

  1. Pin and review:
    • Set module version to 3.0.0 (or your targeted v3 tag).
    • Read docs/v2-to-v3-migration.md and MIGRATION.md end-to-end.
    • Fastest path: with Claude Code or a compatible agent, run the /migrate-v2-to-v3 agent skill from a checkout of this repo — it applies the variable rename map, runs the protected-infrastructure plan gate, and reviews the upgrade plan with you (see the README section "AI-assisted migration").
  2. Run safe upgrade flow:
    • terraform init -upgrade
    • terraform plan
    • Apply only after reviewing all resource actions.
  3. If you use private-network NAT routers created before v2.19.0, check for primary IP replacement and perform state migration first (see migration notes).
  4. Networking behavior changed in v3: nodepool network_id is active and control-plane attachment behavior is explicit. Cilium public overlay remains an experimental preview gated by enable_experimental_cilium_public_overlay until live cross-network datapath validation passes. Prefer blue/green migration for custom/private/Robot/multinetwork topologies; do not apply plans that unexpectedly destroy or recreate network subnets.
  5. New clusters and normal in-place v2 upgrades use network_subnet_mode = "per_nodepool", matching the released v2 subnet topology. Optional network_subnet_mode = "shared" is for new clusters or intentional topology changes only.
  6. Several public inputs were renamed or removed in v3 to clean up the module contract. See MIGRATION.md for the old-to-new variable map, especially the inverted positive booleans (enable_hetzner_csi, enable_placement_groups, allow_inbound_icmp, enable_kube_proxy, enable_network_policy, enable_selinux, nodepool enable_public_ipv4/enable_public_ipv6, autoscaler public-IP flags, and load-balancer enable flags).
  7. The v2 k3s_channel default was v1.33; v3 defaults to the upstream stable channel while automatic Kubernetes upgrades still default on. Before the first v3 apply, either pin k3s_version, set k3s_channel = "v1.33" to keep the v2 minor channel intentionally, or consciously accept following stable.
  8. Addon version defaults are deterministic in v3. Unset addon version variables now use a reviewed module matrix instead of upstream latest/floating behavior; set latest to keep fetching upstream latest releases or following latest Helm charts intentionally.

Version Requirements

  • Minimum Terraform/OpenTofu version: 1.10.1
  • Minimum hcloud provider version: 1.62.0

💥 Breaking Changes

  • Public input cleanup - Renamed Kubernetes distribution, install, audit, load-balancer, Robot, CCM, WireGuard, firewall, placement group, public-IP, kube-proxy, SELinux, and storage inputs to a consistent v3 contract. Removed obsolete inputs such as enable_iscsid, extra_kustomize_*, autoscaler_labels, autoscaler_taints, and the old CCM deployment-mode switch. See MIGRATION.md.
  • Hetzner CCM HelmChart only - Removed the legacy raw-manifest Hetzner CCM path. v3 always renders the CCM HelmChart manifest and removes old non-Helm CCM objects during addon reconciliation.
  • Existing Network shape - Replaced existing_network_id with existing_network = { id = 1234567 }; network_id = 0 is no longer a valid user value, and omitted/null network_id means the primary kube-hetzner Network.
  • Nodepool network behavior - Agent and autoscaler network_id values are now active. Control planes stay on the primary Network and do not accept network_id.
  • Subnet allocation modes - New v3 clusters and normal in-place v2 upgrades use network_subnet_mode = "per_nodepool", matching the released v2 subnet topology. Added optional network_subnet_mode = "shared" for compact new-cluster layouts that intentionally use one shared agent subnet and one shared control-plane subnet.
  • Minimum tool versions - Terraform/OpenTofu >= 1.10.1 and hcloud provider >= 1.62.0 are required.
  • Default/architecture changes - New nodes default to Leap Micro, architecture selection is consolidated into enabled_architectures, and default behavior moved to explicit positive booleans.

🚀 New Features

  • Declarative Node Annotations - Added create-only Kubernetes Node annotations on control-plane, agent, per-node agent/control-plane overrides, and autoscaler nodepools. Non-empty maps render a node-local cloud-init systemd oneshot that waits for k3s/RKE2, uses the node kubelet kubeconfig, and patches only its own Node; empty maps render no unit or payload, preserving existing cluster user-data. This covers Longhorn default-disk bootstrap annotations and autoscaler-created nodes without adding an ongoing reconciler (#2198, requested by @clemlesne).
  • Optional Upgrade Tooling Deployment - Added enable_kured and enable_system_upgrade_controller toggles for clusters that manage reboot orchestration or system-upgrade-controller externally. Disabling these flags omits the resources from future kustomization applies but does not prune already-deployed kured/system-upgrade-controller objects from existing clusters; remove those manually if needed. The k3s and RKE2 kustomization trigger state includes these toggles and the rendered addon payload, so future toggle flips rerun the relevant provisioners (#2223).
  • Per-Set User Kustomization Apply Flags - Added user_kustomizations[*].apply_options for passing validated kubectl apply flags such as server-side apply to individual ordered user kustomization sets (#2218).
  • Raw kube-apiserver Args Passthrough - Added kube_apiserver_args (list of strings, default []) to append arbitrary apiserver flags to the control-plane config.yaml kube-apiserver-arg (e.g. service-account-issuer / service-account-jwks-uri for OIDC workload identity) for options without a dedicated module variable. Applied in-place via the existing config-update provisioner (k3s/rke2 service restart, no control-plane node recreation); entries must omit the leading --, enforced by input validation.
  • Leap Micro Support (Stable Default OS) - Added os selector for control plane, agent, and autoscaler nodepools (plus per-node agent overrides). New nodepools default to leapmicro; existing nodepools remain on MicroOS by default on upgrade to avoid recreation. New variables: leapmicro_x86_snapshot_id, leapmicro_arm_snapshot_id. Added packer template packer-template/hcloud-leapmicro-snapshots.pkr.hcl and automatic OS detection via the kube-hetzner/os server label.
  • Agent Floating IP Family Selection - Added floating_ip_type (ipv4/ipv6) to agent nodepools and node overrides, including IPv6-aware NetworkManager reconfiguration logic.
  • Cilium Egress Gateway HA Reconciler - New cilium_egress_gateway_ha_enabled option to deploy a lightweight controller that keeps labeled CiliumEgressGatewayPolicy objects pinned to a Ready egress node.
  • Cilium v3 Dual-Stack Defaults - Cilium now renders IPv4/IPv6 Helm values from the configured cluster CIDRs and keeps kube-proxy replacement tied to enable_kube_proxy = false (#2170, #2178).
  • Cilium Gateway API Support - Added cilium_gateway_api_enabled to install standard Gateway API CRDs for the selected Cilium line, enable Cilium gatewayAPI.enabled, and wire cert-manager Gateway API support. Added examples/cilium-gateway-api.
  • Cilium Multinetwork Public Overlay Preview - Added gated multinetwork_mode = "cilium_public_overlay" plumbing for Cilium-only clusters spanning multiple Hetzner Networks, including public IPv4/IPv6/dual-stack transport selection, WireGuard/tunnel defaults, public load-balancer targeting, control-plane fanout removal, and one Cluster Autoscaler Deployment per effective network_id. This path now requires enable_experimental_cilium_public_overlay = true and is not production-supported until the live datapath E2E passes.
  • Tailscale Node Transport - Added opt-in node_transport_mode = "tailscale" for secure single-network clusters and supported private multinetwork scale-out. The module can bootstrap Tailscale, use MagicDNS for Terraform/kubeconfig access, optionally advertise each node's Hetzner private /32 route with subnet-route SNAT disabled, keep Kubernetes node IPs on Hetzner private addresses, validate Tailnet/firewall/CNI/load-balancer constraints at plan time with explicit nodepool network_scope, and render autoscaler nodes with per-Network Tailscale bootstrap. Flannel is the first supported CNI; Cilium remains gated as experimental for this transport until live datapath coverage promotes it.
  • Embedded Registry Mirror - Added embedded_registry_mirror for trusted large clusters, enabling k3s/RKE2's embedded Spegel mirror while preserving user registries_config entries.
  • Placement Group Auto-Sharding - Count-based nodepools without an explicit placement_group now shard implicit Hetzner spread placement groups every 10 servers; explicit placement groups still fail validation above Hetzner's 10-server limit.
  • Large-Scale Tailscale Examples - Added +100-node and 10,000-total-node Tailscale node-transport reference examples that account for Hetzner Network attachment limits, placement-group limits, autoscaler shards, and the public-IP/Tailnet exposure model.
  • Endpoint Introspection Outputs - Added outputs for the effective kubeconfig API endpoint, node join endpoint, node transport mode, and Tailscale MagicDNS hostnames.
  • v3 Topology Recommendations - Added docs/v3-topology-recommendations.md covering the recommended dev, HA, NAT, Tailscale, +100 node, 10k reference, RKE2, Cilium dual-stack, Gateway API, Robot/vSwitch, and registry mirror shapes.
  • Multiple Attached Volumes Per Node - Added attached_volumes support for control plane and agent nodepools (including per-node overrides) to provision and mount multiple Hetzner Volumes per node.
  • NAT Router Customization - Added NAT-router extra_runcmd and use_private_nat_router_bastion support for private-network bastion hardening (#2165, #2166).
  • External Overlay Access Hooks - Added and documented the provider-agnostic node_connection_overrides pattern for Tailscale, ZeroTier, Cloudflare WARP, and similar overlays. Use this for user-owned operator access or post-bootstrap overlay features; use node_transport_mode = "tailscale" when Tailscale should be the official Kubernetes node transport.
  • Per-Nodepool Snapshot Overrides - Added os_snapshot_id overrides to control-plane and agent nodepools and node overrides (#2158).
  • Plan-Time Configuration Guardrails - Added Terraform/OpenTofu cross-variable validation for architecture toggles, network regions/CIDRs, nodepool topology, load balancers, autoscaler settings, CCM/Robot, Cilium-only features, firewall sources, and multi-volume attachments so invalid combinations fail during terraform plan.
  • Robot vSwitch Route Exposure Control - Added expose_routes_to_vswitch to manage Hetzner Cloud route exposure to coupled Robot vSwitches when kube-hetzner creates the primary Network.
  • v2-to-v3 Migration Assistant - Added a read-only audit script, project skill, and migration playbook for guided v2 configuration rewrites, plan review, and state-safety checks.
  • OpenTofu Support - Documented OpenTofu as a supported engine and expanded Hetzner CI presets to run both Terraform and OpenTofu apply/health/destroy paths.

🐛 Bug Fixes

  • Shell-Safe User Input Hardening - SSH keys, Kubernetes install environment values, install exec/version inputs, Cluster Autoscaler extra args, and user kustomization template filenames are now validated or YAML-encoded before root bootstrap/rendering. Unsafe quotes, newlines, shell metacharacters, YAML syntax, and path traversal in those inputs are intentionally rejected.
  • Kubeconfig Structural Rename Safety - Rewrote generated kubeconfig endpoint and identity renames through parsed YAML so certificate blobs and other fields containing default are no longer mutated by global string replacement.
  • Ingress Load Balancer Destroy Cleanup - Added fail-open destroy-time cleanup for module-managed ingress LoadBalancer Services across k3s and RKE2 so Hetzner CCM removes the adopted ingress load balancer before Terraform tears down nodes and network attachments. Found by the v3 live gate after a surviving nginx LB blocked network/subnet destroy.
  • Ingress Load Balancer Destroy Retry - CI now retries terraform destroy once to absorb the known already-detaching race between Hetzner CCM deleting an adopted ingress LoadBalancer and Terraform detaching the same LB network attachment; plan 011 tracks the longer-term single-ownership design.
  • Ingress Hook Bootstrap Scheduling - Added hook-scoped bootstrap tolerations to ingress-nginx admission patch jobs and the HAProxy CRD hook so managed ingress Helm installs can finish when v3 bootstraps kustomizations before agent nodes join. Controller Deployments intentionally keep their existing scheduling semantics. Found by the live CI gate via the nginx admission hook deadlock.
  • Ingress Load Balancer Annotation Rendering - Fixed ingress-nginx, Traefik, and HAProxy Helm values templates so Hetzner Load Balancer adoption annotations stay nested at the chart-specific Service annotation path instead of being stripped to the values document root by Terraform template trim markers. Found by the v3 CI gate, with a new plan-time semantic contract for the rendered values.
  • NAT Router Reconciliation Safety - Reworked the NAT router reconcile provisioner so fresh v3 routers no longer write script text into sshd_config.d/kube-hetzner.conf through unterminated nested heredocs, preventing sshd from failing and permanently cutting off the router. Found by the v3 live gate.
  • Size-Aware Control-Plane Kubelet Reservations - Control-plane nodepools that still use the legacy kubelet reservation default now compute kube-reserved memory from the selected Hetzner server type, preventing small RKE2 control planes such as cx23 from rejecting scheduler static pods during bootstrap. Added an RKE2 validation guardrail for parseable reservations above 50% of server RAM. Credits the live-gate finding from fresh v3 RKE2 cluster validation.
  • SSH Authorized Keys Upgrade Safety - Host SSH reconciliation now preserves out-of-band root authorized keys by default while revoking module-managed keys removed from ssh_public_key or ssh_additional_public_keys. Set ssh_authorized_keys_exclusive = true for strict replacement with only module-managed keys.
  • NAT Router Failover Peer Scoping - NAT routers now carry the standard cluster identity labels and redundant failover peer discovery filters by role=nat_router,cluster=<cluster_name>, preventing foreign NAT routers in the same Hetzner project from being selected.
  • Agent Bootstrap Ordering - Ordered agents after k3s/RKE2 kustomization bootstrap, moved post-install readiness waits after agent join, and kept observable agent start failures for default multi-node clusters (#2215, #2220, #2221).
  • Control Plane LB Health Check - Kept the control-plane load balancer health check on HTTP protocol with TLS enabled for the Kubernetes /readyz endpoint, avoiding invalid Hetzner https protocol validation failures (#2188, #2199, #2200, #2205).
  • Autoscaler Large Configs and DRA RBAC - Cluster Autoscaler now reads the generated Hetzner cluster config from a Secret-backed file, uses server-side apply for its manifest, and has read-only RBAC for Kubernetes Dynamic Resource Allocation resources (#2194, #2195, #2202).
  • Kured on Tainted Nodes - Added a universal toleration to Kured so OS reboot management still runs on tainted nodes (#2196).
  • Subnet Validation Contract - Kept NAT router and vSwitch subnet-index upper bounds conditional on those features being enabled, preserving small subnet_count validation compatibility while still failing invalid enabled configurations (#2197).
  • External Manifest Fetch Resilience - Added retry blocks to GitHub and public-IP HTTP data sources so transient TLS handshake timeouts do not fail plans, applies, or destroys.
  • Autoscaler CA Root Loading - Removed the /etc/ssl/certs hostPath mount from Cluster Autoscaler so RKE2/Leap Micro clusters use the image's bundled CA roots instead of hitting host certificate directory permission failures.
  • Terraform 1.15 Validation Compatibility - Moved cross-variable and local-dependent module contract checks from input-variable validation blocks into a hard terraform_data.validation_contract precondition surface, preserving plan-time failures while allowing Terraform 1.15.0 to initialize and validate the module.
  • Tailscale Volume Provisioning Ordering - Agent Longhorn and attached-volume configuration now waits for Tailscale agent bootstrap before using Tailnet MagicDNS SSH targets.
  • Tailscale Auth-Key Ergonomics - auth_key mode no longer advertises kube-hetzner tags by default, so simple pre-auth keys work without Tailnet tagOwners; tagged nodes remain an explicit opt-in and OAuth mode now validates that tag-scoped auth is configured.
  • Tailscale Single-Network Ergonomics - Tailscale mode now cleanly supports ordinary single-network clusters: node-private route advertisement can be disabled when no network_scope = "external" nodepools are used, private control-plane Load Balancers are allowed, and private managed ingress Load Balancers are rejected only for external-network scale-out.
  • Tailscale Same-Root Network Validation - Tailscale static agent and autoscaler nodepools now use explicit network_scope = "primary" | "external" intent, so invalid same-root external Network configurations fail during terraform plan even when network_id is not known until apply.
  • Placement Group Disable/Limit Semantics - enable_placement_groups = false now stops creating unused placement-group resources, and plan-time validation enforces Hetzner's 50-placement-group project limit before large static topologies hit provider errors.
  • Same-Root Tailscale External Networks - In Tailscale transport mode, nodepool network_id values can come from Hetzner Network resources created in the same Terraform root because control planes no longer need apply-time fanout attachments to every external agent Network.
  • Cloud-Init Health-Checker Race - Host and autoscaler cloud-init now masks Leap Micro/MicroOS health-checker.service before cloud-final to prevent a systemd ordering-cycle race that can skip first-boot Kubernetes bootstrap on autoscaled nodes.
  • Cilium Multinetwork Bootstrap - Public-overlay clusters now allow restricted outbound Kubernetes API traffic and keep Hetzner CCM network-aware while route reconciliation stays disabled, so control planes can remain on their private node identity and external-network agents can join over the public overlay.
  • Cilium Default Bootstrap - Cilium now enables eBPF masquerading only when kube-proxy replacement is enabled, matching Cilium's BPF NodePort dependency and preventing default Cilium clusters from CrashLooping on startup.
  • Interface Rename Self-Heal - Added a boot-time kh-rename-interface.service and stale udev MAC refresh so private NIC renames survive MAC changes and reboots (#2182).
  • User Kustomization Redeploys - User kustomization uploads and deploys now rerun after first control-plane replacement (#2160).
  • Custom Ingress Mode - ingress_controller = "custom" now skips managed ingress Service lookup/wait logic (#2173).
  • Autoscaler Without Public IPv4 - Autoscaler cloud-init now routes IPv4 through the private gateway when public IPv4 is disabled, while keeping public IPv6 routing when enabled (#2154).
  • Hetzner CCM Dual-Stack Address Family - Hetzner CCM now keeps route reconciliation on the IPv4 pod CIDR and sets HCLOUD_INSTANCES_ADDRESS_FAMILY for IPv6/dual-stack clusters (#2170).
  • Cilium Egress Gateway Validation - Enforces enable_kube_proxy = false when Cilium Egress Gateway is enabled, matching Cilium's kube-proxy replacement requirement (#2178).
  • Cilium Egress Gateway HA Reconciler - Treats CiliumEgressGatewayPolicy as cluster-scoped when retargeting labeled policies (#2178).
  • Upgrade-Safe Ingress Namespace Defaults - Restored legacy nginx default namespace (nginx) to avoid Helm ownership conflicts during upgrades from v2.19.x clusters.
  • CCM Ownership Compatibility - Keeps Hetzner CCM on the existing HelmChart manifest flow, avoiding release-name collisions with already-installed CCM chart instances.
  • CCM Helm Migration Cleanup - v3 now removes the full legacy non-Helm Hetzner CCM RBAC surface before installing the Helm-managed CCM, while preserving Helm-owned CCM resources on later applies.
  • Upgrade-Safe Hetzner SSH Key State - Preserves the v2-managed hcloud_ssh_key.k3s resource during v3 upgrades instead of auto-adopting the same key through a data source and planning key deletion.
  • Addon Manifest Fetch Stability - Terraform now fetches kured and system-upgrade-controller release manifests and uploads them as local kustomize resources, avoiding control-plane kustomize failures on GitHub release-asset URLs.
  • Subnet Topology Compatibility - Restored per-nodepool control-plane/agent subnet resources and nodepool subnet attachment while keeping auto-assigned private IPv4 behavior.
  • RKE2 SELinux Apply Parity - Wired RKE2 server/agent install flows to apply the rke2-selinux policy module when available and added safe post-install restorecon relabeling for RKE2 binaries.
  • LeapMicro SELinux Snapshot Matrix (k3s/rke2 x x86/arm) - LeapMicro packer now builds distro-specific SELinux snapshots (selinux_package_to_install), labels snapshots with kube-hetzner/k8s-distro and architecture, and auto-selection now matches kubernetes_distribution to prevent k3s/rke2 SELinux RPM conflicts.
  • MicroOS Packer SELinux Scope - Removed rke2-selinux preinstall from the MicroOS packer template; it now only preinstalls and locks k3s-selinux.
  • LeapMicro SELinux Policy De-duplication - Moved k8s_custom_policies into a shared template consumed by both host and autoscaler cloud-init paths to prevent policy drift.
  • RKE2 SELinux Enforcing Guardrail - Added an explicit enforcing-mode validation that fails provisioning if the rke2 SELinux module is still not loaded.
  • Longhorn iSCSI SELinux Capability - Added iscsid_t dac_override permission to the shared kube-hetzner SELinux module.
  • RKE2 TLS SAN Endpoint Parity - control_plane_config_rke2 now includes local.kubeconfig_server_address in tls-san, preserving SAN coverage for NAT-router/private-LB kubeconfig endpoints.
  • Hetzner CI LeapMicro Snapshot Gate - Hetzner test prerequisites now accept LeapMicro snapshot secrets (with MicroOS fallback) instead of requiring MicroOS-only secrets.
  • Autoscaler Nodepool Parity/Validation - Added autoscaler nodepool validation guards (unique names, integer min/max bounds, taint effect and swap/zram format checks) and aligned RKE2 autoscaled node labeling/taint rendering with the k3s autoscaler path.
  • RKE2 User Kustomizations - Switched user kustomization apply path to distribution-aware kubectl_cli, fixing apply failures in RKE2 clusters.
  • extra_network_ids Attachment - Wired extra_network_ids into host provisioning so additional Hetzner networks are actually attached to control-plane and agent nodes.
  • Connection Override Consistency - Unified control-plane and agent node_connection_overrides resolution so provisioning and follow-up operations honor the same override key strategy (including suffixed node names).
  • RKE2 TLS SAN Parity (No LB) - Added kubeconfig/control-plane advertised endpoints to RKE2 non-LB TLS SAN generation to prevent certificate mismatch on custom kubeconfig server addresses.
  • Control Plane Bootstrap Config Files - First-node k3s/RKE2 bootstrap now installs authentication and audit policy config files before starting the API server when the matching API-server args are enabled.
  • RKE2 First Bootstrap Parity - RKE2 first bootstrap now respects enable_selinux and uses the effective kubeconfig/control-plane endpoints in its initial tls-san list, matching steady-state config.
  • Attached Volume Mount Safety - Attached control-plane and agent volumes now rerun mount configuration on size changes, resize XFS via mount path, and persist fstab entries by filesystem UUID instead of mutable device paths.
  • K3s Channel Guardrail - Default k3s_channel now uses the live stable channel, and plan-time validation rejects minor live channels except the explicit v1.33 v2-preservation path unless an exact k3s_version/rke2_version is set, avoiding broken upstream minor-channel installer resolution.
  • API Port Consistency - k3s first bootstrap now honors kubernetes_api_port, the control-plane LB health check/backend follows the configured listener port, IPv6 kubeconfig endpoints are bracketed correctly, and RKE2 now rejects unsupported non-6443 API port settings.
  • RKE2 Apply Parity - RKE2 kustomization triggers now include CCM values and system-upgrade drain/eviction/window settings, readiness waits evaluate dynamically, deployment/job waits match k3s, and RKE2 secret deployment uses the shared file-based secret path instead of shell argv literals.
  • Node Route Robustness - Host cloud-init now handles public-IPv6-only nodes by routing IPv4 through the private gateway while preserving public IPv6 routing, matching autoscaler behavior.
  • Leap Micro First-Boot Readiness - Host provisioning now resets and tolerates the known non-critical transactional-update.service first-boot failure while still blocking on other failed systemd units.
  • Upgrade-Safe Detection/Provisioning - Existing hyphenated nodepool names without random suffixes are detected correctly for OS defaults, NAT routers no longer recreate for image/user-data drift, and RKE2 autoscaler SSH keys use the normalized authorized-key list.
  • RKE2 Replacement/Reapply Safety - RKE2 first-node bootstrap now retriggers on first control-plane replacement, and RKE2 addon application hashes the rendered kustomization payload so template/resource toggles are reapplied.
  • Per-Network Route/Floating IP Detection - Install-time private-route repair and floating IP public-NIC detection now use each node's actual private network CIDR/gateway instead of the primary cluster network.
  • NAT Router Config Reconciliation - Existing NAT routers now reconcile cloud-init-owned SSH, DNS, iptables, and keepalived config through Terraform provisioners while connection-critical SSH/user/key changes force router replacement.
  • Hetzner CI Presets - CI preset tests now use a compact local-checkout fixture, sanitize preset-derived cluster names, and cover Terraform apply, Kubernetes health checks, and Terraform destroy for default, nginx, and RKE2 presets.
  • RKE2 Registry Bootstrap - Initial cloud-init now writes registries_config to /etc/rancher/rke2/registries.yaml for RKE2 clusters instead of the k3s path, so custom registries are available before first RKE2 start.

🔧 Changes

  • SSH Port Validation - Tightened ssh_port input validation so port 0 and fractional values fail early.

  • SMB CSI Chart Pinning - Pinned the csi_driver_smb_version default to reviewed chart 1.20.3 while preserving "*" as an explicit floating opt-in, and removed the unused NFS CSI template scaffold.

  • 🔧 Disabled Addon Fetch Gating - enable_kured = false and enable_system_upgrade_controller = false now skip the corresponding GitHub release/manifest HTTP data sources entirely; disabled clusters may see one idempotent kustomization re-run as addon trigger state normalizes disabled remote manifest inputs to empty strings.

  • Sensitive Kustomization Backup - The generated kustomization backup now uses Terraform's sensitive local-file resource so Rancher registration manifest URLs are treated as sensitive on disk; rotate any Rancher registration token that may have been written by an earlier backup.

  • Hetzner CI Orphan Sweeper - Added a scheduled/manual sweeper for stale kh-ci-* Hetzner CI resources. It skips active Hetzner test runs, defaults to dry-run, and requires prefix-anchored names plus age gates before deletion.

  • Render Harness CI Gate - Added a hermetic rendered-template harness and negative validation-contract plan fixture so Helm values, ingress LB annotations, cloud-init YAML, shell templates, and key v3 validation preconditions are checked before live cluster gates.

  • Explicit Provider Constraints - Pinned the previously implicit Kubernetes, Helm, Random, and CloudInit provider requirements and expanded CI validation across Terraform 1.10.5, 1.14.9, 1.15.0, and OpenTofu 1.11.6.

  • iSCSI Daemon Defaults - iscsid is now enabled on all nodes by default, and the enable_iscsid input was removed.

  • Cilium Default Version - Updated the default Cilium version to 1.19.3 so v3 defaults align with the current Gateway API-supported Cilium line.

  • Gateway API CRD Version Override - Restored the gateway_api_version input for users who need to pin the standard Gateway API CRD bundle independently of cilium_version, matching the v2 pinning capability. The default empty value keeps v3's Cilium-derived CRD version behavior.

  • Primary IP Provider Cleanup - Removed now-unused assignee_type = "server" attributes from hcloud Primary IP resources and raised the hcloud provider minimum to 1.62.0.

  • Cloudflare Zero Trust Support Boundary - Documented Cloudflare Access/Tunnel as a user-managed external access pattern for kube API, SSH, Rancher, and ingress, while explicitly keeping Cloudflare Mesh/WARP out of the v3 node-transport support contract. Use Tailscale for supported secure node transport.

  • Release Attribution Robustness - Release workflow now maps commits to associated PR authors (including squash merges) when generating contributor credits, so original implementers are preserved.

  • v3 Migration Skill Update - Updated the repo-local migrate-v2-to-v3 agent skill with live-upgrade lessons, the destroy retry caveat, and the final Tailscale support wording.



👥 Contributors

Thanks to all contributors who made this release possible:

Attribution includes pull request authors mapped from commits, so squashed PR implementers are credited.

Pull Request Authors

Full Contributor List

What's Changed

📚 Documentation

  • [AUTO] Update Terraform Documentation by @github-actions[bot] in #2057
  • [AUTO] Update Terraform Documentation by @github-actions[bot] in #2061
  • [AUTO] Update Terraform Documentation by @github-actions[bot] in #2064
  • [AUTO] Update Terraform Documentation by @github-actions[bot] in #2065
  • [AUTO] Update Terraform Documentation by @github-actions[bot] in #2072
  • [AUTO] Update Terraform Documentation by @github-actions[bot] in #2142
  • [AUTO] Update Terraform Documentation by @github-actions[bot] in #2143
  • [AUTO] Update Terraform Documentation by @github-actions[bot] in #2144
  • [AUTO] Update Terraform Documentation by @github-actions[bot] in #2145
  • [AUTO] Update Terraform Documentation by @github-actions[bot] in #2146
  • [AUTO] Update Terraform Documentation by @github-actions[bot] in #2148
  • [AUTO] Update Terraform Documentation by @github-actions[bot] in #2149
  • [AUTO] Update Terraform Documentation by @github-actions[bot] in #2150

Other Changes

New Contributors

Full Changelog: v2.21.0...v3.0.0