locals { m3uproxy_path = "/var/lib/m3uproxy" m3uproxy_cache_path = "${local.m3uproxy_path}/cache" squid_app_path = "${local.m3uproxy_path}/squid" wireguard_address = "192.168.5.3/32" wireguard_dns = "192.168.5.1" wireguard_allowed_ips = [ "192.168.5.1/32", "192.168.5.3/32", "0.0.0.0/0" ] wireguard_endpoint = "188.82.170.183" wireguard_endpoint_port = 1195 m3uproxy_config = templatefile("${path.module}/resources/m3uproxy/m3uproxy.json", { m3uproxy_secret = var.m3uproxy_secret }) } resource "kubernetes_namespace" "m3uproxy" { metadata { annotations = { name = "m3uproxy" } labels = { name = "m3uproxy" } name = "m3uproxy" } } resource "kubernetes_secret" "m3uproxy_admin_credentials" { metadata { name = "m3uproxy-credentials" namespace = kubernetes_namespace.m3uproxy.metadata[0].name } data = { username = "tv_admin" password = var.m3uproxy_admin_password } type = "Opaque" } resource "kubernetes_service_account" "m3uproxy_service_account" { metadata { name = "m3uproxy-app-sa" namespace = kubernetes_namespace.m3uproxy.metadata[0].name } automount_service_account_token = false } resource "kubernetes_config_map" "wireguard_config" { metadata { name = "wireguard-config" namespace = kubernetes_namespace.m3uproxy.metadata[0].name } data = { "wireguard.conf" = templatefile("${path.module}/resources/wireguard/wireguard.conf.tpl", { wireguard_private_key = var.wireguard_private_key wireguard_public_key = var.wireguard_public_key wireguard_address = local.wireguard_address wireguard_dns = local.wireguard_dns wireguard_allowed_ips = join(", ", local.wireguard_allowed_ips) wireguard_endpoint = "${local.wireguard_endpoint}:${local.wireguard_endpoint_port}" }) } } resource "kubernetes_config_map" "squid_config" { metadata { name = "squid-config" namespace = kubernetes_namespace.m3uproxy.metadata[0].name } data = { "squid.conf" = file("${path.module}/resources/squid/squid.conf") } } resource "kubernetes_config_map" "m3uproxy_config" { metadata { name = "m3uproxy-config" namespace = kubernetes_namespace.m3uproxy.metadata[0].name } data = { "m3uproxy.json" = local.m3uproxy_config "playlist.json" = file("${path.module}/resources/m3uproxy/playlist.json") } } resource "kubernetes_deployment" "proxy_pt" { metadata { name = "proxy-pt" namespace = kubernetes_namespace.m3uproxy.metadata[0].name annotations = { "security.alpha.kubernetes.io/unsafe-sysctls" = "net.ipv4.conf.all.src_valid_mark=1" } } spec { replicas = 1 selector { match_labels = { app = "proxy-pt" } } strategy { type = "Recreate" } template { metadata { labels = { app = "proxy-pt" } } spec { container { name = "wireguard" image = "linuxserver/wireguard:${local.wireguard_version}" resources { requests = { memory = "64Mi" } } liveness_probe { exec { command = [ "/bin/sh", "-c", "wg show | grep -q transfer" ] } initial_delay_seconds = 90 period_seconds = 90 } security_context { privileged = true capabilities { add = ["NET_ADMIN"] } } env { name = "PUID" value = "1000" } env { name = "PGID" value = "1000" } env { name = "TZ" value = "Europe/Berlin" } volume_mount { name = "wireguard-config" mount_path = "/config/wg_confs" read_only = true } volume_mount { name = "lib-modules" mount_path = "/lib/modules" read_only = true } } container { name = "squid" image = "ubuntu/squid:edge" port { container_port = 3128 name = "proxy" protocol = "TCP" } volume_mount { name = "squid-config" mount_path = "/etc/squid" read_only = true } volume_mount { name = "squid-data" mount_path = "/var/spol/squid" } } volume { name = "wireguard-config" config_map { name = kubernetes_config_map.wireguard_config.metadata[0].name } } volume { name = "lib-modules" host_path { path = "/lib/modules" } } volume { name = "squid-config" config_map { name = kubernetes_config_map.squid_config.metadata[0].name } } volume { name = "squid-data" host_path { path = local.squid_app_path } } } } } lifecycle { replace_triggered_by = [ kubernetes_config_map.wireguard_config, kubernetes_config_map.squid_config ] } } # Create the Deployment resource "kubernetes_deployment" "m3uproxy" { metadata { name = "m3uproxy" namespace = kubernetes_namespace.m3uproxy.metadata[0].name } spec { replicas = 1 selector { match_labels = { app = "m3uproxy" } } strategy { type = "RollingUpdate" } template { metadata { labels = { app = "m3uproxy" } } spec { service_account_name = kubernetes_service_account.m3uproxy_service_account.metadata[0].name container { name = "m3uproxy" image = "a13labs/m3uproxy:${local.m3uproxy_version}" image_pull_policy = "Always" resources { requests = { memory = "256Mi" } } port { container_port = 8080 name = "http" } readiness_probe { http_get { path = "/health" port = "http" } initial_delay_seconds = 5 period_seconds = 10 failure_threshold = 10 } env { name = "USERNAME" value_from { secret_key_ref { name = kubernetes_secret.m3uproxy_admin_credentials.metadata[0].name key = "username" } } } env { name = "PASSWORD" value_from { secret_key_ref { name = kubernetes_secret.m3uproxy_admin_credentials.metadata[0].name key = "password" } } } security_context { run_as_user = 1000 run_as_group = 1000 } volume_mount { name = "m3uproxy-config" mount_path = "/app/conf" read_only = true } volume_mount { name = "m3uproxy-app-cache" mount_path = "/app/cache" } volume_mount { name = "geoip-db" mount_path = "/app/GeoIP" read_only = true } } volume { name = "m3uproxy-config" config_map { name = kubernetes_config_map.m3uproxy_config.metadata[0].name } } volume { name = "m3uproxy-app-cache" host_path { path = local.m3uproxy_cache_path } } volume { name = "geoip-db" host_path { path = "/var/lib/GeoIP" } } } } } } resource "kubernetes_service" "m3uproxy" { metadata { name = "http" namespace = kubernetes_namespace.m3uproxy.metadata[0].name } spec { selector = { app = "m3uproxy" } port { port = 8080 target_port = "http" } cluster_ip = "None" } } resource "kubernetes_service" "proxy_pt" { metadata { name = "proxy-pt" namespace = kubernetes_namespace.m3uproxy.metadata[0].name } spec { selector = { app = "proxy-pt" } port { port = 3128 } cluster_ip = "None" } } resource "kubernetes_ingress_v1" "m3uproxy_ingress_http" { metadata { name = "m3uproxy-ingress" namespace = kubernetes_namespace.m3uproxy.metadata[0].name annotations = { "kubernetes.io/ingress.class" = "public" "cert-manager.io/cluster-issuer" = "letsencrypt-prod" "kubernetes.io/tls-acme" = "true" "nginx.ingress.kubernetes.io/ssl-redirect" = "true" } } spec { tls { hosts = [local.m3uproxy_fqdn] secret_name = "m3uproxy-tls" } rule { host = local.m3uproxy_fqdn http { path { backend { service { name = "http" port { number = 8080 } } } } } } } }