Skip to content

Commit

Permalink
Fix AWSRecreateSG EC2 breaking change bug (demisto#32962)
Browse files Browse the repository at this point in the history
* fixed

* remove print

* update docker + RN

* add BC warning

* remove duplicate

* fixed unit-tests

* newline
  • Loading branch information
jlevypaloalto authored and rundssoar committed Feb 28, 2024
1 parent 99cc7b7 commit 23f1509
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 180 deletions.
9 changes: 9 additions & 0 deletions Packs/AWS-Enrichment-Remediation/ReleaseNotes/1_1_16.md
@@ -0,0 +1,9 @@

#### Scripts

##### AWSRecreateSG

- Fixed an issue where the script failed with the latest version of the `AWS - EC2` integration.
- Updated the Docker image to: *demisto/python3:3.10.13.87159*.

**NOTE:** The `AWS - EC2` integration version must be greater than `1.4.0` for this script to run.
@@ -1,36 +1,13 @@
import demistomock as demisto # noqa: F401
from CommonServerPython import * # noqa: F401


from typing import Any
import traceback
from random import randint

ROLE_SESSION_NAME = "xsoar-session"


def get_context_path(context: dict, path: str):
"""Get a context output ignoring the DT suffix.
Args:
context (dict): The context output with DT paths as keys.
path (str): The outputs prefix path without the DT transform under which the required data is held.
Return:
(Any): The context data under the prefix.
Example:
>>> output = demisto.executeCommand('aws-ec2-describe-addresses')
>>> output
{'Contents': {'path.to.data(val.Id && val.Id == obj.Id)': [1, 2, 3, 4]}}
>>> get_context_path(output, 'path.to.data')
[1, 2, 3, 4]
"""
return context.get(
next((key for key in context if key.partition('(')[0] == path), None)
)


def split_rule(rule: dict, port: int, protocol: str) -> list[dict]:
"""
If there are rules with ranges of ports, split them up
Expand Down Expand Up @@ -93,7 +70,7 @@ def sg_fix(sg_info: list, port: int, protocol: str, assume_role: str, instance_t
Returns:
Dict: Dict of the new SG to be used
"""
info = get_context_path(sg_info[0]['Contents'], 'AWS.EC2.SecurityGroups')[0] # type: ignore
info = dict_safe_get(sg_info, (0, 'Contents', 0))
recreate_list = []
# Keep track of change in SG or not.
change = False
Expand All @@ -109,13 +86,6 @@ def sg_fix(sg_info: list, port: int, protocol: str, assume_role: str, instance_t
and rule['IpProtocol'] == protocol
):
change = True
elif (
rule["FromPort"] == port and port == rule["ToPort"]
and any(d["CidrIp"] == "0.0.0.0/0" for d in rule["IpRanges"])
and rule["IpProtocol"] == protocol
):
# If condition to check for Quad 0 in the rules list for matching port.
change = True
elif (
rule['FromPort'] <= port and port <= rule['ToPort']
and any(d["CidrIp"] == "0.0.0.0/0" for d in rule["IpRanges"])
Expand Down Expand Up @@ -160,7 +130,7 @@ def sg_fix(sg_info: list, port: int, protocol: str, assume_role: str, instance_t
new_sg = demisto.executeCommand("aws-ec2-create-security-group", cmd_args)
if isError(new_sg):
raise ValueError('Error on creating new security group')
new_id = new_sg[0]['Contents']['AWS.EC2.SecurityGroups']['GroupId']
new_id = dict_safe_get(new_sg, (0, 'Contents', 'GroupId'))
for item in recreate_list:
cmd_args = {"groupId": new_id, "IpPermissionsFull": item, "using": instance_to_use}
if assume_role:
Expand Down Expand Up @@ -293,8 +263,7 @@ def instance_info(instance_id: str, public_ip: str, assume_role: str, region: st
# Need a for loop in case multiple AWS-EC2 integrations are configured.
match = False
for instance in instance_info:
# Check if returned error, in the case of multiple integration instances only one should pass.
interfaces = get_context_path(instance.get('Contents'), 'AWS.EC2.Instances')[0].get('NetworkInterfaces') # type: ignore
interfaces = dict_safe_get(instance, ('Contents', 0, 'NetworkInterfaces'))
if not isError(instance) and interfaces:
mapping_dict = {}
for interface in interfaces:
Expand Down
Expand Up @@ -51,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.84405
dockerimage: demisto/python3:3.10.13.87159
enabled: true
name: AWSRecreateSG
runas: DBotWeakRole
Expand Down
Expand Up @@ -72,9 +72,8 @@ def test_sg_fix(mocker):
- Checks the output of the helper function with the expected output.
"""
from AWSRecreateSG import sg_fix
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)
from test_data.sample import SG_INFO, NEW_SG
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",
"region": "us-east-1"}
result = sg_fix(**args)
Expand All @@ -92,15 +91,13 @@ def test_determine_excessive_access(mocker):
- Checks the output of the helper function with the expected output.
"""
from AWSRecreateSG import determine_excessive_access
from test_data.sample import SG_INFO
new_sg = [{'Type': 1, 'Contents': {'AWS.EC2.SecurityGroups': {'GroupId': 'sg-00000000000000001'}}}]
from test_data.sample import SG_INFO, NEW_SG

def executeCommand(name, args):
if name == "aws-ec2-describe-security-groups":
return SG_INFO
elif name == "aws-ec2-create-security-group":
return new_sg
return None
def executeCommand(name, *_):
return {
"aws-ec2-describe-security-groups": SG_INFO,
"aws-ec2-create-security-group": NEW_SG
}.get(name)

mocker.patch.object(demisto, "executeCommand", side_effect=executeCommand)
args = {"int_sg_mapping": {'eni-00000000000000000': ['sg-00000000000000000']}, "port": 22,
Expand All @@ -120,38 +117,18 @@ def test_aws_recreate_sg(mocker):
- Checks the output of the function with the expected output.
"""
from AWSRecreateSG import aws_recreate_sg
from test_data.sample import SG_INFO, INSTANCE_INFO
new_sg = [{'Type': 1, 'Contents': {'AWS.EC2.SecurityGroups': {'GroupId': 'sg-00000000000000001'}}}]

def executeCommand(name, args):
if name == "aws-ec2-describe-security-groups":
return SG_INFO
elif name == "aws-ec2-create-security-group":
return new_sg
elif name == "aws-ec2-describe-instances":
return INSTANCE_INFO
return None
from test_data.sample import SG_INFO, INSTANCE_INFO, NEW_SG

mocker.patch.object(demisto, "executeCommand", side_effect=executeCommand)
def execute_command(command, *_):
return {
"aws-ec2-describe-security-groups": SG_INFO,
"aws-ec2-create-security-group": NEW_SG,
"aws-ec2-describe-instances": INSTANCE_INFO
}.get(command)

mocker.patch.object(demisto, "executeCommand", side_effect=execute_command)
args = {"instance_id": "fake-instance-id", "public_ip": "1.1.1.1", "port": "22", "protocol": "tcp"}
command_results = aws_recreate_sg(args)
readable_output = command_results.readable_output
correct_output = "For interface eni-00000000000000000: \r\nreplaced SG sg-00000000000000000 with sg-00000000000000001 \r\n"
assert readable_output == correct_output


def test_get_context_path():
"""
Given:
An output from demisto.excuteCommand('some-command')['Context']
When:
Calling demisto.excuteCommand.
Then:
Get the context output.
"""
from AWSRecreateSG import get_context_path

outputs = {'path.to.data(dt_path)': [1, 2, 3, 4]}

assert get_context_path(outputs, 'path.to.data') == [1, 2, 3, 4]
assert get_context_path(outputs, 'wrong.path') is None
@@ -1,105 +1,61 @@
SG_INFO = [
{
"Type": 1,
"Contents": {
"AWS.EC2.SecurityGroups(val.GroupId === obj.GroupId)": [
"Contents": [
{
"Description": "sldkjdlskfjs",
"GroupId": "sg-00000000000000001",
"GroupName": "demo-sg",
"IpPermissions": [
{
"Description": "sldkjdlskfjs",
"GroupId": "sg-00000000000000001",
"GroupName": "demo-sg",
"IpPermissions": [
"FromPort": 0,
"IpProtocol": "tcp",
"IpRanges": [
{
"FromPort": 0,
"IpProtocol": "tcp",
"IpRanges": [
{
"CidrIp": "0.0.0.0/0"
}
],
"Ipv6Ranges": [],
"PrefixListIds": [],
"ToPort": 65535,
"UserIdGroupPairs": []
},
"CidrIp": "0.0.0.0/0"
}
],
"Ipv6Ranges": [],
"PrefixListIds": [],
"ToPort": 65535,
"UserIdGroupPairs": []
},
{
"FromPort": 22,
"IpProtocol": "tcp",
"IpRanges": [
{
"FromPort": 22,
"IpProtocol": "tcp",
"IpRanges": [
{
"CidrIp": "0.0.0.0/0"
}
],
"Ipv6Ranges": [],
"PrefixListIds": [],
"ToPort": 22,
"UserIdGroupPairs": []
"CidrIp": "0.0.0.0/0"
}
],
"IpPermissionsEgress": [
"Ipv6Ranges": [],
"PrefixListIds": [],
"ToPort": 22,
"UserIdGroupPairs": []
}
],
"IpPermissionsEgress": [
{
"FromPort": 0,
"IpProtocol": "tcp",
"IpRanges": [
{
"FromPort": 0,
"IpProtocol": "tcp",
"IpRanges": [
{
"CidrIp": "0.0.0.0/0"
}
],
"Ipv6Ranges": [],
"PrefixListIds": [],
"ToPort": 65535,
"UserIdGroupPairs": []
"CidrIp": "0.0.0.0/0"
}
],
"OwnerId": "717007404259",
"Region": "us-east-1",
"VpcId": "vpc-061c242911e464170"
"Ipv6Ranges": [],
"PrefixListIds": [],
"ToPort": 65535,
"UserIdGroupPairs": []
}
]
},
],
"OwnerId": "717007404259",
"Region": "us-east-1",
"VpcId": "vpc-061c242911e464170"
}
],
"HumanReadable": "### AWS EC2 SecurityGroups\n|Description|GroupId|GroupName|OwnerId|Region|VpcId|\n|---|---|---|---|---|---|\n| sldkjdlskfjs | sg-0408c2745d3d13b15 | demo-sg | 717007404259 | us-east-1 | vpc-061c242911e464170 |\n",
"ImportantEntryContext": "None",
"EntryContext": {
"AWS.EC2.SecurityGroups(val.GroupId === obj.GroupId)": [
{
"Description": "sldkjdlskfjs",
"GroupId": "sg-0408c2745d3d13b15",
"GroupName": "demo-sg",
"IpPermissions": [
{
"FromPort": 0,
"IpProtocol": "tcp",
"IpRanges": [
{
"CidrIp": "0.0.0.0/0"
}
],
"Ipv6Ranges": "None",
"PrefixListIds": "None",
"ToPort": 65535,
"UserIdGroupPairs": "None"
}
],
"IpPermissionsEgress": [
{
"FromPort": 0,
"IpProtocol": "tcp",
"IpRanges": [
{
"CidrIp": "0.0.0.0/0"
}
],
"Ipv6Ranges": "None",
"PrefixListIds": "None",
"ToPort": 65535,
"UserIdGroupPairs": "None"
}
],
"OwnerId": "717007404259",
"Region": "us-east-1",
"VpcId": "vpc-061c242911e464170"
}
]
}
}
]
INSTANCE_INFO = [
Expand All @@ -108,25 +64,24 @@
"instance": "AWS - EC2"
},
"Type": 1,
"Contents": {
"AWS.EC2.Instances(val.InstanceId === obj.InstanceId)": [
"Contents": [
{
"NetworkInterfaces": [
{
"NetworkInterfaces": [
"Association": {
"PublicIp": "1.1.1.1"
},
"Groups": [
{
"Association": {
"PublicIp": "1.1.1.1"
},
"Groups": [
{
"GroupId": "sg-00000000000000000",
"GroupName": "sg-name"
}
],
"NetworkInterfaceId": "eni-00000000000000000"
"GroupId": "sg-00000000000000000",
"GroupName": "sg-name"
}
]
],
"NetworkInterfaceId": "eni-00000000000000000"
}
]
}
]
}
]
}
]
NEW_SG = [{'Type': 1, 'Contents': {'GroupId': 'sg-00000000000000001'}}]
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.15",
"currentVersion": "1.1.16",
"author": "Cortex XSOAR",
"url": "https://www.paloaltonetworks.com/cortex",
"email": "",
Expand Down

0 comments on commit 23f1509

Please sign in to comment.