Skip to main content

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​

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​

  1. In the AWS console, go to CloudTrail.
  2. In the left menu, select Trails.
  3. 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.
  4. 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”​

  1. Go to CloudWatch in the console.

  2. In the left menu, click Logs > Log groups.

  3. Click the log group used by CloudTrail (e.g., /aws/cloudtrail/management).

  4. Go to the Metric filters tab.

  5. Click Create metric filter.

  6. In Filter pattern, use:

    { ($.eventName = "ConsoleLogin") && ($.responseElements.ConsoleLogin = "Success") && ($.additionalEventData.MFAUsed = "No") }
  7. Click Next.

  8. Under Assign metric, configure:

    • Filter name: ConsoleLoginWithoutMFA
    • Metric namespace: Security/CloudTrail
    • Metric name: ConsoleLoginWithoutMFA
    • Metric value: 1
  9. 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​

  1. Still in CloudWatch, go to Alarms > All alarms.
  2. Click Create alarm.
  3. Click Select metric.
  4. Navigate to the metric you just created:
    • Custom namespaces > Security/CloudTrail > Metrics with no dimensions > ConsoleLoginWithoutMFA.
  5. Select the metric and click Next.
  6. Set the Statistic to Sum.
  7. Define the threshold, for example:
    • Period: 5 minutes
    • Threshold type: Static
    • Whenever Sum is >= 1
  8. Click Next.
  9. 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.
  10. Click Next, give the alarm a name (e.g., Alert-ConsoleLogin-Without-MFA), and optionally a description.
  11. 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​

  1. Have a test IAM user without MFA perform a console login.
  2. Wait a few minutes for CloudTrail → CloudWatch Logs → Metric → Alarm pipeline to process.
  3. 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:

  1. Ensure CloudTrail is enabled and delivering to a CloudWatch Logs group
  2. Create a metric filter in CloudWatch Logs to detect non‑MFA console logins
  3. 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:DescribeLogGroups
    • cloudwatch:PutMetricAlarm
    • cloudtrail: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​

  1. Confirm CloudTrail is sending logs to log_group_name.
  2. Run the Python script (with correct region, log group, and SNS topic).
  3. Test: perform a console login without MFA (from a test account) and confirm:
    • Metric SecurityMonitoring/ConsoleLoginsWithoutMFA increments
    • Alarm Alert-Console-Login-Without-MFA goes into ALARM state and sends a notification via SNS.
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.

Additional Reading:​