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: