lol

Merge pull request #207115 from s1341/init_freeipa

freeipa: init at 4.10.1

authored by

Benjamin Staffin and committed by
GitHub
ff296a77 823d5a46

+538 -2
+1
nixos/modules/module-list.nix
··· 276 276 ./security/doas.nix 277 277 ./security/duosec.nix 278 278 ./security/google_oslogin.nix 279 + ./security/ipa.nix 279 280 ./security/lock-kernel-modules.nix 280 281 ./security/misc.nix 281 282 ./security/oath.nix
+258
nixos/modules/security/ipa.nix
··· 1 + { 2 + config, 3 + lib, 4 + pkgs, 5 + ... 6 + }: 7 + with 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 + ''; 31 + in { 32 + options = { 33 + security.ipa = { 34 + enable = mkEnableOption (lib.mdDoc "FreeIPA domain integration"); 35 + 36 + certificate = mkOption { 37 + type = types.package; 38 + description = lib.mdDoc '' 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 = lib.mdDoc "Domain of the IPA server."; 56 + }; 57 + 58 + realm = mkOption { 59 + type = types.str; 60 + example = "EXAMPLE.COM"; 61 + description = lib.mdDoc "Kerberos realm."; 62 + }; 63 + 64 + server = mkOption { 65 + type = types.str; 66 + example = "ipa.example.com"; 67 + description = lib.mdDoc "IPA Server hostname."; 68 + }; 69 + 70 + basedn = mkOption { 71 + type = types.str; 72 + example = "dc=example,dc=com"; 73 + description = lib.mdDoc "Base DN to use when performing LDAP operations."; 74 + }; 75 + 76 + offlinePasswords = mkOption { 77 + type = types.bool; 78 + default = true; 79 + description = lib.mdDoc "Whether to store offline passwords when the server is down."; 80 + }; 81 + 82 + cacheCredentials = mkOption { 83 + type = types.bool; 84 + default = true; 85 + description = lib.mdDoc "Whether to cache credentials."; 86 + }; 87 + 88 + ifpAllowedUids = mkOption { 89 + type = types.listOf types.string; 90 + default = ["root"]; 91 + description = lib.mdDoc "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 = lib.mdDoc "Whether to enable FreeIPA automatic hostname updates."; 99 + }; 100 + 101 + interface = mkOption { 102 + type = types.str; 103 + example = "eth0"; 104 + default = "*"; 105 + description = lib.mdDoc "Network interface to perform hostname updates through."; 106 + }; 107 + }; 108 + 109 + chromiumSupport = mkOption { 110 + type = types.bool; 111 + default = true; 112 + description = lib.mdDoc "Whether to whitelist the FreeIPA domain in Chromium."; 113 + }; 114 + }; 115 + }; 116 + 117 + config = mkIf cfg.enable { 118 + assertions = [ 119 + { 120 + assertion = !config.krb5.enable; 121 + message = "krb5 must be disabled through `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 + system.activationScripts.ipa = stringAfter ["etc"] '' 185 + # libcurl requires a hard copy of the certificate 186 + if ! ${pkgs.diffutils}/bin/diff ${cfg.certificate} /etc/ipa/ca.crt > /dev/null 2>&1; then 187 + rm -f /etc/ipa/ca.crt 188 + cp ${cfg.certificate} /etc/ipa/ca.crt 189 + fi 190 + 191 + if [ ! -f /etc/krb5.keytab ]; then 192 + cat <<EOF 193 + 194 + In order to complete FreeIPA integration, please join the domain by completing the following steps: 195 + 1. Authenticate as an IPA user authorized to join new hosts, e.g. kinit admin@${cfg.realm} 196 + 2. Join the domain and obtain the keytab file: ipa-join 197 + 3. Install the keytab file: sudo install -m 600 krb5.keytab /etc/ 198 + 4. Restart sssd systemd service: sudo systemctl restart sssd 199 + 200 + EOF 201 + fi 202 + ''; 203 + 204 + services.sssd.config = '' 205 + [domain/${cfg.domain}] 206 + id_provider = ipa 207 + auth_provider = ipa 208 + access_provider = ipa 209 + chpass_provider = ipa 210 + 211 + ipa_domain = ${cfg.domain} 212 + ipa_server = _srv_, ${cfg.server} 213 + ipa_hostname = ${config.networking.hostName}.${cfg.domain} 214 + 215 + cache_credentials = ${pyBool cfg.cacheCredentials} 216 + krb5_store_password_if_offline = ${pyBool cfg.offlinePasswords} 217 + ${optionalString ((toLower cfg.domain) != (toLower cfg.realm)) 218 + "krb5_realm = ${cfg.realm}"} 219 + 220 + dyndns_update = ${pyBool cfg.dyndns.enable} 221 + dyndns_iface = ${cfg.dyndns.interface} 222 + 223 + ldap_tls_cacert = /etc/ipa/ca.crt 224 + ldap_user_extra_attrs = mail:mail, sn:sn, givenname:givenname, telephoneNumber:telephoneNumber, lock:nsaccountlock 225 + 226 + [sssd] 227 + debug_level = 65510 228 + services = nss, sudo, pam, ssh, ifp 229 + domains = ${cfg.domain} 230 + 231 + [nss] 232 + homedir_substring = /home 233 + 234 + [pam] 235 + pam_pwd_expiration_warning = 3 236 + pam_verbosity = 3 237 + 238 + [sudo] 239 + debug_level = 65510 240 + 241 + [autofs] 242 + 243 + [ssh] 244 + 245 + [pac] 246 + 247 + [ifp] 248 + user_attributes = +mail, +telephoneNumber, +givenname, +sn, +lock 249 + allowed_uids = ${concatStringsSep ", " cfg.ifpAllowedUids} 250 + ''; 251 + 252 + services.ntp.servers = singleton cfg.server; 253 + services.sssd.enable = true; 254 + services.ntp.enable = true; 255 + 256 + security.pki.certificateFiles = singleton cfg.certificate; 257 + }; 258 + }
+24
pkgs/development/compilers/lesscpy/default.nix
··· 1 + { stdenv, lib, python3Packages }: 2 + 3 + python3Packages.buildPythonApplication rec { 4 + pname = "lesscpy"; 5 + version = "0.13.0"; 6 + 7 + src = python3Packages.fetchPypi { 8 + inherit pname version; 9 + sha256 = "1bbjag13kawnjdn7q4flfrkd0a21rgn9ycfqsgfdmg658jsx1ipk"; 10 + }; 11 + 12 + checkInputs = with python3Packages; [ pytestCheckHook ]; 13 + pythonImportsCheck = [ "lesscpy" ]; 14 + propagatedBuildInputs = with python3Packages; [ ply six ]; 15 + 16 + doCheck = false; # Really weird test failures (`nix-build-python2.css not found`) 17 + 18 + meta = with lib; { 19 + description = "Python LESS Compiler"; 20 + homepage = "https://github.com/lesscpy/lesscpy"; 21 + license = licenses.mit; 22 + maintainers = with maintainers; [ s1341 ]; 23 + }; 24 + }
+5 -2
pkgs/development/libraries/kerberos/krb5.nix
··· 1 1 { lib, stdenv, fetchurl, pkg-config, perl, bison, bootstrap_cmds 2 - , openssl, openldap, libedit, keyutils 2 + , openssl, openldap, libedit, keyutils, libverto 3 3 4 4 # for passthru.tests 5 5 , bind ··· 14 14 # This is called "staticOnly" because krb5 does not support 15 15 # builting both static and shared, see below. 16 16 , staticOnly ? false 17 + , withVerto ? false 17 18 }: 18 19 19 20 # Note: this package is used for bootstrapping fetchurl, and thus ··· 39 40 # krb5's ./configure does not allow passing --enable-shared and --enable-static at the same time. 40 41 # See https://bbs.archlinux.org/viewtopic.php?pid=1576737#p1576737 41 42 ++ lib.optionals staticOnly [ "--enable-static" "--disable-shared" ] 43 + ++ lib.optional withVerto "--with-system-verto" 42 44 ++ lib.optional stdenv.isFreeBSD ''WARN_CFLAGS=""'' 43 45 ++ lib.optionals (stdenv.buildPlatform != stdenv.hostPlatform) 44 46 [ "krb5_cv_attr_constructor_destructor=yes,yes" ··· 53 55 54 56 buildInputs = [ openssl ] 55 57 ++ lib.optionals (stdenv.hostPlatform.isLinux && stdenv.hostPlatform.libc != "bionic" && !(stdenv.hostPlatform.useLLVM or false)) [ keyutils ] 56 - ++ lib.optionals (!libOnly) [ openldap libedit ]; 58 + ++ lib.optionals (!libOnly) [ openldap libedit ] 59 + ++ lib.optionals withVerto [ libverto ]; 57 60 58 61 sourceRoot = "krb5-${version}/src"; 59 62
+23
pkgs/development/python-modules/dogtag-pki/default.nix
··· 1 + { stdenv, lib, fetchPypi, buildPythonPackage, cryptography, 2 + ldap, requests, six }: 3 + 4 + buildPythonPackage rec { 5 + pname = "dogtag-pki"; 6 + version = "11.2.1"; 7 + 8 + src = fetchPypi { 9 + inherit pname version; 10 + sha256 = "sha256-rQSnQPNYr5SyeNbKoFAbnGb2X/8utrfWLa8gu93hy2w="; 11 + }; 12 + 13 + buildInputs = [ cryptography ldap ]; 14 + pythonImportsCheck = [ "pki" ]; 15 + propagatedBuildInputs = [ requests six ]; 16 + 17 + meta = with lib; { 18 + description = "An enterprise-class Certificate Authority"; 19 + homepage = "https://github.com/dogtagpki/pki"; 20 + license = licenses.gpl2; 21 + maintainers = with maintainers; [ s1341 ]; 22 + }; 23 + }
+27
pkgs/development/python-modules/yubico/default.nix
··· 1 + { stdenv, lib, buildPythonPackage, fetchPypi, pytestCheckHook, pyusb }: 2 + 3 + buildPythonPackage rec { 4 + pname = "python-yubico"; 5 + version = "1.3.2"; 6 + 7 + src = fetchPypi { 8 + inherit pname version; 9 + sha256 = "1gd3an1cdcq328nr1c9ijrsf32v0crv6dgq7knld8m9cadj517c7"; 10 + }; 11 + 12 + propagatedBuildInputs = [ pyusb ]; 13 + 14 + checkInputs = [ pytestCheckHook ]; 15 + pythonImportsCheck = [ "yubico" ]; 16 + 17 + disabledTests = [ 18 + "usb" # requires a physical yubikey to test 19 + ]; 20 + 21 + meta = with lib; { 22 + description = "Python code to talk to YubiKeys"; 23 + homepage = "https://github.com/Yubico/python-yubico"; 24 + license = licenses.bsd2; 25 + maintainers = with maintainers; [ s1341 ]; 26 + }; 27 + }
+171
pkgs/os-specific/linux/freeipa/default.nix
··· 1 + { stdenv 2 + , lib 3 + , fetchurl 4 + , pkgconfig 5 + , autoconf 6 + , automake 7 + , kerberos 8 + , openldap 9 + , popt 10 + , sasl 11 + , curl 12 + , xmlrpc_c 13 + , ding-libs 14 + , p11-kit 15 + , gettext 16 + , nspr 17 + , nss 18 + , _389-ds-base 19 + , svrcore 20 + , libuuid 21 + , talloc 22 + , tevent 23 + , samba 24 + , libunistring 25 + , libverto 26 + , libpwquality 27 + , systemd 28 + , python3 29 + , bind 30 + , sssd 31 + , jre 32 + , rhino 33 + , lesscpy 34 + , jansson 35 + , runtimeShell 36 + }: 37 + 38 + let 39 + pathsPy = ./paths.py; 40 + 41 + pythonInputs = with python3.pkgs; [ 42 + six 43 + ldap 44 + dns 45 + netaddr 46 + netifaces 47 + gssapi 48 + dogtag-pki 49 + pyasn1 50 + sssd 51 + cffi 52 + lxml 53 + dbus-python 54 + cryptography 55 + memcached 56 + qrcode 57 + pyusb 58 + yubico 59 + setuptools 60 + jinja2 61 + augeas 62 + samba 63 + ]; 64 + in 65 + stdenv.mkDerivation rec { 66 + pname = "freeipa"; 67 + version = "4.10.1"; 68 + 69 + src = fetchurl { 70 + url = "https://releases.pagure.org/freeipa/freeipa-${version}.tar.gz"; 71 + sha256 = "sha256-q2rQzcBl1tI4/7+hxEwOY9ND86hObe7O7Y9EEH7cUoA="; 72 + }; 73 + 74 + nativeBuildInputs = [ 75 + python3.pkgs.wrapPython 76 + jre 77 + rhino 78 + lesscpy 79 + automake 80 + autoconf 81 + gettext 82 + ]; 83 + 84 + buildInputs = [ 85 + kerberos 86 + openldap 87 + popt 88 + sasl 89 + curl 90 + xmlrpc_c 91 + pkgconfig 92 + ding-libs 93 + p11-kit 94 + python3 95 + nspr 96 + nss 97 + _389-ds-base 98 + svrcore 99 + libuuid 100 + talloc 101 + tevent 102 + samba 103 + libunistring 104 + libverto 105 + systemd 106 + bind 107 + libpwquality 108 + jansson 109 + ] ++ pythonInputs; 110 + 111 + postPatch = '' 112 + patchShebangs makeapi makeaci install/ui/util 113 + 114 + substituteInPlace ipaplatform/setup.py \ 115 + --replace 'ipaplatform.debian' 'ipaplatform.nixos' 116 + 117 + substituteInPlace ipasetup.py.in \ 118 + --replace 'int(v)' 'int(v.replace("post", ""))' 119 + 120 + substituteInPlace client/ipa-join.c \ 121 + --replace /usr/sbin/ipa-getkeytab $out/bin/ipa-getkeytab 122 + 123 + cp -r ipaplatform/{fedora,nixos} 124 + substitute ${pathsPy} ipaplatform/nixos/paths.py \ 125 + --subst-var out \ 126 + --subst-var-by bind ${bind.dnsutils} \ 127 + --subst-var-by curl ${curl} \ 128 + --subst-var-by kerberos ${kerberos} 129 + ''; 130 + 131 + NIX_CFLAGS_COMPILE = "-I${_389-ds-base}/include/dirsrv"; 132 + pythonPath = pythonInputs; 133 + 134 + # Building and installing the server fails with silent Rhino errors, skipping 135 + # for now. Need a newer Rhino version. 136 + #buildFlags = [ "client" "server" ] 137 + 138 + configureFlags = [ 139 + "--with-systemdsystemunitdir=$out/lib/systemd/system" 140 + "--with-ipaplatform=nixos" 141 + "--disable-server" 142 + ]; 143 + 144 + postInstall = '' 145 + echo " 146 + #!${runtimeShell} 147 + echo 'ipa-client-install is not available on NixOS. Please see security.ipa, instead.' 148 + exit 1 149 + " > $out/sbin/ipa-client-install 150 + ''; 151 + 152 + postFixup = '' 153 + wrapPythonPrograms 154 + rm -rf $out/etc/ipa $out/var/lib/ipa-client/sysrestore 155 + ''; 156 + 157 + meta = with lib; { 158 + description = "Identity, Policy and Audit system"; 159 + longDescription = '' 160 + IPA is an integrated solution to provide centrally managed Identity (users, 161 + hosts, services), Authentication (SSO, 2FA), and Authorization 162 + (host access control, SELinux user roles, services). The solution provides 163 + features for further integration with Linux based clients (SUDO, automount) 164 + and integration with Active Directory based infrastructures (Trusts). 165 + ''; 166 + homepage = "https://www.freeipa.org/"; 167 + license = licenses.gpl3Plus; 168 + maintainers = [ maintainers.s1341 ]; 169 + platforms = platforms.linux; 170 + }; 171 + }
+13
pkgs/os-specific/linux/freeipa/paths.py
··· 1 + from ipaplatform.fedora.paths import FedoraPathNamespace 2 + 3 + class NixOSPathNamespace(FedoraPathNamespace): 4 + SBIN_IPA_JOIN = "@out@/bin/ipa-join" 5 + IPA_GETCERT = "@out@/bin/ipa-getcert" 6 + IPA_RMKEYTAB = "@out@/bin/ipa-rmkeytab" 7 + IPA_GETKEYTAB = "@out@/bin/ipa-getkeytab" 8 + NSUPDATE = "@bind@/bin/nsupdate" 9 + BIN_CURL = "@curl@/bin/curl" 10 + KINIT = "@kerberos@/bin/kinit" 11 + KDESTROY = "@kerberos@/bin/kdestroy" 12 + 13 + paths = NixOSPathNamespace()
+12
pkgs/top-level/all-packages.nix
··· 2432 2432 2433 2433 krusader = libsForQt5.callPackage ../applications/file-managers/krusader { }; 2434 2434 2435 + lesscpy = callPackage ../development/compilers/lesscpy { }; 2436 + 2435 2437 lf = callPackage ../applications/file-managers/lf { }; 2436 2438 2437 2439 ctpv = callPackage ../applications/file-managers/lf/ctpv.nix { }; ··· 19987 19989 19988 19990 freeimage = callPackage ../development/libraries/freeimage { 19989 19991 inherit (darwin) autoSignDarwinBinariesHook; 19992 + }; 19993 + 19994 + freeipa = callPackage ../os-specific/linux/freeipa { 19995 + kerberos = krb5.override { 19996 + withVerto = true; 19997 + }; 19998 + sasl = cyrus_sasl; 19999 + samba = samba4.override { 20000 + enableLDAP = true; 20001 + }; 19990 20002 }; 19991 20003 19992 20004 freetts = callPackage ../development/libraries/freetts {
+4
pkgs/top-level/python-packages.nix
··· 2841 2841 2842 2842 dogpile-cache = callPackage ../development/python-modules/dogpile-cache { }; 2843 2843 2844 + dogtag-pki = callPackage ../development/python-modules/dogtag-pki { }; 2845 + 2844 2846 dogtail = callPackage ../development/python-modules/dogtail { }; 2845 2847 2846 2848 doit = callPackage ../development/python-modules/doit { }; ··· 12829 12831 yte = callPackage ../development/python-modules/yte { }; 12830 12832 12831 12833 ytmusicapi = callPackage ../development/python-modules/ytmusicapi { }; 12834 + 12835 + yubico = callPackage ../development/python-modules/yubico { }; 12832 12836 12833 12837 yubico-client = callPackage ../development/python-modules/yubico-client { }; 12834 12838