From 726eb1d5ab87f8126452159f57dc7c002d82eae2 Mon Sep 17 00:00:00 2001 From: Yassin Kortam Date: Thu, 9 Jul 2026 21:01:52 +0300 Subject: [PATCH] fix(terraform): fail the plan on a partial billing-metrics config Each PEM secret is created only when its own variable is non-empty, so setting billing_metrics_endpoint with a certificate but no key applied cleanly and left the proxy logging "missing config" and never exporting. Silent non-export is the undercount direction this metric must not drift in, and every other surface fails fast on a half-configured metering block. Both templates now carry a lifecycle precondition requiring the client certificate and its key together whenever the endpoint is set. It lives on the gateway task definition (aws) and the gateway Cloud Run service (gcp) rather than on the secret resources, because those are themselves count-gated on the PEM being present and would never evaluate in the failing case. Cross-variable `validation` blocks would need terraform 1.9; versions.tf pins >= 1.6, and preconditions work there. ca_cert_pem stays optional, so an empty value still falls back to the system trust store. endpoint cert key result "" any any metering off, no secrets created set set set metering on set missing either plan fails Verified each row with `terraform console` against the condition, and reran `terraform fmt -check` and `terraform validate` in both directories --- terraform/litellm/aws/ecs.tf | 19 +++++++++++++++++++ terraform/litellm/gcp/cloudrun.tf | 19 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/terraform/litellm/aws/ecs.tf b/terraform/litellm/aws/ecs.tf index bf0487c0a93..e6848421779 100644 --- a/terraform/litellm/aws/ecs.tf +++ b/terraform/litellm/aws/ecs.tf @@ -207,6 +207,25 @@ locals { # ---------- Gateway ---------- resource "aws_ecs_task_definition" "gateway" { + # Metering needs a client certificate AND its key. Each secret is created only + # when its own PEM is supplied, so an endpoint set with a missing key would + # otherwise apply cleanly and leave the proxy logging "missing config" and + # never exporting. ca_cert_pem stays optional: empty means fall back to the + # system trust store. + # + # endpoint cert key -> result + # "" any any -> metering off, no secrets created + # set set set -> metering on + # set any-missing -> plan fails here + lifecycle { + precondition { + condition = var.billing_metrics_endpoint == "" || ( + var.billing_metrics_client_cert_pem != "" && var.billing_metrics_client_key_pem != "" + ) + error_message = "billing_metrics_client_cert_pem and billing_metrics_client_key_pem are both required when billing_metrics_endpoint is set." + } + } + family = "${local.name}-gateway" network_mode = "awsvpc" requires_compatibilities = ["FARGATE"] diff --git a/terraform/litellm/gcp/cloudrun.tf b/terraform/litellm/gcp/cloudrun.tf index 913ec2bbb3d..5b47f1e08f4 100644 --- a/terraform/litellm/gcp/cloudrun.tf +++ b/terraform/litellm/gcp/cloudrun.tf @@ -165,6 +165,25 @@ locals { # ---------- Gateway ---------- resource "google_cloud_run_v2_service" "gateway" { + # Metering needs a client certificate AND its key. Each secret is created only + # when its own PEM is supplied, so an endpoint set with a missing key would + # otherwise apply cleanly and leave the proxy logging "missing config" and + # never exporting. ca_cert_pem stays optional: empty means fall back to the + # system trust store. + # + # endpoint cert key -> result + # "" any any -> metering off, no secrets created + # set set set -> metering on + # set any-missing -> plan fails here + lifecycle { + precondition { + condition = var.billing_metrics_endpoint == "" || ( + var.billing_metrics_client_cert_pem != "" && var.billing_metrics_client_key_pem != "" + ) + error_message = "billing_metrics_client_cert_pem and billing_metrics_client_key_pem are both required when billing_metrics_endpoint is set." + } + } + name = "${local.name}-gateway" location = var.region ingress = "INGRESS_TRAFFIC_INTERNAL_LOAD_BALANCER"