Exemple #1
0
    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
Exemple #2
0
    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