diff --git a/ansible/deploy-echo-test-helper.yml b/ansible/deploy-echo-test-helper.yml new file mode 100644 index 00000000..fe6434a1 --- /dev/null +++ b/ansible/deploy-echo-test-helper.yml @@ -0,0 +1,21 @@ +--- +- name: Deploy test helpers + hosts: + - echo.th.dev.ooni.io + - echo.th.prod.ooni.io + become: true + roles: + - role: bootstrap + - role: prometheus_node_exporter + vars: + 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 + use_https: false + http_port: 8080 # if we leave port 80, it's taken by nginx + - role: test_helpers + vars: + helper: echo + port: 80 diff --git a/ansible/deploy-json-test-helper.yml b/ansible/deploy-json-test-helper.yml new file mode 100644 index 00000000..ba08b1fc --- /dev/null +++ b/ansible/deploy-json-test-helper.yml @@ -0,0 +1,21 @@ +--- +- name: Deploy test helpers + hosts: + - json.th.dev.ooni.io + - json.th.prod.ooni.io + become: true + roles: + - role: bootstrap + - role: prometheus_node_exporter + vars: + 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 + use_https: false + http_port: 8080 # if we leave port 80, it's taken by nginx + - role: test_helpers + vars: + helper: jsonth + port: 80 diff --git a/ansible/inventory b/ansible/inventory index d2b73ba2..619942a8 100644 --- a/ansible/inventory +++ b/ansible/inventory @@ -46,4 +46,6 @@ openvpn2.htz-fsn.prod.ooni.nu [aws-backend] fastpath.dev.ooni.io fastpath.prod.ooni.io -anonc.dev.ooni.io \ No newline at end of file +anonc.dev.ooni.io +json.th.dev.ooni.io +echo.th.dev.ooni.io diff --git a/ansible/roles/prometheus_node_exporter/tasks/main.yml b/ansible/roles/prometheus_node_exporter/tasks/main.yml index c79a618e..9a4510b7 100644 --- a/ansible/roles/prometheus_node_exporter/tasks/main.yml +++ b/ansible/roles/prometheus_node_exporter/tasks/main.yml @@ -12,6 +12,7 @@ vars: ssl_domains: - "{{ inventory_hostname }}" + when: use_https - include_tasks: install.yml diff --git a/ansible/roles/prometheus_node_exporter/templates/nginx-prometheus.j2 b/ansible/roles/prometheus_node_exporter/templates/nginx-prometheus.j2 index 6e7de3d5..a0019f86 100644 --- a/ansible/roles/prometheus_node_exporter/templates/nginx-prometheus.j2 +++ b/ansible/roles/prometheus_node_exporter/templates/nginx-prometheus.j2 @@ -2,7 +2,7 @@ server { {% if use_https %} - listen 443 ssl http2; + listen {{https_port}} ssl http2; server_name {{ inventory_hostname }}; include /etc/nginx/ssl_intermediate.conf; @@ -11,9 +11,9 @@ server { ssl_certificate_key /var/lib/dehydrated/certs/{{ inventory_hostname }}/privkey.pem; ssl_trusted_certificate /var/lib/dehydrated/certs/{{ inventory_hostname }}/chain.pem; {% else %} - listen 80; + listen {{http_port}}; - server_name {{ inventory_hostname }}; + server_name {{inventory_hostname}}; {% endif %} {% for config in prometheus_nginx_proxy_config %} diff --git a/ansible/roles/prometheus_node_exporter/vars/main.yml b/ansible/roles/prometheus_node_exporter/vars/main.yml index 1cf0521e..567f660b 100644 --- a/ansible/roles/prometheus_node_exporter/vars/main.yml +++ b/ansible/roles/prometheus_node_exporter/vars/main.yml @@ -1 +1,3 @@ -use_https: true \ No newline at end of file +use_https: true +http_port: 80 +https_port: 443 \ No newline at end of file diff --git a/ansible/roles/test_helpers/defaults/main.yml b/ansible/roles/test_helpers/defaults/main.yml new file mode 100644 index 00000000..a431bc19 --- /dev/null +++ b/ansible/roles/test_helpers/defaults/main.yml @@ -0,0 +1,3 @@ +test_helpers_url: https://github.com/ooni/test-helpers/releases/download/0.1.0-1ac1/test-helpers@0.1.0-1ac1.tar.gz +# remember to remove the "sha256:" prefix from github +checksum: 9a7387050412d747df8d0479c004357edfc4cd7825ce7e1c83141e1e0838715c diff --git a/ansible/roles/test_helpers/handlers/main.yml b/ansible/roles/test_helpers/handlers/main.yml new file mode 100644 index 00000000..30593401 --- /dev/null +++ b/ansible/roles/test_helpers/handlers/main.yml @@ -0,0 +1,22 @@ +- name: restart echo + tags: test-helpers + ansible.builtin.systemd_service: + name: echo + state: restarted + +- name: restart jsonth + tags: test-helpers + ansible.builtin.systemd_service: + name: jsonth + state: restarted + +- name: reload nftables + tags: nftables + ansible.builtin.systemd_service: + name: nftables + state: reloaded + +- name: reload nginx + service: + name: nginx + state: reloaded diff --git a/ansible/roles/test_helpers/tasks/main.yml b/ansible/roles/test_helpers/tasks/main.yml new file mode 100644 index 00000000..f35613cc --- /dev/null +++ b/ansible/roles/test_helpers/tasks/main.yml @@ -0,0 +1,106 @@ +--- + +# For prometheus scrape requests +- 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 + +# Create test helpers user +- name: Create the testhelpers user + ansible.builtin.user: + name: "testhelpers" + shell: "/bin/bash" + create_home: no + system: yes + become: yes + +# Install test helpers +- name: Donwload binaries for test helpers + ansible.builtin.get_url: + url: "{{test_helpers_url}}" + dest: "/tmp/test-helpers.tar.gz" + mode: '0600' + become: true + +- name: Get checksum of downloaded file + ansible.builtin.stat: + path: "/tmp/test-helpers.tar.gz" + checksum_algorithm: sha256 + register: file_stat + +- name: Verify checksum + ansible.builtin.fail: + msg: "Checksum failed! Expected: {{checksum}} but got: {{file_stat.stat.checksum}}" + when: file_stat.stat.checksum != checksum + +- name: Create test helpers temp dir + ansible.builtin.file: + path: "/tmp/test-helpers" + state: directory + mode: "0700" + become: yes + +- name: Extract tar content + ansible.builtin.unarchive: + src: "/tmp/test-helpers.tar.gz" + dest: "/tmp/test-helpers" + remote_src: yes + become: yes + +- name: Make jsonth accessible system wide + ansible.builtin.copy: + src: "/tmp/test-helpers/jsonth" + dest: "/usr/local/bin/" + mode: '0755' + remote_src: yes + become: yes + +- name: Make echo accessible system wide + ansible.builtin.copy: + src: "/tmp/test-helpers/echo" + dest: "/usr/local/bin/" + mode: '0755' + remote_src: yes + become: yes + +- name: Clean up temporary files + ansible.builtin.file: + path: "/tmp/test-helpers" + state: absent + become: yes + +- name: Remove downloaded tarball + ansible.builtin.file: + path: "/tmp/test-helpers.tar.gz" + state: absent + become: yes + +# Create systemd units + +- name: Create .service file + tags: test-helpers + ansible.builtin.template: + src: templates/{{helper}}.service + dest: /etc/systemd/system/{{helper}}.service + mode: '0755' + owner: root + notify: + - "restart {{helper}}" + +- name: reload systemd + tags: test-helpers + shell: systemctl daemon-reload + +- name: Start helper + tags: test-helpers + systemd: + name: "{{helper}}.service" + state: started + enabled: yes diff --git a/ansible/roles/test_helpers/templates/echo.service b/ansible/roles/test_helpers/templates/echo.service new file mode 100644 index 00000000..996e6aa1 --- /dev/null +++ b/ansible/roles/test_helpers/templates/echo.service @@ -0,0 +1,22 @@ +[Unit] +Description=Test helper that will start an echo session on request +After=network.target +StartLimitIntervalSec=60 +StartLimitBurst=3 + +[Service] +Type=simple +ExecStart=/usr/local/bin/echo --port {{port}} +Restart=on-failure +RestartSec=5 +User=testhelpers +Group=testhelpers +ProtectSystem=full +ProtectHome=yes +NoNewPrivileges=yes +PrivateTmp=yes +AmbientCapabilities=CAP_NET_BIND_SERVICE +CapabilityBoundingSet=CAP_NET_BIND_SERVICE + +[Install] +WantedBy=multi-user.target diff --git a/ansible/roles/test_helpers/templates/jsonth.service b/ansible/roles/test_helpers/templates/jsonth.service new file mode 100644 index 00000000..54392c17 --- /dev/null +++ b/ansible/roles/test_helpers/templates/jsonth.service @@ -0,0 +1,22 @@ +[Unit] +Description=Test helper that will respond with a json showing the headers it received +After=network.target +StartLimitIntervalSec=60 +StartLimitBurst=3 + +[Service] +Type=simple +ExecStart=/usr/local/bin/jsonth --port {{port}} +Restart=on-failure +RestartSec=5 +User=testhelpers +Group=testhelpers +ProtectSystem=full +ProtectHome=yes +NoNewPrivileges=yes +PrivateTmp=yes +AmbientCapabilities=CAP_NET_BIND_SERVICE +CapabilityBoundingSet=CAP_NET_BIND_SERVICE + +[Install] +WantedBy=multi-user.target diff --git a/ansible/roles/test_helpers/vars/main.yml b/ansible/roles/test_helpers/vars/main.yml new file mode 100644 index 00000000..671bb91e --- /dev/null +++ b/ansible/roles/test_helpers/vars/main.yml @@ -0,0 +1,4 @@ + +# choices: jsonth, echo +helper: "jsonth" +port: "80" \ No newline at end of file diff --git a/tf/environments/dev/main.tf b/tf/environments/dev/main.tf index 55600339..c8fae55f 100644 --- a/tf/environments/dev/main.tf +++ b/tf/environments/dev/main.tf @@ -718,6 +718,142 @@ module "fastpath_builder" { ecs_cluster_name = module.ooniapi_cluster.cluster_name } + +#### Test Helpers Machines + +module "ooni_test_helpers_json" { + 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 = "t3.micro" + + name = "oonijsonth" + ingress_rules = [{ + from_port = 22, + to_port = 22, + protocol = "tcp", + cidr_blocks = ["0.0.0.0/0"], + }, { + from_port = 80, # jsonth + to_port = 80, + protocol = "tcp", + cidr_blocks = ["0.0.0.0/0"], + }, { + from_port = 9100, # Prometheus monitoring + 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 = "oonijsonth" + tg_prefix = "tshp" + + disk_size = 20 + + tags = merge( + local.tags, + { Name = "ooni-tier0-jsonth" } + ) +} + +# Echo test helper, requires a dedicated machine bc it's a tcp server, +# not an HTTP server. It's impossible to reroute using nginx +module "ooni_test_helpers_echo" { + 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 = "t3.micro" + + name = "ooniechoth" + ingress_rules = [{ + from_port = 22, + to_port = 22, + protocol = "tcp", + cidr_blocks = ["0.0.0.0/0"], + }, { + from_port = 80, # echo + to_port = 80, + protocol = "tcp", + cidr_blocks = ["0.0.0.0/0"], + }, { + from_port = 9100, # Prometheus monitoring + 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 = "ooniechoth" + tg_prefix = "echo" + + disk_size = 20 + + tags = merge( + local.tags, + { Name = "ooni-tier0-echoth" } + ) +} + +resource "aws_route53_record" "testhelpers_json_alias" { + zone_id = local.dns_zone_ooni_io + name = "json.th.${local.environment}.ooni.io" + type = "CNAME" + ttl = 300 + + records = [ + module.ooni_test_helpers_json.aws_instance_public_dns + ] +} + +resource "aws_route53_record" "testhelpers_echo_alias" { + zone_id = local.dns_zone_ooni_io + name = "echo.th.${local.environment}.ooni.io" + type = "CNAME" + ttl = 300 + + records = [ + module.ooni_test_helpers_echo.aws_instance_public_dns + ] +} + + #### OONI Run service module "ooniapi_oonirun_deployer" { @@ -927,7 +1063,7 @@ module "ooniapi_oonimeasurements" { task_environment = { # it has to be a json-compliant array - OTHER_COLLECTORS = jsonencode(["https://backend-", "http://fastpath.${local.environment}.ooni.io:8475"]) + OTHER_COLLECTORS = jsonencode(["http://fastpath.${local.environment}.ooni.io:8475", "https://backend-fsn.ooni.org"]) BASE_URL = "https://api.${local.environment}.ooni.io" S3_BUCKET_NAME = "ooni-data-eu-fra-test" }