Пример #1
0
    async def get(self, identifier):
        if config.get("policy_editor.disallow_contractors",
                      True) and self.contractor:
            if self.user not in config.get(
                    "groups.can_bypass_contractor_restrictions", []):
                raise MustBeFte("Only FTEs are authorized to view this page.")

        log_data = {
            "function": "ServiceControlPolicyHandler.get",
            "user": self.user,
            "message": "Retrieving service control policies for identifier",
            "identifier": identifier,
            "user-agent": self.request.headers.get("User-Agent"),
            "request_id": self.request_uuid,
        }

        log.debug(log_data)
        try:
            scps = await get_scps_for_account_or_ou(identifier)
        except Exception as e:
            sentry_sdk.capture_exception()
            response = WebResponse(status=Status2.error,
                                   status_code=403,
                                   errors=[str(e)],
                                   data=[])
            self.write(response.json())
            return
        response = WebResponse(status=Status2.success,
                               status_code=200,
                               data=scps.__root__)
        self.write(response.json())
Пример #2
0
    async def put(self, request_id):
        """
        PUT /api/v2/requests/{request_id}
        """
        tags = {"user": self.user}
        stats.count("RequestDetailHandler.put", tags=tags)
        log_data = {
            "function": "RequestDetailHandler.put",
            "user": self.user,
            "message": "Incoming request",
            "user-agent": self.request.headers.get("User-Agent"),
            "request_id": self.request_uuid,
            "policy_request_id": request_id,
        }
        log.debug(log_data)

        if config.get("policy_editor.disallow_contractors",
                      True) and self.contractor:
            if self.user not in config.get(
                    "groups.can_bypass_contractor_restrictions", []):
                raise MustBeFte("Only FTEs are authorized to view this page.")

        try:
            # Validate the request body
            request_changes = PolicyRequestModificationRequestModel.parse_raw(
                self.request.body)
            log_data["message"] = "Parsed request body"
            log_data["request"] = request_changes.dict()
            log.debug(log_data)

            extended_request, last_updated = await self._get_extended_request(
                request_id, log_data)
            response = await parse_and_apply_policy_request_modification(
                extended_request, request_changes, self.user, self.groups,
                last_updated)

        except (NoMatchingRequest, InvalidRequestParameter,
                ValidationError) as e:
            log_data["message"] = "Validation Exception"
            log.error(log_data, exc_info=True)
            sentry_sdk.capture_exception(tags={"user": self.user})
            stats.count(f"{log_data['function']}.validation_exception",
                        tags={"user": self.user})
            self.write_error(400, message="Error validating input: " + str(e))
            if config.get("development"):
                raise
            return
        except Unauthorized as e:
            log_data["message"] = "Unauthorized"
            log.error(log_data, exc_info=True)
            sentry_sdk.capture_exception(tags={"user": self.user})
            stats.count(f"{log_data['function']}.unauthorized",
                        tags={"user": self.user})
            self.write_error(403, message=str(e))
            if config.get("development"):
                raise
            return
        self.write(response.json())
        await self.finish()
        return
Пример #3
0
    async def get(self, account_id, role_name):
        if config.get("policy_editor.disallow_contractors",
                      True) and self.contractor:
            if self.user not in config.get(
                    "groups.can_bypass_contractor_restrictions", []):
                raise MustBeFte("Only FTEs are authorized to view this page.")

        log_data = {
            "function": "ManagedPoliciesOnRoleHandler.get",
            "user": self.user,
            "ip": self.ip,
            "message": "Retrieving managed policies for role",
            "user-agent": self.request.headers.get("User-Agent"),
            "request_id": self.request_uuid,
            "account_id": account_id,
            "role_name": role_name,
        }

        log.debug(log_data)

        managed_policy_details = await sync_to_async(
            get_role_managed_policy_documents)(
                {
                    "RoleName": role_name
                },
                account_number=account_id,
                assume_role=config.get("policies.role_name"),
                region=config.region,
            )
        res = WebResponse(
            status="success",
            status_code=200,
            data=managed_policy_details,
        )
        self.write(res.json())
Пример #4
0
 async def get(self):
     if config.get("policy_editor.disallow_contractors",
                   True) and self.contractor:
         if self.user not in config.get(
                 "groups.can_bypass_contractor_restrictions", []):
             raise MustBeFte("Only FTEs are authorized to view this page.")
     results = await handle_resource_type_ahead_request(self)
     self.write(json.dumps(results))
Пример #5
0
 async def get(self, account_id):
     """
     Retrieve a list of managed policies for an account.
     """
     if config.get("policy_editor.disallow_contractors",
                   True) and self.contractor:
         if self.user not in config.get(
                 "groups.can_bypass_contractor_restrictions", []):
             raise MustBeFte("Only FTEs are authorized to view this page.")
     all_account_managed_policies = await get_all_iam_managed_policies_for_account(
         account_id)
     self.write(json.dumps(all_account_managed_policies))
Пример #6
0
    async def get(self, policy_arn: str):
        if config.get("policy_editor.disallow_contractors",
                      True) and self.contractor:
            if self.user not in config.get(
                    "groups.can_bypass_contractor_restrictions", []):
                raise MustBeFte("Only FTEs are authorized to view this page.")

        account_id = policy_arn.split(":")[4]
        policy_name = policy_arn.split("/")[-1]
        log_data = {
            "function": "ManagedPoliciesHandler.get",
            "user": self.user,
            "ip": self.ip,
            "message": "Retrieving managed policy",
            "user-agent": self.request.headers.get("User-Agent"),
            "request_id": self.request_uuid,
            "account_id": account_id,
            "policy_name": policy_name,
            "policy_arn": policy_arn,
        }

        log.debug(log_data)

        managed_policy_details = await sync_to_async(
            get_managed_policy_document)(
                policy_arn=policy_arn,
                account_number=account_id,
                assume_role=config.get("policies.role_name"),
                region=config.region,
                retry_max_attempts=2,
                client_kwargs=config.get("boto3.client_kwargs", {}),
            )
        res = WebResponse(
            status=Status2.success,
            status_code=200,
            data=managed_policy_details,
        )
        self.write(res.json())
Пример #7
0
    async def get(self):
        """
        /api/v1/policyuniverse/autocomplete/?prefix=
        ---
        get:
            description: Supplies autocompleted permissions for the ace code editor.
            responses:
                200:
                    description: Returns a list of the matching permissions.
        """

        if config.get("policy_editor.disallow_contractors",
                      True) and self.contractor:
            if self.user not in config.get(
                    "groups.can_bypass_contractor_restrictions", []):
                raise MustBeFte("Only FTEs are authorized to view this page.")

        only_filter_services = False

        if (self.request.arguments.get("only_filter_services")
                and self.request.arguments.get(
                    "only_filter_services")[0].decode("utf-8") == "true"):
            only_filter_services = True

        prefix = self.request.arguments.get("prefix")[0].decode("utf-8") + "*"
        results = _expand_wildcard_action(prefix)
        if only_filter_services:
            # We return known matching services in a format that the frontend expects to see them. We omit the wildcard
            # character returned by policyuniverse.
            services = sorted(
                list({r.split(":")[0].replace("*", "")
                      for r in results}))
            results = [{"title": service} for service in services]
        else:
            results = [dict(permission=r) for r in results]
        self.write(json.dumps(results))
        await self.finish()
Пример #8
0
    async def get(self, account_id, resource_type, region=None, resource_name=None):
        if not self.user:
            return
        if config.get("policy_editor.disallow_contractors", True) and self.contractor:
            if self.user not in config.get(
                "groups.can_bypass_contractor_restrictions", []
            ):
                raise MustBeFte("Only FTEs are authorized to view this page.")
        read_only = False

        can_save_delete = (can_admin_policies(self.user, self.groups),)

        account_id_for_arn: str = account_id
        if resource_type == "s3":
            account_id_for_arn = ""
        arn = f"arn:aws:{resource_type}:{region or ''}:{account_id_for_arn}:{resource_name}"

        stats.count(
            "ResourcePolicyEditHandler.get", tags={"user": self.user, "arn": arn}
        )

        log_data = {
            "user": self.user,
            "ip": self.ip,
            "function": f"{__name__}.{self.__class__.__name__}.{sys._getframe().f_code.co_name}",
            "message": "Incoming request",
            "user-agent": self.request.headers.get("User-Agent"),
            "request_id": self.request_uuid,
            "arn": arn,
        }

        log.debug(log_data)

        resource_details = await fetch_resource_details(
            account_id, resource_type, resource_name, region
        )

        # TODO: Get S3 errors for s3 buckets only, else CT errors
        yesterday = (datetime.today() - timedelta(days=1)).strftime("%Y%m%d")
        s3_query_url = None
        if resource_type == "s3":
            s3_query_url = config.get("s3.bucket_query_url")
        all_s3_errors = None
        if s3_query_url:
            s3_query_url = s3_query_url.format(
                yesterday=yesterday, bucket_name=f"'{resource_name}'"
            )
            s3_error_topic = config.get("redis.s3_errors", "S3_ERRORS")
            all_s3_errors = self.red.get(s3_error_topic)

        s3_errors = []
        if all_s3_errors:
            s3_errors = json.loads(all_s3_errors).get(arn, [])

        account_ids_to_name = await get_account_id_to_name_mapping()
        # TODO(ccastrapel/psanders): Make a Swagger spec for this
        self.write(
            dict(
                arn=arn,
                resource_details=resource_details,
                account_id=account_id,
                account_name=account_ids_to_name.get(account_id, None),
                read_only=read_only,
                can_save_delete=can_save_delete,
                s3_errors=s3_errors,
                error_url=s3_query_url,
            )
        )
Пример #9
0
    async def post(self):
        """
        POST /api/v2/request

        Request example JSON: (Request Schema is RequestCreationModel in models.py)

        {
          "changes": {
            "changes": [
              {
                "principal_arn": "arn:aws:iam::123456789012:role/curtisTestRole1",
                "change_type": "inline_policy",
                "action": "attach",
                "policy": {
                  "policy_document": {
                    "Version": "2012-10-17",
                    "Statement": [
                      {
                        "Action": [
                          "s3:ListMultipartUploadParts*",
                          "s3:ListBucket"
                        ],
                        "Effect": "Allow",
                        "Resource": [
                          "arn:aws:s3:::curtis-nflx-test/*",
                          "arn:aws:s3:::curtis-nflx-test"
                        ],
                        "Sid": "cmccastrapel159494014dsd1shak"
                      },
                      {
                        "Action": [
                          "ec2:describevolumes",
                          "ec2:detachvolume",
                          "ec2:describelicenses",
                          "ec2:AssignIpv6Addresses",
                          "ec2:reportinstancestatus"
                        ],
                        "Effect": "Allow",
                        "Resource": [
                          "*"
                        ],
                        "Sid": "cmccastrapel1594940141hlvvv"
                      },
                      {
                        "Action": [
                          "sts:AssumeRole"
                        ],
                        "Effect": "Allow",
                        "Resource": [
                          "arn:aws:iam::123456789012:role/curtisTestInstanceProfile"
                        ],
                        "Sid": "cmccastrapel1596483596easdits"
                      }
                    ]
                  }
                }
              },
              {
                "principal_arn": "arn:aws:iam::123456789012:role/curtisTestRole1",
                "change_type": "assume_role_policy",
                "policy": {
                  "policy_document": {
                    "Statement": [
                      {
                        "Action": "sts:AssumeRole",
                        "Effect": "Allow",
                        "Principal": {
                          "AWS": "arn:aws:iam::123456789012:role/consolemeInstanceProfile"
                        },
                        "Sid": "AllowConsoleMeProdAssumeRolses"
                      }
                    ],
                    "Version": "2012-10-17"
                  }
                }
              },
              {
                "principal_arn": "arn:aws:iam::123456789012:role/curtisTestRole1",
                "change_type": "managed_policy",
                "policy_name": "ApiProtect",
                "action": "attach",
                "arn": "arn:aws:iam::123456789012:policy/ApiProtect"
              },
              {
                "principal_arn": "arn:aws:iam::123456789012:role/curtisTestRole1",
                "change_type": "managed_policy",
                "policy_name": "TagProtect",
                "action": "detach",
                "arn": "arn:aws:iam::123456789012:policy/TagProtect"
              },
              {
                "principal_arn": "arn:aws:iam::123456789012:role/curtisTestRole1",
                "change_type": "inline_policy",
                "policy_name": "random_policy254",
                "action": "attach",
                "policy": {
                  "policy_document": {
                    "Version": "2012-10-17",
                    "Statement": [
                      {
                        "Action": [
                          "ec2:AssignIpv6Addresses"
                        ],
                        "Effect": "Allow",
                        "Resource": [
                          "*"
                        ],
                        "Sid": "cmccastrapel1594940141shakabcd"
                      }
                    ]
                  }
                }
              }
            ]
          },
          "justification": "testing this out.",
          "admin_auto_approve": false
        }

        Response example JSON: (Response Schema is RequestCreationResponse in models.py)

        {
            "errors": 1,
            "request_created": true,
            "request_id": "0c9fb298-c8ea-4d50-917c-3212da07b3ad",
            "action_results": [
                {
                    "status": "success",
                    "message": "Success description"
                },
                {
                    "status": "error",
                    "message": "Error description"
                }
            ]
        }


        """

        if config.get("policy_editor.disallow_contractors",
                      True) and self.contractor:
            if self.user not in config.get(
                    "groups.can_bypass_contractor_restrictions", []):
                raise MustBeFte("Only FTEs are authorized to view this page.")

        tags = {"user": self.user}
        stats.count("RequestHandler.post", tags=tags)
        log_data = {
            "function":
            f"{__name__}.{self.__class__.__name__}.{sys._getframe().f_code.co_name}",
            "user": self.user,
            "message": "Create request initialization",
            "user-agent": self.request.headers.get("User-Agent"),
            "request_id": self.request_uuid,
            "ip": self.ip,
            "admin_auto_approved": False,
            "probe_auto_approved": False,
        }
        log.debug(log_data)
        try:
            # Validate the model
            changes = RequestCreationModel.parse_raw(self.request.body)
            extended_request = await generate_request_from_change_model_array(
                changes, self.user)
            log_data["request"] = extended_request.dict()
            log.debug(log_data)
            admin_approved = False
            approval_probe_approved = False

            # TODO: Provide a note to the requester that admin_auto_approve will apply the requested policies only.
            # It will not automatically apply generated policies. The administrative user will need to visit the policy
            # Request page to do this manually.
            if changes.admin_auto_approve:
                # make sure user is allowed to use admin_auto_approve
                can_manage_policy_request = (can_admin_policies(
                    self.user, self.groups), )
                if can_manage_policy_request:
                    extended_request.request_status = RequestStatus.approved
                    admin_approved = True
                    extended_request.reviewer = self.user
                    self_approval_comment = CommentModel(
                        id=str(uuid.uuid4()),
                        timestamp=int(time.time()),
                        user_email=self.user,
                        user=extended_request.requester_info,
                        last_modified=int(time.time()),
                        text=f"Self-approved by admin: {self.user}",
                    )
                    extended_request.comments.append(self_approval_comment)
                    log_data["admin_auto_approved"] = True
                    log_data["request"] = extended_request.dict()
                    log.debug(log_data)
                    stats.count(
                        f"{log_data['function']}.post.admin_auto_approved",
                        tags={"user": self.user},
                    )
                else:
                    # someone is trying to use admin bypass without being an admin, don't allow request to proceed
                    stats.count(
                        f"{log_data['function']}.post.unauthorized_admin_bypass",
                        tags={"user": self.user},
                    )
                    log_data[
                        "message"] = "Unauthorized user trying to use admin bypass"
                    log.error(log_data)
                    await write_json_error("Unauthorized", obj=self)
                    return
            else:
                # If admin auto approve is false, check for auto-approve probe eligibility
                is_eligible_for_auto_approve_probe = (
                    await is_request_eligible_for_auto_approval(
                        extended_request, self.user))
                # If we have only made requests that are eligible for auto-approval probe, check against them
                if is_eligible_for_auto_approve_probe:
                    should_auto_approve_request = await should_auto_approve_policy_v2(
                        extended_request, self.user, self.groups)
                    if should_auto_approve_request["approved"]:
                        extended_request.request_status = RequestStatus.approved
                        approval_probe_approved = True
                        stats.count(
                            f"{log_data['function']}.probe_auto_approved",
                            tags={"user": self.user},
                        )
                        approving_probes = []
                        for approving_probe in should_auto_approve_request[
                                "approving_probes"]:
                            approving_probe_comment = CommentModel(
                                id=str(uuid.uuid4()),
                                timestamp=int(time.time()),
                                user_email=
                                f"Auto-Approve Probe: {approving_probe['name']}",
                                last_modified=int(time.time()),
                                text=
                                f"Policy {approving_probe['policy']} auto-approved by probe: {approving_probe['name']}",
                            )
                            extended_request.comments.append(
                                approving_probe_comment)
                            approving_probes.append(approving_probe["name"])
                        extended_request.reviewer = (
                            f"Auto-Approve Probe: {','.join(approving_probes)}"
                        )
                        log_data["probe_auto_approved"] = True
                        log_data["request"] = extended_request.dict()
                        log.debug(log_data)

            dynamo = UserDynamoHandler(self.user)
            request = await dynamo.write_policy_request_v2(extended_request)
            log_data["message"] = "New request created in Dynamo"
            log_data["request"] = extended_request.dict()
            log_data["dynamo_request"] = request
            log.debug(log_data)
        except (InvalidRequestParameter, ValidationError) as e:
            log_data["message"] = "Validation Exception"
            log.error(log_data, exc_info=True)
            stats.count(f"{log_data['function']}.validation_exception",
                        tags={"user": self.user})
            self.write_error(400, message="Error validating input: " + str(e))
            if config.get("development"):
                raise
            return
        except Exception as e:
            log_data[
                "message"] = "Unknown Exception occurred while parsing request"
            log.error(log_data, exc_info=True)
            stats.count(f"{log_data['function']}.exception",
                        tags={"user": self.user})
            sentry_sdk.capture_exception(tags={"user": self.user})
            self.write_error(500, message="Error parsing request: " + str(e))
            if config.get("development"):
                raise
            return

        # If here, request has been successfully created
        response = RequestCreationResponse(
            errors=0,
            request_created=True,
            request_id=extended_request.id,
            request_url=f"/policies/request/{extended_request.id}",
            action_results=[],
        )

        # If approved is true due to an auto-approval probe or admin auto-approval, apply the non-autogenerated changes
        if extended_request.request_status == RequestStatus.approved:
            for change in extended_request.changes.changes:
                if change.autogenerated:
                    continue
                policy_request_modification_model = (
                    PolicyRequestModificationRequestModel.parse_obj({
                        "modification_model": {
                            "command": "apply_change",
                            "change_id": change.id,
                        }
                    }))
                policy_apply_response = (
                    await parse_and_apply_policy_request_modification(
                        extended_request,
                        policy_request_modification_model,
                        self.user,
                        self.groups,
                        int(time.time()),
                        approval_probe_approved,
                    ))
                response.errors = policy_apply_response.errors
                response.action_results = policy_apply_response.action_results

            # Update in dynamo
            await dynamo.write_policy_request_v2(extended_request)
            account_id = await get_resource_account(extended_request.arn)

            # Force a refresh of the role in Redis/DDB
            arn_parsed = parse_arn(extended_request.arn)
            if arn_parsed["service"] == "iam" and arn_parsed[
                    "resource"] == "role":
                await aws.fetch_iam_role(account_id,
                                         extended_request.arn,
                                         force_refresh=True)
            log_data["request"] = extended_request.dict()
            log_data["message"] = "Applied changes based on approved request"
            log_data["response"] = response.dict()
            log.debug(log_data)

        await aws.send_communications_new_policy_request(
            extended_request, admin_approved, approval_probe_approved)
        self.write(response.json())
        await self.finish()
        await cache_all_policy_requests()
        return
Пример #10
0
    async def get(self,
                  account_id,
                  resource_type,
                  region=None,
                  resource_name=None):
        if not self.user:
            return
        if config.get("policy_editor.disallow_contractors",
                      True) and self.contractor:
            if self.user not in config.get(
                    "groups.can_bypass_contractor_restrictions", []):
                raise MustBeFte("Only FTEs are authorized to view this page.")
        read_only = False

        can_save_delete = (can_admin_policies(self.user, self.groups), )

        account_id_for_arn: str = account_id
        if resource_type == "s3":
            account_id_for_arn = ""
        arn = f"arn:aws:{resource_type}:{region or ''}:{account_id_for_arn}:{resource_name}"
        path = ""
        if resource_type == "managed_policy":
            # special case for managed policies
            path = region or ""
            if path:
                arn = f"arn:aws:iam::{account_id}:policy/{path}/{resource_name}"
            else:
                arn = f"arn:aws:iam::{account_id}:policy/{resource_name}"

        stats.count("ResourcePolicyEditHandler.get",
                    tags={
                        "user": self.user,
                        "arn": arn
                    })

        log_data = {
            "user": self.user,
            "ip": self.ip,
            "function":
            f"{__name__}.{self.__class__.__name__}.{sys._getframe().f_code.co_name}",
            "message": "Incoming request",
            "user-agent": self.request.headers.get("User-Agent"),
            "request_id": self.request_uuid,
            "arn": arn,
        }

        log.debug(log_data)

        error = ""

        try:
            resource_details = await fetch_resource_details(
                account_id, resource_type, resource_name, region, path)
        except Exception as e:
            sentry_sdk.capture_exception()
            log.error({**log_data, "error": e}, exc_info=True)
            resource_details = None
            error = str(e)

        if not resource_details:
            self.send_error(
                404,
                message=
                (f"Unable to retrieve the specified {resource_type} resource: "
                 f"{account_id}/{resource_name}/{region}. {error}", ),
            )
            return

        # TODO: Get S3 errors for s3 buckets only, else CT errors
        yesterday = (datetime.today() - timedelta(days=1)).strftime("%Y%m%d")
        s3_query_url = None
        if resource_type == "s3":
            s3_query_url = config.get("s3.bucket_query_url")
        all_s3_errors = None
        if s3_query_url:
            s3_query_url = s3_query_url.format(
                yesterday=yesterday, bucket_name=f"'{resource_name}'")
            s3_error_topic = config.get("redis.s3_errors", "S3_ERRORS")
            all_s3_errors = self.red.get(s3_error_topic)

        s3_errors = []
        if all_s3_errors:
            s3_errors = json.loads(all_s3_errors).get(arn, [])

        account_ids_to_name = await get_account_id_to_name_mapping()
        # TODO(ccastrapel/psanders): Make a Swagger spec for this
        self.write(
            dict(
                arn=arn,
                resource_details=resource_details,
                account_id=account_id,
                account_name=account_ids_to_name.get(account_id, None),
                read_only=read_only,
                can_save_delete=can_save_delete,
                s3_errors=s3_errors,
                error_url=s3_query_url,
                config_timeline_url=resource_details.get(
                    "config_timeline_url"),
            ))
Пример #11
0
    async def get(self, arn):
        if config.get("policy_editor.disallow_contractors",
                      True) and self.contractor:
            if self.user not in config.get(
                    "groups.can_bypass_contractor_restrictions", []):
                raise MustBeFte("Only FTEs are authorized to view this page.")

        errors = []
        if not arn.startswith("arn:aws:iam::"):
            errors.append("ARN must start with 'arn:aws:iam::'")

        principal_name = tornado.escape.xhtml_escape(arn.split("/")[-1])
        principal_type = tornado.escape.xhtml_escape(
            arn.split(":")[5].split("/")[0])
        account_id = tornado.escape.xhtml_escape(arn.split(":")[4])
        if principal_type not in ["role", "user"]:
            errors.append(
                f"Principal type must be role or user. not {principal_type}")

        log_data = {
            "function": "ManagedPoliciesOnRoleHandler.get",
            "user": self.user,
            "ip": self.ip,
            "message": "Retrieving managed policies for role",
            "user-agent": self.request.headers.get("User-Agent"),
            "request_id": self.request_uuid,
            "account_id": account_id,
            "principal_name": principal_name,
            "principal_type": principal_type,
        }

        log.debug(log_data)
        if errors:
            log.error({
                **log_data, "errors": errors,
                "message": "Unable to process request"
            })
            res = WebResponse(
                status=Status2.error,
                reason="bad_request",
                status_code=400,
                errors=errors,
            )
            self.write(res.json())
            return

        if principal_type == "role":
            managed_policy_details = await sync_to_async(
                get_role_managed_policy_documents)(
                    {
                        "RoleName": principal_name
                    },
                    account_number=account_id,
                    assume_role=config.get("policies.role_name"),
                    region=config.region,
                    retry_max_attempts=2,
                    client_kwargs=config.get("boto3.client_kwargs", {}),
                )
        elif principal_type == "user":
            managed_policy_details = await sync_to_async(
                get_user_managed_policy_documents)(
                    {
                        "UserName": principal_name
                    },
                    account_number=account_id,
                    assume_role=config.get("policies.role_name"),
                    region=config.region,
                    retry_max_attempts=2,
                    client_kwargs=config.get("boto3.client_kwargs", {}),
                )
        else:
            raise Exception("Invalid principal type")
        res = WebResponse(
            status=Status2.success,
            status_code=200,
            data=managed_policy_details,
        )
        self.write(res.json())