fix: mariadb.socket is masked, so 3306 is not on the uplink (#29) #30

Merged
marcos-mendez merged 2 commits from fix/mariadb-socket-uplink into main 2026-10-08 21:34:17 -03:00
marcos-mendez commented 2026-10-08 21:19:24 -03:00 (Migrated from github.com)

Closes #29.

Problem

Debian's mariadb.socket has ListenStream=3306, which systemd binds as [::]:3306. Debian's package does not enable it. But pct create of Proxmox VE removes /etc/machine-id, so the first start of a container is the first boot of systemd. On a first boot, systemd enables all units that no preset disables. With the socket active, mariadbd gets its listener from systemd and bind-address has no effect. On the pair test nodes, 3306 answered on the public uplink (finding B3, Keel-Linux/handbook#60). The manifest says expose: mesh.

Change

  • conf.d/main disables and masks mariadb.socket and mariadb-extra.socket in the image. Then it runs bin/keel-socket-wildcard / 3306, which stops the build when a socket unit of the tree can listen on a wildcard address for 3306 and is not masked. The Makefile copies the check into the tree, like bin/keel-project-packages.
  • keel-mariadb 0.1.1 ships /usr/lib/systemd/system-preset/20-keel-mariadb.preset (disable both units at a first boot). Its postinst masks both with deb-systemd-helper, for a machine whose first boot already ran. It does not restart the server. Its postrm removes these masks on purge.
  • The boot test does to each node what pct create does (no machine id, the 00-pve.preset). After the first boot, step 7 makes sure that no socket holds 3306 on a wildcard address and that the node address does not answer on 3306 from the host.
  • The appliance job moves to packages.yml, after the package build, and gives the package to the boot (package_artifact). The job id stays appliance, so the required check appliance / boot-published-layer keeps its name. The gate boots the published layer, upgraded, with the package of this branch. The mask of conf.d/main takes effect in the gate when a layer built from this branch is published.
  • evidence/2026-10-09-mariadb-socket.md: the mitigation on CT 9003 and CT 9004, with commands and outputs.

Tests

  • tests/socket-wildcard.bats (14 tests): the build check on scratch trees.
  • tests/boot-test.bats (12 new tests): bt_pve_create, bt_wildcard_listeners, bt_uplink_verdict.
  • tests/package.bats (5 new tests): the preset, and the maintainer scripts with deb-systemd-helper stubbed.
  • Coverage: 99.79 percent (479/480) over the five measured shell files.

The first commit has only the tests, and they failed (run 37864180295, run 37864180388).
The second commit makes them pass. In the gate (run 37864884481), each node had a first boot of systemd: sshd-keygen.service ran, which runs only on a first boot. Both socket units were masked, 3306 listened only on 127.0.0.1 and [::1], and the host could not connect to 3306 on the node address. The replication phase passed on 2 nodes.

After merge

  • keel-mariadb 0.1.1 must go to the Keel archive, and the layer must be built and published again. Until then, the mask in the image is not in the published layer.
  • Machines made from the current image keep the socket until the operator masks it and restarts the server. The evidence file gives the procedure for a pair: the replica first, then the primary.
Closes #29. ## Problem Debian's `mariadb.socket` has `ListenStream=3306`, which systemd binds as `[::]:3306`. Debian's package does not enable it. But `pct create` of Proxmox VE removes `/etc/machine-id`, so the first start of a container is the first boot of systemd. On a first boot, systemd enables all units that no preset disables. With the socket active, mariadbd gets its listener from systemd and `bind-address` has no effect. On the pair test nodes, 3306 answered on the public uplink (finding B3, Keel-Linux/handbook#60). The manifest says `expose: mesh`. ## Change - `conf.d/main` disables and masks `mariadb.socket` and `mariadb-extra.socket` in the image. Then it runs `bin/keel-socket-wildcard / 3306`, which stops the build when a socket unit of the tree can listen on a wildcard address for 3306 and is not masked. The Makefile copies the check into the tree, like `bin/keel-project-packages`. - `keel-mariadb` 0.1.1 ships `/usr/lib/systemd/system-preset/20-keel-mariadb.preset` (disable both units at a first boot). Its postinst masks both with `deb-systemd-helper`, for a machine whose first boot already ran. It does not restart the server. Its postrm removes these masks on purge. - The boot test does to each node what `pct create` does (no machine id, the `00-pve.preset`). After the first boot, step 7 makes sure that no socket holds 3306 on a wildcard address and that the node address does not answer on 3306 from the host. - The `appliance` job moves to `packages.yml`, after the package build, and gives the package to the boot (`package_artifact`). The job id stays `appliance`, so the required check `appliance / boot-published-layer` keeps its name. The gate boots the published layer, upgraded, with the package of this branch. The mask of `conf.d/main` takes effect in the gate when a layer built from this branch is published. - `evidence/2026-10-09-mariadb-socket.md`: the mitigation on CT 9003 and CT 9004, with commands and outputs. ## Tests - `tests/socket-wildcard.bats` (14 tests): the build check on scratch trees. - `tests/boot-test.bats` (12 new tests): `bt_pve_create`, `bt_wildcard_listeners`, `bt_uplink_verdict`. - `tests/package.bats` (5 new tests): the preset, and the maintainer scripts with `deb-systemd-helper` stubbed. - Coverage: 99.79 percent (479/480) over the five measured shell files. The first commit has only the tests, and they failed (run 37864180295, run 37864180388). The second commit makes them pass. In the gate (run 37864884481), each node had a first boot of systemd: `sshd-keygen.service` ran, which runs only on a first boot. Both socket units were `masked`, 3306 listened only on `127.0.0.1` and `[::1]`, and the host could not connect to 3306 on the node address. The replication phase passed on 2 nodes. ## After merge - keel-mariadb 0.1.1 must go to the Keel archive, and the layer must be built and published again. Until then, the mask in the image is not in the published layer. - Machines made from the current image keep the socket until the operator masks it and restarts the server. The evidence file gives the procedure for a pair: the replica first, then the primary.
Sign in to join this conversation.
No description provided.