Example #1
0
 def test_get_action_data(self):
     """test_get_action_data: Tests function that gets details on a specific IAM Action."""
     desired_output = {
         "ram": [{
             "action":
             "ram:createresourceshare",
             "description":
             "Create resource share with provided resource(s) and/or principal(s)",
             "access_level":
             "Permissions management",
             "resource_arn_format":
             "*",
             "condition_keys": [
                 "aws:RequestTag/${TagKey}", "aws:TagKeys",
                 "ram:RequestedResourceType", "ram:ResourceArn",
                 "ram:RequestedAllowsExternalPrincipals", "ram:Principal"
             ],
             "dependent_actions":
             None
         }]
     }
     output = get_action_data(db_session, 'ram', 'createresourceshare')
     print(json.dumps(output, indent=4))
     self.maxDiff = None
     self.assertDictEqual(desired_output, output)
Example #2
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
Example #3
0
 def test_get_action_data(self):
     """querying.actions.test_get_action_data"""
     desired_output = {
         "ram": [
             {
                 "action": "ram:TagResource",
                 "description": "Tag the specified resources share",
                 "access_level": "Tagging",
                 "resource_arn_format": "arn:${Partition}:ram:${Region}:${Account}:resource-share/${ResourcePath}",
                 "condition_keys": [
                     "aws:ResourceTag/${TagKey}",
                     "ram:AllowsExternalPrincipals",
                     "ram:ResourceShareName"
                 ],
                 "dependent_actions": []
             },
             {
                 "action": "ram:TagResource",
                 "description": "Tag the specified resources share",
                 "access_level": "Tagging",
                 "resource_arn_format": "*",
                 "condition_keys": [
                     "aws:ResourceTag/${TagKey}",
                     "ram:AllowsExternalPrincipals",
                     "ram:ResourceShareName"
                 ],
                 "dependent_actions": []
             }
         ]
     }
     output = get_action_data("ram", "TagResource")
     # print(json.dumps(output, indent=4))
     self.maxDiff = None
     self.assertDictEqual(desired_output, output)
Example #4
0
def remove_wildcard_only_actions(actions_list):
    """Given a list of actions, remove the ones that CANNOT be restricted to ARNs, leaving only the ones that CAN."""
    try:
        actions_list_unique = list(dict.fromkeys(actions_list))
    except TypeError as t_e:  # pragma: no cover
        print(t_e)
        return []
    results = []
    for action in actions_list_unique:
        service_prefix, action_name = action.split(":")
        if service_prefix not in all_service_prefixes:
            continue  # pragma: no cover
        action_data = get_action_data(service_prefix, action_name)

        if len(action_data[service_prefix]) == 0:
            pass  # pragma: no cover
        elif len(action_data[service_prefix]) == 1:
            if action_data[service_prefix][0]["resource_arn_format"] == "*":
                pass
            else:
                # Let's return the CamelCase action name format
                results.append(action_data[service_prefix][0]["action"])
        else:
            results.append(action_data[service_prefix][0]["action"])
    return results
Example #5
0
 def test_get_action_data(self):
     """querying.actions.test_get_action_data"""
     desired_output = {
         "ram": [
             {
                 "action": "ram:createresourceshare",
                 "description": "Create resource share with provided resource(s) and/or principal(s)",
                 "access_level": "Permissions management",
                 "resource_arn_format": "*",
                 "condition_keys": [
                     "aws:RequestTag/${TagKey}",
                     "aws:TagKeys",
                     "ram:RequestedResourceType",
                     "ram:ResourceArn",
                     "ram:RequestedAllowsExternalPrincipals",
                     "ram:Principal",
                 ],
                 "dependent_actions": None,
             }
         ]
     }
     output = get_action_data(db_session, "ram", "createresourceshare")
     # print(json.dumps(output, indent=4))
     self.maxDiff = None
     self.assertDictEqual(desired_output, output)
Example #6
0
def get_actions_from_policy(data):
    """Given a policy dictionary, create a list of the actions"""
    actions_list = []
    statement_clause = data.get("Statement")
    # Statement must be a dict if it's a single statement. Otherwise it will be a list of statements
    if isinstance(statement_clause, dict):
        actions_list.extend(get_actions_from_statement(statement_clause))
    # Otherwise it will be a list of Sids
    elif isinstance(statement_clause, list):
        for statement in data["Statement"]:
            actions_list.extend(get_actions_from_statement(statement))
    else:
        logger.critical("Unknown error: The 'Statement' is neither a dict nor a list")
    actions_list = [x.lower() for x in actions_list]

    new_actions_list = []
    for action in actions_list:
        service, action_name = action.split(":")
        action_data = get_action_data(service, action_name)
        if service in action_data.keys():
            if len(action_data[service]) > 0:
                new_actions_list.append(action_data[service][0]["action"])

    new_actions_list.sort()
    return new_actions_list
Example #7
0
def action_table(name, service, access_level, condition, wildcard_only):
    """Query the Action Table from the Policy Sentry database"""
    db_session = connect_db(DATABASE_FILE_PATH)
    # Actions on all services
    if service == "all":
        all_services = get_all_service_prefixes(db_session)
        if access_level:
            level = transform_access_level_text(access_level)
            print(f"{access_level} actions across ALL services:\n")
            results = []
            for serv in all_services:
                output = get_actions_with_access_level(db_session, serv, level)
                results.extend(output)
            for result in results:
                print(result)
        # Get a list of all services in the database
        else:
            print("All services in the database:\n")
            for item in all_services:
                print(item)
    elif name is None and access_level:
        print(
            f"All IAM actions under the {service} service that have the access level {access_level}:"
        )
        level = transform_access_level_text(access_level)
        output = get_actions_with_access_level(db_session, service, level)
        print(json.dumps(output, indent=4))
    # Get a list of all IAM actions under the service that support the
    # specified condition key.
    elif condition:
        print(
            f"IAM actions under {service} service that support the {condition} condition only:"
        )
        output = get_actions_matching_condition_key(db_session, service,
                                                    condition)
        print(json.dumps(output, indent=4))
    # Get a list of IAM Actions under the service that only support resources = "*"
    # (i.e., you cannot restrict it according to ARN)
    elif wildcard_only:
        print(
            f"IAM actions under {service} service that support wildcard resource values only:"
        )
        output = get_actions_that_support_wildcard_arns_only(
            db_session, service)
        print(json.dumps(output, indent=4))
    elif name and access_level is None:
        output = get_action_data(db_session, service, name)
        print(json.dumps(output, indent=4))
    else:
        print(f"All IAM actions available to {service}:")
        # Get a list of all IAM Actions available to the service
        action_list = get_actions_for_service(db_session, service)
        print(f"ALL {service} actions:")
        for item in action_list:
            print(item)
Example #8
0
    def add_sts_actions(self, sts_actions):
        """
        To add STS actions to the output from special YAML section
        """
        if sts_actions:
            # Hard coded for this special case
            service_prefix = "sts"
            access_level = "Write"

            for action, arns in sts_actions.items():
                clean_action = action.replace(
                    '-', ''
                )  # Convention to follow adding dashes instead of CamelCase
                service_action_data = get_action_data(service_prefix,
                                                      clean_action)

                # Schema validation takes care of this, but just in case. No data returned for the action
                if not service_action_data:
                    raise Exception(
                        f"Could not find service action data for {service_prefix} - {clean_action}"
                    )

                for row in service_action_data[service_prefix]:
                    for arn in arns:
                        if not arn:  # skip the - '' situation
                            continue
                        if (does_arn_match(arn, row["resource_arn_format"])
                                and row["access_level"] == access_level):
                            raw_arn_format = row["resource_arn_format"]

                            # Each action will get its own namespace sts:AssumeRole -> AssumeRole
                            # -1 index is a neat trick if the colon ever goes away we won't get an index error.
                            sid_namespace = row["action"].split(':')[-1]

                            temp_sid_dict = {
                                "arn": [arn],
                                "service": service_prefix,
                                "access_level": access_level,
                                "arn_format": raw_arn_format,
                                "actions": [row["action"]],
                                "conditions": [],  # TODO: Add conditions
                            }

                        # Using a custom namespace and not gathering actions so no need to find
                        # dependent actions either, though we could do it here

                        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)
                        else:
                            self.sids[sid_namespace] = temp_sid_dict
Example #9
0
def get_conditions_for_action_and_raw_arn(action, raw_arn):
    """
    Get a list of conditions available to an action.

    :param action: The IAM action, like s3:GetObject
    :param raw_arn: The raw ARN format specific to the action
    :return:
    """
    service_prefix, action_name = action.split(":")
    action_data = get_action_data(service_prefix, action_name)
    conditions = []
    for action_info in action_data[service_prefix]:
        if action_info["resource_arn_format"].lower() == raw_arn.lower():
            conditions.extend(action_info["condition_keys"])
    return conditions
Example #10
0
 def test_get_action_data(self):
     """test_get_action_data: Tests function that gets details on a specific IAM Action."""
     desired_output = {
         'ram': [
             {
                 'action':
                 'ram:createresourceshare',
                 'description':
                 'Create resource share with provided resource(s) and/or principal(s)',
                 'access_level':
                 'Permissions management',
                 'resource_arn_format':
                 'arn:${Partition}:ram:${Region}:${Account}:resource-share/${ResourcePath}',
                 'condition_keys': [
                     'ram:RequestedResourceType',
                     'ram:ResourceArn',
                     # 'ram:AllowsExternalPrincipals',
                     'ram:RequestedAllowsExternalPrincipals'
                 ],
                 'dependent_actions':
                 None
             },
             {
                 'action': 'ram:createresourceshare',
                 'description':
                 'Create resource share with provided resource(s) and/or principal(s)',
                 'access_level': 'Permissions management',
                 'resource_arn_format': '*',
                 'condition_keys':
                 ['aws:RequestTag/${TagKey}', 'aws:TagKeys'],
                 'dependent_actions': None
             }
         ]
     }
     output = get_action_data(db_session, 'ram', 'createresourceshare')
     self.maxDiff = None
     self.assertDictEqual(desired_output, output)
Example #11
0
 def test_get_action_data(self):
     """querying.actions.test_get_action_data"""
     desired_output = {
         "ram": [
             {
                 "action": "ram:TagResource",
                 "description": "Grants permission to tag the specified resource share",
                 "access_level": "Tagging",
                 "api_documentation_link": "https://docs.aws.amazon.com/ram/latest/APIReference/API_TagResource.html",
                 "resource_arn_format": "arn:${Partition}:ram:${Region}:${Account}:resource-share/${ResourcePath}",
                 "condition_keys": [
                     "aws:ResourceTag/${TagKey}",
                     "ram:AllowsExternalPrincipals",
                     "ram:ResourceShareName"
                 ],
                 "dependent_actions": []
             },
             {
                 "action": "ram:TagResource",
                 "description": "Grants permission to tag the specified resource share",
                 "access_level": "Tagging",
                 "api_documentation_link": "https://docs.aws.amazon.com/ram/latest/APIReference/API_TagResource.html",
                 "resource_arn_format": "*",
                 "condition_keys": [
                     "aws:ResourceTag/${TagKey}",
                     "ram:AllowsExternalPrincipals",
                     "ram:ResourceShareName"
                 ],
                 "dependent_actions": []
             }
         ]
     }
     output = get_action_data("ram", "TagResource")
     print(json.dumps(output, indent=4))
     self.maxDiff = None
     self.assertDictEqual(desired_output, output)
Example #12
0
def query_action_table(name,
                       service,
                       access_level,
                       condition,
                       resource_type,
                       fmt="json"):
    """Query the Action Table from the Policy Sentry database.
    Use this one when leveraging Policy Sentry as a library."""
    if os.path.exists(LOCAL_DATASTORE_FILE_PATH):
        logger.info(
            f"Using the Local IAM definition: {LOCAL_DATASTORE_FILE_PATH}. To leverage the bundled definition instead, remove the folder $HOME/.policy_sentry/"
        )
    else:
        # Otherwise, leverage the datastore inside the python package
        logger.debug("Leveraging the bundled IAM Definition.")
    # Actions on all services
    if service == "all":
        all_services = get_all_service_prefixes()
        if access_level:
            level = transform_access_level_text(access_level)
            print(f"{access_level} actions across ALL services:\n")
            output = []
            for serv in all_services:
                result = get_actions_with_access_level(serv, level)
                output.extend(result)
            print(yaml.dump(output)) if fmt == "yaml" else [
                print(result) for result in output
            ]
        # Get a list of all services in the database
        else:
            print("All services in the database:\n")
            output = all_services
            print(yaml.dump(output)) if fmt == "yaml" else [
                print(item) for item in output
            ]
    elif name is None and access_level and not resource_type:
        print(
            f"All IAM actions under the {service} service that have the access level {access_level}:"
        )
        level = transform_access_level_text(access_level)
        output = get_actions_with_access_level(service, level)
        print(yaml.dump(output)) if fmt == "yaml" else [
            print(json.dumps(output, indent=4))
        ]
    elif name is None and access_level and resource_type:
        print(
            f"{service} {access_level.upper()} actions that have the resource type {resource_type.upper()}:"
        )
        access_level = transform_access_level_text(access_level)
        output = get_actions_with_arn_type_and_access_level(
            service, resource_type, access_level)
        print(yaml.dump(output)) if fmt == "yaml" else [
            print(json.dumps(output, indent=4))
        ]
    # Get a list of all IAM actions under the service that support the specified condition key.
    elif condition:
        print(
            f"IAM actions under {service} service that support the {condition} condition only:"
        )
        output = get_actions_matching_condition_key(service, condition)
        print(yaml.dump(output)) if fmt == "yaml" else [
            print(json.dumps(output, indent=4))
        ]
    # Get a list of IAM Actions under the service that only support resources = "*"
    # (i.e., you cannot restrict it according to ARN)
    elif resource_type:
        print(
            f"IAM actions under {service} service that have the resource type {resource_type}:"
        )
        output = get_actions_matching_arn_type(service, resource_type)
        print(yaml.dump(output)) if fmt == "yaml" else [
            print(json.dumps(output, indent=4))
        ]
    elif name and access_level is None:
        output = get_action_data(service, name)
        print(yaml.dump(output)) if fmt == "yaml" else [
            print(json.dumps(output, indent=4))
        ]
    else:
        # Get a list of all IAM Actions available to the service
        output = get_actions_for_service(service)
        print(f"ALL {service} actions:")
        print(yaml.dump(output)) if fmt == "yaml" else [
            print(item) for item in output
        ]
    return output
Example #13
0
    def add_by_list_of_actions(self, db_session, supplied_actions):
        """
        Takes a list of actions, queries the database for corresponding arns, adds them to the object.

        :param db_session: SQLAlchemy database session object
        :param supplied_actions: A list of supplied actions
        """
        # Make supplied actions lowercase
        # supplied_actions = [x.lower() for x in supplied_actions]
        # actions_list = get_dependent_actions(db_session, supplied_actions)
        dependent_actions = get_dependent_actions(db_session, 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
        ]

        arns_matching_supplied_actions = []

        # arns_matching_supplied_actions is a list of dicts.
        # It must do this rather than dictionaries because there will be duplicate
        #     values by nature of how the entries in the IAM database are structured.
        # I'll provide the example values here to improve readability.

        for action in supplied_actions:
            service_name, action_name = action.split(":")
            action_data = get_action_data(db_session, service_name,
                                          action_name)
            for row in action_data[service_name]:
                if row["resource_arn_format"] not in arns_matching_supplied_actions:
                    arns_matching_supplied_actions.append(
                        {
                            "resource_arn_format": row["resource_arn_format"],
                            "access_level": row["access_level"],
                            "action": row["action"],
                        }
                        # [row["resource_arn_format"], row["access_level"], row["action"]])
                    )

        # arns_matching_supplied_actions = [{
        #         "resource_arn_format": "*",
        #         "access_level": "Write",
        #         "action": "kms:createcustomkeystore"
        #     },{
        #         "resource_arn_format": "arn:${Partition}:kms:${Region}:${Account}:key/${KeyId}",
        #         "access_level": "Permissions management",
        #         "action": "kms:creategrant"
        #     },{
        #         "resource_arn_format": "*",
        #         "access_level": "Permissions management",
        #         "action": "kms:creategrant"
        # }]

        # Identify the actions that do not support resource constraints
        # If that's the case, add it to the wildcard namespace. Otherwise, don't add it.

        actions_without_resource_constraints = []
        for item in arns_matching_supplied_actions:
            if item["resource_arn_format"] != "*":
                self.add_by_arn_and_access_level(db_session,
                                                 [item["resource_arn_format"]],
                                                 item["access_level"])
            else:
                actions_without_resource_constraints.append(item["action"])

        # If there are any dependent actions, we need to add them without resource constraints.
        # Otherwise, we get into issues where the amount of extra SIDs will balloon.
        # Also, the user has no way of knowing what those dependent actions are beforehand.
        # TODO: This is, in fact, a great opportunity to introduce conditions. But we aren't there yet.
        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))
        # Now, because add_by_arn_and_access_level() adds all actions under an access level, we have to
        # remove all actions that do not match the supplied_actions. This is done in-place.
        self.remove_actions_not_matching_these(supplied_actions +
                                               dependent_actions)
        for action in actions_without_resource_constraints:
            self.add_action_without_resource_constraint(action)
        self.remove_actions_duplicated_in_wildcard_arn()
        rendered_policy = self.get_rendered_policy(db_session)
        return rendered_policy
Example #14
0
    def add_by_list_of_actions(self, supplied_actions):
        """
        Takes a list of actions, queries the database for corresponding arns, adds them to the object.

        Arguments:
            supplied_actions: A list of supplied actions
        """
        # actions_list = get_dependent_actions(supplied_actions)
        dependent_actions = get_dependent_actions(supplied_actions)
        dependent_actions = [
            x for x in dependent_actions if x not in supplied_actions
        ]
        logger.debug("Adding by list of actions")
        logger.debug(f"Supplied actions: {str(supplied_actions)}")
        logger.debug(f"Dependent actions: {str(dependent_actions)}")
        arns_matching_supplied_actions = []

        # arns_matching_supplied_actions is a list of dicts.
        # It must do this rather than dictionaries because there will be duplicate
        #     values by nature of how the entries in the IAM database are structured.
        # I'll provide the example values here to improve readability.

        for action in supplied_actions:
            service_name, action_name = action.split(":")
            action_data = get_action_data(service_name, action_name)
            for row in action_data[service_name]:
                if row["resource_arn_format"] not in arns_matching_supplied_actions:
                    arns_matching_supplied_actions.append({
                        "resource_arn_format":
                        row["resource_arn_format"],
                        "access_level":
                        row["access_level"],
                        "action":
                        row["action"],
                    })

        # Identify the actions that do not support resource constraints
        # If that's the case, add it to the wildcard namespace. Otherwise, don't add it.

        actions_without_resource_constraints = []
        for item in arns_matching_supplied_actions:
            if item["resource_arn_format"] != "*":
                self.add_by_arn_and_access_level([item["resource_arn_format"]],
                                                 item["access_level"])
            else:
                actions_without_resource_constraints.append(item["action"])

        # If there are any dependent actions, we need to add them without resource constraints.
        # Otherwise, we get into issues where the amount of extra SIDs will balloon.
        # Also, the user has no way of knowing what those dependent actions are beforehand.
        # TODO: This is, in fact, a great opportunity to introduce conditions. But we aren't there yet.
        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))
        # Now, because add_by_arn_and_access_level() adds all actions under an access level, we have to
        # remove all actions that do not match the supplied_actions. This is done in-place.
        logger.debug(
            "Purging actions that do not match the requested actions and dependent actions"
        )
        logger.debug(f"Supplied actions: {str(supplied_actions)}")
        logger.debug(f"Dependent actions: {str(dependent_actions)}")
        self.remove_actions_not_matching_these(supplied_actions +
                                               dependent_actions)
        for action in actions_without_resource_constraints:
            logger.debug(
                f"Deliberately adding the action {action} without resource constraints"
            )
            self.add_action_without_resource_constraint(action)
        logger.debug(
            "Removing actions that are in the wildcard arn (Resources = '*') as well as other statements that have "
            "resource constraints ")
        self.remove_actions_duplicated_in_wildcard_arn()
        logger.debug("Getting the rendered policy")
        rendered_policy = self.get_rendered_policy()
        return rendered_policy
Example #15
0
#!/usr/bin/env python
from policy_sentry.shared.database import connect_db
from policy_sentry.querying.actions import get_action_data
import json

if __name__ == '__main__':
    db_session = connect_db('bundled')
    output = get_action_data(db_session, 'ram', 'createresourceshare')
    print(json.dumps(output, indent=4))

"""
Output:

{
    'ram': [
        {
            'action': 'ram:createresourceshare',
            'description': 'Create resource share with provided resource(s) and/or principal(s)',
            'access_level': 'Permissions management',
            'resource_arn_format': 'arn:${Partition}:ram:${Region}:${Account}:resource-share/${ResourcePath}',
            'condition_keys': [
                'ram:RequestedResourceType',
                'ram:ResourceArn',
                'ram:RequestedAllowsExternalPrincipals'
            ],
            'dependent_actions': None
        },
        {
            'action': 'ram:createresourceshare',
            'description': 'Create resource share with provided resource(s) and/or principal(s)',
            'access_level': 'Permissions management',
Example #16
0
#!/usr/bin/env python

from policy_sentry.querying.actions import get_action_data
import json

if __name__ == '__main__':

    output = get_action_data('ram', 'createresourceshare')
    print(json.dumps(output, indent=4))
"""
Output:

{
    'ram': [
        {
            'action': 'ram:createresourceshare',
            'description': 'Create resource share with provided resource(s) and/or principal(s)',
            'access_level': 'Permissions management',
            'resource_arn_format': 'arn:${Partition}:ram:${Region}:${Account}:resource-share/${ResourcePath}',
            'condition_keys': [
                'ram:RequestedResourceType',
                'ram:ResourceArn',
                'ram:RequestedAllowsExternalPrincipals'
            ],
            'dependent_actions': None
        },
        {
            'action': 'ram:createresourceshare',
            'description': 'Create resource share with provided resource(s) and/or principal(s)',
            'access_level': 'Permissions management',
            'resource_arn_format': '*',
Example #17
0
def query_action_table(name,
                       service,
                       access_level,
                       condition,
                       wildcard_only,
                       fmt="json"):
    """Query the Action Table from the Policy Sentry database. Use this one when leveraging Policy Sentry as a library."""
    # Actions on all services
    if service == "all":
        all_services = get_all_service_prefixes()
        if access_level:
            level = transform_access_level_text(access_level)
            print(f"{access_level} actions across ALL services:\n")
            output = []
            for serv in all_services:
                result = get_actions_with_access_level(serv, level)
                output.extend(result)
            print(yaml.dump(output)) if fmt == "yaml" else [
                print(result) for result in output
            ]
        # Get a list of all services in the database
        else:
            print("All services in the database:\n")
            output = all_services
            print(yaml.dump(output)) if fmt == "yaml" else [
                print(item) for item in output
            ]
    elif name is None and access_level and not wildcard_only:
        print(
            f"All IAM actions under the {service} service that have the access level {access_level}:"
        )
        level = transform_access_level_text(access_level)
        output = get_actions_with_access_level(service, level)
        print(yaml.dump(output)) if fmt == "yaml" else [
            print(json.dumps(output, indent=4))
        ]
    elif name is None and access_level and wildcard_only:
        print(
            f"{service} {access_level.upper()} actions that must use wildcards in the resources block:"
        )
        access_level = transform_access_level_text(access_level)
        output = get_actions_at_access_level_that_support_wildcard_arns_only(
            service, access_level)
        print(yaml.dump(output)) if fmt == "yaml" else [
            print(json.dumps(output, indent=4))
        ]
    # Get a list of all IAM actions under the service that support the specified condition key.
    elif condition:
        print(
            f"IAM actions under {service} service that support the {condition} condition only:"
        )
        output = get_actions_matching_condition_key(service, condition)
        print(yaml.dump(output)) if fmt == "yaml" else [
            print(json.dumps(output, indent=4))
        ]
    # Get a list of IAM Actions under the service that only support resources = "*"
    # (i.e., you cannot restrict it according to ARN)
    elif wildcard_only:
        print(
            f"IAM actions under {service} service that support wildcard resource values only:"
        )
        output = get_actions_that_support_wildcard_arns_only(service)
        print(yaml.dump(output)) if fmt == "yaml" else [
            print(json.dumps(output, indent=4))
        ]
    elif name and access_level is None:
        output = get_action_data(service, name)
        print(yaml.dump(output)) if fmt == "yaml" else [
            print(json.dumps(output, indent=4))
        ]
    else:
        # Get a list of all IAM Actions available to the service
        output = get_actions_for_service(service)
        print(f"ALL {service} actions:")
        print(yaml.dump(output)) if fmt == "yaml" else [
            print(item) for item in output
        ]
    return output