talos-platform/main.tf
root a6e68e6ec6
Some checks failed
Talos Platform Deploy / deploy (push) Failing after 1m27s
last
2026-11-13 16:46:13 +01:00

200 lines
5.2 KiB
HCL
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# talos-platform – gemeinsame Cluster-Dienste für Produktion (Talos)
# Hier liegt alles, was ALLE Apps brauchen. Apps (boday_tf, ...) bringen nur ihr eigenes Chart mit.
terraform {
required_providers {
kubernetes = {
source = "hashicorp/kubernetes"
version = "~> 2.26"
}
helm = {
source = "hashicorp/helm"
version = "~> 2.12"
}
}
backend "consul" {
address = "consul:8500"
path = "terraform/states/talos_platform"
}
}
variable "kubeconfig_path" {
type = string
default = "./talos_kubeconfig"
}
# Version des Traefik-Helm-Charts (traefik/traefik). Bewusst pinnen, damit Updates geplant passieren.
variable "traefik_chart_version" {
type = string
}
provider "kubernetes" {
config_path = var.kubeconfig_path
}
provider "helm" {
kubernetes {
config_path = var.kubeconfig_path
}
}
# Feste IP für Traefik aus dem MetalLB-Pool. Auf diese IP zeigt das OPNsense-Portforwarding (80/443).
variable "traefik_lb_ip" {
type = string
}
# Hostname des Longhorn-Dashboards (internes DNS, z.B. Unbound-Override in OPNsense)
variable "longhorn_host" {
type = string
default = "longhorn.boday.lan"
}
# BasicAuth für Longhorn als htpasswd-Zeile, z.B.: htpasswd -nbB admin 'geheim'
variable "longhorn_basic_auth" {
type = string
sensitive = true
}
# --- TLS: cert-manager + Let's Encrypt -------------------------------------
# Version des cert-manager-Helm-Charts (jetstack/cert-manager), bewusst gepinnt
variable "cert_manager_chart_version" {
type = string
}
# Kontakt-E-Mail für Let's Encrypt (Ablauf-Warnungen)
variable "acme_email" {
type = string
}
resource "helm_release" "cert_manager" {
name = "cert-manager"
repository = "https://charts.jetstack.io"
chart = "cert-manager"
version = var.cert_manager_chart_version
namespace = "cert-manager"
create_namespace = true
timeout = 600
atomic = true
values = [yamlencode({
crds = { enabled = true }
})]
}
# Eigener kleiner Chart, damit Terraform beim Plan die cert-manager-CRDs noch nicht kennen muss
resource "helm_release" "cluster_issuer" {
name = "cluster-issuer"
chart = "${path.module}/charts/cluster-issuer"
namespace = "cert-manager"
set {
name = "email"
value = var.acme_email
}
depends_on = [helm_release.cert_manager]
}
# Kein hostPort mehr -> der Talos-Standard (PSA "baseline") reicht
resource "kubernetes_namespace" "traefik" {
metadata {
name = "traefik"
}
}
# Traefik hinter einem MetalLB-LoadBalancer: VIP wandert bei Node-Ausfall auf den anderen Node
resource "helm_release" "traefik" {
name = "traefik"
repository = "https://traefik.github.io/charts"
chart = "traefik"
version = var.traefik_chart_version
namespace = kubernetes_namespace.traefik.metadata[0].name
timeout = 600
atomic = true
values = [yamlencode({
deployment = { replicas = 2 }
# Möglichst je ein Pod pro Node (weich: bei nur einem Worker laufen beide dort)
topologySpreadConstraints = [{
maxSkew = 1
topologyKey = "kubernetes.io/hostname"
whenUnsatisfiable = "ScheduleAnyway"
labelSelector = {
matchLabels = {
"app.kubernetes.io/name" = "traefik"
"app.kubernetes.io/instance" = "traefik-traefik"
}
}
}]
service = {
type = "LoadBalancer"
annotations = {
"metallb.io/loadBalancerIPs" = var.traefik_lb_ip
}
spec = {
# Echte Client-IP bleibt erhalten (Django-Logs, CrowdSec)
externalTrafficPolicy = "Local"
}
}
ingressClass = {
enabled = true
isDefaultClass = true
name = "traefik"
}
providers = {
kubernetesIngress = { enabled = true }
kubernetesCRD = { enabled = true }
}
# Gemeinsame Routen der Plattform: Longhorn-Dashboard mit Login hinter Traefik
extraObjects = [
{
apiVersion = "v1"
kind = "Secret"
metadata = { name = "longhorn-basic-auth", namespace = "longhorn-system" }
type = "Opaque"
stringData = { users = var.longhorn_basic_auth }
},
{
apiVersion = "traefik.io/v1alpha1"
kind = "Middleware"
metadata = { name = "longhorn-auth", namespace = "longhorn-system" }
spec = { basicAuth = { secret = "longhorn-basic-auth" } }
},
{
apiVersion = "networking.k8s.io/v1"
kind = "Ingress"
metadata = {
name = "longhorn"
namespace = "longhorn-system"
annotations = {
"traefik.ingress.kubernetes.io/router.middlewares" = "longhorn-system-longhorn-auth@kubernetescrd"
}
}
spec = {
ingressClassName = "traefik"
rules = [{
host = var.longhorn_host
http = {
paths = [{
path = "/"
pathType = "Prefix"
backend = { service = { name = "longhorn-frontend", port = { number = 80 } } }
}]
}
}]
}
},
]
})]
}
output "traefik_lb_ip" {
value = var.traefik_lb_ip
}