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)
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