AWS Console Sign In Without MFA Should Be Monitored
More Info:
AWS Console Sign-In Requests Without MFA should be monitored using CloudWatch Events.
Risk Level
Medium
Address
Security
Compliance Standards
- APRA CPS 234 (Australia)
- BSI C5 (Germany)
- Brazil LGPD
- CCPA / CPRA (California)
- CIS AWS
- CIS Critical Security Controls v8
- CMMC 2.0
- CSA Cloud Controls Matrix v4
- Cloudanix Best Practice
- DPDPA
- Digital Operational Resilience Act (EU)
- Essential 8
- HIPAA
- HITRUST CSF
- ISO 27001
- ISO/IEC 27017
- ISO/IEC 27018
- ISO/IEC 27701
- KSA PDPL
- MAS Technology Risk Management (Singapore)
- MITRE ATT&CK (Cloud)
- NIS2 Directive
- NIST CSF
- NIST SP 800-171
- NYDFS 23 NYCRR 500
- PCI
- SOC2
- SWIFT Customer Security Controls Framework
- Sarbanes-Oxley IT General Controls
- Securities and Exchange Board of India (SEBI) - Cloud Security Adoption Framework
- UK NCSC Cyber Assessment Framework
Triage and Remediation
- Remediation
Remediation
Using Console
Below are the exact steps to monitor “AWS Console sign-in without MFA” using CloudWatch via the AWS Management Console.
1. Make sure CloudTrail is enabled and sending logs to CloudWatch Logs
- In the AWS console, go to CloudTrail.
- In the left menu, select Trails.
- If you don’t have a trail:
- Click Create trail.
- Name it (e.g.,
org-trail). - Under Storage location, choose/create an S3 bucket.
- Under CloudWatch Logs, check Enabled.
- Choose/Create a Log group (e.g.,
/aws/cloudtrail/management). - Choose/Create an IAM role for CloudWatch Logs.
- Turn on Management events (Read + Write).
- Click Create trail.
- If you already have a trail:
- Click your trail name.
- Under CloudWatch Logs, click Edit.
- Enable CloudWatch Logs and select/create a log group.
- Save.
You now have CloudTrail events (including ConsoleLogin) going into a CloudWatch Logs log group.
2. Create a Metric Filter for “Console sign-in without MFA”
-
Go to CloudWatch in the console.
-
In the left menu, click Logs > Log groups.
-
Click the log group used by CloudTrail (e.g.,
/aws/cloudtrail/management). -
Go to the Metric filters tab.
-
Click Create metric filter.
-
In Filter pattern, use:
{ ($.eventName = "ConsoleLogin") && ($.responseElements.ConsoleLogin = "Success") && ($.additionalEventData.MFAUsed = "No") } -
Click Next.
-
Under Assign metric, configure:
- Filter name:
ConsoleLoginWithoutMFA - Metric namespace:
Security/CloudTrail - Metric name:
ConsoleLoginWithoutMFA - Metric value:
1
- Filter name:
-
Click Next, then Create metric filter.
This creates a metric that increments when there is a successful console login without MFA.
3. Create a CloudWatch Alarm on that metric
- Still in CloudWatch, go to Alarms > All alarms.
- Click Create alarm.
- Click Select metric.
- Navigate to the metric you just created:
- Custom namespaces >
Security/CloudTrail>Metrics with no dimensions>ConsoleLoginWithoutMFA.
- Custom namespaces >
- Select the metric and click Next.
- Set the Statistic to
Sum. - Define the threshold, for example:
- Period:
5 minutes - Threshold type:
Static - Whenever Sum is >= 1
- Period:
- Click Next.
- Under Notification, choose or create an SNS topic:
- E.g., Create new topic → name
security-alerts→ add email addresses. - Confirm the subscription via the email you receive.
- E.g., Create new topic → name
- Click Next, give the alarm a name (e.g.,
Alert-ConsoleLogin-Without-MFA), and optionally a description. - Click Create alarm.
You now have monitoring in place: any successful AWS Console login without MFA will generate a CloudTrail event, match the metric filter, increment the metric, and trigger a CloudWatch alarm that notifies you via SNS.
Using CLI
Below are step‑by‑step AWS CLI instructions to monitor AWS console sign‑ins without MFA using CloudWatch, based on CloudTrail logs.
Assumptions:
- You already have a CloudTrail trail delivering events to a CloudWatch Logs log group (replace names as needed).
- Region:
us-east-1(change where appropriate).
1. Identify your CloudTrail log group
If you don’t know it, list log groups and look for the one used by CloudTrail:
aws logs describe-log-groups \
--log-group-name-prefix "/aws/cloudtrail" \
--region us-east-1
Assume it is:
/aws/cloudtrail/logs
2. Create a CloudWatch Logs metric filter
This filter finds ConsoleLogin events where:
responseElements.ConsoleLogin = "Success"additionalEventData.MFAUsed = "No"
Create the metric filter:
aws logs put-metric-filter \
--log-group-name "/aws/cloudtrail/logs" \
--filter-name "ConsoleSignInWithoutMFA" \
--filter-pattern '{ ($.eventName = "ConsoleLogin") && ($.responseElements.ConsoleLogin = "Success") && ($.additionalEventData.MFAUsed = "No") }' \
--metric-transformations \
metricName="ConsoleSignInWithoutMFA",metricNamespace="CloudTrailMetrics",metricValue="1" \
--region us-east-1
Verify it:
aws logs describe-metric-filters \
--log-group-name "/aws/cloudtrail/logs" \
--region us-east-1
3. Create an SNS topic for alerts (optional but typical)
aws sns create-topic \
--name "ConsoleSignInWithoutMFA-Alerts" \
--region us-east-1
Capture the returned TopicArn, e.g.:
arn:aws:sns:us-east-1:111122223333:ConsoleSignInWithoutMFA-Alerts
Subscribe an email endpoint:
aws sns subscribe \
--topic-arn arn:aws:sns:us-east-1:111122223333:ConsoleSignInWithoutMFA-Alerts \
--protocol email \
--notification-endpoint your-email@example.com \
--region us-east-1
Confirm the subscription from your email inbox.
4. Create a CloudWatch alarm on the metric
This example alarms if at least 1 such event occurs in a 5‑minute period:
aws cloudwatch put-metric-alarm \
--alarm-name "ConsoleSignInWithoutMFA-Alarm" \
--alarm-description "Alarm when an AWS Console sign-in occurs without MFA" \
--metric-name "ConsoleSignInWithoutMFA" \
--namespace "CloudTrailMetrics" \
--statistic Sum \
--period 300 \
--evaluation-periods 1 \
--threshold 1 \
--comparison-operator GreaterThanOrEqualToThreshold \
--treat-missing-data notBreaching \
--alarm-actions arn:aws:sns:us-east-1:111122223333:ConsoleSignInWithoutMFA-Alerts \
--region us-east-1
5. Test
- Have a test IAM user without MFA perform a console login.
- Wait a few minutes for CloudTrail → CloudWatch Logs → Metric → Alarm pipeline to process.
- Check the alarm status and SNS email.
aws cloudwatch describe-alarms \
--alarm-names "ConsoleSignInWithoutMFA-Alarm" \
--region us-east-1
This fully implements “AWS Console Sign In Without MFA Should Be Monitored” using CloudWatch and AWS CLI.
Using Python
To monitor AWS console sign-ins without MFA using CloudWatch + Python (boto3), you need to:
- Ensure CloudTrail is enabled and delivering to a CloudWatch Logs group
- Create a metric filter in CloudWatch Logs to detect non‑MFA console logins
- Create a CloudWatch alarm on that metric
Below are the steps and example Python code.
1. Prerequisites
- AWS CloudTrail enabled (at least one trail, logging Management events)
- Trail configured to send logs to a CloudWatch Logs log group (e.g.,
/aws/cloudtrail/management) - An IAM role/user with permissions for:
logs:PutMetricFilter,logs:DescribeLogGroupscloudwatch:PutMetricAlarmcloudtrail:DescribeTrails
2. Metric Filter Pattern for Console Sign‑In Without MFA
The relevant CloudTrail event is ConsoleLogin in signin.amazonaws.com.
Non-MFA console logins typically have "additionalEventData": {"MFAUsed":"No"} or just "MFAUsed":"No".
Use a filter pattern like:
{ ($.eventName = "ConsoleLogin") && ($.eventSource = "signin.amazonaws.com") && ($.additionalEventData.MFAUsed = "No") && ($.responseElements.ConsoleLogin = "Success") }
Adjust for your environment if you also want to include failed logins.
3. Python Script (boto3) to Create Metric Filter + Alarm
import boto3
import sys
region = "us-east-1" # change to your region
log_group_name = "/aws/cloudtrail/management" # change to your CloudTrail log group
metric_namespace = "SecurityMonitoring"
metric_name = "ConsoleLoginsWithoutMFA"
alarm_name = "Alert-Console-Login-Without-MFA"
alarm_topic_arn = "arn:aws:sns:us-east-1:123456789012:SecurityAlerts" # change to your SNS topic ARN
logs_client = boto3.client("logs", region_name=region)
cw_client = boto3.client("cloudwatch", region_name=region)
def create_metric_filter():
filter_pattern = '{ ($.eventName = "ConsoleLogin") && ($.eventSource = "signin.amazonaws.com") && ($.additionalEventData.MFAUsed = "No") && ($.responseElements.ConsoleLogin = "Success") }'
print(f"Creating/updating metric filter on log group: {log_group_name}")
logs_client.put_metric_filter(
logGroupName=log_group_name,
filterName="ConsoleLoginWithoutMFAFilter",
filterPattern=filter_pattern,
metricTransformations=[
{
"metricName": metric_name,
"metricNamespace": metric_namespace,
"metricValue": "1",
"defaultValue": 0.0
}
]
)
def create_alarm():
print(f"Creating/updating CloudWatch alarm: {alarm_name}")
cw_client.put_metric_alarm(
AlarmName=alarm_name,
AlarmDescription="Triggers when there is at least one AWS console login without MFA.",
Namespace=metric_namespace,
MetricName=metric_name,
Statistic="Sum",
Period=300, # 5 minutes
EvaluationPeriods=1,
Threshold=1,
ComparisonOperator="GreaterThanOrEqualToThreshold",
TreatMissingData="notBreaching",
AlarmActions=[alarm_topic_arn],
OKActions=[alarm_topic_arn],
Unit="Count"
)
if __name__ == "__main__":
try:
create_metric_filter()
create_alarm()
print("Metric filter and alarm configured successfully.")
except Exception as e:
print(f"Error: {e}")
sys.exit(1)
4. High-Level Remediation Steps
- Confirm CloudTrail is sending logs to
log_group_name. - Run the Python script (with correct region, log group, and SNS topic).
- Test: perform a console login without MFA (from a test account) and confirm:
- Metric
SecurityMonitoring/ConsoleLoginsWithoutMFAincrements - Alarm
Alert-Console-Login-Without-MFAgoes intoALARMstate and sends a notification via SNS.
- Metric
Using Terraform
resource "aws_sns_topic" "console_signin_without_mfa_alerts" {
name = "ConsoleSignInWithoutMFA-Alerts"
}
resource "aws_cloudwatch_event_rule" "detect_console_signin_without_mfa" {
name = "DetectConsoleSignInWithoutMFA"
description = "Detects AWS console sign-ins performed without using MFA"
event_pattern = jsonencode({
source = ["aws.signin"]
"detail-type" = ["AWS Console Sign In via CloudTrail"]
detail = {
eventName = ["ConsoleLogin"]
additionalEventData = {
MFAUsed = ["No"]
}
}
})
}
resource "aws_cloudwatch_event_target" "console_signin_without_mfa_to_sns" {
rule = aws_cloudwatch_event_rule.detect_console_signin_without_mfa.name
target_id = "ConsoleSignInWithoutMFA-Target"
arn = aws_sns_topic.console_signin_without_mfa_alerts.arn
}
resource "aws_sns_topic_subscription" "console_signin_without_mfa_email" {
topic_arn = aws_sns_topic.console_signin_without_mfa_alerts.arn
protocol = "email"
endpoint = "ALERT_EMAIL_ADDRESS@example.com" # replace with the email to receive alerts
}
This adds new resources only; existing resources are not replaced. You still need an active CloudTrail trail in this region logging management events for the rule to match events.
Verification: terraform plan should show one aws_sns_topic, one aws_cloudwatch_event_rule, one aws_cloudwatch_event_target, and one aws_sns_topic_subscription to be created.