logo_kerberos.gif

Difference between revisions of "Projects/Keytab initiation"

From K5Wiki
Jump to: navigation, search
(Code components)
Line 9: Line 9:
 
== Requirements ==
 
== Requirements ==
   
1. The system should work, perhaps with some external configuration, for a typical caller which invokes gss_init_sec_context() with no initiator cred (or, equivalently, acquires an initiator cred with no desired name).
+
# The system should work, perhaps with some external configuration, for a typical caller which invokes gss_init_sec_context() with no initiator cred (or, equivalently, acquires an initiator cred with no desired name).
+
# The system should also behave as well as possible when the caller does supply a desired name, or when krb5_cc_select() can deduce a client principal from the target name. In this case, multiple principals from the same keytab might be used for different initiations.
2. The system should also behave as well as possible when the caller does supply a desired name, or when krb5_cc_select() can deduce a client principal from the target name. In this case, multiple principals from the same keytab might be used for different initiations.
+
# The system should work well with credential cache collections (see [[Projects/Client_principal_selection]]). For example, an application should be able to, from the same process, initiate two security contexts with different desired names, using the same keytab, and have the resulting credentials both be cached within the collection (assuming the default ccache is collection-enabled).
+
# There should be minimal or no surprise. An existing deployment of GSSAPI applications should not begin doing keytab-based initiation and write to the default per-uid ccache without reason to believe this is intended.
3. The system should work well with credential cache collections (see [[Projects/Client_principal_selection]]). For example, an application should be able to, from the same process, initiate two security contexts with different desired names, using the same keytab, and have the resulting credentials both be cached within the collection (assuming the default ccache is collection-enabled).
+
# Credentials obtained this way should be cached. Otherwise, applications which initialize many security contexts (such as HTTP clients) could generate large numbers of unnecessary AS and TGS requests.
 
4. There should be minimal or no surprise. An existing deployment of GSSAPI applications should not begin doing keytab-based initiation and write to the default per-uid ccache without reason to believe this is intended.
 
 
5. Credentials obtained this way should be cached. Otherwise, applications which initialize many security contexts (such as HTTP clients) could generate large numbers of unnecessary AS and TGS requests.
 
   
 
It is not required for this system to work with initiators like krlogin which directly use libkrb5. However, some of the underlying components may be useful for FAST armor ccaches, so putting reusable parts of the code in libkrb5 is desirable.
 
It is not required for this system to work with initiators like krlogin which directly use libkrb5. However, some of the underlying components may be useful for FAST armor ccaches, so putting reusable parts of the code in libkrb5 is desirable.
Line 24: Line 24:
   
 
Automated keytab initiation will not make use of this keytab. Instead, there will be a new complementary "default client keytab", obtained with krb5_kt_client_default(), with its own set of underlying discovery mechanisms. Unless an administrator sets up a client keytab, automated keytab initiation will not take place, thus minimizing surprise.
 
Automated keytab initiation will not make use of this keytab. Instead, there will be a new complementary "default client keytab", obtained with krb5_kt_client_default(), with its own set of underlying discovery mechanisms. Unless an administrator sets up a client keytab, automated keytab initiation will not take place, thus minimizing surprise.
  +
  +
(TBD: what discovery mechanisms do we need? Candidates include a revised version of gss_krb5_import_cred with a client keytab argument, a GSS extension parallel to krb5_gss_register_acceptor_identity, a URN for [[Projects/Credential_Store_extensions]], an environment variable parallel to KRB5_KTNAME, a profile relation parallel to default_keytab_name, and a hardcoded default.)
   
 
=== Caching and refreshing ===
 
=== Caching and refreshing ===
   
Initial credentials obtained through automated keytab initiation will be cached in the default ccache or, if the default ccache type supports it, the associated collection. The new ccache will remember, using ccache config entries, which keytab name was used to obtain the credentials and the time of the last attempt to refresh them (if any). The gss-krb5 initiator code will attempt to refresh the cache with the keytab again if (1) the credentials are at least halfway to being expired, and (2) the last recorded attempt to refresh the cache was more than a minimum delta of time in the past.
+
Initial credentials obtained through automated keytab initiation will be cached in the default ccache or, if the default ccache type supports it, the associated collection. The new ccache will remember, using ccache config entries, the time of the last attempt to refresh credentials from the client keytab (or a distinguished value if there has been no attempt yet). The gss-krb5 initiator code will attempt to refresh the cache with the keytab again if (1) the credentials are at least halfway to being expired, and (2) the last recorded attempt to refresh the cache was more than a minimum delta of time in the past.
   
 
=== Code changes ===
 
=== Code changes ===
   
In gss-krb5:
 
  +
Introducing a client keytab requires a careful re-evaluation of the lifetime of an initiator credential, which has three stages:
  +
  +
# acquire_init_cred, called from gss_acquire_cred, records the information given by the caller (which may include client principal, ccache, client keytab, and/or password), and detects errors based on the information known so far. If the necessary information is available and IAKERB is not in use, acquire_init_cred acquires a TGT using the password, client keytab, or (only on Windows at the moment) interactive input.
  +
# kg_cred_resolve, called from gss_init_sec_context or gss_inquire_cred, forces resolution of the client principal, using the target principal if called from gss_inquire_cred. kg_cred_resolve detects errors and/or acquires an initial TGT as acquire_init_creds would have given the new information.
  +
# get_credentials, called from gss_init_sec_context, gets a service ticket (possibly making a TGS request if IAKERB is not in use).
   
* acquire_init_creds: if #7160 is fixed, credentials should be considered available if the default client keytab has content. If a desired_name is specified and no credentials for it are available in the default ccache (or collection), search the default client keytab for desired_name and, if it is found, prep the default ccache (or a new ccache in the collection) for keytab initiation.
 
  +
The client principal is determined by, in order of preference:
  +
* (Stage 1) The caller's desired_name parameter if given.
  +
* (Stage 1) The principal of the caller-specified ccache, if one is given and exists.
  +
* (Stage 2) The principal of an existing ccache determined by krb5_cc_select using the target principal.
  +
* (Stage 2) The principal determined by krb5_cc_select (for which we do not have an existing ccache).
  +
* (Stage 2) The principal of the default ccache, if it exists.
  +
* (Stage 2) The first principal listed in the client keytab, if we have one. (If we choose this, we need to re-check the collection for an existing ccache for this principal.)
  +
* Give up and return an error
   
* kg_cred_resolve: if client_princ is determined by krb5_cc_select but no cache is available, search the default client keytab for that principal and prep a ccache as above. (TBD: obviously this should be factored out into a helper; figure out how that fits in with scan_ccache and prep_ccache.)
 
  +
If the ccache is not determined from caller parameters, it can be determined once the client principal is known:
  +
* If there is an existing ccache in the collection for the client principal, use that
  +
* If the default cache is not collection-enabled, use it (which may result in an error if it doesn't match the client principal)
  +
* If the caller supplied a password and there is no default cache yet, use the default cache as the destination
  +
* Use a new unique ccache of the default type as the destination
   
* get_credentials: before calling krb5_get_credentials, check the cache for config variables indicating it's time to try a refresh with the client keytab. If so, and this is not an IAKERB cred, attempt the refresh. If it fails, record the timestamp of the last refresh. If krb5_get_credentials fails with KRB5_CC_NOTFOUND and this is not an IAKERB cred, try to get credentials with the default client keytab. (TBD: some of this logic should be in private libkrb5 interfaces for use by FAST ccaches.)
 
  +
The errors we could detect at stages 1 and 2 are:
  +
* Client principal and ccache are known, and ccache contains creds for a different principal
  +
* Client principal and ccache are known, ccache contains no current creds for client principal, and we have no way (password or client keytab) to acquire creds for client principal
  +
* Client principal is known, there is a default ccache which is not collection-enabled, and it contains creds for a different principal
  +
* Client principal is known, there are no creds available for it in the collection, and we have no way to acquire creds for it
  +
* ccache is known but is empty, and we have no way to acquire creds
  +
* There are no creds at all in the collection and we have no way to acquire creds for any principal
   
* iakerb_get_initial_state: similar logic to the above, but set up for an IAKERB AS request instead of actually getting initial credentials with the default client keytab.
 
  +
Initial credentials are acquired in stage 1 or 2, after the client principal and ccache are known, if:
  +
* ccache contains a config variable indicating that it was derived from the client keytab, and it is time for a refresh. (If this fails, we will continue on and try to use ccache if it contains current creds.)
  +
* ccache doesn't contain a current TGT and we have a password
  +
* ccache doesn't contain a current TGT and we have a client keytab containing a key for the client principal
   
(To be finished)
 
  +
(Note: as of krb5 1.10, getting initial credentials with a password is deferred until get_credentials, even if IAKERB is not in use. Heimdal does not defer this, and we will no longer defer this after the restructuring.)

Revision as of 15:24, 15 June 2012

This is an early stage project for MIT Kerberos. It is being fleshed out by its proponents. Feel free to help flesh out the details of this project. After the project is ready, it will be presented for review and approval.


This project is to add support for automatically getting credentials for gss-krb5 security context initiation using a keytab.

Overview

To initiate a gss-krb5 security context, one needs credentials (typically a TGT). During a user login session, these credentials are typically obtained ahead of time by the login system or using kinit (or on Windows or OSX, by bringing up a UI prompt from inside the GSSAPI functions). When a service wishes to communicate with another service, it uses its keytab to acquire credentials. Currently, it is necessary to use kinit -k or k5start out of band in order to ensure that credentials are available for the server's use. This project is to automate this process within the GSSAPI calls.

Requirements

  1. The system should work, perhaps with some external configuration, for a typical caller which invokes gss_init_sec_context() with no initiator cred (or, equivalently, acquires an initiator cred with no desired name).
  2. The system should also behave as well as possible when the caller does supply a desired name, or when krb5_cc_select() can deduce a client principal from the target name. In this case, multiple principals from the same keytab might be used for different initiations.
  3. The system should work well with credential cache collections (see Projects/Client_principal_selection). For example, an application should be able to, from the same process, initiate two security contexts with different desired names, using the same keytab, and have the resulting credentials both be cached within the collection (assuming the default ccache is collection-enabled).
  4. There should be minimal or no surprise. An existing deployment of GSSAPI applications should not begin doing keytab-based initiation and write to the default per-uid ccache without reason to believe this is intended.
  5. Credentials obtained this way should be cached. Otherwise, applications which initialize many security contexts (such as HTTP clients) could generate large numbers of unnecessary AS and TGS requests.

It is not required for this system to work with initiators like krlogin which directly use libkrb5. However, some of the underlying components may be useful for FAST armor ccaches, so putting reusable parts of the code in libkrb5 is desirable.

Design

Default client keytab

libkrb5 provides an API for discovering the default keytab (krb5_kt_default()). The underlying mechanism for discovering this keytab may be an environment variable (KRB5_KTNAME), a profile relation (default_keytab_name under libdefaults), or a hardcoded default (/etc/krb5.keytab). This keytab is currently used, absent application input the contrary, for accepting security contexts with gss_accept_sec_context or krb5_rd_req.

Automated keytab initiation will not make use of this keytab. Instead, there will be a new complementary "default client keytab", obtained with krb5_kt_client_default(), with its own set of underlying discovery mechanisms. Unless an administrator sets up a client keytab, automated keytab initiation will not take place, thus minimizing surprise.

(TBD: what discovery mechanisms do we need? Candidates include a revised version of gss_krb5_import_cred with a client keytab argument, a GSS extension parallel to krb5_gss_register_acceptor_identity, a URN for Projects/Credential_Store_extensions, an environment variable parallel to KRB5_KTNAME, a profile relation parallel to default_keytab_name, and a hardcoded default.)

Caching and refreshing

Initial credentials obtained through automated keytab initiation will be cached in the default ccache or, if the default ccache type supports it, the associated collection. The new ccache will remember, using ccache config entries, the time of the last attempt to refresh credentials from the client keytab (or a distinguished value if there has been no attempt yet). The gss-krb5 initiator code will attempt to refresh the cache with the keytab again if (1) the credentials are at least halfway to being expired, and (2) the last recorded attempt to refresh the cache was more than a minimum delta of time in the past.

Code changes

Introducing a client keytab requires a careful re-evaluation of the lifetime of an initiator credential, which has three stages:

  1. acquire_init_cred, called from gss_acquire_cred, records the information given by the caller (which may include client principal, ccache, client keytab, and/or password), and detects errors based on the information known so far. If the necessary information is available and IAKERB is not in use, acquire_init_cred acquires a TGT using the password, client keytab, or (only on Windows at the moment) interactive input.
  2. kg_cred_resolve, called from gss_init_sec_context or gss_inquire_cred, forces resolution of the client principal, using the target principal if called from gss_inquire_cred. kg_cred_resolve detects errors and/or acquires an initial TGT as acquire_init_creds would have given the new information.
  3. get_credentials, called from gss_init_sec_context, gets a service ticket (possibly making a TGS request if IAKERB is not in use).

The client principal is determined by, in order of preference:

  • (Stage 1) The caller's desired_name parameter if given.
  • (Stage 1) The principal of the caller-specified ccache, if one is given and exists.
  • (Stage 2) The principal of an existing ccache determined by krb5_cc_select using the target principal.
  • (Stage 2) The principal determined by krb5_cc_select (for which we do not have an existing ccache).
  • (Stage 2) The principal of the default ccache, if it exists.
  • (Stage 2) The first principal listed in the client keytab, if we have one. (If we choose this, we need to re-check the collection for an existing ccache for this principal.)
  • Give up and return an error

If the ccache is not determined from caller parameters, it can be determined once the client principal is known:

  • If there is an existing ccache in the collection for the client principal, use that
  • If the default cache is not collection-enabled, use it (which may result in an error if it doesn't match the client principal)
  • If the caller supplied a password and there is no default cache yet, use the default cache as the destination
  • Use a new unique ccache of the default type as the destination

The errors we could detect at stages 1 and 2 are:

  • Client principal and ccache are known, and ccache contains creds for a different principal
  • Client principal and ccache are known, ccache contains no current creds for client principal, and we have no way (password or client keytab) to acquire creds for client principal
  • Client principal is known, there is a default ccache which is not collection-enabled, and it contains creds for a different principal
  • Client principal is known, there are no creds available for it in the collection, and we have no way to acquire creds for it
  • ccache is known but is empty, and we have no way to acquire creds
  • There are no creds at all in the collection and we have no way to acquire creds for any principal

Initial credentials are acquired in stage 1 or 2, after the client principal and ccache are known, if:

  • ccache contains a config variable indicating that it was derived from the client keytab, and it is time for a refresh. (If this fails, we will continue on and try to use ccache if it contains current creds.)
  • ccache doesn't contain a current TGT and we have a password
  • ccache doesn't contain a current TGT and we have a client keytab containing a key for the client principal

(Note: as of krb5 1.10, getting initial credentials with a password is deferred until get_credentials, even if IAKERB is not in use. Heimdal does not defer this, and we will no longer defer this after the restructuring.)