openldap: tenant databases are world-readable to any bound user, and to anonymous #303
Labels
No labels
bug
enhancement
in-progress
needs-info
needs-triage
p0
ready-for-agent
ready-for-human
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Cloonar/nixos#303
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Independent of #299 — no dependency either way, and it can ship now.
dc=cloonar,dc=comis properly closed: its ACL list endsby * 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 endsby * read(hosts/mail/modules/openldap.nix:41-45):There is no
olcRequires: authcand noolcDisallows: bind_anon, andolcSecurity = "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 atkerberos.nix:5go 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 existingby dn.subtree=... readclause already covers, so the catch-allby * readmay simply be replaceable withby * none— but that wants checking against every consumer of the tenant trees, not just Dovecot, before it lands.