0

I'm trying to set up the Traefik Helm chart in Kubernetes to get a Let's Encrypt TLS/HTTPS certificate and use it for an IngressRoute, but whenever I add the Proxy Protocol stuff to preserve client IP addresses as per Civo's docs (the trustedIPs, annotations, and externalTrafficPolicy), it stops working, and I get the following in the Traefik logs:

2025-04-22T13:09:33Z ERR Unable to obtain ACME certificate for domains error="unable to generate a certificate for the domains [dashboard.example.blue]: error: one or more domains had a problem:\n[dashboard.example.blue] inv.alid authorization: acme: error: 400 :: urn:ietf:params:acme:error:connection :: 74.220.25.170: Fetching http://dashboard.example.blue/.well-known/acme-challenge/DN4ggaxOm7FlVZiHQqiGe4-x9lN1EJkHA5n6TymfkJ4: Error getting validation data\n" ACME CA=https://acme-staging-v02.api.letsencrypt.org/directory acmeCA=https://acme-staging-v02.api.letsencrypt.org/directory domains=["dashboard.example.blue"] providerName=staging.acme routerName=websecure-dash-drupal-42da837a8cc7a01b7ea1@kubernetescrd rule=Host(dashboard.example.blue)

Also:

% curl -I http://dashboard.example.blue
HTTP/1.1 502 Server Hangup
% curl -I https://dashboard.example.blue
curl: (35) error:0A000126:SSL routines::unexpected eof while reading

Here's the Terraform code (I didn't include the IngressRoute kubernetes_manifest resource because that doesn't change):

resource "helm_release" "traefik" {
  name       = "traefik"
  namespace  = kubernetes_namespace.drupal_dashboard.metadata[0].name
  repository = "https://traefik.github.io/charts"
  chart      = "traefik"
  version    = var.traefik_helm_chart_version

values = [ yamlencode({ additionalArguments = [ "--entryPoints.web.address=:${var.http_port}", "--entryPoints.web.proxyProtocol.trustedIPs=${join(",", ["0.0.0.0/0"])}", "--entryPoints.websecure.address=:${var.https_port}", "--entryPoints.websecure.proxyProtocol.trustedIPs=${join(",", ["0.0.0.0/0"])}" ] service = { annotations = { "kubernetes.civo.com/loadbalancer-enable-proxy-protocol" = "send-proxy-v2" "kubernetes.civo.com/firewall-id" = var.firewall_id_annotation_value } spec = { externalTrafficPolicy = "Local" } } certificatesResolvers = { (var.letsencrypt_staging_environment_name) = { acme = { caServer = "https://acme-staging-v02.api.letsencrypt.org/directory" email = var.technical_contact_email storage = local.tls_certificate_data_path httpChallenge = { entryPoint = "web" } } } (var.letsencrypt_production_environment_name) = { acme = { caServer = "https://acme-v02.api.letsencrypt.org/directory" email = var.technical_contact_email storage = local.tls_certificate_data_path httpChallenge = { entryPoint = "web" } } } } }) ] }

Anyone have any ideas what's going wrong?

colan
  • 173
  • 1
  • 6

1 Answers1

0

I never got an answer for this so I gave up on Traefik, and switched to Nginx Ingress + Cert Manager:

resource "helm_release" "nginx_ingress" {
  name       = "nginx-ingress"
  namespace  = kubernetes_namespace.drupal_dashboard.metadata[0].name
  repository = "https://kubernetes.github.io/ingress-nginx"
  chart      = "ingress-nginx"
  version    = var.nginx_ingress_helm_chart_version

values = [yamlencode({ controller = { replicaCount = 2 service = { type = "LoadBalancer" annotations = { (var.client_ip_preservation_annotation_key) = var.client_ip_preservation_annotation_value (var.firewall_id_annotation_key) = var.firewall_id_annotation_value (var.loadbalancer_algorithm_annotation_key) = var.loadbalancer_algorithm_annotation_value } externalTrafficPolicy = "Local" ports = { http = var.http_port https = var.https_port } } # https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/ config = { use-forwarded-headers = "true" use-proxy-protocol = "true" proxy-real-ip-cidr = join(",", var.trusted_ip_address_ranges) } } })] } resource "helm_release" "cert_manager" { name = "cert-manager" namespace = kubernetes_namespace.drupal_dashboard.metadata[0].name repository = "https://charts.jetstack.io" chart = "cert-manager" version = var.cert_manager_helm_chart_version set { name = "installCRDs" value = "true" } } resource "kubectl_manifest" "le_staging" { depends_on = [helm_release.cert_manager] yaml_body = <<YAML apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: ${var.letsencrypt_staging_environment_name} spec: acme: email: ${var.technical_contact_email} server: https://acme-staging-v02.api.letsencrypt.org/directory privateKeySecretRef: name: acme-staging-key solvers: - http01: ingress: class: nginx YAML } resource "kubectl_manifest" "le_production" { depends_on = [helm_release.cert_manager] yaml_body = <<YAML apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: ${var.letsencrypt_production_environment_name} spec: acme: email: ${var.technical_contact_email} server: https://acme-v02.api.letsencrypt.org/directory privateKeySecretRef: name: acme-prod-key solvers: - http01: ingress: class: nginx YAML } resource "kubernetes_ingress_v1" "drupal_public" { metadata { name = "drupal-public" namespace = kubernetes_namespace.drupal_dashboard.metadata[0].name annotations = { "nginx.ingress.kubernetes.io/force-ssl-redirect" = "true" "cert-manager.io/cluster-issuer" = var.environment_is_production ? var.letsencrypt_production_environment_name : var.letsencrypt_staging_environment_name } } spec { ingress_class_name = "nginx" tls { hosts = [var.public_hostname] secret_name = "drupal-tls" } rule { host = var.public_hostname http { path { path = "/" path_type = "Prefix" backend { service { name = var.kubernetes_drupal_service_name port { number = var.http_port } } } } } } } } resource "kubernetes_ingress_v1" "drupal_admin" { metadata { name = "drupal-admin" namespace = kubernetes_namespace.drupal_dashboard.metadata[0].name annotations = { "nginx.ingress.kubernetes.io/use-regex": "true" "nginx.ingress.kubernetes.io/force-ssl-redirect" = "true" "nginx.ingress.kubernetes.io/whitelist-source-range" = var.vpn_range "cert-manager.io/cluster-issuer" = var.environment_is_production ? var.letsencrypt_production_environment_name : var.letsencrypt_staging_environment_name } } spec { ingress_class_name = "nginx" tls { hosts = [var.public_hostname] secret_name = "drupal-admin-tls" } rule { host = var.public_hostname http { path { path = "/admin" path_type = "Prefix" backend { service { name = var.kubernetes_drupal_service_name port { number = var.http_port } } } } path { path = "/(core/(install|authorize|rebuild)|update).php" path_type = "ImplementationSpecific" backend { service { name = var.kubernetes_drupal_service_name port { number = var.http_port } } } } } } } }

colan
  • 173
  • 1
  • 6