···
+
import ../../make-test-python.nix (
+
DITRoot = "dc=example,dc=com";
+
krb5Package = pkgs.krb5.override { withLdap = true; };
+
# Password used by Kerberos services to bind to their identities
+
krbSrvPwd = "kerberos_service_password";
+
# Stash file read by Kerberos daemons containing the service password
+
# DO NOT DO THIS IN PRODUCTION! The stash file is a fundamental secret!
+
krbPwdStash = pkgs.runCommand "krb-pwd-stash" { } ''
+
for srv in cn=kadmin,${DITRoot} cn=kdc,${DITRoot}
+
echo -e "${krbSrvPwd}\n${krbSrvPwd}" | \
+
${krb5Package}/bin/kdb5_ldap_util -r ${realm} stashsrvpw -f $out $srv 2>&1 > /dev/null
+
# The LDAP schema for Kerberos 5 objects is part of the source distribution of Kerberos 5
+
krbLdapSchema = pkgs.runCommand "krb-ldap-schema" { } ''
+
tar -Oxf ${krb5Package.src} \
+
${krb5Package.sourceRoot}/plugins/kdb/ldap/libkdb_ldap/kerberos.openldap.ldif > $out
+
# Initial LDAP tree containing only the Kerberos services
+
objectClass: organization
+
objectClass: krbKdcService
+
objectClass: simpleSecurityObject
+
userPassword: ${krbSrvPwd}
+
dn: cn=kadmin,${DITRoot}
+
objectClass: krbAdmService
+
objectClass: simpleSecurityObject
+
userPassword: ${krbSrvPwd}
+
rootDnPwd = "ldap_root_password";
+
name = "kerberos_server-mit-ldap";
+
declarativeContents."${DITRoot}" = ldapDIT;
+
"cn=schema".includes = [
+
"${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={0}config" = {
+
objectClass = [ "olcDatabaseConfig" ];
+
olcDatabase = "{0}config";
+
"olcDatabase={1}mdb" = {
+
olcDatabase = "{1}mdb";
+
olcDbDirectory = "/var/lib/openldap/db";
+
olcRootDN = "cn=root,${DITRoot}";
+
# A tiny but realistic ACL
+
to dn.subtree="cn=${realm},cn=realms,${DITRoot}"
+
by dn.exact="cn=kdc,${DITRoot}" write
+
by dn.exact="cn=kadmin,${DITRoot}" write
+
services.kerberos_server = {
+
libdefaults.default_realm = realm;
+
ldap_kerberos_container_dn = "cn=realms,${DITRoot}";
+
ldap_kdc_dn = "cn=kdc,${DITRoot}";
+
ldap_kadmind_dn = "cn=kadmin,${DITRoot}";
+
ldap_service_password_file = toString krbPwdStash;
+
ldap_servers = "ldapi:///";
+
admin_server = "machine";
+
users.extraUsers.alice = {
+
machine.wait_for_unit("openldap.service")
+
with subtest("realm container initialization"):
+
# Passing a master key directly avoids the need for a separate master key stash file
+
"kdb5_ldap_util -D cn=root,${DITRoot} create -w ${rootDnPwd} -s -P master_key",
+
# These units are bound to fail, as they are started before the directory service is ready
+
machine.execute("systemctl restart kadmind.service kdc.service")
+
with subtest("service bind"):
+
for unit in ["kadmind", "kdc"]:
+
machine.wait_for_unit(f"{unit}.service")
+
with subtest("administration principal initialization"):
+
machine.succeed("kadmin.local add_principal -pw admin_pw admin")
+
with subtest("user principal creation and kinit"):
+
"kadmin -p admin -w admin_pw addprinc -pw alice_pw alice",
+
"echo alice_pw | sudo -u alice kinit",
+
# Make extra sure that the user principal actually exists in the directory
+
"ldapsearch -x -D cn=root,${DITRoot} -w ${rootDnPwd} \
+
-b ${DITRoot} 'krbPrincipalName=alice@${realm}' | grep 'numEntries: 1'"
+
meta.maintainers = [ pkgs.lib.maintainers.nessdoor ];