def _construct_role(self, managed_policy_map):
        """Constructs a Lambda execution role based on this SAM function's Policies property.

        :returns: the generated IAM Role
        :rtype: model.iam.IAMRole
        """
        execution_role = IAMRole(self.logical_id + 'Role')
        execution_role.AssumeRolePolicyDocument = IAMRolePolicies.lambda_assume_role_policy()

        managed_policy_arns = [ArnGenerator.generate_aws_managed_policy_arn('service-role/AWSLambdaBasicExecutionRole')]
        if self.Tracing:
            managed_policy_arns.append(ArnGenerator.generate_aws_managed_policy_arn('AWSXrayWriteOnlyAccess'))

        function_policies = FunctionPolicies({"Policies": self.Policies},
                                             # No support for policy templates in the "core"
                                             policy_template_processor=None)
        policy_documents = []

        if self.DeadLetterQueue:
            policy_documents.append(IAMRolePolicies.dead_letter_queue_policy(
                self.dead_letter_queue_policy_actions[self.DeadLetterQueue['Type']],
                self.DeadLetterQueue['TargetArn']))

        for index, policy_entry in enumerate(function_policies.get()):

            if policy_entry.type is PolicyTypes.POLICY_STATEMENT:

                policy_documents.append({
                    'PolicyName': execution_role.logical_id + 'Policy' + str(index),
                    'PolicyDocument': policy_entry.data
                })
            elif policy_entry.type is PolicyTypes.MANAGED_POLICY:

                # There are three options:
                #   Managed Policy Name (string): Try to convert to Managed Policy ARN
                #   Managed Policy Arn (string): Insert it directly into the list
                #   Intrinsic Function (dict): Insert it directly into the list
                #
                # When you insert into managed_policy_arns list, de-dupe to prevent same ARN from showing up twice
                #

                policy_arn = policy_entry.data
                if isinstance(policy_entry.data, string_types) and policy_entry.data in managed_policy_map:
                    policy_arn = managed_policy_map[policy_entry.data]

                # De-Duplicate managed policy arns before inserting. Mainly useful
                # when customer specifies a managed policy which is already inserted
                # by SAM, such as AWSLambdaBasicExecutionRole
                if policy_arn not in managed_policy_arns:
                    managed_policy_arns.append(policy_arn)
            else:
                # Policy Templates are not supported here in the "core"
                raise InvalidResourceException(
                    self.logical_id,
                    "Policy at index {} in the 'Policies' property is not valid".format(index))

        execution_role.ManagedPolicyArns = list(managed_policy_arns)
        execution_role.Policies = policy_documents or None

        return execution_role
    def _construct_role(self, managed_policy_map):
        """Constructs a Lambda execution role based on this SAM function's Policies property.

        :returns: the generated IAM Role
        :rtype: model.iam.IAMRole
        """
        execution_role = IAMRole(self.logical_id + 'Role')
        execution_role.AssumeRolePolicyDocument = IAMRolePolicies.lambda_assume_role_policy()

        managed_policy_arns = [ArnGenerator.generate_aws_managed_policy_arn('service-role/AWSLambdaBasicExecutionRole')]
        if self.Tracing:
            managed_policy_arns.append(ArnGenerator.generate_aws_managed_policy_arn('AWSXrayWriteOnlyAccess'))

        function_policies = FunctionPolicies({"Policies": self.Policies},
                                             # No support for policy templates in the "core"
                                             policy_template_processor=None)
        policy_documents = []

        if self.DeadLetterQueue:
            policy_documents.append(IAMRolePolicies.dead_letter_queue_policy(
                self.dead_letter_queue_policy_actions[self.DeadLetterQueue['Type']],
                self.DeadLetterQueue['TargetArn']))

        for index, policy_entry in enumerate(function_policies.get()):

            if policy_entry.type is PolicyTypes.POLICY_STATEMENT:

                policy_documents.append({
                    'PolicyName': execution_role.logical_id + 'Policy' + str(index),
                    'PolicyDocument': policy_entry.data
                })
            elif policy_entry.type is PolicyTypes.MANAGED_POLICY:

                # There are three options:
                #   Managed Policy Name (string): Try to convert to Managed Policy ARN
                #   Managed Policy Arn (string): Insert it directly into the list
                #   Intrinsic Function (dict): Insert it directly into the list
                #
                # When you insert into managed_policy_arns list, de-dupe to prevent same ARN from showing up twice
                #

                policy_arn = policy_entry.data
                if isinstance(policy_entry.data, string_types) and policy_entry.data in managed_policy_map:
                    policy_arn = managed_policy_map[policy_entry.data]

                # De-Duplicate managed policy arns before inserting. Mainly useful
                # when customer specifies a managed policy which is already inserted
                # by SAM, such as AWSLambdaBasicExecutionRole
                if policy_arn not in managed_policy_arns:
                    managed_policy_arns.append(policy_arn)
            else:
                # Policy Templates are not supported here in the "core"
                raise InvalidResourceException(
                    self.logical_id,
                    "Policy at index {} in the 'Policies' property is not valid".format(index))

        execution_role.ManagedPolicyArns = list(managed_policy_arns)
        execution_role.Policies = policy_documents or None

        return execution_role
    def test_get_must_yield_no_results_with_no_policies(self, get_policies_mock):
        resource_properties = {} # Just some input
        dummy_policy_results = []
        expected_result = []

        # Setup _get_policies to return these dummy values for testing
        get_policies_mock.return_value = dummy_policy_results
        function_policies = FunctionPolicies(resource_properties, self.policy_template_processor_mock)

        # `list()` will implicitly call the `get()` repeatedly because it is a generator
        self.assertEqual(list(function_policies.get()), expected_result)
    def test_get_must_yield_no_results_with_no_policies(self, get_policies_mock):
        resource_properties = {} # Just some input
        dummy_policy_results = []
        expected_result = []

        # Setup _get_policies to return these dummy values for testing
        get_policies_mock.return_value = dummy_policy_results
        function_policies = FunctionPolicies(resource_properties, self.policy_template_processor_mock)

        # `list()` will implicitly call the `get()` repeatedly because it is a generator
        self.assertEqual(list(function_policies.get()), expected_result)
예제 #5
0
    def on_before_transform_resource(self, logical_id, resource_type,
                                     resource_properties):
        """
        Hook method that gets called before "each" SAM resource gets processed

        :param string logical_id: Logical ID of the resource being processed
        :param string resource_type: Type of the resource being processed
        :param dict resource_properties: Properties of the resource
        :return: Nothing
        """

        if not self._is_supported(resource_type):
            return

        function_policies = FunctionPolicies(resource_properties,
                                             self._policy_template_processor)

        if len(function_policies) == 0:
            # No policies to process
            return

        result = []
        for policy_entry in function_policies.get():

            if policy_entry.type is not PolicyTypes.POLICY_TEMPLATE:
                # If we don't know the type, skip processing and pass to result as is.
                result.append(policy_entry.data)
                continue

            # We are processing policy templates. We know they have a particular structure:
            # {"templateName": { parameter_values_dict }}
            template_data = policy_entry.data
            template_name = list(template_data.keys())[0]
            template_parameters = list(template_data.values())[0]

            try:

                # 'convert' will return a list of policy statements
                result.append(
                    self._policy_template_processor.convert(
                        template_name, template_parameters))

            except InsufficientParameterValues as ex:
                # Exception's message will give lot of specific details
                raise InvalidResourceException(logical_id, str(ex))
            except InvalidParameterValues:
                raise InvalidResourceException(
                    logical_id,
                    "Must specify valid parameter values for policy template '{}'"
                    .format(template_name))

        # Save the modified policies list to the input
        resource_properties[FunctionPolicies.POLICIES_PROPERTY_NAME] = result
    def on_before_transform_resource(self, logical_id, resource_type, resource_properties):
        """
        Hook method that gets called before "each" SAM resource gets processed

        :param string logical_id: Logical ID of the resource being processed
        :param string resource_type: Type of the resource being processed
        :param dict resource_properties: Properties of the resource
        :return: Nothing
        """

        if not self._is_supported(resource_type):
            return

        function_policies = FunctionPolicies(resource_properties, self._policy_template_processor)

        if len(function_policies) == 0:
            # No policies to process
            return

        result = []
        for policy_entry in function_policies.get():

            if policy_entry.type is not PolicyTypes.POLICY_TEMPLATE:
                # If we don't know the type, skip processing and pass to result as is.
                result.append(policy_entry.data)
                continue

            # We are processing policy templates. We know they have a particular structure:
            # {"templateName": { parameter_values_dict }}
            template_data = policy_entry.data
            template_name = list(template_data.keys())[0]
            template_parameters = list(template_data.values())[0]

            try:

                # 'convert' will return a list of policy statements
                result.append(self._policy_template_processor.convert(template_name, template_parameters))

            except InsufficientParameterValues as ex:
                # Exception's message will give lot of specific details
                raise InvalidResourceException(logical_id, str(ex))
            except InvalidParameterValues:
                raise InvalidResourceException(logical_id,
                                               "Must specify valid parameter values for policy template '{}'"
                                               .format(template_name))

        # Save the modified policies list to the input
        resource_properties[FunctionPolicies.POLICIES_PROPERTY_NAME] = result
    def on_before_transform_resource(self, logical_id, resource_type,
                                     resource_properties):
        """
        Hook method that gets called before "each" SAM resource gets processed

        :param string logical_id: Logical ID of the resource being processed
        :param string resource_type: Type of the resource being processed
        :param dict resource_properties: Properties of the resource
        :return: Nothing
        """

        if not self._is_supported(resource_type):
            return

        function_policies = FunctionPolicies(resource_properties,
                                             self._policy_template_processor)

        if len(function_policies) == 0:
            # No policies to process
            return

        result = []
        for policy_entry in function_policies.get():

            if policy_entry.type is not PolicyTypes.POLICY_TEMPLATE:
                # If we don't know the type, skip processing and pass to result as is.
                result.append(policy_entry.data)
                continue

            if is_intrinsic_if(policy_entry.data):
                # If policy is an intrinsic if, we need to process each sub-statement separately
                processed_intrinsic_if = self._process_intrinsic_if_policy_template(
                    logical_id, policy_entry)
                result.append(processed_intrinsic_if)
                continue

            converted_policy = self._process_policy_template(
                logical_id, policy_entry.data)
            result.append(converted_policy)

        # Save the modified policies list to the input
        resource_properties[FunctionPolicies.POLICIES_PROPERTY_NAME] = result