As businesses move to the cloud, ensuring the security of the cloud environment is crucial. AWS offers a range of security services like AWS Security Hub, AWS GuardDuty, Amazon Inspector, Amazon Macie etc. designed to help you monitor and respond to security events for your workload and infra. It’s also important to ensure that these security services themselves should be always active and functioning correctly. This post will dive into how we can monitor these AWS Security services and build a layered security approach, emphasizing the importance of both prevention and detection.
Before we dive into the details of AWS monitoring and detection tools, it’s important to acknowledge the role of preventive security measures like Service Control Policies (SCPs), IAM Policies, and AWS Guardrails. These tools are essential in preventing unauthorized or undesirable actions from taking place. For example, SCPs allow you to enforce account-wide permissions, ensuring that critical operations like disabling security services are blocked from the start.
Remember: Prevention is always the first line of defense. By implementing least privilege IAM policies, guardrails, and SCPs, you can prevent a large number of security risks from materialising.
However, even in a well-architected environment, there are scenarios where preventive measures alone may not be sufficient. Imagine an organization where a legacy IAM role has been left with broad permissions, or a developer was temporarily granted permissions that haven’t been properly audited. Despite having SCPs or guardrails in place, this role might still have enough privilege to disable key security services like GuardDuty, Inspector or tamper with CloudTrail. In such cases, it becomes imperative to have detection mechanisms in place to catch risky actions that slip through the preventive layer.
This is where AWS monitoring services come into play, allowing you to detect and respond to such actions before they escalate into full-blown security incidents.
Detecting Suspicious Activity
To effectively monitor the AWS environment, we can leverage CloudTrail events. By configuring alerts and rules based on specific CloudTrail events, we can detect suspicious activity, such as unauthorized attempts to stop logging, disable security hub, disable inspector etc. This part outlined how we can monitor AWS security services themselves. For instance, we can set up CloudWatch Alarms or EventBridge rules that trigger alerts when events like StopLogging, DeleteTrail are detected.
Below architecture explains how we can monitor these services
Event Flow :
- I have created EventRule that gets triggered as soon as if any one of the Security services get deactivated/disabled/deleted.
- Event rule target is Lambda function, that extract details from corresponding event. Details like username — who disabled service, source ip, timestamp, eventname, eventsource. This will help us in investigation.
- Once event is processed by Lambda, lambda publish message to SNS.
- With SNS, depending on subscription (Email, SMS, HTTPs) we will get notified. Here we can cofigure any communication channel thats feasible for us. For this blog and demo, I’m using only Email and OpsGenie.
Below Python code shows event processing and SNS publish. In order find complete CloudFormation stack and code, refer repo :
import json
import boto3
import os
sns = boto3.client('sns')
def handler(event, context):
detail = event['detail']
eventName = detail['eventName']
userType = detail['userIdentity']['type']
eventSource = detail['eventSource']
if eventName == 'ConsoleLogin' and userType == 'Root':
accountId = detail['userIdentity']['accountId']
timestamp = detail['eventTime']
sourceIp = detail['sourceIPAddress']
loginStatus = detail.get('responseElements', {}).get('ConsoleLogin')
mfaUsed = detail.get('additionalEventData', {}).get('MFAUsed', 'No')
# Log the event details
print(f"Root login attempt: AccountId={accountId}, Timestamp={timestamp}, SourceIp={sourceIp}, Status={loginStatus}, MFAUsed={mfaUsed}")
# Create JSON message
message = {
"AccountId": accountId,
"Timestamp": timestamp,
"SourceIp": sourceIp,
"LoginStatus": loginStatus,
"MFAUsed": mfaUsed,
"Message": "Root login attempt detected"
}
# Publish message to SNS topic
messageToPublish = json.dumps(message)
messageHeader = f"Root login attempt detected\nAccountId: {accountId}\nTimestamp: {timestamp}\nSourceIp: {sourceIp}\nStatus: {loginStatus}\nMFAUsed: {mfaUsed}"
sns.publish(
TopicArn=f"arn:aws:sns:{os.environ['REGION']}:{os.environ['ACCOUNT_ID']}:SecurityAlarmsTopic",
Message=messageToPublish,
Subject=messageHeader
)
elif eventName == 'DisableSecurityHub':
accountId = detail['userIdentity']['accountId']
timestamp = detail['eventTime']
sourceIp = detail['sourceIPAddress']
userid = detail['userIdentity']['sessionContext']['sessionIssuer']['userName']
# Create JSON message
message = {
"AccountId": accountId,
"Timestamp": timestamp,
"SourceIp": sourceIp,
"UserID": userid,
"EventSource": eventSource,
"Message": "Security Hub has been Disabled"
}
# Publish message to SNS topic
messageToPublish = json.dumps(message)
messageHeader = f"Security Hub Disabled for Account: {accountId}"
sns.publish(
TopicArn=f"arn:aws:sns:{os.environ['REGION']}:{os.environ['ACCOUNT_ID']}:SecurityAlarmsTopic",
Message=messageToPublish,
Subject=messageHeader
)
# Alarm - GuardDuty Disable
elif eventName == 'DeleteDetector' and eventSource == 'guardduty.amazonaws.com':
accountId = detail['userIdentity']['accountId']
timestamp = detail['eventTime']
eventsource = detail['eventSource']
sourceIp = detail['sourceIPAddress']
userid = detail['userIdentity']['sessionContext']['sessionIssuer']['userName']
# Create JSON message
message = {
"AccountId": accountId,
"Timestamp": timestamp,
"SourceIp": sourceIp,
"UserID": userid,
"EventSource": eventSource,
"Message": "GuardDuty has been Disabled"
}
# Publish message to SNS topic
messageToPublish = json.dumps(message)
messageHeader = f"GuardDuty Disabled for Account: {accountId}"
sns.publish(
TopicArn=f"arn:aws:sns:{os.environ['REGION']}:{os.environ['ACCOUNT_ID']}:SecurityAlarmsTopic",
Message=messageToPublish,
Subject=messageHeader
)
# Alarm - Inspector Disabled
elif eventName == 'Disable' and eventSource == 'inspector2.amazonaws.com':
accountId = detail['userIdentity']['accountId']
timestamp = detail['eventTime']
eventsource = detail['eventSource']
sourceIp = detail['sourceIPAddress']
userid = detail['userIdentity']['sessionContext']['sessionIssuer']['userName']
# Create JSON message
message = {
"AccountId": accountId,
"Timestamp": timestamp,
"SourceIp": sourceIp,
"UserID": userid,
"EventSource": eventSource,
"Message": "AWS Inspector has been Disabled"
}
# Publish message to SNS topic
messageToPublish = json.dumps(message)
messageHeader = f"AWS Inspector Disabled for Account: {accountId}"
sns.publish(
TopicArn=f"arn:aws:sns:{os.environ['REGION']}:{os.environ['ACCOUNT_ID']}:SecurityAlarmsTopic",
Message=messageToPublish,
Subject=messageHeader
)
# Alarm - Config Disabled
elif eventName == 'DeleteConfigurationRecorder' and eventSource == 'config.amazonaws.com':
accountId = detail['userIdentity']['accountId']
timestamp = detail['eventTime']
eventsource = detail['eventSource']
sourceIp = detail['sourceIPAddress']
userid = detail['userIdentity']['sessionContext']['sessionIssuer']['userName']
# Create JSON message
message = {
"AccountId": accountId,
"Timestamp": timestamp,
"SourceIp": sourceIp,
"UserID": userid,
"EventSource": eventSource,
"Message": "AWS Config has been Disabled"
}
# Publish message to SNS topic
messageToPublish = json.dumps(message)
messageHeader = f"AWS Config Disabled for Account: {accountId}"
sns.publish(
TopicArn=f"arn:aws:sns:{os.environ['REGION']}:{os.environ['ACCOUNT_ID']}:SecurityAlarmsTopic",
Message=messageToPublish,
Subject=messageHeader
)
Troubleshooting
- Make sure SNS subscription have status Confirmed.
- Check Cloudwatch logs for lambda function for further error.
AWS Security – CloudTrail Events
Security Service | Description | CloudTrail Event Source | EventName (when disabled) |
---|---|---|---|
AWS CloudTrail | Tracks API calls and user activity within your AWS account. | cloudtrail.amazonaws.com | StopLogging |
Amazon GuardDuty | Threat detection service that continuously monitors for malicious activity. | guardduty.amazonaws.com | StopMonitoringMembers |
Amazon GuardDuty | Threat detection service that continuously monitors for malicious activity. | guardduty.amazonaws.com | DeleteDetector |
AWS Config | Monitors and records configurations of AWS resources and evaluates resource compliance. | config.amazonaws.com | StopConfigurationRecorder |
AWS Security Hub | Provides a comprehensive view of security alerts and security posture across AWS accounts. | securityhub.amazonaws.com | DisableSecurityHub |
AWS Shield | Managed DDoS protection service that safeguards applications. | shield.amazonaws.com | DeleteSubscription |
Amazon Macie | Uses machine learning to discover, classify, and protect sensitive data. | macie2.amazonaws.com | DisableMacie |
AWS Firewall Manager | Centrally configures and manages firewall rules across accounts and applications. | fms.amazonaws.com | DeletePolicy |
AWS IAM Access Analyzer | Helps identify resources that are shared with external entities. | access-analyzer.amazonaws.com | DeleteAnalyzer |
Amazon Inspector | Automated security assessment service to help improve the security and compliance of applications deployed on AWS. | inspector.amazonaws.com | DeleteAssessmentTarget |
AWS WAF | Web application firewall that helps protect web applications from common web exploits. | waf.amazonaws.com | DeleteWebACL |
I hope this blog gave you an idea how we can monitor security services in AWS. While preventive controls such as SCPs and IAM policies are crucial to protecting your AWS environment but sometimes they are not enough. A truly secure environment requires a layered approach, incorporating monitoring and detection mechanisms to ensure that no gaps are left uncovered.
Stay proactive, stay secure, and make the most of AWS’s powerful security monitoring capabilities.