<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Montaigu</title>
    <description>The latest articles on DEV Community by Montaigu (@montaigu).</description>
    <link>https://dev.to/montaigu</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1348968%2F3e8a414e-eeb8-4dfb-81b1-1267429b1b15.png</url>
      <title>DEV Community: Montaigu</title>
      <link>https://dev.to/montaigu</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/montaigu"/>
    <language>en</language>
    <item>
      <title>How to monitor all AWS Console logins and failed attempts with CloudTrail and CloudWatch - Terraform automation</title>
      <dc:creator>Montaigu</dc:creator>
      <pubDate>Wed, 29 May 2024 20:54:53 +0000</pubDate>
      <link>https://dev.to/montaigu/how-to-monitor-all-aws-console-logins-and-failed-attempts-with-cloudtrail-and-cloudwatch-terraform-automation-2pi1</link>
      <guid>https://dev.to/montaigu/how-to-monitor-all-aws-console-logins-and-failed-attempts-with-cloudtrail-and-cloudwatch-terraform-automation-2pi1</guid>
      <description>&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;I suggest to open the CloudTrail in eu-east-1 to also monitor all console login events. &lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzbwaok5ebka94z4lan3w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzbwaok5ebka94z4lan3w.png" alt="Image description" width="800" height="609"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And the event history will look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwy16h0squl17ekw3zto1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwy16h0squl17ekw3zto1.png" alt="Image description" width="800" height="157"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When all is set you need to go to the CloudWatch group to see if there are some streams:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F80zatto5oxelvnm1y0ao.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F80zatto5oxelvnm1y0ao.png" alt="Image description" width="800" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And need to create two metrics in this group:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsgb4ls3kk24s0zelk7vh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsgb4ls3kk24s0zelk7vh.png" alt="Image description" width="800" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One which will be for all ConsoleLogin events with a filter on: { $.eventName = "ConsoleLogin" }&lt;/p&gt;

&lt;p&gt;And the other on failed console login attempts: { ($.eventName = "ConsoleLogin") &amp;amp;&amp;amp; ($.errorMessage = "Failed authentication") }&lt;/p&gt;

&lt;p&gt;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:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo7eg96ifr8kgfyiw7h0s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo7eg96ifr8kgfyiw7h0s.png" alt="Image description" width="800" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Afterwards you can set some alarms. For All logins:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffvnaf6vh9jysdwzmirhk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffvnaf6vh9jysdwzmirhk.png" alt="Image description" width="800" height="606"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And for failed ones:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu9rqnxt8fdmweoyj2m0h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu9rqnxt8fdmweoyj2m0h.png" alt="Image description" width="800" height="606"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And both to send emails or sms through and SNS topic.&lt;/p&gt;

&lt;p&gt;Some Terraform code to automate a bit the entire process:&lt;br&gt;
The cloudtrail logic and the role link:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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"
        }
      }
    ]
  })
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The filter on metrics for logins:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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\") &amp;amp;&amp;amp; ($.errorMessage = \"Failed authentication\") }"
  log_group_name = aws_cloudwatch_log_group.cloudtrail_log_group.name
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the alarms linked to the metrics:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>aws</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
