By Implementation

Service Control PoliciesConfig RulesAuto Remediation RulesConformance PacksAmazon GuardDutyAmazon InspectorAWS Security HubAWS Network FirewallRoute53 Resolver SecurityAmazon MacieS3 Bucket PoliciesCloudWatch Alarms and Event RulesAWS WAFAWS Secrets ManagerAWS Systems ManagerSecurity Groups & NACLsAWS KMSIAM Policies

By Service Protected

Configuration Packages

Strategy Guides

Other

Security Monitoring and Compliance

EC2 Events and Compliance Rules

A configuration package to monitor EC2 related API activity as well as configuration compliance rules to ensure the security of Amazon EC2 configuration. The package includes:

Items
22
Size
17.6 KB
AWSTemplateFormatVersion: "2010-09-09"
Description: ""
Resources:
  S3SharedBucket:
    Type: "AWS::S3::Bucket"
    Properties:
      LoggingConfiguration: {}
      AccessControl: "LogDeliveryWrite"
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: "AES256"
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
  BucketPolicy:
    Type: "AWS::S3::BucketPolicy"
    Properties:
      Bucket:
        Ref: "S3SharedBucket"
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Principal:
              Service:
                - "cloudtrail.amazonaws.com"
                - "config.amazonaws.com"
            Action:
              - "s3:GetBucketAcl"
            Resource:
              - Fn::GetAtt:
                  - "S3SharedBucket"
                  - "Arn"
            Effect: "Allow"
            Condition: {}
          - Principal:
              Service:
                - "cloudtrail.amazonaws.com"
                - "config.amazonaws.com"
            Action:
              - "s3:PutObject"
            Resource:
              - Fn::Join:
                  - ""
                  -
                    - ""
                    - Fn::GetAtt:
                        - "S3SharedBucket"
                        - "Arn"
                    - "/*"
            Effect: "Allow"
            Condition:
              StringEquals:
                s3:x-amz-acl: "bucket-owner-full-control"
    DependsOn: "S3SharedBucket"
  CloudTrail:
    Type: "AWS::CloudTrail::Trail"
    Properties:
      TrailName: "ManagementEventsTrail"
      IsLogging: true
      EnableLogFileValidation: true
      EventSelectors:
        - IncludeManagementEvents: true
          ReadWriteType: "All"
      IsMultiRegionTrail: true
      IncludeGlobalServiceEvents: true
      S3BucketName:
        Ref: "S3SharedBucket"
      CloudWatchLogsLogGroupArn:
        Fn::GetAtt:
          - "CWLogGroupForCloudTrail"
          - "Arn"
      CloudWatchLogsRoleArn:
        Fn::GetAtt:
          - "IamRoleForCwLogsCloudTrail"
          - "Arn"
    DependsOn:
      - "BucketPolicy"
  IamRoleForCwLogsCloudTrail:
    Type: "AWS::IAM::Role"
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Sid: ""
            Effect: "Allow"
            Principal:
              Service: "cloudtrail.amazonaws.com"
            Action: "sts:AssumeRole"
      Policies:
        - PolicyName: "allow-access-to-cw-logs"
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: "Allow"
                Action:
                  - "logs:CreateLogStream"
                  - "logs:PutLogEvents"
                Resource: "*"
  CWLogGroupForCloudTrail:
    Type: "AWS::Logs::LogGroup"
    Properties:
      LogGroupName: "CloudTrailLogs"
      RetentionInDays: 90
  ConfigurationRecorder:
    Type: "AWS::Config::ConfigurationRecorder"
    Properties:
      RoleARN:
        Fn::GetAtt:
          - "IamRoleForAwsConfig"
          - "Arn"
      RecordingGroup:
        AllSupported: true
        IncludeGlobalResourceTypes: true
  DeliveryChannel:
    Type: "AWS::Config::DeliveryChannel"
    Properties:
      S3BucketName:
        Ref: "S3SharedBucket"
  IamRoleForAwsConfig:
    Type: "AWS::IAM::Role"
    Properties:
      ManagedPolicyArns:
        - "arn:aws:iam::aws:policy/service-role/AWSConfigRole"
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Sid: ""
            Effect: "Allow"
            Principal:
              Service: "config.amazonaws.com"
            Action: "sts:AssumeRole"
      Policies:
        - PolicyName: "allow-access-to-config-s3-bucket"
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: "Allow"
                Action:
                  - "s3:PutObject"
                Resource:
                  - Fn::Join:
                      - ""
                      -
                        - Fn::GetAtt:
                            - "S3SharedBucket"
                            - "Arn"
                        - "/*"
                Condition:
                  StringLike:
                    s3:x-amz-acl: "bucket-owner-full-control"
              - Effect: "Allow"
                Action:
                  - "s3:GetBucketAcl"
                Resource:
                  Fn::GetAtt:
                    - "S3SharedBucket"
                    - "Arn"
      RoleName: "iamRoleForAWSConfig"
  SnsTopic1:
    Type: "AWS::SNS::Topic"
    Properties:
      Subscription:
        - Endpoint: "email@example.com"
          Protocol: "email"
      TopicName: "sns-topic"
  ConfigRule1:
    Type: "AWS::Config::ConfigRule"
    Properties:
      ConfigRuleName: "restricted-ssh"
      Scope:
        ComplianceResourceTypes:
          - "AWS::EC2::SecurityGroup"
      Description: "A Config rule that checks whether security groups in use do not allow restricted incoming SSH traffic. This rule applies only to IPv4."
      Source:
        Owner: "AWS"
        SourceIdentifier: "INCOMING_SSH_DISABLED"
    DependsOn:
      - "ConfigurationRecorder"
  ConfigRule2:
    Type: "AWS::Config::ConfigRule"
    Properties:
      ConfigRuleName: "restricted-common-ports"
      Scope:
        ComplianceResourceTypes:
          - "AWS::EC2::SecurityGroup"
      Description: "A Config rule that checks whether security groups in use do not allow restricted incoming TCP traffic to the specified ports. This rule applies only to IPv4."
      InputParameters:
        blockedPort1: "20"
        blockedPort2: "21"
        blockedPort3: "3389"
        blockedPort4: "3306"
        blockedPort5: "4333"
      Source:
        Owner: "AWS"
        SourceIdentifier: "RESTRICTED_INCOMING_TRAFFIC"
    DependsOn:
      - "ConfigurationRecorder"
  ConfigRule3:
    Type: "AWS::Config::ConfigRule"
    Properties:
      ConfigRuleName: "ec2_vpc_public_subnet"
      Scope:
        ComplianceResourceTypes:
          - "AWS::EC2::Instance"
      Description: "A Config rule that checks that no EC2 Instances are in Public Subnet."
      Source:
        Owner: "CUSTOM_LAMBDA"
        SourceIdentifier:
          Fn::GetAtt:
            - "LambdaFunctionForConfigRule3"
            - "Arn"
        SourceDetails:
          - EventSource: "aws.config"
            MessageType: "ConfigurationItemChangeNotification"
          - EventSource: "aws.config"
            MessageType: "OversizedConfigurationItemChangeNotification"
    DependsOn:
      - "ConfigurationRecorder"
  LambdaInvokePermissionsConfigRule3:
    Type: "AWS::Lambda::Permission"
    Properties:
      FunctionName:
        Fn::GetAtt:
          - "LambdaFunctionForConfigRule3"
          - "Arn"
      Action: "lambda:InvokeFunction"
      Principal: "config.amazonaws.com"
  LambdaFunctionForConfigRule3:
    Type: "AWS::Lambda::Function"
    Properties:
      FunctionName: "LambdaForec2_vpc_public_subnet"
      Handler: "index.lambda_handler"
      Role:
        Fn::GetAtt:
          - "LambdaIamRoleConfigRule3"
          - "Arn"
      Runtime: "python3.6"
      Code:
        ZipFile:
          Fn::Join:
            - "\n"
            -
              - ""
              - "#"
              - "# This file made available under CC0 1.0 Universal (https://creativecommons.org/publicdomain/zero/1.0/legalcode)"
              - "#"
              - "# Description: Check that no EC2 Instances are in Public Subnet"
              - "#"
              - "# Trigger Type: Change Triggered"
              - "# Scope of Changes: EC2:Instance"
              - "# Accepted Parameters: None"
              - "# Your Lambda function execution role will need to have a policy that provides the appropriate"
              - "# permissions.  Here is a policy that you can consider.  You should validate this for your own"
              - "# environment"
              - "#{"
              - "#    \"Version\": \"2012-10-17\","
              - "#    \"Statement\": ["
              - "#        {"
              - "#            \"Effect\": \"Allow\","
              - "#            \"Action\": ["
              - "#                \"logs:CreateLogGroup\","
              - "#                \"logs:CreateLogStream\","
              - "#                \"logs:PutLogEvents\""
              - "#            ],"
              - "#            \"Resource\": \"arn:aws:logs:*:*:*\""
              - "#        },"
              - "#        {"
              - "#            \"Effect\": \"Allow\","
              - "#            \"Action\": ["
              - "#                \"config:PutEvaluations\","
              - "#                \"ec2:DescribeRouteTables\""
              - "#            ],"
              - "#            \"Resource\": \"*\""
              - "#        }"
              - "#    ]"
              - "#}"
              - "#"
              - ""
              - "import boto3"
              - "import botocore"
              - "import json"
              - "import logging"
              - ""
              - "log = logging.getLogger()"
              - "log.setLevel(logging.INFO)"
              - ""
              - "def evaluate_compliance(configuration_item):"
              - "    subnet_id   = configuration_item[\"configuration\"][\"subnetId\"]"
              - "    vpc_id      = configuration_item[\"configuration\"][\"vpcId\"]"
              - "    client      = boto3.client(\"ec2\");"
              - ""
              - "    response    = client.describe_route_tables()"
              - ""
              - "    # If the subnet is explicitly associated to a route table, check if there"
              - "    # is a public route. If no explicit association exists, check if the main"
              - "    # route table has a public route."
              - ""
              - "    private = True"
              - "    mainTableIsPublic = False"
              - "    noExplicitAssociationFound = True"
              - "    explicitAssocationIsPublic = False"
              - ""
              - "    for i in response['RouteTables']:"
              - "        if i['VpcId'] == vpc_id:"
              - "            for j in i['Associations']:"
              - "                if j['Main'] == True:"
              - "                    for k in i['Routes']:"
              - "                        if k['DestinationCidrBlock'] == '0.0.0.0/0' or k['GatewayId'].startswith('igw-'):"
              - "                            mainTableIsPublic = True"
              - "                else:"
              - "                    if j['SubnetId'] == subnet_id:"
              - "                        noExplicitAssociationFound = False"
              - "                        for k in i['Routes']:"
              - "                            if k['DestinationCidrBlock'] == '0.0.0.0/0' or k['GatewayId'].startswith('igw-'):"
              - "                                explicitAssocationIsPublic = True"
              - ""
              - "    if (mainTableIsPublic and noExplicitAssociationFound) or explicitAssocationIsPublic:"
              - "        private = False"
              - ""
              - "    if private:"
              - "        return {"
              - "            \"compliance_type\": \"COMPLIANT\","
              - "            \"annotation\": 'Its in private subnet'"
              - "        }"
              - "    else:"
              - "        return {"
              - "            \"compliance_type\" : \"NON_COMPLIANT\","
              - "            \"annotation\" : 'Not in private subnet'"
              - "        }"
              - ""
              - "def lambda_handler(event, context):"
              - "    log.debug('Event %s', event)"
              - "    invoking_event      = json.loads(event['invokingEvent'])"
              - "    configuration_item  = invoking_event[\"configurationItem\"]"
              - "    evaluation          = evaluate_compliance(configuration_item)"
              - "    config              = boto3.client('config')"
              - ""
              - "    response = config.put_evaluations("
              - "       Evaluations=["
              - "           {"
              - "               'ComplianceResourceType':    invoking_event['configurationItem']['resourceType'],"
              - "               'ComplianceResourceId':      invoking_event['configurationItem']['resourceId'],"
              - "               'ComplianceType':            evaluation[\"compliance_type\"],"
              - "               \"Annotation\":                evaluation[\"annotation\"],"
              - "               'OrderingTimestamp':         invoking_event['configurationItem']['configurationItemCaptureTime']"
              - "           },"
              - "       ],"
              - "       ResultToken=event['resultToken'])"
              - ""
      Timeout: 300
    DependsOn: "LambdaIamRoleConfigRule3"
  LambdaIamRoleConfigRule3:
    Type: "AWS::IAM::Role"
    Properties:
      RoleName: "IAMRoleForec2_vpc_public_subnetLhC"
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Principal:
              Service:
                - "lambda.amazonaws.com"
            Action:
              - "sts:AssumeRole"
      ManagedPolicyArns:
        - "arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess"
        - "arn:aws:iam::aws:policy/service-role/AWSConfigRulesExecutionRole"
        - "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
      Policies: []
  ConfigRule4:
    Type: "AWS::Config::ConfigRule"
    Properties:
      ConfigRuleName: "encrypted-volumes"
      Scope:
        ComplianceResourceTypes:
          - "AWS::EC2::Volume"
      Description: "A Config rule that checks whether the EBS volumes that are in an attached state are encrypted. If you specify the ID of a KMS key for encryption using the kmsId parameter, the rule checks if the EBS volumes in an attached state are encrypted with that ..."
      Source:
        Owner: "AWS"
        SourceIdentifier: "ENCRYPTED_VOLUMES"
    DependsOn:
      - "ConfigurationRecorder"
  CwEvent1:
    Type: "AWS::Events::Rule"
    Properties:
      Name: "detect-config-rule-compliance-changes"
      Description: "A CloudWatch Event Rule that detects changes to AWS Config Rule compliance status and publishes change events to an SNS topic for notification."
      State: "ENABLED"
      Targets:
        - Arn:
            Ref: "SnsTopic1"
          Id: "target-id1"
      EventPattern:
        detail-type:
          - "Config Rules Compliance Change"
        source:
          - "aws.config"
  SnsTopicPolicyCwEvent1:
    Type: "AWS::SNS::TopicPolicy"
    Properties:
      PolicyDocument:
        Statement:
          - Sid: "__default_statement_ID"
            Effect: "Allow"
            Principal:
              AWS: "*"
            Action:
              - "SNS:GetTopicAttributes"
              - "SNS:SetTopicAttributes"
              - "SNS:AddPermission"
              - "SNS:RemovePermission"
              - "SNS:DeleteTopic"
              - "SNS:Subscribe"
              - "SNS:ListSubscriptionsByTopic"
              - "SNS:Publish"
              - "SNS:Receive"
            Resource:
              Ref: "SnsTopic1"
            Condition:
              StringEquals:
                AWS:SourceOwner:
                  Ref: "AWS::AccountId"
          - Sid: "TrustCWEToPublishEventsToMyTopic"
            Effect: "Allow"
            Principal:
              Service: "events.amazonaws.com"
            Action: "sns:Publish"
            Resource:
              Ref: "SnsTopic1"
      Topics:
        - Ref: "SnsTopic1"
  CwAlarm1:
    Type: "AWS::CloudWatch::Alarm"
    Properties:
      AlarmName: "securitygroup_changes"
      AlarmDescription: "A CloudWatch Alarm that triggers when changes are made to Security Groups."
      MetricName: "SecurityGroupEventCount"
      Namespace: "CloudTrailMetrics"
      Statistic: "Sum"
      Period: "300"
      EvaluationPeriods: "1"
      Threshold: "1"
      ComparisonOperator: "GreaterThanOrEqualToThreshold"
      AlarmActions:
        - Ref: "SnsTopic1"
      TreatMissingData: "notBreaching"
  MetricFilter1:
    Type: "AWS::Logs::MetricFilter"
    Properties:
      LogGroupName:
        Ref: "CWLogGroupForCloudTrail"
      FilterPattern: "{ ($.eventName = AuthorizeSecurityGroupIngress) || ($.eventName = AuthorizeSecurityGroupEgress) || ($.eventName = RevokeSecurityGroupIngress) || ($.eventName = RevokeSecurityGroupEgress) || ($.eventName = CreateSecurityGroup) || ($.eventName = DeleteSecurityGroup) }"
      MetricTransformations:
        - MetricValue: "1"
          MetricNamespace: "CloudTrailMetrics"
          MetricName: "SecurityGroupEventCount"
  CwAlarm2:
    Type: "AWS::CloudWatch::Alarm"
    Properties:
      AlarmName: "ec2_changes"
      AlarmDescription: "A CloudWatch Alarm that triggers when changes are made to EC2 Instances."
      MetricName: "EC2InstanceEventCount"
      Namespace: "CloudTrailMetrics"
      Statistic: "Sum"
      Period: "300"
      EvaluationPeriods: "1"
      Threshold: "1"
      ComparisonOperator: "GreaterThanOrEqualToThreshold"
      AlarmActions:
        - Ref: "SnsTopic1"
      TreatMissingData: "notBreaching"
  MetricFilter2:
    Type: "AWS::Logs::MetricFilter"
    Properties:
      LogGroupName:
        Ref: "CWLogGroupForCloudTrail"
      FilterPattern: "{ ($.eventName = RunInstances) || ($.eventName = RebootInstances) || ($.eventName = StartInstances) || ($.eventName = StopInstances) || ($.eventName = TerminateInstances) }"
      MetricTransformations:
        - MetricValue: "1"
          MetricNamespace: "CloudTrailMetrics"
          MetricName: "EC2InstanceEventCount"
Parameters: {}
Metadata: {}
Conditions: {}

Actions



Customize Template

Configuration Presets

Resource Settings

EDIT
EDIT
EDIT
EDIT
EDIT
EDIT
EDIT
EDIT
EDIT
EDIT
EDIT
EDIT
EDIT
EDIT
EDIT
EDIT
EDIT