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.
- The kadm5 client code canonicalizes the configured admin server name to construct the kadmin/hostname service principal, for a direct AS request. If this principal is not found, kadmin will fall back to using kadmin/admin, so a change in the canonicalization result would usually go unnoticed. The KDC could be used to search multiple values, though the AS request code would need to iterate, as this code does not use krb5_get_credentials(). We could possibly get away with just using kadmin/admin initially, and not worry too much about the host-based principal name.
- "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.
- kprop canonicalizes the local hostname to determine its client principal (host/local-hostname), and canonicalizes the replica hostname to determine the kpropd service principal (host/replica-hostname) for an AS request directly to the service principal. The keytab could be used to search multiple client principal names and the KDC could be used to search multiple server principal names. (As with the kadm5 client code, the AS request code would need to iterate.)
- kpropd canonicalizes the local hostname to determine its client principal (kiprop/local-hostname) and its service principal for receiving kprop dumps (host/local-hostname). The keytab could be used to search multiple values.
- TBD: plugins/kdb/ldap/ldap_util/kdb5_ldap_realm.c
- TBD: appl/simple/server/sim_server.c
- TBD: appl/sample/sserver/sserver.c
- 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