nixos/nixosTests.kerberos: add test suite for LDAP backend

This commit is contained in:
Nessdoor 2024-08-27 15:45:01 +02:00
parent 0ee34b361b
commit 005ec27097
4 changed files with 201 additions and 0 deletions

View File

@ -4,4 +4,5 @@
{
mit = import ./mit.nix { inherit system pkgs; };
heimdal = import ./heimdal.nix { inherit system pkgs; };
ldap = import ./ldap { inherit system pkgs; };
}

View File

@ -0,0 +1,7 @@
{
system ? builtins.currentSystem,
pkgs ? import ../../../.. { inherit system; },
}:
{
mit = import ./mit.nix { inherit system pkgs; };
}

View File

@ -0,0 +1,192 @@
import ../../make-test-python.nix (
{ pkgs, ... }:
let
DITRoot = "dc=example,dc=com";
realm = "EXAMPLE.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}
do
echo -e "${krbSrvPwd}\n${krbSrvPwd}" | \
${krb5Package}/bin/kdb5_ldap_util -r ${realm} stashsrvpw -f $out $srv 2>&1 > /dev/null
done
'';
# 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
ldapDIT = ''
dn: ${DITRoot}
objectClass: organization
objectClass: dcObject
dc: example
o: Example Company
dn: cn=kdc,${DITRoot}
objectClass: krbKdcService
objectClass: simpleSecurityObject
cn: kdc
userPassword: ${krbSrvPwd}
dn: cn=kadmin,${DITRoot}
objectClass: krbAdmService
objectClass: simpleSecurityObject
cn: kadmin
userPassword: ${krbSrvPwd}
'';
rootDnPwd = "ldap_root_password";
in
{
name = "kerberos_server-mit-ldap";
nodes.machine =
{ pkgs, ... }:
{
services.openldap = {
enable = true;
urlList = [
"ldapi:///"
"ldap://"
];
declarativeContents."${DITRoot}" = ldapDIT;
settings = {
children = {
"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"
"${krbLdapSchema}"
];
"olcDatabase={0}config" = {
attrs = {
objectClass = [ "olcDatabaseConfig" ];
olcDatabase = "{0}config";
};
};
"olcDatabase={1}mdb" = {
attrs = {
objectClass = [
"olcDatabaseConfig"
"olcMdbConfig"
];
olcDatabase = "{1}mdb";
olcDbDirectory = "/var/lib/openldap/db";
olcSuffix = DITRoot;
olcRootDN = "cn=root,${DITRoot}";
olcRootPW = rootDnPwd;
# A tiny but realistic ACL
olcAccess = [
''
to attrs=userPassword
by anonymous auth
by * none''
''
to dn.subtree="cn=${realm},cn=realms,${DITRoot}"
by dn.exact="cn=kdc,${DITRoot}" write
by dn.exact="cn=kadmin,${DITRoot}" write
by * none''
''
to *
by * read''
];
};
};
};
};
};
services.kerberos_server = {
enable = true;
settings = {
libdefaults.default_realm = realm;
realms = {
"${realm}" = {
acl = [
{
principal = "admin";
access = "all";
}
];
};
};
dbmodules = {
"${realm}" = {
db_library = "kldap";
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:///";
};
};
};
};
security.krb5 = {
enable = true;
package = krb5Package;
settings = {
libdefaults = {
default_realm = realm;
};
realms = {
"${realm}" = {
admin_server = "machine";
kdc = "machine";
};
};
};
};
users.extraUsers.alice = {
isNormalUser = true;
};
};
testScript = ''
machine.wait_for_unit("openldap.service")
with subtest("realm container initialization"):
machine.succeed(
# 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"):
machine.succeed(
"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
machine.succeed(
"ldapsearch -x -D cn=root,${DITRoot} -w ${rootDnPwd} \
-b ${DITRoot} 'krbPrincipalName=alice@${realm}' | grep 'numEntries: 1'"
)
'';
meta.maintainers = [ pkgs.lib.maintainers.nessdoor ];
}
)

View File

@ -129,6 +129,7 @@ stdenv.mkDerivation rec {
passthru.tests = {
inherit (nixosTests) openldap;
kerberosWithLdap = nixosTests.kerberos.ldap;
};
meta = with lib; {