diff --git a/lambda-events/src/event/cloudwatch_events/cloudtrail.rs b/lambda-events/src/event/cloudwatch_events/cloudtrail.rs index 36d071ea..3f6bcc3e 100644 --- a/lambda-events/src/event/cloudwatch_events/cloudtrail.rs +++ b/lambda-events/src/event/cloudwatch_events/cloudtrail.rs @@ -1,3 +1,4 @@ +use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use serde_json::Value; @@ -26,23 +27,89 @@ pub struct AWSAPICall { #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] -pub struct UserIdentity { +pub struct SessionIssuer { pub r#type: String, + pub user_name: Option, pub principal_id: String, pub arn: String, pub account_id: String, - pub session_context: Option, } #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] -pub struct SessionContext { - pub attributes: Attributes, +pub struct WebIdFederationData { + pub federated_provider: Option, + pub attributes: Option, } #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] pub struct Attributes { pub mfa_authenticated: String, - pub creation_date: String, + pub creation_date: DateTime, +} + +#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SessionContext { + pub session_issuer: Option, + pub web_id_federation_data: Option, + pub attributes: Attributes, + pub source_identity: Option, + pub ec2_role_delivery: Option, +} + +#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct OnBehalfOf { + pub user_id: String, + pub identity_store_arn: String, +} + +// https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-event-reference-user-identity.html +#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct UserIdentity { + pub r#type: String, + pub account_id: Option, + pub arn: Option, + pub credential_id: Option, + pub invoked_by: Option, + pub principal_id: Option, + pub session_context: Option, + pub user_name: Option, + pub on_behalf_of: Option, +} + +#[cfg(test)] +mod tests { + use super::AWSAPICall; + + #[test] + #[cfg(feature = "cloudwatch_events")] + fn example_cloudwatch_cloudtrail_unknown_assumed_role() { + let data = include_bytes!("../../fixtures/example-cloudwatch-cloudtrail-assumed-role.json"); + let parsed: AWSAPICall = serde_json::from_slice(data).unwrap(); + let output: String = serde_json::to_string(&parsed).unwrap(); + let reparsed: AWSAPICall = serde_json::from_slice(&output.as_bytes()).unwrap(); + assert_eq!(parsed, reparsed); + } + #[test] + #[cfg(feature = "cloudwatch_events")] + fn example_cloudwatch_cloudtrail_unknown_federate() { + let data = include_bytes!("../../fixtures/example-cloudwatch-cloudtrail-unknown-federate.json"); + let parsed: AWSAPICall = serde_json::from_slice(data).unwrap(); + let output: String = serde_json::to_string(&parsed).unwrap(); + let reparsed: AWSAPICall = serde_json::from_slice(&output.as_bytes()).unwrap(); + assert_eq!(parsed, reparsed); + } + #[test] + #[cfg(feature = "cloudwatch_events")] + fn example_cloudwatch_cloudtrail_assumed_role() { + let data = include_bytes!("../../fixtures/example-cloudwatch-cloudtrail-unknown-user-auth.json"); + let parsed: AWSAPICall = serde_json::from_slice(data).unwrap(); + let output: String = serde_json::to_string(&parsed).unwrap(); + let reparsed: AWSAPICall = serde_json::from_slice(&output.as_bytes()).unwrap(); + assert_eq!(parsed, reparsed); + } } diff --git a/lambda-events/src/fixtures/example-cloudwatch-cloudtrail-assumed-role.json b/lambda-events/src/fixtures/example-cloudwatch-cloudtrail-assumed-role.json new file mode 100644 index 00000000..6e8946e9 --- /dev/null +++ b/lambda-events/src/fixtures/example-cloudwatch-cloudtrail-assumed-role.json @@ -0,0 +1,52 @@ +{ + "eventVersion": "1.08", + "userIdentity": { + "type": "AssumedRole", + "principalId": "ZZZZZZZZZZZZZZZZZZZZZ:me@dev.com", + "arn": "arn:aws:sts::123456789000:assumed-role/AWSReservedSSO_AWSAdministratorAccess_abcdef1234567890/me@dev.com", + "accountId": "123456789000", + "accessKeyId": "ABCDEFGHI12345678890", + "sessionContext": { + "sessionIssuer": { + "type": "Role", + "principalId": "ZZZZZZZZZZZZZZZZZZZZZ", + "arn": "arn:aws:iam::123456789000:role/aws-reserved/sso.amazonaws.com/eu-west-1/AWSReservedSSO_AWSAdministratorAccess_abcdef1234567890", + "accountId": "123456789000", + "userName": "AWSReservedSSO_AWSAdministratorAccess_abcdef1234567890" + }, + "webIdFederationData": {}, + "attributes": { + "creationDate": "2024-07-10T16:03:25Z", + "mfaAuthenticated": "false" + } + }, + "invokedBy": "servicecatalog.amazonaws.com" + }, + "eventTime": "2024-07-10T16:48:26Z", + "eventSource": "controltower.amazonaws.com", + "eventName": "CreateManagedAccount", + "awsRegion": "eu-west-1", + "sourceIPAddress": "servicecatalog.amazonaws.com", + "userAgent": "servicecatalog.amazonaws.com", + "requestParameters": { + "accountEmail": "HIDDEN_DUE_TO_SECURITY_REASONS", + "accountName": "Account Name", + "parentOrganizationalUnitName": "Organizational Unit (ou-a1b2-abcdef12)", + "sSOUserEmail": "HIDDEN_DUE_TO_SECURITY_REASONS", + "sSOUserFirstName": "HIDDEN_DUE_TO_SECURITY_REASONS", + "sSOUserLastName": "HIDDEN_DUE_TO_SECURITY_REASONS", + "provisionedProductId": "pp-abcdefg123456", + "idempotencyToken": "abcdef12345-abcdef12345" + }, + "responseElements": { + "createManagedAccountExecutionId": "123456789000-abcdef12345-abcdef12345" + }, + "requestID": "00000000-0000-0000-0000-000000000000", + "eventID": "00000000-0000-0000-0000-000000000000", + "readOnly": false, + "eventType": "AwsApiCall", + "managementEvent": true, + "recipientAccountId": "123456789000", + "eventCategory": "Management", + "sessionCredentialFromConsole": "true" +} diff --git a/lambda-events/src/fixtures/example-cloudwatch-cloudtrail-unknown-federate.json b/lambda-events/src/fixtures/example-cloudwatch-cloudtrail-unknown-federate.json new file mode 100644 index 00000000..336edc1f --- /dev/null +++ b/lambda-events/src/fixtures/example-cloudwatch-cloudtrail-unknown-federate.json @@ -0,0 +1,27 @@ +{ + "eventVersion": "1.08", + "userIdentity": { + "type": "Unknown", + "principalId": "00000000-0000-0000-0000-000000000000", + "accountId": "123456789000", + "userName": "me@dev.com" + }, + "eventTime": "2024-07-10T18:41:56Z", + "eventSource": "sso.amazonaws.com", + "eventName": "Federate", + "awsRegion": "eu-west-1", + "sourceIPAddress": "1.1.1.1", + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36", + "requestParameters": null, + "responseElements": null, + "requestID": "00000000-0000-0000-0000-000000000000", + "eventID": "00000000-0000-0000-0000-000000000000", + "readOnly": false, + "eventType": "AwsServiceEvent", + "managementEvent": true, + "recipientAccountId": "123456789000", + "serviceEventDetails": { + "relayId": "00000000-0000-0000-0000-000000000000_00000000-0000-0000-0000-000000000000" + }, + "eventCategory": "Management" +} diff --git a/lambda-events/src/fixtures/example-cloudwatch-cloudtrail-unknown-user-auth.json b/lambda-events/src/fixtures/example-cloudwatch-cloudtrail-unknown-user-auth.json new file mode 100644 index 00000000..96fed176 --- /dev/null +++ b/lambda-events/src/fixtures/example-cloudwatch-cloudtrail-unknown-user-auth.json @@ -0,0 +1,33 @@ +{ + "eventVersion": "1.08", + "userIdentity": { + "type": "Unknown", + "principalId": "123456789000", + "arn": "", + "accountId": "123456789000", + "accessKeyId": "" + }, + "eventTime": "2024-07-10T16:05:11Z", + "eventSource": "signin.amazonaws.com", + "eventName": "UserAuthentication", + "awsRegion": "eu-west-1", + "sourceIPAddress": "1.1.1.1", + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36", + "requestParameters": null, + "responseElements": null, + "additionalEventData": { + "AuthWorkflowID": "00000000-0000-0000-0000-000000000000", + "LoginTo": "https://tenant.awsapps.com/start/", + "CredentialType": "EXTERNAL_IDP" + }, + "requestID": "00000000-0000-0000-0000-000000000000", + "eventID": "00000000-0000-0000-0000-000000000000", + "readOnly": false, + "eventType": "AwsServiceEvent", + "managementEvent": true, + "recipientAccountId": "123456789000", + "serviceEventDetails": { + "UserAuthentication": "Success" + }, + "eventCategory": "Management" +}