dcgm: 3.3.5 -> 3.3.9; cudaPackages_10{,_0,_1,_2}: drop (#357655)
[NixPkgs.git] / nixos / modules / security / ipa.nix
blobe746ca75724a1a7d223f5f394d6c727d2bd5b8d3
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";
14   ldapConf = pkgs.writeText "ldap.conf" ''
15     # Turning this off breaks GSSAPI used with krb5 when rdns = false
16     SASL_NOCANON    on
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 "FreeIPA domain integration";
36       certificate = mkOption {
37         type = types.package;
38         description = ''
39           IPA server CA certificate.
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       };
52       domain = mkOption {
53         type = types.str;
54         example = "example.com";
55         description = "Domain of the IPA server.";
56       };
58       realm = mkOption {
59         type = types.str;
60         example = "EXAMPLE.COM";
61         description = "Kerberos realm.";
62       };
64       server = mkOption {
65         type = types.str;
66         example = "ipa.example.com";
67         description = "IPA Server hostname.";
68       };
70       basedn = mkOption {
71         type = types.str;
72         example = "dc=example,dc=com";
73         description = "Base DN to use when performing LDAP operations.";
74       };
76       offlinePasswords = mkOption {
77         type = types.bool;
78         default = true;
79         description = "Whether to store offline passwords when the server is down.";
80       };
82       cacheCredentials = mkOption {
83         type = types.bool;
84         default = true;
85         description = "Whether to cache credentials.";
86       };
88       ipaHostname = mkOption {
89         type = types.str;
90         example = "myworkstation.example.com";
91         default = if config.networking.domain != null then config.networking.fqdn
92                   else "${config.networking.hostName}.${cfg.domain}";
93         defaultText = literalExpression ''
94           if config.networking.domain != null then config.networking.fqdn
95           else "''${networking.hostName}.''${security.ipa.domain}"
96         '';
97         description = "Fully-qualified hostname used to identify this host in the IPA domain.";
98       };
100       ifpAllowedUids = mkOption {
101         type = types.listOf types.str;
102         default = ["root"];
103         description = "A list of users allowed to access the ifp dbus interface.";
104       };
106       dyndns = {
107         enable = mkOption {
108           type = types.bool;
109           default = true;
110           description = "Whether to enable FreeIPA automatic hostname updates.";
111         };
113         interface = mkOption {
114           type = types.str;
115           example = "eth0";
116           default = "*";
117           description = "Network interface to perform hostname updates through.";
118         };
119       };
121       chromiumSupport = mkOption {
122         type = types.bool;
123         default = true;
124         description = "Whether to whitelist the FreeIPA domain in Chromium.";
125       };
126     };
127   };
129   config = mkIf cfg.enable {
130     assertions = [
131       {
132         assertion = !config.security.krb5.enable;
133         message = "krb5 must be disabled through `security.krb5.enable` for FreeIPA integration to work.";
134       }
135       {
136         assertion = !config.users.ldap.enable;
137         message = "ldap must be disabled through `users.ldap.enable` for FreeIPA integration to work.";
138       }
139     ];
141     environment.systemPackages = with pkgs; [krb5Full freeipa];
143     environment.etc = {
144       "ipa/default.conf".text = ''
145         [global]
146         basedn = ${cfg.basedn}
147         realm = ${cfg.realm}
148         domain = ${cfg.domain}
149         server = ${cfg.server}
150         host = ${config.networking.hostName}
151         xmlrpc_uri = https://${cfg.server}/ipa/xml
152         enable_ra = True
153       '';
155       "ipa/nssdb".source = nssDb;
157       "krb5.conf".text = ''
158         [libdefaults]
159          default_realm = ${cfg.realm}
160          dns_lookup_realm = false
161          dns_lookup_kdc = true
162          rdns = false
163          ticket_lifetime = 24h
164          forwardable = true
165          udp_preference_limit = 0
167         [realms]
168          ${cfg.realm} = {
169           kdc = ${cfg.server}:88
170           master_kdc = ${cfg.server}:88
171           admin_server = ${cfg.server}:749
172           default_domain = ${cfg.domain}
173           pkinit_anchors = FILE:/etc/ipa/ca.crt
174         }
176         [domain_realm]
177          .${cfg.domain} = ${cfg.realm}
178          ${cfg.domain} = ${cfg.realm}
179          ${cfg.server} = ${cfg.realm}
181         [dbmodules]
182           ${cfg.realm} = {
183             db_library = ${pkgs.freeipa}/lib/krb5/plugins/kdb/ipadb.so
184           }
185       '';
187       "openldap/ldap.conf".source = ldapConf;
188     };
190     environment.etc."chromium/policies/managed/freeipa.json" = mkIf cfg.chromiumSupport {
191       text = ''
192         { "AuthServerWhitelist": "*.${cfg.domain}" }
193       '';
194     };
196     systemd.services."ipa-activation" = {
197       wantedBy = [ "sysinit.target" ];
198       before = [ "sysinit.target" "shutdown.target" ];
199       conflicts = [ "shutdown.target" ];
200       unitConfig.DefaultDependencies = false;
201       serviceConfig.Type = "oneshot";
202       serviceConfig.RemainAfterExit = true;
203       script = ''
204         # libcurl requires a hard copy of the certificate
205         if ! ${pkgs.diffutils}/bin/diff ${cfg.certificate} /etc/ipa/ca.crt > /dev/null 2>&1; then
206           rm -f /etc/ipa/ca.crt
207           cp ${cfg.certificate} /etc/ipa/ca.crt
208         fi
210         if [ ! -f /etc/krb5.keytab ]; then
211           cat <<EOF
213             In order to complete FreeIPA integration, please join the domain by completing the following steps:
214             1. Authenticate as an IPA user authorized to join new hosts, e.g. kinit admin@${cfg.realm}
215             2. Join the domain and obtain the keytab file: ipa-join
216             3. Install the keytab file: sudo install -m 600 krb5.keytab /etc/
217             4. Restart sssd systemd service: sudo systemctl restart sssd
219         EOF
220         fi
221       '';
222     };
224     services.sssd.config = ''
225       [domain/${cfg.domain}]
226       id_provider = ipa
227       auth_provider = ipa
228       access_provider = ipa
229       chpass_provider = ipa
231       ipa_domain = ${cfg.domain}
232       ipa_server = _srv_, ${cfg.server}
233       ipa_hostname = ${cfg.ipaHostname}
235       cache_credentials = ${pyBool cfg.cacheCredentials}
236       krb5_store_password_if_offline = ${pyBool cfg.offlinePasswords}
237       ${optionalString ((toLower cfg.domain) != (toLower cfg.realm))
238         "krb5_realm = ${cfg.realm}"}
240       dyndns_update = ${pyBool cfg.dyndns.enable}
241       dyndns_iface = ${cfg.dyndns.interface}
243       ldap_tls_cacert = /etc/ipa/ca.crt
244       ldap_user_extra_attrs = mail:mail, sn:sn, givenname:givenname, telephoneNumber:telephoneNumber, lock:nsaccountlock
246       [sssd]
247       services = nss, sudo, pam, ssh, ifp
248       domains = ${cfg.domain}
250       [nss]
251       homedir_substring = /home
253       [pam]
254       pam_pwd_expiration_warning = 3
255       pam_verbosity = 3
257       [sudo]
259       [autofs]
261       [ssh]
263       [pac]
265       [ifp]
266       user_attributes = +mail, +telephoneNumber, +givenname, +sn, +lock
267       allowed_uids = ${concatStringsSep ", " cfg.ifpAllowedUids}
268     '';
270     services.ntp.servers = singleton cfg.server;
271     services.sssd.enable = true;
272     services.ntp.enable = true;
274     security.pki.certificateFiles = singleton cfg.certificate;
275   };