feat(admin): emit KMS management audit events (#5554)

* feat(s3-types): add KMS service-control audit events

Configuration changes and service start/stop are management-plane actions
with no event name of their own, so they could not reach the audit
pipeline at all. Append three variants for them, following the existing
rule that KMS events are audit-only and live outside the `s3:` namespace,
so no bucket notification selector can expand to them.

* feat(admin): audit KMS management operations

Every KMS admin endpoint now builds an OperationContext from the
authenticated caller and hands it to the KMS layer, so the record the
manager already produces carries the principal, source address and
canonical request id instead of the internal placeholder.

A new adapter maps those records onto the server's existing AuditEntry
format and installs itself as the KMS audit sink at service assembly, so
KMS activity reaches the targets a deployment already operates. The
handlers emit directly for what the KMS layer cannot see: a request the
authorization gate rejects, and the endpoints with no context-aware KMS
entry point (data-key derivation and service control).

Only the failure class is recorded, never the error message, and the new
module joins the logging guardrail's checked files alongside the handlers
it serves.
This commit is contained in:
Zhengchao An
2026-08-01 19:14:31 +08:00
committed by GitHub
parent da389c0e21
commit 0bd53becb5
10 changed files with 965 additions and 174 deletions
@@ -32,6 +32,9 @@ const KMS_EVENTS: &[EventName] = &[
EventName::KmsKeyDeletionCancelled,
EventName::KmsKeyDeleted,
EventName::KmsKeyAccessed,
EventName::KmsServiceConfigured,
EventName::KmsServiceStarted,
EventName::KmsServiceStopped,
];
fn test_target() -> TargetID {
+25 -5
View File
@@ -87,11 +87,13 @@ pub enum EventName {
ObjectCreatedCreateMultipartUpload,
ObjectRemovedDeleteObjects,
// KMS management-plane events. They travel to the audit sink only and are
// never produced by the bucket notification path, so no compound `s3:`
// event expands to them. New variants must keep being appended here: the
// discriminant of every preceding variant is a `mask()` bit position, and
// inserting in the middle would silently renumber existing bits.
// KMS management-plane events, covering both key operations and the
// service-control endpoints that change which backend holds the keys. They
// travel to the audit sink only and are never produced by the bucket
// notification path, so no compound `s3:` event expands to them. New
// variants must keep being appended here: the discriminant of every
// preceding variant is a `mask()` bit position, and inserting in the middle
// would silently renumber existing bits.
KmsKeyCreated,
KmsKeyRotated,
KmsKeyEnabled,
@@ -100,6 +102,9 @@ pub enum EventName {
KmsKeyDeletionCancelled,
KmsKeyDeleted,
KmsKeyAccessed,
KmsServiceConfigured,
KmsServiceStarted,
KmsServiceStopped,
}
// Single event type sequential array for Everything.expand()
@@ -211,6 +216,9 @@ impl EventName {
"kms:Key:DeletionCancelled" => Ok(EventName::KmsKeyDeletionCancelled),
"kms:Key:Deleted" => Ok(EventName::KmsKeyDeleted),
"kms:Key:Accessed" => Ok(EventName::KmsKeyAccessed),
"kms:Service:Configured" => Ok(EventName::KmsServiceConfigured),
"kms:Service:Started" => Ok(EventName::KmsServiceStarted),
"kms:Service:Stopped" => Ok(EventName::KmsServiceStopped),
// `Everything` has no string representation (`as_str` yields ""), so it
// cannot be parsed back from a string. Every other variant round-trips.
_ => Err(ParseEventNameError(s.to_string())),
@@ -284,6 +292,9 @@ impl EventName {
EventName::KmsKeyDeletionCancelled => "kms:Key:DeletionCancelled",
EventName::KmsKeyDeleted => "kms:Key:Deleted",
EventName::KmsKeyAccessed => "kms:Key:Accessed",
EventName::KmsServiceConfigured => "kms:Service:Configured",
EventName::KmsServiceStarted => "kms:Service:Started",
EventName::KmsServiceStopped => "kms:Service:Stopped",
}
}
@@ -407,6 +418,9 @@ impl EventName {
| EventName::KmsKeyDeletionCancelled
| EventName::KmsKeyDeleted
| EventName::KmsKeyAccessed
| EventName::KmsServiceConfigured
| EventName::KmsServiceStarted
| EventName::KmsServiceStopped
)
}
}
@@ -630,6 +644,9 @@ mod tests {
EventName::KmsKeyDeletionCancelled,
EventName::KmsKeyDeleted,
EventName::KmsKeyAccessed,
EventName::KmsServiceConfigured,
EventName::KmsServiceStarted,
EventName::KmsServiceStopped,
];
/// Every KMS management-plane event.
@@ -642,6 +659,9 @@ mod tests {
EventName::KmsKeyDeletionCancelled,
EventName::KmsKeyDeleted,
EventName::KmsKeyAccessed,
EventName::KmsServiceConfigured,
EventName::KmsServiceStarted,
EventName::KmsServiceStopped,
];
/// Regression for backlog#965: `mask()` used to recurse forever for the