def _get_type_from_intrinsic_if(self, policy): """ Returns the type of the given policy assuming that it is an intrinsic if function :param policy: Input value to get type from :return: PolicyTypes: Type of the given policy. PolicyTypes.UNKNOWN, if type could not be inferred """ intrinsic_if_value = policy["Fn::If"] try: validate_intrinsic_if_items(intrinsic_if_value) except ValueError as e: raise InvalidTemplateException(e) if_data = intrinsic_if_value[1] else_data = intrinsic_if_value[2] if_data_type = self._get_type(if_data) else_data_type = self._get_type(else_data) if if_data_type == else_data_type: return if_data_type if is_intrinsic_no_value(if_data): return else_data_type if is_intrinsic_no_value(else_data): return if_data_type raise InvalidTemplateException( "Different policy types within the same Fn::If statement is unsupported. " "Separate different policy types into different Fn::If statements")
def test_is_intrinsic_no_value_must_return_false_for_other_value(self): bad_key = {"sRefs": "AWS::NoValue"} bad_value = {"Ref": "SWA::NoValue"} too_many_keys = {"Ref": "AWS::NoValue", "feR": "SWA::NoValue"} self.assertFalse(is_intrinsic_no_value(bad_key)) self.assertFalse(is_intrinsic_no_value(bad_value)) self.assertFalse(is_intrinsic_no_value(None)) self.assertFalse(is_intrinsic_no_value(too_many_keys))
def _build_alarm_configuration(self, alarms): """ Builds an AlarmConfiguration from a list of alarms Parameters ---------- alarms : list[str] Alarms Returns ------- dict AlarmsConfiguration for a deployment group Raises ------ ValueError If alarms is not a list """ if not isinstance(alarms, list): raise ValueError("Alarms must be a list") if len(alarms) == 0 or is_intrinsic_no_value(alarms[0]): return {} return { "Enabled": True, "Alarms": [{ "Name": alarm } for alarm in alarms], }
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 _set_default_authorizer(self, open_api_editor, authorizers, default_authorizer, api_authorizers): """ Sets the default authorizer if one is given in the template :param open_api_editor: editor object that contains the OpenApi definition :param authorizers: authorizer definitions converted from the API auth section :param default_authorizer: name of the default authorizer :param api_authorizers: API auth section authorizer defintions """ if not default_authorizer: return if is_intrinsic_no_value(default_authorizer): return if is_intrinsic(default_authorizer): raise InvalidResourceException( self.logical_id, "Unable to set DefaultAuthorizer because intrinsic functions are not supported for this field.", ) if not authorizers.get(default_authorizer): raise InvalidResourceException( self.logical_id, "Unable to set DefaultAuthorizer because '" + default_authorizer + "' was not defined in 'Authorizers'.", ) for path in open_api_editor.iter_on_path(): open_api_editor.set_path_default_authorizer( path, default_authorizer, authorizers=authorizers, api_authorizers=api_authorizers)
def _process_intrinsic_if_policy_template(self, logical_id, policy_entry): intrinsic_if = policy_entry.data then_statement = intrinsic_if["Fn::If"][1] else_statement = intrinsic_if["Fn::If"][2] processed_then_statement = then_statement \ if is_intrinsic_no_value(then_statement) \ else self._process_policy_template(logical_id, then_statement) processed_else_statement = else_statement \ if is_intrinsic_no_value(else_statement) \ else self._process_policy_template(logical_id, else_statement) processed_intrinsic_if = { "Fn::If": [ policy_entry.data["Fn::If"][0], processed_then_statement, processed_else_statement ] } return processed_intrinsic_if
def test_is_intrinsic_no_value_must_return_true_for_no_value(self): policy = {"Ref": "AWS::NoValue"} self.assertTrue(is_intrinsic_no_value(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