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

GCP-EXPANDR-3608: Determine potential offending firewall rules #32678

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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
421 changes: 287 additions & 134 deletions Packs/GCP-Enrichment-Remediation/Playbooks/GCP_-_Enrichment.yml

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,21 @@ This playbook does not use any sub-playbooks.

### Integrations

* Google Cloud Compute
* GCP-IAM
* Google Cloud Compute

### Scripts

GCPProjectHierarchy
* GCPOffendingFirewallRule
* Set
* GCPProjectHierarchy

### Commands

* gcp-compute-aggregated-list-instances-by-ip
* gcp-compute-list-firewall
* gcp-iam-project-iam-policy-get
* gcp-iam-tagbindings-list
* gcp-iam-project-iam-policy-get
* gcp-compute-aggregated-list-instances-by-ip
* gcp-compute-get-instance

## Playbook Inputs

Expand All @@ -31,6 +33,8 @@ GCPProjectHierarchy
| **Name** | **Description** | **Default Value** | **Required** |
| --- | --- | --- | --- |
| GcpIP | GCP IP in alert | alert.remoteip | Required |
| port | Port to match traffic on for firewall rules. | ${alert.remoteport} | Optional |
| protocol | Protocol to match traffic on for firewall rules. | ${alert.protocol} | Optional |

## Playbook Outputs

Expand All @@ -39,13 +43,13 @@ GCPProjectHierarchy
| **Path** | **Description** | **Type** |
| --- | --- | --- |
| GoogleCloudCompute.Instances | GCP VM Instances information. | unknown |
| GoogleCloudCompute.Firewalls | GCP Firewall information | unknown |
| GCPIAM.Policy | GCP IAM information | unknown |
| GCPIAM.TagBindings | Project/Folder/Organization level tags. | unknown |
| GCPHierarchy | GCP project hierarchy information. | unknown |
| GCPHierarchy | GCP project hierarchy information. | unknown |
| GCPOffendingFirewallRule | One or more potential offending firewall rules in GCP based on port, protocol and possibly target tags \(network tags\). | unknown |

## Playbook Image

---

![GCP - Enrichment](../doc_files/GCP_-_Enrichment.png)
![GCP - Enrichment](../doc_files/GCP_-_Enrichment.png)
8 changes: 7 additions & 1 deletion Packs/GCP-Enrichment-Remediation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,10 @@ This content pack includes the following playbooks:

Automation to determine GCP project hierarchy by looking up parent objects until the organization level is reached.

![GCPProjectHierarchy](https://raw.githubusercontent.com/demisto/content/7065e08ec9738db1ea3e2bc5d78ac643931f46d1/Packs/GCP-Enrichment-Remediation/doc_files/GCPProjecHierarchy.png)
![GCPProjectHierarchy](https://raw.githubusercontent.com/demisto/content/master/Packs/GCP-Enrichment-Remediation/doc_files/GCPProjecHierarchy.png)

#### GCPOffendingFirewallRule

Automation to determine potential offending firewall rules in GCP based on port, protocol and possibly target tags (network tags).

![GCPOffendingFirewallRule](https://raw.githubusercontent.com/demisto/content/2eabf20887e5664294168fb1fbd9d1bbdb916a35/Packs/GCP-Enrichment-Remediation/doc_files/GCP_-_Enrichment.png)
15 changes: 15 additions & 0 deletions Packs/GCP-Enrichment-Remediation/ReleaseNotes/1_1_16.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

#### Playbooks

##### GCP - Enrichment

Updated the playbook to include the new **GCPOffendingFirewallRule** script.

#### Scripts

##### New: GCPOffendingFirewallRule

New: Determine potential offending firewall rules in GCP based on port, protocol and possibly target tags (network tags).

Considerations:
At this time this automation only finds potential offending rules and not necessarily the rule that is matching traffic. (Available from Cortex XSOAR 6.8.0).
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import demistomock as demisto # noqa: F401
from CommonServerPython import * # noqa: F401
from typing import Any
import traceback


''' STANDALONE FUNCTION '''


def is_port_in_range(port_range: str, port: str) -> bool:
"""
Breaks a string port range (i.e. '20-25') into integers for comapirson
Args:
port_range (str): string based port range from the GCP firewall rule.
port (str): port supplied in script args.

Returns:
bool: whether there was a match between the supplied port in args and the supplied range.
"""
split_range = port_range.split('-')
if int(port) >= int(split_range[0]) and int(port) <= int(split_range[1]):
return True
return False


def is_there_traffic_match(port: str, protocol: str, rule: dict, network_tags: list) -> bool:
"""
Breaks a string port range (i.e. '20-25') into integers for comapirson
Args:
port (str): port supplied in script args.
protocol (str): protocol supplied in script args.
rule (Dict): GCP firewall rule pulled from integration command.
network_tags (list): list of network tags (can be empty).

Returns:
bool: whether there was a match between the supplied port, protocol
and possible target tag combination and the GCP firewall rule.
"""
# Match rule needs to be direction ingress, source from internet (0.0.0.0/0), enabled and an allow rule.
if rule.get('direction') == 'INGRESS' and '0.0.0.0/0' in rule.get('sourceRanges', []) \
and rule.get('disabled') is False and 'allowed' in rule:
# Test if targetTags are relevant or not (if show up in keys or tag match)
target_tags_verdict = ('targetTags' not in rule.keys() or len(set(rule.get('targetTags', [])) & set(network_tags)) > 0)
for entry in rule.get('allowed', []):
# Match is all protocol AND either no target tags OR target tags match
if entry.get('IPProtocol') == 'all' and target_tags_verdict:
return True
# Complicated because just {'IPProtocol': 'udp'} means all udp ports
# therefore if protocol match but no ports, this is a match
elif entry.get('IPProtocol') == protocol.lower() and 'ports' not in entry:
return True
# Else need to go through all ports to see if range or not
elif entry.get('IPProtocol') == protocol.lower() and 'ports' in entry:
for port_entry in entry.get('ports', []):
if "-" in port_entry:
res = is_port_in_range(port_entry, port)
if res and target_tags_verdict:
return True
else:
if port == port_entry and target_tags_verdict:
return True
return False


''' COMMAND FUNCTION '''


def gcp_offending_firewall_rule(args: dict[str, Any]) -> CommandResults:
"""
Determine potential offending firewall rules in GCP based on port, protocol and possibly target tags (network tags).
Args:
args (dict): Command arguments from XSOAR.

Returns:
list[CommandResults]: outputs, readable outputs and raw response for XSOAR.

"""

project_id = args["project_id"]
network_url = args["network_url"]
port = args["port"]
protocol = args["protocol"]
network_tags = args.get("network_tags", [])

# Using `demisto.executeCommand` instead of `execute_command` because for
# multiple integration instances we can expect one too error out.
shmuel44 marked this conversation as resolved.
Show resolved Hide resolved
network_url_filter = f"network=\"{network_url}\""
fw_rules = demisto.executeCommand(
"gcp-compute-list-firewall", {"project_id": project_id, "filters": network_url_filter}
)
fw_rules_returned = [
instance
for instance in fw_rules
if (not isError(instance) and instance.get("Contents", {}).get("id"))
]
if not fw_rules_returned:
return CommandResults(readable_output="Could not find specified firewall info")
final_match_list = []
for rule in fw_rules_returned[0].get('Contents', {}).get('items'):
if is_there_traffic_match(port, protocol, rule, network_tags):
final_match_list.append(rule['name'])
if not final_match_list:
return CommandResults(readable_output="Could not find any potential offending firewall rules")

return CommandResults(
outputs={'GCPOffendingFirewallRule': final_match_list},
raw_response={'GCPOffendingFirewallRule': final_match_list},
readable_output=f"Potential Offending GCP Firewall Rule(s) Found: {final_match_list}",
)


''' MAIN FUNCTION '''


def main():
try:
return_results(gcp_offending_firewall_rule(demisto.args()))
except Exception as ex:
demisto.error(traceback.format_exc()) # print the traceback
return_error(f'Failed to execute GCPOffendingFirewallRule. Error: {str(ex)}')


''' ENTRY POINT '''


if __name__ in ('__main__', '__builtin__', 'builtins'):
main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
args:
- description: The project to look up firewall rules in. The project ID instead of the project number. No need to supply `projects/` before the ID (i.e., use `project-name` instead of `projects/project-name` or `projects/111111111111`).
name: project_id
required: true
- description: The url of the network objects to lookup firewall rules in. This will be the url of the network and not just the name (i.e. https://www.googleapis.com/compute/v1/projects/<project_name>/global/networks/<network_name>).
name: network_url
required: true
- description: Port to match traffic on for firewall rules.
name: port
required: true
- description: Protocol to match traffic on for firewall rules.
name: protocol
required: true
- description: Network tags on GCP VM instance to match rules based on target tag (optional).
isArray: true
name: network_tags
comment: |-
Determine potential offending firewall rules in GCP based on port, protocol and possibly target tags (network tags).

Considerations:
- At this time this automation only find potential offending rules and not necessarily the rule that is matching traffic.
commonfields:
id: GCPOffendingFirewallRule
version: -1
dockerimage: demisto/python3:3.10.13.86272
enabled: true
engineinfo: {}
name: GCPOffendingFirewallRule
outputs:
- contextPath: GCPOffendingFirewallRule
description: One or more potential offending firewall rules in GCP based on port, protocol and possibly target tags (network tags).
runas: DBotWeakRole
runonce: false
script: ''
scripttarget: 0
subtype: python3
tags: []
type: python
fromversion: 6.8.0
tests:
- No tests (auto formatted)
Loading
Loading