diff --git a/roles/base/files/mtail.service b/roles/base/files/mtail.service
index 69dec02288523a8831fd40bb1b63248af077dc5e..594e5218b12fbf84dbf78d2293358585b20f37a6 100644
--- a/roles/base/files/mtail.service
+++ b/roles/base/files/mtail.service
@@ -5,7 +5,7 @@ Requires=mtail.socket
 [Service]
 Type=simple
 # Systemd will pass mtail.socket as FD 3.
-ExecStart=/usr/bin/mtail -progs /etc/mtail -logtostderr -port 3903 -logfds 3
+ExecStart=/usr/bin/mtail --progs /etc/mtail --logtostderr --port 3903 --logs /dev/fd/3
 Restart=on-failure
 User=mtail
 
diff --git a/roles/base/files/mtail.service.buster b/roles/base/files/mtail.service.buster
deleted file mode 100644
index 594e5218b12fbf84dbf78d2293358585b20f37a6..0000000000000000000000000000000000000000
--- a/roles/base/files/mtail.service.buster
+++ /dev/null
@@ -1,17 +0,0 @@
-[Unit]
-Description=MTail
-Requires=mtail.socket
-
-[Service]
-Type=simple
-# Systemd will pass mtail.socket as FD 3.
-ExecStart=/usr/bin/mtail --progs /etc/mtail --logtostderr --port 3903 --logs /dev/fd/3
-Restart=on-failure
-User=mtail
-
-# Limit memory leaks
-MemoryMax=1G
-ExecStartPost=+/bin/sh -c "echo 0 > /sys/fs/cgroup/memory/system.slice/%n/memory.swappiness"
-
-[Install]
-WantedBy=multi-user.target
diff --git a/roles/base/files/node-exporter.default b/roles/base/files/node-exporter.default
index b9948f2d682248e40d4b1e12b35525b06fcda98b..e97bc9bbd2b3416a7d84a39850a5dc70e46f24d4 100644
--- a/roles/base/files/node-exporter.default
+++ b/roles/base/files/node-exporter.default
@@ -1,6 +1 @@
-
-ARGS="--collectors.enabled=conntrack,diskstats,entropy,filefd,filesystem,hwmon,loadavg,meminfo,netdev,netstat,sockstat,stat,systemd,textfile,time,uname,vmstat \
-    --collector.diskstats.ignored-devices=^(ram|loop|fd)\d+$ \
-    --collector.filesystem.ignored-mount-points=^/(sys|proc|dev|run)($|/) \
-    --collector.textfile.directory=/var/lib/prometheus/node-exporter \
-    --collector.systemd.unit-blacklist=^.*\.(device|swap|mount)$"
+ARGS="--collector.systemd.unit-blacklist=.+(\.device|\.swap|\.mount|\.scope|\.slice|\.target)"
diff --git a/roles/base/files/node-exporter.default.buster b/roles/base/files/node-exporter.default.buster
deleted file mode 100644
index e97bc9bbd2b3416a7d84a39850a5dc70e46f24d4..0000000000000000000000000000000000000000
--- a/roles/base/files/node-exporter.default.buster
+++ /dev/null
@@ -1 +0,0 @@
-ARGS="--collector.systemd.unit-blacklist=.+(\.device|\.swap|\.mount|\.scope|\.slice|\.target)"
diff --git a/roles/base/tasks/apt.yml b/roles/base/tasks/apt.yml
index e959d5d2f63e9548b3b9f680b765ae6ee68960da..50a02f07e5b4981360f6be7a32b869d16108735c 100644
--- a/roles/base/tasks/apt.yml
+++ b/roles/base/tasks/apt.yml
@@ -76,26 +76,7 @@
       - restic
       - runcron
       - acpid
-
-- name: Install Stretch packages
-  apt:
-    name: "{{ packages }}"
-    state: present
-  vars:
-    packages:
-      - apt-transport-https
-      - liblz4-tool
-      - python-docker
-  when: float_debian_dist == 'stretch'
-
-- name: Install Buster packages
-  apt:
-    name: "{{ packages }}"
-    state: present
-  vars:
-    packages:
       - lz4
-  when: float_debian_dist == 'buster'
 
 - name: Install extra packages
   apt:
diff --git a/roles/base/tasks/harden.yml b/roles/base/tasks/harden.yml
index a23b0ced0c9d47686e71e3cbccd1c636271032e4..3ed2700dfc1c1d5c74d64e437f326220325ea002 100644
--- a/roles/base/tasks/harden.yml
+++ b/roles/base/tasks/harden.yml
@@ -41,6 +41,7 @@
 
 # Audit configuration on Debian stretch uses augenrules by default, so
 # we copy our rules in /etc/audit/rules.d.
+# TODO: evaluate whether we still need this.
 - name: Auditd installed
   apt:
     name: "{{ packages }}"
diff --git a/roles/base/tasks/prometheus.yml b/roles/base/tasks/prometheus.yml
index dc22d3dadb722315f4fd0b6576f53b87c54d6f56..8e822dfe68e913e84f0b492e5498af692711d489 100644
--- a/roles/base/tasks/prometheus.yml
+++ b/roles/base/tasks/prometheus.yml
@@ -2,7 +2,7 @@
 
 - name: Install prometheus config files in /etc/default
   copy:
-    src: "{{ 'node-exporter.default' if ansible_distribution_release == 'stretch' else 'node-exporter.default.buster' }}"
+    src: "node-exporter.default"
     dest: "/etc/default/prometheus-node-exporter"
   notify:
     - reload prometheus-node-exporter
diff --git a/roles/base/tasks/syslog.yml b/roles/base/tasks/syslog.yml
index 09828c147d79799499ebb12ce5d1fa7e5d94bbff..cac9e5fbfc909e08ad026300ef0965785c1512ed 100644
--- a/roles/base/tasks/syslog.yml
+++ b/roles/base/tasks/syslog.yml
@@ -8,17 +8,9 @@
     dest: "/etc/apt/preferences.d/99float-syslog"
   when: float_debian_dist == 'buster'
 
-# Install rsyslog from the backports repository. This isn't strictly
-# necessary but it is done to have the same version of rsyslog on all
-# hosts, including the log-collector.
-#
-# This sources.list check must use float_debian_dist because otherwise
-# Ansible complains about the unknown source on dist upgrades.
-# TODO: drop this check when stretch is obsolete.
-- name: Install rsyslog packages from backports
+- name: Install rsyslog packages
   apt:
     name: "{{ packages }}"
-    default_release: "{{ 'stretch-backports' if float_debian_dist == 'stretch' else '' }}"
     state: present
   vars:
     packages:
@@ -34,7 +26,7 @@
 
 - name: Install mtail systemd unit
   copy:
-    src: "{{ 'mtail.service' if ansible_distribution_release == 'stretch' else 'mtail.service.buster' }}"
+    src: "mtail.service"
     dest: "/etc/systemd/system/mtail.service"
   notify: restart mtail
 
diff --git a/roles/base/templates/ssh/sshd_config.j2 b/roles/base/templates/ssh/sshd_config.j2
index ac1a969440f2d7d3886cd27311993dfb51404a44..4c7baeb8a114ce1707d9bf060f66b4b8838ecbf5 100644
--- a/roles/base/templates/ssh/sshd_config.j2
+++ b/roles/base/templates/ssh/sshd_config.j2
@@ -12,10 +12,6 @@ HostKey /etc/ssh/ssh_host_{{ key_type }}_key
 HostCertificate /etc/ssh/ssh_host_{{ key_type }}_key-cert.pub
 {% endfor %}
 
-{% if ansible_distribution_release == 'stretch' %}
-UsePrivilegeSeparation sandbox
-{% endif %}
-
 # Ciphers and MACs
 KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256
 Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
diff --git a/roles/docker/tasks/buster_upgrade.yml b/roles/docker/tasks/buster_upgrade.yml
deleted file mode 100644
index 5d31aeb1f03c3df2efd2e2a134201fd517808f5e..0000000000000000000000000000000000000000
--- a/roles/docker/tasks/buster_upgrade.yml
+++ /dev/null
@@ -1,22 +0,0 @@
-- name: Remove docker.com GPG key
-  apt_key:
-    id: 9DC858229FC7DD38854AE2D88D81803C0EBFCD88
-    url: https://download.docker.com/linux/debian/gpg
-    state: absent
-
-- name: Remove docker packages
-  apt:
-    name: "{{ packages }}"
-    state: absent
-  vars:
-    packages:
-      - docker-ce
-      - systemd-docker
-
-- name: Remove docker files
-  file:
-    dest: "{{ item }}"
-    state: absent
-  with_items:
-    - /etc/apt/sources.list.d/download_docker_com_linux_debian.list
-    - /etc/docker
diff --git a/roles/docker/tasks/main.yml b/roles/docker/tasks/main.yml
index ae49764767346d634d8c1ade965052f9cbe18545..d4493153b0be3f9c6cf536c0ac39eb6866ebca07 100644
--- a/roles/docker/tasks/main.yml
+++ b/roles/docker/tasks/main.yml
@@ -3,13 +3,6 @@
 - set_fact:
     container_runtime: "podman"
 
-- set_fact:
-    container_runtime: "docker"
-  when: "ansible_distribution_release == 'stretch'"
-
-- include_tasks: buster_upgrade.yml
-  when: "ansible_distribution_release == 'buster'"
-
 - include_tasks: docker.yml
   when: "container_runtime == 'docker'"
 
diff --git a/roles/mariadb/tasks/main.yml b/roles/mariadb/tasks/main.yml
index 56316d1333004210758141bbe4fd3f5607b5a8f3..9f410f96ea9811998f646f5af8f6cd236a2241b5 100644
--- a/roles/mariadb/tasks/main.yml
+++ b/roles/mariadb/tasks/main.yml
@@ -114,7 +114,7 @@
   register: mariadb_systemd_unit
 
 - name: Bootstrap data directory
-  shell: "/usr/bin/mysql_install_db --defaults-file={{ mariadb_config }} --datadir={{ mariadb_data_dir }} --user=mysql --auth-root-authentication-method=socket {{ ansible_distribution_release == 'stretch' and '--skip-auth-anonymous-user' or '' }} && date > {{ mariadb_data_dir }}/.float-bootstrap-ok"
+  shell: "/usr/bin/mysql_install_db --defaults-file={{ mariadb_config }} --datadir={{ mariadb_data_dir }} --user=mysql --auth-root-authentication-method=socket && date > {{ mariadb_data_dir }}/.float-bootstrap-ok"
   args:
     creates: "{{ mariadb_data_dir }}/.float-bootstrap-ok"
 
diff --git a/roles/mariadb/templates/exporter.service.j2 b/roles/mariadb/templates/exporter.service.j2
index 2cd55e04f0987ede0e16823b43e89e279fff1211..30b7e2d058dc5a03b6f97354dd61c7299c1f460f 100644
--- a/roles/mariadb/templates/exporter.service.j2
+++ b/roles/mariadb/templates/exporter.service.j2
@@ -4,11 +4,7 @@ Description=Prometheus exporter for MySQL server (%I)
 [Service]
 Restart=always
 User=prometheus
-{% if ansible_distribution_release == 'stretch' %}
-ExecStart=/usr/bin/prometheus-mysqld-exporter -web.listen-address {{ mariadb_metrics_address }}:{{ mariadb_metrics_port }} -config.my-cnf {{ mariadb_metrics_config }} -collect.info_schema.tables=false -collect.info_schema.tablestats=false
-{% else %}
 ExecStart=/usr/bin/prometheus-mysqld-exporter --web.listen-address {{ mariadb_metrics_address }}:{{ mariadb_metrics_port }} --config.my-cnf {{ mariadb_metrics_config }} --no-collect.info_schema.tables --no-collect.info_schema.tablestats
-{% endif %}
 
 [Install]
 WantedBy=multi-user.target
diff --git a/test/integration-test-docker.yml b/test/integration-test-docker.yml
index d896929a3b38d707fd5041d788bec1c118d6a002..ade66b7ecc6cdb197c9646d168be16f4485ac20e 100644
--- a/test/integration-test-docker.yml
+++ b/test/integration-test-docker.yml
@@ -8,15 +8,8 @@
         dest: /tmp/test-config.yml
         content: "{{ vars|to_nice_yaml }}"
 
-    - name: Setup test Docker image
-      docker_image:
-        name: registry.git.autistici.org/ai3/float:integration-test
-        force: true
-      when: "ansible_distribution_release == 'stretch'"
-
     - name: Setup test Docker image
       command: "podman pull registry.git.autistici.org/ai3/float:integration-test"
-      when: "ansible_distribution_release != 'stretch'"
 
     - name: Run tests
       command: docker run --net host --mount type=bind,source=/tmp/test-config.yml,destination=/test-config.yml registry.git.autistici.org/ai3/float:integration-test