From 580b8f642b8a000f01d90cba7eda1eea3414310e Mon Sep 17 00:00:00 2001 From: Noah Metz Date: Thu, 30 Nov 2023 02:46:55 -0700 Subject: [PATCH] Added shepherd service for krb5kdc and package that has kldap --- machines/kerberos.metznet.ca.scm | 320 ++++++++++++++++++++++++++----- 1 file changed, 275 insertions(+), 45 deletions(-) diff --git a/machines/kerberos.metznet.ca.scm b/machines/kerberos.metznet.ca.scm index f0294b9..e9423a9 100644 --- a/machines/kerberos.metznet.ca.scm +++ b/machines/kerberos.metznet.ca.scm @@ -1,99 +1,329 @@ (define-module (machines kerberos.metznet.ca) + #:use-module (srfi srfi-26) #:use-module (srfi srfi-9) #:use-module (srfi srfi-1) #:use-module (gnu system) #:use-module (guix gexp) + #:use-module (guix packages) + #:use-module (guix download) + #:use-module (guix utils) + #:use-module (guix build-system gnu) + #:use-module ((guix licenses) + #:prefix license:) #:use-module (system base-system) + #:use-module (gnu system shadow) + #:use-module (gnu packages) #:use-module (gnu packages kerberos) #:use-module (gnu packages base) + #:use-module (gnu packages admin) + #:use-module (gnu packages tls) + #:use-module (gnu packages bison) + #:use-module (gnu packages perl) + #:use-module (gnu packages tcl) + #:use-module (gnu packages readline) + #:use-module (gnu packages openldap) #:use-module (gnu services) + #:use-module (gnu services shepherd) #:use-module (gnu services configuration) #:use-module (gnu services certbot)) -(define (realm-name? val) - (string? val)) +(define-public mit-krb5-ldap + (package + (name "mit-krb5-ldap") + (version "1.20") + (source (origin + (method url-fetch) + (uri (list (string-append + "https://web.mit.edu/kerberos/dist/krb5/" + (version-major+minor version) "/krb5-" version + ".tar.gz") + (string-append "https://kerberos.org/dist/krb5/" + (version-major+minor version) "/krb5-" + version ".tar.gz"))) + (patches (search-patches "mit-krb5-hurd.patch")) + (sha256 + (base32 + "0bz16sh0vgzlpy2kx5acmpyy181hl83a1alz7wbk06457kfjn0ky")))) + (build-system gnu-build-system) + (native-inputs (list bison perl tcl openldap)) ;required for some tests + (inputs (list openssl readline)) + (arguments + `( ;XXX: On 32-bit systems, 'kdb5_util' hangs on an fcntl/F_SETLKW call + ;; while running the tests in 'src/tests'. Also disable tests when + ;; cross-compiling. + #:tests? ,(and (not (%current-target-system)) + (string=? (%current-system) "x86_64-linux")) + + ,@(if (%current-target-system) + '(#:configure-flags (list "--localstatedir=/var" + "--with-readline" + "--with-ldap" + "krb5_cv_attr_constructor_destructor=yes" + "ac_cv_func_regcomp=yes" + "ac_cv_printf_positional=yes" + "ac_cv_file__etc_environment=yes" + "ac_cv_file__etc_TIMEZONE=no") + #:make-flags (list "CFLAGS+=-DDESTRUCTOR_ATTR_WORKS=1")) + '(#:configure-flags (list "--with-readline" "--with-ldap" "--localstatedir=/var"))) + #:phases (modify-phases %standard-phases + (add-after 'unpack 'enter-source-directory + (lambda _ + (chdir "src"))) + (add-before 'check 'pre-check + (lambda* (#:key inputs native-inputs #:allow-other-keys) + (let ((perl (search-input-file (or native-inputs inputs) + "bin/perl"))) + (substitute* "plugins/kdb/db2/libdb2/test/run.test" + (("/bin/cat") + perl) + (("D/bin/sh") + (string-append "D" + (which "sh"))) + (("bindir=/bin/.") + (string-append "bindir=" + (dirname perl)))))))))) + (synopsis "MIT Kerberos 5") + (description + "Massachusetts Institute of Technology implementation of Kerberos. +Kerberos is a network authentication protocol designed to provide strong +authentication for client/server applications by using secret-key +cryptography.") + (license (license:non-copyleft "file://NOTICE" + "See NOTICE in the distribution.")) + (home-page "https://web.mit.edu/kerberos/") + (properties '((cpe-name . "kerberos"))))) + +(define (serialize-field conv pad) + (lambda (field-name value) + #~(string-append #$pad + #$(symbol->string field-name) " = " + #$(conv value) "\n"))) + +(define serialize-string + (serialize-field (lambda (val) + val) " ")) -(define (serialize-string field-name val) - (string-append " " (symbol->string field-name) " = " val "\n")) (define-maybe string) (define list-of-ports? (list-of integer?)) -(define (serialize-list-of-ports field-name value) - (string-append " " (symbol->string field-name) " = " (string-join (map number->string value) ", ") "\n")) - -(define (realm-serialize-list-of-ports field-name value) - (string-append " " (symbol->string field-name) " = " (string-join (map number->string value) ", ") "\n")) +(define serialize-list-of-ports + (serialize-field (lambda (val) + (string-join (map number->string val) ",")) " ")) +(define realm-serialize-list-of-ports + (serialize-field (lambda (val) + (string-join (map number->string val) ",")) " ")) (define-maybe list-of-ports) (define-maybe file-like) -(define (serialize-file-like field-name value) - #~(string-append " " #$(symbol->string field-name) " = " #$value "\n")) +(define serialize-file-like + (serialize-field (lambda (val) + val) " ")) -(define (serialize-none field-name value) "") +(define (serialize-none field-name value) + "") (define-configuration kdc-realm-configuration - (name (string "EXAMPLE.COM") "realm name" serialize-none) - (database_module maybe-string "database module") - (acl_file maybe-file-like "acl file") - (key_stash_file maybe-file-like "key stash file") - (kdc_ports (list-of-ports '(750 88)) "list of ports to listen on" realm-serialize-list-of-ports) - (kadmind_ports (list-of-ports '(749)) "list of ports to listen on for kadmin connections" realm-serialize-list-of-ports) - (max_life (string "10h 0m 0s") "maximum life of granted tickets") - (max_renewable_type (string "7d 0h 0m 0s") "maximum time to renew ticket") - (master_key_type (string "des3-hmac-sha1") "master key type") - (default_principal_flags (string "+preauth") "default flag for new principals")) + (name (string "EXAMPLE.COM") "realm name" serialize-none) + (database_module maybe-string "database module") + (acl_file maybe-file-like "acl file") + (key_stash_file maybe-string "key stash file") + (kdc_ports (list-of-ports '(750 88)) + "list of ports to listen on" + realm-serialize-list-of-ports) + (kadmind_ports (list-of-ports '(749)) + "list of ports to listen on for kadmin connections" + realm-serialize-list-of-ports) + (max_life (string "10h 0m 0s") + "maximum life of granted tickets") + (max_renewable_type (string "7d 0h 0m 0s") + "maximum time to renew ticket") + (master_key_type (string "des3-hmac-sha1") + "master key type") + (supported_enctypes maybe-string + "supported encryption types") + (default_principal_flags maybe-string + "default flag for new principals")) (define list-of-kdc-realm-configuration? (list-of kdc-realm-configuration?)) (define (serialize-kdc-realm-configuration realm) - #~(string-append " " #$(kdc-realm-configuration-name realm) " = {\n" - #$(serialize-configuration realm kdc-realm-configuration-fields) - " }\n")) + #~(string-append " " + #$(kdc-realm-configuration-name realm) " = {\n" + #$(serialize-configuration realm + kdc-realm-configuration-fields) + " }\n")) -(define (serialize-list-of-strings field-name value) - (string-join (append (list (string-append "[" (symbol->string field-name) "]" )) value) "\n")) +(define serialize-boolean + (serialize-field (lambda (val) + (if val "true" "false")) " ")) +(define serialize-number + (serialize-field number->string " ")) + +(define-configuration kldap-configuration + (db_library (string "kldap") "db library to use") + (disable_last_success (boolean #f) + "disable last success field") + (disable_lockout (boolean #f) "disable lockout field") + (ldap_kdc_dn (string "uid=kdc,dc=example,dc=com") + "dn to bind for kdc operations") + (ldap_kadmind_dn (string "uid=kadmind,dc=example,dc=com") + "dn to bind for kadmin operations") + (ldap_service_password_file maybe-file-like + "file that stores the passwords for the ldap bind dns") + (ldap_servers (string "ldap://example.com") + "ldap server url") + (ldap_conns_per_server (number 5) + "number of connections per ldap server")) (define (serialize-list-of-kdc-realm-configuration field-name value) #~(string-join (list "[realms]" - #$@(map (lambda (realm) (serialize-kdc-realm-configuration realm)) value)) - "\n")) + #$@(map (lambda (realm) + (serialize-kdc-realm-configuration realm)) + value)) "\n")) + +(define (dbmodule? val) + (if (list? val) + (let ((name (car val)) + (config (cdr val))) + (if (string? name) + (or (kldap-configuration? config)) #f)))) + +(define list-of-dbmodules? + (list-of dbmodule?)) + +(define (serialize-dbmodule dbmodule) + (let ((name (car dbmodule)) + (config (cdr dbmodule))) + #~(string-append " " + #$name " = {\n" + #$(or (if (kldap-configuration? config) + (serialize-configuration config + kldap-configuration-fields) #f) "") " }\n"))) + +(define (serialize-list-of-dbmodules field-name value) + #~(string-join (list "[dbmodules]" + #$@(map (lambda (dbmodule) + (serialize-dbmodule dbmodule)) value)) "\n")) + +(define list-of-strings? + (list-of string?)) + +(define (serialize-list-of-strings field-name value) + #~(string-append "[" + #$(symbol->string field-name) "]\n" + #$(string-join (map (cut string-append " " <>) value) "\n") + "\n")) + +(define-maybe list-of-strings) (define-configuration kdc-configuration - (krb5 (file-like mit-krb5) "krb5 package to use" serialize-none) - (kdc_ports (list-of-ports '(750 88)) "list of ports to listen on") - (realms (list-of-kdc-realm-configuration '()) "Realms to configure the KDC with") - (extra (list-of-strings '()) "extra lines")) + (krb5 (file-like mit-krb5-ldap) "krb5 package to use" + serialize-none) + (kdc_ports (list-of-ports '(750 88)) + "list of ports to listen on") + (realms (list-of-kdc-realm-configuration '()) + "Realms to configure the KDC with") + (logging maybe-list-of-strings + "extra logging lines") + (dbdefaults maybe-list-of-strings + "extra dbdefault lines") + (dbmodules (list-of-dbmodules '()) + "dbmodules to configure")) (define (serialize-kdc-configuration configuration) - (mixed-text-file - "kdc.conf" - #~(string-append "[kdcdefaults]\n" - #$(serialize-configuration configuration kdc-configuration-fields)))) + (mixed-text-file "kdc.conf" + #~(string-append "[kdcdefaults]\n" + #$(serialize-configuration configuration + kdc-configuration-fields)))) + +(define (kdc-accounts configuration) + (list (user-group + (name "kerberos") + (system? #t)) + (user-account + (name "kerberos") + (group "kerberos") + (system? #t) + (comment "kdc service account") + (home-directory "/var/lib/krb5kdc/") + (shell #~(string-append #$shadow "/sbin/nologin"))))) (define (kdc-activation configuration) - #~(symlink #$(serialize-kdc-configuration configuration) "/etc/kdc.conf")) + #~(begin + (let ((user (getpw "kerberos")) + (group (getgr "kerberos"))) + (mkdir-p/perms "/var/lib/krb5kdc" user 488)))) + +(define (kdc-etc configuration) + `(("kdc.conf" ,(serialize-kdc-configuration configuration)))) + +(define (kdc-shepherd configuration) + (list (shepherd-service (documentation "") + (provision '(krb5kdc)) + (requirement '(networking user-processes)) + (start #~(make-forkexec-constructor (list #$(file-append + (kdc-configuration-krb5 + configuration) + "/sbin/krb5kdc") + "-n" "-P" + "/run/krb5kdc.pid") + #:environment-variables + (list (string-append + "LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:" + #$(kdc-configuration-krb5 + configuration) + "/lib/krb5/plugins/kdb") + "KRB5_KDC_PROFILE=/etc/kdc.conf") + #:user "kerberos" + #:group "kerberos")) + (stop #~(make-kill-destructor))))) (define kdc-service-type (service-type (name 'kdc-service) (description "KDC service") - (extensions (list (service-extension activation-service-type kdc-activation))) + (extensions (list (service-extension activation-service-type + kdc-activation) + (service-extension + shepherd-root-service-type kdc-shepherd) + (service-extension account-service-type + kdc-accounts) + (service-extension etc-service-type kdc-etc))) (default-value (kdc-configuration)))) +(define %kerberos-dn "uid=kerberos,ou=system,ou=accounts,dc=metznet,dc=ca") + (operating-system (inherit %metznet-base-server-system) (host-name "kerberos-guix.metznet.ca") (services (append (list (service kdc-service-type - (kdc-configuration - (realms (list - (kdc-realm-configuration - (name "METZNET.CA") - (database_module "openldap_ldapconf") - (acl_file (plain-file "kadm5.acl" "*/admin@METZNET.CA *\n"))))))) + (kdc-configuration (dbdefaults '("ldap_kerberos_container_dn = cn=kerberos,dc=metznet,dc=ca")) + (logging '("kdc = SYSLOG:DEBUG:DAEMON")) + (dbmodules (list (cons + "openldap_ldapconf" + (kldap-configuration + (ldap_kdc_dn %kerberos-dn) + (ldap_kadmind_dn %kerberos-dn) + (ldap_servers "ldap://ldap.metznet.ca") + (ldap_service_password_file + (plain-file + "service.keyfile" + "uid=kerberos,ou=system,ou=accounts,dc=metznet,dc=ca#{HEX}594459525a793139\n")))))) + (realms (list (kdc-realm-configuration + (name "METZNET.CA") + (database_module + "openldap_ldapconf") + (key_stash_file + "/var/lib/krb5kdc/stash") + (default_principal_flags + "+preauth") + (acl_file (plain-file + "kadm5.acl" + "*/admin@METZNET.CA *\n"))))))) (service certbot-service-type (certbot-configuration (email "admin@metznet.ca") (certificates (list (certificate-configuration