def transitive(self): instances = self.get( "AWS::Ec2::Instance").get( "Resource") functions = self.get( "AWS::Lambda::Function").get( "Resource") roles = self.get( "AWS::Iam::Role").get( "Resource") instance_profiles = self.get( "AWS::Iam::InstanceProfile").get( "Resource") # Instance - [TRANSITIVE] -> Iam Instance Profile for instance in instances: if "IamInstanceProfile" not in instance.properties(): continue target = next((ip for ip in instance_profiles if ip.id() == instance.properties()["IamInstanceProfile"]["Arn"]), None) del instance.properties()["IamInstanceProfile"] self.add(Transitive( {"Name": "Attached"}, source=instance, target=target)) # Lambda - [TRANSITIVE] -> Role for function in functions: if "Role" not in function.properties(): continue role = next((r for r in roles if r.id() == function.properties()["Role"]), None) del function.properties()["Role"] self.add(Transitive( {"Name": "Attached"}, source=function, target=role))
def get_account_authorization_details(self, only_arns, except_arns): elements = Elements() edges = {"Groups": [], "Policies": [], "InstanceProfiles": []} def get_aad_element(label, entry): properties = dict() for pk, pv in sorted(entry.items()): if pk.endswith("PolicyList"): properties["Documents"] = [{ p["PolicyName"]: p["PolicyDocument"] for p in pv }] elif pk == "AssumeRolePolicyDocument": properties["Trusts"] = pv elif pk in [ "GroupList", "InstanceProfileList", "AttachedManagedPolicies" ]: continue elif pk == "PolicyVersionList": properties["Document"] = [{ "DefaultVersion": [p for p in pv if p["IsDefaultVersion"]][0]["Document"] }] else: properties[pk.replace(label, "")] = pv element = Resource(properties=properties, labels=["Resource", f"AWS::Iam::{label}"]) if f"AWS::Iam::Group" in self.run and "GroupList" in entry.keys(): edges["Groups"].extend([(element, g) for g in entry["GroupList"]]) if f"AWS::Iam::InstanceProfile" in self.run \ and "InstanceProfileList" in entry.keys(): edges["InstanceProfiles"].extend([ (get_aad_element("InstanceProfile", ip), element) for ip in entry["InstanceProfileList"] ]) if f"AWS::Iam::Policy" in self.run \ and "AttachedManagedPolicies" in entry.keys(): edges["Policies"].extend([ (element, p["PolicyArn"]) for p in entry["AttachedManagedPolicies"] ]) if (str(f"AWS::Iam::{label}") in self.run and (len(except_arns) == 0 or properties["Arn"] not in except_arns) and (len(only_arns) == 0 or properties["Arn"] in only_arns) and element not in elements): self._print(f"[*] Adding {element}") elements.append(element) return element account_authorization_details = [ aad for aad in self.client.get_paginator( "get_account_authorization_details").paginate() ] account_authorization_details = [ (label.replace("DetailList", "").replace("Policies", "Policy"), entry) for aad in account_authorization_details for (label, v) in aad.items() if isinstance(v, list) for entry in v ] for label, entry in account_authorization_details: get_aad_element(label, entry) # Ensure edge nodes exist for k, v in edges.items(): edges[k] = list( filter(lambda e: e[0] is not None and e[1] is not None, [ e if type(e[1]) == Resource else (e[0], next((t for t in elements if (k == "Groups" and str(t).endswith(str(e[1]))) or str(t) == str(e[1])), None)) for e in v ])) # (:User|Group|Role)-[:TRANSITIVE{Attached}]->(:Policy) for (s, t) in edges["Policies"]: elements.append( Transitive(properties={"Name": "Attached"}, source=s, target=t)) # # (:User)-[:TRANSITIVE{MemberOf}]->(:Group) for (s, t) in edges["Groups"]: elements.append( Transitive(properties={"Name": "MemberOf"}, source=s, target=t)) # (:InstanceProfile)-[:TRANSITIVE{Attached}]->(:Role) for (s, t) in edges["InstanceProfiles"]: del s.properties()["Roles"] elements.append( Transitive(properties={"Name": "Attached"}, source=s, target=t)) return elements
def load_transitives(self): resources = self.get("Resource") groups = resources.get("AWS::Iam::Group") roles = resources.get("AWS::Iam::Role") policies = resources.get("AWS::Iam::Policy") instance_profiles = resources.get("AWS::Iam::InstanceProfile") for resource in self.console.tasklist( "Adding Transitive relationships", iterables=resources, done="Added Transitive relationships", ): if resource.label() in [ "AWS::Iam::User", "AWS::Iam::Group", "AWS::Iam::Role" ]: # (User|Group|Role) --> (Policy) if "AttachedManagedPolicies" in resource.properties(): policy_arns = [ policy["PolicyArn"] for policy in resource.get("AttachedManagedPolicies") ] for policy in filter(lambda r: r.id() in policy_arns, policies): self.add( Transitive(properties={"Name": "Attached"}, source=resource, target=policy)) policy_arns = [ p for p in policy_arns if p != str(policy) ] if not len(policy_arns) > 0: del resource.properties()["AttachedManagedPolicies"] # (User)-->(Group) if (resource.label() in ["AWS::Iam::User"] and "GroupList" in resource.properties()): group_names = resource.get("GroupList") for group in filter(lambda r: r.get("Name") in group_names, groups): self.add( Transitive(properties={"Name": "Attached"}, source=resource, target=group)) group_names = [ g for g in group_names if g != str(group) ] if not len(group_names) > 0: del resource.properties()["GroupList"] # (Instance) --> (Instance Profile) if (resource.label() in ["AWS::Ec2::Instance"] and "IamInstanceProfile" in resource.properties()): instance_profile = next( (i for i in instance_profiles if str(i) == resource.get("IamInstanceProfile")["Arn"]), None) if instance_profile is not None: self.add( Transitive({"Name": "Attached"}, source=resource, target=instance_profile)) del resource.properties()["IamInstanceProfile"] # (InstanceProfile) --> (Role) if (resource.label() in ["AWS::Iam::InstanceProfile"] and "Roles" in resource.properties()): role_arns = list(map(lambda r: r["Arn"], resource.get("Roles"))) for role in filter(lambda r: r.id() in role_arns, roles): self.add( Transitive(properties={"Name": "Attached"}, source=resource, target=role)) role_arns = [r for r in role_arns if r != str(role)] if not len(role_arns) > 0: del resource.properties()["Roles"] # (Function) --> (Role) if (resource.label() in ["AWS::Lambda::Function"] and "Role" in resource.properties()): role = next( (r for r in roles if str(r) == resource.get("Role")), None) if role is not None: self.add( Transitive(properties={"Name": "Attached"}, source=resource, target=role)) del resource.properties()["Role"]
def get_account_authorization_details(self): elements = Elements() edges = {"Groups": [], "Policies": [], "InstanceProfiles": []} def get_aad_element(label, entry): properties = dict() for pk, pv in sorted(entry.items()): if pk.endswith("PolicyList"): properties["Documents"] = [{ p["PolicyName"]: p["PolicyDocument"] for p in pv }] elif pk == "AssumeRolePolicyDocument": properties["Trusts"] = pv elif pk in [ "GroupList", "InstanceProfileList", "AttachedManagedPolicies" ]: continue elif pk == "PolicyVersionList": properties["Document"] = [{ "DefaultVersion": [p for p in pv if p["IsDefaultVersion"]][0]["Document"] }] else: properties[pk.replace(label, "")] = pv element = Resource(properties=properties, labels=["Resource", "AWS::Iam::%s" % label]) if "GroupList" in entry.keys(): edges["Groups"].extend([(element, g) for g in entry["GroupList"]]) if "InstanceProfileList" in entry.keys(): edges["InstanceProfiles"].extend([ (get_aad_element("InstanceProfile", ip), element) for ip in entry["InstanceProfileList"] ]) if "AttachedManagedPolicies" in entry.keys(): edges["Policies"].extend([ (element, p["PolicyArn"]) for p in entry["AttachedManagedPolicies"] ]) if element not in elements: print(f" \-> Adding {element}") elements.append(element) return element account_authorization_details = [ aad for aad in self.client.get_paginator( "get_account_authorization_details").paginate() ] account_authorization_details = [ (label.replace("DetailList", "").replace("Policies", "Policy"), entry) for aad in account_authorization_details for (label, v) in aad.items() if isinstance(v, list) for entry in v ] for label, entry in account_authorization_details: get_aad_element(label, entry) # User|Group|Role - Attached -> Policy for (s, t) in edges["Policies"]: t = next(entry for entry in elements if entry.id() == t) elements.append( Transitive(properties={"Name": "Attached"}, source=s, target=t)) # User - [MemberOf] -> Group for (s, t) in edges["Groups"]: t = next(entry for entry in elements.get("AWS::Iam::Group") if str(entry).endswith(t)) elements.append( Transitive(properties={"Name": "MemberOf"}, source=s, target=t)) # InstanceProfile - [Attached] -> Role for (s, t) in edges["InstanceProfiles"]: del s.properties()["Roles"] elements.append( Transitive(properties={"Name": "Attached"}, source=s, target=t)) return elements