From 099b36c5046b5656281786838f399c16600cdea8 Mon Sep 17 00:00:00 2001 From: connorrobertson Date: Mon, 14 Nov 2022 15:11:58 -0800 Subject: [PATCH 01/10] [WIP] Create SAM Statemachine without Policy --- Makefile | 2 +- integration/combination/test_connectors.py | 1 + ...cket_to_function_write_without_policy.json | 34 +++++++ ...cket_to_function_write_without_policy.yaml | 89 +++++++++++++++++++ pytest.ini | 2 +- .../model/stepfunctions/generators.py | 27 ++++-- .../test_state_machine_generator.py | 8 +- 7 files changed, 150 insertions(+), 13 deletions(-) create mode 100644 integration/resources/expected/combination/connector_bucket_to_function_write_without_policy.json create mode 100644 integration/resources/templates/combination/connector_bucket_to_function_write_without_policy.yaml diff --git a/Makefile b/Makefile index 6da84ab35..b8a5d804f 100755 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ test-cov-report: pytest --cov samtranslator --cov-report term-missing --cov-report html --cov-fail-under 95 tests/* integ-test: - pytest --no-cov integration/* + pytest --no-cov integration/* -k test_function_with_alias_with_intrinsics --pdb black: black setup.py samtranslator/* tests/* integration/* bin/*.py diff --git a/integration/combination/test_connectors.py b/integration/combination/test_connectors.py index 1fa84123c..944f952f4 100644 --- a/integration/combination/test_connectors.py +++ b/integration/combination/test_connectors.py @@ -132,6 +132,7 @@ def test_connector_by_async_execute_an_state_machine(self, template_file_path): @parameterized.expand( [ ("combination/connector_bucket_to_function_write",), + ("combination/connector_bucket_to_function_write_without_policy",), ] ) @retry_once diff --git a/integration/resources/expected/combination/connector_bucket_to_function_write_without_policy.json b/integration/resources/expected/combination/connector_bucket_to_function_write_without_policy.json new file mode 100644 index 000000000..864279699 --- /dev/null +++ b/integration/resources/expected/combination/connector_bucket_to_function_write_without_policy.json @@ -0,0 +1,34 @@ +[ + { + "LogicalResourceId": "TriggerFunctionRole", + "ResourceType": "AWS::IAM::Role" + }, + { + "LogicalResourceId": "TriggerFunction", + "ResourceType": "AWS::Lambda::Function" + }, + { + "LogicalResourceId": "InvokedFunctionRole", + "ResourceType": "AWS::IAM::Role" + }, + { + "LogicalResourceId": "InvokedFunction", + "ResourceType": "AWS::Lambda::Function" + }, + { + "LogicalResourceId": "TriggerBucket", + "ResourceType": "AWS::S3::Bucket" + }, + { + "LogicalResourceId": "VerificationQueue", + "ResourceType": "AWS::SQS::Queue" + }, + { + "LogicalResourceId": "MyConnectorWriteLambdaPermission", + "ResourceType": "AWS::Lambda::Permission" + }, + { + "LogicalResourceId": "ConnectorNotTestedPolicy", + "ResourceType": "AWS::IAM::ManagedPolicy" + } + ] \ No newline at end of file diff --git a/integration/resources/templates/combination/connector_bucket_to_function_write_without_policy.yaml b/integration/resources/templates/combination/connector_bucket_to_function_write_without_policy.yaml new file mode 100644 index 000000000..f43c9ccf3 --- /dev/null +++ b/integration/resources/templates/combination/connector_bucket_to_function_write_without_policy.yaml @@ -0,0 +1,89 @@ +Parameters: + BucketName: + Type: String + +Resources: + VerificationQueue: + Type: AWS::SQS::Queue + + TriggerFunction: + Type: AWS::Serverless::Function + Properties: + Runtime: nodejs14.x + Handler: index.handler + Timeout: 10 # in case eb has delay + InlineCode: | + const AWS = require('aws-sdk'); + exports.handler = async (event) => { + var params = { + Bucket: process.env.BUCKET_NAME, + Key: "MyKey", + Body: JSON.stringify("Test Message") + }; + var s3 = new AWS.S3(); + await s3.putObject(params).promise(); + + const data = await new AWS.SQS().receiveMessage({ + QueueUrl: process.env.VERIFICATION_QUEUE_URL, + WaitTimeSeconds: 5, + }).promise(); + if (data.Messages.length == 0) { + throw 'No messages in the queue!'; + } + }; + Environment: + Variables: + BUCKET_NAME: !Ref TriggerBucket + VERIFICATION_QUEUE_URL: !Ref VerificationQueue + + InvokedFunction: + Type: AWS::Serverless::Function + Properties: + Runtime: nodejs14.x + Handler: index.handler + InlineCode: | + const AWS = require('aws-sdk'); + exports.handler = async (event) => { + const sqs = new AWS.SQS(); + await sqs.sendMessage({ + QueueUrl: process.env.VERIFICATION_QUEUE_URL, + MessageBody: "test" + }).promise(); + }; + Environment: + Variables: + VERIFICATION_QUEUE_URL: !Ref VerificationQueue + + + TriggerBucket: + # See also https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket-notificationconfig.html + DependsOn: MyConnector + Type: AWS::S3::Bucket + Properties: + BucketName: !Ref BucketName + NotificationConfiguration: + LambdaConfigurations: + - Event: 's3:ObjectCreated:*' + Function: !GetAtt InvokedFunction.Arn + + MyConnector: + Type: AWS::Serverless::Connector + Properties: + Source: + Type: AWS::S3::Bucket + Arn: !Sub arn:${AWS::Partition}:s3:::${BucketName} + Destination: + Id: InvokedFunction + Permissions: + - Write + + ConnectorNotTested: + Type: AWS::Serverless::Connector + Properties: + Source: + Id: TriggerFunction + Destination: + Id: TriggerBucket + Permissions: + - Write + \ No newline at end of file diff --git a/pytest.ini b/pytest.ini index 5e98ba5f1..7e50975a3 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,7 +1,7 @@ [pytest] # Fail if coverage falls below 95% # NOTE: If debug breakpoints aren't working, comment out the code coverage line below -addopts = --cov samtranslator --cov-report term-missing --cov-fail-under 95 --reruns 1 +addopts = --cov samtranslator --cov-report term-missing --cov-fail-under 95 testpaths = tests markers = slow: marks tests as slow (deselect with '-m "not slow"') diff --git a/samtranslator/model/stepfunctions/generators.py b/samtranslator/model/stepfunctions/generators.py index 1a0865f35..29f13bd1e 100644 --- a/samtranslator/model/stepfunctions/generators.py +++ b/samtranslator/model/stepfunctions/generators.py @@ -134,15 +134,32 @@ def to_cloudformation(self): # type: ignore[no-untyped-def] ) if self.role: self.state_machine.RoleArn = self.role - elif self.policies: - if not self.managed_policy_map: + elif not self.role: + if self.policies and not self.managed_policy_map: raise Exception("Managed policy map is empty, but should not be.") - + if not self.policies: + self.policies = [{ + "Version": "2012-10-17", + "Statement": [{ + "Effect": "Allow", + "Action": ["iam:*", + "organizations:DescribeAccount", + "organizations:DescribeOrganization", + "organizations:DescribeOrganizationalUnit", + "organizations:DescribePolicy", + "organizations:ListChildren", + "organizations:ListParents", + "organizations:ListPoliciesForTarget", + "organizations:ListRoots", + "organizations:ListPolicies", + "organizations:ListTargetsForPolicy"], + "Resource": "*" + } + ] +}] execution_role = self._construct_role() # type: ignore[no-untyped-call] self.state_machine.RoleArn = execution_role.get_runtime_attr("arn") resources.append(execution_role) - else: - raise InvalidResourceException(self.logical_id, "Either 'Role' or 'Policies' property must be specified.") self.state_machine.StateMachineName = self.name self.state_machine.StateMachineType = self.type diff --git a/tests/model/stepfunctions/test_state_machine_generator.py b/tests/model/stepfunctions/test_state_machine_generator.py index cf5f747e6..8e21e4919 100644 --- a/tests/model/stepfunctions/test_state_machine_generator.py +++ b/tests/model/stepfunctions/test_state_machine_generator.py @@ -56,12 +56,8 @@ def test_state_machine_no_role_or_policies(self): self.kwargs["definition_uri"] = "s3://my-demo-bucket/my_asl_file.asl.json" self.kwargs["role"] = None self.kwargs["policies"] = None - with self.assertRaises(InvalidResourceException) as error: - StateMachineGenerator(**self.kwargs).to_cloudformation() - self.assertEqual( - error.exception.message, - "Resource with id [StateMachineId] is invalid. Either 'Role' or 'Policies' property must be specified.", - ) + generated_event_resources = StateMachineGenerator(**self.kwargs).to_cloudformation() + self.assertEqual(generated_event_resources[1].resource_type, "AWS::IAM::Role") def test_state_machine_both_role_and_policies(self): self.kwargs["definition_uri"] = "s3://my-demo-bucket/my_asl_file.asl.json" From 7f95a135fc599ca2aca3e5c254a333fd4649b433 Mon Sep 17 00:00:00 2001 From: connorrobertson Date: Mon, 14 Nov 2022 16:36:30 -0800 Subject: [PATCH 02/10] Changed basic_state_machine_inline_definition test to work without policy --- Makefile | 2 +- integration/combination/test_connectors.py | 1 - ...cket_to_function_write_without_policy.json | 34 ------- ...cket_to_function_write_without_policy.yaml | 89 ------------------- ...basic_state_machine_inline_definition.yaml | 6 -- 5 files changed, 1 insertion(+), 131 deletions(-) delete mode 100644 integration/resources/expected/combination/connector_bucket_to_function_write_without_policy.json delete mode 100644 integration/resources/templates/combination/connector_bucket_to_function_write_without_policy.yaml diff --git a/Makefile b/Makefile index b8a5d804f..a1317b4d5 100755 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ test-cov-report: pytest --cov samtranslator --cov-report term-missing --cov-report html --cov-fail-under 95 tests/* integ-test: - pytest --no-cov integration/* -k test_function_with_alias_with_intrinsics --pdb + pytest --no-cov integration/* -k test_state_machine_with_cwe_without_policy black: black setup.py samtranslator/* tests/* integration/* bin/*.py diff --git a/integration/combination/test_connectors.py b/integration/combination/test_connectors.py index 944f952f4..1fa84123c 100644 --- a/integration/combination/test_connectors.py +++ b/integration/combination/test_connectors.py @@ -132,7 +132,6 @@ def test_connector_by_async_execute_an_state_machine(self, template_file_path): @parameterized.expand( [ ("combination/connector_bucket_to_function_write",), - ("combination/connector_bucket_to_function_write_without_policy",), ] ) @retry_once diff --git a/integration/resources/expected/combination/connector_bucket_to_function_write_without_policy.json b/integration/resources/expected/combination/connector_bucket_to_function_write_without_policy.json deleted file mode 100644 index 864279699..000000000 --- a/integration/resources/expected/combination/connector_bucket_to_function_write_without_policy.json +++ /dev/null @@ -1,34 +0,0 @@ -[ - { - "LogicalResourceId": "TriggerFunctionRole", - "ResourceType": "AWS::IAM::Role" - }, - { - "LogicalResourceId": "TriggerFunction", - "ResourceType": "AWS::Lambda::Function" - }, - { - "LogicalResourceId": "InvokedFunctionRole", - "ResourceType": "AWS::IAM::Role" - }, - { - "LogicalResourceId": "InvokedFunction", - "ResourceType": "AWS::Lambda::Function" - }, - { - "LogicalResourceId": "TriggerBucket", - "ResourceType": "AWS::S3::Bucket" - }, - { - "LogicalResourceId": "VerificationQueue", - "ResourceType": "AWS::SQS::Queue" - }, - { - "LogicalResourceId": "MyConnectorWriteLambdaPermission", - "ResourceType": "AWS::Lambda::Permission" - }, - { - "LogicalResourceId": "ConnectorNotTestedPolicy", - "ResourceType": "AWS::IAM::ManagedPolicy" - } - ] \ No newline at end of file diff --git a/integration/resources/templates/combination/connector_bucket_to_function_write_without_policy.yaml b/integration/resources/templates/combination/connector_bucket_to_function_write_without_policy.yaml deleted file mode 100644 index f43c9ccf3..000000000 --- a/integration/resources/templates/combination/connector_bucket_to_function_write_without_policy.yaml +++ /dev/null @@ -1,89 +0,0 @@ -Parameters: - BucketName: - Type: String - -Resources: - VerificationQueue: - Type: AWS::SQS::Queue - - TriggerFunction: - Type: AWS::Serverless::Function - Properties: - Runtime: nodejs14.x - Handler: index.handler - Timeout: 10 # in case eb has delay - InlineCode: | - const AWS = require('aws-sdk'); - exports.handler = async (event) => { - var params = { - Bucket: process.env.BUCKET_NAME, - Key: "MyKey", - Body: JSON.stringify("Test Message") - }; - var s3 = new AWS.S3(); - await s3.putObject(params).promise(); - - const data = await new AWS.SQS().receiveMessage({ - QueueUrl: process.env.VERIFICATION_QUEUE_URL, - WaitTimeSeconds: 5, - }).promise(); - if (data.Messages.length == 0) { - throw 'No messages in the queue!'; - } - }; - Environment: - Variables: - BUCKET_NAME: !Ref TriggerBucket - VERIFICATION_QUEUE_URL: !Ref VerificationQueue - - InvokedFunction: - Type: AWS::Serverless::Function - Properties: - Runtime: nodejs14.x - Handler: index.handler - InlineCode: | - const AWS = require('aws-sdk'); - exports.handler = async (event) => { - const sqs = new AWS.SQS(); - await sqs.sendMessage({ - QueueUrl: process.env.VERIFICATION_QUEUE_URL, - MessageBody: "test" - }).promise(); - }; - Environment: - Variables: - VERIFICATION_QUEUE_URL: !Ref VerificationQueue - - - TriggerBucket: - # See also https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket-notificationconfig.html - DependsOn: MyConnector - Type: AWS::S3::Bucket - Properties: - BucketName: !Ref BucketName - NotificationConfiguration: - LambdaConfigurations: - - Event: 's3:ObjectCreated:*' - Function: !GetAtt InvokedFunction.Arn - - MyConnector: - Type: AWS::Serverless::Connector - Properties: - Source: - Type: AWS::S3::Bucket - Arn: !Sub arn:${AWS::Partition}:s3:::${BucketName} - Destination: - Id: InvokedFunction - Permissions: - - Write - - ConnectorNotTested: - Type: AWS::Serverless::Connector - Properties: - Source: - Id: TriggerFunction - Destination: - Id: TriggerBucket - Permissions: - - Write - \ No newline at end of file diff --git a/integration/resources/templates/single/basic_state_machine_inline_definition.yaml b/integration/resources/templates/single/basic_state_machine_inline_definition.yaml index 8fb8a16cd..c24e330cd 100644 --- a/integration/resources/templates/single/basic_state_machine_inline_definition.yaml +++ b/integration/resources/templates/single/basic_state_machine_inline_definition.yaml @@ -15,9 +15,3 @@ Resources: Type: Pass Result: World End: true - Policies: - - Version: '2012-10-17' - Statement: - - Effect: Deny - Action: "*" - Resource: "*" From 5c98256ced68944ff5ec4ae3eb3cd6c5e207969f Mon Sep 17 00:00:00 2001 From: connorrobertson Date: Tue, 15 Nov 2022 09:35:25 -0800 Subject: [PATCH 03/10] Made generated policy more limited. --- .../model/stepfunctions/generators.py | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/samtranslator/model/stepfunctions/generators.py b/samtranslator/model/stepfunctions/generators.py index 29f13bd1e..3758be087 100644 --- a/samtranslator/model/stepfunctions/generators.py +++ b/samtranslator/model/stepfunctions/generators.py @@ -141,22 +141,10 @@ def to_cloudformation(self): # type: ignore[no-untyped-def] self.policies = [{ "Version": "2012-10-17", "Statement": [{ - "Effect": "Allow", - "Action": ["iam:*", - "organizations:DescribeAccount", - "organizations:DescribeOrganization", - "organizations:DescribeOrganizationalUnit", - "organizations:DescribePolicy", - "organizations:ListChildren", - "organizations:ListParents", - "organizations:ListPoliciesForTarget", - "organizations:ListRoots", - "organizations:ListPolicies", - "organizations:ListTargetsForPolicy"], + "Effect": "Deny", + "Action": "*", "Resource": "*" - } - ] -}] + }]}] execution_role = self._construct_role() # type: ignore[no-untyped-call] self.state_machine.RoleArn = execution_role.get_runtime_attr("arn") resources.append(execution_role) From 003a25eb8894db1dd41513eb8f7610be9e17fd4f Mon Sep 17 00:00:00 2001 From: connorrobertson Date: Wed, 16 Nov 2022 11:09:28 -0800 Subject: [PATCH 04/10] Changed the error message and policy used to a better policy --- Makefile | 2 +- pytest.ini | 2 +- .../model/stepfunctions/generators.py | 20 +++++++++++-------- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index a1317b4d5..6da84ab35 100755 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ test-cov-report: pytest --cov samtranslator --cov-report term-missing --cov-report html --cov-fail-under 95 tests/* integ-test: - pytest --no-cov integration/* -k test_state_machine_with_cwe_without_policy + pytest --no-cov integration/* black: black setup.py samtranslator/* tests/* integration/* bin/*.py diff --git a/pytest.ini b/pytest.ini index 7e50975a3..5e98ba5f1 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,7 +1,7 @@ [pytest] # Fail if coverage falls below 95% # NOTE: If debug breakpoints aren't working, comment out the code coverage line below -addopts = --cov samtranslator --cov-report term-missing --cov-fail-under 95 +addopts = --cov samtranslator --cov-report term-missing --cov-fail-under 95 --reruns 1 testpaths = tests markers = slow: marks tests as slow (deselect with '-m "not slow"') diff --git a/samtranslator/model/stepfunctions/generators.py b/samtranslator/model/stepfunctions/generators.py index 3758be087..44d7662bb 100644 --- a/samtranslator/model/stepfunctions/generators.py +++ b/samtranslator/model/stepfunctions/generators.py @@ -130,7 +130,7 @@ def to_cloudformation(self): # type: ignore[no-untyped-def] if self.role and self.policies: raise InvalidResourceException( - self.logical_id, "Specify either 'Role' or 'Policies' property and not both." + self.logical_id, "Specify either 'Role' or 'Policies' or neither property and not both." ) if self.role: self.state_machine.RoleArn = self.role @@ -138,13 +138,17 @@ def to_cloudformation(self): # type: ignore[no-untyped-def] if self.policies and not self.managed_policy_map: raise Exception("Managed policy map is empty, but should not be.") if not self.policies: - self.policies = [{ - "Version": "2012-10-17", - "Statement": [{ - "Effect": "Deny", - "Action": "*", - "Resource": "*" - }]}] + self.policies = [ + { "Version": "2012-10-17", + "Statement": [ { + "Action": ["sts:AssumeRole"], + "Effect": "Allow", + "Principal": { + "Service": ["states.amazonaws.com"] + }, + }], + } + ] execution_role = self._construct_role() # type: ignore[no-untyped-call] self.state_machine.RoleArn = execution_role.get_runtime_attr("arn") resources.append(execution_role) From ba6d5e58acd5299fff06eaa8f60f8024c1ba5436 Mon Sep 17 00:00:00 2001 From: connorrobertson Date: Thu, 17 Nov 2022 10:16:17 -0800 Subject: [PATCH 05/10] Created integration tests and fixed error message when giving both a role and policy --- integration/combination/test_connectors.py | 1 + ...nector_sfn_to_function_without_policy.json | 22 ++++++++++++ ...nector_sfn_to_function_without_policy.yaml | 34 +++++++++++++++++++ ...basic_state_machine_inline_definition.yaml | 6 ++++ .../model/stepfunctions/generators.py | 23 ++++++------- .../test_state_machine_generator.py | 2 +- 6 files changed, 75 insertions(+), 13 deletions(-) create mode 100644 integration/resources/expected/combination/connector_sfn_to_function_without_policy.json create mode 100644 integration/resources/templates/combination/connector_sfn_to_function_without_policy.yaml diff --git a/integration/combination/test_connectors.py b/integration/combination/test_connectors.py index 1fa84123c..1efed2521 100644 --- a/integration/combination/test_connectors.py +++ b/integration/combination/test_connectors.py @@ -69,6 +69,7 @@ def test_connector_by_invoking_a_function(self, template_file_path): @parameterized.expand( [ + ("combination/connector_sfn_to_function_without_policy",), ("combination/connector_sfn_to_table_read",), ("combination/connector_sfn_to_table_write",), ("combination/connector_sfn_to_sqs_write",), diff --git a/integration/resources/expected/combination/connector_sfn_to_function_without_policy.json b/integration/resources/expected/combination/connector_sfn_to_function_without_policy.json new file mode 100644 index 000000000..3dbdcbec4 --- /dev/null +++ b/integration/resources/expected/combination/connector_sfn_to_function_without_policy.json @@ -0,0 +1,22 @@ +[ + { + "LogicalResourceId": "TriggerStateMachineRole", + "ResourceType": "AWS::IAM::Role" + }, + { + "LogicalResourceId": "MyFunctionRole", + "ResourceType": "AWS::IAM::Role" + }, + { + "LogicalResourceId": "TriggerStateMachine", + "ResourceType": "AWS::StepFunctions::StateMachine" + }, + { + "LogicalResourceId": "MyFunction", + "ResourceType": "AWS::Lambda::Function" + }, + { + "LogicalResourceId": "MyConnectorPolicy", + "ResourceType": "AWS::IAM::ManagedPolicy" + } + ] \ No newline at end of file diff --git a/integration/resources/templates/combination/connector_sfn_to_function_without_policy.yaml b/integration/resources/templates/combination/connector_sfn_to_function_without_policy.yaml new file mode 100644 index 000000000..2fde4c80c --- /dev/null +++ b/integration/resources/templates/combination/connector_sfn_to_function_without_policy.yaml @@ -0,0 +1,34 @@ +Resources: + TriggerStateMachine: + Type: AWS::Serverless::StateMachine + Properties: + Type: EXPRESS + Definition: + StartAt: TryDoSomething + States: + TryDoSomething: + Type: Task + Resource: !Sub arn:${AWS::Partition}:states:::lambda:invoke + Parameters: + FunctionName: !Ref MyFunction + End: True + + MyFunction: + Type: AWS::Serverless::Function + Properties: + Runtime: nodejs14.x + Handler: index.handler + InlineCode: | + exports.handler = async (event) => { + console.log(JSON.stringify(event)); + }; + + MyConnector: + Type: AWS::Serverless::Connector + Properties: + Source: + Id: TriggerStateMachine + Destination: + Id: MyFunction + Permissions: + - Write diff --git a/integration/resources/templates/single/basic_state_machine_inline_definition.yaml b/integration/resources/templates/single/basic_state_machine_inline_definition.yaml index c24e330cd..8fb8a16cd 100644 --- a/integration/resources/templates/single/basic_state_machine_inline_definition.yaml +++ b/integration/resources/templates/single/basic_state_machine_inline_definition.yaml @@ -15,3 +15,9 @@ Resources: Type: Pass Result: World End: true + Policies: + - Version: '2012-10-17' + Statement: + - Effect: Deny + Action: "*" + Resource: "*" diff --git a/samtranslator/model/stepfunctions/generators.py b/samtranslator/model/stepfunctions/generators.py index 44d7662bb..5427b3fc5 100644 --- a/samtranslator/model/stepfunctions/generators.py +++ b/samtranslator/model/stepfunctions/generators.py @@ -129,24 +129,23 @@ def to_cloudformation(self): # type: ignore[no-untyped-def] ) if self.role and self.policies: - raise InvalidResourceException( - self.logical_id, "Specify either 'Role' or 'Policies' or neither property and not both." - ) + raise InvalidResourceException(self.logical_id, "Specify 'Role' or 'Policies' or neither property.") if self.role: self.state_machine.RoleArn = self.role - elif not self.role: + else: if self.policies and not self.managed_policy_map: raise Exception("Managed policy map is empty, but should not be.") if not self.policies: self.policies = [ - { "Version": "2012-10-17", - "Statement": [ { - "Action": ["sts:AssumeRole"], - "Effect": "Allow", - "Principal": { - "Service": ["states.amazonaws.com"] - }, - }], + { + "Version": "2012-10-17", + "Statement": [ + { + "Action": ["Lambda:InvokeFunction"], + "Effect": "Allow", + "Resource": "arn:aws:lambda:us-west-2:534568764167:function:SomethingDoesNotMatter*", + } + ], } ] execution_role = self._construct_role() # type: ignore[no-untyped-call] diff --git a/tests/model/stepfunctions/test_state_machine_generator.py b/tests/model/stepfunctions/test_state_machine_generator.py index 8e21e4919..e5528f2dd 100644 --- a/tests/model/stepfunctions/test_state_machine_generator.py +++ b/tests/model/stepfunctions/test_state_machine_generator.py @@ -69,7 +69,7 @@ def test_state_machine_both_role_and_policies(self): StateMachineGenerator(**self.kwargs).to_cloudformation() self.assertEqual( error.exception.message, - "Resource with id [StateMachineId] is invalid. Specify either 'Role' or 'Policies' property and not both.", + "Resource with id [StateMachineId] is invalid. Specify 'Role' or 'Policies' or neither property.", ) def test_state_machine_invalid_definition_uri_string(self): From 78f471718c0ac322e7223ab34ca31f21c90f4f7a Mon Sep 17 00:00:00 2001 From: connorrobertson Date: Thu, 17 Nov 2022 15:08:54 -0800 Subject: [PATCH 06/10] Making the generated role use an empty policy. --- samtranslator/model/stepfunctions/generators.py | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/samtranslator/model/stepfunctions/generators.py b/samtranslator/model/stepfunctions/generators.py index 5427b3fc5..3196a7a3f 100644 --- a/samtranslator/model/stepfunctions/generators.py +++ b/samtranslator/model/stepfunctions/generators.py @@ -136,18 +136,7 @@ def to_cloudformation(self): # type: ignore[no-untyped-def] if self.policies and not self.managed_policy_map: raise Exception("Managed policy map is empty, but should not be.") if not self.policies: - self.policies = [ - { - "Version": "2012-10-17", - "Statement": [ - { - "Action": ["Lambda:InvokeFunction"], - "Effect": "Allow", - "Resource": "arn:aws:lambda:us-west-2:534568764167:function:SomethingDoesNotMatter*", - } - ], - } - ] + self.policies = [] execution_role = self._construct_role() # type: ignore[no-untyped-call] self.state_machine.RoleArn = execution_role.get_runtime_attr("arn") resources.append(execution_role) @@ -216,7 +205,7 @@ def _construct_role(self): # type: ignore[no-untyped-def] :rtype: model.iam.IAMRole """ policies = self.policies[:] - if self.tracing and self.tracing.get("Enabled") is True: + if self.tracing and self.tracing.get("Enabled") is True and self.policies: policies.append(get_xray_managed_policy_name()) # type: ignore[no-untyped-call] state_machine_policies = ResourcePolicies( # type: ignore[no-untyped-call] From 787e2b83faab91129bdcd3b0d6f2762722ba63f4 Mon Sep 17 00:00:00 2001 From: connorrobertson Date: Fri, 18 Nov 2022 13:25:18 -0800 Subject: [PATCH 07/10] Added changes requested by Slava and cleaned up --- samtranslator/model/stepfunctions/generators.py | 6 ++++-- tests/model/stepfunctions/test_state_machine_generator.py | 7 ++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/samtranslator/model/stepfunctions/generators.py b/samtranslator/model/stepfunctions/generators.py index 3196a7a3f..52693930d 100644 --- a/samtranslator/model/stepfunctions/generators.py +++ b/samtranslator/model/stepfunctions/generators.py @@ -21,6 +21,8 @@ class StateMachineGenerator(object): _SAM_VALUE = "SAM" _SUBSTITUTION_NAME_TEMPLATE = "definition_substitution_%s" _SUBSTITUTION_KEY_TEMPLATE = "${definition_substitution_%s}" + SFN_INVALID_PROPERTY_BOTH_ROLE_POLICY = "Specify either 'Role' or 'Policies' (but not both at the same time) or neither of them" + def __init__( # type: ignore[no-untyped-def] self, @@ -129,7 +131,7 @@ def to_cloudformation(self): # type: ignore[no-untyped-def] ) if self.role and self.policies: - raise InvalidResourceException(self.logical_id, "Specify 'Role' or 'Policies' or neither property.") + raise InvalidResourceException(self.logical_id, self.SFN_INVALID_PROPERTY_BOTH_ROLE_POLICY) if self.role: self.state_machine.RoleArn = self.role else: @@ -205,7 +207,7 @@ def _construct_role(self): # type: ignore[no-untyped-def] :rtype: model.iam.IAMRole """ policies = self.policies[:] - if self.tracing and self.tracing.get("Enabled") is True and self.policies: + if self.tracing and self.tracing.get("Enabled") is True: policies.append(get_xray_managed_policy_name()) # type: ignore[no-untyped-call] state_machine_policies = ResourcePolicies( # type: ignore[no-untyped-call] diff --git a/tests/model/stepfunctions/test_state_machine_generator.py b/tests/model/stepfunctions/test_state_machine_generator.py index e5528f2dd..df002aacf 100644 --- a/tests/model/stepfunctions/test_state_machine_generator.py +++ b/tests/model/stepfunctions/test_state_machine_generator.py @@ -56,8 +56,8 @@ def test_state_machine_no_role_or_policies(self): self.kwargs["definition_uri"] = "s3://my-demo-bucket/my_asl_file.asl.json" self.kwargs["role"] = None self.kwargs["policies"] = None - generated_event_resources = StateMachineGenerator(**self.kwargs).to_cloudformation() - self.assertEqual(generated_event_resources[1].resource_type, "AWS::IAM::Role") + generated_resources = StateMachineGenerator(**self.kwargs).to_cloudformation() + self.assertEqual(generated_resources[1].resource_type, "AWS::IAM::Role") def test_state_machine_both_role_and_policies(self): self.kwargs["definition_uri"] = "s3://my-demo-bucket/my_asl_file.asl.json" @@ -69,7 +69,8 @@ def test_state_machine_both_role_and_policies(self): StateMachineGenerator(**self.kwargs).to_cloudformation() self.assertEqual( error.exception.message, - "Resource with id [StateMachineId] is invalid. Specify 'Role' or 'Policies' or neither property.", + "Resource with id [StateMachineId] is invalid. " + + StateMachineGenerator.SFN_INVALID_PROPERTY_BOTH_ROLE_POLICY, ) def test_state_machine_invalid_definition_uri_string(self): From 9b78d94a30bf28e122aa1b2bd1a6e91b65da7d51 Mon Sep 17 00:00:00 2001 From: connorrobertson Date: Fri, 18 Nov 2022 14:40:30 -0800 Subject: [PATCH 08/10] Ran make pr --- samtranslator/model/stepfunctions/generators.py | 5 +++-- tests/model/stepfunctions/test_state_machine_generator.py | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/samtranslator/model/stepfunctions/generators.py b/samtranslator/model/stepfunctions/generators.py index 52693930d..f76aa65f6 100644 --- a/samtranslator/model/stepfunctions/generators.py +++ b/samtranslator/model/stepfunctions/generators.py @@ -21,8 +21,9 @@ class StateMachineGenerator(object): _SAM_VALUE = "SAM" _SUBSTITUTION_NAME_TEMPLATE = "definition_substitution_%s" _SUBSTITUTION_KEY_TEMPLATE = "${definition_substitution_%s}" - SFN_INVALID_PROPERTY_BOTH_ROLE_POLICY = "Specify either 'Role' or 'Policies' (but not both at the same time) or neither of them" - + SFN_INVALID_PROPERTY_BOTH_ROLE_POLICY = ( + "Specify either 'Role' or 'Policies' (but not both at the same time) or neither of them" + ) def __init__( # type: ignore[no-untyped-def] self, diff --git a/tests/model/stepfunctions/test_state_machine_generator.py b/tests/model/stepfunctions/test_state_machine_generator.py index df002aacf..2b1cb726f 100644 --- a/tests/model/stepfunctions/test_state_machine_generator.py +++ b/tests/model/stepfunctions/test_state_machine_generator.py @@ -69,8 +69,8 @@ def test_state_machine_both_role_and_policies(self): StateMachineGenerator(**self.kwargs).to_cloudformation() self.assertEqual( error.exception.message, - "Resource with id [StateMachineId] is invalid. " + - StateMachineGenerator.SFN_INVALID_PROPERTY_BOTH_ROLE_POLICY, + "Resource with id [StateMachineId] is invalid. " + + StateMachineGenerator.SFN_INVALID_PROPERTY_BOTH_ROLE_POLICY, ) def test_state_machine_invalid_definition_uri_string(self): From dbd12ad3472a6f4b2430243eae776b2c9a9ab426 Mon Sep 17 00:00:00 2001 From: connorrobertson Date: Fri, 18 Nov 2022 15:20:23 -0800 Subject: [PATCH 09/10] Ran make pr --- ...nector_sfn_to_function_without_policy.json | 42 +++++++++---------- ...nector_sfn_to_function_without_policy.yaml | 6 ++- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/integration/resources/expected/combination/connector_sfn_to_function_without_policy.json b/integration/resources/expected/combination/connector_sfn_to_function_without_policy.json index 3dbdcbec4..6ba1b3b23 100644 --- a/integration/resources/expected/combination/connector_sfn_to_function_without_policy.json +++ b/integration/resources/expected/combination/connector_sfn_to_function_without_policy.json @@ -1,22 +1,22 @@ [ - { - "LogicalResourceId": "TriggerStateMachineRole", - "ResourceType": "AWS::IAM::Role" - }, - { - "LogicalResourceId": "MyFunctionRole", - "ResourceType": "AWS::IAM::Role" - }, - { - "LogicalResourceId": "TriggerStateMachine", - "ResourceType": "AWS::StepFunctions::StateMachine" - }, - { - "LogicalResourceId": "MyFunction", - "ResourceType": "AWS::Lambda::Function" - }, - { - "LogicalResourceId": "MyConnectorPolicy", - "ResourceType": "AWS::IAM::ManagedPolicy" - } - ] \ No newline at end of file + { + "LogicalResourceId": "TriggerStateMachineRole", + "ResourceType": "AWS::IAM::Role" + }, + { + "LogicalResourceId": "MyFunctionRole", + "ResourceType": "AWS::IAM::Role" + }, + { + "LogicalResourceId": "TriggerStateMachine", + "ResourceType": "AWS::StepFunctions::StateMachine" + }, + { + "LogicalResourceId": "MyFunction", + "ResourceType": "AWS::Lambda::Function" + }, + { + "LogicalResourceId": "MyConnectorPolicy", + "ResourceType": "AWS::IAM::ManagedPolicy" + } +] diff --git a/integration/resources/templates/combination/connector_sfn_to_function_without_policy.yaml b/integration/resources/templates/combination/connector_sfn_to_function_without_policy.yaml index 2fde4c80c..a011a40d3 100644 --- a/integration/resources/templates/combination/connector_sfn_to_function_without_policy.yaml +++ b/integration/resources/templates/combination/connector_sfn_to_function_without_policy.yaml @@ -11,7 +11,7 @@ Resources: Resource: !Sub arn:${AWS::Partition}:states:::lambda:invoke Parameters: FunctionName: !Ref MyFunction - End: True + End: true MyFunction: Type: AWS::Serverless::Function @@ -31,4 +31,6 @@ Resources: Destination: Id: MyFunction Permissions: - - Write + - Write +Metadata: + SamTransformTest: true From 8ee6d07476ff7ed7a1056b9fa2138be57ef0b47b Mon Sep 17 00:00:00 2001 From: connorrobertson Date: Mon, 21 Nov 2022 14:11:29 -0800 Subject: [PATCH 10/10] Transform Test --- ...nector_sfn_to_function_without_policy.yaml | 36 ++++ ...nector_sfn_to_function_without_policy.json | 175 ++++++++++++++++++ ...nector_sfn_to_function_without_policy.json | 175 ++++++++++++++++++ ...nector_sfn_to_function_without_policy.json | 175 ++++++++++++++++++ 4 files changed, 561 insertions(+) create mode 100644 tests/translator/input/connector_sfn_to_function_without_policy.yaml create mode 100644 tests/translator/output/aws-cn/connector_sfn_to_function_without_policy.json create mode 100644 tests/translator/output/aws-us-gov/connector_sfn_to_function_without_policy.json create mode 100644 tests/translator/output/connector_sfn_to_function_without_policy.json diff --git a/tests/translator/input/connector_sfn_to_function_without_policy.yaml b/tests/translator/input/connector_sfn_to_function_without_policy.yaml new file mode 100644 index 000000000..a011a40d3 --- /dev/null +++ b/tests/translator/input/connector_sfn_to_function_without_policy.yaml @@ -0,0 +1,36 @@ +Resources: + TriggerStateMachine: + Type: AWS::Serverless::StateMachine + Properties: + Type: EXPRESS + Definition: + StartAt: TryDoSomething + States: + TryDoSomething: + Type: Task + Resource: !Sub arn:${AWS::Partition}:states:::lambda:invoke + Parameters: + FunctionName: !Ref MyFunction + End: true + + MyFunction: + Type: AWS::Serverless::Function + Properties: + Runtime: nodejs14.x + Handler: index.handler + InlineCode: | + exports.handler = async (event) => { + console.log(JSON.stringify(event)); + }; + + MyConnector: + Type: AWS::Serverless::Connector + Properties: + Source: + Id: TriggerStateMachine + Destination: + Id: MyFunction + Permissions: + - Write +Metadata: + SamTransformTest: true diff --git a/tests/translator/output/aws-cn/connector_sfn_to_function_without_policy.json b/tests/translator/output/aws-cn/connector_sfn_to_function_without_policy.json new file mode 100644 index 000000000..3e84b0ddf --- /dev/null +++ b/tests/translator/output/aws-cn/connector_sfn_to_function_without_policy.json @@ -0,0 +1,175 @@ +{ + "Metadata": { + "SamTransformTest": true + }, + "Resources": { + "MyConnectorPolicy": { + "Metadata": { + "aws:sam:connectors": { + "MyConnector": { + "Destination": { + "Type": "AWS::Serverless::Function" + }, + "Source": { + "Type": "AWS::Serverless::StateMachine" + } + } + } + }, + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "lambda:InvokeAsync", + "lambda:InvokeFunction" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "Roles": [ + { + "Ref": "TriggerStateMachineRole" + } + ] + }, + "Type": "AWS::IAM::ManagedPolicy" + }, + "MyFunction": { + "Properties": { + "Code": { + "ZipFile": "exports.handler = async (event) => {\n console.log(JSON.stringify(event));\n};\n" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs14.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "MyFunctionRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "TriggerStateMachine": { + "Properties": { + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"StartAt\": \"TryDoSomething\",", + " \"States\": {", + " \"TryDoSomething\": {", + " \"End\": true,", + " \"Parameters\": {", + " \"FunctionName\": \"${definition_substitution_1}\"", + " },", + " \"Resource\": \"${definition_substitution_2}\",", + " \"Type\": \"Task\"", + " }", + " }", + "}" + ] + ] + }, + "DefinitionSubstitutions": { + "definition_substitution_1": { + "Ref": "MyFunction" + }, + "definition_substitution_2": { + "Fn::Sub": "arn:${AWS::Partition}:states:::lambda:invoke" + } + }, + "RoleArn": { + "Fn::GetAtt": [ + "TriggerStateMachineRole", + "Arn" + ] + }, + "StateMachineType": "EXPRESS", + "Tags": [ + { + "Key": "stateMachine:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::StepFunctions::StateMachine" + }, + "TriggerStateMachineRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [], + "Tags": [ + { + "Key": "stateMachine:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + } + } +} diff --git a/tests/translator/output/aws-us-gov/connector_sfn_to_function_without_policy.json b/tests/translator/output/aws-us-gov/connector_sfn_to_function_without_policy.json new file mode 100644 index 000000000..8ec6cc2b9 --- /dev/null +++ b/tests/translator/output/aws-us-gov/connector_sfn_to_function_without_policy.json @@ -0,0 +1,175 @@ +{ + "Metadata": { + "SamTransformTest": true + }, + "Resources": { + "MyConnectorPolicy": { + "Metadata": { + "aws:sam:connectors": { + "MyConnector": { + "Destination": { + "Type": "AWS::Serverless::Function" + }, + "Source": { + "Type": "AWS::Serverless::StateMachine" + } + } + } + }, + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "lambda:InvokeAsync", + "lambda:InvokeFunction" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "Roles": [ + { + "Ref": "TriggerStateMachineRole" + } + ] + }, + "Type": "AWS::IAM::ManagedPolicy" + }, + "MyFunction": { + "Properties": { + "Code": { + "ZipFile": "exports.handler = async (event) => {\n console.log(JSON.stringify(event));\n};\n" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs14.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "MyFunctionRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "TriggerStateMachine": { + "Properties": { + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"StartAt\": \"TryDoSomething\",", + " \"States\": {", + " \"TryDoSomething\": {", + " \"End\": true,", + " \"Parameters\": {", + " \"FunctionName\": \"${definition_substitution_1}\"", + " },", + " \"Resource\": \"${definition_substitution_2}\",", + " \"Type\": \"Task\"", + " }", + " }", + "}" + ] + ] + }, + "DefinitionSubstitutions": { + "definition_substitution_1": { + "Ref": "MyFunction" + }, + "definition_substitution_2": { + "Fn::Sub": "arn:${AWS::Partition}:states:::lambda:invoke" + } + }, + "RoleArn": { + "Fn::GetAtt": [ + "TriggerStateMachineRole", + "Arn" + ] + }, + "StateMachineType": "EXPRESS", + "Tags": [ + { + "Key": "stateMachine:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::StepFunctions::StateMachine" + }, + "TriggerStateMachineRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [], + "Tags": [ + { + "Key": "stateMachine:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + } + } +} diff --git a/tests/translator/output/connector_sfn_to_function_without_policy.json b/tests/translator/output/connector_sfn_to_function_without_policy.json new file mode 100644 index 000000000..96ae532c9 --- /dev/null +++ b/tests/translator/output/connector_sfn_to_function_without_policy.json @@ -0,0 +1,175 @@ +{ + "Metadata": { + "SamTransformTest": true + }, + "Resources": { + "MyConnectorPolicy": { + "Metadata": { + "aws:sam:connectors": { + "MyConnector": { + "Destination": { + "Type": "AWS::Serverless::Function" + }, + "Source": { + "Type": "AWS::Serverless::StateMachine" + } + } + } + }, + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "lambda:InvokeAsync", + "lambda:InvokeFunction" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "MyFunction", + "Arn" + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "Roles": [ + { + "Ref": "TriggerStateMachineRole" + } + ] + }, + "Type": "AWS::IAM::ManagedPolicy" + }, + "MyFunction": { + "Properties": { + "Code": { + "ZipFile": "exports.handler = async (event) => {\n console.log(JSON.stringify(event));\n};\n" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "MyFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs14.x", + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::Lambda::Function" + }, + "MyFunctionRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Key": "lambda:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + }, + "TriggerStateMachine": { + "Properties": { + "DefinitionString": { + "Fn::Join": [ + "\n", + [ + "{", + " \"StartAt\": \"TryDoSomething\",", + " \"States\": {", + " \"TryDoSomething\": {", + " \"End\": true,", + " \"Parameters\": {", + " \"FunctionName\": \"${definition_substitution_1}\"", + " },", + " \"Resource\": \"${definition_substitution_2}\",", + " \"Type\": \"Task\"", + " }", + " }", + "}" + ] + ] + }, + "DefinitionSubstitutions": { + "definition_substitution_1": { + "Ref": "MyFunction" + }, + "definition_substitution_2": { + "Fn::Sub": "arn:${AWS::Partition}:states:::lambda:invoke" + } + }, + "RoleArn": { + "Fn::GetAtt": [ + "TriggerStateMachineRole", + "Arn" + ] + }, + "StateMachineType": "EXPRESS", + "Tags": [ + { + "Key": "stateMachine:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::StepFunctions::StateMachine" + }, + "TriggerStateMachineRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "states.amazonaws.com" + ] + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [], + "Tags": [ + { + "Key": "stateMachine:createdBy", + "Value": "SAM" + } + ] + }, + "Type": "AWS::IAM::Role" + } + } +}