at 24.11-pre 7.4 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7with lib; let 8 cfg = config.security.ipa; 9 pyBool = x: 10 if x 11 then "True" 12 else "False"; 13 14 ldapConf = pkgs.writeText "ldap.conf" '' 15 # Turning this off breaks GSSAPI used with krb5 when rdns = false 16 SASL_NOCANON on 17 18 URI ldaps://${cfg.server} 19 BASE ${cfg.basedn} 20 TLS_CACERT /etc/ipa/ca.crt 21 ''; 22 nssDb = 23 pkgs.runCommand "ipa-nssdb" 24 { 25 nativeBuildInputs = [pkgs.nss.tools]; 26 } '' 27 mkdir -p $out 28 certutil -d $out -N --empty-password 29 certutil -d $out -A --empty-password -n "${cfg.realm} IPA CA" -t CT,C,C -i ${cfg.certificate} 30 ''; 31in { 32 options = { 33 security.ipa = { 34 enable = mkEnableOption "FreeIPA domain integration"; 35 36 certificate = mkOption { 37 type = types.package; 38 description = '' 39 IPA server CA certificate. 40 41 Use `nix-prefetch-url http://$server/ipa/config/ca.crt` to 42 obtain the file and the hash. 43 ''; 44 example = literalExpression '' 45 pkgs.fetchurl { 46 url = http://ipa.example.com/ipa/config/ca.crt; 47 sha256 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; 48 }; 49 ''; 50 }; 51 52 domain = mkOption { 53 type = types.str; 54 example = "example.com"; 55 description = "Domain of the IPA server."; 56 }; 57 58 realm = mkOption { 59 type = types.str; 60 example = "EXAMPLE.COM"; 61 description = "Kerberos realm."; 62 }; 63 64 server = mkOption { 65 type = types.str; 66 example = "ipa.example.com"; 67 description = "IPA Server hostname."; 68 }; 69 70 basedn = mkOption { 71 type = types.str; 72 example = "dc=example,dc=com"; 73 description = "Base DN to use when performing LDAP operations."; 74 }; 75 76 offlinePasswords = mkOption { 77 type = types.bool; 78 default = true; 79 description = "Whether to store offline passwords when the server is down."; 80 }; 81 82 cacheCredentials = mkOption { 83 type = types.bool; 84 default = true; 85 description = "Whether to cache credentials."; 86 }; 87 88 ifpAllowedUids = mkOption { 89 type = types.listOf types.str; 90 default = ["root"]; 91 description = "A list of users allowed to access the ifp dbus interface."; 92 }; 93 94 dyndns = { 95 enable = mkOption { 96 type = types.bool; 97 default = true; 98 description = "Whether to enable FreeIPA automatic hostname updates."; 99 }; 100 101 interface = mkOption { 102 type = types.str; 103 example = "eth0"; 104 default = "*"; 105 description = "Network interface to perform hostname updates through."; 106 }; 107 }; 108 109 chromiumSupport = mkOption { 110 type = types.bool; 111 default = true; 112 description = "Whether to whitelist the FreeIPA domain in Chromium."; 113 }; 114 }; 115 }; 116 117 config = mkIf cfg.enable { 118 assertions = [ 119 { 120 assertion = !config.security.krb5.enable; 121 message = "krb5 must be disabled through `security.krb5.enable` for FreeIPA integration to work."; 122 } 123 { 124 assertion = !config.users.ldap.enable; 125 message = "ldap must be disabled through `users.ldap.enable` for FreeIPA integration to work."; 126 } 127 ]; 128 129 environment.systemPackages = with pkgs; [krb5Full freeipa]; 130 131 environment.etc = { 132 "ipa/default.conf".text = '' 133 [global] 134 basedn = ${cfg.basedn} 135 realm = ${cfg.realm} 136 domain = ${cfg.domain} 137 server = ${cfg.server} 138 host = ${config.networking.hostName} 139 xmlrpc_uri = https://${cfg.server}/ipa/xml 140 enable_ra = True 141 ''; 142 143 "ipa/nssdb".source = nssDb; 144 145 "krb5.conf".text = '' 146 [libdefaults] 147 default_realm = ${cfg.realm} 148 dns_lookup_realm = false 149 dns_lookup_kdc = true 150 rdns = false 151 ticket_lifetime = 24h 152 forwardable = true 153 udp_preference_limit = 0 154 155 [realms] 156 ${cfg.realm} = { 157 kdc = ${cfg.server}:88 158 master_kdc = ${cfg.server}:88 159 admin_server = ${cfg.server}:749 160 default_domain = ${cfg.domain} 161 pkinit_anchors = FILE:/etc/ipa/ca.crt 162 } 163 164 [domain_realm] 165 .${cfg.domain} = ${cfg.realm} 166 ${cfg.domain} = ${cfg.realm} 167 ${cfg.server} = ${cfg.realm} 168 169 [dbmodules] 170 ${cfg.realm} = { 171 db_library = ${pkgs.freeipa}/lib/krb5/plugins/kdb/ipadb.so 172 } 173 ''; 174 175 "openldap/ldap.conf".source = ldapConf; 176 }; 177 178 environment.etc."chromium/policies/managed/freeipa.json" = mkIf cfg.chromiumSupport { 179 text = '' 180 { "AuthServerWhitelist": "*.${cfg.domain}" } 181 ''; 182 }; 183 184 systemd.services."ipa-activation" = { 185 wantedBy = [ "sysinit.target" ]; 186 before = [ "sysinit.target" "shutdown.target" ]; 187 conflicts = [ "shutdown.target" ]; 188 unitConfig.DefaultDependencies = false; 189 serviceConfig.Type = "oneshot"; 190 serviceConfig.RemainAfterExit = true; 191 script = '' 192 # libcurl requires a hard copy of the certificate 193 if ! ${pkgs.diffutils}/bin/diff ${cfg.certificate} /etc/ipa/ca.crt > /dev/null 2>&1; then 194 rm -f /etc/ipa/ca.crt 195 cp ${cfg.certificate} /etc/ipa/ca.crt 196 fi 197 198 if [ ! -f /etc/krb5.keytab ]; then 199 cat <<EOF 200 201 In order to complete FreeIPA integration, please join the domain by completing the following steps: 202 1. Authenticate as an IPA user authorized to join new hosts, e.g. kinit admin@${cfg.realm} 203 2. Join the domain and obtain the keytab file: ipa-join 204 3. Install the keytab file: sudo install -m 600 krb5.keytab /etc/ 205 4. Restart sssd systemd service: sudo systemctl restart sssd 206 207 EOF 208 fi 209 ''; 210 }; 211 212 services.sssd.config = '' 213 [domain/${cfg.domain}] 214 id_provider = ipa 215 auth_provider = ipa 216 access_provider = ipa 217 chpass_provider = ipa 218 219 ipa_domain = ${cfg.domain} 220 ipa_server = _srv_, ${cfg.server} 221 ipa_hostname = ${config.networking.hostName}.${cfg.domain} 222 223 cache_credentials = ${pyBool cfg.cacheCredentials} 224 krb5_store_password_if_offline = ${pyBool cfg.offlinePasswords} 225 ${optionalString ((toLower cfg.domain) != (toLower cfg.realm)) 226 "krb5_realm = ${cfg.realm}"} 227 228 dyndns_update = ${pyBool cfg.dyndns.enable} 229 dyndns_iface = ${cfg.dyndns.interface} 230 231 ldap_tls_cacert = /etc/ipa/ca.crt 232 ldap_user_extra_attrs = mail:mail, sn:sn, givenname:givenname, telephoneNumber:telephoneNumber, lock:nsaccountlock 233 234 [sssd] 235 debug_level = 65510 236 services = nss, sudo, pam, ssh, ifp 237 domains = ${cfg.domain} 238 239 [nss] 240 homedir_substring = /home 241 242 [pam] 243 pam_pwd_expiration_warning = 3 244 pam_verbosity = 3 245 246 [sudo] 247 debug_level = 65510 248 249 [autofs] 250 251 [ssh] 252 253 [pac] 254 255 [ifp] 256 user_attributes = +mail, +telephoneNumber, +givenname, +sn, +lock 257 allowed_uids = ${concatStringsSep ", " cfg.ifpAllowedUids} 258 ''; 259 260 services.ntp.servers = singleton cfg.server; 261 services.sssd.enable = true; 262 services.ntp.enable = true; 263 264 security.pki.certificateFiles = singleton cfg.certificate; 265 }; 266}