def test_with_policy_templates(self): self.create_and_verify_stack("combination/state_machine_with_policy_templates") state_machine_role_name = self.get_stack_outputs()["MyStateMachineRole"] # There should be two policies created. Each policy has the name <resource-logicalid>Policy<index> # Verify the contents of first policy sqs_poller_policy = get_policy_statements( state_machine_role_name, "MyStateMachineRolePolicy0", self.client_provider.iam_client ) self.assertEqual(len(sqs_poller_policy), 1, "Only one statement must be in SQS Poller policy") sqs_policy_statement = sqs_poller_policy[0] self.assertTrue(type(sqs_policy_statement["Resource"]) != list) queue_url = self.get_physical_id_by_type("AWS::SQS::Queue") parts = queue_url.split("/") expected_queue_name = parts[-1] actual_queue_arn = sqs_policy_statement["Resource"] self.assertTrue( actual_queue_arn.endswith(expected_queue_name), "Queue Arn " + actual_queue_arn + " must end with suffix " + expected_queue_name, ) # Verify the contents of second policy lambda_invoke_policy = get_policy_statements( state_machine_role_name, "MyStateMachineRolePolicy1", self.client_provider.iam_client ) self.assertEqual(len(lambda_invoke_policy), 1, "One policies statements should be present") lambda_policy_statement = lambda_invoke_policy[0] self.assertTrue(type(lambda_policy_statement["Resource"]) != list) function_name = self.get_physical_id_by_type("AWS::Lambda::Function") # NOTE: The resource ARN has "*" suffix to allow for any Lambda function version as well expected_function_suffix = "function:" + function_name + "*" actual_function_arn = lambda_policy_statement["Resource"] self.assertTrue( actual_function_arn.endswith(expected_function_suffix), "Function ARN " + actual_function_arn + " must end with suffix " + expected_function_suffix, )
def test_state_machine_with_schedule(self): self.create_and_verify_stack("combination/state_machine_with_schedule") outputs = self.get_stack_outputs() state_machine_arn = outputs["MyStateMachineArn"] schedule_name = outputs["MyScheduleName"] event_role_name = outputs["MyEventRole"] # get the cloudwatch schedule rule cloud_watch_event_client = self.client_provider.cloudwatch_event_client cw_rule_result = cloud_watch_event_client.describe_rule( Name=schedule_name) # checking if the name, description and state properties are correct self.assertEqual(cw_rule_result["Name"], schedule_name) self.assertEqual(cw_rule_result["Description"], "test schedule") self.assertEqual(cw_rule_result["State"], "DISABLED") self.assertEqual(cw_rule_result["ScheduleExpression"], "rate(1 minute)") # checking if the role used by the event rule to trigger the state machine execution is correct start_execution_policy = get_policy_statements( event_role_name, "MyStateMachineCWScheduleRoleStartExecutionPolicy", self.client_provider.iam_client) self.assertEqual( len(start_execution_policy), 1, "Only one statement must be in Start Execution policy") start_execution_policy_statement = start_execution_policy[0] self.assertTrue( type(start_execution_policy_statement["Action"]) != list) policy_action = start_execution_policy_statement["Action"] self.assertEqual( policy_action, "states:StartExecution", "Action referenced in event role policy must be 'states:StartExecution'", ) self.assertTrue( type(start_execution_policy_statement["Resource"]) != list) referenced_state_machine_arn = start_execution_policy_statement[ "Resource"] self.assertEqual( referenced_state_machine_arn, state_machine_arn, "State machine referenced in event role policy is incorrect", )
def _test_api_integration_with_state_machine(self, api_id, method, path, role_name, role_arn, policy_name, state_machine_arn, partition, region): apigw_client = self.client_provider.api_client resources = apigw_client.get_resources(restApiId=api_id)["items"] resource = get_resource_by_path(resources, path) post_method = apigw_client.get_method(restApiId=api_id, resourceId=resource["id"], httpMethod=method) method_integration = post_method["methodIntegration"] self.assertEqual(method_integration["credentials"], role_arn) # checking if the uri in the API integration is set for Step Functions State Machine execution expected_integration_uri = "arn:" + partition + ":apigateway:" + region + ":states:action/StartExecution" self.assertEqual(method_integration["uri"], expected_integration_uri) # checking if the role used by the event rule to trigger the state machine execution is correct start_execution_policy = get_policy_statements( role_name, policy_name, self.client_provider.iam_client) self.assertEqual( len(start_execution_policy), 1, "Only one statement must be in Start Execution policy") start_execution_policy_statement = start_execution_policy[0] self.assertTrue( type(start_execution_policy_statement["Action"]) != list) policy_action = start_execution_policy_statement["Action"] self.assertEqual( policy_action, "states:StartExecution", "Action referenced in event role policy must be 'states:StartExecution'", ) self.assertTrue( type(start_execution_policy_statement["Resource"]) != list) referenced_state_machine_arn = start_execution_policy_statement[ "Resource"] self.assertEqual( referenced_state_machine_arn, state_machine_arn, "State machine referenced in event role policy is incorrect", )
def test_state_machine_with_cwe(self): self.create_and_verify_stack("combination/state_machine_with_cwe") outputs = self.get_stack_outputs() state_machine_arn = outputs["MyStateMachineArn"] rule_name = outputs["MyEventName"] event_role_name = outputs["MyEventRole"] cloud_watch_events_client = self.client_provider.cloudwatch_event_client # Check if the CWE rule is created with the state machine as the target rule_name_by_target_result = cloud_watch_events_client.list_rule_names_by_target(TargetArn=state_machine_arn) self.assertEqual(len(rule_name_by_target_result["RuleNames"]), 1) rule_name_with_state_machine_target = rule_name_by_target_result["RuleNames"][0] self.assertEqual(rule_name_with_state_machine_target, rule_name) # checking if the role used by the event rule to trigger the state machine execution is correct start_execution_policy = get_policy_statements( event_role_name, "MyStateMachineCWEventRoleStartExecutionPolicy", self.client_provider.iam_client ) self.assertEqual(len(start_execution_policy), 1, "Only one statement must be in Start Execution policy") start_execution_policy_statement = start_execution_policy[0] self.assertTrue(type(start_execution_policy_statement["Action"]) != list) policy_action = start_execution_policy_statement["Action"] self.assertEqual( policy_action, "states:StartExecution", "Action referenced in event role policy must be 'states:StartExecution'", ) self.assertTrue(type(start_execution_policy_statement["Resource"]) != list) referenced_state_machine_arn = start_execution_policy_statement["Resource"] self.assertEqual( referenced_state_machine_arn, state_machine_arn, "State machine referenced in event role policy is incorrect", )
def test_state_machine_with_cwe(self): self.create_and_verify_stack( "combination/state_machine_with_cwe_dlq_generated") outputs = self.get_stack_outputs() state_machine_arn = outputs["MyStateMachineArn"] rule_name = outputs["MyEventName"] event_role_name = outputs["MyEventRole"] state_machine_target_dlq_arn = outputs["MyDLQArn"] state_machine_target_dlq_url = outputs["MyDLQUrl"] cloud_watch_events_client = self.client_provider.cloudwatch_event_client cw_rule_result = cloud_watch_events_client.describe_rule( Name=rule_name) # Check if the CWE rule is created with the state machine as the target rule_name_by_target_result = cloud_watch_events_client.list_rule_names_by_target( TargetArn=state_machine_arn) self.assertEqual(len(rule_name_by_target_result["RuleNames"]), 1) rule_name_with_state_machine_target = rule_name_by_target_result[ "RuleNames"][0] self.assertEqual(rule_name_with_state_machine_target, rule_name) # checking if the role used by the event rule to trigger the state machine execution is correct start_execution_policy = get_policy_statements( event_role_name, "MyStateMachineCWEventRoleStartExecutionPolicy", self.client_provider.iam_client) self.assertEqual( len(start_execution_policy), 1, "Only one statement must be in Start Execution policy") start_execution_policy_statement = start_execution_policy[0] self.assertTrue( type(start_execution_policy_statement["Action"]) != list) policy_action = start_execution_policy_statement["Action"] self.assertEqual( policy_action, "states:StartExecution", "Action referenced in event role policy must be 'states:StartExecution'", ) self.assertTrue( type(start_execution_policy_statement["Resource"]) != list) referenced_state_machine_arn = start_execution_policy_statement[ "Resource"] self.assertEqual( referenced_state_machine_arn, state_machine_arn, "State machine referenced in event role policy is incorrect", ) # checking if the target has a dead-letter queue attached to it targets = cloud_watch_events_client.list_targets_by_rule( Rule=rule_name)["Targets"] self.assertEqual(len(targets), 1, "Rule should contain a single target") target = targets[0] self.assertEqual(target["Arn"], state_machine_arn) self.assertEqual(target["DeadLetterConfig"]["Arn"], state_machine_target_dlq_arn) # checking target's retry policy properties self.assertEqual(target["RetryPolicy"]["MaximumEventAgeInSeconds"], 200) self.assertIsNone(target["RetryPolicy"].get("MaximumRetryAttempts")) # checking if the generated dead-letter queue has necessary resource based policy attached to it dlq_policy = get_queue_policy(state_machine_target_dlq_url, self.client_provider.sqs_client) self.assertEqual( len(dlq_policy), 1, "Only one statement must be in Dead-letter queue policy") dlq_policy_statement = dlq_policy[0] # checking policy action self.assertFalse( isinstance(dlq_policy_statement["Action"], list), "Only one action must be in dead-letter queue policy" ) # if it is an array, it means has more than one action self.assertEqual( dlq_policy_statement["Action"], "sqs:SendMessage", "Action referenced in dead-letter queue policy must be 'sqs:SendMessage'", ) # checking service principal self.assertEqual( len(dlq_policy_statement["Principal"]), 1, ) self.assertEqual( dlq_policy_statement["Principal"]["Service"], "events.amazonaws.com", "Policy should grant EventBridge service principal to send messages to dead-letter queue", ) # checking condition type key, value = get_first_key_value_pair_in_dict( dlq_policy_statement["Condition"]) self.assertEqual(key, "ArnEquals") # checking condition key self.assertEqual(len(dlq_policy_statement["Condition"]), 1) condition_kay, condition_value = get_first_key_value_pair_in_dict( value) self.assertEqual(condition_kay, "aws:SourceArn") # checking condition value self.assertEqual(len(dlq_policy_statement["Condition"][key]), 1) self.assertEqual( condition_value, cw_rule_result["Arn"], "Policy should only allow requests coming from schedule rule resource", )
def test_state_machine_with_schedule(self): self.create_and_verify_stack( "combination/state_machine_with_schedule_dlq_and_retry_policy") outputs = self.get_stack_outputs() state_machine_arn = outputs["MyStateMachineArn"] schedule_name = outputs["MyScheduleName"] state_machine_target_dlq_arn = outputs["MyDLQArn"] event_role_name = outputs["MyEventRole"] # get the cloudwatch schedule rule cloud_watch_event_client = self.client_provider.cloudwatch_event_client cw_rule_result = cloud_watch_event_client.describe_rule( Name=schedule_name) # checking if the name, description and state properties are correct self.assertEqual(cw_rule_result["Name"], schedule_name) self.assertEqual(cw_rule_result["Description"], "test schedule") self.assertEqual(cw_rule_result["State"], "DISABLED") self.assertEqual(cw_rule_result["ScheduleExpression"], "rate(1 minute)") # checking if the target's DLQ and RetryPolicy properties are correct targets = cloud_watch_event_client.list_targets_by_rule( Rule=schedule_name)["Targets"] self.assertEqual(len(targets), 1, "Rule should contain a single target") target = targets[0] self.assertEqual(target["Arn"], state_machine_arn) self.assertEqual(target["DeadLetterConfig"]["Arn"], state_machine_target_dlq_arn) self.assertIsNone( target["RetryPolicy"].get("MaximumEventAgeInSeconds")) self.assertEqual(target["RetryPolicy"]["MaximumRetryAttempts"], 2) # checking if the role used by the event rule to trigger the state machine execution is correct start_execution_policy = get_policy_statements( event_role_name, "MyStateMachineCWScheduleRoleStartExecutionPolicy", self.client_provider.iam_client) self.assertEqual( len(start_execution_policy), 1, "Only one statement must be in Start Execution policy") start_execution_policy_statement = start_execution_policy[0] self.assertTrue( type(start_execution_policy_statement["Action"]) != list) policy_action = start_execution_policy_statement["Action"] self.assertEqual( policy_action, "states:StartExecution", "Action referenced in event role policy must be 'states:StartExecution'", ) self.assertTrue( type(start_execution_policy_statement["Resource"]) != list) referenced_state_machine_arn = start_execution_policy_statement[ "Resource"] self.assertEqual( referenced_state_machine_arn, state_machine_arn, "State machine referenced in event role policy is incorrect", )