Пример #1
0
    def add_by_arn_and_access_level(self,
                                    arn_list,
                                    access_level,
                                    conditions_block=None):
        """
        This adds the user-supplied ARN(s), service prefixes, access levels, and condition keys (if applicable) given
        by the user. It derives the list of IAM actions based on the user's requested ARNs and access levels.

        Arguments:
            arn_list: Just a list of resource ARNs.
            access_level: "Read", "List", "Tagging", "Write", or "Permissions management"
            conditions_block: Optionally, a condition block with one or more conditions
        """
        for arn in arn_list:
            service_prefix = get_service_from_arn(arn)
            service_action_data = get_action_data(service_prefix, "*")
            for service_prefix in service_action_data:
                for row in service_action_data[service_prefix]:
                    if (does_arn_match(arn, row["resource_arn_format"])
                            and row["access_level"] == access_level):
                        raw_arn_format = row["resource_arn_format"]
                        resource_type_name = get_resource_type_name_with_raw_arn(
                            raw_arn_format)
                        sid_namespace = create_policy_sid_namespace(
                            service_prefix, access_level, resource_type_name)
                        actions = get_actions_with_arn_type_and_access_level(
                            service_prefix, resource_type_name, access_level)
                        # Make supplied actions lowercase
                        # supplied_actions = [x.lower() for x in actions]
                        supplied_actions = actions.copy()
                        dependent_actions = get_dependent_actions(
                            supplied_actions)
                        # List comprehension to get all dependent actions that are not in the supplied actions.
                        dependent_actions = [
                            x for x in dependent_actions
                            if x not in supplied_actions
                        ]
                        if len(dependent_actions) > 0:
                            for dep_action in dependent_actions:
                                self.add_action_without_resource_constraint(
                                    dep_action)
                                # self.add_action_without_resource_constraint(
                                #     str.lower(dep_action)
                                # )

                        temp_sid_dict = {
                            "arn": [arn],
                            "service": service_prefix,
                            "access_level": access_level,
                            "arn_format": raw_arn_format,
                            "actions": actions,
                            "conditions": [],  # TODO: Add conditions
                        }
                        if sid_namespace in self.sids.keys():
                            # If the ARN already exists there, skip it.
                            if arn not in self.sids[sid_namespace]["arn"]:
                                self.sids[sid_namespace]["arn"].append(arn)
                        # If it did not exist before at all, create it.
                        else:
                            self.sids[sid_namespace] = temp_sid_dict
Пример #2
0
def get_actions_matching_arn(arn):
    """
    Given a user-supplied ARN, get a list of all actions that correspond to that ARN.

    Arguments:
        arn: A user-supplied arn
    Returns:
        List: A list of all actions that can match it.
    """
    raw_arns = get_matching_raw_arns(arn)
    results = []
    for raw_arn in raw_arns:
        resource_type_name = get_resource_type_name_with_raw_arn(raw_arn)
        service_prefix = get_service_from_arn(raw_arn)
        service_prefix_data = get_service_prefix_data(service_prefix)
        for action_name, action_data in service_prefix_data[
                "privileges"].items():
            # for some_action in service_prefix_data["privileges"]:
            for resource_name, resource_data in action_data[
                    "resource_types"].items():
                this_resource_type = resource_data["resource_type"].strip("*")
                if this_resource_type.lower() == resource_type_name.lower():
                    results.append(
                        f"{service_prefix}:{action_data['privilege']}")
    results = list(dict.fromkeys(results))
    results.sort()
    return results
Пример #3
0
def get_actions_matching_condition_crud_and_arn(db_session, condition_key,
                                                access_level, raw_arn):
    """
    Get a list of IAM Actions matching a condition key, CRUD level, and raw ARN format.

    :param db_session: SQL Alchemy database session
    :param condition_key: A condition key, like aws:TagKeys
    :param access_level: Access level that matches the database value. "Read", "Write", "List", "Tagging", or "Permissions management"
    :param raw_arn: The raw ARN format in the database, like arn:${Partition}:s3:::${BucketName}
    :return: List of IAM Actions
    """
    actions_list = []
    looking_for = "%{0}%".format(condition_key)
    if raw_arn == "*":
        rows = db_session.query(ActionTable).filter(
            and_(
                # ActionTable.service.ilike(service),
                ActionTable.access_level.ilike(access_level),
                ActionTable.resource_arn_format.is_(raw_arn),
                ActionTable.condition_keys.ilike(looking_for),
            ))
    else:
        service = get_service_from_arn(raw_arn)
        rows = db_session.query(ActionTable).filter(
            and_(
                ActionTable.service.ilike(service),
                ActionTable.access_level.ilike(access_level),
                ActionTable.resource_arn_format.ilike(raw_arn),
                ActionTable.condition_keys.ilike(looking_for),
            ))

    for row in rows:
        action = get_full_action_name(row.service, row.name)
        actions_list.append(action)
    return actions_list
Пример #4
0
    def add(self, db_session, arn_list_from_user, access_level):
        """
        This just adds the ARN, Service, and Access Level. ARN Format and Actions are not filled out.
        Example data can be found in the class ArnActionGroupTestCase in the testing folder.

        :param db_session: SQLAlchemy database session
        :param arn_list_from_user: Just a list of resource ARNs.
        :param access_level: "Read", "List", "Tagging", "Write", or "Permissions management"
        """
        for arn_from_user in arn_list_from_user:
            service = get_service_from_arn(arn_from_user)
            for row in db_session.query(ActionTable).filter(
                    ActionTable.service.like(service)):
                if does_arn_match(arn_from_user, row.resource_arn_format):
                    if row.access_level == access_level:
                        # If it's not a key in the dictionary, add it as a key
                        # and then add the item in the list
                        raw_arn_format = row.resource_arn_format
                        temp_arn_dict = {
                            'arn': arn_from_user,
                            'service': service,
                            'access_level': access_level,
                            'arn_format': raw_arn_format,
                            'actions': []
                        }

                        # If there is already an entry, skip it to avoid duplicates
                        # Otherwise, add it
                        if temp_arn_dict in self.arns:
                            continue
                        self.arns.append(copy.deepcopy(temp_arn_dict))
Пример #5
0
def build_arn_table(db_session, service):
    """
    Builds the ARN Table - the table of resource types - in the SQLite database.

    :param db_session: SQLAlchemy database session.
    :param service: The AWS service prefix
    """
    directory = os.path.abspath(os.path.dirname(__file__)) + "/data/docs/"
    html_list = get_html(directory, service)
    for df_list in html_list:
        for df in df_list:  # pylint: disable=invalid-name
            table = json.loads(df.to_json(orient="split"))
            table_data = df
            if "Resource Types" in table_data and "ARN" in table_data:
                for i in range(len(table["data"])):
                    # Replace the random spaces in the ARN
                    temp_raw_arn = table["data"][i][1].replace(" ", "")
                    # Handle resource ARN path
                    if get_resource_path_from_arn(temp_raw_arn):
                        resource_path = get_resource_path_from_arn(temp_raw_arn)
                    else:
                        resource_path = ""
                    # Handle condition keys
                    if table["data"][i][2] is None:
                        condition_keys = None
                    # If there are multiple condition keys, make them comma separated
                    # Otherwise, if we ingest them as-is, it will show up as
                    # two spaces
                    elif "  " in table["data"][i][2]:
                        condition_keys = get_comma_separated_condition_keys(
                            table["data"][i][2]
                        )
                    else:
                        condition_keys = table["data"][i][2]
                    db_session.add(
                        ArnTable(
                            resource_type_name=table["data"][i][0],
                            raw_arn=str(temp_raw_arn),
                            arn="arn",
                            partition=get_partition_from_arn(temp_raw_arn),
                            service=get_service_from_arn(temp_raw_arn),
                            region=get_region_from_arn(temp_raw_arn),
                            account=get_account_from_arn(temp_raw_arn),
                            resource=get_resource_from_arn(temp_raw_arn),
                            resource_path=resource_path,
                            condition_keys=condition_keys,
                        )
                    )
                    db_session.commit()
Пример #6
0
def get_actions_matching_arn(arn):
    """Given a user-supplied arn, get a list of all actions that can match it."""
    raw_arn = get_matching_raw_arn(arn)
    resource_type_name = get_resource_type_name_with_raw_arn(raw_arn)
    service_prefix = get_service_from_arn(raw_arn)
    service_prefix_data = get_service_prefix_data(service_prefix)
    results = []
    for some_action in service_prefix_data["privileges"]:
        for some_resource_type in some_action["resource_types"]:
            this_resource_type = some_resource_type["resource_type"].strip("*")
            if this_resource_type.lower() == resource_type_name.lower():
                results.append(f"{service_prefix}:{some_action['privilege']}")
    results = list(dict.fromkeys(results))
    results.sort()
    return results
Пример #7
0
def get_matching_raw_arn(arn):
    """
    Given a user-supplied ARN, return the raw_arn since that is used as a unique identifier throughout this library

    :param arn: The user-supplied arn, like arn:aws:s3:::mybucket
    :return: The raw ARN stored in the database, like 'arn:${Partition}:s3:::${BucketName}'
    """
    result = None
    service_in_scope = get_service_from_arn(arn)
    # Determine which resource it applies to
    all_raw_arns_for_service = get_raw_arns_for_service(service_in_scope)
    # Get the raw ARN specific to the provided one
    for raw_arn in all_raw_arns_for_service:
        if does_arn_match(arn, raw_arn):
            result = raw_arn
    return result
Пример #8
0
def validate_user_or_principal_arn(arn: str):
    if arn.strip('"').strip("'") == "*":
        return True
    else:
        service = get_service_from_arn(arn)
        resource_type = parse_arn_for_resource_type(arn)
        # Make sure it is an IAM ARN
        if service != "iam":
            raise Exception(
                "Please supply a valid IAM principal ARN (a user or a role)")
        # Make sure that it is a user or a role
        elif resource_type not in ["user", "role"]:
            raise Exception(
                "Please supply a valid IAM principal ARN (a user or a role)")
        else:
            return True
Пример #9
0
def get_matching_raw_arns(arn):
    """
    Given a user-supplied ARN, return the list of raw_arns since that is used as a unique identifier throughout this library

    Arguments:
        arn: The user-supplied arn, like arn:aws:s3:::mybucket
    Returns:
        list(str): The list of raw ARNs stored in the database, like 'arn:${Partition}:s3:::${BucketName}'
    """
    result = []
    service_in_scope = get_service_from_arn(arn)
    # Determine which resource it applies to
    all_raw_arns_for_service = get_raw_arns_for_service(service_in_scope)
    # Get the raw ARN specific to the provided one
    for raw_arn in all_raw_arns_for_service:
        if does_arn_match(arn, raw_arn) and raw_arn not in result:
            result.append(raw_arn)
    return result