| 6 | |
| 7 | |
| 8 | class CloudCheck(BaseInterceptModule): |
| 9 | watched_events = ["*"] |
| 10 | meta = { |
| 11 | "description": "Tag events by cloud provider, identify cloud resources like storage buckets", |
| 12 | "created_date": "2024-07-07", |
| 13 | "author": "@TheTechromancer", |
| 14 | } |
| 15 | # tag events up to and including distance-2 |
| 16 | scope_distance_modifier = 2 |
| 17 | _priority = 3 |
| 18 | |
| 19 | async def setup(self): |
| 20 | self._cloud_hostname_regexes = None |
| 21 | self._cloud_hostname_regexes_lock = asyncio.Lock() |
| 22 | # perform a test lookup during setup to force signature update |
| 23 | await self.helpers.cloudcheck.lookup("8.8.8.8") |
| 24 | return True |
| 25 | |
| 26 | async def filter_event(self, event): |
| 27 | if (not event.host) or (event.type in ("IP_RANGE",)): |
| 28 | return False, "event does not have host attribute" |
| 29 | return True |
| 30 | |
| 31 | async def handle_event(self, event, **kwargs): |
| 32 | # cloud tagging by hosts |
| 33 | hosts_to_check = set(event.resolved_hosts) |
| 34 | with suppress(KeyError): |
| 35 | hosts_to_check.remove(event.host_original) |
| 36 | hosts_to_check = [str(event.host_original)] + list(hosts_to_check) |
| 37 | |
| 38 | for i, host in enumerate(hosts_to_check): |
| 39 | host_is_ip = self.helpers.is_ip(host) |
| 40 | try: |
| 41 | cloudcheck_results = await self.helpers.cloudcheck.lookup(host) |
| 42 | except Exception as e: |
| 43 | self.warning(f"Error running cloudcheck against {event} (host: {host}): {e}") |
| 44 | continue |
| 45 | for provider in cloudcheck_results: |
| 46 | provider_name = provider["name"].lower() |
| 47 | tags = provider.get("tags", []) |
| 48 | for tag in tags: |
| 49 | event.add_tag(tag) |
| 50 | event.add_tag(f"{tag}-{provider_name}") |
| 51 | if host_is_ip: |
| 52 | event.add_tag(f"{provider_name}-ip") |
| 53 | else: |
| 54 | # if the original hostname is a cloud domain, tag it as such |
| 55 | if i == 0: |
| 56 | event.add_tag(f"{provider_name}-domain") |
| 57 | # any children are tagged as CNAMEs |
| 58 | else: |
| 59 | event.add_tag(f"{provider_name}-cname") |
| 60 | |
| 61 | # we only generate storage buckets off of in-scope or distance-1 events |
| 62 | if event.scope_distance >= self.max_scope_distance: |
| 63 | return |
| 64 | |
| 65 | # see if any of our hosts are storage buckets, etc. |
no outgoing calls
no test coverage detected
searching dependent graphs…