How to monitor all AWS Console logins and failed attempts with CloudTrail and CloudWatch - Terraform automation
Tags: aws, devops
Published: 2024-05-29 20:54:53

You never know when a bad guy wants to send birthdays alerts with Lambda.. just joking :D 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.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zbwaok5ebka94z4lan3w.png)

And the event history will look like this:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wy16h0squl17ekw3zto1.png)

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

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/80zatto5oxelvnm1y0ao.png)

And need to create two metrics in this group:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sgb4ls3kk24s0zelk7vh.png)

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:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o7eg96ifr8kgfyiw7h0s.png)

Afterwards you can set some alarms. For All logins:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fvnaf6vh9jysdwzmirhk.png)

And for failed ones:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u9rqnxt8fdmweoyj2m0h.png)

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]
}
```