Projects/Server Hostname Canonicalization
This page tracks efforts to provide a pathway away from using insecure name services for server hostname canonicalization.
- 1 Reverse name resolution
- 2 An option to turn off name resolution entirely
- 3 A transition path for turning off name resolution
- 4 Qualifying short names
- 5 Heimdal name canonicalization rules
- 6 Turning off canonicalization at the KDC
- 7 Other uses of sname-to-principal besides TGS requests
Reverse name resolution
By default, krb5_sname_to_principal() not only canonicalizes server hostnames using forward name resolution, but also tries to use reverse resolution on the resulting IP address. This additional step is not performed by Heimdal and is generally considered to cause more harm than good, but turning it off by default would be disruptive to existing deployments. Release 1.4 added a boolean krb5.conf variable "rdns" which can be set to false to disable this step.
An option to turn off name resolution entirely
Release 1.12 added a boolean krb5.conf variable "dns_canonicalize_hostname" which can be set to false to disable the use of name-service resolution in krb5_sname_to_principal(). This option name was first implemented in Heimdal.
A transition path for turning off name resolution
Red Hat's experiments with turning off dns_canonicalize_hostname by default determined that many deployments have provisioned keytabs under the assumption that canonicalization will occur, and that is difficult to determine ahead of time which keytabs need to be re-provisioned.
Release 1.18 will add "dns_canonicalize_hostname=fallback", which will turn off canonicalization in krb5_sname_to_principal(), but will cause krb5_get_credentials() to retry TGS requests after server hostname canonicalization if the original attempt fails with KDC_ERR_S_PRINCIPAL_UNKNOWN.
Setting dns_canonicalize_hostname=fallback will not provide any security benefit (because the PRINCIPAL_UNKNOWN error can be faked, even if FAST TGS is used). However, examining KDC logs after it has been set can help determine which alias names need keys provisioned.
Qualifying short names
In addition to resolving aliases, DNS canonicalization also expands short hostnames by trying to append one or more DNS suffixes, e.g. changing "small-gods" to "small-gods.mit.edu". Suffixes are tried even for multi-component names if the original name is not found in the DNS. (Suffixes may be tried for multi-component names before trying the original name, if the "ndots" variable is set to a value greater than 1 in resolv.conf.)
If name service canonicalization is turned off, users lose the convenience of automatically qualifying short names. We could restore at least some of this convenience without using DNS. Possibilities include providing a configurable suffix for single-label names, and/or looking into _res (or the res_state object populated by res_ninit()) to find the DNS search suffixes automatically. (TBD: research whether it is similarly possible to obtain this information on Windows.)
Qualifying shortnames with a single suffix is simpler than supporting multiple suffixes, because it could be performed immediately in krb5_sname_to_principal() and does not require retries. Some environments use multiple search suffixes; to support this case, krb5_sname_to_principal() would have to leave the short hostname in the principal name, and krb5_get_credentials() would have to add suffixes when performing TGS requests. An attacker could fake PRINCIPAL_UNKNOWN errors to influence which suffix is used for the successful query if server principals are present for multiple qualified versions of the short name.
The local hostname
A significant case of short names is the local hostname. POSIX provides a gethostname() function to determine the local name, but it normally only returns a single label. The only standard way to expand this name to a fully-qualified name is to use getaddrinfo(), which risks using insecure name resolution (although in many cases the answer is discovered after consulting only /etc/hosts).
It may make sense to add a configuration variable for the fully-qualified local hostname, or the more general solution for qualifying shortnames may turn out to be sufficient.
Heimdal name canonicalization rules
Heimdal (as of 2011) supports the name_canon_rules krb5.conf variable, allowing greater administrator control over the canonical principal names the library will try. Here is an example from Heimdal's krb5.conf(5) man page:
[libdefaults] name_canon_rules = as-is:realm=FOO.SE name_canon_rules = qualify:domain=foo.se:realm=FOO.SE name_canon_rules = qualify:domain=bar.se:realm=FOO.SE name_canon_rules = nss
We could implement all or a subset of these semantics. However, rule-based configuration facilities (PAM, auth_to_local, etc.) are notoriously error-prone for administrators, so providing simpler options for common scenarios is a higher priority.
Turning off canonicalization at the KDC
All of the above solutions require client-side configuration, which can be a burden to deploy. We can lift that burden by allowing a KDC to express in an AS reply that it can canonicalize server hostnames for requests to that realm. This could be communicated via a ticket flag, or alternatively through encrypted padata.
Other uses of sname-to-principal besides TGS requests
In release 1.6, krb5_sname_to_principal() was changed to support referrals, with complementary changes to krb5_get_credentials(). This change created numerous ripple effects due to other uses of the sname-to-principal facility. As we are considering again changing the semantics of krb5_sname_to_principal(), we should inventory other uses of name canonicalization.
After TGS requests, the most common use of canonicalization is on the local hostname to determine the acceptor principal for gss_accept_sec_context() or krb5_rd_req(). For this case the keytab could be consulted to try multiple canonicalization possibilities.
Instances of this use case within the krb5 source tree are:
- kpropd, for receiving dumps from kprop.
- The sample and simple servers.
- The GSS sample server imports the name it is told on the command line as a host-based name; this string might include a hostname.
kprop and kpropd canonicalize the local hostname to determine a client principal which is expected to exist in the keytab. Keytab search could again be used to try multiple possibilities.
Some code canonicalizes a server principal for use with a direct AS request to the service. The KDC could be used to try multiple possibilities, but the relevant code path is the init_creds code, not krb5_get_credentials(). These cases are:
- The kadm5 client initialization functions use the canonicalized admin hostname. This code falls back to kadmin/admin if it does not find the host-based principal, so a change in the canonicalized result might go unnoticed.
- kprop uses the canonicalized replica hostname provided on the command line.
- kpropd uses the un-canonicalized admin hostname when constructing the kiprop/hostname service principal for kadmind. This is inconsistent with other uses of the admin hostname and is perhaps a bug.
"kdb5_util create" canonicalizes the local hostname to determine what kadmin/hostname and kiprop/hostname principals to create. There is no authoritative source to search multiple values. "kdb5_ldap_util create" has separate code to do the same.
- TBD: lib/gssapi/krb5/import_name.c
- TBD: lib/gssapi/krb5/naming_exts.c
- TBD: kadmin/cli/kadmin.c
- TBD: clients/kinit/kinit.c
- TBD: clients/kvno/kvno.c
- TBD: clients/ksu/heuristic.c
- TBD: GSS applications which commonly import "host@gethostname()" as a host-based name