How to monitor all AWS Console logins and failed attempts with CloudTrail and CloudWatch – Terraform automation

How to monitor all AWS Console logins and failed attempts with CloudTrail and CloudWatch – Terraform automation

You never know when a bad guy wants to send birthdays alerts with Lambda.. just joking 😀 He probably will want to use your AWS account for his purposes and you’ll end up with xxxx bill at the end of the month.

In the following article it will be explained how to monitor all the AWS Console login events and also the monitoring of the failed attempts.

I suggest to open the CloudTrail in eu-east-1 to also monitor all console login events.

You need to create a trail which sends the logs into S3 just optional, and very important in this case to send them to a CloudWatch group.

And the event history will look like this:

When all is set you need to go to the CloudWatch group to see if there are some streams:

And need to create two metrics in this group:

One which will be for all ConsoleLogin events with a filter on: { $.eventName = “ConsoleLogin” }

And the other on failed console login attempts: { ($.eventName = “ConsoleLogin”) && ($.errorMessage = “Failed authentication”) }

If everything goes well just do some console logins as a test, also fail some of those. The result in these two metrics should be:

Afterwards you can set some alarms. For All logins:

And for failed ones:

And both to send emails or sms through and SNS topic.

Some Terraform code to automate a bit the entire process:
The cloudtrail logic and the role link:

provider “aws” {
region = “us-west-1”
}

resource “aws_sns_topic” “cloudtrail_alerts” {
name = “cloudtrail-alerts”
}

resource “aws_cloudwatch_log_group” “cloudtrail_log_group” {
name = “cloudtrail-log-group”
}

resource “aws_cloudtrail” “main” {
name = “cloudtrail-example”
s3_bucket_name = aws_s3_bucket.cloudtrail_bucket.bucket
cloud_watch_logs_group_arn = aws_cloudwatch_log_group.cloudtrail_log_group.arn
cloud_watch_logs_role_arn = aws_iam_role.cloud_watch_logs_role.arn
enable_logging = true
}

resource “aws_s3_bucket” “cloudtrail_bucket” {
bucket = “my-cloudtrail-bucket”
}

resource “aws_iam_role” “cloud_watch_logs_role” {
name = “CloudWatchLogsRole”

assume_role_policy = jsonencode({
Version = “2012-10-17”
Statement = [
{
Action = “sts:AssumeRole”
Effect = “Allow”
Principal = {
Service = “cloudtrail.amazonaws.com”
}
}
]
})
}

The filter on metrics for logins:

resource “aws_cloudwatch_metric_filter” “console_login” {
name = “ConsoleLogin”
pattern = “{ $.eventName = “ConsoleLogin” }”
log_group_name = aws_cloudwatch_log_group.cloudtrail_log_group.name
}

resource “aws_cloudwatch_metric_filter” “failed_console_login” {
name = “FailedConsoleLogin”
pattern = “{ ($.eventName = “ConsoleLogin”) && ($.errorMessage = “Failed authentication”) }”
log_group_name = aws_cloudwatch_log_group.cloudtrail_log_group.name
}

And the alarms linked to the metrics:

resource “aws_cloudwatch_metric_alarm” “console_login_alarm” {
alarm_name = “ConsoleLoginAlarm”
comparison_operator = “GreaterThanOrEqualToThreshold”
evaluation_periods = “1”
metric_name = “ConsoleLogin”
namespace = “CloudTrailMetrics”
period = “300”
statistic = “SampleCount”
threshold = “5”
alarm_description = “This metric checks for console logins”
alarm_actions = [aws_sns_topic.cloudtrail_alerts.arn]
}

resource “aws_cloudwatch_metric_alarm” “failed_console_login_alarm” {
alarm_name = “FailedConsoleLoginAlarm”
comparison_operator = “GreaterThanOrEqualToThreshold”
evaluation_periods = “1”
metric_name = “FailedConsoleLogin”
namespace = “CloudTrailMetrics”
period = “300”
statistic = “SampleCount”
threshold = “5”
alarm_description = “This metric checks for failed console logins”
alarm_actions = [aws_sns_topic.cloudtrail_alerts.arn]
}