Merge pull request #30014 from eqyiel/krb5-fixes

nixos/krb5: complete rewrite

Changed files
+527 -207
nixos
-206
nixos/modules/config/krb5.nix
···
-
{ config, lib, pkgs, ... }:
-
-
with lib;
-
-
let
-
-
cfg = config.krb5;
-
-
in
-
-
{
-
###### interface
-
-
options = {
-
-
krb5 = {
-
-
enable = mkOption {
-
default = false;
-
description = "Whether to enable Kerberos V.";
-
};
-
-
defaultRealm = mkOption {
-
default = "ATENA.MIT.EDU";
-
description = "Default realm.";
-
};
-
-
domainRealm = mkOption {
-
default = "atena.mit.edu";
-
description = "Default domain realm.";
-
};
-
-
kdc = mkOption {
-
default = "kerberos.mit.edu";
-
description = "Key Distribution Center";
-
};
-
-
kerberosAdminServer = mkOption {
-
default = "kerberos.mit.edu";
-
description = "Kerberos Admin Server.";
-
};
-
-
};
-
-
};
-
-
###### implementation
-
-
config = mkIf config.krb5.enable {
-
-
environment.systemPackages = [ pkgs.krb5Full ];
-
-
environment.etc."krb5.conf".text =
-
''
-
[libdefaults]
-
default_realm = ${cfg.defaultRealm}
-
encrypt = true
-
-
# The following krb5.conf variables are only for MIT Kerberos.
-
krb4_config = /etc/krb.conf
-
krb4_realms = /etc/krb.realms
-
kdc_timesync = 1
-
ccache_type = 4
-
forwardable = true
-
proxiable = true
-
-
# The following encryption type specification will be used by MIT Kerberos
-
# if uncommented. In general, the defaults in the MIT Kerberos code are
-
# correct and overriding these specifications only serves to disable new
-
# encryption types as they are added, creating interoperability problems.
-
-
# default_tgs_enctypes = aes256-cts arcfour-hmac-md5 des3-hmac-sha1 des-cbc-crc des-cbc-md5
-
# default_tkt_enctypes = aes256-cts arcfour-hmac-md5 des3-hmac-sha1 des-cbc-crc des-cbc-md5
-
# permitted_enctypes = aes256-cts arcfour-hmac-md5 des3-hmac-sha1 des-cbc-crc des-cbc-md5
-
-
# The following libdefaults parameters are only for Heimdal Kerberos.
-
v4_instance_resolve = false
-
v4_name_convert = {
-
host = {
-
rcmd = host
-
ftp = ftp
-
}
-
plain = {
-
something = something-else
-
}
-
}
-
fcc-mit-ticketflags = true
-
-
[realms]
-
${cfg.defaultRealm} = {
-
kdc = ${cfg.kdc}
-
admin_server = ${cfg.kerberosAdminServer}
-
#kpasswd_server = ${cfg.kerberosAdminServer}
-
}
-
ATHENA.MIT.EDU = {
-
kdc = kerberos.mit.edu:88
-
kdc = kerberos-1.mit.edu:88
-
kdc = kerberos-2.mit.edu:88
-
admin_server = kerberos.mit.edu
-
default_domain = mit.edu
-
}
-
MEDIA-LAB.MIT.EDU = {
-
kdc = kerberos.media.mit.edu
-
admin_server = kerberos.media.mit.edu
-
}
-
ZONE.MIT.EDU = {
-
kdc = casio.mit.edu
-
kdc = seiko.mit.edu
-
admin_server = casio.mit.edu
-
}
-
MOOF.MIT.EDU = {
-
kdc = three-headed-dogcow.mit.edu:88
-
kdc = three-headed-dogcow-1.mit.edu:88
-
admin_server = three-headed-dogcow.mit.edu
-
}
-
CSAIL.MIT.EDU = {
-
kdc = kerberos-1.csail.mit.edu
-
kdc = kerberos-2.csail.mit.edu
-
admin_server = kerberos.csail.mit.edu
-
default_domain = csail.mit.edu
-
krb524_server = krb524.csail.mit.edu
-
}
-
IHTFP.ORG = {
-
kdc = kerberos.ihtfp.org
-
admin_server = kerberos.ihtfp.org
-
}
-
GNU.ORG = {
-
kdc = kerberos.gnu.org
-
kdc = kerberos-2.gnu.org
-
kdc = kerberos-3.gnu.org
-
admin_server = kerberos.gnu.org
-
}
-
1TS.ORG = {
-
kdc = kerberos.1ts.org
-
admin_server = kerberos.1ts.org
-
}
-
GRATUITOUS.ORG = {
-
kdc = kerberos.gratuitous.org
-
admin_server = kerberos.gratuitous.org
-
}
-
DOOMCOM.ORG = {
-
kdc = kerberos.doomcom.org
-
admin_server = kerberos.doomcom.org
-
}
-
ANDREW.CMU.EDU = {
-
kdc = vice28.fs.andrew.cmu.edu
-
kdc = vice2.fs.andrew.cmu.edu
-
kdc = vice11.fs.andrew.cmu.edu
-
kdc = vice12.fs.andrew.cmu.edu
-
admin_server = vice28.fs.andrew.cmu.edu
-
default_domain = andrew.cmu.edu
-
}
-
CS.CMU.EDU = {
-
kdc = kerberos.cs.cmu.edu
-
kdc = kerberos-2.srv.cs.cmu.edu
-
admin_server = kerberos.cs.cmu.edu
-
}
-
DEMENTIA.ORG = {
-
kdc = kerberos.dementia.org
-
kdc = kerberos2.dementia.org
-
admin_server = kerberos.dementia.org
-
}
-
stanford.edu = {
-
kdc = krb5auth1.stanford.edu
-
kdc = krb5auth2.stanford.edu
-
kdc = krb5auth3.stanford.edu
-
admin_server = krb5-admin.stanford.edu
-
default_domain = stanford.edu
-
}
-
-
[domain_realm]
-
.${cfg.domainRealm} = ${cfg.defaultRealm}
-
${cfg.domainRealm} = ${cfg.defaultRealm}
-
.mit.edu = ATHENA.MIT.EDU
-
mit.edu = ATHENA.MIT.EDU
-
.exchange.mit.edu = EXCHANGE.MIT.EDU
-
exchange.mit.edu = EXCHANGE.MIT.EDU
-
.media.mit.edu = MEDIA-LAB.MIT.EDU
-
media.mit.edu = MEDIA-LAB.MIT.EDU
-
.csail.mit.edu = CSAIL.MIT.EDU
-
csail.mit.edu = CSAIL.MIT.EDU
-
.whoi.edu = ATHENA.MIT.EDU
-
whoi.edu = ATHENA.MIT.EDU
-
.stanford.edu = stanford.edu
-
-
[logging]
-
kdc = SYSLOG:INFO:DAEMON
-
admin_server = SYSLOG:INFO:DAEMON
-
default = SYSLOG:INFO:DAEMON
-
krb4_convert = true
-
krb4_get_tickets = false
-
-
[appdefaults]
-
pam = {
-
debug = false
-
ticket_lifetime = 36000
-
renew_lifetime = 36000
-
max_timeout = 30
-
timeout_shift = 2
-
initial_timeout = 1
-
}
-
'';
-
-
};
-
-
}
···
+367
nixos/modules/config/krb5/default.nix
···
···
+
{ config, lib, pkgs, ... }:
+
+
with lib;
+
+
let
+
+
cfg = config.krb5;
+
+
# This is to provide support for old configuration options (as much as is
+
# reasonable). This can be removed after 18.03 was released.
+
defaultConfig = {
+
libdefaults = optionalAttrs (cfg.defaultRealm != null)
+
{ default_realm = cfg.defaultRealm; };
+
+
realms = optionalAttrs (lib.all (value: value != null) [
+
cfg.defaultRealm cfg.kdc cfg.kerberosAdminServer
+
]) {
+
"${cfg.defaultRealm}" = {
+
kdc = cfg.kdc;
+
admin_server = cfg.kerberosAdminServer;
+
};
+
};
+
+
domain_realm = optionalAttrs (lib.all (value: value != null) [
+
cfg.domainRealm cfg.defaultRealm
+
]) {
+
".${cfg.domainRealm}" = cfg.defaultRealm;
+
"${cfg.domainRealm}" = cfg.defaultRealm;
+
};
+
};
+
+
mergedConfig = (recursiveUpdate defaultConfig {
+
inherit (config.krb5)
+
kerberos libdefaults realms domain_realm capaths appdefaults plugins
+
extraConfig config;
+
});
+
+
filterEmbeddedMetadata = value: if isAttrs value then
+
(filterAttrs
+
(attrName: attrValue: attrName != "_module" && attrValue != null)
+
value)
+
else value;
+
+
mkIndent = depth: concatStrings (builtins.genList (_: " ") (2 * depth));
+
+
mkRelation = name: value: "${name} = ${mkVal { inherit value; }}";
+
+
mkVal = { value, depth ? 0 }:
+
if (value == true) then "true"
+
else if (value == false) then "false"
+
else if (isInt value) then (toString value)
+
else if (isList value) then
+
concatMapStringsSep " " mkVal { inherit value depth; }
+
else if (isAttrs value) then
+
(concatStringsSep "\n${mkIndent (depth + 1)}"
+
([ "{" ] ++ (mapAttrsToList
+
(attrName: attrValue: let
+
mappedAttrValue = mkVal {
+
value = attrValue;
+
depth = depth + 1;
+
};
+
in "${attrName} = ${mappedAttrValue}")
+
value))) + "\n${mkIndent depth}}"
+
else value;
+
+
mkMappedAttrsOrString = value: concatMapStringsSep "\n"
+
(line: if builtins.stringLength line > 0
+
then "${mkIndent 1}${line}"
+
else line)
+
(splitString "\n"
+
(if isAttrs value then
+
concatStringsSep "\n"
+
(mapAttrsToList mkRelation value)
+
else value));
+
+
in {
+
+
###### interface
+
+
options = {
+
krb5 = {
+
enable = mkEnableOption "Whether to enable Kerberos V.";
+
+
kerberos = mkOption {
+
type = types.package;
+
default = pkgs.krb5Full;
+
defaultText = "pkgs.krb5Full";
+
example = literalExample "pkgs.heimdalFull";
+
description = ''
+
The Kerberos implementation that will be present in
+
<literal>environment.systemPackages</literal> after enabling this
+
service.
+
'';
+
};
+
+
libdefaults = mkOption {
+
type = with types; either attrs lines;
+
default = {};
+
apply = attrs: filterEmbeddedMetadata attrs;
+
example = literalExample ''
+
{
+
default_realm = "ATHENA.MIT.EDU";
+
};
+
'';
+
description = ''
+
Settings used by the Kerberos V5 library.
+
'';
+
};
+
+
realms = mkOption {
+
type = with types; either attrs lines;
+
default = {};
+
example = literalExample ''
+
{
+
"ATHENA.MIT.EDU" = {
+
admin_server = "athena.mit.edu";
+
kdc = "athena.mit.edu";
+
};
+
};
+
'';
+
apply = attrs: filterEmbeddedMetadata attrs;
+
description = "Realm-specific contact information and settings.";
+
};
+
+
domain_realm = mkOption {
+
type = with types; either attrs lines;
+
default = {};
+
example = literalExample ''
+
{
+
"example.com" = "EXAMPLE.COM";
+
".example.com" = "EXAMPLE.COM";
+
};
+
'';
+
apply = attrs: filterEmbeddedMetadata attrs;
+
description = ''
+
Map of server hostnames to Kerberos realms.
+
'';
+
};
+
+
capaths = mkOption {
+
type = with types; either attrs lines;
+
default = {};
+
example = literalExample ''
+
{
+
"ATHENA.MIT.EDU" = {
+
"EXAMPLE.COM" = ".";
+
};
+
"EXAMPLE.COM" = {
+
"ATHENA.MIT.EDU" = ".";
+
};
+
};
+
'';
+
apply = attrs: filterEmbeddedMetadata attrs;
+
description = ''
+
Authentication paths for non-hierarchical cross-realm authentication.
+
'';
+
};
+
+
appdefaults = mkOption {
+
type = with types; either attrs lines;
+
default = {};
+
example = literalExample ''
+
{
+
pam = {
+
debug = false;
+
ticket_lifetime = 36000;
+
renew_lifetime = 36000;
+
max_timeout = 30;
+
timeout_shift = 2;
+
initial_timeout = 1;
+
};
+
};
+
'';
+
apply = attrs: filterEmbeddedMetadata attrs;
+
description = ''
+
Settings used by some Kerberos V5 applications.
+
'';
+
};
+
+
plugins = mkOption {
+
type = with types; either attrs lines;
+
default = {};
+
example = literalExample ''
+
{
+
ccselect = {
+
disable = "k5identity";
+
};
+
};
+
'';
+
apply = attrs: filterEmbeddedMetadata attrs;
+
description = ''
+
Controls plugin module registration.
+
'';
+
};
+
+
extraConfig = mkOption {
+
type = with types; nullOr lines;
+
default = null;
+
example = ''
+
[logging]
+
kdc = SYSLOG:NOTICE
+
admin_server = SYSLOG:NOTICE
+
default = SYSLOG:NOTICE
+
'';
+
description = ''
+
These lines go to the end of <literal>krb5.conf</literal> verbatim.
+
<literal>krb5.conf</literal> may include any of the relations that are
+
valid for <literal>kdc.conf</literal> (see <literal>man
+
kdc.conf</literal>), but it is not a recommended practice.
+
'';
+
};
+
+
config = mkOption {
+
type = with types; nullOr lines;
+
default = null;
+
example = ''
+
[libdefaults]
+
default_realm = EXAMPLE.COM
+
+
[realms]
+
EXAMPLE.COM = {
+
admin_server = kerberos.example.com
+
kdc = kerberos.example.com
+
default_principal_flags = +preauth
+
}
+
+
[domain_realm]
+
example.com = EXAMPLE.COM
+
.example.com = EXAMPLE.COM
+
+
[logging]
+
kdc = SYSLOG:NOTICE
+
admin_server = SYSLOG:NOTICE
+
default = SYSLOG:NOTICE
+
'';
+
description = ''
+
Verbatim <literal>krb5.conf</literal> configuration. Note that this
+
is mutually exclusive with configuration via
+
<literal>libdefaults</literal>, <literal>realms</literal>,
+
<literal>domain_realm</literal>, <literal>capaths</literal>,
+
<literal>appdefaults</literal>, <literal>plugins</literal> and
+
<literal>extraConfig</literal> configuration options. Consult
+
<literal>man krb5.conf</literal> for documentation.
+
'';
+
};
+
+
defaultRealm = mkOption {
+
type = with types; nullOr str;
+
default = null;
+
example = "ATHENA.MIT.EDU";
+
description = ''
+
DEPRECATED, please use
+
<literal>krb5.libdefaults.default_realm</literal>.
+
'';
+
};
+
+
domainRealm = mkOption {
+
type = with types; nullOr str;
+
default = null;
+
example = "athena.mit.edu";
+
description = ''
+
DEPRECATED, please create a map of server hostnames to Kerberos realms
+
in <literal>krb5.domain_realm</literal>.
+
'';
+
};
+
+
kdc = mkOption {
+
type = with types; nullOr str;
+
default = null;
+
example = "kerberos.mit.edu";
+
description = ''
+
DEPRECATED, please pass a <literal>kdc</literal> attribute to a realm
+
in <literal>krb5.realms</literal>.
+
'';
+
};
+
+
kerberosAdminServer = mkOption {
+
type = with types; nullOr str;
+
default = null;
+
example = "kerberos.mit.edu";
+
description = ''
+
DEPRECATED, please pass an <literal>admin_server</literal> attribute
+
to a realm in <literal>krb5.realms</literal>.
+
'';
+
};
+
};
+
};
+
+
###### implementation
+
+
config = mkIf cfg.enable {
+
+
environment.systemPackages = [ cfg.kerberos ];
+
+
environment.etc."krb5.conf".text = if isString cfg.config
+
then cfg.config
+
else (''
+
[libdefaults]
+
${mkMappedAttrsOrString mergedConfig.libdefaults}
+
+
[realms]
+
${mkMappedAttrsOrString mergedConfig.realms}
+
+
[domain_realm]
+
${mkMappedAttrsOrString mergedConfig.domain_realm}
+
+
[capaths]
+
${mkMappedAttrsOrString mergedConfig.capaths}
+
+
[appdefaults]
+
${mkMappedAttrsOrString mergedConfig.appdefaults}
+
+
[plugins]
+
${mkMappedAttrsOrString mergedConfig.plugins}
+
'' + optionalString (mergedConfig.extraConfig != null)
+
("\n" + mergedConfig.extraConfig));
+
+
warnings = flatten [
+
(optional (cfg.defaultRealm != null) ''
+
The option krb5.defaultRealm is deprecated, please use
+
krb5.libdefaults.default_realm.
+
'')
+
(optional (cfg.domainRealm != null) ''
+
The option krb5.domainRealm is deprecated, please use krb5.domain_realm.
+
'')
+
(optional (cfg.kdc != null) ''
+
The option krb5.kdc is deprecated, please pass a kdc attribute to a
+
realm in krb5.realms.
+
'')
+
(optional (cfg.kerberosAdminServer != null) ''
+
The option krb5.kerberosAdminServer is deprecated, please pass an
+
admin_server attribute to a realm in krb5.realms.
+
'')
+
];
+
+
assertions = [
+
{ assertion = !((builtins.any (value: value != null) [
+
cfg.defaultRealm cfg.domainRealm cfg.kdc cfg.kerberosAdminServer
+
]) && ((builtins.any (value: value != {}) [
+
cfg.libdefaults cfg.realms cfg.domain_realm cfg.capaths
+
cfg.appdefaults cfg.plugins
+
]) || (builtins.any (value: value != null) [
+
cfg.config cfg.extraConfig
+
])));
+
message = ''
+
Configuration of krb5.conf by deprecated options is mutually exclusive
+
with configuration by section. Please migrate your config using the
+
attributes suggested in the warnings.
+
'';
+
}
+
{ assertion = !(cfg.config != null
+
&& ((builtins.any (value: value != {}) [
+
cfg.libdefaults cfg.realms cfg.domain_realm cfg.capaths
+
cfg.appdefaults cfg.plugins
+
]) || (builtins.any (value: value != null) [
+
cfg.extraConfig cfg.defaultRealm cfg.domainRealm cfg.kdc
+
cfg.kerberosAdminServer
+
])));
+
message = ''
+
Configuration of krb5.conf using krb.config is mutually exclusive with
+
configuration by section. If you want to mix the two, you can pass
+
lines to any configuration section or lines to krb5.extraConfig.
+
'';
+
}
+
];
+
};
+
}
+1 -1
nixos/modules/module-list.nix
···
./config/fonts/ghostscript.nix
./config/gnu.nix
./config/i18n.nix
-
./config/krb5.nix
./config/ldap.nix
./config/networking.nix
./config/no-x-libs.nix
···
./config/fonts/ghostscript.nix
./config/gnu.nix
./config/i18n.nix
+
./config/krb5/default.nix
./config/ldap.nix
./config/networking.nix
./config/no-x-libs.nix
+5
nixos/tests/krb5/default.nix
···
···
+
{ system ? builtins.currentSystem }:
+
{
+
example-config = import ./example-config.nix { inherit system; };
+
deprecated-config = import ./deprecated-config.nix { inherit system; };
+
}
+48
nixos/tests/krb5/deprecated-config.nix
···
···
+
# Verifies that the configuration suggested in deprecated example values
+
# will result in the expected output.
+
+
import ../make-test.nix ({ pkgs, ...} : {
+
name = "krb5-with-deprecated-config";
+
meta = with pkgs.stdenv.lib.maintainers; {
+
maintainers = [ eqyiel ];
+
};
+
+
machine =
+
{ config, pkgs, ... }: {
+
krb5 = {
+
enable = true;
+
defaultRealm = "ATHENA.MIT.EDU";
+
domainRealm = "athena.mit.edu";
+
kdc = "kerberos.mit.edu";
+
kerberosAdminServer = "kerberos.mit.edu";
+
};
+
};
+
+
testScript =
+
let snapshot = pkgs.writeText "krb5-with-deprecated-config.conf" ''
+
[libdefaults]
+
default_realm = ATHENA.MIT.EDU
+
+
[realms]
+
ATHENA.MIT.EDU = {
+
admin_server = kerberos.mit.edu
+
kdc = kerberos.mit.edu
+
}
+
+
[domain_realm]
+
.athena.mit.edu = ATHENA.MIT.EDU
+
athena.mit.edu = ATHENA.MIT.EDU
+
+
[capaths]
+
+
+
[appdefaults]
+
+
+
[plugins]
+
+
'';
+
in ''
+
$machine->succeed("diff /etc/krb5.conf ${snapshot}");
+
'';
+
})
+106
nixos/tests/krb5/example-config.nix
···
···
+
# Verifies that the configuration suggested in (non-deprecated) example values
+
# will result in the expected output.
+
+
import ../make-test.nix ({ pkgs, ...} : {
+
name = "krb5-with-example-config";
+
meta = with pkgs.stdenv.lib.maintainers; {
+
maintainers = [ eqyiel ];
+
};
+
+
machine =
+
{ config, pkgs, ... }: {
+
krb5 = {
+
enable = true;
+
kerberos = pkgs.krb5Full;
+
libdefaults = {
+
default_realm = "ATHENA.MIT.EDU";
+
};
+
realms = {
+
"ATHENA.MIT.EDU" = {
+
admin_server = "athena.mit.edu";
+
kdc = "athena.mit.edu";
+
};
+
};
+
domain_realm = {
+
"example.com" = "EXAMPLE.COM";
+
".example.com" = "EXAMPLE.COM";
+
};
+
capaths = {
+
"ATHENA.MIT.EDU" = {
+
"EXAMPLE.COM" = ".";
+
};
+
"EXAMPLE.COM" = {
+
"ATHENA.MIT.EDU" = ".";
+
};
+
};
+
appdefaults = {
+
pam = {
+
debug = false;
+
ticket_lifetime = 36000;
+
renew_lifetime = 36000;
+
max_timeout = 30;
+
timeout_shift = 2;
+
initial_timeout = 1;
+
};
+
};
+
plugins = {
+
ccselect = {
+
disable = "k5identity";
+
};
+
};
+
extraConfig = ''
+
[logging]
+
kdc = SYSLOG:NOTICE
+
admin_server = SYSLOG:NOTICE
+
default = SYSLOG:NOTICE
+
'';
+
};
+
};
+
+
testScript =
+
let snapshot = pkgs.writeText "krb5-with-example-config.conf" ''
+
[libdefaults]
+
default_realm = ATHENA.MIT.EDU
+
+
[realms]
+
ATHENA.MIT.EDU = {
+
admin_server = athena.mit.edu
+
kdc = athena.mit.edu
+
}
+
+
[domain_realm]
+
.example.com = EXAMPLE.COM
+
example.com = EXAMPLE.COM
+
+
[capaths]
+
ATHENA.MIT.EDU = {
+
EXAMPLE.COM = .
+
}
+
EXAMPLE.COM = {
+
ATHENA.MIT.EDU = .
+
}
+
+
[appdefaults]
+
pam = {
+
debug = false
+
initial_timeout = 1
+
max_timeout = 30
+
renew_lifetime = 36000
+
ticket_lifetime = 36000
+
timeout_shift = 2
+
}
+
+
[plugins]
+
ccselect = {
+
disable = k5identity
+
}
+
+
[logging]
+
kdc = SYSLOG:NOTICE
+
admin_server = SYSLOG:NOTICE
+
default = SYSLOG:NOTICE
+
'';
+
in ''
+
$machine->succeed("diff /etc/krb5.conf ${snapshot}");
+
'';
+
})