diff options
| author | Irene Knapp <ireneista@internetsafetylabs.org> | 2025-10-01 16:01:23 -0700 |
|---|---|---|
| committer | Irene Knapp <ireneista@internetsafetylabs.org> | 2025-10-01 16:01:23 -0700 |
| commit | 673ce2438657bd81d2226e2dc8918d4ef9d34137 (patch) | |
| tree | a0a665779701f274ea752c40276ef21135cd46c1 /services | |
| parent | 58dd4440eaf6be9d260809b9dcb361d1f46f2abb (diff) | |
add a skeleton openldap config, which isn't actually turned on yet
I'd like to check this in to serve as a basis for your work, and you can turn it on when you feel it's ready. sound good? Change-Id: Icd192b1a7beacf844b5df7742114271889fd384a
Diffstat (limited to 'services')
| -rw-r--r-- | services/accounts/openldap.nix | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/services/accounts/openldap.nix b/services/accounts/openldap.nix new file mode 100644 index 0000000..764d7bf --- /dev/null +++ b/services/accounts/openldap.nix @@ -0,0 +1,190 @@ +# TODO: it would be nice to have an abstraction layer that deals with long +# lines for us, analogous to the one we have for haproxy. it's not immediately +# clear to me what the best design for that is; ideally we could use it with +# any olcAccess section. it's not a need that's likely to arise with any +# section but those, although in principle it could. +# +# TODO: this is not hooked up to anything yet; when you feel it's ready to +# turn on, add it to the list of imported modules in flake.nix +# +# TODO: once we have all +{ lib, pkgs, ... }: + +{ + imports = [ ]; + + services.openldap = { + enable = true; + + urlList = [ + "ldap:///" + ]; + + mutableConfig = false; + + settings = { + attrs = { + olcLogLevel = "config stats"; + olcAuthzPolicy = "to"; + }; + + children = { + # TODO: There are a lot of different "person" types, and we should + # really pick one. It is my firm political belief that first name, + # last name, and display name should all be optional. Also, for our + # needs organizationally, since we have both internal and external + # users, sometimes we want to have uid and sometimes we want to have + # email and sometimes we want both. I don't think any of the existing + # schemas do this, but feel free to take a look and see how close we + # can get. If we decide it's time to make our own, I'll register an + # ISL private enterprise number, but it's bureaucracy I'd prefer to + # skip if we can. + "cn=schema".includes = [ + # TODO: We probably don't need all these schemas. + "${pkgs.openldap}/etc/schema/core.ldif" + "${pkgs.openldap}/etc/schema/cosine.ldif" + "${pkgs.openldap}/etc/schema/inetorgperson.ldif" + "${pkgs.openldap}/etc/schema/nis.ldif" + ]; + + "olcDatabase={-1}frontend".attrs = { + objectClass = [ "olcDatabaseConfig" "olcFrontendConfig" ]; + + olcDatabase = "{-1}frontend"; + + # Otherwise the default is the root, which is not world-readable. + olcDefaultSearchBase = "dc=internetsafetylabs,dc=org"; + + # This is the access control list that pertains to configuration + # settings. This needs to be set explicitly or else you can't check + # what the settings are at runtime, and user-management portals + # benefit from being able to. + olcAccess = [ + '' + {0}to dn.base="" + by * read + '' '' + {1}to dn.base="cn=subschema" + by * read + '' '' + {2}to * + by group.exact="cn=ldap-admins,ou=groups,dc=internetsafetylabs,dc=org" read + by * none + '' + ]; + }; + + "olcDatabase={0}config".attrs = { + objectClass = [ "olcDatabaseConfig" ]; + + olcDatabase = "{0}config"; + + # These things were in the default setup, before we did anything + # to explicitly set up the config database. Setting up the olcAccess + # values overrode them, so here they are in case they're important. + # They haven't been the subject of much thought. + olcAddContentAcl = "TRUE"; + olcLastMod = "TRUE"; + olcLastBind = "FALSE"; + olcLastBindPrecision = "0"; + olcMaxDerefDepth = "15"; + olcReadOnly = "FALSE"; + olcSyncUseSubentry = "FALSE"; + olcMonitoring = "FALSE"; + + olcAccess = [ + '' + {0}to dn.subtree="cn=config" + by group.exact="cn=ldap-admins,ou=groups,dc=internetsafetylabs,dc=org" read + by group.exact="cn=ldap-frontends,ou=groups,dc=internetsafetylabs,dc=org" read + by * none + '' '' + {1}to * + by * none + '' + ]; + }; + + "olcDatabase={1}mdb" = { + attrs = { + objectClass = [ "olcDatabaseConfig" "olcMdbConfig" ]; + + olcDatabase = "{1}mdb"; + olcDbDirectory = "/var/lib/openldap/data"; + + olcSuffix = "dc=internetsafetylabs,dc=org"; + + # This is needed because the memberof overlay has to do its + # changes as a DN. + olcRootDN = "cn=admin,dc=internetsafetylabs,dc=org"; + + # This should probably be commented out when there's nothing + # horrible going on. It's important for bootstrapping and for + # recovering broken situations, but it's a security risk. + # + # The important property of logins that use the root DN and + # password is that logging in that way ignores all ACLs and also + # the account doesn't have to actually exist in the database. + # + # TODO: we might consider adding some sort of auto-expiration + # feature to the secret manager? + #olcRootPW = builtins.readFile + # "/etc/nixos/secrets/openldap/root-password"; + + # TODO: once we have better formatting for this code (see the TODO + # about an abstraction layer for long lines), the thinking behind + # each individual rule should be documented + olcAccess = [ + '' + {0}to attrs=userPassword + by self =xw + by group.exact="cn=ldap-admins,ou=groups,dc=internetsafetylabs,dc=org" =xw + by group.exact="cn=ldap-password-managers,ou=groups,dc=internetsafetylabs,dc=org" =xw + by anonymous auth + by * none + '' '' + {1}to attrs=authzTo + by group.exact="cn=ldap-frontends,ou=groups,dc=internetsafetylabs,dc=org" auth + by group.exact="cn=ldap-admins,ou=groups,dc=internetsafetylabs,dc=org" write + by * none + '' '' + {2}to attrs=memberOf + by group.exact="cn=ldap-admins,ou=groups,dc=internetsafetylabs,dc=org" read + by self read + by * none + '' '' + {3}to dn.subtree="dc=internetsafetylabs,dc=org" + by self write + by group.exact="cn=ldap-admins,ou=groups,dc=internetsafetylabs,dc=org" write + by users read + by * auth + '' '' + {4}to * + by self write + by users read + by * none + '' + ]; + }; + + # The `memberof` operator is extremely useful in writing ACLs, so + # we enable it. + # + # We specifically turn on referential integrity for it, meaning + # the server will reject edits that would break the bidirectional + # nature of the link. These error messages can be confusing, so it's + # worth knowing about. + children = { + "olcOverlay={0}memberof".attrs = { + objectClass = [ "olcOverlayConfig" "olcMemberOf" ]; + + olcOverlay = "memberof"; + olcMemberOfRefint = "TRUE"; + }; + }; + }; + }; + }; + }; +} + |