nixos/ipa: fix proper hostname handling (#461646)

This commit is contained in:
Sandro
2025-11-14 21:12:32 +00:00
committed by GitHub

View File

@@ -4,7 +4,7 @@
pkgs, pkgs,
... ...
}: }:
with lib;
let let
cfg = config.security.ipa; cfg = config.security.ipa;
@@ -30,17 +30,17 @@ in
{ {
options = { options = {
security.ipa = { security.ipa = {
enable = mkEnableOption "FreeIPA domain integration"; enable = lib.mkEnableOption "FreeIPA domain integration";
certificate = mkOption { certificate = lib.mkOption {
type = types.package; type = lib.types.package;
description = '' description = ''
IPA server CA certificate. IPA server CA certificate.
Use `nix-prefetch-url http://$server/ipa/config/ca.crt` to Use `nix-prefetch-url http://$server/ipa/config/ca.crt` to
obtain the file and the hash. obtain the file and the hash.
''; '';
example = literalExpression '' example = lib.literalExpression ''
pkgs.fetchurl { pkgs.fetchurl {
url = "http://ipa.example.com/ipa/config/ca.crt"; url = "http://ipa.example.com/ipa/config/ca.crt";
hash = lib.fakeHash; hash = lib.fakeHash;
@@ -48,87 +48,87 @@ in
''; '';
}; };
domain = mkOption { domain = lib.mkOption {
type = types.str; type = lib.types.str;
example = "example.com"; example = "example.com";
description = "Domain of the IPA server."; description = "Domain of the IPA server.";
}; };
realm = mkOption { realm = lib.mkOption {
type = types.str; type = lib.types.str;
example = "EXAMPLE.COM"; example = "EXAMPLE.COM";
description = "Kerberos realm."; description = "Kerberos realm.";
}; };
server = mkOption { server = lib.mkOption {
type = types.str; type = lib.types.str;
example = "ipa.example.com"; example = "ipa.example.com";
description = "IPA Server hostname."; description = "IPA Server hostname.";
}; };
basedn = mkOption { basedn = lib.mkOption {
type = types.str; type = lib.types.str;
example = "dc=example,dc=com"; example = "dc=example,dc=com";
description = "Base DN to use when performing LDAP operations."; description = "Base DN to use when performing LDAP operations.";
}; };
offlinePasswords = mkOption { offlinePasswords = lib.mkOption {
type = types.bool; type = lib.types.bool;
default = true; default = true;
description = "Whether to store offline passwords when the server is down."; description = "Whether to store offline passwords when the server is down.";
}; };
cacheCredentials = mkOption { cacheCredentials = lib.mkOption {
type = types.bool; type = lib.types.bool;
default = true; default = true;
description = "Whether to cache credentials."; description = "Whether to cache credentials.";
}; };
ipaHostname = mkOption { ipaHostname = lib.mkOption {
type = types.str; type = lib.types.str;
example = "myworkstation.example.com"; example = "myworkstation.example.com";
default = default =
if config.networking.domain != null then if config.networking.domain != null then
config.networking.fqdn config.networking.fqdn
else else
"${config.networking.hostName}.${cfg.domain}"; "${config.networking.hostName}.${cfg.domain}";
defaultText = literalExpression '' defaultText = lib.literalExpression ''
if config.networking.domain != null then config.networking.fqdn if config.networking.domain != null then config.networking.fqdn
else "''${networking.hostName}.''${security.ipa.domain}" else "''${networking.hostName}.''${security.ipa.domain}"
''; '';
description = "Fully-qualified hostname used to identify this host in the IPA domain."; description = "Fully-qualified hostname used to identify this host in the IPA domain.";
}; };
ifpAllowedUids = mkOption { ifpAllowedUids = lib.mkOption {
type = types.listOf types.str; type = lib.types.listOf lib.types.str;
default = [ "root" ]; default = [ "root" ];
description = "A list of users allowed to access the ifp dbus interface."; description = "A list of users allowed to access the ifp dbus interface.";
}; };
dyndns = { dyndns = {
enable = mkOption { enable = lib.mkOption {
type = types.bool; type = lib.types.bool;
default = true; default = true;
description = "Whether to enable FreeIPA automatic hostname updates."; description = "Whether to enable FreeIPA automatic hostname updates.";
}; };
interface = mkOption { interface = lib.mkOption {
type = types.str; type = lib.types.str;
example = "eth0"; example = "eth0";
default = "*"; default = "*";
description = "Network interface to perform hostname updates through."; description = "Network interface to perform hostname updates through.";
}; };
}; };
chromiumSupport = mkOption { chromiumSupport = lib.mkOption {
type = types.bool; type = lib.types.bool;
default = true; default = true;
description = "Whether to whitelist the FreeIPA domain in Chromium."; description = "Whether to whitelist the FreeIPA domain in Chromium.";
}; };
}; };
}; };
config = mkIf cfg.enable { config = lib.mkIf cfg.enable {
assertions = [ assertions = [
{ {
assertion = !config.security.krb5.enable; assertion = !config.security.krb5.enable;
@@ -146,16 +146,19 @@ in
]; ];
environment.etc = { environment.etc = {
"ipa/default.conf".text = '' "ipa/default.conf".text = lib.generators.toINI { } {
[global] global = {
basedn = ${cfg.basedn} inherit (cfg)
realm = ${cfg.realm} basedn
domain = ${cfg.domain} realm
server = ${cfg.server} domain
host = ${config.networking.hostName} server
xmlrpc_uri = https://${cfg.server}/ipa/xml ;
enable_ra = True host = cfg.ipaHostname;
''; xmlrpc_uri = "https://${cfg.server}/ipa/xml";
enable_ra = "True";
};
};
"ipa/nssdb".source = nssDb; "ipa/nssdb".source = nssDb;
@@ -191,7 +194,7 @@ in
"ldap.conf".source = ldapConf; "ldap.conf".source = ldapConf;
"chromium/policies/managed/freeipa.json" = mkIf cfg.chromiumSupport { "chromium/policies/managed/freeipa.json" = lib.mkIf cfg.chromiumSupport {
text = builtins.toJSON { text = builtins.toJSON {
AuthServerWhitelist = "*.${cfg.domain}"; AuthServerWhitelist = "*.${cfg.domain}";
}; };
@@ -248,7 +251,7 @@ in
cache_credentials = cfg.cacheCredentials; cache_credentials = cfg.cacheCredentials;
krb5_store_password_if_offline = cfg.offlinePasswords; krb5_store_password_if_offline = cfg.offlinePasswords;
krb5_realm = lib.mkIf ((toLower cfg.domain) != (toLower cfg.realm)) cfg.realm; krb5_realm = lib.mkIf ((lib.toLower cfg.domain) != (lib.toLower cfg.realm)) cfg.realm;
dyndns_update = cfg.dyndns.enable; dyndns_update = cfg.dyndns.enable;
dyndns_iface = cfg.dyndns.interface; dyndns_iface = cfg.dyndns.interface;
@@ -279,13 +282,13 @@ in
ifp = { ifp = {
user_attributes = "+mail, +telephoneNumber, +givenname, +sn, +lock"; user_attributes = "+mail, +telephoneNumber, +givenname, +sn, +lock";
allowed_uids = concatStringsSep ", " cfg.ifpAllowedUids; allowed_uids = lib.concatStringsSep ", " cfg.ifpAllowedUids;
}; };
}; };
}; };
networking.timeServers = singleton cfg.server; networking.timeServers = lib.singleton cfg.server;
security.pki.certificateFiles = singleton cfg.certificate; security.pki.certificateFiles = lib.singleton cfg.certificate;
}; };
} }