logo_kerberos.gif

Difference between revisions of "Projects/Audit"

From K5Wiki
Jump to: navigation, search
m
m
 
(24 intermediate revisions by 2 users not shown)
Line 1: Line 1:
{{project-early}}
+
{{project-rel|1.12}}
   
== Purpose ==
+
== Description ==
   
Create an Audit infrastructure within MIT Kerberos to monitor security related events on the KDC.
+
This project creates a pluggable audit interface to allow the monitoring of security-related events on the KDC.
In future expand Kerberos Audit facility to the application servers, kadmin if it remains desirable.
 
   
  +
The interface is considered "experimental", in that API stability is not guaranteed to future major releases.
 
 
 
== Requirements ==
 
== Requirements ==
Line 12: Line 13:
 
* build-time enabled;
 
* build-time enabled;
 
* run-time pluggable;
 
* run-time pluggable;
* simple, so it could be easily replaced with the OS specific implementations;
+
* simple and flexible, so it could be easily replaced with the OS specific and third-parties implementations;
   
   
 
== Events ==
 
== Events ==
   
This section details the categories of the auditable events and the associated information.
 
  +
We consider events under the categorization of the Common Criteria Class FIA.
   
;Audit module loaded/unloaded: Startup and shutdown of the audit system must be recorded by audit system;
 
  +
This section details the categories of the auditable events and the associated data.
; KDC started/stopped
 
:KDC start-up - list of KDC realms and corresponding ports on which the Kerberos server should listen for UDP and TCP requests; location and names of the plugins;
 
:KDC stopped - no additional information;
 
; Authentication (Common Criteria Class FIA)
 
:AS exchange:
 
:: ticket ID (if available);
 
:: KDC status message;
 
:: kdc request: client and server principals, kdc options, start/end/renew_till times, available enctypes, 2nd ticket (see below ticket details), auth data type, pre-auth data type, addresses, message type,
 
:: kdc reply: client principal, ticket (see below ticket details), message type;
 
:: remote port;
 
:: pre-auth error;
 
:: chosen by KDC enctype (Common Criteria FCS_CKM.1, FCS_CKM.4);
 
:: session key cleared (Common Criteria FCS_CKM.1, FCS_CKM.4);
 
:TGS exchange:
 
:: ticket ID (if available);
 
:: KDC status message;
 
:: kdc request: client and server principals, kdc options, start/end/renew_till times, available enctypes, 2nd ticket (see below ticket details), auth data type, pre-auth data type, addresses, message type,
 
:: kdc reply: client principal, ticket (see below ticket details), message type;
 
:: principals: (if applicable) alternate client and server principals, 2nd ticket server name;
 
:: full address;
 
:: is_referral;
 
:: xrealm name;
 
:: chosen by KDC enctype, u2u enctype (Common Criteria FCS_CKM.1, FCS_CKM.4);
 
:: session key cleared (Common Criteria FCS_CKM.1, FCS_CKM.4);
 
:Policy: Policies violation when processing requests - TBD;
 
::AS request; TGS request; S4U2PROXY request. Can be separate reports or part of AS/TGS request processing
 
   
:Ticket details:
 
  +
1. Startup and shutdown of the KDC must be recorded by audit system;
::client and server principals, flags, ticket start/end/renew_till times, authtime, transited encoding type and contents, session key type, addresses;
 
   
  +
2. The bulk of the audit information will be produced while processing AS and TGS requests. Though KDC request processing can be grouped into several logical phases, we generate (usually) only two events, one at the initial receipt of a request, and a second, final, one before sending a reply. All events relating to the same request can be linked together in the audit log by a 32-character alphanumeric string (about 190 bits of uniqueness) which is randomly generated at the start of processing. If the request is a S4U2Self or S4U2Proxy request, an additional audit event will be generated with information particular to the S4U request. The following table lists the logical stages of KDC processing, and which components are logged in the AS and TGS cases:
   
== Design details ==
 
  +
{| class="wikitable" style="border: 3px solid #59121e"
  +
|+
  +
|-
  +
! Phase
  +
! style="padding-left: 2em; padding-right: 2em;" | Data to be logged
  +
! AS_REQ
  +
! TGS_REQ
  +
|-
  +
|rowspan=3|Authenticate request content and client
  +
| client’s address and port || ✔ || ✔
  +
|-
  +
| original KDC request and [[#Request ID| request ID ]] || ✔ || ✔
  +
|-
  +
| primary [[#Ticket ID|ticket ID]] || ✗ ||(S4U:front-end server's) TGT
  +
|-
  +
|rowspan=3|Determine service principal
  +
| modified KDC request and [[#Request ID|request ID]] ||✔ || ✔
  +
|-
  +
| cross-realm referral || ✗ || service principal, TGS
  +
|-
  +
| user-to-user: client in the 2nd ticket || ✗ ||✔
  +
|-
  +
|rowspan=2|Validate policies
  +
| local policy violation ||✔ || ✔
  +
|-
  +
| protocol constraints ||✗ || S4U2Proxy, S4U2Self
  +
|-
  +
|rowspan=5|Issue ticket
  +
| ticket renewed ||✗ || ✔
  +
|-
  +
| ticket validated ||✗ || ✔
  +
|-
  +
| session key enctype (short-term) ||✔ || ✔
  +
|-
  +
| enctype of the service's long-term key||✗ || ✔
  +
|-
  +
| derived [[#Ticket ID|ticket ID]]|| TGT || service or referral TGT
  +
|-
  +
|rowspan=2|Encrypt reply
  +
| KDC reply ||✔ || ✔
  +
|-
  +
| Reply-encrypting key enctype (long-term) ||✔ || ✔
  +
|-
  +
|rowspan=1|All phases
  +
| Additional info(KDC status,policy details,etc)|| ✔ ||✔
  +
|-
  +
|}
   
=== Ticket ID ===
 
  +
The following information will be made available to audit plugins:
   
Ticket ID is recorded as part of audit messages. This allows to link tickets to their initial TGT at any stage of the Kerberos exchange.
 
  +
: a unique [[#Request ID| request ID ]]
  +
: the complete KDC request structure
  +
: the KDC reply structure (possibly only partially populated)
  +
: the client's IP address and port number
  +
: the stage of KDC processing at which the audit event was triggered
  +
: the KDC status string (as appears in kdc.log)
  +
: [[#Ticket ID|ticket IDs]] (checksums) for any supplied tickets or ticket to be returned
  +
: the remote client's realm (for referrals)
  +
: the impersonated user for an S4U2Self request
  +
: the "type of violation" which caused the request to fail, if applicable
   
TODO: Consider a new authorization data element AD_TKT_ID per http://tools.ietf.org/html/draft-ietf-krb-wg-cammac-04 draft to securely communicate ticket id between all Kerberos exchange participants.
 
  +
Other events to consider for the future development:
   
  +
3. Further details about policy viloations
  +
:Event description, reason and how to fix it;
  +
4. Secrets (Common Criteria FCS_CKM.1, FCS_CKM.4);
  +
:long- and short-term key creation, manipulation, cleaning.
  +
  +
== Design details ==
   
=== Design 1 (one-API-per-event) ===
 
  +
====Ticket ID====
  +
Ticket ID is recorded as part of audit messages. This allows to link tickets to their initial TGT at any stage of the Kerberos exchange.
   
This design exercises the idea of one-API-per-KDC-event. The benefit of this approach is it's very low cost to KDC. However, any modification in the list of the auditable events will cause the API to be changed.
 
  +
For the purpose of this project we will create a private to KDC ticket ID: each successfully created ticket will be hashed and recorded into audit log. The administrators will correlate the primary and derived ticket IDs after the fact.
   
  +
For the future, however, we need a more complex system that would allow to tie the tickets from a successful AS_REQ all the way to the application server. It is marked as an action item in [[#Future work|this]] section.
   
NOTE: 'event_id' is an assigned ID of the auditable event and 'status' indicates whether the event succeeded (status = 1) or failed (status = 0).
 
  +
====Request ID====
 
  +
Request ID is a randomly generated alpha-numeric string. Using this ID an administrator can easily correlate multiple audit events related to a single request. It should be informative both in cases when the request is sent to multiple KDCs, or to the same KDC multiple times.
==== KDC facing API ====
 
  +
  +
=== KDC facing API ===
   
 
/* Audit plugin loaded/unloaded */
 
/* Audit plugin loaded/unloaded */
Line 74: Line 113:
 
krb5_error_code
 
krb5_error_code
 
unload_audit_plugin(krb5_context context);
 
unload_audit_plugin(krb5_context context);
/* KDC started /stopped */
 
  +
krb5_boolean
krb5_error_code
 
  +
kau_isloaded(krb5_context context);
kau_kdc_start(krb5_context context, int status);
 
  +
/* event specific functions */
krb5_error_code
+
krb5_error_code
kau_kdc_stop(krb5_context context, krb5_error_code status);
+
kau_kdc_start(krb5_context context, const int event_id, const int status);
krb5_error_code
+
krb5_error_code
kau_as_req(krb5_context context, struct as_req_state *state, int status);
+
kau_kdc_stop(krb5_context context, const int event_id, const int status);
krb5_error_code
+
krb5_error_code
kau_tgs(krb5_context context, struct tgs_req_audit_state *state, int status);
+
kau_asreq(krb5_context context, const int event_id, const int status, audit_state *state);
  +
krb5_error_code
  +
kau_tgsreq(krb5_context context, const int event_id, const int status, audit_state *state);
  +
krb5_error_code
  +
kau_s4u2self(krb5_context context, const int event_id, const int status, audit_state *state);
  +
krb5_error_code
  +
kau_s4u2proxy(krb5_context context, const int event_id, const int status, audit_state *state);
  +
krb5_error_code
  +
kau_u2u(krb5_context context, const int event_id, const int status, audit_state *state);
  +
/* utilities */
  +
krb5_error_code
  +
kau_init_kdc_req(krb5_context context, krb5_kdc_req *request, const krb5_fulladdr *from, audit_state **au_state);
  +
krb5_error_code
  +
kau_make_tkt_id(krb5_context context, const krb5_ticket *ticket, char **out);
  +
krb5_error_code
  +
kau_make_req_id(krb5_context context, const krb5_kdc_req *request, char **out);
  +
  +
where ''event_id'' references to the ''Phase'' (left column of [[#Events| events]] table), and ''audit_state'' structure holds the following information:
   
struct as_req_state {
+
typedef struct _audit_state {
loop_respond_fn respond;
+
krb5_kdc_req *req_in; /* request in the original form */
void *arg;
+
krb5_kdc_req *req_mod; /* modified (per protocol) request */
...
+
krb5_kdc_rep *reply;
char *tkt_id;
 
};
 
struct tgs_req_audit_state {
 
krb5_kdc_req *request;
 
krb5_timestamp authtime;
 
char *sname, *cname, *s4u_name, *u2ucname;
 
krb5_principal altprinc;
 
char *xrealm;
 
 
const krb5_fulladdr *from;
 
const krb5_fulladdr *from;
unsigned int c_flags;
 
  +
const char *status; /* additional information string */
const char *status; /* KDC status message */
+
char *tkt_in_id; /* primary (TGT) ticket ID */
krb5_enctype useenctype;
+
char *tkt_out_id; /* derived (service or referral TGT) ticket ID */
  +
char *evid_tkt_id; /* for s4u2proxy - user's evidence ticket ID, for u2u - TGT ticket ID */
  +
char *req_in_id; /* original-request ID */
  +
char *req_mod_id; /* modified-request ID */
  +
krb5_int32 sess_etype; /* session key enctype */
  +
krb5_int32 srv_etype; /* enctype of the long-term key of service */
  +
krb5_int32 rep_etype; /* reply-encrypting key enctype */
 
krb5_boolean tkt_renewed;
 
krb5_boolean tkt_renewed;
krb5_boolean is_referral;
+
krb5_boolean tkt_validated;
char *tkt_id;
+
/* referrals */
};
+
krb5_data *cl_realm; /* remote client's realm */
  +
/* s4u and u2u */
  +
krb5_principal s4u2self_user; /* impersonated user */
  +
krb5_principal s4u2proxy_user; /* delegated user */
  +
krb5_principal u2u_user; /* client for the second ticket */
  +
char *violation; /* local or protocol policy problem */
  +
} audit_state;
   
==== Pluggable interface ====
+
=== Pluggable interface ===
   
 
/* Audit plugin vtable */
 
/* Audit plugin vtable */
 
typedef struct krb5_audit_vtable_st {
 
typedef struct krb5_audit_vtable_st {
 
/* Mandatory: name of module. */
 
/* Mandatory: name of module. */
char *name;
+
char *name;
kau_open_fn open;
+
int conf_options;
kau_close_fn close;
+
kau_open_fn open;
kau_kdc_start_fn kdc_start;
+
kau_close_fn close;
kau_kdc_stop_fn kdc_stop;
+
kau_kdc_start_fn kdc_start;
kau_as_req_fn as_req;
+
kau_kdc_stop_fn kdc_stop;
kau_tgs_fn tgs;
+
kau_as_req_fn as_req;
  +
kau_tgs_req_fn tgs_req;
  +
kau_s4u2self_fn tgs_s4u2self;
  +
kau_s4u2proxy_fn tgs_s4u2proxy;
  +
kau_u2u_fn tgs_u2u;;
 
} *krb5_audit_vtable;
 
} *krb5_audit_vtable;
 
  +
 
typedef krb5_error_code
 
typedef krb5_error_code
 
(*kau_open_fn)(kau_ctx *au_ctx);
 
(*kau_open_fn)(kau_ctx *au_ctx);
Line 116: Line 155:
 
(*kau_close_fn)(kau_ctx au_ctx);
 
(*kau_close_fn)(kau_ctx au_ctx);
 
typedef krb5_error_code
 
typedef krb5_error_code
(*kau_kdc_start_fn)(kau_ctx au_ctx, krb5_deltat clockskew, const char *realm_port,
+
(*kau_kdc_start_fn)(kau_ctx au_ctx, const int event_id, int status);
krb5_boolean allow_weak_crypto, const char *plugins, const char *plugin_dir, int status);
 
 
typedef krb5_error_code
 
typedef krb5_error_code
(*kau_kdc_stop_fn)(kau_ctx au_ctx, krb5_error_code status);
+
(*kau_kdc_stop_fn)(kau_ctx au_ctx, const int event_id, int status);
 
typedef krb5_error_code
 
typedef krb5_error_code
(*kau_as_req_fn)(kau_ctx au_ctx, const char *tkt_id, const char *cname, const char *sname, const int from_port,
+
(*kau_as_req_fn)(kau_ctx au_ctx, const int event_id, int status, audit_state *state);
krb5_enctype sesskey_etype, krb5_flags tkt_flags, const char *tkt_cname,
 
krb5_deltat tkt_start_time, krb5_deltat tkt_end_time, krb5_deltat tkt_renew_till,
 
const char *kdc_status, int status);
 
 
typedef krb5_error_code
 
typedef krb5_error_code
(*kau_tgs_fn)(kau_ctx au_ctx, const char *tkt_id, krb5_timestamp authtime, const char *cname, const char *sname,
+
(*kau_tgs_req_fn)(kau_ctx au_ctx, const int event_id, int status, audit_state *state);
const int from_port, krb5_enctype session_key_etype, const int is_referral, const int tkt_renewed,
 
krb5_flags tkt_flags, krb5_deltat tkt_start_time, krb5_deltat tkt_end_time, krb5_deltat tkt_renew_till,
 
const char *kdc_status, int status);
 
 
 
 
=== Design 2 (JSON-based) ===
 
 
Design-2 is based on JSON serialization of the KDC auditable events. (See CEE Log Syntax (CLS) Encoding http://cee.mitre.org/language/1.0-beta1/cls.html#cls-encodings )
 
 
This approach is simple and extremely flexible as auditable events and attributes can be added and modified without changing API. The drawback here is that some performance overhead due to the encoding operations will occur (of course, only if audit plugin is loaded/enabled).
 
 
Note: The encoding operations can be performed using the MIT Kerberos libkrb5support.so library. For the decoding and further processing of the audit output one can use the variety of tools (Sky is the limit!) including native MIT Kerberos json decoders. See subsection "Output" for the details.
 
 
==== KDC facing API ====
 
 
/* Load/unload Audit plugin */
 
krb5_error_code
 
load_audit_plugin(krb5_context context);
 
krb5_error_code
 
unload_audit_plugin(krb5_context context);
 
 
/* Record KDC event. */
 
krb5_error_code
 
kau_kdc_event(krb5_context context, const int event_id, const int status, const char *audit_str);
 
 
/* Helpers */
 
 
/* Check if Audit plugin is loaded */
 
krb5_boolean
 
kau_isloaded(krb5_context context);
 
 
/* Create a ticket ID */
 
krb5_error_code
 
kau_make_tkt_id(const krb5_keyblock sk, char **out);
 
 
/* Basic serialization functions. */
 
krb5_error_code
 
kau_jenc_shandle(krb5_context context, int event_id, int status,
 
struct server_handle shdl, char **out);
 
krb5_error_code
 
kau_jenc_asreq(krb5_context context, int event_id, int status,
 
struct as_req_state *state, char **out);
 
krb5_error_code
 
kau_jenc_tgsreq(krb5_context context, int event_id, int status,
 
struct tgs_req_state *state, char **out);
 
 
==== Pluggable interface ====
 
 
/* Audit plugin vtable */
 
typedef struct krb5_audit_vtable_st {
 
/* Mandatory: name of module. */
 
char *name;
 
kau_open_fn open;
 
kau_close_fn close;
 
kau_record_fn record;
 
} *krb5_audit_vtable;
 
 
 
typedef krb5_error_code
 
typedef krb5_error_code
(*kau_open_fn)(kau_ctx *au_ctx);
 
  +
(*kau_s4u2self_fn)(kau_ctx au_ctx, const int event_id, int status, audit_state *state);
 
 
typedef krb5_error_code
 
typedef krb5_error_code
(*kau_close_fn)(kau_ctx au_ctx);
 
  +
(*kau_s4u2proxy_fn)(kau_ctx au_ctx, const int event_id, int status, audit_state *state);
 
 
typedef krb5_error_code
 
typedef krb5_error_code
(*kau_record_fn)(kau_ctx au_ctx, const int event_id, const int status, const char *audit_string);
+
(*kau_u2u_fn)(kau_ctx au_ctx, const int event_id, int status, audit_state *state);
 
==== Example ====
 
   
The typical call on KDC side (TGS-REQ):
 
   
#include "k5-json.h"
 
  +
== JSON based audit module ==
 
krb5_error_code rc = 0;
 
char *aud_str = NULL;
 
struct tgs_req_audit_state *state;
 
...
 
if (kau_isloaded(kdc_context) == TRUE) {
 
/* JSON encode tgs_req_audit_state */
 
rc = kau_jenc_asreq(kdc_context, TGS_REQ, 0, state, &aud_str);
 
if (!rc && aud_str != NULL) {
 
rc = kau_kdc_event(kdc_context, TS_REQ, 0, aud_str)
 
free(aud_str);
 
}
 
}
 
   
==== Output ====
 
  +
We will use libaudit module available on Fedora, Debian, SuSe for the first round. The new JSON utility library will be built to parse Kerberos specific structures. The "simple" audit module will be statically linked to this library.
   
The plugin implementor can use wide variety of tools to process JSON event record.
 
  +
The following is a proposed ''Dictionary '' - the basic field names for JSON parsing:
   
The following is an example of the KDC audit record:
 
  +
{| class="wikitable" style="border: 3px solid #59121e"
  +
|+
  +
|-
  +
! Key
  +
! style="padding-left: 2em; padding-right: 2em;" | Type
  +
! Comments
  +
|-
  +
| event_success || style="padding-left: 2em "| INT || event was success or failure
  +
|-
  +
| event_name || style="padding-left: 2em "| STR || name of the event (KDC_START, AS_REQ etc)
  +
|-
  +
| stage || style="padding-left: 2em "| INT || stage in the KDC exchange processing
  +
|-
  +
| tkt_id_in || style="padding-left: 2em "| STR || primary (TGT) ticket ID
  +
|-
  +
| tkt_id_out || style="padding-left: 2em "| STR || derived (service or referral TGT) ticket ID
  +
|-
  +
| req_id || style="padding-left: 2em "| STR || request ID
  +
|-
  +
| kdc_status || style="padding-left: 2em "| STR|| Additional information string
  +
|-
  +
| fromaddr || style="padding-left: 2em "| STR || client's address
  +
|-
  +
| fromport || style="padding-left: 2em "| NUM || client's port
  +
|-
  +
|sess_etype || style="padding-left: 2em "| NUM || enctype of session key
  +
|-
  +
|rep_etype || style="padding-left: 2em "| NUM || enctype of reply-encrypting key
  +
|-
  +
|srv_etype || style="padding-left: 2em "| NUM || enctype of long-term key of the service key
  +
|-
  +
|tkt_renewed|| style="padding-left: 2em "| BOOL || was ticket renewed
  +
|-
  +
|tkt_validated|| style="padding-left: 2em "| BOOL || was ticket validated
  +
|-
  +
|req.addresses || style="padding-left: 2em "| STR || requested addresses
  +
|-
  +
|req.avail_etypes || style="padding-left: 2em "| STR || requested/available enc types
  +
|-
  +
|req.kdc_options || style="padding-left: 2em "| NUM || KDC options (forwardable, allow_postdate etc)
  +
|-
  +
|req.tkt_start || style="padding-left: 2em "| NUM || requested ticket start time
  +
|-
  +
|req.tkt_end || style="padding-left: 2em "| NUM || requested ticket end time
  +
|-
  +
|req.tkt_renew_till || style="padding-left: 2em "| NUM || requested ticket renew-till time
  +
|-
  +
|req.tkt_authtime || style="padding-left: 2em "| NUM || requested ticket authtime
  +
|-
  +
| req.sectkt_cname|| style="padding-left: 2em "| STR || client principal in the second ticket (U2U etc)
  +
|-
  +
| req.sectkt_sname|| style="padding-left: 2em "| STR || service principal in the second ticket
  +
|-
  +
| req.sectkt_flags|| style="padding-left: 2em "| NUM || second ticket flags
  +
|-
  +
| req.sectkt_start|| style="padding-left: 2em "| NUM || second ticket start time
  +
|-
  +
| req.sectkt_end|| style="padding-left: 2em "| NUM || second ticket end time
  +
|-
  +
| req.sectkt_authtime|| style="padding-left: 2em "| NUM || second ticket authtime
  +
|-
  +
| req.sectkt_etype|| style="padding-left: 2em "| NUM || second ticket key type
  +
|-
  +
|req.sname || style="padding-left: 2em "| STR || requested service principal
  +
|-
  +
| req.cname || style="padding-left: 2em "| STR || client's principal
  +
|-
  +
|rep.sname || style="padding-left: 2em "| STR || service principal in ticket
  +
|-
  +
| rep.cname || style="padding-left: 2em "| STR || client principal in ticket
  +
|-
  +
| rep.pa_type || style="padding-left: 2em "| STR || reply preauth types
  +
|-
  +
| rep.rep_authtime || style="padding-left: 2em "| NUM || ticket authtime
  +
|-
  +
| rep.tkt_start || style="padding-left: 2em "| NUM || ticket start time
  +
|-
  +
| rep.tkt_end || style="padding-left: 2em "| NUM || ticket end time
  +
|-
  +
| rep.tkt_renew_till|| style="padding-left: 2em "| NUM || ticket renewed-till time
  +
|-
  +
|rep.tr_contents|| style="padding-left: 2em "| STR|| ticket transited-realms list
  +
|-
  +
|}
   
{
 
  +
== Configuration ==
"event_id":5,
 
"event_status":1,
 
"tkt_id":"C8A7D0C7A86E373E",
 
"kdc_status":"ISSUE",
 
"kdcreq":{
 
"server":{"components":["host","xxx.mit.edu"],"realm":"KRBTEST.COM","length":2,"type":1},
 
"kdc_options":65536,
 
"end":1362867131,
 
"avail_etypes":[18,17,16,23,25,26,1,3,2]
 
},
 
"kdcrep":{
 
"msg_type":13,
 
"client":{"components":["user"],"realm":"KRBTEST.COM","length":1,"type":1},
 
"ticket":{
 
"server":{"components":["host","xxx.mit.edu"],"realm":"KRBTEST.COM","length":2,"type":1},
 
"flags":589824,
 
"client":{"components":["user"],"realm":"KRBTEST.COM","length":1,"type":1},
 
"start":0,"end":1362867131,"renew_till":0,
 
"authtime":1362780731,
 
"tr_type":1,"skey_etype":18
 
}
 
},
 
"full_address":{"port":37652,"address":{"addrtype":2,"length":4,"addr":[18,18,44,333]}},
 
"rep_flags":176,
 
"skey_etype":18,
 
"sesskey_cleared":true
 
}
 
   
  +
The following ./configure option to be added:
   
==== Dictionary of the field names ====
 
  +
--with-audit-plugin
   
One needs to define a dictionary of the field names to be used to describe the events in some unified way.
 
  +
For example,'' --with-audit-plugin=simple'', where ''simple'' is the name of the audit plugin module
   
The possible basic field names are:
 
* "event_id" for audit event ID
 
* "event_status" to indicate if the event is reported on success or failure.
 
* "tkt_id" for ticket ID;
 
* "client" and "server" for client and service principal names;
 
* "full_address" for address and portport
 
* "pa_error" for pre-authentication error;
 
* "skey_etype" and "avail_etypes" for available key types and chosen enc type;
 
* "sesskey_cleared" to indicate that session key was cleared;
 
* "start", "end" and "renew_till" for the ticket's start/end/renew-until times;
 
* "rep_flags" for reply flags;
 
* "kdc_status" for KDC status message;
 
* "plugins" and "plugins_base_dir" for available plugins (reported on KDC startup);
 
* etc.
 
 
   
=== Design 3 (variadic) ===
 
  +
== Test ==
   
Use C variadic function to pass key-value pairs, if desired. Alternatively, if general purpose interface is not implemented, pass the event-specific C structure to a plugable interface.
 
  +
A testable audit module, k5audit_test, will be built, and enabled for a python test program which is added. This test module uses the internal libauditjenc library to generate a JSON encoding of the audit event, and writes that encoded string to a flat file, which is parsed by the python test program.
   
When compared to Design-2, this approach reduces the amount of code needed to process audit-related information on the KDC side. The only additional code that would be necessary to write would be in creating sanitized surrogates of the event-specific structures to guarantee that security sensitive information does not leave KDC.
 
   
When compared to Design-1, this approach provides flexibility of adding new audit *attributes* without changing the audit API. Note, that in both cases (Design-1 and Design-3) the audit API would need to be changed if new audit *events* were introduced.
 
  +
==Future work==
   
The drawback of Design-3 is a type-safety concern due to the nature of C variadic functions. Also, the plugin implementors would need to do some heavy-lifting in C, as the expected input to their functions would be either the set of variadic parameters or event-specific C structures.
 
  +
# Standardize a ''Ticket ID'';
  +
# Make reporting auditable events configurable. For example, one can choose to report TGS_REQ, but not AS_REQ;
  +
# Sanitize ''KDC request'' and ''KDC reply'' before passing them to the concrete audit implementation: security sensitive information should not leave KDC boundaries;
  +
# Develop audit system for Preauth and Authdata mechanisms;
  +
# Expand Kerberos Audit facility to the application servers and kadmin.
   
==== KDC facing API ====
 
   
/* Audit plugin loaded/unloaded */
 
  +
== References ==
krb5_error_code
 
load_audit_plugin(krb5_context context);
 
krb5_error_code
 
unload_audit_plugin(krb5_context context);
 
/* event specific functions */
 
krb5_error_code
 
kau_kdc_start(krb5_context context, int status);
 
krb5_error_code
 
kau_kdc_stop(krb5_context context, krb5_error_code status);
 
krb5_error_code
 
kau_as_req(krb5_context context, struct as_req_state *state, int status);
 
krb5_error_code
 
kau_tgs(krb5_context context, struct tgs_req_audit_state *state, int status);
 
 
==== Pluggable interface ====
 
   
/* Audit plugin vtable */
 
  +
# Common Criteria for Information Technology Security Evaluation http://www.commoncriteriaportal.org/files/ccfiles/CCPART2V3.1R4.pdf
typedef struct krb5_audit_vtable_st {
 
  +
# Oracle Solaris Auditing http://docs.oracle.com/cd/E19963-01/html/821-1456/auditov-1.html
/* Mandatory: name of module. */
 
  +
# Understanding Linux Audit http://doc.opensuse.org/products/draft/SLES/SLES-security_sd_draft/cha.audit.comp.html
char *name;
 
  +
# Advanced Security Audit Policy Settings http://technet.microsoft.com/en-us/library/dd772712(v=ws.10).aspx
kau_open_fn open;
 
  +
# Events Classification in Log Audit http://airccse.org/journal/nsa/0410ijnsa5.pdf
kau_close_fn close;
 
  +
# CEE Log Syntax (CLS) Encoding http://cee.mitre.org/language/1.0-beta1/cls.html
kau_record_fn record;
 
kau_kdc_start_fn kdc_start;
 
kau_kdc_stop_fn kdc_stop;
 
kau_as_req_fn as_req;
 
kau_tgs_fn tgs;
 
} *krb5_audit_vtable;
 
 
typedef krb5_error_code
 
(*kau_open_fn)(kau_ctx *au_ctx);
 
 
typedef krb5_error_code
 
(*kau_close_fn)(kau_ctx au_ctx);
 
 
/* general purpose interface to pass unspecified number of
 
* key-type-value triplets to a plugable interface.
 
*/
 
typedef krb5_error_code
 
(*kau_record_fn)(kau_ctx au_ctx, const int event_id, const int status, ... );
 
 
/* one-API-per-event surrogate */
 
typedef krb5_error_code
 
(*kau_kdc_start_fn)(kau_ctx au_ctx, const int event_id, const int status,
 
struct server_handle_san shdl);
 
typedef krb5_error_code
 
(*kau_kdc_stop_fn)(kau_ctx au_ctx, const int event_id, const int status);
 
typedef krb5_error_code
 
(*kau_as_req_fn)(kau_ctx au_ctx, const int event_id, const int status,
 
struct as_req_state_san *state);
 
typedef krb5_error_code
 
(*kau_tgs_fn)(kau_ctx au_ctx, const int event_id, const int status,
 
struct tgs_req_state_san*state);
 
   
where new types server_handle_san, as_req_state_san and tgs_req_state_san are sanitized variants of server_handle, as_req_state and tgs_req_state structures respectively.
 
   
==== Example ====
+
== Commits ==
   
krb5_error_code
 
  +
e63b2c9b0ed3b19f6aa1ac90222240690a1bc55b KDC Audit infrastructure and plugin implementation
kau_as_req(krb5_context context, struct as_req_state *state,
 
  +
1003f0173f266a6428ccf2c89976f0029d3ee831 KDC Audit infrastructure and plugin implementation (merged)
krb5_error_code status)
 
  +
5036f91e7b61a73a1ec2d39ce1cc6bbf60dd82ab Fix audit test module initialization
{
 
krb5_error_code rc = 0;
 
...
 
/* If audit plugin generic record function is implemented, call it. */
 
if (hdl->vt.record) {
 
rc = rec_as_req(hdl->au_ctx, event_id, event_status, state);
 
return rc;
 
}
 
/* Otherwise, call into event-specific function */
 
if (hdl->vt.as_req)
 
rc = hdl->vt.as_req(hdl->au_ctx, event_id, event_status, state);
 
return rc;
 
}
 
 
static krb5_error_code
 
rec_as_req(krb5_context context, struct as_req_state_san *state,
 
krb5_error_code status)
 
{
 
krb5_error_code rc = 0;
 
...
 
hdl->vt.record(hdl->au_ctx, event_id, event_status,
 
"tkt_id", TYPE_NUM, state->tkt_id,
 
"kdc_status", TYPE_STR, state->status,
 
"full_address", TYPE_STR, state->full_address,
 
"skey_etype", TYPE_NUM, state->session_key_enctype,
 
"pa_error", TYPE_NUM, preauth_err,
 
/* request */
 
"kdcreq.msg_type", TYPE_STR, state->req_msg_type,
 
"kdcreq.client", TYPE_STR, state->req_client,
 
"kdcreq.server", TYPE_STR, state->req_server,
 
"kdcreq.kdc_options", TYPE_STR, state->req_kdc_options,
 
"kdcreq.start", TYPE_NUM, state->req_from,
 
"kdcreq.end", TYPE_NUM, state->req_end,
 
"kdcreq.renew_till", TYPE_NUM, state->req_rtime,
 
/* reply */
 
"kdcrep.msg_type", TYPE_STR,state->rep_msg_type,
 
"kdcrep.client", TYPE_STR, state->rep_client,
 
"kdcrep.server", TYPE_STR, state->rep_server,
 
"kdcrep.tkt.server", TYPE_STR, state->rep_tkt_server,
 
"kdcrep.tkt.flags", TYPE_NUM, state->rep_tkt_flags,
 
"kdcrep.tkt.start", TYPE_NUM, state->rep_tarttime,
 
"kdcrep.tkt.end", TYPE_NUM, pstate->rep_endtime,
 
"kdcrep.tkt.renew_till", TYPE_NUM, state->rep_renew_till,
 
"kdcrep.tkt.authtime", TYPE_NUM, state->rep_authtime,
 
"kdcrep.tkt.tr_type", TYPE_NUM, state->rep_transited_type,
 
"kdcrep.tkt.caddrs", TYPE_STR, state->rep_caddrs,
 
"kdcrep.tkt.skey_etype", TYPE_NUM, state->rep_session_enctype);
 
return rc;
 
}
 
   
== Configuration ==
 
  +
Completed in {{bug|7712}} and {{bug|7713}}
   
The following ./configure option to be added:
 
   
;--with-audit-plugin=simple: (For demo and testing purposes) Build the audit plugin "simple" and enable audit plugin.
 
  +
== Release Notes ==
   
  +
Administrator experience:
   
== Test implementation ==
 
  +
* Add an experimental pluggable interface for auditing KDC processing. This interface may change in a backwards-incompatible way in a future release.
 
We will use libaudit module available on Fedora, Debian, Suse for the first round.
 
 
Some "simple" audit plugin will be implemented and Python test system will become aware of its existence. New ./configure --with-audit-plugin option will be introduced to build "simple" audit plugin for testing purpose. If audit is enabled and audit plugin is available, "make check" will store audit messages into audit log file.
 
 
== References ==
 
 
# Common Criteria for Information Technology Security Evaluation http://www.commoncriteriaportal.org/files/ccfiles/CCPART2V3.1R4.pdf
 
# Oracle Solaris Auditing http://docs.oracle.com/cd/E19963-01/html/821-1456/auditov-1.html
 
# Understanding Linux Audit http://doc.opensuse.org/products/draft/SLES/SLES-security_sd_draft/cha.audit.comp.html
 
# Advanced Security Audit Policy Settings http://technet.microsoft.com/en-us/library/dd772712(v=ws.10).aspx
 
# Events Classification in Log Audit http://airccse.org/journal/nsa/0410ijnsa5.pdf
 
# CEE Log Syntax (CLS) Encoding http://cee.mitre.org/language/1.0-beta1/cls.html
 

Latest revision as of 13:01, 29 October 2013

This project was completed in release 1.12.


Description

This project creates a pluggable audit interface to allow the monitoring of security-related events on the KDC.

The interface is considered "experimental", in that API stability is not guaranteed to future major releases.

Requirements

The new audit system should be:

  • build-time enabled;
  • run-time pluggable;
  • simple and flexible, so it could be easily replaced with the OS specific and third-parties implementations;


Events

We consider events under the categorization of the Common Criteria Class FIA.

This section details the categories of the auditable events and the associated data.

1. Startup and shutdown of the KDC must be recorded by audit system;

2. The bulk of the audit information will be produced while processing AS and TGS requests. Though KDC request processing can be grouped into several logical phases, we generate (usually) only two events, one at the initial receipt of a request, and a second, final, one before sending a reply. All events relating to the same request can be linked together in the audit log by a 32-character alphanumeric string (about 190 bits of uniqueness) which is randomly generated at the start of processing. If the request is a S4U2Self or S4U2Proxy request, an additional audit event will be generated with information particular to the S4U request. The following table lists the logical stages of KDC processing, and which components are logged in the AS and TGS cases:

Phase Data to be logged AS_REQ TGS_REQ
Authenticate request content and client client’s address and port
original KDC request and request ID
primary ticket ID (S4U:front-end server's) TGT
Determine service principal modified KDC request and request ID
cross-realm referral service principal, TGS
user-to-user: client in the 2nd ticket
Validate policies local policy violation
protocol constraints S4U2Proxy, S4U2Self
Issue ticket ticket renewed
ticket validated
session key enctype (short-term)
enctype of the service's long-term key
derived ticket ID TGT service or referral TGT
Encrypt reply KDC reply
Reply-encrypting key enctype (long-term)
All phases Additional info(KDC status,policy details,etc)

The following information will be made available to audit plugins:

a unique request ID
the complete KDC request structure
the KDC reply structure (possibly only partially populated)
the client's IP address and port number
the stage of KDC processing at which the audit event was triggered
the KDC status string (as appears in kdc.log)
ticket IDs (checksums) for any supplied tickets or ticket to be returned
the remote client's realm (for referrals)
the impersonated user for an S4U2Self request
the "type of violation" which caused the request to fail, if applicable

Other events to consider for the future development:

3. Further details about policy viloations

Event description, reason and how to fix it;

4. Secrets (Common Criteria FCS_CKM.1, FCS_CKM.4);

long- and short-term key creation, manipulation, cleaning.

Design details

Ticket ID

Ticket ID is recorded as part of audit messages. This allows to link tickets to their initial TGT at any stage of the Kerberos exchange.

For the purpose of this project we will create a private to KDC ticket ID: each successfully created ticket will be hashed and recorded into audit log. The administrators will correlate the primary and derived ticket IDs after the fact.

For the future, however, we need a more complex system that would allow to tie the tickets from a successful AS_REQ all the way to the application server. It is marked as an action item in this section.

Request ID

Request ID is a randomly generated alpha-numeric string. Using this ID an administrator can easily correlate multiple audit events related to a single request. It should be informative both in cases when the request is sent to multiple KDCs, or to the same KDC multiple times.

KDC facing API

/* Audit plugin loaded/unloaded */
krb5_error_code 
load_audit_plugin(krb5_context context);
krb5_error_code 
unload_audit_plugin(krb5_context context);
krb5_boolean
kau_isloaded(krb5_context context);
/* event specific functions */
krb5_error_code
kau_kdc_start(krb5_context context, const int event_id, const int status);
krb5_error_code
kau_kdc_stop(krb5_context context, const int event_id, const int status);
krb5_error_code
kau_asreq(krb5_context context, const int event_id, const int status, audit_state *state);
krb5_error_code
kau_tgsreq(krb5_context context, const int event_id, const int status, audit_state *state);
krb5_error_code
kau_s4u2self(krb5_context context, const int event_id, const int status,  audit_state *state);
krb5_error_code
kau_s4u2proxy(krb5_context context, const int event_id, const int status, audit_state *state);
krb5_error_code
kau_u2u(krb5_context context, const int event_id, const int status, audit_state *state);
/* utilities */
krb5_error_code
kau_init_kdc_req(krb5_context context, krb5_kdc_req *request,  const krb5_fulladdr *from, audit_state **au_state);
krb5_error_code
kau_make_tkt_id(krb5_context context, const krb5_ticket *ticket, char **out);
krb5_error_code
kau_make_req_id(krb5_context context, const krb5_kdc_req *request, char **out);

where event_id references to the Phase (left column of events table), and audit_state structure holds the following information:

typedef struct _audit_state {
   krb5_kdc_req *req_in;   /* request in the original form */
   krb5_kdc_req *req_mod;  /* modified (per protocol) request */
   krb5_kdc_rep  *reply;
   const krb5_fulladdr *from;
   const char    *status; /* additional information string */
   char *tkt_in_id;       /* primary (TGT) ticket ID */
   char *tkt_out_id;      /* derived (service or referral TGT) ticket ID */
   char *evid_tkt_id;     /* for s4u2proxy - user's evidence ticket ID, for u2u - TGT ticket ID */
   char *req_in_id;       /* original-request ID */
   char *req_mod_id;      /* modified-request ID */
   krb5_int32 sess_etype; /* session key enctype */
   krb5_int32 srv_etype;  /* enctype of the long-term key of service */
   krb5_int32 rep_etype;  /* reply-encrypting key enctype */
   krb5_boolean tkt_renewed;
   krb5_boolean tkt_validated;
   /* referrals */
   krb5_data *cl_realm;   /* remote client's realm */
   /* s4u and u2u */
   krb5_principal s4u2self_user;  /* impersonated user */
   krb5_principal s4u2proxy_user; /* delegated user */
   krb5_principal u2u_user;       /* client for the second ticket */
   char *violation;               /* local or protocol policy problem */
} audit_state;

Pluggable interface

/* Audit plugin vtable */
typedef struct krb5_audit_vtable_st {
   /* Mandatory: name of module. */
   char                 *name;
   int                   conf_options;
   kau_open_fn           open;
   kau_close_fn          close;
   kau_kdc_start_fn      kdc_start;
   kau_kdc_stop_fn       kdc_stop;
   kau_as_req_fn         as_req;
   kau_tgs_req_fn        tgs_req;
   kau_s4u2self_fn       tgs_s4u2self;
   kau_s4u2proxy_fn      tgs_s4u2proxy;
   kau_u2u_fn            tgs_u2u;;
} *krb5_audit_vtable;
 
typedef krb5_error_code
(*kau_open_fn)(kau_ctx *au_ctx);
typedef krb5_error_code
(*kau_close_fn)(kau_ctx au_ctx);
typedef krb5_error_code
(*kau_kdc_start_fn)(kau_ctx au_ctx, const int event_id, int status);
typedef krb5_error_code
(*kau_kdc_stop_fn)(kau_ctx au_ctx, const int event_id, int status);
typedef krb5_error_code
(*kau_as_req_fn)(kau_ctx au_ctx, const int event_id, int status, audit_state *state);
typedef krb5_error_code
(*kau_tgs_req_fn)(kau_ctx au_ctx, const int event_id, int status, audit_state *state);
typedef krb5_error_code
(*kau_s4u2self_fn)(kau_ctx au_ctx, const int event_id, int status,  audit_state *state);
typedef krb5_error_code
(*kau_s4u2proxy_fn)(kau_ctx au_ctx, const int event_id, int status,  audit_state *state);
typedef krb5_error_code
(*kau_u2u_fn)(kau_ctx au_ctx, const int event_id, int status, audit_state *state);


JSON based audit module

We will use libaudit module available on Fedora, Debian, SuSe for the first round. The new JSON utility library will be built to parse Kerberos specific structures. The "simple" audit module will be statically linked to this library.

The following is a proposed Dictionary - the basic field names for JSON parsing:

Key Type Comments
event_success INT event was success or failure
event_name STR name of the event (KDC_START, AS_REQ etc)
stage INT stage in the KDC exchange processing
tkt_id_in STR primary (TGT) ticket ID
tkt_id_out STR derived (service or referral TGT) ticket ID
req_id STR request ID
kdc_status STR Additional information string
fromaddr STR client's address
fromport NUM client's port
sess_etype NUM enctype of session key
rep_etype NUM enctype of reply-encrypting key
srv_etype NUM enctype of long-term key of the service key
tkt_renewed BOOL was ticket renewed
tkt_validated BOOL was ticket validated
req.addresses STR requested addresses
req.avail_etypes STR requested/available enc types
req.kdc_options NUM KDC options (forwardable, allow_postdate etc)
req.tkt_start NUM requested ticket start time
req.tkt_end NUM requested ticket end time
req.tkt_renew_till NUM requested ticket renew-till time
req.tkt_authtime NUM requested ticket authtime
req.sectkt_cname STR client principal in the second ticket (U2U etc)
req.sectkt_sname STR service principal in the second ticket
req.sectkt_flags NUM second ticket flags
req.sectkt_start NUM second ticket start time
req.sectkt_end NUM second ticket end time
req.sectkt_authtime NUM second ticket authtime
req.sectkt_etype NUM second ticket key type
req.sname STR requested service principal
req.cname STR client's principal
rep.sname STR service principal in ticket
rep.cname STR client principal in ticket
rep.pa_type STR reply preauth types
rep.rep_authtime NUM ticket authtime
rep.tkt_start NUM ticket start time
rep.tkt_end NUM ticket end time
rep.tkt_renew_till NUM ticket renewed-till time
rep.tr_contents STR ticket transited-realms list

Configuration

The following ./configure option to be added:

--with-audit-plugin

For example, --with-audit-plugin=simple, where simple is the name of the audit plugin module


Test

A testable audit module, k5audit_test, will be built, and enabled for a python test program which is added. This test module uses the internal libauditjenc library to generate a JSON encoding of the audit event, and writes that encoded string to a flat file, which is parsed by the python test program.


Future work

  1. Standardize a Ticket ID;
  2. Make reporting auditable events configurable. For example, one can choose to report TGS_REQ, but not AS_REQ;
  3. Sanitize KDC request and KDC reply before passing them to the concrete audit implementation: security sensitive information should not leave KDC boundaries;
  4. Develop audit system for Preauth and Authdata mechanisms;
  5. Expand Kerberos Audit facility to the application servers and kadmin.


References

  1. Common Criteria for Information Technology Security Evaluation http://www.commoncriteriaportal.org/files/ccfiles/CCPART2V3.1R4.pdf
  2. Oracle Solaris Auditing http://docs.oracle.com/cd/E19963-01/html/821-1456/auditov-1.html
  3. Understanding Linux Audit http://doc.opensuse.org/products/draft/SLES/SLES-security_sd_draft/cha.audit.comp.html
  4. Advanced Security Audit Policy Settings http://technet.microsoft.com/en-us/library/dd772712(v=ws.10).aspx
  5. Events Classification in Log Audit http://airccse.org/journal/nsa/0410ijnsa5.pdf
  6. CEE Log Syntax (CLS) Encoding http://cee.mitre.org/language/1.0-beta1/cls.html


Commits

   e63b2c9b0ed3b19f6aa1ac90222240690a1bc55b KDC Audit infrastructure and plugin implementation
   1003f0173f266a6428ccf2c89976f0029d3ee831 KDC Audit infrastructure and plugin implementation (merged)
   5036f91e7b61a73a1ec2d39ce1cc6bbf60dd82ab Fix audit test module initialization

Completed in [krbdev.mit.edu #7712] and [krbdev.mit.edu #7713]


Release Notes

Administrator experience:

  • Add an experimental pluggable interface for auditing KDC processing. This interface may change in a backwards-incompatible way in a future release.