Collect AWS IAM logs
This document explains how to ingest AWS IAM logs to Google Security Operations. The parser transforms raw JSON formatted logs into a structured Unified Data Model (UDM). It extracts relevant fields like user details, role information, permissions, and timestamps, mapping them to corresponding UDM fields for consistent security analysis.
Before you begin
- Ensure that you have a Google SecOps instance.
- Ensure that you have privileged access to AWS.
Configure AWS IAM and S3
- Create an Amazon S3 bucket following this user guide: Creating a bucket.
- Save the bucket Name and Region for later use.
- Create a user following this user guide: Creating an IAM user.
- Select the created User.
- Select the Security credentials tab.
- Click Create Access Key in the Access Keys section.
- Select Third-party service as the Use case.
- Click Next.
- Optional: add a description tag.
- Click Create access key.
- Click Download CSV file to save the Access Key and Secret Access Key for later use.
- Click Done.
- Select the Permissions tab.
- Click Add permissions in the Permissions policies section.
- Select Add permissions.
- Select Attach policies directly
- Search for and select the AmazonS3FullAccess policy.
- Click Next.
- Click Add permissions.
Configure CloudTrail to capture IAM logs
- Sign in to the AWS Management Console.
- In the search bar, type and select CloudTrail from the services list.
- Click Create trail.
- Provide a Trail name; for example,
IAMActivityTrail
.- Apply trail to all regions: select Yes to capture activities across all regions.
- Storage location: select the S3 bucket created earlier or create a new one.
- S3 Bucket: enter a name for the S3 bucket; for example,
iam-logs-bucket
. - Select Create a new IAM role (if not created earlier).
- Management events: select Read and Write to capture both read and write events on IAM resources.
- Data events: enable S3 and Lambda data events.
- Click Create to create the trail.
Configure CloudTrail to Export Logs to S3
- Go to Services > S3.
- Select the S3 bucket where CloudTrail logs are stored; for example,
iam-logs-bucket
. - Ensure that CloudTrail has the right permissions to write logs to the bucket.
Add the following policy if it's not already present:
{ "Version": "2012-10-17", "Statement": [ { "Sid": "CloudTrailS3Access", "Effect": "Allow", "Principal": { "Service": "cloudtrail.amazonaws.com" }, "Action": "s3:PutObject", "Resource": "arn:aws:s3:::your-bucket-name/AWSLogs/*" } ] }
Enable Versioning on the S3 bucket to ensure that logs are stored with multiple versions.
Go to Properties > Bucket Versioning > Enable.
Optional: Configure Lambda for real-time export
- Go to the AWS Lambda Console.
- Click Create function.
- Select Author from Scratch.
- Set the function name as
ExportIAMLogsToS3
. - Select a Python 3.x runtime.
Assign an IAM Role to the function that has permissions to:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "logs:GetLogEvents", "logs:FilterLogEvents", "logs:DescribeLogGroups", "logs:DescribeLogStreams" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "s3:PutObject" ], "Resource": "arn:aws:s3:::your-bucket-name/*" } ] }
Use the following Python code to fetch IAM logs and upload them to S3:
import boto3 import gzip from io import BytesIO s3 = boto3.client('s3') logs = boto3.client('logs') def lambda_handler(event, context): log_group = event['logGroup'] log_stream = event['logStream'] log_events = logs.get_log_events( logGroupName=log_group, logStreamName=log_stream, startFromHead=True ) log_data = "\n".join([event['message'] for event in log_events['events']]) # Compress and upload to S3 compressed_data = gzip.compress(log_data.encode('utf-8')) s3.put_object( Bucket='your-s3-bucket-name', Key='iam-logs/{log_stream}.gz', Body=compressed_data )
- Replace
your-s3-bucket-name
with your actual bucket name.
Configure Lambda Trigger for CloudWatch Logs
- In the Lambda Console, go to Designer.
- Choose Add Trigger > CloudWatch Logs.
- Select the CloudWatch Logs log group associated with your IAM logs; for example,
/aws/cloudtrail/
. - Click Add.
Configure a feed in Google SecOps to ingest AWS IAM logs
- Go to SIEM Settings > Feeds.
- Click Add new.
- In the Feed name field, enter a name for the feed; for example, AWS IAM Logs.
- Select Amazon S3 as the Source type.
- Select AWS IAM as the Log type.
- Click Next.
Specify values for the following input parameters:
- Region: the region where the Amazon S3 bucket is located.
- S3 URI: the bucket URI.
s3://your-log-bucket-name/
- Replace
your-log-bucket-name
with the actual name of the bucket.
- Replace
- URI is a: select Directory or Directory which includes subdirectories.
Source deletion options: select the deletion option according to your preference.
Access Key ID: the User access key with access to the s3 bucket.
Secret Access Key: the User secret key with access to the s3 bucket.
Asset namespace: the asset namespace.
Ingestion labels: the label to be applied to the events from this feed.
Click Next.
Review your new feed configuration in the Finalize screen, and then click Submit.
UDM Mapping Table
Log Field | UDM Mapping | Logic |
---|---|---|
Arn | entity.entity.resource.name | Directly mapped from the Arn field for USER and RESOURCE entity types. For GROUP entity type, it's mapped from Group.Arn . |
AssumeRolePolicyDocument | entity.entity.resource.attribute.permissions.name | Directly mapped from the AssumeRolePolicyDocument field, but only for RESOURCE entity type. |
CreateDate | entity.entity.user.attribute.creation_time | Directly mapped from the CreateDate field and converted to Chronicle's timestamp format for USER entity type. |
CreateDate | entity.entity.resource.attribute.creation_time | Directly mapped from the CreateDate field and converted to Chronicle's timestamp format for RESOURCE entity type. |
Group.Arn | entity.entity.resource.name | Directly mapped from the Group.Arn field for GROUP entity type. |
Group.CreateDate | entity.entity.group.attribute.creation_time | Directly mapped from the Group.CreateDate field and converted to Chronicle's timestamp format. |
Group.GroupID | entity.entity.group.product_object_id | Directly mapped from the Group.GroupID field. |
Group.GroupName | entity.entity.group.group_display_name | Directly mapped from the Group.GroupName field. |
Group.GroupName | entity.entity.group.email_addresses | Directly mapped from the Group.GroupName field. |
Group.Path | entity.entity.group.attribute.labels.value | Directly mapped from the Group.Path field, the key is hardcoded to path |
IsTruncated | entity.entity.group.attribute.labels.value | Directly mapped from the IsTruncated field and converted to string, the key is hardcoded to is_truncated |
Marker | entity.entity.group.attribute.labels.value | Directly mapped from the Marker field, the key is hardcoded to marker |
PasswordLastUsed | entity.entity.user.last_login_time | Directly mapped from the PasswordLastUsed field and converted to Chronicle's timestamp format. |
Path | entity.entity.user.attribute.labels.value | Directly mapped from the Path field for USER entity type, the key is hardcoded to path . |
Path | entity.entity.resource.attribute.labels.value | Directly mapped from the Path field for RESOURCE entity type, the key is hardcoded to path . |
PermissionsBoundary.PermissionsBoundaryArn | entity.entity.resource.attribute.labels.value | Directly mapped from the PermissionsBoundary.PermissionsBoundaryArn field, the key is hardcoded to permissions_boundary_arn . |
PermissionsBoundary.PermissionsBoundaryType | entity.entity.resource.attribute.labels.value | Directly mapped from the PermissionsBoundary.PermissionsBoundaryType field, the key is hardcoded to permissions_boundary_type . |
RoleID | entity.entity.resource.product_object_id | Directly mapped from the RoleID field. |
RoleLastUsed.LastUsedDate | entity.entity.resource.attribute.labels.value | Directly mapped from the RoleLastUsed.LastUsedDate field, the key is hardcoded to role_last_used_date . |
RoleLastUsed.Region | entity.entity.location.name | Directly mapped from the RoleLastUsed.Region field. |
RoleName | entity.entity.resource.attribute.roles.name | Directly mapped from the RoleName field. |
Tags.Key | entity.entity.user.attribute.labels.key | Used as the key for the labels field within the user attribute. |
Tags.Value | entity.entity.user.attribute.labels.value | Used as the value for the labels field within the user attribute. |
UserID | entity.entity.user.product_object_id | Directly mapped from the UserID field. |
UserName | entity.entity.user.userid | Directly mapped from the UserName field. |
Users.Arn | relations.entity.resource.name | Directly mapped from the Users.Arn field within the user relation. |
Users.CreateDate | relations.entity.user.attribute.creation_time | Directly mapped from the Users.CreateDate field within the user relation and converted to Chronicle's timestamp format. |
Users.PasswordLastUsed | relations.entity.user.last_login_time | Directly mapped from the Users.PasswordLastUsed field within the user relation and converted to Chronicle's timestamp format. |
Users.Path | relations.entity.user.attribute.labels.value | Directly mapped from the Users.Path field within the user relation, the key is hardcoded to path . |
Users.PermissionsBoundary.PermissionsBoundaryArn | relations.entity.resource.attribute.labels.value | Directly mapped from the Users.PermissionsBoundary.PermissionsBoundaryArn field within the user relation, the key is hardcoded to permissions_boundary_arn . |
Users.PermissionsBoundary.PermissionsBoundaryType | relations.entity.resource.attribute.labels.value | Directly mapped from the Users.PermissionsBoundary.PermissionsBoundaryType field within the user relation, the key is hardcoded to permissions_boundary_type . |
Users.UserID | relations.entity.user.product_object_id | Directly mapped from the Users.UserID field within the user relation. |
Users.UserName | relations.entity.user.userid | Directly mapped from the Users.UserName field within the user relation. |
N/A | entity.metadata.collected_timestamp | Populated with the event timestamp from the raw log. |
N/A | entity.metadata.vendor_name | Hardcoded to AWS . |
N/A | entity.metadata.product_name | Hardcoded to AWS IAM . |
N/A | entity.metadata.entity_type | Determined based on the presence of specific fields: USER if UserID exists, RESOURCE if RoleName exists, and GROUP if Group.GroupName exists. |
N/A | entity.entity.resource.resource_subtype | Set to User for USER and GROUP entity types. |
N/A | entity.entity.resource.resource_type | Set to ACCESS_POLICY for RESOURCE entity type. |
N/A | entity.entity.resource.attribute.cloud.environment | Hardcoded to AMAZON_WEB_SERVICES . |
N/A | relations.entity_type | Hardcoded to USER for user relations within a group. |
N/A | relations.relationship | Hardcoded to MEMBER for user relations within a group. |
N/A | relations.direction | Hardcoded to UNIDIRECTIONAL for user relations within a group. |
N/A | relations.entity.resource.resource_subtype | Hardcoded to User for user relations within a group. |
Changes
2023-12-14
- Newly created parser.
Need more help? Get answers from Community members and Google SecOps professionals.