AWS EC2 Manual Security Group Change


Description

An EC2 security group was manually updated without abiding by the organization's accepted processes. This rule expects organizations to either use the Console, CloudFormation, or Terraform, configurable in the rule's ALLOWED_USER_AGENTS.

Query · python

from panther_aws_helpers import aws_cloudtrail_success, aws_rule_context
from panther_base_helpers import pattern_match_list

PROD_ACCOUNT_IDS = {"11111111111111", "112233445566"}
SG_CHANGE_EVENTS = {
    "CreateSecurityGroup": {
        "fields": ["groupName", "vpcId"],
        "title": "New security group [{groupName}] created by {actor}",
    },
    "AuthorizeSecurityGroupIngress": {
        "fields": ["groupId"],
        "title": "User {actor} has updated security group [{groupId}]",
    },
    "AuthorizeSecurityGroupEgress": {
        "fields": ["groupId"],
        "title": "User {actor} has updated security group [{groupId}]",
    },
}
ALLOWED_USER_AGENTS = {
    "* HashiCorp/?.0 Terraform/*",
    # 'console.ec2.amazonaws.com',
    # 'cloudformation.amazonaws.com',
}
ALLOWED_ROLE_NAMES = {
    "Operator",
    "ContinousDeployment",
}


def rule(event):
    return aws_cloudtrail_success(event) and (
        event.get("eventName") in SG_CHANGE_EVENTS.keys()
        and event.get("recipientAccountId") in PROD_ACCOUNT_IDS
        and
        # Validate the deployment mechanism (Console, CloudFormation, or Terraform)
        not (
            pattern_match_list(event.get("userAgent"), ALLOWED_USER_AGENTS)
            and
            # Validate the IAM Role used is in our acceptable list
            any(role in event.deep_get("userIdentity", "arn") for role in ALLOWED_ROLE_NAMES)
        )
    )


def dedup(event):
    return ":".join(
        event.deep_get("requestParameters", field, default="<UNKNOWN_FIELD>")
        for field in SG_CHANGE_EVENTS[event.get("eventName")]["fields"]
    )


def title(event):
    title_fields = {
        field: event.deep_get("requestParameters", field, default="<UNKNOWN_FIELD>")
        for field in SG_CHANGE_EVENTS[event.get("eventName")]["fields"]
    }
    user = event.deep_get("userIdentity", "arn", default="<UNKNOWN_USER>").split("/")[-1]
    title_template = SG_CHANGE_EVENTS[event.get("eventName")]["title"]
    title_fields["actor"] = user
    return title_template.format(**title_fields)


def alert_context(event):
    return aws_rule_context(event)

Analyst notes

Identify the actor who changed the security group and validate it was legitimate

Raw source AWS EC2 Manual Security Group Change · Panther Python
Esc
Published by panther-labs/panther-analysis ↗, licensed under Apache 2.0 ↗. Reproduced here unmodified.
AnalysisType: rule
Filename: aws_ec2_manual_security_group_changes.py
RuleID: "AWS.EC2.ManualSecurityGroupChange"
DisplayName: "AWS EC2 Manual Security Group Change"
Enabled: false
LogTypes:
  - AWS.CloudTrail
Reports:
  MITRE ATT&CK:
    - TA0005:T1562
Tags:
  - AWS
  - Security Control
  - Configuration Required
  - Defense Evasion:Impair Defenses
Severity: Medium
Description: >
  An EC2 security group was manually updated without abiding by the organization's accepted processes. This rule expects organizations to either use the Console, CloudFormation, or Terraform, configurable in the rule's ALLOWED_USER_AGENTS.
Runbook: Identify the actor who changed the security group and validate it was legitimate
Reference: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/working-with-security-groups.html
Tests:
  - Name: AWS Console - Ingress SG Authorization
    LogType: AWS.CloudTrail
    ExpectedResult: true
    Log:
      {
        "awsRegion": "us-west-2",
        "eventID": "504b492f-7832-406b-a4fd-45a13e48adc4",
        "eventName": "AuthorizeSecurityGroupIngress",
        "eventSource": "ec2.amazonaws.com",
        "eventTime": "2021-01-24 04:55:45.000",
        "eventType": "AwsApiCall",
        "eventVersion": "1.08",
        "managementEvent": true,
        "readOnly": false,
        "recipientAccountId": "112233445566",
        "requestID": "91f34d65-513d-4e9f-a3de-e8d27f7ee4b2",
        "requestParameters":
          {
            "groupId": "sg-04f0b44316f7d2471",
            "ipPermissions":
              {
                "items":
                  [
                    {
                      "ipRanges": { "items": [{ "cidrIp": "0.0.0.0/16" }] },
                      "prefixListIds": {},
                      "fromPort": "443",
                      "toPort": "443",
                      "groups": {},
                      "ipProtocol": "tcp",
                      "ipv6Ranges": {},
                    },
                  ],
              },
          },
        "responseElements":
          {
            "_return": true,
            "requestId": "91f34d65-513d-4e9f-a3de-e8d27f7ee4b2",
          },
        "sourceIPAddress": "136.25.37.134",
        "userAgent": "console.ec2.amazonaws.com",
        "userIdentity":
          {
            "type": "AssumedRole",
            "principalid": "ARORJ4ULULLE0EEJAAKDO:alan",
            "arn": "arn:aws:sts::112233445566:assumed-role/TestAdmin/alan",
            "accountid": "112233445566",
            "accesskeyid": "ASIASWJRT64Z7ZLFLJNI",
            "sessioncontext":
              {
                "attributes":
                  {
                    "mfaauthenticated": "true",
                    "creationdate": "2021-01-24T04:55:10Z",
                  },
                "sessionissuer":
                  {
                    "type": "Role",
                    "principalid": "ARORJ4ULULLE0EEJAAKDO",
                    "arn": "arn:aws:iam::112233445566:role/TestAdmin",
                    "accountid": "112233445566",
                    "username": "TestAdmin",
                  },
              },
          },
        "p_event_time": "2021-01-24 04:55:45.000",
        "p_parse_time": "2021-01-24 05:02:58.358",
        "p_log_type": "AWS.CloudTrail",
        "p_row_id": "1a57ff7ade26aaf5a1a4d7d20775",
        "p_source_id": "e55677c6-7ef5-4541-a443-0d0f17eec19f",
        "p_source_label": "CloudTrail Test",
        "p_any_ip_addresses": ["136.25.37.134"],
        "p_any_aws_account_ids": ["112233445566"],
        "p_any_aws_arns":
          [
            "arn:aws:iam::112233445566:role/TestAdmin",
            " arn:aws:sts::112233445566:assumed-role/TestAdmin/alan",
          ],
      }
  - Name: Terraform Security Group Creation
    LogType: AWS.CloudTrail
    ExpectedResult: false
    Log:
      {
        "eventVersion": "1.05",
        "userIdentity":
          {
            "type": "AssumedRole",
            "principalId": "AROAIZCYMDBM4SJU6XXXX:ryan@example.com",
            "arn": "arn:aws:sts::112233445566:assumed-role/Operator/ryan@example.com",
            "accountId": "112233445566",
            "accessKeyId": "ASIAWDWBPTM3RJH7XXXX",
            "sessionContext":
              {
                "sessionIssuer":
                  {
                    "type": "Role",
                    "principalId": "AROAIZCYMDBM4SJU65M54",
                    "arn": "arn:aws:iam::112233445566:role/Operator",
                    "accountId": "112233445566",
                    "userName": "Operator",
                  },
                "webIdFederationData": {},
                "attributes":
                  {
                    "mfaAuthenticated": "false",
                    "creationDate": "2020-04-30T23:50:12Z",
                  },
              },
          },
        "eventTime": "2020-04-30T23:51:06Z",
        "eventSource": "ec2.amazonaws.com",
        "eventName": "CreateSecurityGroup",
        "awsRegion": "us-east-1",
        "sourceIPAddress": "100.1.114.142",
        "userAgent": "aws-sdk-go/1.29.7 (go1.13.7; darwin; amd64) APN/1.0 HashiCorp/1.0 Terraform/0.12.24 (+https://www.terraform.io)",
        "requestParameters":
          {
            "groupName": "prod-webapp-webserver-security",
            "groupDescription": "prod-webapp-webserver Security SG",
            "vpcId": "vpc-a1a044c7",
          },
        "responseElements":
          {
            "requestId": "594fe3e3-0f74-4085-9336-189b36a1cd8c",
            "_return": true,
            "groupId": "sg-04d018d184a18f647",
          },
        "requestID": "594fe3e3-0f74-4085-9336-189b36a1cd8c",
        "eventID": "52601748-2659-4ed8-b5fd-c530547b07ec",
        "eventType": "AwsApiCall",
        "recipientAccountId": "112233445566",
      }
  - Name: Terraform Security Group Authorize Egress
    LogType: AWS.CloudTrail
    ExpectedResult: false
    Log:
      {
        "eventVersion": "1.05",
        "userIdentity":
          {
            "type": "AssumedRole",
            "principalId": "AROAIZCYMDBM4SJU65M54:ryan@example.com",
            "arn": "arn:aws:sts::112233445566:assumed-role/ContinousDeployment/ryan@example.com",
            "accountId": "112233445566",
            "accessKeyId": "ASIAWDWBPTM3RJH7XXXX",
            "sessionContext":
              {
                "sessionIssuer":
                  {
                    "type": "Role",
                    "principalId": "AROAIZCYMDBM4SJU65M54",
                    "arn": "arn:aws:iam::112233445566:role/Operator",
                    "accountId": "112233445566",
                    "userName": "Operator",
                  },
                "webIdFederationData": {},
                "attributes":
                  {
                    "mfaAuthenticated": "false",
                    "creationDate": "2020-04-30T23:50:12Z",
                  },
              },
          },
        "eventTime": "2020-04-30T23:51:08Z",
        "eventSource": "ec2.amazonaws.com",
        "eventName": "AuthorizeSecurityGroupEgress",
        "awsRegion": "us-east-1",
        "sourceIPAddress": "100.1.114.142",
        "userAgent": "aws-sdk-go/1.29.7 (go1.13.7; darwin; amd64) APN/1.0 HashiCorp/1.0 Terraform/0.12.24 (+https://www.terraform.io)",
        "requestParameters":
          {
            "groupId": "sg-03eee825d6bb78f54",
            "ipPermissions":
              {
                "items":
                  [
                    {
                      "ipProtocol": "-1",
                      "groups": {},
                      "ipRanges":
                        {
                          "items":
                            [
                              {
                                "cidrIp": "0.0.0.0/0",
                                "description": "Allow egress to the internet. Required for now until we land ECS/ECR endpoints in the VPC",
                              },
                            ],
                        },
                      "ipv6Ranges": {},
                      "prefixListIds": {},
                    },
                  ],
              },
          },
        "responseElements":
          {
            "requestId": "4c7a5036-09d3-46e8-b0b6-f611ff1959a6",
            "_return": true,
          },
        "requestID": "4c7a5036-09d3-46e8-b0b6-f611ff1959a6",
        "eventID": "1a593035-e072-49c4-8c72-4ff35e195330",
        "eventType": "AwsApiCall",
        "recipientAccountId": "112233445566",
      }
  - Name: Go Script Authorize Ingress
    LogType: AWS.CloudTrail
    ExpectedResult: true
    Log:
      {
        "eventVersion": "1.05",
        "userIdentity":
          {
            "type": "AssumedRole",
            "principalId": "AROAIZCYMDBM4SJU65M54:ryan@example.com",
            "arn": "arn:aws:sts::112233445566:assumed-role/Operator/ryan@example.com",
            "accountId": "112233445566",
            "accessKeyId": "ASIAWDWBPTM3QPXQXXXX",
            "sessionContext":
              {
                "sessionIssuer":
                  {
                    "type": "Role",
                    "principalId": "AROAIZCYMDBM4SJU65M54",
                    "arn": "arn:aws:iam::112233445566:role/Operator",
                    "accountId": "112233445566",
                    "userName": "Operator",
                  },
                "webIdFederationData": {},
                "attributes":
                  {
                    "mfaAuthenticated": "false",
                    "creationDate": "2020-04-30T04:37:13Z",
                  },
              },
          },
        "eventTime": "2020-04-30T04:40:52Z",
        "eventSource": "ec2.amazonaws.com",
        "eventName": "AuthorizeSecurityGroupIngress",
        "awsRegion": "us-east-1",
        "sourceIPAddress": "100.1.114.142",
        "userAgent": "aws-sdk-go/1.24.1 (go1.14; darwin; amd64)",
        "requestParameters":
          {
            "groupId": "sg-0d921df5d84f7270a",
            "ipPermissions":
              {
                "items":
                  [
                    {
                      "ipProtocol": "tcp",
                      "fromPort": 22,
                      "toPort": 22,
                      "groups": {},
                      "ipRanges": { "items": [{ "cidrIp": "0.0.0.0/0" }] },
                      "ipv6Ranges": {},
                      "prefixListIds": {},
                    },
                  ],
              },
          },
        "responseElements":
          {
            "requestId": "2be70b99-4937-4a76-b7d9-390b6d0eda73",
            "_return": true,
          },
        "requestID": "2be70b99-4937-4a76-b7d9-390b6d0eda73",
        "eventID": "42155429-7e8e-43b5-9b5e-6953f80d51d5",
        "eventType": "AwsApiCall",
        "recipientAccountId": "112233445566",
      }
  - Name: AWS Console - Ingress SG Authorization Error
    LogType: AWS.CloudTrail
    ExpectedResult: false
    Log:
      {
        "awsRegion": "us-west-2",
        "errorCode": "UnauthorizedOperation",
        "eventID": "504b492f-7832-406b-a4fd-45a13e48adc4",
        "eventName": "AuthorizeSecurityGroupIngress",
        "eventSource": "ec2.amazonaws.com",
        "eventTime": "2021-01-24 04:55:45.000",
        "eventType": "AwsApiCall",
        "eventVersion": "1.08",
        "managementEvent": true,
        "readOnly": false,
        "recipientAccountId": "112233445566",
        "requestID": "91f34d65-513d-4e9f-a3de-e8d27f7ee4b2",
        "requestParameters":
          {
            "groupId": "sg-04f0b44316f7d2471",
            "ipPermissions":
              {
                "items":
                  [
                    {
                      "ipRanges": { "items": [{ "cidrIp": "0.0.0.0/16" }] },
                      "prefixListIds": {},
                      "fromPort": "443",
                      "toPort": "443",
                      "groups": {},
                      "ipProtocol": "tcp",
                      "ipv6Ranges": {},
                    },
                  ],
              },
          },
        "responseElements":
          {
            "_return": true,
            "requestId": "91f34d65-513d-4e9f-a3de-e8d27f7ee4b2",
          },
        "sourceIPAddress": "136.25.37.134",
        "userAgent": "console.ec2.amazonaws.com",
        "userIdentity":
          {
            "type": "AssumedRole",
            "principalid": "ARORJ4ULULLE0EEJAAKDO:alan",
            "arn": "arn:aws:sts::112233445566:assumed-role/TestAdmin/alan",
            "accountid": "112233445566",
            "accesskeyid": "ASIASWJRT64Z7ZLFLJNI",
            "sessioncontext":
              {
                "attributes":
                  {
                    "mfaauthenticated": "true",
                    "creationdate": "2021-01-24T04:55:10Z",
                  },
                "sessionissuer":
                  {
                    "type": "Role",
                    "principalid": "ARORJ4ULULLE0EEJAAKDO",
                    "arn": "arn:aws:iam::112233445566:role/TestAdmin",
                    "accountid": "112233445566",
                    "username": "TestAdmin",
                  },
              },
          },
        "p_event_time": "2021-01-24 04:55:45.000",
        "p_parse_time": "2021-01-24 05:02:58.358",
        "p_log_type": "AWS.CloudTrail",
        "p_row_id": "1a57ff7ade26aaf5a1a4d7d20775",
        "p_source_id": "e55677c6-7ef5-4541-a443-0d0f17eec19f",
        "p_source_label": "CloudTrail Test",
        "p_any_ip_addresses": ["136.25.37.134"],
        "p_any_aws_account_ids": ["112233445566"],
        "p_any_aws_arns":
          [
            "arn:aws:iam::112233445566:role/TestAdmin",
            " arn:aws:sts::112233445566:assumed-role/TestAdmin/alan",
          ],
      }


# ------ paired body: aws_ec2_manual_security_group_changes.py ------

from panther_aws_helpers import aws_cloudtrail_success, aws_rule_context
from panther_base_helpers import pattern_match_list

PROD_ACCOUNT_IDS = {"11111111111111", "112233445566"}
SG_CHANGE_EVENTS = {
    "CreateSecurityGroup": {
        "fields": ["groupName", "vpcId"],
        "title": "New security group [{groupName}] created by {actor}",
    },
    "AuthorizeSecurityGroupIngress": {
        "fields": ["groupId"],
        "title": "User {actor} has updated security group [{groupId}]",
    },
    "AuthorizeSecurityGroupEgress": {
        "fields": ["groupId"],
        "title": "User {actor} has updated security group [{groupId}]",
    },
}
ALLOWED_USER_AGENTS = {
    "* HashiCorp/?.0 Terraform/*",
    # 'console.ec2.amazonaws.com',
    # 'cloudformation.amazonaws.com',
}
ALLOWED_ROLE_NAMES = {
    "Operator",
    "ContinousDeployment",
}


def rule(event):
    return aws_cloudtrail_success(event) and (
        event.get("eventName") in SG_CHANGE_EVENTS.keys()
        and event.get("recipientAccountId") in PROD_ACCOUNT_IDS
        and
        # Validate the deployment mechanism (Console, CloudFormation, or Terraform)
        not (
            pattern_match_list(event.get("userAgent"), ALLOWED_USER_AGENTS)
            and
            # Validate the IAM Role used is in our acceptable list
            any(role in event.deep_get("userIdentity", "arn") for role in ALLOWED_ROLE_NAMES)
        )
    )


def dedup(event):
    return ":".join(
        event.deep_get("requestParameters", field, default="<UNKNOWN_FIELD>")
        for field in SG_CHANGE_EVENTS[event.get("eventName")]["fields"]
    )


def title(event):
    title_fields = {
        field: event.deep_get("requestParameters", field, default="<UNKNOWN_FIELD>")
        for field in SG_CHANGE_EVENTS[event.get("eventName")]["fields"]
    }
    user = event.deep_get("userIdentity", "arn", default="<UNKNOWN_USER>").split("/")[-1]
    title_template = SG_CHANGE_EVENTS[event.get("eventName")]["title"]
    title_fields["actor"] = user
    return title_template.format(**title_fields)


def alert_context(event):
    return aws_rule_context(event)

Detection rules belong to the projects that publish them and remain under their own licenses. This site indexes and links to them; it claims no rights in them.