use chrono::{DateTime, Utc};
use serde::Serialize;
use tracing::info;
#[derive(Serialize, Debug, Clone, Copy)]
#[serde(rename_all = "snake_case")]
pub enum Outcome {
Success,
Failure,
}
#[derive(Serialize, Debug, Clone, Copy)]
#[serde(rename_all = "snake_case")]
pub enum Operation {
GenerateKey,
Write,
Read,
Sign,
Verify,
Rekey,
}
#[derive(Serialize, Debug)]
pub struct AuditEvent {
#[serde(with = "chrono::serde::ts_seconds")]
pub timestamp: DateTime<Utc>,
pub operation: Operation,
pub outcome: Outcome,
#[serde(skip_serializing_if = "Option::is_none")]
pub error_message: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub key_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub key_size: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub key_version: Option<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub recipient_key_versions: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub symmetric_algorithm: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub signature_algorithm: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub signer_key_version: Option<String>,
}
impl AuditEvent {
pub fn new(operation: Operation) -> Self {
Self {
timestamp: Utc::now(),
operation,
outcome: Outcome::Success, error_message: None,
key_type: None,
key_size: None,
key_version: None,
recipient_key_versions: Vec::new(),
symmetric_algorithm: None,
signature_algorithm: None,
signer_key_version: None,
}
}
pub fn log(&self) {
match serde_json::to_value(self) {
Ok(serde_json::Value::Object(map)) => {
info!(target: "audit", event = ?map);
}
_ => {
info!(target: "audit", "Failed to serialize audit event");
}
}
}
}