logo_kerberos.gif

Difference between revisions of "Projects/Audit"

From K5Wiki
Jump to: navigation, search
(Updated Events section)
Line 28: Line 28:
 
:: ticket ID (if available);
 
:: ticket ID (if available);
 
:: KDC status message;
 
:: KDC status message;
:: kdc request: client and server principals, kdc options, star/end/renew_till times, enctypes, 2nd ticket, auth data type, pre-auth data type, addresses, message type,
+
:: kdc request: client and server principals, kdc options, star/end/renew_till times, available enctypes, 2nd ticket, auth data type, pre-auth data type, addresses, message type,
 
:: kdc reply: client principal, ticket, message type;
 
:: kdc reply: client principal, ticket, message type;
 
:: remote port;
 
:: remote port;
 
:: pre-auth error;
 
:: pre-auth error;
:: enctypes: available and chosen by KDC (Common Criteria FCS_CKM.1, FCS_CKM.4);
+
:: chosen by KDC enctype (Common Criteria FCS_CKM.1, FCS_CKM.4);
 
:: session key cleared (Common Criteria FCS_CKM.1, FCS_CKM.4);
 
:: session key cleared (Common Criteria FCS_CKM.1, FCS_CKM.4);
 
:TGS exchange:
 
:TGS exchange:
 
:: ticket ID (if available);
 
:: ticket ID (if available);
 
:: KDC status message;
 
:: KDC status message;
:: kdc request: client and server principals, kdc options, star/end/renew_till times, enctypes, 2nd ticket, auth data type, pre-auth data type, addresses, message type,
+
:: kdc request: client and server principals, kdc options, star/end/renew_till times, available enctypes, 2nd ticket, auth data type, pre-auth data type, addresses, message type,
 
:: kdc reply: client principal, ticket, message type;
 
:: kdc reply: client principal, ticket, message type;
 
:: principals: (if applicable) alternate client and server principals, 2nd ticket server name;
 
:: principals: (if applicable) alternate client and server principals, 2nd ticket server name;
Line 43: Line 43:
 
:: is_referral;
 
:: is_referral;
 
:: xrealm name;
 
:: xrealm name;
:: enctypes: available and chosen by KDC, u2u enctype (Common Criteria FCS_CKM.1, FCS_CKM.4);
+
:: 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);
 
:: session key cleared (Common Criteria FCS_CKM.1, FCS_CKM.4);
 
:Policy: Policies violation when processing requests - TBD;
 
:Policy: Policies violation when processing requests - TBD;
Line 57: Line 57:
 
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.
 
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 3 (key-value pairs) ===
+
=== Design 3 (variadic functions) ===
   
 
Use C variadic function to construct/parse key-value pairs.
 
Use C variadic function to construct/parse key-value pairs.
 
 
  +
 
 
 
=== Design 2 (JSON-like) ===
 
=== Design 2 (JSON-like) ===
   
This approach is based on JSON-like serialization of the KDC auditable events and utilized the existing MIT Kerberos json.so library.
+
This approach is based on JSON-like serialization of the KDC auditable events and utilized the existing MIT Kerberos json.so (libkrb5support.so) library.
 
   
 
==== KDC facing API ====
 
==== KDC facing API ====
Line 122: Line 123:
 
(*kau_record_fn)(kau_ctx au_ctx, const int event_id, const int status, const char *audit_string);
 
(*kau_record_fn)(kau_ctx au_ctx, const int event_id, const int status, const char *audit_string);
 
 
==== Example (code and linearized output) ====
+
==== Example ====
   
 
The typical call on KDC side (TGS-REQ):
 
The typical call on KDC side (TGS-REQ):
Line 141: Line 142:
 
}
 
}
   
The output 'aud_str' string looks similar to the following:
 
  +
==== Output ====
  +
  +
To process the audit output, the plugin implementor can use the wide variety of tools to process the linearized json-like key-value pairs.
  +
  +
The following is an example of the audit output:
 
 
  +
({
 
"event_id":5,
 
"event_id":5,
 
"event_status":1,
 
"event_status":1,
"tkt_id":"94321337D58FC432",
+
"tkt_id":"D56D26929446BA61",
 
"kdc_status":"ISSUE",
 
"kdc_status":"ISSUE",
 
"kdcreq":{
 
"kdcreq":{
  +
"server":
  +
{"realm":"KRBTEST.COM","data":"host","length":2,"type":1},
 
"kdc_options":65536,
 
"kdc_options":65536,
"end":1362163527,
+
"end":1362516533,
"num_enctypes":9,
+
"avail_etypes":[18,17,16,23,25,26,1,3,2]
"ktype":18,
 
"server":{"realm":"KRBTEST.COM","data":"host","length":2,"type":1}
 
 
},
 
},
 
"kdcrep":{
 
"kdcrep":{
Line 156: Line 164:
 
"client":{"realm":"KRBTEST.COM","data":"user","length":1,"type":1},
 
"client":{"realm":"KRBTEST.COM","data":"user","length":1,"type":1},
 
"ticket":{
 
"ticket":{
"server":{"realm":"KRBTEST.COM","data":"host","length":2,"type":1},
 
  +
"server":
"flags":589824,
 
  +
{"realm":"KRBTEST.COM","data":"host","length":2,"type":1},
"client":{"realm":"KRBTEST.COM","data":"user","length":1,"type":1},
 
  +
"client":
"start":0,
 
  +
{"realm":"KRBTEST.COM","data":"user","length":1,"type":1},
"end":1362163527,
+
"start":1362430134,
  +
"end":1362516533,
 
"renew_till":0,
 
"renew_till":0,
"authtime":1362077127,
+
"authtime":1362430133,
  +
"flags":589824,
 
"tr_type":1
 
"tr_type":1
}
+
}
 
},
 
},
"princ_cl":{"realm":"KRBTEST.COM","data":"user","length":1,"type":1},
 
"princ_srv":{"realm":"KRBTEST.COM","data":"host","length":2,"type":1},
 
 
"full_address":{
 
"full_address":{
"port":45335,
+
"port":35899,
"address":{"addrtype":2,"length":4,"addr":[18,18,22,333]}
+
"address":{"addrtype":2,"length":4,"addr":[18,18,44,333]}
 
},
 
},
 
"rep_flags":176,
 
"rep_flags":176,
"tkt_end":1362163527,
 
  +
"skey_etype":18,
"authtime":1362077127,
 
  +
"sesskey_cleared":true
"ktype":18,
 
  +
})
"avail_ktypes":[18,17,16,23,25,26,1,3,2],
 
"sesskey_cleared":true}
 
 
 
   
 
==== Dictionary of the field names ====
 
==== Dictionary of the field names ====
Line 185: Line 187:
 
One needs to define a dictionary of the field names to be used to describe the events in some unified way.
 
One needs to define a dictionary of the field names to be used to describe the events in some unified way.
   
The possible field names are:
+
The possible basic field names are:
   
 
* "tkt_id" for ticket ID;
 
* "tkt_id" for ticket ID;
 
* "client" and "server" for client and server principal names;
 
* "client" and "server" for client and server principal names;
* "port" for client's port;
 
  +
* "full_address" for address and portport
 
* "pa_error" for pre-authentication error;
 
* "pa_error" for pre-authentication error;
* "ktype" and "avail_ktypes" for available key types and used keytype;
+
* "skey_etype" and "avail_etypes" for available key types and chosen enc type;
 
* "sesskey_cleared" to indicate that session key was cleared;
 
* "sesskey_cleared" to indicate that session key was cleared;
* "tkt_start", "tkt_end" and "tkt_renewtill" for the ticket's start/end/renewed-until times;
+
* "start", "end" and "renew_till" for the ticket's start/end/renew-until times;
 
* "rep_flags" for reply flags;
 
* "rep_flags" for reply flags;
 
* "kdc_status" for KDC status message;
 
* "kdc_status" for KDC status message;
Line 201: Line 203:
 
Also, "event_id" and "event_status" for audit event ID and to indicate if the event is reported on success or failure. (Most likely these two already have some standard names)
 
Also, "event_id" and "event_status" for audit event ID and to indicate if the event is reported on success or failure. (Most likely these two already have some standard names)
 
 
  +
 
=== Design 1 (one-API-per-event) ===
 
=== Design 1 (one-API-per-event) ===
   
Line 394: Line 397:
 
const int from_port, krb5_enctype used_ktype,
 
const int from_port, krb5_enctype used_ktype,
 
const char *kdc_status, int status);
 
const char *kdc_status, int status);
  +
   
 
== Configuration ==
 
== Configuration ==

Revision as of 17:35, 4 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, star/end/renew_till times, available enctypes, 2nd ticket, auth data type, pre-auth data type, addresses, message type,
kdc reply: client principal, ticket, 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, star/end/renew_till times, available enctypes, 2nd ticket, auth data type, pre-auth data type, addresses, message type,
kdc reply: client principal, ticket, 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


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.

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 3 (variadic functions)

Use C variadic function to construct/parse key-value pairs.


Design 2 (JSON-like)

This approach is based on JSON-like serialization of the KDC auditable events and utilized the existing MIT Kerberos json.so (libkrb5support.so) library.

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.
 * Here 'event_id' is an assigned ID of the auditable event and
 * 'status' indicates whether the event succeeded or failed. 
 */
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_reg_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

To process the audit output, the plugin implementor can use the wide variety of tools to process the linearized json-like key-value pairs.

The following is an example of the audit output:

({
"event_id":5,
"event_status":1,
"tkt_id":"D56D26929446BA61",
"kdc_status":"ISSUE",
"kdcreq":{
  "server":
     {"realm":"KRBTEST.COM","data":"host","length":2,"type":1},
  "kdc_options":65536,
  "end":1362516533,
  "avail_etypes":[18,17,16,23,25,26,1,3,2]
},
"kdcrep":{
  "msg_type":13,
  "client":{"realm":"KRBTEST.COM","data":"user","length":1,"type":1},
  "ticket":{
     "server":
        {"realm":"KRBTEST.COM","data":"host","length":2,"type":1},
     "client":
        {"realm":"KRBTEST.COM","data":"user","length":1,"type":1},
     "start":1362430134,
     "end":1362516533,
     "renew_till":0,
     "authtime":1362430133,
     "flags":589824,
     "tr_type":1
   }
},
"full_address":{
  "port":35899,
  "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:

  • "tkt_id" for ticket ID;
  • "client" and "server" for client and server 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.

Also, "event_id" and "event_status" for audit event ID and to indicate if the event is reported on success or failure. (Most likely these two already have some standard names)


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.

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);
/* AS exchange: Successful (status=1) or unsuccessful (status=0) attempt */
krb5_error_code 
kau_as_req(krb5_context context, struct as_req_state *state, int status);
krb5_error_code 
kau_as_req_pa(krb5_context context, struct as_req_state *state, int status);
/* TGS exchange: Successful (status=1) or unsuccessful (status=0) attempt; alternate, u2u, s4u and cross-realm TGS */
krb5_error_code 
kau_tgs(krb5_context context,
        struct tgs_req_audit_state *state, int status);
krb5_error_code 
kau_tgs_alt(krb5_context context,
            struct tgs_req_audit_state *state, int status);
krb5_error_code
kau_tgs_u2u(krb5_context context, struct tgs_req_audit_state *state,
            krb5_principal cl2, int status);
krb5_error_code
kau_tgs_xrealm(krb5_context context, struct tgs_req_audit_state *state,
               char* xrealm, int status);
/* Policy driven events - TBD */
krb5_error_code
kau_policy_as_req(krb5_context context, struct as_req_state *state,
                  krb5_error_code status);
krb5_error_code
kau_policy_s4u2proxy_req(krb5_context context, struct tgs_req_audit_state *state,
                         krb5_db_entry *st_client, krb5_error_code status);
krb5_error_code
kau_policy_tgs_req(krb5_context context, struct tgs_req_audit_state *state,
                   krb5_ticket *header_ticket, krb5_error_code status);
/* Session key generation and cleaning up */
krb5_error_code 
kau_sesskey_as_generated(krb5_context context,
                         struct as_req_state *state, int status);
krb5_error_code 
kau_sesskey_as_cleared(krb5_context context,
                       struct as_req_state *state, int status);
krb5_error_code 
kau_sesskey_tgs_generated(krb5_context context,
                          struct tgs_req_audit_state *state,int status);
krb5_error_code 
kau_sesskey_tgs_cleared(krb5_context context,
                        struct tgs_req_audit_state *state, int status);
/* Name of audit module */
krb5_error_code 
kau_plugin_name(krb5_context context, char **name);
struct as_req_state {
   loop_respond_fn respond;
   void *arg;
   ...
   kdc_realm_t *active_realm;
   krb5_error_code preauth_err;
   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;
   kau_tgs_alt_fn    tgs_alt;
   kau_tgs_u2u_fn    tgs_u2u;
   kau_tgs_xrealm_fn tgs_xrealm;
   kau_policy_as_req_fn        policy_as_req;
   kau_policy_tgs_req_fn       policy_tgs_req;
   kau_policy_s4u2proxy_req_fn policy_s4u2proxy_req;
   kau_sesskey_as_generated_fn  sesskey_as_generated;
   kau_sesskey_as_cleared_fn    sesskey_as_cleared;
   kau_sesskey_tgs_generated_fn sesskey_tgs_generated;
   kau_sesskey_tgs_cleared_fn   sesskey_tgs_cleared;
} *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);

typedef krb5_error_code
(*kau_tgs_alt_fn)(kau_ctx au_ctx, const char *tkt_id,
                  krb5_timestamp authtime, 
                  const char *cname, const char *sname,  const char *altsrv, 
                  const int from_port, const char *kdc_status, int status);

typedef krb5_error_code
(*kau_tgs_u2u_fn)(kau_ctx au_ctx, const char *tkt_id,
                  krb5_timestamp authtime,
                  const char *cname, const char *sname,
                  const char *cl2, const char *srv2,
                  const int from_port, const char *kdc_status, int status);
 
typedef krb5_error_code
(*kau_tgs_xrealm_fn)(kau_ctx au_ctx, const char *tkt_id,
                     krb5_timestamp authtime,
                     const char *cname, const char *sname, const char *xrealm,
                     krb5_flags c_flags, krb5_flags s_flags,
                     const int from_port, const char *kdc_status, int status);

typedef krb5_error_code
(*kau_sesskey_as_generated_fn)(kau_ctx au_ctx, const char *tkt_id,
                               const char *cname, const char *sname,
                               const int from_port,
                               const char * ktypes, krb5_enctype used_ktype,
                               const char *kdc_status, int status);

typedef krb5_error_code
(*kau_sesskey_as_cleared_fn)(kau_ctx au_ctx, const char *tkt_id,
                             const char *cname, const char *sname,
                             const int from_port, krb5_enctype used_ktype,
                             const char *kdc_status, int status);

typedef krb5_error_code
(*kau_sesskey_tgs_generated_fn)(kau_ctx au_ctx, const char *tkt_id,
                                const char *cname, const char *sname,
                                const int from_port,
                                const char *ktypes, krb5_enctype used_ktype,
                                const char *kdc_status, int status);

typedef krb5_error_code
(*kau_sesskey_tgs_cleared_fn)(kau_ctx au_ctx, const char *tkt_id,                        
                              const char *cname, const char *sname,
                              const int from_port, krb5_enctype used_ktype,
                              const char *kdc_status, int status);


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