From 25847f27ffac886984284f7377aebfe10f164551 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20D=C3=ADaz?= Date: Wed, 2 Sep 2026 15:55:31 +0200 Subject: [PATCH 1/6] Setup load balancer rules to map to the legacy ooniprobe based on header --- tf/environments/dev/main.tf | 53 ++++++++++++++++++- tf/modules/ooniapi_frontend/main.tf | 65 ++++++++++++++++++++++-- tf/modules/ooniapi_frontend/variables.tf | 4 ++ 3 files changed, 117 insertions(+), 5 deletions(-) diff --git a/tf/environments/dev/main.tf b/tf/environments/dev/main.tf index 95826431..b366b875 100644 --- a/tf/environments/dev/main.tf +++ b/tf/environments/dev/main.tf @@ -581,7 +581,7 @@ module "ooniapi_ooniprobe_deployer" { service_name = "ooniprobe" repo = "ooni/backend" - branch_name = "1237-check-in-to-th" + branch_name = "master" environment = local.environment trigger_path = "ooniapi/services/ooniprobe/**" buildspec_path = "ooniapi/services/ooniprobe/buildspec.yml" @@ -651,6 +651,56 @@ module "ooniapi_ooniprobe" { ) } +# Legacy ooniprobe service, used to serve older probes. Identified by the +# X-Protocol-Version header that specifies the anonymous credentials protocol +# version. +module "ooniapi_ooniprobe_legacy" { + source = "../../modules/ooniapi_service" + + task_memory = 256 + + vpc_id = module.network.vpc_id + + service_name = "ooniprobe-legacy" + default_docker_image_url = "ooni/api-ooniprobe:20260824-f2dac67a" + stage = local.environment + dns_zone_ooni_io = local.dns_zone_ooni_io + key_name = module.adm_iam_roles.oonidevops_key_name + ecs_cluster_id = module.ooniapi_cluster.cluster_id + + task_secrets = { + POSTGRESQL_URL = data.aws_ssm_parameter.oonipg_url.arn + JWT_ENCRYPTION_KEY = data.aws_ssm_parameter.jwt_secret_legacy.arn + PROMETHEUS_METRICS_PASSWORD = data.aws_ssm_parameter.prometheus_metrics_password.arn + CLICKHOUSE_URL = data.aws_ssm_parameter.clickhouse_ooniprobe_url.arn + ANONC_SECRET_KEY = data.aws_ssm_parameter.anonc_secret_key.arn + } + + task_environment = { + FASTPATH_URL = "http://fastpath.${local.environment}.ooni.io:8472" + FASTPATH_URLS = jsonencode([for h in local.fastpath_hosts : "http://${h}:8472"]) + FAILED_REPORTS_BUCKET = aws_s3_bucket.ooniprobe_failed_reports.bucket + COLLECTOR_ID = 3 # use a different one in prod + CONFIG_BUCKET = aws_s3_bucket.ooni_private_config_bucket.bucket + TOR_TARGETS = "tor_targets.json" + PSIPHON_CONFIG = "psiphon_config.json" + ANONC_MANIFEST_BUCKET = aws_s3_bucket.anoncred_manifests.bucket + ANONC_MANIFEST_FILE = "manifest.json" + } + + ooniapi_service_security_groups = [ + # module.ooniapi_cluster.web_security_group_id + ] + + use_autoscaling = false + service_desired_count = 1 + + tags = merge( + local.tags, + { Name = "ooni-tier0-ooniprobe-legacy" } + ) +} + #### OONI Backend proxy service module "ooniapi_reverseproxy_deployer" { @@ -1301,6 +1351,7 @@ module "ooniapi_frontend" { ooniapi_oonirun_target_group_arn = module.ooniapi_oonirun.alb_target_group_id ooniapi_ooniauth_target_group_arn = module.ooniapi_ooniauth.alb_target_group_id ooniapi_ooniprobe_target_group_arn = module.ooniapi_ooniprobe.alb_target_group_id + ooniapi_ooniprobe_legacy_target_group_arn = module.ooniapi_ooniprobe_legacy.alb_target_group_id ooniapi_oonifindings_target_group_arn = module.ooniapi_oonifindings.alb_target_group_id ooniapi_oonimeasurements_target_group_arn = module.ooniapi_oonimeasurements.alb_target_group_id ooniapi_testlists_target_group_arn = module.ooniapi_testlists.alb_target_group_id diff --git a/tf/modules/ooniapi_frontend/main.tf b/tf/modules/ooniapi_frontend/main.tf index d6034f2e..2e1bee8e 100644 --- a/tf/modules/ooniapi_frontend/main.tf +++ b/tf/modules/ooniapi_frontend/main.tf @@ -377,22 +377,79 @@ resource "aws_lb_listener_rule" "ooniapi_ooniprobe_rule_2" { } } -resource "aws_lb_listener_rule" "ooniapi_ooniprobe_rule_3" { +resource "aws_lb_listener_rule" "ooniapi_ooniprobe_rule_3_legacy_version" { listener_arn = aws_alb_listener.ooniapi_listener_https.arn priority = 122 + action { + type = "forward" + target_group_arn = var.ooniapi_ooniprobe_legacy_target_group_arn + } + + condition { + path_pattern { + values = [ + "/api/v1/manifest*", + "/api/v1/submit_measurement*", + "/api/v1/sign_credential*" + ] + } + } + + condition { + http_header { + http_header_name = "X-Protocol-Version" + values = ["0.1.0"] + } + } +} + +resource "aws_lb_listener_rule" "ooniapi_ooniprobe_rule_3_current_version" { + listener_arn = aws_alb_listener.ooniapi_listener_https.arn + priority = 124 + action { type = "forward" target_group_arn = var.ooniapi_ooniprobe_target_group_arn } - # anonymous credentials condition { path_pattern { values = [ "/api/v1/manifest*", - "/api/v1/sign_credential*", - "/api/v1/submit_measurement*" + "/api/v1/submit_measurement*", + "/api/v1/sign_credential*" + ] + } + } + + # matches any value, but only when the header is present + condition { + http_header { + http_header_name = "X-Protocol-Version" + values = ["*"] + } + } +} + +resource "aws_lb_listener_rule" "ooniapi_ooniprobe_rule_3_no_version" { + listener_arn = aws_alb_listener.ooniapi_listener_https.arn + priority = 126 + + action { + type = "forward" + target_group_arn = var.ooniapi_ooniprobe_legacy_target_group_arn + } + + # No X-Protocol-Version header at all: rules 122/124 above already + # matched every request that does carry the header, so anything left + # here is header-less and should go to the legacy service. + condition { + path_pattern { + values = [ + "/api/v1/manifest*", + "/api/v1/submit_measurement*", + "/api/v1/sign_credential*" ] } } diff --git a/tf/modules/ooniapi_frontend/variables.tf b/tf/modules/ooniapi_frontend/variables.tf index d92c39e3..614056e6 100644 --- a/tf/modules/ooniapi_frontend/variables.tf +++ b/tf/modules/ooniapi_frontend/variables.tf @@ -28,6 +28,10 @@ variable "ooniapi_ooniprobe_target_group_arn" { description = "arn for the target group of the ooniprobe service" } +variable "ooniapi_ooniprobe_legacy_target_group_arn" { + description = "arn for the target group of the legacy ooniprobe service" +} + variable "ooniapi_oonifindings_target_group_arn" { description = "arn for the target group of the oonifindings service" } From 22b14b9cc2ef24475dfb47c285983b8ad53df47f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20D=C3=ADaz?= Date: Wed, 2 Sep 2026 16:02:26 +0200 Subject: [PATCH 2/6] Add ooniprobe-legacy service to prod as well --- tf/environments/prod/main.tf | 51 ++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/tf/environments/prod/main.tf b/tf/environments/prod/main.tf index b6980c4b..9cd5da00 100644 --- a/tf/environments/prod/main.tf +++ b/tf/environments/prod/main.tf @@ -966,6 +966,56 @@ module "ooniapi_ooniprobe" { ) } +# Legacy ooniprobe service, used to serve older probes. Identified by the +# X-Protocol-Version header that specifies the anonymous credentials protocol +# version. +module "ooniapi_ooniprobe_legacy" { + source = "../../modules/ooniapi_service" + + vpc_id = module.network.vpc_id + + service_name = "ooniprobe-legacy" + default_docker_image_url = "ooni/api-ooniprobe:20260824-f2dac67a" + stage = local.environment + dns_zone_ooni_io = local.dns_zone_ooni_io + key_name = module.adm_iam_roles.oonidevops_key_name + ecs_cluster_id = module.ooniapi_cluster.cluster_id + task_memory = 1024 + + task_secrets = { + POSTGRESQL_URL = data.aws_ssm_parameter.oonipg_url.arn + JWT_ENCRYPTION_KEY = data.aws_ssm_parameter.jwt_secret.arn + PROMETHEUS_METRICS_PASSWORD = data.aws_ssm_parameter.prometheus_metrics_password.arn + CLICKHOUSE_URL = data.aws_ssm_parameter.clickhouse_write_url.arn + ANONC_SECRET_KEY = data.aws_ssm_parameter.anonc_secret_key.arn + } + + task_environment = { + # hardcoded IP for fastpath2.prod.prod.ooni.io + FASTPATH_URL = "http://10.0.0.32:8472" + FASTPATH_URLS = jsonencode([for h in local.fastpath_hosts : "http://${h}:8472"]) + FAILED_REPORTS_BUCKET = aws_s3_bucket.ooniprobe_failed_reports.bucket + COLLECTOR_ID = 4 # be sure this is different from dev + CONFIG_BUCKET = aws_s3_bucket.ooni_private_config_bucket.bucket + TOR_TARGETS = "tor_targets.json" + PSIPHON_CONFIG = "psiphon_config.json" + ANONC_MANIFEST_BUCKET = aws_s3_bucket.anoncred_manifests.bucket + ANONC_MANIFEST_FILE = "manifest.json" + } + + ooniapi_service_security_groups = [ + module.ooniapi_cluster.web_security_group_id + ] + + use_autoscaling = false + service_desired_count = 1 + + tags = merge( + local.tags, + { Name = "ooni-tier0-ooniprobe-legacy" } + ) +} + ### Fastpath module "ooni_fastpath" { source = "../../modules/ooni_fastpath" @@ -1534,6 +1584,7 @@ module "ooniapi_frontend" { ooniapi_oonirun_target_group_arn = module.ooniapi_oonirun.alb_target_group_id ooniapi_ooniauth_target_group_arn = module.ooniapi_ooniauth.alb_target_group_id ooniapi_ooniprobe_target_group_arn = module.ooniapi_ooniprobe.alb_target_group_id + ooniapi_ooniprobe_legacy_target_group_arn = module.ooniapi_ooniprobe_legacy.alb_target_group_id ooniapi_oonifindings_target_group_arn = module.ooniapi_oonifindings.alb_target_group_id ooniapi_oonimeasurements_target_group_arn = module.ooniapi_oonimeasurements.alb_target_group_id ooniapi_testlists_target_group_arn = module.ooniapi_testlists.alb_target_group_id From d8d8d3c9e900d510ffe804c01f749fefd066bdb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20D=C3=ADaz?= Date: Thu, 3 Sep 2026 11:12:02 +0200 Subject: [PATCH 3/6] Set first run to true for these services --- tf/environments/dev/main.tf | 3 +++ tf/environments/prod/main.tf | 3 +++ 2 files changed, 6 insertions(+) diff --git a/tf/environments/dev/main.tf b/tf/environments/dev/main.tf index b366b875..3bf6abe1 100644 --- a/tf/environments/dev/main.tf +++ b/tf/environments/dev/main.tf @@ -657,6 +657,9 @@ module "ooniapi_ooniprobe" { module "ooniapi_ooniprobe_legacy" { source = "../../modules/ooniapi_service" + # First run should be set on first run to bootstrap the task definition + first_run = true + task_memory = 256 vpc_id = module.network.vpc_id diff --git a/tf/environments/prod/main.tf b/tf/environments/prod/main.tf index 9cd5da00..ab6438a7 100644 --- a/tf/environments/prod/main.tf +++ b/tf/environments/prod/main.tf @@ -972,6 +972,9 @@ module "ooniapi_ooniprobe" { module "ooniapi_ooniprobe_legacy" { source = "../../modules/ooniapi_service" + # First run should be set on first run to bootstrap the task definition + first_run = true + vpc_id = module.network.vpc_id service_name = "ooniprobe-legacy" From bab971db74a67696d9b288aad97046d71666e545 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20D=C3=ADaz?= Date: Thu, 3 Sep 2026 11:55:10 +0200 Subject: [PATCH 4/6] Fix trying to create the service --- tf/environments/dev/main.tf | 2 +- tf/modules/ooniapi_service/main.tf | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/tf/environments/dev/main.tf b/tf/environments/dev/main.tf index 3bf6abe1..809632b5 100644 --- a/tf/environments/dev/main.tf +++ b/tf/environments/dev/main.tf @@ -658,7 +658,7 @@ module "ooniapi_ooniprobe_legacy" { source = "../../modules/ooniapi_service" # First run should be set on first run to bootstrap the task definition - first_run = true + # first_run = true task_memory = 256 diff --git a/tf/modules/ooniapi_service/main.tf b/tf/modules/ooniapi_service/main.tf index 84e9f38f..94bebfd8 100644 --- a/tf/modules/ooniapi_service/main.tf +++ b/tf/modules/ooniapi_service/main.tf @@ -126,6 +126,9 @@ resource "aws_ecs_service" "ooniapi_service" { lifecycle { create_before_destroy = true + # fixes an issue when AWS changes the capacity provider + # on its own, terraform has no record of that on its internal state + ignore_changes = [capacity_provider_strategy] } force_new_deployment = true From 7dfda84bb3f2b48bcdc1eef47d2f2e7a82297658 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20D=C3=ADaz?= Date: Mon, 28 Sep 2026 12:36:08 +0200 Subject: [PATCH 5/6] Update docker tag in legacy --- tf/environments/dev/main.tf | 2 +- tf/environments/prod/main.tf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tf/environments/dev/main.tf b/tf/environments/dev/main.tf index 99d15327..9e3fd3b1 100644 --- a/tf/environments/dev/main.tf +++ b/tf/environments/dev/main.tf @@ -665,7 +665,7 @@ module "ooniapi_ooniprobe_legacy" { vpc_id = module.network.vpc_id service_name = "ooniprobe-legacy" - default_docker_image_url = "ooni/api-ooniprobe:20260824-f2dac67a" + default_docker_image_url = "ooni/api-ooniprobe:20260921-da8b057f" stage = local.environment dns_zone_ooni_io = local.dns_zone_ooni_io key_name = module.adm_iam_roles.oonidevops_key_name diff --git a/tf/environments/prod/main.tf b/tf/environments/prod/main.tf index ab6438a7..a4b4f5f6 100644 --- a/tf/environments/prod/main.tf +++ b/tf/environments/prod/main.tf @@ -978,7 +978,7 @@ module "ooniapi_ooniprobe_legacy" { vpc_id = module.network.vpc_id service_name = "ooniprobe-legacy" - default_docker_image_url = "ooni/api-ooniprobe:20260824-f2dac67a" + default_docker_image_url = "ooni/api-ooniprobe:20260921-da8b057f" stage = local.environment dns_zone_ooni_io = local.dns_zone_ooni_io key_name = module.adm_iam_roles.oonidevops_key_name From eeff8dd99f3b8cdff9579023425dfaea82ed3edb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20D=C3=ADaz?= Date: Mon, 28 Sep 2026 12:40:53 +0200 Subject: [PATCH 6/6] Already deployed; first_run no longer needed --- tf/environments/prod/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tf/environments/prod/main.tf b/tf/environments/prod/main.tf index a4b4f5f6..35f43a97 100644 --- a/tf/environments/prod/main.tf +++ b/tf/environments/prod/main.tf @@ -973,7 +973,7 @@ module "ooniapi_ooniprobe_legacy" { source = "../../modules/ooniapi_service" # First run should be set on first run to bootstrap the task definition - first_run = true + # first_run = true vpc_id = module.network.vpc_id