async def get_resources_from_events( policy_changes: List[Dict]) -> Dict[str, dict]: """Returns a dict of resources affected by a list of policy changes along with the actions and other data points that are relevant to them. Returned dict format: { "resource_name": { "actions": ["service1:action1", "service2:action2"], "arns": ["arn:aws:service1:::resource_name", "arn:aws:service1:::resource_name/*"], "account": "1234567890", "type": "service1", "region": "", } } """ def default_resource(): return { "actions": [], "arns": [], "account": "", "type": "", "region": "" } resource_actions: Dict[str, Dict] = defaultdict(default_resource) for event in policy_changes: for policy_type in ["inline_policies", "managed_policies"]: for policy in event.get(policy_type, []): policy_document = policy["policy_document"] for statement in policy_document.get("Statement", []): resources = statement.get("Resource", []) resources = (resources if isinstance(resources, list) else [resources]) for resource in resources: if resource == "*": continue resource_name = get_resource_from_arn(resource) if resource_name == "*": continue if not resource_actions[resource_name]["account"]: resource_actions[resource_name][ "account"] = await get_resource_account( resource) if not resource_actions[resource_name]["type"]: resource_actions[resource_name][ "type"] = get_service_from_arn(resource) if not resource_actions[resource_name]["region"]: resource_actions[resource_name][ "region"] = get_region_from_arn(resource) resource_actions[resource_name]["arns"].append( resource) actions = get_actions_for_resource(resource, statement) resource_actions[resource_name]["actions"].extend( x for x in actions if x not in resource_actions[resource_name]["actions"]) return dict(resource_actions)
def get_actions_for_resource(resource_arn: str, statement: Dict) -> List[str]: """For the given resource and policy statement, return the actions that are for that resource's service. """ results: List[str] = [] # Get service from resource resource_service = get_service_from_arn(resource_arn) # Get relevant actions from policy doc actions = statement.get("Action", []) actions = actions if isinstance(actions, list) else [actions] for action in actions: if action == "*": results.append(action) else: if get_service_from_action(action) == resource_service: if action not in results: results.append(action) return results