def test_is_intrinsic_if_must_return_false_for_others(self): too_many_keys = {"Fn::If": "some value", "Fn::And": "other value"} not_if = {"Fn::Or": "some value"} self.assertFalse(is_intrinsic_if(too_many_keys)) self.assertFalse(is_intrinsic_if(not_if)) self.assertFalse(is_intrinsic_if(None))
def _get_type(self, policy): """ Returns the type of the given policy :param string or dict policy: Policy data :return PolicyTypes: Type of the given policy. None, if type could not be inferred """ # Must handle intrinsic functions. Policy could be a primitive type or an intrinsic function # Managed policies are of type string if isinstance(policy, string_types): return PolicyTypes.MANAGED_POLICY # Handle the special case for 'if' intrinsic function if is_intrinsic_if(policy): return self._get_type_from_intrinsic_if(policy) # Intrinsic functions are treated as managed policies by default if is_intrinsic(policy): return PolicyTypes.MANAGED_POLICY # Policy statement is a dictionary with the key "Statement" in it if isinstance(policy, dict) and "Statement" in policy: return PolicyTypes.POLICY_STATEMENT # This could be a policy template then. if self._is_policy_template(policy): return PolicyTypes.POLICY_TEMPLATE # Nothing matches. Don't take opinions on how to handle it. Instead just set the appropriate type. return PolicyTypes.UNKNOWN
def _convert_alarms(self, preference_alarms): """ Converts deployment preference alarms to an AlarmsConfiguration Parameters ---------- preference_alarms : dict Deployment preference alarms Returns ------- dict AlarmsConfiguration if alarms is set, None otherwise Raises ------ ValueError If Alarms is in the wrong format """ if not preference_alarms or is_intrinsic_no_value(preference_alarms): return None if is_intrinsic_if(preference_alarms): processed_alarms = copy.deepcopy(preference_alarms) alarms_list = processed_alarms.get("Fn::If") validate_intrinsic_if_items(alarms_list) alarms_list[1] = self._build_alarm_configuration(alarms_list[1]) alarms_list[2] = self._build_alarm_configuration(alarms_list[2]) return processed_alarms return self._build_alarm_configuration(preference_alarms)
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
def test_is_intrinsic_if_must_return_true_for_if(self): policy = {"Fn::If": "some value"} self.assertTrue(is_intrinsic_if(policy))
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', attributes=self.get_passthrough_resource_attributes()) 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')) if self.VpcConfig: managed_policy_arns.append( ArnGenerator.generate_aws_managed_policy_arn('service-role/AWSLambdaVPCAccessExecutionRoles') ) 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: if is_intrinsic_if(policy_entry.data): intrinsic_if = policy_entry.data then_statement = intrinsic_if["Fn::If"][1] else_statement = intrinsic_if["Fn::If"][2] if not is_intrinsic_no_value(then_statement): then_statement = { 'PolicyName': execution_role.logical_id + 'Policy' + str(index), 'PolicyDocument': then_statement } intrinsic_if["Fn::If"][1] = then_statement if not is_intrinsic_no_value(else_statement): else_statement = { 'PolicyName': execution_role.logical_id + 'Policy' + str(index), 'PolicyDocument': else_statement } intrinsic_if["Fn::If"][2] = else_statement policy_documents.append(intrinsic_if) else: 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 execution_role.PermissionsBoundary = self.PermissionsBoundary return execution_role
def construct_role_for_resource( resource_logical_id, attributes, managed_policy_map, assume_role_policy_document, resource_policies, managed_policy_arns=None, policy_documents=None, permissions_boundary=None, tags=None, ): """ Constructs an execution role for a resource. :param resource_logical_id: The logical_id of the SAM resource that the role will be associated with :param attributes: Map of resource attributes to their values :param managed_policy_map: Map of managed policy names to the ARNs :param assume_role_policy_document: The trust policy that must be associated with the role :param resource_policies: ResourcePolicies object encapuslating the policies property of SAM resource :param managed_policy_arns: List of managed policy ARNs to be associated with the role :param policy_documents: List of policy documents to be associated with the role :param permissions_boundary: The ARN of the policy used to set the permissions boundary for the role :param tags: Tags to be associated with the role :returns: the generated IAM Role :rtype: model.iam.IAMRole """ role_logical_id = resource_logical_id + "Role" execution_role = IAMRole(logical_id=role_logical_id, attributes=attributes) execution_role.AssumeRolePolicyDocument = assume_role_policy_document if not managed_policy_arns: managed_policy_arns = [] if not policy_documents: policy_documents = [] for index, policy_entry in enumerate(resource_policies.get()): if policy_entry.type is PolicyTypes.POLICY_STATEMENT: if is_intrinsic_if(policy_entry.data): intrinsic_if = policy_entry.data then_statement = intrinsic_if["Fn::If"][1] else_statement = intrinsic_if["Fn::If"][2] if not is_intrinsic_no_value(then_statement): then_statement = { "PolicyName": execution_role.logical_id + "Policy" + str(index), "PolicyDocument": then_statement, } intrinsic_if["Fn::If"][1] = then_statement if not is_intrinsic_no_value(else_statement): else_statement = { "PolicyName": execution_role.logical_id + "Policy" + str(index), "PolicyDocument": else_statement, } intrinsic_if["Fn::If"][2] = else_statement policy_documents.append(intrinsic_if) else: 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( resource_logical_id, "Policy at index {} in the '{}' property is not valid".format( index, resource_policies.POLICIES_PROPERTY_NAME), ) execution_role.ManagedPolicyArns = list(managed_policy_arns) execution_role.Policies = policy_documents or None execution_role.PermissionsBoundary = permissions_boundary execution_role.Tags = tags return execution_role