Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AWS EXPANDR-6233 #30002

Merged
merged 2 commits into from Oct 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -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