(define-module (metznet services kdc) #:use-module (srfi srfi-26) #:use-module (gnu services configuration) #:use-module (guix gexp) #:use-module (gnu services) #:use-module (gnu services shepherd) #:use-module (gnu system shadow) #:use-module (gnu packages admin) #:use-module (metznet packages kdc) #:export (kdc-service-type kdc-realm-configuration kdc-realm-configuration? kldap-configuration kldap-configuration? kdc-configuration kdc-configuration?)) (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-maybe string) (define list-of-ports? (list-of integer?)) (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 (serialize-field (lambda (val) val) " ")) (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 (string "/var/lib/kerberos/stash") "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")) (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-string "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")) (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-ldap) "krb5 package to use" serialize-none) (pkinit_anchors (string "DIR:/run/current-system/profile/etc/ssl/certs/") "CA certificate directory/file" (serialize-field (lambda (x) x) " ")) (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)))) (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/kerberos/") (shell #~(string-append #$shadow "/sbin/nologin"))))) (define (kdc-activation configuration) #~(begin (let ((user (getpw "kerberos")) (group (getgr "kerberos"))) (mkdir-p/perms "/var/lib/kerberos" user 488)))) (define (kdc-etc configuration) `(("kdc.conf" ,(serialize-kdc-configuration configuration)))) ; TODO: have to stash the KDC master key with `KRB5_KDC_PROFILE=/etc/kdc.conf kdb5_util stash` on first boot (define (kdc-shepherd configuration) (list (shepherd-service (documentation "") (provision '(kdc)) (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") "SSL_CERT_DIR=/etc/ssl/certs" "KRB5_KDC_PROFILE=/etc/kdc.conf") #:user "root" #:group "root")) (stop #~(make-kill-destructor))) (shepherd-service (documentation "") (provision '(kadmind)) (requirement '(networking user-processes)) (start #~(make-forkexec-constructor (list #$(file-append (kdc-configuration-krb5 configuration) "/sbin/kadmind") "-nofork" "-P" "/run/kadmind.pid") #:environment-variables (list (string-append "LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:" #$(kdc-configuration-krb5 configuration) "/lib/krb5/plugins/kdb") "SSL_CERT_DIR=/etc/ssl/certs" "KRB5_KDC_PROFILE=/etc/kdc.conf") #:user "root" #:group "root")) (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) (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))))