···
1
+
import ../../make-test-python.nix (
4
+
DITRoot = "dc=example,dc=com";
5
+
realm = "EXAMPLE.COM";
7
+
krb5Package = pkgs.krb5.override { withLdap = true; };
9
+
# Password used by Kerberos services to bind to their identities
10
+
krbSrvPwd = "kerberos_service_password";
11
+
# Stash file read by Kerberos daemons containing the service password
12
+
# DO NOT DO THIS IN PRODUCTION! The stash file is a fundamental secret!
13
+
krbPwdStash = pkgs.runCommand "krb-pwd-stash" { } ''
14
+
for srv in cn=kadmin,${DITRoot} cn=kdc,${DITRoot}
16
+
echo -e "${krbSrvPwd}\n${krbSrvPwd}" | \
17
+
${krb5Package}/bin/kdb5_ldap_util -r ${realm} stashsrvpw -f $out $srv 2>&1 > /dev/null
21
+
# The LDAP schema for Kerberos 5 objects is part of the source distribution of Kerberos 5
22
+
krbLdapSchema = pkgs.runCommand "krb-ldap-schema" { } ''
23
+
tar -Oxf ${krb5Package.src} \
24
+
${krb5Package.sourceRoot}/plugins/kdb/ldap/libkdb_ldap/kerberos.openldap.ldif > $out
27
+
# Initial LDAP tree containing only the Kerberos services
30
+
objectClass: organization
31
+
objectClass: dcObject
35
+
dn: cn=kdc,${DITRoot}
36
+
objectClass: krbKdcService
37
+
objectClass: simpleSecurityObject
39
+
userPassword: ${krbSrvPwd}
41
+
dn: cn=kadmin,${DITRoot}
42
+
objectClass: krbAdmService
43
+
objectClass: simpleSecurityObject
45
+
userPassword: ${krbSrvPwd}
48
+
rootDnPwd = "ldap_root_password";
51
+
name = "kerberos_server-mit-ldap";
57
+
services.openldap = {
63
+
declarativeContents."${DITRoot}" = ldapDIT;
66
+
"cn=schema".includes = [
67
+
"${pkgs.openldap}/etc/schema/core.ldif"
68
+
"${pkgs.openldap}/etc/schema/cosine.ldif"
69
+
"${pkgs.openldap}/etc/schema/inetorgperson.ldif"
70
+
"${pkgs.openldap}/etc/schema/nis.ldif"
73
+
"olcDatabase={0}config" = {
75
+
objectClass = [ "olcDatabaseConfig" ];
76
+
olcDatabase = "{0}config";
79
+
"olcDatabase={1}mdb" = {
85
+
olcDatabase = "{1}mdb";
86
+
olcDbDirectory = "/var/lib/openldap/db";
87
+
olcSuffix = DITRoot;
88
+
olcRootDN = "cn=root,${DITRoot}";
89
+
olcRootPW = rootDnPwd;
90
+
# A tiny but realistic ACL
93
+
to attrs=userPassword
97
+
to dn.subtree="cn=${realm},cn=realms,${DITRoot}"
98
+
by dn.exact="cn=kdc,${DITRoot}" write
99
+
by dn.exact="cn=kadmin,${DITRoot}" write
111
+
services.kerberos_server = {
114
+
libdefaults.default_realm = realm;
119
+
principal = "admin";
127
+
db_library = "kldap";
128
+
ldap_kerberos_container_dn = "cn=realms,${DITRoot}";
129
+
ldap_kdc_dn = "cn=kdc,${DITRoot}";
130
+
ldap_kadmind_dn = "cn=kadmin,${DITRoot}";
131
+
ldap_service_password_file = toString krbPwdStash;
132
+
ldap_servers = "ldapi:///";
140
+
package = krb5Package;
143
+
default_realm = realm;
147
+
admin_server = "machine";
154
+
users.extraUsers.alice = {
155
+
isNormalUser = true;
160
+
machine.wait_for_unit("openldap.service")
162
+
with subtest("realm container initialization"):
164
+
# Passing a master key directly avoids the need for a separate master key stash file
165
+
"kdb5_ldap_util -D cn=root,${DITRoot} create -w ${rootDnPwd} -s -P master_key",
168
+
# These units are bound to fail, as they are started before the directory service is ready
169
+
machine.execute("systemctl restart kadmind.service kdc.service")
171
+
with subtest("service bind"):
172
+
for unit in ["kadmind", "kdc"]:
173
+
machine.wait_for_unit(f"{unit}.service")
175
+
with subtest("administration principal initialization"):
176
+
machine.succeed("kadmin.local add_principal -pw admin_pw admin")
178
+
with subtest("user principal creation and kinit"):
180
+
"kadmin -p admin -w admin_pw addprinc -pw alice_pw alice",
181
+
"echo alice_pw | sudo -u alice kinit",
183
+
# Make extra sure that the user principal actually exists in the directory
185
+
"ldapsearch -x -D cn=root,${DITRoot} -w ${rootDnPwd} \
186
+
-b ${DITRoot} 'krbPrincipalName=alice@${realm}' | grep 'numEntries: 1'"
190
+
meta.maintainers = [ pkgs.lib.maintainers.nessdoor ];