From 4c8d920659b51f9bcd1c9421a4c81bcdb95e8d44 Mon Sep 17 00:00:00 2001 From: Aaron Gibson Date: Fri, 2 Jan 2026 13:57:33 +0000 Subject: [PATCH 01/24] Add ooniapi test-lists service to load balancer Add ec2 t3a.nano for test-lists api backend Add DNS alias for citizenlab.{env}.ooni.io --- README.md | 3 + ansible/deploy-citizenlab.yml | 23 +++ ansible/deploy-tier2.yml | 3 + ansible/inventory | 2 + ansible/roles/citizenlab/defaults/main.yml | 6 + ansible/roles/citizenlab/handlers/main.yml | 27 +++ ansible/roles/citizenlab/tasks/main.yml | 157 ++++++++++++++++++ .../citizenlab/templates/citizenlab.conf | 19 +++ .../roles/citizenlab/templates/nginx-api.conf | 118 +++++++++++++ .../roles/prometheus/templates/prometheus.yml | 46 +++++ tf/environments/dev/main.tf | 99 ++++++++++- tf/modules/ec2/outputs.tf | 6 +- tf/modules/ooniapi_frontend/main.tf | 42 +++++ tf/modules/ooniapi_frontend/variables.tf | 4 + 14 files changed, 553 insertions(+), 2 deletions(-) create mode 100644 ansible/deploy-citizenlab.yml create mode 100644 ansible/roles/citizenlab/defaults/main.yml create mode 100644 ansible/roles/citizenlab/handlers/main.yml create mode 100644 ansible/roles/citizenlab/tasks/main.yml create mode 100644 ansible/roles/citizenlab/templates/citizenlab.conf create mode 100644 ansible/roles/citizenlab/templates/nginx-api.conf diff --git a/README.md b/README.md index fa9b8c7a..45bb0076 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ flowchart TB apiorg([api.ooni.org])-->alb apiio([api.ooni.io])-->backend ecs[Backend API ECS]<-->ch[(Clickhouse Cluster)] + cz[Citizenlab API EC2]<-->ch + subgraph Hetzner backend[OONI Backend Monolith]<-->ch monitoring[Monitoring host] @@ -15,6 +17,7 @@ flowchart TB subgraph AWS alb[API Load Balancer]<-->ecs alb-->backend + alb-->cz ecs<-->s3[(OONI S3 Buckets)] s3<-->backend end diff --git a/ansible/deploy-citizenlab.yml b/ansible/deploy-citizenlab.yml new file mode 100644 index 00000000..a4a0fb9f --- /dev/null +++ b/ansible/deploy-citizenlab.yml @@ -0,0 +1,23 @@ +--- +- name: Deploy citizenlab + hosts: + - citiz.dev.ooni.io + - citiz.prod.ooni.io + become: true + roles: + - role: bootstrap + - role: nginx + - role: prometheus_node_exporter + vars: + use_https: false + node_exporter_port: 9100 + node_exporter_host: "0.0.0.0" + prometheus_nginx_proxy_config: + - location: /metrics/node_exporter + proxy_pass: http://127.0.0.1:9100/metrics + - role: geerlingguy.docker + docker_users: + - citizenlab + - ubuntu + docker_package_state: latest + - role: citizenlab diff --git a/ansible/deploy-tier2.yml b/ansible/deploy-tier2.yml index cff8d695..79df612e 100644 --- a/ansible/deploy-tier2.yml +++ b/ansible/deploy-tier2.yml @@ -9,6 +9,9 @@ - name: Include notebook playbook ansible.builtin.import_playbook: deploy-notebook.yml +- name: Include citizenlab playbook + ansible.builtin.import_playbook: deploy-citizenlab.yml + # commented out due to the fact it requires manual config of ~/.ssh/config #- name: Setup codesign box # hosts: codesign-box diff --git a/ansible/inventory b/ansible/inventory index 7437f1af..af6de1cf 100644 --- a/ansible/inventory +++ b/ansible/inventory @@ -49,3 +49,5 @@ fastpath.prod.ooni.io anonc.dev.ooni.io jumphost.dev.ooni.io jumphost.prod.ooni.io +citiz.dev.ooni.io +citiz.prod.ooni.io diff --git a/ansible/roles/citizenlab/defaults/main.yml b/ansible/roles/citizenlab/defaults/main.yml new file mode 100644 index 00000000..2d2dfa1c --- /dev/null +++ b/ansible/roles/citizenlab/defaults/main.yml @@ -0,0 +1,6 @@ +# citizenlab user +citizenlab_user: citizenlab +citizenlab_home: "/opt/{{ citizenlab_user }}" + +# citizenlab settings +clickhouse_url: "clickhouse://write:{{ lookup('amazon.aws.aws_ssm', '/oonidevops/secrets/clickhouse_write_password', profile='oonidevops_user_prod') }}@clickhouseproxy.dev.ooni.io/oonitest" diff --git a/ansible/roles/citizenlab/handlers/main.yml b/ansible/roles/citizenlab/handlers/main.yml new file mode 100644 index 00000000..5c8f17dd --- /dev/null +++ b/ansible/roles/citizenlab/handlers/main.yml @@ -0,0 +1,27 @@ +- name: test nginx config + command: /usr/sbin/nginx -t -c /etc/nginx/nginx.conf + listen: + - restart nginx + - reload nginx + +- name: restart nginx + service: + name: nginx + state: restarted + +- name: reload nginx + service: + name: nginx + state: reloaded + +- name: reload nftables + tags: nftables + ansible.builtin.systemd_service: + name: nftables + state: reloaded + +- name: restart docker + tags: docker + ansible.builtin.systemd_service: + name: docker + state: restarted diff --git a/ansible/roles/citizenlab/tasks/main.yml b/ansible/roles/citizenlab/tasks/main.yml new file mode 100644 index 00000000..23fb2d52 --- /dev/null +++ b/ansible/roles/citizenlab/tasks/main.yml @@ -0,0 +1,157 @@ +--- +# For prometheus scrape requests +- name: Flush all handlers + meta: flush_handlers + +- name: Allow traffic on port 9100 + become: true + tags: prometheus-proxy + blockinfile: + path: /etc/ooni/nftables/tcp/9100.nft + create: yes + block: | + add rule inet filter input tcp dport 9100 counter accept comment "node exporter" + notify: + - reload nftables + +# For statsd importer metrics +- name: Flush all handlers + meta: flush_handlers + +- name: Allow traffic on port 9102 + become: true + tags: prometheus-proxy + blockinfile: + path: /etc/ooni/nftables/tcp/9102.nft + create: yes + block: | + add rule inet filter input tcp dport 9102 counter accept comment "node exporter" + notify: + - reload nftables + +# For incoming citizenlab traffic +- name: Allow traffic on port 80 + become: true + tags: citizenlab + blockinfile: + path: /etc/ooni/nftables/tcp/80.nft + create: yes + block: | + add rule inet filter input tcp dport 80 counter accept comment "citizenlab" + notify: + - reload nftables + +### Create citizenlab user +- name: Ensure the citizenlab group exists + ansible.builtin.group: + name: "{{ citizenlab_user }}" + state: present + become: yes + +- name: Create the citizenlab user + ansible.builtin.user: + name: "{{ citizenlab_user }}" + home: "{{ citizenlab_home }}" + shell: "/bin/bash" + group: "{{ citizenlab_user }}" + create_home: yes + system: yes + become: yes + +- name: Set ownership of the citizenlab directory + ansible.builtin.file: + path: "{{ citizenlab_home }}" + owner: "{{ citizenlab_user }}" + group: "{{ citizenlab_user }}" + state: directory + mode: "0700" + become: yes + +### Run citizenlab +- name: Make sure that the citizenlab configuration directory exists + ansible.builtin.file: + path: /opt/{{citizenlab_user}}/backend/citizenlab/ + state: directory + mode: "0700" + owner: "{{citizenlab_user}}" + group: "{{citizenlab_user}}" + +- name: Create configuration file + tags: citizenlab + template: + src: templates/citizenlab.conf + dest: "/opt/{{citizenlab_user}}/backend/citizenlab/citizenlab.conf" + mode: "0400" + owner: "{{citizenlab_user}}" + become: yes + +- name: Ensure ooniapi directory existence + ansible.builtin.file: + path: /var/lib/ooniapi + state: directory + mode: "0711" + owner: "{{citizenlab_user}}" + group: "{{citizenlab_user}}" + +- name: Ensure citizenlab var dir exists + ansible.builtin.file: + path: /var/lib/citizenlab + state: directory + mode: "0700" + owner: "{{citizenlab_user}}" + group: "{{citizenlab_user}}" + +## Nginx ## +- name: Ensure /etc/nginx/sites-available directory exists + file: + path: /etc/nginx/sites-available + state: directory + mode: '0755' + owner: root + group: root + +- name: Overwrite API nginx conf + tags: citizenlab + template: + src: templates/nginx-api.conf + dest: /etc/nginx/sites-available/ooni-api.conf + mode: 0755 + owner: root + vars: + # Uses dehydrated + certpath: /var/lib/dehydrated/certs/ + +- name: Create symlink for API nginx conf + tags: citizenlab + file: + src=/etc/nginx/sites-available/ooni-api.conf + dest=/etc/nginx/sites-enabled/ooni-api.conf + state=link + +- name: Get UID of a specific user + command: id -u {{citizenlab_user}} + register: user_uid + changed_when: false + +- name: Get GID of a specific user + command: id -g {{citizenlab_user}} + register: user_gid + changed_when: false + +- name: Ensure citizenlab is running + community.docker.docker_container: + env: + CLICKHOUSE_URL: "{{ clickhouse_url }}" + name: citizenlab + image: ooni/api-citizenlab:latest + state: started + user: "{{user_uid.stdout}}:{{user_gid.stdout}}" + # use network mode = host to allow traffic from citizenlab to the statsd exporter without + # creating a network with redirection rules to match the ports + network_mode: host + volumes: + - /opt/{{citizenlab_user}}/backend/citizenlab/citizenlab.conf:/etc/ooni/citizenlab.conf + - /var/lib/ooniapi:/var/lib/ooniapi + - /var/lib/citizenlab:/var/lib/citizenlab + tags: + - citizenlab diff --git a/ansible/roles/citizenlab/templates/citizenlab.conf b/ansible/roles/citizenlab/templates/citizenlab.conf new file mode 100644 index 00000000..54ec9d7e --- /dev/null +++ b/ansible/roles/citizenlab/templates/citizenlab.conf @@ -0,0 +1,19 @@ +[DEFAULT] +# Collector hostnames, comma separated +collectors = localhost + + +{% if psql_uri is defined %} +# The password is already made public +db_uri = {{ psql_uri }} +{% else %} +db_uri = +{% endif %} + +# S3 access credentials +# Currently unused +s3_access_key = +s3_secret_key = + + +clickhouse_url = {{clickhouse_url}} diff --git a/ansible/roles/citizenlab/templates/nginx-api.conf b/ansible/roles/citizenlab/templates/nginx-api.conf new file mode 100644 index 00000000..f2f6704e --- /dev/null +++ b/ansible/roles/citizenlab/templates/nginx-api.conf @@ -0,0 +1,118 @@ +# Managed by ansible +# roles/citizenlab/templates/nginx-api.conf + +# Use 2-level cache, 20MB of RAM + 5GB on disk, +proxy_cache_path /var/cache/nginx/ooni-api levels=1:2 keys_zone=apicache:100M + max_size=5g inactive=24h use_temp_path=off; + +# anonymize ipaddr +map $remote_addr $remote_addr_anon { + ~(?P\d+\.\d+\.\d+)\. $ip.0; + ~(?P[^:]+:[^:]+): $ip::; + default 0.0.0.0; +} + +# anonymize forwarded ipaddr +map $http_x_forwarded_for $remote_fwd_anon { + ~(?P\d+\.\d+\.\d+)\. $ip.0; + ~(?P[^:]+:[^:]+): $ip::; + default 0.0.0.0; +} + + +# log anonymized ipaddr and caching status +log_format ooni_api_fmt '$remote_addr_anon $remote_fwd_anon $upstream_cache_status [$time_local] ' + '"$request" $status snt:$body_bytes_sent rt:$request_time uprt:$upstream_response_time "$http_referer" "$http_user_agent"'; + +server { + # TODO(bassosimone): we need support for cleartext HTTP to make sure that requests + # over Tor correctly land to the proper backend. We are listening on this custom port + # and we are configuring Tor such that it routes traffic to this port. + listen 127.0.0.1:17744; + + listen 80 http2 default_server; + listen [::]:80 http2 default_server; + server_name _; + access_log syslog:server=unix:/dev/log,tag=ooniapi,severity=info ooni_api_fmt; + error_log syslog:server=unix:/dev/log,tag=ooniapi,severity=info; + gzip on; + gzip_types text/plain application/xml application/json; + + # TODO: we could use different client_max_body_size and SSL configurations for probe service paths + # and everyhing else + client_max_body_size 200M; # for measurement POST + + # Use the intermediate configuration to support legacy probes + # https://ssl-config.mozilla.org/#server=nginx&version=1.14.2&config=intermediate&openssl=1.1.1d&guideline=5.6 + ssl_session_timeout 5m; + ssl_session_cache shared:MozSSL:30m; + ssl_session_tickets off; + + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + add_header X-Frame-Options DENY always; + add_header X-Content-Type-Options nosniff always; + + # OCSP stapling + ssl_stapling on; + ssl_stapling_verify on; + + # verify chain of trust of OCSP response using Root CA and Intermediate certs + #ssl_trusted_certificate /path/to/root_CA_cert_plus_intermediates; + + location /whoami { + return 200 "{{ inventory_hostname }}"; + } + + location /metrics { + return 200 ''; + } + + # new API + location / { + + # Protect /apidocs invoked with url= and/or urls= args + if ($uri ~ "^/apidocs") { set $block_apidocs X; } + if ($args ~ "url=" ) { set $block_apidocs "${block_apidocs}Y"; } + if ($args ~ "urls=" ) { set $block_apidocs "${block_apidocs}Y"; } + if ($block_apidocs ~ "XY") { return 403; } # nested "if" are not supported + + deny 216.244.66.0/24; # DotBot/1.2 + deny 114.119.128.0/19; # PetalBot + allow all; + proxy_pass http://127.0.0.1:8000; + proxy_set_header Host $host; + + set $external_remote_addr $remote_addr; + if ($remote_addr ~ "^3.") { + # If remote_addr is AWS trust the X-Real-IP header + set $external_remote_addr $http_x_real_ip; + } + proxy_set_header X-Real-IP $external_remote_addr; + + proxy_cache apicache; + proxy_cache_min_uses 1; + proxy_cache_lock on; + proxy_cache_lock_timeout 30; + proxy_cache_lock_age 30; + proxy_cache_use_stale error timeout invalid_header updating; + proxy_cache_methods HEAD GET; + # Cache only 200, 301, and 302 by default and for very short. + # Overridden by the API using the Expires header + proxy_cache_valid 200 301 302 10s; + proxy_cache_valid any 0; + add_header x-cache-status $upstream_cache_status; + add_header X-Cache-Status $upstream_cache_status; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + add_header X-Frame-Options DENY always; + add_header X-Content-Type-Options nosniff always; + } +} + +# Used by Netdata to monitor Nginx +server { + listen 127.0.0.1:80; + server_name localhost; + location = /stub_status { + stub_status; + } +} diff --git a/ansible/roles/prometheus/templates/prometheus.yml b/ansible/roles/prometheus/templates/prometheus.yml index d1e5b90e..0027b4ab 100755 --- a/ansible/roles/prometheus/templates/prometheus.yml +++ b/ansible/roles/prometheus/templates/prometheus.yml @@ -369,4 +369,50 @@ scrape_configs: replacement: "/$2" target_label: "__metrics_path__" action: "replace" + + - job_name: "citizenlab" + static_configs: + - targets: + - citizenlab.dev.ooni.io:9102 + - citizenlab.prod.ooni.io:9102 + scrape_interval: 5s + scheme: https + relabel_configs: # Change the host to the proxy host with relabeling + # Store ip in ecs_host + - source_labels: [__address__] + regex: "([a-z\\.]+):([0-9]+)" # :" + replacement: "$1" + target_label: "ec2_host" + action: "replace" + # Extract environment from address + - source_labels: [__address__] + regex: ".*(dev|prod).*" + replacement: "$1" + target_label: "env" + action: "replace" + # Store the full adress with path in proxy_host + - source_labels: [__address__] + regex: "([a-z\\.]+):([0-9]+)" # : + replacement: "{{monitoring_proxy_host}}:9200/${1}/${2}/metrics" # proxy.org:9200///metrics + target_label: "__proxy_host" + action: "replace" + # Change the environment part in proxy host + - source_labels: [__proxy_host, env] + separator: ";" + regex: "([^;]*)ENV([^;]*);(.*)" # __proxy_host;env + replacement: "$1$3$2" + target_label: "__proxy_host" + action: "replace" + # Change the address where to send the scrape request to + - source_labels: [__proxy_host] + regex: "([^/]*)/(.*)" + replacement: "$1" + target_label: "__address__" + action: "replace" + # Change the metrics path to include ip address and /metrics path + - source_labels: [__proxy_host] + regex: "([^/]*)/(.*)" + replacement: "/$2" + target_label: "__metrics_path__" + action: "replace" ... diff --git a/tf/environments/dev/main.tf b/tf/environments/dev/main.tf index 099b5c5f..abe48b41 100644 --- a/tf/environments/dev/main.tf +++ b/tf/environments/dev/main.tf @@ -706,7 +706,8 @@ module "ooni_clickhouse_proxy" { from_port = 9000, to_port = 9000, protocol = "tcp", - cidr_blocks = concat(module.network.vpc_subnet_private[*].cidr_block, ["${module.ooni_fastpath.aws_instance_private_ip}/32", "${module.ooni_fastpath.aws_instance_public_ip}/32"]), + cidr_blocks = concat(module.network.vpc_subnet_private[*].cidr_block, ["${module.ooni_fastpath.aws_instance_private_ip}/32", "${module.ooni_fastpath.aws_instance_public_ip}/32"], + ["${module.ooniapi_citizenlab.aws_instance_private_ip}/32", "${module.ooniapi_citizenlab.aws_instance_public_ip}/32"]), }, { // For the prometheus proxy: from_port = 9200, @@ -1150,6 +1151,100 @@ module "ooniapi_oonimeasurements" { ) } +### Tier2 Citizenlab service +module "ooniapi_citizenlab" { + source = "../../modules/ec2" + + stage = local.environment + + vpc_id = module.network.vpc_id + subnet_id = module.network.vpc_subnet_public[0].id + private_subnet_cidr = module.network.vpc_subnet_private[*].cidr_block + dns_zone_ooni_io = local.dns_zone_ooni_io + + key_name = module.adm_iam_roles.oonidevops_key_name + instance_type = "t3a.micro" + + name = "oonictzlab" + ingress_rules = [{ + from_port = 22, + to_port = 22, + protocol = "tcp", + cidr_blocks = ["0.0.0.0/0"], + }, { + from_port = 80, # for dehydrated challenge + to_port = 80, + protocol = "tcp", + cidr_blocks = ["0.0.0.0/0"], + }, { + // API endpoint + from_port = 443, + to_port = 443, + protocol = "tcp", + cidr_blocks = ["0.0.0.0/0"], + }, { + // For the prometheus proxy: + from_port = 9200, + to_port = 9200, + protocol = "tcp" + cidr_blocks = [for ip in flatten(data.dns_a_record_set.monitoring_host.*.addrs) : "${tostring(ip)}/32"] + }, { + from_port = 9100, + to_port = 9100, + protocol = "tcp" + cidr_blocks = ["${module.ooni_monitoring_proxy.aws_instance_private_ip}/32"] + }] + + egress_rules = [{ + from_port = 0, + to_port = 0, + protocol = "-1", + cidr_blocks = ["0.0.0.0/0"], + }, { + from_port = 0, + to_port = 0, + protocol = "-1", + ipv6_cidr_blocks = ["::/0"] + }] + + sg_prefix = "ooniciti" + tg_prefix = "citi" + + disk_size = 20 + + tags = merge( + local.tags, + { Name = "ooni-tier2-citizenlab" } + ) +} + +resource "aws_route53_record" "citizenlab_alias" { + zone_id = local.dns_zone_ooni_io + name = "citiz.${local.environment}.ooni.io" + type = "CNAME" + ttl = 300 + + records = [ + module.ooniapi_citizenlab.aws_instance_public_dns + ] +} + +module "citizenlab_builder" { + source = "../../modules/ooni_docker_build" + trigger_tag = "" + + service_name = "citizenlab" + repo = "ooni/backend" + branch_name = "add_citizenlab_url_management_with_porcelain" + buildspec_path = "ooniapi/services/citizenlab/buildspec.yml" + trigger_path = "ooniapi/services/citizenlab/**" + codestar_connection_arn = aws_codestarconnections_connection.oonidevops.arn + + codepipeline_bucket = aws_s3_bucket.ooniapi_codepipeline_bucket.bucket + + ecs_cluster_name = module.ooniapi_cluster.cluster_name +} + #### OONI Tier0 API Frontend module "ooniapi_frontend" { @@ -1164,6 +1259,7 @@ module "ooniapi_frontend" { ooniapi_ooniprobe_target_group_arn = module.ooniapi_ooniprobe.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_citizenlab_target_group_arn = module.ooniapi_citizenlab.alb_target_group_id ooniapi_service_security_groups = [ module.ooniapi_cluster.web_security_group_id, @@ -1190,6 +1286,7 @@ locals { "oonirun.${local.environment}.ooni.io" : local.dns_zone_ooni_io, "oonimeasurements.${local.environment}.ooni.io" : local.dns_zone_ooni_io, "8.th.dev.ooni.io" : local.dns_zone_ooni_io, + "citizenlab.${local.environment}.ooni.io" : local.dns_zone_ooni_io, } ooniapi_frontend_main_domain_name = "api.${local.environment}.ooni.io" ooniapi_frontend_main_domain_name_zone_id = local.dns_zone_ooni_io diff --git a/tf/modules/ec2/outputs.tf b/tf/modules/ec2/outputs.tf index a09c3362..4aa12946 100644 --- a/tf/modules/ec2/outputs.tf +++ b/tf/modules/ec2/outputs.tf @@ -16,4 +16,8 @@ output "aws_instance_private_ip" { output "aws_instance_public_ip" { value = aws_instance.ooni_ec2.public_ip -} \ No newline at end of file +} + +output "alb_target_group_id" { + value = aws_alb_target_group.ooni_ec2.id +} diff --git a/tf/modules/ooniapi_frontend/main.tf b/tf/modules/ooniapi_frontend/main.tf index d8ba5b87..9b3e3880 100644 --- a/tf/modules/ooniapi_frontend/main.tf +++ b/tf/modules/ooniapi_frontend/main.tf @@ -477,3 +477,45 @@ resource "aws_lb_listener_rule" "ooniapi_oonimeasurements_rule_2" { } } } + +resource "aws_lb_listener_rule" "ooniapi_citizenlab_rule" { + listener_arn = aws_alb_listener.ooniapi_listener_https.arn + priority = 143 + + action { + type = "forward" + target_group_arn = var.ooniapi_citizenlab_target_group_arn + } + condition { + path_pattern { + values = [ + "/api/_/url-submission/test-list/*", + "/api/_/url-priorities/list", + "/api/_/url-priorities/update", + "/api/v1/url-submission/submit", + "/api/v1/url-submission/update-url", + ] + } + } +} + +#resource "aws_lb_listener_rule" "ooniapi_citizenlab_rule" { +# listener_arn = aws_alb_listener.ooniapi_listener_https.arn +# priority = 143 +# +# action { +# type = "forward" +# target_group_arn = var.ooniapi_citizenlab_target_group_arn +# } +# condition { +# path_pattern { +# values = [ +# "/api/_/url-submission/test-list/*", +# "/api/_/url-priorities/list", +# "/api/_/url-priorities/update", +# "/api/v1/url-submission/submit", +# "/api/v1/url-submission/update-url", +# ] +# } +# } +#} diff --git a/tf/modules/ooniapi_frontend/variables.tf b/tf/modules/ooniapi_frontend/variables.tf index d4ec3dd0..2c676694 100644 --- a/tf/modules/ooniapi_frontend/variables.tf +++ b/tf/modules/ooniapi_frontend/variables.tf @@ -37,6 +37,10 @@ variable "ooniapi_oonimeasurements_target_group_arn" { default = null } +variable "ooniapi_citizenlab_target_group_arn" { + description = "arn for the target group of the citizenlab service" +} + variable "dns_zone_ooni_io" { description = "id of the DNS zone for ooni_io" } From 5bf1bfd367f61c0b0206378e2fbc236d6012f1cc Mon Sep 17 00:00:00 2001 From: Aaron Gibson Date: Mon, 9 Feb 2026 12:38:41 +0100 Subject: [PATCH 02/24] rename citizenlab to testlists --- ...oy-citizenlab.yml => deploy-testlists.yml} | 10 +-- ansible/deploy-tier2.yml | 4 +- ansible/inventory | 4 +- ansible/roles/ooni-backend/templates/api.conf | 2 +- .../roles/prometheus/templates/prometheus.yml | 6 +- .../defaults/main.yml | 8 +- .../handlers/main.yml | 0 .../{citizenlab => testlists}/tasks/main.yml | 80 +++++++++---------- .../templates/citizenlab.conf | 0 .../templates/nginx-api.conf | 2 +- tf/environments/dev/main.tf | 28 +++---- tf/modules/ooniapi_frontend/main.tf | 25 +----- tf/modules/ooniapi_frontend/variables.tf | 4 +- 13 files changed, 76 insertions(+), 97 deletions(-) rename ansible/{deploy-citizenlab.yml => deploy-testlists.yml} (78%) rename ansible/roles/{citizenlab => testlists}/defaults/main.yml (62%) rename ansible/roles/{citizenlab => testlists}/handlers/main.yml (100%) rename ansible/roles/{citizenlab => testlists}/tasks/main.yml (63%) rename ansible/roles/{citizenlab => testlists}/templates/citizenlab.conf (100%) rename ansible/roles/{citizenlab => testlists}/templates/nginx-api.conf (98%) diff --git a/ansible/deploy-citizenlab.yml b/ansible/deploy-testlists.yml similarity index 78% rename from ansible/deploy-citizenlab.yml rename to ansible/deploy-testlists.yml index a4a0fb9f..35ac064a 100644 --- a/ansible/deploy-citizenlab.yml +++ b/ansible/deploy-testlists.yml @@ -1,8 +1,8 @@ --- -- name: Deploy citizenlab +- name: Deploy testlists hosts: - - citiz.dev.ooni.io - - citiz.prod.ooni.io + - testlists.dev.ooni.io + - testlists.prod.ooni.io become: true roles: - role: bootstrap @@ -17,7 +17,7 @@ proxy_pass: http://127.0.0.1:9100/metrics - role: geerlingguy.docker docker_users: - - citizenlab + - testlists - ubuntu docker_package_state: latest - - role: citizenlab + - role: testlists diff --git a/ansible/deploy-tier2.yml b/ansible/deploy-tier2.yml index 79df612e..ae76ab04 100644 --- a/ansible/deploy-tier2.yml +++ b/ansible/deploy-tier2.yml @@ -9,8 +9,8 @@ - name: Include notebook playbook ansible.builtin.import_playbook: deploy-notebook.yml -- name: Include citizenlab playbook - ansible.builtin.import_playbook: deploy-citizenlab.yml +- name: Include testlists playbook + ansible.builtin.import_playbook: deploy-testlists.yml # commented out due to the fact it requires manual config of ~/.ssh/config #- name: Setup codesign box diff --git a/ansible/inventory b/ansible/inventory index af6de1cf..1434d217 100644 --- a/ansible/inventory +++ b/ansible/inventory @@ -49,5 +49,5 @@ fastpath.prod.ooni.io anonc.dev.ooni.io jumphost.dev.ooni.io jumphost.prod.ooni.io -citiz.dev.ooni.io -citiz.prod.ooni.io +testlists.dev.ooni.io +testlists.prod.ooni.io diff --git a/ansible/roles/ooni-backend/templates/api.conf b/ansible/roles/ooni-backend/templates/api.conf index 0ff0ca01..86ba04c2 100644 --- a/ansible/roles/ooni-backend/templates/api.conf +++ b/ansible/roles/ooni-backend/templates/api.conf @@ -48,7 +48,7 @@ MAIL_PASSWORD = "{{ mail_smtp_password }}" MAIL_SOURCE_ADDRESS = "contact@ooni.org" LOGIN_BASE_URL = "{{ login_base_url }}" -GITHUB_WORKDIR = "/var/lib/ooniapi/citizenlab" +GITHUB_WORKDIR = "/var/lib/ooniapi/testlists" GITHUB_TOKEN = "{{ github_token }}" GITHUB_USER = "ooni-bot" GITHUB_ORIGIN_REPO = "{{ github_origin_repo }}" diff --git a/ansible/roles/prometheus/templates/prometheus.yml b/ansible/roles/prometheus/templates/prometheus.yml index 0027b4ab..ebe5cb71 100755 --- a/ansible/roles/prometheus/templates/prometheus.yml +++ b/ansible/roles/prometheus/templates/prometheus.yml @@ -370,11 +370,11 @@ scrape_configs: target_label: "__metrics_path__" action: "replace" - - job_name: "citizenlab" + - job_name: "testlists" static_configs: - targets: - - citizenlab.dev.ooni.io:9102 - - citizenlab.prod.ooni.io:9102 + - testlists.dev.ooni.io:9102 + - testlists.prod.ooni.io:9102 scrape_interval: 5s scheme: https relabel_configs: # Change the host to the proxy host with relabeling diff --git a/ansible/roles/citizenlab/defaults/main.yml b/ansible/roles/testlists/defaults/main.yml similarity index 62% rename from ansible/roles/citizenlab/defaults/main.yml rename to ansible/roles/testlists/defaults/main.yml index 2d2dfa1c..b58d9932 100644 --- a/ansible/roles/citizenlab/defaults/main.yml +++ b/ansible/roles/testlists/defaults/main.yml @@ -1,6 +1,6 @@ -# citizenlab user -citizenlab_user: citizenlab -citizenlab_home: "/opt/{{ citizenlab_user }}" +# testlists user +testlists_user: testlists +testlists_home: "/opt/{{ testlists_user }}" -# citizenlab settings +# testlists settings clickhouse_url: "clickhouse://write:{{ lookup('amazon.aws.aws_ssm', '/oonidevops/secrets/clickhouse_write_password', profile='oonidevops_user_prod') }}@clickhouseproxy.dev.ooni.io/oonitest" diff --git a/ansible/roles/citizenlab/handlers/main.yml b/ansible/roles/testlists/handlers/main.yml similarity index 100% rename from ansible/roles/citizenlab/handlers/main.yml rename to ansible/roles/testlists/handlers/main.yml diff --git a/ansible/roles/citizenlab/tasks/main.yml b/ansible/roles/testlists/tasks/main.yml similarity index 63% rename from ansible/roles/citizenlab/tasks/main.yml rename to ansible/roles/testlists/tasks/main.yml index 23fb2d52..1fd0cd1d 100644 --- a/ansible/roles/citizenlab/tasks/main.yml +++ b/ansible/roles/testlists/tasks/main.yml @@ -29,60 +29,60 @@ notify: - reload nftables -# For incoming citizenlab traffic +# For incoming testlists traffic - name: Allow traffic on port 80 become: true - tags: citizenlab + tags: testlists blockinfile: path: /etc/ooni/nftables/tcp/80.nft create: yes block: | - add rule inet filter input tcp dport 80 counter accept comment "citizenlab" + add rule inet filter input tcp dport 80 counter accept comment "testlists" notify: - reload nftables -### Create citizenlab user -- name: Ensure the citizenlab group exists +### Create testlists user +- name: Ensure the testlists group exists ansible.builtin.group: - name: "{{ citizenlab_user }}" + name: "{{ testlists_user }}" state: present become: yes -- name: Create the citizenlab user +- name: Create the testlists user ansible.builtin.user: - name: "{{ citizenlab_user }}" - home: "{{ citizenlab_home }}" + name: "{{ testlists_user }}" + home: "{{ testlists_home }}" shell: "/bin/bash" - group: "{{ citizenlab_user }}" + group: "{{ testlists_user }}" create_home: yes system: yes become: yes -- name: Set ownership of the citizenlab directory +- name: Set ownership of the testlists directory ansible.builtin.file: - path: "{{ citizenlab_home }}" - owner: "{{ citizenlab_user }}" - group: "{{ citizenlab_user }}" + path: "{{ testlists_home }}" + owner: "{{ testlists_user }}" + group: "{{ testlists_user }}" state: directory mode: "0700" become: yes -### Run citizenlab -- name: Make sure that the citizenlab configuration directory exists +### Run testlists +- name: Make sure that the testlists configuration directory exists ansible.builtin.file: - path: /opt/{{citizenlab_user}}/backend/citizenlab/ + path: /opt/{{testlists_user}}/backend/testlists/ state: directory mode: "0700" - owner: "{{citizenlab_user}}" - group: "{{citizenlab_user}}" + owner: "{{testlists_user}}" + group: "{{testlists_user}}" - name: Create configuration file - tags: citizenlab + tags: testlists template: - src: templates/citizenlab.conf - dest: "/opt/{{citizenlab_user}}/backend/citizenlab/citizenlab.conf" + src: templates/testlists.conf + dest: "/opt/{{testlists_user}}/backend/testlists/testlists.conf" mode: "0400" - owner: "{{citizenlab_user}}" + owner: "{{testlists_user}}" become: yes - name: Ensure ooniapi directory existence @@ -90,16 +90,16 @@ path: /var/lib/ooniapi state: directory mode: "0711" - owner: "{{citizenlab_user}}" - group: "{{citizenlab_user}}" + owner: "{{testlists_user}}" + group: "{{testlists_user}}" -- name: Ensure citizenlab var dir exists +- name: Ensure testlists var dir exists ansible.builtin.file: - path: /var/lib/citizenlab + path: /var/lib/testlists state: directory mode: "0700" - owner: "{{citizenlab_user}}" - group: "{{citizenlab_user}}" + owner: "{{testlists_user}}" + group: "{{testlists_user}}" ## Nginx ## - name: Ensure /etc/nginx/sites-available directory exists @@ -111,7 +111,7 @@ group: root - name: Overwrite API nginx conf - tags: citizenlab + tags: testlists template: src: templates/nginx-api.conf dest: /etc/nginx/sites-available/ooni-api.conf @@ -122,36 +122,36 @@ certpath: /var/lib/dehydrated/certs/ - name: Create symlink for API nginx conf - tags: citizenlab + tags: testlists file: src=/etc/nginx/sites-available/ooni-api.conf dest=/etc/nginx/sites-enabled/ooni-api.conf state=link - name: Get UID of a specific user - command: id -u {{citizenlab_user}} + command: id -u {{testlists_user}} register: user_uid changed_when: false - name: Get GID of a specific user - command: id -g {{citizenlab_user}} + command: id -g {{testlists_user}} register: user_gid changed_when: false -- name: Ensure citizenlab is running +- name: Ensure testlists is running community.docker.docker_container: env: CLICKHOUSE_URL: "{{ clickhouse_url }}" - name: citizenlab - image: ooni/api-citizenlab:latest + name: testlists + image: ooni/api-testlists:latest state: started user: "{{user_uid.stdout}}:{{user_gid.stdout}}" - # use network mode = host to allow traffic from citizenlab to the statsd exporter without + # use network mode = host to allow traffic from testlists to the statsd exporter without # creating a network with redirection rules to match the ports network_mode: host volumes: - - /opt/{{citizenlab_user}}/backend/citizenlab/citizenlab.conf:/etc/ooni/citizenlab.conf + - /opt/{{testlists_user}}/backend/testlists/testlists.conf:/etc/ooni/testlists.conf - /var/lib/ooniapi:/var/lib/ooniapi - - /var/lib/citizenlab:/var/lib/citizenlab + - /var/lib/testlists:/var/lib/testlists tags: - - citizenlab + - testlists diff --git a/ansible/roles/citizenlab/templates/citizenlab.conf b/ansible/roles/testlists/templates/citizenlab.conf similarity index 100% rename from ansible/roles/citizenlab/templates/citizenlab.conf rename to ansible/roles/testlists/templates/citizenlab.conf diff --git a/ansible/roles/citizenlab/templates/nginx-api.conf b/ansible/roles/testlists/templates/nginx-api.conf similarity index 98% rename from ansible/roles/citizenlab/templates/nginx-api.conf rename to ansible/roles/testlists/templates/nginx-api.conf index f2f6704e..0ba953ec 100644 --- a/ansible/roles/citizenlab/templates/nginx-api.conf +++ b/ansible/roles/testlists/templates/nginx-api.conf @@ -1,5 +1,5 @@ # Managed by ansible -# roles/citizenlab/templates/nginx-api.conf +# roles/testlists/templates/nginx-api.conf # Use 2-level cache, 20MB of RAM + 5GB on disk, proxy_cache_path /var/cache/nginx/ooni-api levels=1:2 keys_zone=apicache:100M diff --git a/tf/environments/dev/main.tf b/tf/environments/dev/main.tf index abe48b41..3b7509dd 100644 --- a/tf/environments/dev/main.tf +++ b/tf/environments/dev/main.tf @@ -707,7 +707,7 @@ module "ooni_clickhouse_proxy" { to_port = 9000, protocol = "tcp", cidr_blocks = concat(module.network.vpc_subnet_private[*].cidr_block, ["${module.ooni_fastpath.aws_instance_private_ip}/32", "${module.ooni_fastpath.aws_instance_public_ip}/32"], - ["${module.ooniapi_citizenlab.aws_instance_private_ip}/32", "${module.ooniapi_citizenlab.aws_instance_public_ip}/32"]), + ["${module.ooniapi_testlists.aws_instance_private_ip}/32", "${module.ooniapi_testlists.aws_instance_public_ip}/32"]), }, { // For the prometheus proxy: from_port = 9200, @@ -1151,8 +1151,8 @@ module "ooniapi_oonimeasurements" { ) } -### Tier2 Citizenlab service -module "ooniapi_citizenlab" { +### Tier2 testlists service +module "ooniapi_testlists" { source = "../../modules/ec2" stage = local.environment @@ -1214,30 +1214,30 @@ module "ooniapi_citizenlab" { tags = merge( local.tags, - { Name = "ooni-tier2-citizenlab" } + { Name = "ooni-tier2-testlists" } ) } -resource "aws_route53_record" "citizenlab_alias" { +resource "aws_route53_record" "testlists_alias" { zone_id = local.dns_zone_ooni_io - name = "citiz.${local.environment}.ooni.io" + name = "testl.${local.environment}.ooni.io" type = "CNAME" ttl = 300 records = [ - module.ooniapi_citizenlab.aws_instance_public_dns + module.ooniapi_testlists.aws_instance_public_dns ] } -module "citizenlab_builder" { +module "testlists_builder" { source = "../../modules/ooni_docker_build" trigger_tag = "" - service_name = "citizenlab" + service_name = "testlists" repo = "ooni/backend" - branch_name = "add_citizenlab_url_management_with_porcelain" - buildspec_path = "ooniapi/services/citizenlab/buildspec.yml" - trigger_path = "ooniapi/services/citizenlab/**" + branch_name = "add_testlists_url_management" + buildspec_path = "ooniapi/services/testlists/buildspec.yml" + trigger_path = "ooniapi/services/testlists/**" codestar_connection_arn = aws_codestarconnections_connection.oonidevops.arn codepipeline_bucket = aws_s3_bucket.ooniapi_codepipeline_bucket.bucket @@ -1259,7 +1259,7 @@ module "ooniapi_frontend" { ooniapi_ooniprobe_target_group_arn = module.ooniapi_ooniprobe.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_citizenlab_target_group_arn = module.ooniapi_citizenlab.alb_target_group_id + ooniapi_testlists_target_group_arn = module.ooniapi_testlists.alb_target_group_id ooniapi_service_security_groups = [ module.ooniapi_cluster.web_security_group_id, @@ -1286,7 +1286,7 @@ locals { "oonirun.${local.environment}.ooni.io" : local.dns_zone_ooni_io, "oonimeasurements.${local.environment}.ooni.io" : local.dns_zone_ooni_io, "8.th.dev.ooni.io" : local.dns_zone_ooni_io, - "citizenlab.${local.environment}.ooni.io" : local.dns_zone_ooni_io, + "testlists.${local.environment}.ooni.io" : local.dns_zone_ooni_io, } ooniapi_frontend_main_domain_name = "api.${local.environment}.ooni.io" ooniapi_frontend_main_domain_name_zone_id = local.dns_zone_ooni_io diff --git a/tf/modules/ooniapi_frontend/main.tf b/tf/modules/ooniapi_frontend/main.tf index 9b3e3880..4b8ff069 100644 --- a/tf/modules/ooniapi_frontend/main.tf +++ b/tf/modules/ooniapi_frontend/main.tf @@ -478,13 +478,13 @@ resource "aws_lb_listener_rule" "ooniapi_oonimeasurements_rule_2" { } } -resource "aws_lb_listener_rule" "ooniapi_citizenlab_rule" { +resource "aws_lb_listener_rule" "ooniapi_testlists_rule" { listener_arn = aws_alb_listener.ooniapi_listener_https.arn priority = 143 action { type = "forward" - target_group_arn = var.ooniapi_citizenlab_target_group_arn + target_group_arn = var.ooniapi_testlists_target_group_arn } condition { path_pattern { @@ -498,24 +498,3 @@ resource "aws_lb_listener_rule" "ooniapi_citizenlab_rule" { } } } - -#resource "aws_lb_listener_rule" "ooniapi_citizenlab_rule" { -# listener_arn = aws_alb_listener.ooniapi_listener_https.arn -# priority = 143 -# -# action { -# type = "forward" -# target_group_arn = var.ooniapi_citizenlab_target_group_arn -# } -# condition { -# path_pattern { -# values = [ -# "/api/_/url-submission/test-list/*", -# "/api/_/url-priorities/list", -# "/api/_/url-priorities/update", -# "/api/v1/url-submission/submit", -# "/api/v1/url-submission/update-url", -# ] -# } -# } -#} diff --git a/tf/modules/ooniapi_frontend/variables.tf b/tf/modules/ooniapi_frontend/variables.tf index 2c676694..58b227ff 100644 --- a/tf/modules/ooniapi_frontend/variables.tf +++ b/tf/modules/ooniapi_frontend/variables.tf @@ -37,8 +37,8 @@ variable "ooniapi_oonimeasurements_target_group_arn" { default = null } -variable "ooniapi_citizenlab_target_group_arn" { - description = "arn for the target group of the citizenlab service" +variable "ooniapi_testlists_target_group_arn" { + description = "arn for the target group of the testlists service" } variable "dns_zone_ooni_io" { From 452daa3fdee7793ff737d3471f7cbdd7c4645e08 Mon Sep 17 00:00:00 2001 From: Aaron Gibson Date: Mon, 9 Feb 2026 14:54:45 +0100 Subject: [PATCH 03/24] rename inventory testlists to testl (ec2 instance) --- ansible/deploy-testlists.yml | 4 ++-- ansible/inventory | 4 ++-- .../testlists/templates/{citizenlab.conf => testlists.conf} | 0 3 files changed, 4 insertions(+), 4 deletions(-) rename ansible/roles/testlists/templates/{citizenlab.conf => testlists.conf} (100%) diff --git a/ansible/deploy-testlists.yml b/ansible/deploy-testlists.yml index 35ac064a..28de7a6d 100644 --- a/ansible/deploy-testlists.yml +++ b/ansible/deploy-testlists.yml @@ -1,8 +1,8 @@ --- - name: Deploy testlists hosts: - - testlists.dev.ooni.io - - testlists.prod.ooni.io + - testl.dev.ooni.io + - testl.prod.ooni.io become: true roles: - role: bootstrap diff --git a/ansible/inventory b/ansible/inventory index 1434d217..a270ee4b 100644 --- a/ansible/inventory +++ b/ansible/inventory @@ -49,5 +49,5 @@ fastpath.prod.ooni.io anonc.dev.ooni.io jumphost.dev.ooni.io jumphost.prod.ooni.io -testlists.dev.ooni.io -testlists.prod.ooni.io +testl.dev.ooni.io +testl.prod.ooni.io diff --git a/ansible/roles/testlists/templates/citizenlab.conf b/ansible/roles/testlists/templates/testlists.conf similarity index 100% rename from ansible/roles/testlists/templates/citizenlab.conf rename to ansible/roles/testlists/templates/testlists.conf From 6db851e572ff45d69eb5b68bd361282ed2ab6a5c Mon Sep 17 00:00:00 2001 From: Aaron Gibson Date: Wed, 11 Feb 2026 10:32:59 +0100 Subject: [PATCH 04/24] testlists: remove unused paths; create necessary paths --- ansible/roles/testlists/tasks/main.yml | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/ansible/roles/testlists/tasks/main.yml b/ansible/roles/testlists/tasks/main.yml index 1fd0cd1d..5085c191 100644 --- a/ansible/roles/testlists/tasks/main.yml +++ b/ansible/roles/testlists/tasks/main.yml @@ -68,22 +68,6 @@ become: yes ### Run testlists -- name: Make sure that the testlists configuration directory exists - ansible.builtin.file: - path: /opt/{{testlists_user}}/backend/testlists/ - state: directory - mode: "0700" - owner: "{{testlists_user}}" - group: "{{testlists_user}}" - -- name: Create configuration file - tags: testlists - template: - src: templates/testlists.conf - dest: "/opt/{{testlists_user}}/backend/testlists/testlists.conf" - mode: "0400" - owner: "{{testlists_user}}" - become: yes - name: Ensure ooniapi directory existence ansible.builtin.file: @@ -93,9 +77,9 @@ owner: "{{testlists_user}}" group: "{{testlists_user}}" -- name: Ensure testlists var dir exists +- name: Ensure testlists users var dir exists ansible.builtin.file: - path: /var/lib/testlists + path: /var/lib/ooniapi/testlists/users state: directory mode: "0700" owner: "{{testlists_user}}" From 8c86346d9de81256e25741bba12afa11ec0ea606 Mon Sep 17 00:00:00 2001 From: Aaron Gibson Date: Wed, 11 Feb 2026 10:33:29 +0100 Subject: [PATCH 05/24] testlists: remove certpath / dehydrated --- ansible/roles/testlists/tasks/main.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/ansible/roles/testlists/tasks/main.yml b/ansible/roles/testlists/tasks/main.yml index 5085c191..2be7a4f7 100644 --- a/ansible/roles/testlists/tasks/main.yml +++ b/ansible/roles/testlists/tasks/main.yml @@ -101,9 +101,6 @@ dest: /etc/nginx/sites-available/ooni-api.conf mode: 0755 owner: root - vars: - # Uses dehydrated - certpath: /var/lib/dehydrated/certs/ - name: Create symlink for API nginx conf tags: testlists From f29f52cda0c85410ae67f5f04634197f0fdf4f3f Mon Sep 17 00:00:00 2001 From: Aaron Gibson Date: Wed, 11 Feb 2026 10:33:53 +0100 Subject: [PATCH 06/24] testlists: squashme remove unused paths --- ansible/roles/testlists/tasks/main.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/ansible/roles/testlists/tasks/main.yml b/ansible/roles/testlists/tasks/main.yml index 2be7a4f7..07377c18 100644 --- a/ansible/roles/testlists/tasks/main.yml +++ b/ansible/roles/testlists/tasks/main.yml @@ -131,8 +131,6 @@ # creating a network with redirection rules to match the ports network_mode: host volumes: - - /opt/{{testlists_user}}/backend/testlists/testlists.conf:/etc/ooni/testlists.conf - /var/lib/ooniapi:/var/lib/ooniapi - - /var/lib/testlists:/var/lib/testlists tags: - testlists From 4c72ebfff354da0235f2c15ae831a88d1927cff8 Mon Sep 17 00:00:00 2001 From: Aaron Gibson Date: Wed, 11 Feb 2026 10:34:18 +0100 Subject: [PATCH 07/24] testlists: add jwt_encryption_key and github_token to host_vars --- ansible/host_vars/testl.dev.ooni.io/vars.yml | 2 ++ ansible/host_vars/testl.prod.ooni.io/vars.yml | 1 + 2 files changed, 3 insertions(+) create mode 100644 ansible/host_vars/testl.dev.ooni.io/vars.yml create mode 100644 ansible/host_vars/testl.prod.ooni.io/vars.yml diff --git a/ansible/host_vars/testl.dev.ooni.io/vars.yml b/ansible/host_vars/testl.dev.ooni.io/vars.yml new file mode 100644 index 00000000..ab19bea5 --- /dev/null +++ b/ansible/host_vars/testl.dev.ooni.io/vars.yml @@ -0,0 +1,2 @@ +jwt_encryption_key: "{{ lookup('amazon.aws.aws_ssm', '/oonidevops/secrets/ooni_services/jwt_secret', profile='oonidevops_user_dev') }}" +github_token: "{{ lookup('amazon.aws.aws_secret', 'oonidevops/ooni_services/testlists_github_token', profile='oonidevops_user_dev') }}" diff --git a/ansible/host_vars/testl.prod.ooni.io/vars.yml b/ansible/host_vars/testl.prod.ooni.io/vars.yml new file mode 100644 index 00000000..b7960e20 --- /dev/null +++ b/ansible/host_vars/testl.prod.ooni.io/vars.yml @@ -0,0 +1 @@ +jwt_encryption_key: "{{ lookup('amazon.aws.aws_ssm', '/oonidevops/secrets/ooni_services/jwt_secret', profile='oonidevops_user_prod') }}" From df511e49e61cb6dd6ffc738630ff8b7115772d4a Mon Sep 17 00:00:00 2001 From: Aaron Gibson Date: Wed, 11 Feb 2026 10:39:33 +0100 Subject: [PATCH 08/24] testlists: add environment config variables USER and EMAIL configure the git author when making commits WORKING_DIR is the root of path where repo is cloned and user data lives PUSH_REPO is where PR branches are pushed ORIGIN_REPO is the upstream repo where PRs are opened --- ansible/host_vars/testl.dev.ooni.io/vars.yml | 1 + ansible/host_vars/testl.prod.ooni.io/vars.yml | 1 + ansible/roles/testlists/tasks/main.yml | 10 ++++++++++ 3 files changed, 12 insertions(+) diff --git a/ansible/host_vars/testl.dev.ooni.io/vars.yml b/ansible/host_vars/testl.dev.ooni.io/vars.yml index ab19bea5..7ab99273 100644 --- a/ansible/host_vars/testl.dev.ooni.io/vars.yml +++ b/ansible/host_vars/testl.dev.ooni.io/vars.yml @@ -1,2 +1,3 @@ jwt_encryption_key: "{{ lookup('amazon.aws.aws_ssm', '/oonidevops/secrets/ooni_services/jwt_secret', profile='oonidevops_user_dev') }}" github_token: "{{ lookup('amazon.aws.aws_secret', 'oonidevops/ooni_services/testlists_github_token', profile='oonidevops_user_dev') }}" +log_level: "debug" diff --git a/ansible/host_vars/testl.prod.ooni.io/vars.yml b/ansible/host_vars/testl.prod.ooni.io/vars.yml index b7960e20..be6bdee6 100644 --- a/ansible/host_vars/testl.prod.ooni.io/vars.yml +++ b/ansible/host_vars/testl.prod.ooni.io/vars.yml @@ -1 +1,2 @@ jwt_encryption_key: "{{ lookup('amazon.aws.aws_ssm', '/oonidevops/secrets/ooni_services/jwt_secret', profile='oonidevops_user_prod') }}" +log_level: "info" diff --git a/ansible/roles/testlists/tasks/main.yml b/ansible/roles/testlists/tasks/main.yml index 07377c18..308633b7 100644 --- a/ansible/roles/testlists/tasks/main.yml +++ b/ansible/roles/testlists/tasks/main.yml @@ -123,6 +123,16 @@ community.docker.docker_container: env: CLICKHOUSE_URL: "{{ clickhouse_url }}" + JWT_ENCRYPTION_KEY: "{{ jwt_encryption_key }}" + WORKING_DIR: "/var/lib/ooniapi/testlists" + GITHUB_TOKEN: "{{ github_token }}" + GITHUB_USER: "ooni-bot" + ORIGIN_REPO: "citizenlab/test-lists" + PUSH_REPO: "ooni/test-lists" + LOG_LEVEL: "{{ log_level }}" + USER: "ooniapi" + EMAIL: "ooniapi@test-lists.ooni.org" + name: testlists image: ooni/api-testlists:latest state: started From 084f1875470beda56509101a7f20dc8a3ee3066b Mon Sep 17 00:00:00 2001 From: Aaron Gibson Date: Thu, 12 Feb 2026 10:11:16 +0100 Subject: [PATCH 09/24] add github_token to host vars for testl.prod.ooni.io --- ansible/host_vars/testl.prod.ooni.io/vars.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/ansible/host_vars/testl.prod.ooni.io/vars.yml b/ansible/host_vars/testl.prod.ooni.io/vars.yml index be6bdee6..4a8d32d5 100644 --- a/ansible/host_vars/testl.prod.ooni.io/vars.yml +++ b/ansible/host_vars/testl.prod.ooni.io/vars.yml @@ -1,2 +1,3 @@ jwt_encryption_key: "{{ lookup('amazon.aws.aws_ssm', '/oonidevops/secrets/ooni_services/jwt_secret', profile='oonidevops_user_prod') }}" +github_token: "{{ lookup('amazon.aws.aws_secret', 'oonidevops/ooni_services/testlists_github_token', profile='oonidevops_user_prod') }}" log_level: "info" From c08e1c643fa45c1cc3d7262527b14924cc3f6692 Mon Sep 17 00:00:00 2001 From: Aaron Gibson Date: Thu, 12 Feb 2026 10:12:59 +0100 Subject: [PATCH 10/24] rename from oonictzlab to oonitestlists, update sg_prefix and tg_prefix --- tf/environments/dev/main.tf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tf/environments/dev/main.tf b/tf/environments/dev/main.tf index 3b7509dd..76b13796 100644 --- a/tf/environments/dev/main.tf +++ b/tf/environments/dev/main.tf @@ -1165,7 +1165,7 @@ module "ooniapi_testlists" { key_name = module.adm_iam_roles.oonidevops_key_name instance_type = "t3a.micro" - name = "oonictzlab" + name = "oonitestlists" ingress_rules = [{ from_port = 22, to_port = 22, @@ -1207,8 +1207,8 @@ module "ooniapi_testlists" { ipv6_cidr_blocks = ["::/0"] }] - sg_prefix = "ooniciti" - tg_prefix = "citi" + sg_prefix = "oonitestl" + tg_prefix = "tstl" disk_size = 20 From a5a31231c8cf5af472cc5522bf2bf91b1405320d Mon Sep 17 00:00:00 2001 From: Aaron Gibson Date: Thu, 12 Feb 2026 10:15:10 +0100 Subject: [PATCH 11/24] remove port 443, unused, remove dehydrated comment --- tf/environments/dev/main.tf | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/tf/environments/dev/main.tf b/tf/environments/dev/main.tf index 76b13796..5cc48384 100644 --- a/tf/environments/dev/main.tf +++ b/tf/environments/dev/main.tf @@ -1172,17 +1172,11 @@ module "ooniapi_testlists" { protocol = "tcp", cidr_blocks = ["0.0.0.0/0"], }, { - from_port = 80, # for dehydrated challenge + from_port = 80, to_port = 80, protocol = "tcp", cidr_blocks = ["0.0.0.0/0"], }, { - // API endpoint - from_port = 443, - to_port = 443, - protocol = "tcp", - cidr_blocks = ["0.0.0.0/0"], - }, { // For the prometheus proxy: from_port = 9200, to_port = 9200, From b844edd30af1e1267216375ededc4bcc55dc0033 Mon Sep 17 00:00:00 2001 From: Aaron Gibson Date: Thu, 12 Feb 2026 12:13:49 +0100 Subject: [PATCH 12/24] reload nginx after copying config --- ansible/roles/testlists/tasks/main.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ansible/roles/testlists/tasks/main.yml b/ansible/roles/testlists/tasks/main.yml index 308633b7..f5903493 100644 --- a/ansible/roles/testlists/tasks/main.yml +++ b/ansible/roles/testlists/tasks/main.yml @@ -108,6 +108,8 @@ src=/etc/nginx/sites-available/ooni-api.conf dest=/etc/nginx/sites-enabled/ooni-api.conf state=link + notify: + - reload nginx - name: Get UID of a specific user command: id -u {{testlists_user}} From 432a5bcd7e0da7f46eac5679318298eaca8cc42e Mon Sep 17 00:00:00 2001 From: Aaron Gibson Date: Thu, 12 Feb 2026 12:14:58 +0100 Subject: [PATCH 13/24] remove unused cfg --- .../roles/testlists/templates/testlists.conf | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 ansible/roles/testlists/templates/testlists.conf diff --git a/ansible/roles/testlists/templates/testlists.conf b/ansible/roles/testlists/templates/testlists.conf deleted file mode 100644 index 54ec9d7e..00000000 --- a/ansible/roles/testlists/templates/testlists.conf +++ /dev/null @@ -1,19 +0,0 @@ -[DEFAULT] -# Collector hostnames, comma separated -collectors = localhost - - -{% if psql_uri is defined %} -# The password is already made public -db_uri = {{ psql_uri }} -{% else %} -db_uri = -{% endif %} - -# S3 access credentials -# Currently unused -s3_access_key = -s3_secret_key = - - -clickhouse_url = {{clickhouse_url}} From a82fc192e5fde7bffbf861d69152d28291368508 Mon Sep 17 00:00:00 2001 From: Aaron Gibson Date: Thu, 12 Feb 2026 12:22:43 +0100 Subject: [PATCH 14/24] testlists: listen on 443, obtain certificate --- ansible/deploy-testlists.yml | 5 +++++ ansible/roles/testlists/tasks/main.yml | 3 +++ ansible/roles/testlists/templates/nginx-api.conf | 15 ++++++++++----- tf/environments/dev/main.tf | 5 +++++ 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/ansible/deploy-testlists.yml b/ansible/deploy-testlists.yml index 28de7a6d..56a1fab9 100644 --- a/ansible/deploy-testlists.yml +++ b/ansible/deploy-testlists.yml @@ -6,6 +6,11 @@ become: true roles: - role: bootstrap + - role: dehydrated + vars: + ssl_domains: + - "{{ inventory_hostname }}" + tls_cert_dir: /var/lib/dehydrated/certs - role: nginx - role: prometheus_node_exporter vars: diff --git a/ansible/roles/testlists/tasks/main.yml b/ansible/roles/testlists/tasks/main.yml index f5903493..62bc4bb6 100644 --- a/ansible/roles/testlists/tasks/main.yml +++ b/ansible/roles/testlists/tasks/main.yml @@ -101,6 +101,9 @@ dest: /etc/nginx/sites-available/ooni-api.conf mode: 0755 owner: root + vars: + # Uses dehydrated + certpath: /var/lib/dehydrated/certs/ - name: Create symlink for API nginx conf tags: testlists diff --git a/ansible/roles/testlists/templates/nginx-api.conf b/ansible/roles/testlists/templates/nginx-api.conf index 0ba953ec..765322ca 100644 --- a/ansible/roles/testlists/templates/nginx-api.conf +++ b/ansible/roles/testlists/templates/nginx-api.conf @@ -25,13 +25,10 @@ log_format ooni_api_fmt '$remote_addr_anon $remote_fwd_anon $upstream_cache_stat '"$request" $status snt:$body_bytes_sent rt:$request_time uprt:$upstream_response_time "$http_referer" "$http_user_agent"'; server { - # TODO(bassosimone): we need support for cleartext HTTP to make sure that requests - # over Tor correctly land to the proper backend. We are listening on this custom port - # and we are configuring Tor such that it routes traffic to this port. - listen 127.0.0.1:17744; - listen 80 http2 default_server; listen [::]:80 http2 default_server; + listen 443 ssl http2 default_server; + listen [::]:443 ssl http2 default_server; server_name _; access_log syslog:server=unix:/dev/log,tag=ooniapi,severity=info ooni_api_fmt; error_log syslog:server=unix:/dev/log,tag=ooniapi,severity=info; @@ -42,12 +39,20 @@ server { # and everyhing else client_max_body_size 200M; # for measurement POST + ssl_certificate {{ certpath }}{{ inventory_hostname }}/fullchain.pem; + ssl_certificate_key {{ certpath }}{{ inventory_hostname }}/privkey.pem; + ssl_trusted_certificate {{ certpath }}{{ inventory_hostname }}/chain.pem; # for ssl_stapling_verify + # Use the intermediate configuration to support legacy probes # https://ssl-config.mozilla.org/#server=nginx&version=1.14.2&config=intermediate&openssl=1.1.1d&guideline=5.6 ssl_session_timeout 5m; ssl_session_cache shared:MozSSL:30m; ssl_session_tickets off; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; + ssl_prefer_server_ciphers off; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header X-Frame-Options DENY always; add_header X-Content-Type-Options nosniff always; diff --git a/tf/environments/dev/main.tf b/tf/environments/dev/main.tf index 5cc48384..28005460 100644 --- a/tf/environments/dev/main.tf +++ b/tf/environments/dev/main.tf @@ -1177,6 +1177,11 @@ module "ooniapi_testlists" { protocol = "tcp", cidr_blocks = ["0.0.0.0/0"], }, { + from_port = 443, + to_port = 443, + protocol = "tcp", + cidr_blocks = ["0.0.0.0/0"], + }, { // For the prometheus proxy: from_port = 9200, to_port = 9200, From ed74811925061ffd1356058283c0aec9c61d4265 Mon Sep 17 00:00:00 2001 From: Aaron Gibson Date: Thu, 12 Feb 2026 13:23:50 +0100 Subject: [PATCH 15/24] install nginx before dehydrated, restart nginx this seems to fix dehydrated failing to run and obtain certificates --- ansible/deploy-testlists.yml | 2 +- ansible/roles/testlists/tasks/main.yml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ansible/deploy-testlists.yml b/ansible/deploy-testlists.yml index 56a1fab9..de636c51 100644 --- a/ansible/deploy-testlists.yml +++ b/ansible/deploy-testlists.yml @@ -6,12 +6,12 @@ become: true roles: - role: bootstrap + - role: nginx - role: dehydrated vars: ssl_domains: - "{{ inventory_hostname }}" tls_cert_dir: /var/lib/dehydrated/certs - - role: nginx - role: prometheus_node_exporter vars: use_https: false diff --git a/ansible/roles/testlists/tasks/main.yml b/ansible/roles/testlists/tasks/main.yml index 62bc4bb6..9b402aa1 100644 --- a/ansible/roles/testlists/tasks/main.yml +++ b/ansible/roles/testlists/tasks/main.yml @@ -113,6 +113,7 @@ state=link notify: - reload nginx + - restart nginx - name: Get UID of a specific user command: id -u {{testlists_user}} From 20db23a3bd8e7d241c717130cdac7bfc450537eb Mon Sep 17 00:00:00 2001 From: Aaron Gibson Date: Wed, 18 Feb 2026 11:17:07 +0100 Subject: [PATCH 16/24] remove dehydrated role from prometheus_node_exporter role and nginx role from testlists TODO: may need to modify scheme for metrics collector --- ansible/deploy-testlists.yml | 6 - .../prometheus_node_exporter/tasks/main.yml | 9 -- ansible/roles/testlists/handlers/main.yml | 16 --- ansible/roles/testlists/tasks/main.yml | 34 ----- .../roles/testlists/templates/nginx-api.conf | 123 ------------------ 5 files changed, 188 deletions(-) delete mode 100644 ansible/roles/testlists/templates/nginx-api.conf diff --git a/ansible/deploy-testlists.yml b/ansible/deploy-testlists.yml index de636c51..98dc7525 100644 --- a/ansible/deploy-testlists.yml +++ b/ansible/deploy-testlists.yml @@ -6,12 +6,6 @@ become: true roles: - role: bootstrap - - role: nginx - - role: dehydrated - vars: - ssl_domains: - - "{{ inventory_hostname }}" - tls_cert_dir: /var/lib/dehydrated/certs - role: prometheus_node_exporter vars: use_https: false diff --git a/ansible/roles/prometheus_node_exporter/tasks/main.yml b/ansible/roles/prometheus_node_exporter/tasks/main.yml index c79a618e..3a56b273 100644 --- a/ansible/roles/prometheus_node_exporter/tasks/main.yml +++ b/ansible/roles/prometheus_node_exporter/tasks/main.yml @@ -4,15 +4,6 @@ - nginx - node_exporter -- ansible.builtin.include_role: - name: dehydrated - tags: - - oonidata - - dehydrated - vars: - ssl_domains: - - "{{ inventory_hostname }}" - - include_tasks: install.yml - name: create ooni configuration directory diff --git a/ansible/roles/testlists/handlers/main.yml b/ansible/roles/testlists/handlers/main.yml index 5c8f17dd..d44c00f4 100644 --- a/ansible/roles/testlists/handlers/main.yml +++ b/ansible/roles/testlists/handlers/main.yml @@ -1,19 +1,3 @@ -- name: test nginx config - command: /usr/sbin/nginx -t -c /etc/nginx/nginx.conf - listen: - - restart nginx - - reload nginx - -- name: restart nginx - service: - name: nginx - state: restarted - -- name: reload nginx - service: - name: nginx - state: reloaded - - name: reload nftables tags: nftables ansible.builtin.systemd_service: diff --git a/ansible/roles/testlists/tasks/main.yml b/ansible/roles/testlists/tasks/main.yml index 9b402aa1..4a7b5dc9 100644 --- a/ansible/roles/testlists/tasks/main.yml +++ b/ansible/roles/testlists/tasks/main.yml @@ -14,10 +14,6 @@ notify: - reload nftables -# For statsd importer metrics -- name: Flush all handlers - meta: flush_handlers - - name: Allow traffic on port 9102 become: true tags: prometheus-proxy @@ -85,36 +81,6 @@ owner: "{{testlists_user}}" group: "{{testlists_user}}" -## Nginx ## -- name: Ensure /etc/nginx/sites-available directory exists - file: - path: /etc/nginx/sites-available - state: directory - mode: '0755' - owner: root - group: root - -- name: Overwrite API nginx conf - tags: testlists - template: - src: templates/nginx-api.conf - dest: /etc/nginx/sites-available/ooni-api.conf - mode: 0755 - owner: root - vars: - # Uses dehydrated - certpath: /var/lib/dehydrated/certs/ - -- name: Create symlink for API nginx conf - tags: testlists - file: - src=/etc/nginx/sites-available/ooni-api.conf - dest=/etc/nginx/sites-enabled/ooni-api.conf - state=link - notify: - - reload nginx - - restart nginx - - name: Get UID of a specific user command: id -u {{testlists_user}} register: user_uid diff --git a/ansible/roles/testlists/templates/nginx-api.conf b/ansible/roles/testlists/templates/nginx-api.conf deleted file mode 100644 index 765322ca..00000000 --- a/ansible/roles/testlists/templates/nginx-api.conf +++ /dev/null @@ -1,123 +0,0 @@ -# Managed by ansible -# roles/testlists/templates/nginx-api.conf - -# Use 2-level cache, 20MB of RAM + 5GB on disk, -proxy_cache_path /var/cache/nginx/ooni-api levels=1:2 keys_zone=apicache:100M - max_size=5g inactive=24h use_temp_path=off; - -# anonymize ipaddr -map $remote_addr $remote_addr_anon { - ~(?P\d+\.\d+\.\d+)\. $ip.0; - ~(?P[^:]+:[^:]+): $ip::; - default 0.0.0.0; -} - -# anonymize forwarded ipaddr -map $http_x_forwarded_for $remote_fwd_anon { - ~(?P\d+\.\d+\.\d+)\. $ip.0; - ~(?P[^:]+:[^:]+): $ip::; - default 0.0.0.0; -} - - -# log anonymized ipaddr and caching status -log_format ooni_api_fmt '$remote_addr_anon $remote_fwd_anon $upstream_cache_status [$time_local] ' - '"$request" $status snt:$body_bytes_sent rt:$request_time uprt:$upstream_response_time "$http_referer" "$http_user_agent"'; - -server { - listen 80 http2 default_server; - listen [::]:80 http2 default_server; - listen 443 ssl http2 default_server; - listen [::]:443 ssl http2 default_server; - server_name _; - access_log syslog:server=unix:/dev/log,tag=ooniapi,severity=info ooni_api_fmt; - error_log syslog:server=unix:/dev/log,tag=ooniapi,severity=info; - gzip on; - gzip_types text/plain application/xml application/json; - - # TODO: we could use different client_max_body_size and SSL configurations for probe service paths - # and everyhing else - client_max_body_size 200M; # for measurement POST - - ssl_certificate {{ certpath }}{{ inventory_hostname }}/fullchain.pem; - ssl_certificate_key {{ certpath }}{{ inventory_hostname }}/privkey.pem; - ssl_trusted_certificate {{ certpath }}{{ inventory_hostname }}/chain.pem; # for ssl_stapling_verify - - # Use the intermediate configuration to support legacy probes - # https://ssl-config.mozilla.org/#server=nginx&version=1.14.2&config=intermediate&openssl=1.1.1d&guideline=5.6 - ssl_session_timeout 5m; - ssl_session_cache shared:MozSSL:30m; - ssl_session_tickets off; - - ssl_protocols TLSv1.2 TLSv1.3; - ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; - ssl_prefer_server_ciphers off; - - add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; - add_header X-Frame-Options DENY always; - add_header X-Content-Type-Options nosniff always; - - # OCSP stapling - ssl_stapling on; - ssl_stapling_verify on; - - # verify chain of trust of OCSP response using Root CA and Intermediate certs - #ssl_trusted_certificate /path/to/root_CA_cert_plus_intermediates; - - location /whoami { - return 200 "{{ inventory_hostname }}"; - } - - location /metrics { - return 200 ''; - } - - # new API - location / { - - # Protect /apidocs invoked with url= and/or urls= args - if ($uri ~ "^/apidocs") { set $block_apidocs X; } - if ($args ~ "url=" ) { set $block_apidocs "${block_apidocs}Y"; } - if ($args ~ "urls=" ) { set $block_apidocs "${block_apidocs}Y"; } - if ($block_apidocs ~ "XY") { return 403; } # nested "if" are not supported - - deny 216.244.66.0/24; # DotBot/1.2 - deny 114.119.128.0/19; # PetalBot - allow all; - proxy_pass http://127.0.0.1:8000; - proxy_set_header Host $host; - - set $external_remote_addr $remote_addr; - if ($remote_addr ~ "^3.") { - # If remote_addr is AWS trust the X-Real-IP header - set $external_remote_addr $http_x_real_ip; - } - proxy_set_header X-Real-IP $external_remote_addr; - - proxy_cache apicache; - proxy_cache_min_uses 1; - proxy_cache_lock on; - proxy_cache_lock_timeout 30; - proxy_cache_lock_age 30; - proxy_cache_use_stale error timeout invalid_header updating; - proxy_cache_methods HEAD GET; - # Cache only 200, 301, and 302 by default and for very short. - # Overridden by the API using the Expires header - proxy_cache_valid 200 301 302 10s; - proxy_cache_valid any 0; - add_header x-cache-status $upstream_cache_status; - add_header X-Cache-Status $upstream_cache_status; - add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; - add_header X-Frame-Options DENY always; - add_header X-Content-Type-Options nosniff always; - } -} - -# Used by Netdata to monitor Nginx -server { - listen 127.0.0.1:80; - server_name localhost; - location = /stub_status { - stub_status; - } -} From 04a5137a3b6e3ab0966c59dea4f6c8b56d8a99c6 Mon Sep 17 00:00:00 2001 From: Aaron Gibson Date: Wed, 18 Feb 2026 17:11:04 +0100 Subject: [PATCH 17/24] remove unused firewall allow on port 9102 --- ansible/roles/testlists/tasks/main.yml | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/ansible/roles/testlists/tasks/main.yml b/ansible/roles/testlists/tasks/main.yml index 4a7b5dc9..a41c16dd 100644 --- a/ansible/roles/testlists/tasks/main.yml +++ b/ansible/roles/testlists/tasks/main.yml @@ -14,17 +14,6 @@ notify: - reload nftables -- name: Allow traffic on port 9102 - become: true - tags: prometheus-proxy - blockinfile: - path: /etc/ooni/nftables/tcp/9102.nft - create: yes - block: | - add rule inet filter input tcp dport 9102 counter accept comment "node exporter" - notify: - - reload nftables - # For incoming testlists traffic - name: Allow traffic on port 80 become: true From f1a812c1f62b698d8b0178a6ff94cce5d0277981 Mon Sep 17 00:00:00 2001 From: Aaron Gibson Date: Wed, 18 Feb 2026 17:25:30 +0100 Subject: [PATCH 18/24] ansible: prometheus_node_exporter: add prometheus_user allow configuring the prometheus_user and prometheus group. this is so that permission on htaccess file can be set by group if prometheus_node_exporter shall enforce http basic auth without nginx --- ansible/roles/prometheus_node_exporter/defaults/main.yml | 3 +++ ansible/roles/prometheus_node_exporter/tasks/install.yml | 8 +++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/ansible/roles/prometheus_node_exporter/defaults/main.yml b/ansible/roles/prometheus_node_exporter/defaults/main.yml index 3433498f..338a929b 100644 --- a/ansible/roles/prometheus_node_exporter/defaults/main.yml +++ b/ansible/roles/prometheus_node_exporter/defaults/main.yml @@ -2,6 +2,9 @@ prometheus_nginx_proxy_config: - location: /metrics/node_exporter proxy_pass: http://127.0.0.1:8100/metrics +prometheus_user: 'node_exporter' +prometheus_group: 'node_exporter' + node_exporter_version: '1.8.2' node_exporter_arch: 'amd64' node_exporter_download_url: https://github.com/prometheus/node_exporter/releases/download/v{{ node_exporter_version }}/node_exporter-{{ node_exporter_version }}.linux-{{ node_exporter_arch }}.tar.gz diff --git a/ansible/roles/prometheus_node_exporter/tasks/install.yml b/ansible/roles/prometheus_node_exporter/tasks/install.yml index 2ad7ccd7..21fa2cd6 100644 --- a/ansible/roles/prometheus_node_exporter/tasks/install.yml +++ b/ansible/roles/prometheus_node_exporter/tasks/install.yml @@ -27,10 +27,16 @@ node_exporter_download_check is changed or node_exporter_version_check.stdout | length == 0 +- name: Create node_exporter group. + group: + name: "{{ prometheus_group }}" + state: present + - name: Create node_exporter user. user: - name: node_exporter + name: "{{ prometheus_user }}" shell: /sbin/nologin + group: "{{ prometheus_group }}" state: present - name: Copy the node_exporter systemd unit file. From 50cd09ab9113542660594a284b82a9b03083a127 Mon Sep 17 00:00:00 2001 From: Aaron Gibson Date: Wed, 18 Feb 2026 17:28:32 +0100 Subject: [PATCH 19/24] add var use_nginx to selectively install nginx with node exporter --- ansible/roles/prometheus_node_exporter/tasks/main.yml | 4 +++- ansible/roles/prometheus_node_exporter/vars/main.yml | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ansible/roles/prometheus_node_exporter/tasks/main.yml b/ansible/roles/prometheus_node_exporter/tasks/main.yml index 3a56b273..0ebd8d1f 100644 --- a/ansible/roles/prometheus_node_exporter/tasks/main.yml +++ b/ansible/roles/prometheus_node_exporter/tasks/main.yml @@ -3,6 +3,7 @@ tags: - nginx - node_exporter + when: use_nginx - include_tasks: install.yml @@ -22,7 +23,7 @@ name: prom password: "{{ prometheus_metrics_password }}" owner: root - group: nginx + group: "{{ 'nginx' if use_nginx else prometheus_group }}" mode: 0640 tags: - monitoring @@ -40,3 +41,4 @@ - monitoring - node_exporter - config + when: use_nginx diff --git a/ansible/roles/prometheus_node_exporter/vars/main.yml b/ansible/roles/prometheus_node_exporter/vars/main.yml index 1cf0521e..4be67fb4 100644 --- a/ansible/roles/prometheus_node_exporter/vars/main.yml +++ b/ansible/roles/prometheus_node_exporter/vars/main.yml @@ -1 +1,2 @@ -use_https: true \ No newline at end of file +use_https: true +use_nginx: true From 4b86cf026febd9865048ca1e67a3b13fea09af23 Mon Sep 17 00:00:00 2001 From: Aaron Gibson Date: Wed, 18 Feb 2026 17:40:14 +0100 Subject: [PATCH 20/24] prometheus_node_exporter: set htpasswd from default allow configuring path to htaccess file --- ansible/roles/prometheus_node_exporter/defaults/main.yml | 1 + ansible/roles/prometheus_node_exporter/tasks/main.yml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ansible/roles/prometheus_node_exporter/defaults/main.yml b/ansible/roles/prometheus_node_exporter/defaults/main.yml index 338a929b..9066e94c 100644 --- a/ansible/roles/prometheus_node_exporter/defaults/main.yml +++ b/ansible/roles/prometheus_node_exporter/defaults/main.yml @@ -12,6 +12,7 @@ node_exporter_download_url: https://github.com/prometheus/node_exporter/releases node_exporter_bin_path: /usr/local/bin/node_exporter node_exporter_host: 'localhost' node_exporter_port: 8100 +node_exporter_htpasswd: '/etc/ooni/prometheus_passwd' node_exporter_options: '' node_exporter_state: started diff --git a/ansible/roles/prometheus_node_exporter/tasks/main.yml b/ansible/roles/prometheus_node_exporter/tasks/main.yml index 0ebd8d1f..e683675a 100644 --- a/ansible/roles/prometheus_node_exporter/tasks/main.yml +++ b/ansible/roles/prometheus_node_exporter/tasks/main.yml @@ -19,7 +19,7 @@ - name: Add a user to a password file and ensure permissions are set community.general.htpasswd: - path: /etc/ooni/prometheus_passwd + path: "{{ node_exporter_htpasswd }}" name: prom password: "{{ prometheus_metrics_password }}" owner: root From 817c0a05f6630f5d7f36bcab8f9fdabf6130110c Mon Sep 17 00:00:00 2001 From: Aaron Gibson Date: Wed, 18 Feb 2026 17:41:46 +0100 Subject: [PATCH 21/24] testlists: deploy prometheus_node_exporter without nginx disable nginx installation, but use http basic auth prometheus node exporter also supports TLS natively now too, but this isn't implemented here yet --- ansible/deploy-testlists.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ansible/deploy-testlists.yml b/ansible/deploy-testlists.yml index 98dc7525..ce4d296c 100644 --- a/ansible/deploy-testlists.yml +++ b/ansible/deploy-testlists.yml @@ -9,11 +9,10 @@ - role: prometheus_node_exporter vars: use_https: false + use_nginx: false node_exporter_port: 9100 node_exporter_host: "0.0.0.0" - prometheus_nginx_proxy_config: - - location: /metrics/node_exporter - proxy_pass: http://127.0.0.1:9100/metrics + node_exporter_options: "--web.auth.file={{ node_exporter_htpasswd }}" - role: geerlingguy.docker docker_users: - testlists From d93e773e11c838d54b13e8d8de22e38a915f20a9 Mon Sep 17 00:00:00 2001 From: Aaron Gibson Date: Thu, 19 Feb 2026 09:13:16 +0100 Subject: [PATCH 22/24] create htaccess in install.yml after user/group exist --- .../prometheus_node_exporter/tasks/install.yml | 13 +++++++++++++ .../prometheus_node_exporter/tasks/main.yml | 17 ++--------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/ansible/roles/prometheus_node_exporter/tasks/install.yml b/ansible/roles/prometheus_node_exporter/tasks/install.yml index 21fa2cd6..47ed566e 100644 --- a/ansible/roles/prometheus_node_exporter/tasks/install.yml +++ b/ansible/roles/prometheus_node_exporter/tasks/install.yml @@ -39,6 +39,19 @@ group: "{{ prometheus_group }}" state: present +- name: Add a user to a password file and ensure permissions are set + community.general.htpasswd: + path: "{{ node_exporter_htpasswd }}" + name: prom + password: "{{ prometheus_metrics_password }}" + owner: root + group: "{{ 'nginx' if use_nginx else prometheus_group }}" + mode: 0640 + tags: + - monitoring + - node_exporter + - config + - name: Copy the node_exporter systemd unit file. template: src: node_exporter.service.j2 diff --git a/ansible/roles/prometheus_node_exporter/tasks/main.yml b/ansible/roles/prometheus_node_exporter/tasks/main.yml index e683675a..698b34ac 100644 --- a/ansible/roles/prometheus_node_exporter/tasks/main.yml +++ b/ansible/roles/prometheus_node_exporter/tasks/main.yml @@ -5,8 +5,6 @@ - node_exporter when: use_nginx -- include_tasks: install.yml - - name: create ooni configuration directory ansible.builtin.file: path: "/etc/ooni/" @@ -17,19 +15,6 @@ - node_exporter - config -- name: Add a user to a password file and ensure permissions are set - community.general.htpasswd: - path: "{{ node_exporter_htpasswd }}" - name: prom - password: "{{ prometheus_metrics_password }}" - owner: root - group: "{{ 'nginx' if use_nginx else prometheus_group }}" - mode: 0640 - tags: - - monitoring - - node_exporter - - config - - name: Setup prometheus nginx config ansible.builtin.template: src: "nginx-prometheus.j2" @@ -42,3 +27,5 @@ - node_exporter - config when: use_nginx + +- include_tasks: install.yml From 7fcdd2c2750266b8468881382ddb66e12c3078dc Mon Sep 17 00:00:00 2001 From: Aaron Gibson Date: Thu, 19 Feb 2026 14:59:03 +0100 Subject: [PATCH 23/24] web.auth.file is deprecated --- ansible/deploy-testlists.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ansible/deploy-testlists.yml b/ansible/deploy-testlists.yml index ce4d296c..ccee26ed 100644 --- a/ansible/deploy-testlists.yml +++ b/ansible/deploy-testlists.yml @@ -12,7 +12,7 @@ use_nginx: false node_exporter_port: 9100 node_exporter_host: "0.0.0.0" - node_exporter_options: "--web.auth.file={{ node_exporter_htpasswd }}" + node_exporter_options: "" - role: geerlingguy.docker docker_users: - testlists From d15ee6f583c8e0b239ad5251af5d0377695f1417 Mon Sep 17 00:00:00 2001 From: Aaron Gibson Date: Thu, 19 Feb 2026 15:57:29 +0100 Subject: [PATCH 24/24] use nftables backend; bind port 80 to container port --- ansible/roles/testlists/tasks/main.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/ansible/roles/testlists/tasks/main.yml b/ansible/roles/testlists/tasks/main.yml index a41c16dd..b05efbd2 100644 --- a/ansible/roles/testlists/tasks/main.yml +++ b/ansible/roles/testlists/tasks/main.yml @@ -80,6 +80,14 @@ register: user_gid changed_when: false +- name: Make containerd use nftables backend + ansible.builtin.lineinfile: + path: /etc/containerd/config.toml + line: 'firewall-backend="nftables"' + state: present + notify: + - restart docker + - name: Ensure testlists is running community.docker.docker_container: env: @@ -100,7 +108,8 @@ user: "{{user_uid.stdout}}:{{user_gid.stdout}}" # use network mode = host to allow traffic from testlists to the statsd exporter without # creating a network with redirection rules to match the ports - network_mode: host + ports: + - "80:80" volumes: - /var/lib/ooniapi:/var/lib/ooniapi tags: