GCPOffendingFirewallRule
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.
python · GCP Enrichment and Remediation
Source
import traceback from typing import Any import demistomock as demisto # noqa: F401 from CommonServerPython import * # noqa: F401 """ 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 comparison 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. """ start, end = port_range.split("-") return int(start) <= int(port) <= int(end) def is_there_traffic_match(port: str, protocol: str, rule: dict, network_tags: list) -> bool: """ Determines if there's a match between the supplied port, protocol, and possible target tag combination and the GCP firewall rule. The function checks: if the rule is an ingress rule, if the source is from the internet (0.0.0.0/0), if the rule is enabled, and if it's an allow rule. It also checks if the target tags are relevant (if they show up in keys or tag match), and if the protocol and ports match the supplied protocol and port. Args: port (str): The port supplied in script args. protocol (str): The protocol supplied in script args. This should be a string representing a network protocol (e.g., 'tcp', 'udp', 'icmp'). rule (dict): A dictionary representing a GCP firewall rule. This is pulled from the integration command. network_tags (list): A list of network tags. This can be empty. Returns: bool: True if there's a match between the supplied port, protocol, and possible target tag combination and the GCP firewall rule. False otherwise. """ # 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 or len(set(rule.get("targetTags", [])) & set(network_tags)) > 0 for entry in rule["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: 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. 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: {ex!s}") """ ENTRY POINT """ if __name__ in ("__main__", "__builtin__", "builtins"): main()
README
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.
Script Data
| Name | Description |
|---|---|
| Script Type | python3 |
| Cortex XSOAR Version | 6.8.0 |
Used In
This script is used in the following playbooks and scripts.
- GCP - Enrichment - EXPANDR-3608
- GCP - Enrichment
Inputs
| Argument Name | Description |
|---|---|
| project_id | 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`). |
| network_url | 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>). |
| port | Port to match traffic on for firewall rules. |
| protocol | Protocol to match traffic on for firewall rules. |
| network_tags | Network tags on GCP VM instance to match rules based on target tag (optional). |
Outputs
| Path | Description | Type |
|---|---|---|
| GCPOffendingFirewallRule | One or more potential offending firewall rules in GCP based on port, protocol and possibly target tags (network tags). | Unknown |