infra/stacks/coturn/main.tf
Viktor Barzin 39b3c51709 migrate 16 plan-time stacks: vault data source → ESO + kubernetes_secret
Replaced data "vault_kv_secret_v2" with:
1. ExternalSecret (ESO syncs Vault KV → K8s Secret)
2. data "kubernetes_secret" (reads ESO-created secret at plan time)

This removes the Vault provider dependency at plan time for these
stacks — they now only need K8s API access, not a Vault token.

Stacks: actualbudget, affine, audiobookshelf, calibre, changedetection,
coturn, freedify, freshrss, grampsweb, navidrome, novelapp, ollama,
owntracks, real-estate-crawler, servarr, ytdlp
2026-03-15 22:06:39 +00:00

232 lines
5 KiB
HCL

variable "tls_secret_name" {
type = string
sensitive = true
}
variable "public_ip" { type = string }
resource "kubernetes_manifest" "external_secret" {
manifest = {
apiVersion = "external-secrets.io/v1beta1"
kind = "ExternalSecret"
metadata = {
name = "coturn-secrets"
namespace = "coturn"
}
spec = {
refreshInterval = "15m"
secretStoreRef = {
name = "vault-kv"
kind = "ClusterSecretStore"
}
target = {
name = "coturn-secrets"
}
dataFrom = [{
extract = {
key = "coturn"
}
}]
}
}
depends_on = [kubernetes_namespace.coturn]
}
data "kubernetes_secret" "eso_secrets" {
metadata {
name = "coturn-secrets"
namespace = kubernetes_namespace.coturn.metadata[0].name
}
depends_on = [kubernetes_manifest.external_secret]
}
locals {
turn_realm = "viktorbarzin.me"
turn_port = 3478
# Small relay range — 100 ports is plenty for a home lab (~50 concurrent streams)
min_port = 49152
max_port = 49252
}
resource "kubernetes_namespace" "coturn" {
metadata {
name = "coturn"
labels = {
tier = local.tiers.edge
}
}
}
module "tls_secret" {
source = "../../modules/kubernetes/setup_tls_secret"
namespace = kubernetes_namespace.coturn.metadata[0].name
tls_secret_name = var.tls_secret_name
}
resource "kubernetes_config_map" "coturn_config" {
metadata {
name = "coturn-config"
namespace = kubernetes_namespace.coturn.metadata[0].name
}
data = {
"turnserver.conf" = <<-EOF
# TURN server configuration
listening-port=${local.turn_port}
fingerprint
lt-cred-mech
use-auth-secret
static-auth-secret=${data.kubernetes_secret.eso_secrets.data["turn_secret"]}
realm=${local.turn_realm}
server-name=turn.${local.turn_realm}
# Network — use 0.0.0.0, coturn auto-detects pod IP
listening-ip=0.0.0.0
external-ip=${var.public_ip}
# Media relay port range (narrow — 100 ports)
min-port=${local.min_port}
max-port=${local.max_port}
# Logging
verbose
no-stdout-log
syslog
# Security
no-multicast-peers
no-cli
no-tlsv1
no-tlsv1_1
# Performance
total-quota=100
stale-nonce=600
max-bps=0
EOF
}
}
resource "kubernetes_deployment" "coturn" {
metadata {
name = "coturn"
namespace = kubernetes_namespace.coturn.metadata[0].name
labels = {
app = "coturn"
tier = local.tiers.edge
}
annotations = {
"reloader.stakater.com/auto" = "true"
}
}
spec {
replicas = 1
strategy {
type = "RollingUpdate"
rolling_update {
max_unavailable = 0
max_surge = 1
}
}
selector {
match_labels = {
app = "coturn"
}
}
template {
metadata {
labels = {
app = "coturn"
}
}
spec {
container {
name = "coturn"
image = "coturn/coturn:latest"
args = ["-c", "/etc/turnserver/turnserver.conf"]
# STUN/TURN signaling port
port {
name = "turn-udp"
container_port = local.turn_port
protocol = "UDP"
}
port {
name = "turn-tcp"
container_port = local.turn_port
protocol = "TCP"
}
volume_mount {
name = "config"
mount_path = "/etc/turnserver"
read_only = true
}
resources {
requests = {
cpu = "10m"
memory = "64Mi"
}
limits = {
memory = "64Mi"
}
}
}
volume {
name = "config"
config_map {
name = kubernetes_config_map.coturn_config.metadata[0].name
}
}
}
}
}
}
# LoadBalancer service with MetalLB — exposes STUN/TURN signaling + relay ports
resource "kubernetes_service" "coturn" {
metadata {
name = "coturn"
namespace = kubernetes_namespace.coturn.metadata[0].name
annotations = {
"metallb.universe.tf/loadBalancerIPs" = "10.0.20.200"
"metallb.universe.tf/allow-shared-ip" = "shared"
}
}
spec {
type = "LoadBalancer"
selector = {
app = "coturn"
}
# STUN/TURN signaling
port {
name = "turn-udp"
port = local.turn_port
target_port = local.turn_port
protocol = "UDP"
}
port {
name = "turn-tcp"
port = local.turn_port
target_port = local.turn_port
protocol = "TCP"
}
# Relay port range (49152-49252)
dynamic "port" {
for_each = range(local.min_port, local.max_port + 1)
content {
name = "relay-${port.value}"
port = port.value
target_port = port.value
protocol = "UDP"
}
}
}
}