<?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: noweder</title>
    <description>The latest articles on DEV Community by noweder (@noweder).</description>
    <link>https://dev.to/noweder</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%2F444682%2F74bf9461-d803-41f8-a974-e2a26de79ed9.png</url>
      <title>DEV Community: noweder</title>
      <link>https://dev.to/noweder</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/noweder"/>
    <language>en</language>
    <item>
      <title>Using AWS Lambda to Revert Unauthorized Security Group Changes</title>
      <dc:creator>noweder</dc:creator>
      <pubDate>Sun, 15 Jan 2023 21:04:03 +0000</pubDate>
      <link>https://dev.to/aws-builders/using-aws-lambda-to-revert-unauthorized-security-group-changes-5hke</link>
      <guid>https://dev.to/aws-builders/using-aws-lambda-to-revert-unauthorized-security-group-changes-5hke</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;In this blog, we will demonstrate how to proactively monitor a web server EC2 security group for any traffic rule changes using Lambda along with a few other services. If we detect &lt;em&gt;any&lt;/em&gt; unauthorized changes, we will then undo them using Lambda. There will also be an SNS notification sent out to the admins, which is us.&lt;/p&gt;

&lt;p&gt;In this activity we will be working with the following AWS services:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Lambda&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SNS&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CloudTrail&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CloudWatch&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CloudFormation&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;EC2&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;VPC&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;S3&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This scenario is a working example of how we can use Lambda to perform various operational tasks within our account, especially ones that maintain our security posture.&lt;/p&gt;

&lt;h1&gt;
  
  
  Architecture
&lt;/h1&gt;

&lt;p&gt;The below diagram illustrates the high-level architecture and the steps to be followed in sequence.&lt;/p&gt;

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

&lt;h1&gt;
  
  
  Prerequisites
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;An AWS account&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An existing VPC such as the default VPC&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Steps
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Create Your CloudTrail Trail
&lt;/h2&gt;

&lt;p&gt;Navigate to the &lt;code&gt;CloudTrail&lt;/code&gt; service. From the left-hand menu, access &lt;code&gt;Trails&lt;/code&gt; and click on &lt;code&gt;Create trail&lt;/code&gt;.&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Specify your desired name for the trail&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For &lt;code&gt;Storage location&lt;/code&gt; section, choose &lt;code&gt;New S3 bucket&lt;/code&gt; and keep the default generated name. This will create an S3 bucket to load API event trail logs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enable &lt;code&gt;CloudWatch Logs&lt;/code&gt; to create a log group to which the trail will send events.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Choose &lt;code&gt;Event type&lt;/code&gt; as &lt;code&gt;Management events&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Choose &lt;code&gt;API activity&lt;/code&gt; to log both &lt;code&gt;Read&lt;/code&gt; and &lt;code&gt;Write&lt;/code&gt; activities.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Leave other settings as is and finally click &lt;code&gt;Create trail&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Deploy the CloudFormation Template
&lt;/h2&gt;

&lt;p&gt;The CloudFormation template will create several resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A web security group that is monitored for any changes&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An IAM role attached to the Lambda function as an execution role with permissions to remove any changes to the security group inbound rules.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A Lambda Permission which allows CloudWatch Events to invoke the Lambda function&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A Lambda function that revokes any changes to the web security group and publishes a message to an SNS topic&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A CloudWatch Event Rule that captures security group change events and triggers the Lambda function (&lt;strong&gt;Note&lt;/strong&gt;: CloudWatch Events is now Amazon EventBridge)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SNS topic with an email subscription to send an email notification when the Lambda function is invoked&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Follow the below steps to deploy these resources:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Using your preferred code editor, create a &lt;code&gt;.yaml&lt;/code&gt; file with the below CloudFormation template.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;AWSTemplateFormatVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2010-09-09&lt;/span&gt;
&lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
  &lt;span class="s"&gt;Creates the resources necessary to create a rule to monitor and&lt;/span&gt;
  &lt;span class="s"&gt;auto-mitigate security group change events&lt;/span&gt;

&lt;span class="na"&gt;Metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;License&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.&lt;/span&gt;

      &lt;span class="s"&gt;Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with the License. A copy of the License is located at&lt;/span&gt;

          &lt;span class="s"&gt;http://aws.amazon.com/apache2.0/&lt;/span&gt;

      &lt;span class="s"&gt;or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.&lt;/span&gt;

  &lt;span class="na"&gt;AWS::CloudFormation::Interface&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;ParameterGroups&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Label&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Settings&lt;/span&gt;
        &lt;span class="na"&gt;Parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;NotificationEmailAddress&lt;/span&gt;

    &lt;span class="na"&gt;ParameterLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;NotificationEmailAddress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Send notifications to&lt;/span&gt;

&lt;span class="na"&gt;Parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

  &lt;span class="na"&gt;NotificationEmailAddress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;This is the email address that will receive change notifications. You will&lt;/span&gt;
      &lt;span class="s"&gt;receive a confirmation email that you must accept before you will receive&lt;/span&gt;
      &lt;span class="s"&gt;notifications.&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;

&lt;span class="na"&gt;Conditions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

  &lt;span class="na"&gt;AddEmailNotificationSubscription&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="kt"&gt;!Not&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;!Equals&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="nv"&gt;NotificationEmailAddress&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="pi"&gt;]]&lt;/span&gt;

&lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

  &lt;span class="na"&gt;WebServerSecurityGroup&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::EC2::SecurityGroup&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;GroupDescription&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow HTTPS access to web servers&lt;/span&gt;
      &lt;span class="na"&gt;SecurityGroupIngress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;IpProtocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tcp&lt;/span&gt;
        &lt;span class="na"&gt;FromPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;443&lt;/span&gt;
        &lt;span class="na"&gt;ToPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;443&lt;/span&gt;
        &lt;span class="na"&gt;CidrIp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.0.0/0&lt;/span&gt;
      &lt;span class="na"&gt;Tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Name&lt;/span&gt;
          &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Web Server Security Group&lt;/span&gt;

  &lt;span class="na"&gt;SecurityGroupChangeAutoResponseRole&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::IAM::Role&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;AssumeRolePolicyDocument&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2012-10-17&lt;/span&gt;
        &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt;
            &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
            &lt;span class="na"&gt;Principal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;Service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lambda.amazonaws.com&lt;/span&gt;
            &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sts:AssumeRole&lt;/span&gt;
      &lt;span class="na"&gt;ManagedPolicyArns&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole&lt;/span&gt;
      &lt;span class="na"&gt;Policies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt;
          &lt;span class="na"&gt;PolicyName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SecurityGroupModification&lt;/span&gt;
          &lt;span class="na"&gt;PolicyDocument&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;Version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2012-10-17&lt;/span&gt;
            &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt;
                &lt;span class="na"&gt;Sid&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AllowSecurityGroupActions&lt;/span&gt;
                &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
                &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ec2:RevokeSecurityGroupIngress&lt;/span&gt;
                &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Sub&lt;/span&gt; &lt;span class="s"&gt;arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:security-group/${WebServerSecurityGroup.GroupId}&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt;
                &lt;span class="na"&gt;Sid&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AllowSnsActions&lt;/span&gt;
                &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
                &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sns:Publish&lt;/span&gt;
                &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;SnsTopicForCloudWatchEvent&lt;/span&gt;

  &lt;span class="na"&gt;SecurityGroupChangeAutoResponse&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Lambda::Function&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Responds to security group changes&lt;/span&gt;
      &lt;span class="na"&gt;Handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;index.lambda_handler&lt;/span&gt;
      &lt;span class="na"&gt;MemorySize&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1024&lt;/span&gt;
      &lt;span class="na"&gt;Role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="s"&gt;SecurityGroupChangeAutoResponseRole.Arn&lt;/span&gt;
      &lt;span class="na"&gt;Runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python3.9&lt;/span&gt;
      &lt;span class="na"&gt;Timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;60&lt;/span&gt;
      &lt;span class="na"&gt;Environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;security_group_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="s"&gt;WebServerSecurityGroup.GroupId&lt;/span&gt;
          &lt;span class="na"&gt;sns_topic_arn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;SnsTopicForCloudWatchEvent&lt;/span&gt;
      &lt;span class="na"&gt;Code&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;ZipFile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;import os, json, boto3&lt;/span&gt;

          &lt;span class="s"&gt;#===============================================================================&lt;/span&gt;
          &lt;span class="s"&gt;def lambda_handler(event, context):&lt;/span&gt;

              &lt;span class="s"&gt;print(event)&lt;/span&gt;

              &lt;span class="s"&gt;# Ensure that we have an event name to evaluate.&lt;/span&gt;
              &lt;span class="s"&gt;if 'detail' not in event or ('detail' in event and 'eventName' not in event['detail']):&lt;/span&gt;
                  &lt;span class="s"&gt;return {"Result": "Failure", "Message": "Lambda not triggered by an event"}&lt;/span&gt;

              &lt;span class="s"&gt;# Remove the rule only if the event was to authorize the ingress rule for the given&lt;/span&gt;
              &lt;span class="s"&gt;# security group that was injected during CloudFormation execution.&lt;/span&gt;
              &lt;span class="s"&gt;if (event['detail']['eventName'] == 'AuthorizeSecurityGroupIngress' and&lt;/span&gt;
                  &lt;span class="s"&gt;event['detail']['requestParameters']['groupId'] == os.environ['security_group_id']):&lt;/span&gt;
                  &lt;span class="s"&gt;result = revoke_security_group_ingress(event['detail'])&lt;/span&gt;

                  &lt;span class="s"&gt;message = "AUTO-MITIGATED: Ingress rule removed from security group: {} that was added by {}: {}".format(&lt;/span&gt;
                          &lt;span class="s"&gt;result['group_id'],&lt;/span&gt;
                          &lt;span class="s"&gt;result['user_name'],&lt;/span&gt;
                          &lt;span class="s"&gt;json.dumps(result['ip_permissions'])&lt;/span&gt;
                          &lt;span class="s"&gt;)&lt;/span&gt;

                  &lt;span class="s"&gt;boto3.client('sns').publish(&lt;/span&gt;
                    &lt;span class="s"&gt;TargetArn = os.environ['sns_topic_arn'],&lt;/span&gt;
                    &lt;span class="s"&gt;Message = message,&lt;/span&gt;
                    &lt;span class="s"&gt;Subject = "Auto-mitigation successful"&lt;/span&gt;
                    &lt;span class="s"&gt;)&lt;/span&gt;


          &lt;span class="s"&gt;#===============================================================================&lt;/span&gt;
          &lt;span class="s"&gt;def revoke_security_group_ingress(event_detail):&lt;/span&gt;

              &lt;span class="s"&gt;request_parameters = event_detail['requestParameters']&lt;/span&gt;

              &lt;span class="s"&gt;# Build the normalized IP permission JSON struture.&lt;/span&gt;
              &lt;span class="s"&gt;ip_permissions = normalize_paramter_names(request_parameters['ipPermissions']['items'])&lt;/span&gt;

              &lt;span class="s"&gt;response = boto3.client('ec2').revoke_security_group_ingress(&lt;/span&gt;
                  &lt;span class="s"&gt;GroupId = request_parameters['groupId'],&lt;/span&gt;
                  &lt;span class="s"&gt;IpPermissions = ip_permissions&lt;/span&gt;
                  &lt;span class="s"&gt;)&lt;/span&gt;

              &lt;span class="s"&gt;# Build the result&lt;/span&gt;
              &lt;span class="s"&gt;result = {}&lt;/span&gt;
              &lt;span class="s"&gt;result['group_id'] = request_parameters['groupId']&lt;/span&gt;
              &lt;span class="s"&gt;result['user_name'] = event_detail['userIdentity']['arn']&lt;/span&gt;
              &lt;span class="s"&gt;result['ip_permissions'] = ip_permissions&lt;/span&gt;

              &lt;span class="s"&gt;return result&lt;/span&gt;


          &lt;span class="s"&gt;#===============================================================================&lt;/span&gt;
          &lt;span class="s"&gt;def normalize_paramter_names(ip_items):&lt;/span&gt;

              &lt;span class="s"&gt;# Start building the permissions items list.&lt;/span&gt;
              &lt;span class="s"&gt;new_ip_items = []&lt;/span&gt;

              &lt;span class="s"&gt;# First, build the basic parameter list.&lt;/span&gt;
              &lt;span class="s"&gt;for ip_item in ip_items:&lt;/span&gt;

                  &lt;span class="s"&gt;new_ip_item = {&lt;/span&gt;
                      &lt;span class="s"&gt;"IpProtocol": ip_item['ipProtocol'],&lt;/span&gt;
                      &lt;span class="s"&gt;"FromPort": ip_item['fromPort'],&lt;/span&gt;
                      &lt;span class="s"&gt;"ToPort": ip_item['toPort']&lt;/span&gt;
                  &lt;span class="s"&gt;}&lt;/span&gt;

                  &lt;span class="s"&gt;#CidrIp or CidrIpv6 (IPv4 or IPv6)?&lt;/span&gt;
                  &lt;span class="s"&gt;if 'ipv6Ranges' in ip_item and ip_item['ipv6Ranges']:&lt;/span&gt;
                      &lt;span class="s"&gt;# This is an IPv6 permission range, so change the key names.&lt;/span&gt;
                      &lt;span class="s"&gt;ipv_range_list_name = 'ipv6Ranges'&lt;/span&gt;
                      &lt;span class="s"&gt;ipv_address_value = 'cidrIpv6'&lt;/span&gt;
                      &lt;span class="s"&gt;ipv_range_list_name_capitalized = 'Ipv6Ranges'&lt;/span&gt;
                      &lt;span class="s"&gt;ipv_address_value_capitalized = 'CidrIpv6'&lt;/span&gt;
                  &lt;span class="s"&gt;else:&lt;/span&gt;
                      &lt;span class="s"&gt;ipv_range_list_name = 'ipRanges'&lt;/span&gt;
                      &lt;span class="s"&gt;ipv_address_value = 'cidrIp'&lt;/span&gt;
                      &lt;span class="s"&gt;ipv_range_list_name_capitalized = 'IpRanges'&lt;/span&gt;
                      &lt;span class="s"&gt;ipv_address_value_capitalized = 'CidrIp'&lt;/span&gt;

                  &lt;span class="s"&gt;ip_ranges = []&lt;/span&gt;

                  &lt;span class="s"&gt;# Next, build the IP permission list.&lt;/span&gt;
                  &lt;span class="s"&gt;for item in ip_item[ipv_range_list_name]['items']:&lt;/span&gt;
                      &lt;span class="s"&gt;ip_ranges.append(&lt;/span&gt;
                          &lt;span class="s"&gt;{ipv_address_value_capitalized : item[ipv_address_value]}&lt;/span&gt;
                          &lt;span class="s"&gt;)&lt;/span&gt;

                  &lt;span class="s"&gt;new_ip_item[ipv_range_list_name_capitalized] = ip_ranges&lt;/span&gt;

                  &lt;span class="s"&gt;new_ip_items.append(new_ip_item)&lt;/span&gt;

              &lt;span class="s"&gt;return new_ip_items&lt;/span&gt;

  &lt;span class="na"&gt;SecurityGroupChangeAutoResponseLambdaPermission&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Lambda::Permission&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lambda:InvokeFunction&lt;/span&gt;
      &lt;span class="na"&gt;Principal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;events.amazonaws.com&lt;/span&gt;
      &lt;span class="na"&gt;FunctionName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;SecurityGroupChangeAutoResponse&lt;/span&gt;

  &lt;span class="na"&gt;TriggeredRuleForSecurityGroupChangeAutoResponse&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Events::Rule&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;#Name: SecurityGroupChangeAutoResponse&lt;/span&gt;
      &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Responds to security group change events&lt;/span&gt;
      &lt;span class="na"&gt;EventPattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;detail&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;eventSource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ec2.amazonaws.com&lt;/span&gt;
          &lt;span class="na"&gt;eventName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;AuthorizeSecurityGroupIngress&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;AuthorizeSecurityGroupEgress&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;RevokeSecurityGroupEgress&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;RevokeSecurityGroupIngress&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;CreateSecurityGroup&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DeleteSecurityGroup&lt;/span&gt;
      &lt;span class="na"&gt;State&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ENABLED&lt;/span&gt;
      &lt;span class="na"&gt;Targets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt;
          &lt;span class="na"&gt;Arn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="s"&gt;SecurityGroupChangeAutoResponse.Arn&lt;/span&gt;
          &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TargetFunctionV1&lt;/span&gt;

  &lt;span class="na"&gt;SnsTopicForCloudWatchEvent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::SNS::Topic&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;DisplayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Broadcasts message to subscribers&lt;/span&gt;

  &lt;span class="na"&gt;SnsTopicSubscriptionForCloudWatchEvent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::SNS::Subscription&lt;/span&gt;
    &lt;span class="na"&gt;Condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AddEmailNotificationSubscription&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;TopicArn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;SnsTopicForCloudWatchEvent&lt;/span&gt;
      &lt;span class="na"&gt;Endpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;NotificationEmailAddress&lt;/span&gt;
      &lt;span class="na"&gt;Protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;email&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Navigate to &lt;code&gt;CloudFormation&lt;/code&gt; service and click on &lt;code&gt;Create stack&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click on &lt;code&gt;Upload a template file&lt;/code&gt; from the &lt;code&gt;Specify template&lt;/code&gt; section and choose the locally created &lt;code&gt;.yaml&lt;/code&gt; file, then click &lt;code&gt;Next&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Specify your desired name of the stack.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enter your email address in the &lt;code&gt;Parameters&lt;/code&gt; section under &lt;code&gt;Send notifications to&lt;/code&gt; parameter.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

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

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Leave everything else as is and click on &lt;code&gt;Submit&lt;/code&gt; at the end.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Once the stack status changes to &lt;code&gt;CREATE_COMPLETE&lt;/code&gt;, you should receive an email from AWS to confirm the subscription to the SNS topic. Click on &lt;code&gt;Confirm subscription&lt;/code&gt; link within the email bod&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Test and Verify The Solution
&lt;/h2&gt;

&lt;p&gt;Head to &lt;code&gt;EC2&lt;/code&gt; in the console and access &lt;code&gt;Security Groups&lt;/code&gt; under &lt;code&gt;Network &amp;amp; Security&lt;/code&gt;. Select the created &lt;code&gt;Web Server Security Group&lt;/code&gt; and click on &lt;code&gt;Edit inbound rules&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Click on &lt;code&gt;Add rule&lt;/code&gt;. Select &lt;code&gt;SSH&lt;/code&gt; as Type and &lt;code&gt;Anywhere-IPv4&lt;/code&gt; as the Source. Then click on &lt;code&gt;Save rules&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;Once this change is done, CloudTrail will catch this event and send it to CloudWatch, which will trigger the deployed event rule and pass the data to the Lambda function. The function will parse that data and do two things; it will remove the rule we added, and also publish to the SNS topic which will send an email to the defined email address.&lt;/p&gt;

&lt;p&gt;Refresh the inbound rules and you will notice the newly added rule has been immediately removed!&lt;/p&gt;

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

&lt;p&gt;You will also receive a notification email mentioning that the added ingress rule has been removed as shown below.&lt;/p&gt;

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

&lt;p&gt;We can also view the metrics of the successful lambda function invocation from the &lt;code&gt;Monitor&lt;/code&gt; menu of the function as shown below.&lt;/p&gt;

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

&lt;p&gt;Until next time...&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>watercooler</category>
    </item>
  </channel>
</rss>
