openldap: tenant databases are world-readable to any bound user, and to anonymous #303

Open
opened 2026-08-08 13:30:27 +02:00 by dominik.polakovics · 0 comments

Independent of #299 — no dependency either way, and it can ship now.

dc=cloonar,dc=com is properly closed: its ACL list ends by * none (hosts/mail/modules/openldap.nix:152-157), so a tenant user cannot read the identity tenant. That direction is fine.

The reverse is not. Every tenant database is built from standardTenantAccess, whose catch-all ends by * read (hosts/mail/modules/openldap.nix:41-45):

{2}to *
  by dn.subtree="ou=system,ou=users,dc=cloonar,dc=com" read
  by group.exact="cn=Administrators,ou=groups,dc=cloonar,dc=com" write
  by * read

There is no olcRequires: authc and no olcDisallows: bind_anon, and olcSecurity = "tls=1" mandates encryption but not authentication. So any bound user — from any tenant — and plausibly any anonymous client can enumerate every tenant's directory: user lists, mail addresses, pgpPublicKey.

Ports 389 and 636 are opened on the host firewall (hosts/mail/modules/openldap.nix:423). Whether the Hetzner cloud firewall narrows them is not recorded in this repo — the same undocumented boundary that made the port-88 comment at kerberos.nix:5 go stale. Worth establishing and writing down as part of this, because it is the difference between an internal leak and a public one.

For this fleet the impact is modest. For the reference architecture #299 is aiming at — whose selling point is that a mail account on someone else's domain reaches nothing of yours — it is the first thing an auditor asks about, and right now the isolation only holds in one direction.

What needs deciding

What a tenant legitimately needs to read. Dovecot binds as cn=vmail,ou=system,ou=users,dc=cloonar,dc=com, which the existing by dn.subtree=... read clause already covers, so the catch-all by * read may simply be replaceable with by * none — but that wants checking against every consumer of the tenant trees, not just Dovecot, before it lands.

Independent of #299 — no dependency either way, and it can ship now. `dc=cloonar,dc=com` is properly closed: its ACL list ends `by * none` (`hosts/mail/modules/openldap.nix:152-157`), so a tenant user cannot read the identity tenant. That direction is fine. The reverse is not. Every tenant database is built from `standardTenantAccess`, whose catch-all ends **`by * read`** (`hosts/mail/modules/openldap.nix:41-45`): ``` {2}to * by dn.subtree="ou=system,ou=users,dc=cloonar,dc=com" read by group.exact="cn=Administrators,ou=groups,dc=cloonar,dc=com" write by * read ``` There is no `olcRequires: authc` and no `olcDisallows: bind_anon`, and `olcSecurity = "tls=1"` mandates encryption but not authentication. So any bound user — from any tenant — and plausibly any anonymous client can enumerate every tenant's directory: user lists, mail addresses, `pgpPublicKey`. Ports 389 and 636 are opened on the host firewall (`hosts/mail/modules/openldap.nix:423`). Whether the Hetzner cloud firewall narrows them is **not recorded in this repo** — the same undocumented boundary that made the port-88 comment at `kerberos.nix:5` go stale. Worth establishing and writing down as part of this, because it is the difference between an internal leak and a public one. For this fleet the impact is modest. For the reference architecture #299 is aiming at — whose selling point is that a mail account on someone else's domain reaches nothing of yours — it is the first thing an auditor asks about, and right now the isolation only holds in one direction. ## What needs deciding What a tenant legitimately needs to read. Dovecot binds as `cn=vmail,ou=system,ou=users,dc=cloonar,dc=com`, which the existing `by dn.subtree=... read` clause already covers, so the catch-all `by * read` may simply be replaceable with `by * none` — but that wants checking against every consumer of the tenant trees, not just Dovecot, before it lands.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Cloonar/nixos#303
No description provided.