logo_kerberos.gif

Difference between revisions of "Projects/Audit"

From K5Wiki
Jump to: navigation, search
m
(Upon further discussion, the preferrence was given to Design-3. So, removing JSON based and one-API-per-event designs from the project page.)
Line 54: Line 54:
 
== Design details ==
 
== Design details ==
   
=== Ticket ID ===
 
 
The proposal is a hybrid of variadic key-value-pair (KVP) and one-API-per-event approaches.
   
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.
 
 
The following are highlights of this new feature:
  +
;Flow: On the KDC side call audit event-specific functions, whose input consists of the event-id, event-status (success or failure) and event-specific structure. If event-specific callback is implemented by the audit plugin, pass the pointer to the event-specific structure to the plugin. Otherwise, fallback to the generic function with variadic KVP arguments;
 
;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.
  +
: Ticket ID is created as a hash of AS session key or client principal name plus timestamp or some other way;
 
: 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.
 
;Dictionary: Define the dictionary of the key names to be used in KVP to describe the events in the unified way. See below for details;
  +
;Sanitizing: Strip the event-specific structure from the security sensitive information before passing it to the plugin;
  +
;Variadic KVP: KVP is a triplet consisting of key-name, key-value and a hint about the type of the value. All key-values should be converted into the strings. The plugin implementor is hinted at the "original" type of the key-value.
   
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.
 
 
 
=== Design 1 (one-API-per-event) ===
 
 
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.
 
 
 
NOTE: 'event_id' is an assigned ID of the auditable event and 'status' indicates whether the event succeeded (status = 1) or failed (status = 0).
 
 
==== 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);
 
/* KDC started /stopped */
 
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);
 
 
struct as_req_state {
 
loop_respond_fn respond;
 
void *arg;
 
...
 
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;
 
unsigned int c_flags;
 
const char *status; /* KDC status message */
 
krb5_enctype useenctype;
 
krb5_boolean tkt_renewed;
 
krb5_boolean is_referral;
 
char *tkt_id;
 
};
 
 
==== 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_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);
 
typedef krb5_error_code
 
(*kau_kdc_start_fn)(kau_ctx au_ctx, krb5_deltat clockskew, const char *realm_port,
 
krb5_boolean allow_weak_crypto, const char *plugins, const char *plugin_dir, int status);
 
typedef krb5_error_code
 
(*kau_kdc_stop_fn)(kau_ctx au_ctx, krb5_error_code status);
 
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,
 
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
 
(*kau_tgs_fn)(kau_ctx au_ctx, const char *tkt_id, krb5_timestamp authtime, const char *cname, const char *sname,
 
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
 
(*kau_open_fn)(kau_ctx *au_ctx);
 
 
typedef krb5_error_code
 
(*kau_close_fn)(kau_ctx au_ctx);
 
 
typedef krb5_error_code
 
(*kau_record_fn)(kau_ctx au_ctx, const int event_id, const int status, const char *audit_string);
 
 
==== Example ====
 
 
The typical call on KDC side (TGS-REQ):
 
 
#include "k5-json.h"
 
 
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 ====
 
 
The plugin implementor can use wide variety of tools to process JSON event record.
 
 
The following is an example of the KDC audit record:
 
 
{
 
"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
 
}
 
 
 
==== Dictionary of the field names ====
 
 
One needs to define a dictionary of the field names to be used to describe the events in some unified way.
 
 
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) ===
 
 
Design-3 is a hybrid of variadic key-value-pair and one-API-per-event approaches.
 
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.
 
 
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.
 
 
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.
 
   
 
==== KDC facing API ====
 
==== KDC facing API ====
Line 298: Line 76:
 
/* event specific functions */
 
/* event specific functions */
 
krb5_error_code
 
krb5_error_code
kau_kdc_start(krb5_context context, int status);
+
kau_kdc_start(krb5_context context, struct server_handle shdl, int status);
 
krb5_error_code
 
krb5_error_code
 
kau_kdc_stop(krb5_context context, krb5_error_code status);
 
kau_kdc_stop(krb5_context context, krb5_error_code status);
Line 314: Line 92:
 
kau_open_fn open;
 
kau_open_fn open;
 
kau_close_fn close;
 
kau_close_fn close;
kau_record_fn record;
+
kau_generic_fn generic;
 
kau_kdc_start_fn kdc_start;
 
kau_kdc_start_fn kdc_start;
 
kau_kdc_stop_fn kdc_stop;
 
kau_kdc_stop_fn kdc_stop;
 
kau_as_req_fn as_req;
 
kau_as_req_fn as_req;
kau_tgs_fn tgs;
+
kau_tgs_req_fn tgs_req;
 
} *krb5_audit_vtable;
 
} *krb5_audit_vtable;
 
 
Line 331: Line 109:
 
*/
 
*/
 
typedef krb5_error_code
 
typedef krb5_error_code
(*kau_record_fn)(kau_ctx au_ctx, const int event_id, const int status, ... );
+
(*kau_generic_fn)(kau_ctx au_ctx, const int event_id, const int status, ... );
 
 
 
/* one-API-per-event surrogate */
 
/* one-API-per-event surrogate */
Line 344: Line 122:
 
typedef krb5_error_code
 
typedef krb5_error_code
 
(*kau_tgs_fn)(kau_ctx au_ctx, const int event_id, const int status,
 
(*kau_tgs_fn)(kau_ctx au_ctx, const int event_id, const int status,
struct tgs_req_state_san*state);
+
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.
 
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.
Line 356: Line 134:
 
krb5_error_code rc = 0;
 
krb5_error_code rc = 0;
 
...
 
...
/* If audit plugin generic record function is implemented, call it. */
+
/* If audit plugin event-specific callback is implemented, call it */
if (hdl->vt.record) {
+
if (hdl->vt.as_req) {
rc = rec_as_req(hdl->au_ctx, event_id, event_status, state);
+
rc = hdl->vt.as_req(hdl->au_ctx, event_id, event_status, state);
 
return rc;
 
return rc;
 
}
 
}
/* Otherwise, call into event-specific function */
+
/* Otherwise, try the generic one. */
if (hdl->vt.as_req)
+
if (hdl->vt.generic)
rc = hdl->vt.as_req(hdl->au_ctx, event_id, event_status, state);
+
rc = rec_as_req(hdl->au_ctx, event_id, event_status, state);
 
return rc;
 
return rc;
 
}
 
}
Line 373: Line 151:
 
krb5_error_code rc = 0;
 
krb5_error_code rc = 0;
 
...
 
...
  +
/* All values with TYPE_NUM type-hint are string representations of
  +
* their numeric conterparts in 'state' structure.
 
*/
 
hdl->vt.record(hdl->au_ctx, event_id, event_status,
 
hdl->vt.record(hdl->au_ctx, event_id, event_status,
"tkt_id", TYPE_NUM, state->tkt_id,
+
"tkt_id", TYPE_NUM, tkt_id, // state->tkt_id
 
"kdc_status", TYPE_STR, state->status,
 
"kdc_status", TYPE_STR, state->status,
 
"full_address", TYPE_STR, state->full_address,
 
"full_address", TYPE_STR, state->full_address,
"skey_etype", TYPE_NUM, state->session_key_enctype,
+
"skey_etype", TYPE_NUM, session_key_enctype, // state->session_key_enctype
"pa_error", TYPE_NUM, preauth_err,
+
"pa_error", TYPE_NUM, preauth_err, // state->preauth_err
 
/* request */
 
/* request */
 
"kdcreq.msg_type", TYPE_STR, state->req_msg_type,
 
"kdcreq.msg_type", TYPE_STR, state->req_msg_type,
Line 384: Line 165:
 
"kdcreq.server", TYPE_STR, state->req_server,
 
"kdcreq.server", TYPE_STR, state->req_server,
 
"kdcreq.kdc_options", TYPE_STR, state->req_kdc_options,
 
"kdcreq.kdc_options", TYPE_STR, state->req_kdc_options,
"kdcreq.start", TYPE_NUM, state->req_from,
+
"kdcreq.start", TYPE_NUM, req_from, // state->req_from
"kdcreq.end", TYPE_NUM, state->req_end,
+
"kdcreq.end", TYPE_NUM, req_end, // state->req_end
"kdcreq.renew_till", TYPE_NUM, state->req_rtime,
+
"kdcreq.renew_till", TYPE_NUM, req_time, // state->req_rtime
 
/* reply */
 
/* reply */
 
"kdcrep.msg_type", TYPE_STR,state->rep_msg_type,
 
"kdcrep.msg_type", TYPE_STR,state->rep_msg_type,
Line 392: Line 173:
 
"kdcrep.server", TYPE_STR, state->rep_server,
 
"kdcrep.server", TYPE_STR, state->rep_server,
 
"kdcrep.tkt.server", TYPE_STR, state->rep_tkt_server,
 
"kdcrep.tkt.server", TYPE_STR, state->rep_tkt_server,
"kdcrep.tkt.flags", TYPE_NUM, state->rep_tkt_flags,
+
"kdcrep.tkt.flags", TYPE_NUM, rep_tkt_flags, // state->rep_tkt_flags
"kdcrep.tkt.start", TYPE_NUM, state->rep_tarttime,
+
"kdcrep.tkt.start", TYPE_NUM, rep_tarttime, // state->rep_tarttime
"kdcrep.tkt.end", TYPE_NUM, pstate->rep_endtime,
+
"kdcrep.tkt.end", TYPE_NUM, rep_endtime, // pstate->rep_endtime,
"kdcrep.tkt.renew_till", TYPE_NUM, state->rep_renew_till,
+
"kdcrep.tkt.renew_till", TYPE_NUM, rep_renew_till, // state->rep_renew_till
"kdcrep.tkt.authtime", TYPE_NUM, state->rep_authtime,
+
"kdcrep.tkt.authtime", TYPE_NUM, rep_authtime, // state->rep_authtime,
"kdcrep.tkt.tr_type", TYPE_NUM, state->rep_transited_type,
+
"kdcrep.tkt.tr_type", TYPE_NUM, rep_transited_type // state->rep_transited_type
"kdcrep.tkt.caddrs", TYPE_STR, state->rep_caddrs,
+
"kdcrep.tkt.skey_etype", TYPE_NUM, rep_session_enctype, // state->rep_session_enctype
"kdcrep.tkt.skey_etype", TYPE_NUM, state->rep_session_enctype);
+
"kdcrep.tkt.caddrs", TYPE_STR, state->rep_caddrs
  +
);
 
return rc;
 
return rc;
 
}
 
}
  +
  +
 
==== Dictionary of the field names ====
  +
 
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.
 
  +
   
 
== Configuration ==
 
== Configuration ==

Revision as of 13:14, 28 March 2013

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.


Purpose

Create an Audit infrastructure within MIT Kerberos to monitor security related events on the KDC. In future expand Kerberos Audit facility to the application servers, kadmin if it remains desirable.


Requirements

The new audit system should be:

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


Events

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

Audit module loaded/unloaded
Startup and shutdown of the audit system must be recorded by audit system;
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:
client and server principals, flags, ticket start/end/renew_till times, authtime, transited encoding type and contents, session key type, addresses;


Design details

The proposal is a hybrid of variadic key-value-pair (KVP) and one-API-per-event approaches.

The following are highlights of this new feature:

Flow
On the KDC side call audit event-specific functions, whose input consists of the event-id, event-status (success or failure) and event-specific structure. If event-specific callback is implemented by the audit plugin, pass the pointer to the event-specific structure to the plugin. Otherwise, fallback to the generic function with variadic KVP arguments;
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.
Ticket ID is created as a hash of AS session key or client principal name plus timestamp or some other way;
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.
Dictionary
Define the dictionary of the key names to be used in KVP to describe the events in the unified way. See below for details;
Sanitizing
Strip the event-specific structure from the security sensitive information before passing it to the plugin;
Variadic KVP
KVP is a triplet consisting of key-name, key-value and a hint about the type of the value. All key-values should be converted into the strings. The plugin implementor is hinted at the "original" type of the key-value.


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);
/* event specific functions */
krb5_error_code 
kau_kdc_start(krb5_context context, struct server_handle shdl, 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 */
typedef struct krb5_audit_vtable_st {
   /* Mandatory: name of module. */
   char             *name;
   kau_open_fn       open;
   kau_close_fn      close;
   kau_generic_fn    generic;
   kau_kdc_start_fn  kdc_start;
   kau_kdc_stop_fn   kdc_stop;
   kau_as_req_fn     as_req;
   kau_tgs_req_fn    tgs_req;
} *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_generic_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

krb5_error_code
kau_as_req(krb5_context context, struct as_req_state *state,
          krb5_error_code  status)
{
   krb5_error_code rc = 0;
   ...
   /* If audit plugin event-specific callback is implemented, call it */
   if (hdl->vt.as_req) {
       rc = hdl->vt.as_req(hdl->au_ctx, event_id, event_status, state);
       return rc;
   }
   /* Otherwise, try the generic one. */
   if (hdl->vt.generic)
       rc = rec_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;
   ...
   /* All values with TYPE_NUM type-hint are string representations of 
    * their numeric conterparts in 'state' structure.
    */
   hdl->vt.record(hdl->au_ctx, event_id, event_status,
                  "tkt_id",             TYPE_NUM, tkt_id,              // state->tkt_id 
                  "kdc_status",         TYPE_STR, state->status,
                  "full_address",       TYPE_STR, state->full_address,                 
                  "skey_etype",         TYPE_NUM, session_key_enctype, //  state->session_key_enctype
                  "pa_error",           TYPE_NUM, preauth_err,         //  state->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, req_from,  // state->req_from
                  "kdcreq.end",         TYPE_NUM, req_end,   // state->req_end
                  "kdcreq.renew_till",  TYPE_NUM, req_time,  // 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, rep_tkt_flags,    // state->rep_tkt_flags
                  "kdcrep.tkt.start",   TYPE_NUM, rep_tarttime,     // state->rep_tarttime
                  "kdcrep.tkt.end",     TYPE_NUM, rep_endtime,      // pstate->rep_endtime,
                  "kdcrep.tkt.renew_till",  TYPE_NUM, rep_renew_till,      // state->rep_renew_till
                  "kdcrep.tkt.authtime",    TYPE_NUM, rep_authtime,        // state->rep_authtime,
                  "kdcrep.tkt.tr_type",     TYPE_NUM, rep_transited_type   // state->rep_transited_type
                  "kdcrep.tkt.skey_etype",  TYPE_NUM, rep_session_enctype, // state->rep_session_enctype
                  "kdcrep.tkt.caddrs",      TYPE_STR, state->rep_caddrs
   );
   return rc;
}


Dictionary of the field names

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.


Configuration

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.


Test implementation

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

  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