Skip to content

Commit

Permalink
AWS EXPANDR-6233 (demisto#29840) (demisto#30002)
Browse files Browse the repository at this point in the history
* update script

* update play

* RN

* fix RN

* Apply suggestions from code review



* docker update

* clean README

* add predefined regions

---------

Co-authored-by: johnnywilkes <32227961+johnnywilkes@users.noreply.github.com>
Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com>
Co-authored-by: Michael Yochpaz <8832013+MichaelYochpaz@users.noreply.github.com>
  • Loading branch information
4 people authored and xsoar-bot committed Oct 5, 2023
1 parent ad31796 commit b71c306
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 31 deletions.
@@ -1,18 +1,16 @@
id: AWS - Security Group Remediation v2
version: -1
contentitemexportablefields:
contentitemfields: {}
name: AWS - Security Group Remediation v2
description: |-
This playbook takes in some information about an EC2 instance (ID and public_ip) and with provided port and protocol, determines what security groups on the primary interface of an EC2 instance are over-permissive. It uses an automation to determine what interface on an EC2 instance has an over-permissive security group on, determine which security groups have over-permissive rules and to replace them with a copy of the security group that has only the over-permissive portion removed. Over-permissive is defined as sensitive ports (SSH, RDP, etc) being exposed to the internet via IPv4.
starttaskid: "0"
tasks:
"0":
id: "0"
taskid: 887ec5b3-a4d7-47fc-82b0-701e072c0deb
taskid: 7aeccd71-8a2e-47a8-8ba0-b91bac919bf4
type: start
task:
id: 887ec5b3-a4d7-47fc-82b0-701e072c0deb
id: 7aeccd71-8a2e-47a8-8ba0-b91bac919bf4
version: -1
name: ""
iscommand: false
Expand All @@ -39,10 +37,10 @@ tasks:
isautoswitchedtoquietmode: false
"2":
id: "2"
taskid: 978b630a-7e00-443b-83f3-5e683144863a
taskid: 57209409-3b96-48f9-865d-61de73bd6309
type: title
task:
id: 978b630a-7e00-443b-83f3-5e683144863a
id: 57209409-3b96-48f9-865d-61de73bd6309
version: -1
name: Done
type: title
Expand All @@ -67,10 +65,10 @@ tasks:
isautoswitchedtoquietmode: false
"31":
id: "31"
taskid: e71350f2-0f75-41e1-841d-ee3c938fc23f
taskid: fe8c7803-f99e-4ee6-8481-fa710b622cd7
type: condition
task:
id: e71350f2-0f75-41e1-841d-ee3c938fc23f
id: fe8c7803-f99e-4ee6-8481-fa710b622cd7
version: -1
name: Is AWS - EC2 enabled and are input values defined?
description: Determines if the AWS - EC2 integration instance is configured and input values are defined in order to continue with remediating security groups.
Expand Down Expand Up @@ -152,10 +150,10 @@ tasks:
isautoswitchedtoquietmode: false
"32":
id: "32"
taskid: 193a8c2a-b241-47af-8e26-16eb37674369
taskid: d2488b84-78ba-4f31-8b35-c47e61425dd9
type: regular
task:
id: 193a8c2a-b241-47af-8e26-16eb37674369
id: d2488b84-78ba-4f31-8b35-c47e61425dd9
version: -1
name: Create Security Group automation
description: Automation to determine what interface on an EC2 instance has an over-permissive security group on, determine which security groups have over-permissive rules and to replace them with a copy of the security group that has only the over-permissive portion removed. Over-permissive is defined as sensitive ports (SSH, RDP, etc) being exposed to the internet via IPv4.
Expand All @@ -182,6 +180,9 @@ tasks:
public_ip:
complex:
root: inputs.PublicIP
region:
complex:
root: inputs.Region
separatecontext: false
continueonerrortype: ""
view: |-
Expand Down Expand Up @@ -234,14 +235,19 @@ inputs:
complex:
root: alert
accessor: remoteip
required: false
required: true
description: Public IP address of the EC2 instance.
playbookInputQuery:
- key: AWSAssumeArn
value: {}
required: false
description: Name of an AWS role to assume (should be the same for all organizations).
playbookInputQuery:
- key: Region
value: {}
required: false
description: Region where EC2 instance is present.
playbookInputQuery:
outputs: []
tests:
- No tests (auto formatted)
Expand Down
Expand Up @@ -29,8 +29,9 @@ This playbook does not use any commands.
| InstanceID | ID of the AWS EC2 instance. | | Required |
| Port | TCP/UDP port to be restricted. | alert.remoteport | Required |
| Protocol | Protocol of the port to be restricted. | | Required |
| PublicIP | Public IP address of the EC2 instance. | alert.remoteip | Optional |
| PublicIP | Public IP address of the EC2 instance. | alert.remoteip | Required |
| AWSAssumeArn | Name of an AWS role to assume \(should be the same for all organizations\). | | Optional |
| Region | Region where EC2 instance is present. | | Optional |

## Playbook Outputs

Expand Down
13 changes: 13 additions & 0 deletions Packs/AWS-Enrichment-Remediation/ReleaseNotes/1_1_5.md
@@ -0,0 +1,13 @@

#### Playbooks

##### AWS - Security Group Remediation v2

Updated the playbook to include the **Region** input in the **AWSRecreateSG** script.

#### Scripts

##### AWSRecreateSG

- Added the **Region** input to specify the region to run AWS commands.
- Updated the Docker image to: *demisto/python3:3.10.13.75921*.
Expand Up @@ -57,7 +57,7 @@ def split_rule(rule: dict, port: int, protocol: str) -> list[dict]:
return (res_list)


def sg_fix(sg_info: list, port: int, protocol: str, assume_role: str, instance_to_use: str) -> dict:
def sg_fix(sg_info: list, port: int, protocol: str, assume_role: str, instance_to_use: str, region: str) -> dict:
"""
For a SG determine what needs to be recreated.
Calls split_rule() if there are rules with ranges of ports to be split up
Expand Down Expand Up @@ -118,6 +118,8 @@ def sg_fix(sg_info: list, port: int, protocol: str, assume_role: str, instance_t
cmd_args = {"groupName": new_name, "vpcId": info['VpcId'], "description": description, "using": instance_to_use}
if assume_role:
cmd_args.update({'roleArn': assume_role, 'roleSessionName': ROLE_SESSION_NAME})
if region:
cmd_args.update({'region': region})
new_sg = demisto.executeCommand("aws-ec2-create-security-group", cmd_args)
if isError(new_sg):
raise ValueError('Error on creating new security group')
Expand All @@ -126,6 +128,8 @@ def sg_fix(sg_info: list, port: int, protocol: str, assume_role: str, instance_t
cmd_args = {"groupId": new_id, "IpPermissionsFull": item, "using": instance_to_use}
if assume_role:
cmd_args.update({'roleArn': assume_role, 'roleSessionName': ROLE_SESSION_NAME})
if region:
cmd_args.update({'region': region})
res = demisto.executeCommand("aws-ec2-authorize-security-group-ingress-rule",
cmd_args)
if isError(res):
Expand All @@ -144,6 +148,8 @@ def sg_fix(sg_info: list, port: int, protocol: str, assume_role: str, instance_t
cmd_args = {"groupId": new_id, "IpPermissionsFull": e_format, "using": instance_to_use}
if assume_role:
cmd_args.update({'roleArn': assume_role, 'roleSessionName': ROLE_SESSION_NAME})
if region:
cmd_args.update({'region': region})
res = demisto.executeCommand("aws-ec2-authorize-security-group-egress-rule",
cmd_args)
# Don't error if the message is that the rule already exists.
Expand All @@ -159,14 +165,16 @@ def sg_fix(sg_info: list, port: int, protocol: str, assume_role: str, instance_t
cmd_args = {"groupId": new_id, "IpPermissionsFull": all_traffic_rule, "using": instance_to_use}
if assume_role:
cmd_args.update({'roleArn': assume_role, 'roleSessionName': ROLE_SESSION_NAME})
if region:
cmd_args.update({'region': region})
res = demisto.executeCommand("aws-ec2-revoke-security-group-egress-rule",
cmd_args)
if isError(res):
raise ValueError('Error on removing egress `allow all` rule on new security group')
return {'new-sg': new_id}


def replace_sgs(replace_list: list, int_sg_mapping: dict, assume_role: str, instance_to_use: str):
def replace_sgs(replace_list: list, int_sg_mapping: dict, assume_role: str, instance_to_use: str, region: str):
"""
Replace the actual SGs on the interface
Expand All @@ -185,13 +193,16 @@ def replace_sgs(replace_list: list, int_sg_mapping: dict, assume_role: str, inst
cmd_args = {"networkInterfaceId": entry['int'], "groups": formatted_list, "using": instance_to_use}
if assume_role:
cmd_args.update({'roleArn': assume_role, 'roleSessionName': ROLE_SESSION_NAME})
if region:
cmd_args.update({'region': region})
res = demisto.executeCommand("aws-ec2-modify-network-interface-attribute",
cmd_args)
if isError(res):
raise ValueError('Error on replacing security group(s) on network interface')


def determine_excessive_access(int_sg_mapping: dict, port: int, protocol: str, assume_role: str, instance_to_use: str) -> list:
def determine_excessive_access(int_sg_mapping: dict, port: int, protocol: str, assume_role: str, instance_to_use: str,
region: str) -> list:
"""
Pulls info on each SG and then calls sg_fix() to actually create the new SGs
Expand All @@ -208,13 +219,15 @@ def determine_excessive_access(int_sg_mapping: dict, port: int, protocol: str, a
for mapping in int_sg_mapping:
for sg in int_sg_mapping[mapping]:
cmd_args = {"groupIds": sg, "using": instance_to_use}
if region:
cmd_args.update({'region': region})
if assume_role:
cmd_args.update({'roleArn': assume_role, 'roleSessionName': ROLE_SESSION_NAME})
sg_info = demisto.executeCommand("aws-ec2-describe-security-groups", cmd_args)
if isError(sg_info):
raise ValueError('Error on describing security group')
elif sg_info:
res = sg_fix(sg_info, port, protocol, assume_role, instance_to_use)
res = sg_fix(sg_info, port, protocol, assume_role, instance_to_use, region)
# Need interface, old sg and new sg.
if res.get('new-sg'):
res['old-sg'] = sg
Expand All @@ -223,7 +236,7 @@ def determine_excessive_access(int_sg_mapping: dict, port: int, protocol: str, a
return replace_list


def instance_info(instance_id: str, public_ip: str, assume_role: str) -> tuple[dict, str]:
def instance_info(instance_id: str, public_ip: str, assume_role: str, region: str) -> tuple[dict, str]:
"""
Finds interface with public_ip and from this creates interface ID/SG mapping
Expand All @@ -235,6 +248,8 @@ def instance_info(instance_id: str, public_ip: str, assume_role: str) -> tuple[d
tuple[dict, str]: A dictionary mapping interfaces to security groups (dict), and an integration to use (str).
"""
cmd_args = {"instanceIds": instance_id}
if region:
cmd_args.update({'region': region})
if assume_role:
cmd_args.update({'roleArn': assume_role, 'roleSessionName': ROLE_SESSION_NAME})
instance_info = demisto.executeCommand("aws-ec2-describe-instances", cmd_args)
Expand Down Expand Up @@ -282,17 +297,18 @@ def aws_recreate_sg(args: dict[str, Any]) -> str:
protocol = args.get('protocol', None)
public_ip = args.get('public_ip', None)
assume_role = args.get('assume_role', None)
region = args.get('region', None)

if not instance_id or not port or not protocol or not public_ip:
raise ValueError('instance_id, port, protocol and public_ip all need to be specified')

# Determine interface with public IP and associated SGs.
int_sg_mapping, instance_to_use = instance_info(instance_id, public_ip, assume_role)
int_sg_mapping, instance_to_use = instance_info(instance_id, public_ip, assume_role, region)
# Determine what SGs are overpermissive for particular port.
replace_list = determine_excessive_access(int_sg_mapping, port, protocol, assume_role, instance_to_use)
replace_list = determine_excessive_access(int_sg_mapping, port, protocol, assume_role, instance_to_use, region)
if len(replace_list) == 0:
raise ValueError('No security groups were found to need to be replaced')
replace_sgs(replace_list, int_sg_mapping, assume_role, instance_to_use)
replace_sgs(replace_list, int_sg_mapping, assume_role, instance_to_use, region)
display_message = f"For interface {replace_list[0]['int']}: \r\n"
for replace in replace_list:
display_message += f"replaced SG {replace['old-sg']} with {replace['new-sg']} \r\n"
Expand Down
Expand Up @@ -17,6 +17,28 @@ args:
required: true
- description: Name of an AWS role to assume (should be the same for all organizations).
name: assume_role
- description: Region where EC2 instance is present.
name: region
auto: PREDEFINED
predefined:
- us-east-1
- us-east-2
- us-west-1
- us-west-2
- ca-central-1
- eu-west-1
- eu-central-1
- eu-west-2
- ap-northeast-1
- ap-northeast-2
- ap-southeast-1
- ap-southeast-2
- ap-south-1
- sa-east-1
- eu-north-1
- eu-west-3
- us-gov-east-1
- us-gov-west-1
comment: Automation to determine which interface on an EC2 instance has an over-permissive security group, determine which security groups have over-permissive rules, and replace them with a copy of the security group that has only the over-permissive portion removed. Over-permissive is defined as sensitive ports (SSH, RDP, etc) being exposed to the internet via IPv4.
commonfields:
id: AWSRecreateSG
Expand All @@ -29,7 +51,7 @@ dependson:
- AWS - EC2|||aws-ec2-authorize-security-group-egress-rule
- AWS - EC2|||aws-ec2-revoke-security-group-ingress-rule
- AWS - EC2|||aws-ec2-revoke-security-group-egress-rule
dockerimage: demisto/python3:3.10.13.73190
dockerimage: demisto/python3:3.10.13.75921
enabled: true
name: AWSRecreateSG
runas: DBotWeakRole
Expand All @@ -41,3 +63,5 @@ type: python
fromversion: 6.5.0
tests:
- No tests (auto formatted)
engineinfo: {}
runonce: false
Expand Up @@ -51,7 +51,7 @@ def test_instance_info(mocker):
from AWSRecreateSG import instance_info
from test_data.sample import INSTANCE_INFO
mocker.patch.object(demisto, "executeCommand", return_value=INSTANCE_INFO)
args = {"instance_id": "fake-instance-id", "public_ip": "1.1.1.1", "assume_role": "test_role"}
args = {"instance_id": "fake-instance-id", "public_ip": "1.1.1.1", "assume_role": "test_role", "region": "us-east-1"}
result = instance_info(**args)
assert result == ({'eni-00000000000000000': ['sg-00000000000000000']}, 'AWS - EC2')

Expand All @@ -70,7 +70,8 @@ def test_sg_fix(mocker):
from test_data.sample import SG_INFO
new_sg = [{'Type': 1, 'Contents': {'AWS.EC2.SecurityGroups': {'GroupId': 'sg-00000000000000001'}}}]
mocker.patch.object(demisto, "executeCommand", return_value=new_sg)
args = {"sg_info": SG_INFO, "port": 22, "protocol": "tcp", "assume_role": "test_role", "instance_to_use": "AWS - EC2"}
args = {"sg_info": SG_INFO, "port": 22, "protocol": "tcp", "assume_role": "test_role", "instance_to_use": "AWS - EC2",
"region": "us-east-1"}
result = sg_fix(**args)
assert result == {'new-sg': 'sg-00000000000000001'}

Expand Down Expand Up @@ -98,7 +99,7 @@ def executeCommand(name, args):

mocker.patch.object(demisto, "executeCommand", side_effect=executeCommand)
args = {"int_sg_mapping": {'eni-00000000000000000': ['sg-00000000000000000']}, "port": 22,
"protocol": "tcp", "assume_role": "test_role", "instance_to_use": "AWS - EC2"}
"protocol": "tcp", "assume_role": "test_role", "instance_to_use": "AWS - EC2", "region": "us-east-1"}
result = determine_excessive_access(**args)
assert result == [{'int': 'eni-00000000000000000', 'old-sg': 'sg-00000000000000000', 'new-sg': 'sg-00000000000000001'}]

Expand Down
21 changes: 15 additions & 6 deletions Packs/AWS-Enrichment-Remediation/Scripts/AWSRecreateSG/README.md
@@ -1,4 +1,4 @@
Automation to determine what interface on an EC2 instance has an over-permissive security group on, determine which security groups have over-permissive rules and to replace them with a copy of the security group that has only the over-permissive portion removed. Over-permissive is defined as sensitive ports (SSH, RDP, etc) being exposed to the internet via IPv4.
Automation to determine which interface on an EC2 instance has an over-permissive security group, determine which security groups have over-permissive rules and replace them with a copy of the security group that has only the over-permissive portion removed. Over-permissive is defined as sensitive ports (SSH, RDP, etc.) being exposed to the internet via IPv4.

## Script Data

Expand All @@ -7,18 +7,26 @@ Automation to determine what interface on an EC2 instance has an over-permissive
| **Name** | **Description** |
| --- | --- |
| Script Type | python3 |
| Cortex XSOAR Version | 6.5.0 |

## Dependencies

---
This script uses the following commands and scripts.

* aws-ec2-create-security-group
* aws-ec2-authorize-security-group-ingress-rule
* aws-ec2-revoke-security-group-egress-rule
* aws-ec2-authorize-security-group-ingress-rule
* aws-ec2-authorize-security-group-egress-rule
* aws-ec2-revoke-security-group-ingress-rule
* aws-ec2-describe-instances
* aws-ec2-revoke-security-group-ingress-rule
* aws-ec2-create-security-group

## Used In

---
This script is used in the following playbooks and scripts.

* AWS - Security Group Remediation v2

## Inputs

Expand All @@ -27,10 +35,11 @@ This script uses the following commands and scripts.
| **Argument Name** | **Description** |
| --- | --- |
| instance_id | EC2 Instance ID. |
| port | TCP/UDP Port to be restricted. |
| port | TCP/UDP port to be restricted. |
| protocol | Protocol of the port to be restricted. |
| public_ip | Public IP address of the EC2 instance. |
| assume_role | If assuming roles for AWS, this is the name of the role to assume (should be the same for all organizations). |
| assume_role | Name of an AWS role to assume \(should be the same for all organizations\). |
| region | Region where EC2 instance is present. |

## Outputs

Expand Down
2 changes: 1 addition & 1 deletion Packs/AWS-Enrichment-Remediation/pack_metadata.json
Expand Up @@ -2,7 +2,7 @@
"name": "AWS Enrichment and Remediation",
"description": "Playbooks using multiple AWS content packs for enrichment and remediation purposes",
"support": "xsoar",
"currentVersion": "1.1.4",
"currentVersion": "1.1.5",
"author": "Cortex XSOAR",
"url": "https://www.paloaltonetworks.com/cortex",
"email": "",
Expand Down

0 comments on commit b71c306

Please sign in to comment.