def _get_principals(self): '''https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_principal.html''' principals = Elements() key = list(filter(lambda x: "Principal" in x, self.__statement.keys()))[0] statement = self.__statement[key] if isinstance(statement, str) and statement == "*": statement = {"AWS": "*"} assert isinstance(statement, dict) if "AWS" in statement: if not isinstance(statement["AWS"], list): statement["AWS"] = [statement["AWS"]] if '*' in statement["AWS"]: external = External( key="Arn", labels=["AWS::Account"], properties={ "Name": "All AWS Accounts", "Description": "Pseudo-Account representing anyone who possesses an AWS account", "Arn": "arn:aws:iam::{Account}:root" }) principals = Elements([ *self.__resources.get('AWS::Iam::User').get("Resource"), *self.__resources.get('AWS::Iam::Role').get("Resource"), external ]) for principal in [ p for p in statement["AWS"] if '*' not in statement["AWS"] ]: if '*' in principal: continue node = next((a for a in self.__resources.get("Resource") if a.id() == principal), None) # We haven't seen this node before. It may belong to another account, # or it belongs to a service that was not loaded. if node is None: name = principal labels = ["AWS::Account"] if re.compile(f"^{RESOURCES.regex['Account']}$").match( principal) is not None: principal = f"arn:aws:iam::{principal}:root" labels += ["AWS::Account"] elif re.compile( f"^arn:aws:iam::{RESOURCES.regex['Account']}:root$" ).match(principal) is not None: name = str(principal.split(":")[4]) labels += ["AWS::Account"] else: for k, v in RESOURCES.items(): if re.compile(v).match(principal): name = principal.replace('/', ':').split(':')[-1] labels = [k] break node = External( key=str("Arn" if principal. startswith("arn") else "CanonicalUser"), labels=labels, properties={ "Name": str(name), str("Arn" if principal.startswith("arn") else "CanonicalUser"): principal, }) principals.add(node) elif "Service" in statement: services = statement["Service"] if isinstance( statement["Service"], list) else [statement["Service"]] for service in services: if service.lower().endswith("amazonaws.com"): labels = ["AWS::Domain"] else: labels = ["Internet::Domain"] principals.add( External(key="Name", labels=labels, properties={"Name": service})) elif "Federated" in statement: node = None labels = [] statements = statement["Federated"] \ if isinstance(statement["Federated"], list) \ else [statement["Federated"]] for federated in statements: if re.compile(RESOURCES["AWS::Iam::SamlProvider"]).match( federated) is not None: base = Resource if (next( (a for a in self.__resources.get("Resoure") if a.account() == federated.split(':')[4]), False)) else External node = base(key="Arn", labels=["AWS::Iam::SamlProvider"], properties={ "Name": federated.split('/')[-1], "Arn": federated }) elif re.compile( "^(?=.{1,253}\.?$)(?:(?!-|[^.]+_)[A-Za-z0-9-_]{1,63}(?<!-)(?:\.|$)){2,}$" ).match(federated): node = External(key="Name", labels=["Internet::Domain"], properties={"Name": federated}) else: node = External(key="Name", properties={ "Name": federated, }) principals.add(node) # TODO: elif "CanonicalUser" in statement: principals.add( External(key="CanonicalUser", labels=["AWS::Account"], properties={ "Name": statement["CanonicalUser"], "CanonicalUser": statement["CanonicalUser"], })) else: console.warn("Unknown principal: ", statement) return principals
def _resolve_principal_statement(self): principals = Elements() key = list(filter(lambda x: "Principal" in x, self._statement.keys()))[0] statement = self._statement[key] if isinstance(statement, str) and statement == "*": statement = {"AWS": "*"} if not isinstance(statement, dict): raise ValueError if "AWS" in statement: if not isinstance(statement["AWS"], list): statement["AWS"] = [statement["AWS"]] if '*' in statement["AWS"]: principals = self._resources.get('AWS::Iam::User').get( "Resource") + self._resources.get('AWS::Iam::Role').get( "Resource") + [ External(key="Arn", labels=["AWS::Account"], properties={ "Name": "All AWS Accounts", "Arn": "arn:aws:iam::{Account}:root" }) ] for principal in [ p for p in statement["AWS"] if '*' not in statement["AWS"] ]: if '*' in principal: continue node = next( (a for a in self._resources if a.id() == principal), None) # We haven't seen this node before. It may belong to another account, # or it belongs to a service that was not loaded. if node is None: name = principal labels = [] if re.compile("^%s$" % RESOURCES.regex["Account"]).match( principal) is not None: labels += ["AWS::Account"] principal = "arn:aws:iam::{Account}:root".format( Account=principal) elif re.compile( "^%s$" % "arn:aws:iam::{Account}:root".format( Account=RESOURCES.regex["Account"])).match( principal) is not None: name = str(principal.split(":")[4]) labels += ["AWS::Account"] else: for k, v in RESOURCES.items(): if re.compile(v).match(principal): name = principal.replace('/', ':').split(':')[-1] labels = [k] break node = External(key="Arn", labels=labels, properties={ "Name": str(name), "Arn": principal }) principals.add(node) elif "Service" in statement: services = statement["Service"] if isinstance( statement["Service"], list) else [statement["Service"]] for service in services: if service.endswith("amazonaws.com"): labels = ["AWS::Domain"] else: labels = ["Internet::Domain"] principals.add( External(labels=labels, properties={"Name": service})) elif "Federated" in statement: node = None labels = [] if re.compile(RESOURCES["AWS::Iam::SamlProvider"]).match( statement["Federated"]) is not None: base = Resource if (next( (a for a in self._resources if a.id().split(':')[4] == statement["Federated"].split( ':')[4]), False)) else External node = base(key="Arn", labels=["AWS::Iam::SamlProvider"], properties={ "Name": statement["Federated"].split('/')[-1], "Arn": statement["Federated"] }) elif re.compile( "^(?=.{1,253}\.?$)(?:(?!-|[^.]+_)[A-Za-z0-9-_]{1,63}(?<!-)(?:\.|$)){2,}$" ).match(statement["Federated"]): node = External(labels=["Internet::Domain"], properties={"Name": statement["Federated"]}) else: node = External(properties={ "Name": statement["Federated"], }) principals.add(node) # TODO: elif "CanonicalUser" in statement: principals.add( External(labels=["AWS::Account"], properties={ "Name": statement["CanonicalUser"], "CanonicalUser": statement["CanonicalUser"], "Arn": "" })) else: print("Unknown pricipal: ", statement) self._explicit_principals = principals