Step Functions Workflow: Route S3 Uploads to Lambda or Fargate
Overview
This skill deploys an event-driven workflow using AWS CLI. When a file is uploaded to
an S3 bucket, EventBridge triggers a Step Functions state machine. The state machine
checks the file size and routes processing to either a Lambda function (files ≤ 6 MB)
or a Fargate task (files > 6 MB).
The architecture includes:
- An S3 bucket with EventBridge notifications enabled
- An EventBridge rule that triggers Step Functions on S3 object creation
- A Step Functions state machine with a Choice state for routing
- A Lambda function for processing small files
- An ECS Fargate task for processing large files
- A VPC with two subnets, internet gateway, and security group
- An ECR repository for the Fargate container image
- Scoped IAM roles for Lambda, Step Functions, and ECS tasks
Use this skill when:
- You need to process S3 uploads with different compute based on file size
- You want a serverless workflow that can handle both small and large files
- You need Step Functions orchestration with Lambda and Fargate
Do not use this skill when:
- All files are small enough for Lambda (use S3 → Lambda directly)
- You need real-time streaming (use Kinesis)
- You don't need file-size-based routing
Prerequisites
- AWS CLI v2 — Installed and configured. Verify with
aws sts get-caller-identity.
- Python 3.12 — For the Lambda function runtime.
- Docker — For building and pushing the Fargate container image.
Parameters
- bucket_name (required): Name for the S3 bucket (globally unique, lowercase, 3-63 characters)
- region (required): AWS region for all resources
- ecr_repo_name (required): Name for the ECR repository
- state_machine_name (required): Name for the Step Functions state machine
- kms_key_arn (optional): ARN of a KMS key for CloudWatch Logs encryption. If not provided, create one with
aws kms create-key --description "Key for CloudWatch Logs encryption" --region {region}
Constraints for parameter acquisition:
- You MUST ask for all required parameters upfront in a single prompt
- You MUST support multiple input methods (direct input, file path, URL)
- You MUST confirm successful acquisition of all parameters before proceeding
- You MUST validate that bucket_name follows S3 naming rules
Procedures
Step 0: Verify Dependencies
Constraints:
- You MUST verify the following tools are available: aws-cli, python3 (3.12+), docker
- You MUST inform the user about any missing tools with a clear message
- You MUST ask if the user wants to proceed despite missing tools
- You MUST respect the customer's decision to abort at any point
- You MUST explain to the customer what step is being executed, why, and which tool is being called
Step 1: Retrieve AWS Account ID
Constraints:
- You MUST retrieve the account ID with:
aws sts get-caller-identity --query 'Account' --output text
- You MUST store the result as {account_id} for use in all subsequent steps
- You MUST abort if credentials are not configured
Step 2: Get the Default VPC and Networking
Constraints:
- You MUST retrieve the default VPC ID with:
aws ec2 describe-vpcs --filters Name=isDefault,Values=true --query 'Vpcs[0].VpcId' --output text --region {region}
- If no default VPC exists, inform the user they must create one with
aws ec2 create-default-vpc --region {region} or provide a VPC ID manually
- You MUST retrieve two subnet IDs from the default VPC:
aws ec2 describe-subnets --filters Name=vpc-id,Values={vpc_id} --query 'Subnets[0:2].SubnetId' --output text --region {region}
- You MUST create a security group in the default VPC:
aws ec2 create-security-group --group-name fargate-sg --description "Security group for Fargate tasks" --vpc-id {vpc_id} --region {region}
- You MUST configure security group egress rules to allow only HTTPS and DNS outbound. First revoke the default allow-all egress rule:
aws ec2 revoke-security-group-egress --group-id {sg_id} --ip-permissions IpProtocol=-1,IpRanges='[{CidrIp=0.0.0.0/0}]' --region {region}
Then add scoped rules:
aws ec2 authorize-security-group-egress --group-id {sg_id} --protocol tcp --port 443 --cidr 0.0.0.0/0 --region {region} and
aws ec2 authorize-security-group-egress --group-id {sg_id} --protocol udp --port 53 --cidr 0.0.0.0/0 --region {region}
- You MUST recommend VPC endpoints for S3 and CloudWatch Logs for production workloads to avoid internet-routed traffic and eliminate the need for broad egress rules
- You MUST capture {vpc_id}, {subnet1_id}, {subnet2_id}, and {sg_id} for use in later steps
Step 3: Create the ECR Repository
Constraints:
- You MUST create the repository with:
aws ecr create-repository --repository-name {ecr_repo_name} --region {region}
- You MUST capture the repositoryUri from the response
Step 4: Build and Push the Container Image
Constraints:
You MUST verify Docker is installed by running docker --version. If Docker is not installed, instruct the user to install it from https://docs.docker.com/get-docker/ and abort until it is available
You MUST authenticate Docker with ECR:
aws ecr get-login-password --region {region} | docker login --username AWS --password-stdin {account_id}.dkr.ecr.{region}.amazonaws.com
The Dockerfile and processor code are in scripts/Dockerfile and scripts/fargate_processor.py
You MUST build and push the image from the scripts directory:
cd scripts
docker build --platform linux/amd64 -t {ecr_repo_name} .
docker tag {ecr_repo_name}:latest {account_id}.dkr.ecr.{region}.amazonaws.com/{ecr_repo_name}:latest
docker push {account_id}.dkr.ecr.{region}.amazonaws.com/{ecr_repo_name}:latest
cd ..
Step 5: Create IAM Roles
Follow the detailed instructions in references/iam-roles.md to create all IAM roles (Lambda, ECS task execution, ECS task, Step Functions, and EventBridge roles).
- You MUST wait at least 10 seconds for IAM role propagation
Step 6: Create the Lambda Function
Constraints:
The function code is in scripts/lambda_function.py
You MUST be in the skill root directory before packaging and creating the function
You MUST package it with: python3 -c "import zipfile,io; z=io.BytesIO(); f=zipfile.ZipFile(z,'w'); f.writestr('lambda_function.py', open('scripts/lambda_function.py').read()); f.close(); open('/tmp/lambda_function.zip','wb').write(z.getvalue())"
You MUST create the function with:
aws lambda create-function \
--function-name sfn-file-processor \
--runtime python3.12 \
--handler lambda_function.lambda_handler \
--role arn:aws:iam::{account_id}:role/sfn-lambda-role \
--zip-file fileb:///tmp/lambda_function.zip \
--timeout 60 \
--architectures x86_64 \
--region {region}
You MUST verify the function was created with:
aws lambda get-function --function-name sfn-file-processor --region {region}
Step 7: Create the CloudWatch Log Group
Constraints:
- You MUST create the log group for Fargate:
aws logs create-log-group --log-group-name /StepFunctionFargateTask --region {region}
- You MUST encrypt the log group with a KMS key:
aws logs associate-kms-key --log-group-name /StepFunctionFargateTask --kms-key-arn {kms_key_arn} --region {region}
Step 8: Create the ECS Cluster and Task Definition
Follow the detailed instructions in references/ecs-task-definition.md to create the ECS cluster and register the Fargate task definition.
- You MUST capture the task definition ARN from the response
Step 9: Create the S3 Bucket with EventBridge Notifications
Constraints:
- You MUST create the bucket with:
aws s3api create-bucket --bucket {bucket_name} --region {region} --create-bucket-configuration LocationConstraint={region}
- You MUST NOT include
--create-bucket-configuration if region is us-east-1
- You MUST enable EventBridge notifications on the bucket:
aws s3api put-bucket-notification-configuration --bucket {bucket_name} --notification-configuration '{"EventBridgeConfiguration": {}}' --region {region}
- You MUST enable default encryption on the bucket:
aws s3api put-bucket-encryption --bucket {bucket_name} --server-side-encryption-configuration '{"Rules":[{"ApplyServerSideEncryptionByDefault":{"SSEAlgorithm":"aws:kms"}}]}' --region {region}
Step 10: Create the Step Functions State Machine
Constraints:
The state machine definition is in scripts/statemachine.asl.json
You MUST create a working copy and replace all placeholders:
sed -e 's|${LambdaFunction}|arn:aws:lambda:{region}:{account_id}:function:sfn-file-processor|g' \
-e 's|${Cluster}|arn:aws:ecs:{region}:{account_id}:cluster/sfn-cluster|g' \
-e 's|${TaskDefinition}|{task_definition_arn}|g' \
-e 's|${Subnet1}|{subnet1_id}|g' \
-e 's|${Subnet2}|{subnet2_id}|g' \
-e 's|${SecurityGroup}|{sg_id}|g' \
scripts/statemachine.asl.json > /tmp/statemachine.asl.json
You MUST create the state machine with:
aws stepfunctions create-state-machine \
--name {state_machine_name} \
--definition file:///tmp/statemachine.asl.json \
--role-arn arn:aws:iam::{account_id}:role/sfn-state-machine-role \
--type STANDARD \
--region {region}
You MUST capture the stateMachineArn from the response
Step 11: Create the EventBridge Rule
Constraints:
You MUST create the EventBridge rule to trigger on S3 object creation:
aws events put-rule \
--name s3-to-stepfunctions \
--event-pattern '{
"source": ["aws.s3"],
"detail-type": ["Object Created"],
"detail": {
"bucket": {
"name": ["{bucket_name}"]
}
}
}' \
--region {region}
You MUST add the state machine as a target:
aws events put-targets \
--rule s3-to-stepfunctions \
--targets '[{
"Id": "StepFunctionsTarget",
"Arn": "{state_machine_arn}",
"RoleArn": "arn:aws:iam::{account_id}:role/sfn-eventbridge-role"
}]' \
--region {region}
Step 12: Configure Monitoring
Constraints:
You MUST create a Dead Letter Queue for failed EventBridge invocations:
aws sqs create-queue --queue-name s3-to-stepfunctions-dlq --region {region}
You MUST update the EventBridge target to attach the DLQ:
aws events put-targets \
--rule s3-to-stepfunctions \
--targets '[{
"Id": "StepFunctionsTarget",
"Arn": "{state_machine_arn}",
"RoleArn": "arn:aws:iam::{account_id}:role/sfn-eventbridge-role",
"DeadLetterConfig": {
"Arn": "arn:aws:sqs:{region}:{account_id}:s3-to-stepfunctions-dlq"
}
}]' \
--region {region}
You MUST create a CloudWatch alarm for Step Functions execution failures:
aws cloudwatch put-metric-alarm --alarm-name sfn-execution-failures --metric-name ExecutionsFailed --namespace AWS/States --statistic Sum --period 300 --threshold 1 --comparison-operator GreaterThanOrEqualToThreshold --evaluation-periods 1 --dimensions Name=StateMachineArn,Value={state_machine_arn} --region {region}
Step 13: Validate
Constraints:
You MUST test with a small file (< 6 MB) to verify Lambda processing:
echo 'test data' > /tmp/small-file.txt
aws s3 cp /tmp/small-file.txt s3://{bucket_name}/small-file.txt --region {region}
You MUST wait 15 seconds then check the Step Functions execution:
aws stepfunctions list-executions --state-machine-arn {state_machine_arn} --region {region}
You MUST verify the execution succeeded and routed to Lambda
You MUST provide a summary of all created resources including: VPC ID, subnet IDs, security group ID, ECR repo URI, ECS cluster ARN, task definition ARN, Lambda function ARN, state machine ARN, bucket name, and EventBridge rule name
Troubleshooting
EventBridge rule not triggering
- Verify EventBridge notifications are enabled on the bucket:
aws s3api get-bucket-notification-configuration --bucket {bucket_name}
- Verify the rule exists:
aws events describe-rule --name s3-to-stepfunctions --region {region}
- Check that the target has the correct state machine ARN and role
Step Functions execution fails at Fargate task
- Verify the container image exists in ECR:
aws ecr describe-images --repository-name {ecr_repo_name} --region {region}
- Check that the subnets have internet access (route table with IGW)
- Verify the security group allows outbound traffic
- Check CloudWatch Logs at
/StepFunctionFargateTask
Lambda invocation fails
- Check CloudWatch Logs:
aws logs tail /aws/lambda/sfn-file-processor --region {region}
- Verify the Step Functions role has
lambda:InvokeFunction permission
IAM PassRole errors
- The Step Functions role must have
iam:PassRole for both the ECS execution role and task role ARNs
Fargate task stuck in PROVISIONING
- Verify the subnets have auto-assign public IP enabled
- Verify the internet gateway is attached and route table has 0.0.0.0/0 route
Security Considerations
- Fargate tasks with public IPs are exposed to the internet. Revoke the default allow-all egress rule and configure scoped egress:
aws ec2 revoke-security-group-egress --group-id {sg_id} --ip-permissions IpProtocol=-1,IpRanges='[{CidrIp=0.0.0.0/0}]' then add aws ec2 authorize-security-group-egress --group-id {sg_id} --protocol tcp --port 443 --cidr 0.0.0.0/0 and aws ec2 authorize-security-group-egress --group-id {sg_id} --protocol udp --port 53 --cidr 0.0.0.0/0. For production, consider using VPC endpoints for S3 and CloudWatch Logs instead of internet-routed traffic.
- Scan container images for vulnerabilities before pushing to ECR. Enable ECR image scanning with:
aws ecr put-image-scanning-configuration --repository-name {ecr_repo_name} --image-scanning-configuration scanOnPush=true --region {region}
- Use IAM roles for credentials — never hardcode access keys in container code.
- Enable encryption at rest for the S3 bucket:
aws s3api put-bucket-encryption --bucket {bucket_name} --server-side-encryption-configuration '{"Rules":[{"ApplyServerSideEncryptionByDefault":{"SSEAlgorithm":"aws:kms"}}]}'
- Enable CloudWatch Logs encryption for Fargate container logs:
aws logs associate-kms-key --log-group-name /StepFunctionFargateTask --kms-key-arn <KMS_KEY_ARN>
- Configure a Dead Letter Queue on the EventBridge rule for failed invocations
- Set up CloudWatch alarms on Step Functions execution failures for operational visibility
Version information
- AWS CLI: 2.x
- Python runtime: 3.12
- Last validated: 2026-04-27
Additional Resources
1---
2name: processing-s3-uploads-with-step-functions
3description: >
4 Deploy an event-driven workflow that routes S3 uploads to either Lambda or Fargate
5 via Step Functions based on file size. Uses EventBridge to trigger a Step Functions
6 state machine when objects are uploaded to S3. Small files are processed by Lambda,
7 large files by a Fargate task. Includes VPC, ECR repository, ECS cluster, and scoped
8 IAM roles. Trigger keywords: Step Functions, Fargate, Lambda, S3 event, EventBridge,
9 ECS, ECR, file processing, workflow orchestration, serverless.
10version: 1
11---
12
13# Step Functions Workflow: Route S3 Uploads to Lambda or Fargate
14
15## Overview
16
17This skill deploys an event-driven workflow using AWS CLI. When a file is uploaded to
18an S3 bucket, EventBridge triggers a Step Functions state machine. The state machine
19checks the file size and routes processing to either a Lambda function (files ≤ 6 MB)
20or a Fargate task (files > 6 MB).
21
22The architecture includes:
23
24- An S3 bucket with EventBridge notifications enabled
25- An EventBridge rule that triggers Step Functions on S3 object creation
26- A Step Functions state machine with a Choice state for routing
27- A Lambda function for processing small files
28- An ECS Fargate task for processing large files
29- A VPC with two subnets, internet gateway, and security group
30- An ECR repository for the Fargate container image
31- Scoped IAM roles for Lambda, Step Functions, and ECS tasks
32
33Use this skill when:
34
35- You need to process S3 uploads with different compute based on file size
36- You want a serverless workflow that can handle both small and large files
37- You need Step Functions orchestration with Lambda and Fargate
38
39Do not use this skill when:
40
41- All files are small enough for Lambda (use S3 → Lambda directly)
42- You need real-time streaming (use Kinesis)
43- You don't need file-size-based routing
44
45## Prerequisites
46
471. **AWS CLI v2** — Installed and configured. Verify with `aws sts get-caller-identity`.
482. **Python 3.12** — For the Lambda function runtime.
493. **Docker** — For building and pushing the Fargate container image.
50
51## Parameters
52
53- bucket_name (required): Name for the S3 bucket (globally unique, lowercase, 3-63 characters)
54- region (required): AWS region for all resources
55- ecr_repo_name (required): Name for the ECR repository
56- state_machine_name (required): Name for the Step Functions state machine
57- kms_key_arn (optional): ARN of a KMS key for CloudWatch Logs encryption. If not provided, create one with `aws kms create-key --description "Key for CloudWatch Logs encryption" --region {region}`
58
59Constraints for parameter acquisition:
60
61- You MUST ask for all required parameters upfront in a single prompt
62- You MUST support multiple input methods (direct input, file path, URL)
63- You MUST confirm successful acquisition of all parameters before proceeding
64- You MUST validate that bucket_name follows S3 naming rules
65
66## Procedures
67
68### Step 0: Verify Dependencies
69
70Constraints:
71
72- You MUST verify the following tools are available: aws-cli, python3 (3.12+), docker
73- You MUST inform the user about any missing tools with a clear message
74- You MUST ask if the user wants to proceed despite missing tools
75- You MUST respect the customer's decision to abort at any point
76- You MUST explain to the customer what step is being executed, why, and which tool is being called
77
78### Step 1: Retrieve AWS Account ID
79
80Constraints:
81
82- You MUST retrieve the account ID with: `aws sts get-caller-identity --query 'Account' --output text`
83- You MUST store the result as {account_id} for use in all subsequent steps
84- You MUST abort if credentials are not configured
85
86### Step 2: Get the Default VPC and Networking
87
88Constraints:
89
90- You MUST retrieve the default VPC ID with:
91 `aws ec2 describe-vpcs --filters Name=isDefault,Values=true --query 'Vpcs[0].VpcId' --output text --region {region}`
92- If no default VPC exists, inform the user they must create one with `aws ec2 create-default-vpc --region {region}` or provide a VPC ID manually
93- You MUST retrieve two subnet IDs from the default VPC:
94 `aws ec2 describe-subnets --filters Name=vpc-id,Values={vpc_id} --query 'Subnets[0:2].SubnetId' --output text --region {region}`
95- You MUST create a security group in the default VPC:
96 `aws ec2 create-security-group --group-name fargate-sg --description "Security group for Fargate tasks" --vpc-id {vpc_id} --region {region}`
97- You MUST configure security group egress rules to allow only HTTPS and DNS outbound. First revoke the default allow-all egress rule:
98 `aws ec2 revoke-security-group-egress --group-id {sg_id} --ip-permissions IpProtocol=-1,IpRanges='[{CidrIp=0.0.0.0/0}]' --region {region}`
99 Then add scoped rules:
100 `aws ec2 authorize-security-group-egress --group-id {sg_id} --protocol tcp --port 443 --cidr 0.0.0.0/0 --region {region}` and
101 `aws ec2 authorize-security-group-egress --group-id {sg_id} --protocol udp --port 53 --cidr 0.0.0.0/0 --region {region}`
102- You MUST recommend VPC endpoints for S3 and CloudWatch Logs for production workloads to avoid internet-routed traffic and eliminate the need for broad egress rules
103- You MUST capture {vpc_id}, {subnet1_id}, {subnet2_id}, and {sg_id} for use in later steps
104
105### Step 3: Create the ECR Repository
106
107Constraints:
108
109- You MUST create the repository with:
110 `aws ecr create-repository --repository-name {ecr_repo_name} --region {region}`
111- You MUST capture the repositoryUri from the response
112
113### Step 4: Build and Push the Container Image
114
115Constraints:
116
117- You MUST verify Docker is installed by running `docker --version`. If Docker is not installed, instruct the user to install it from https://docs.docker.com/get-docker/ and abort until it is available
118- You MUST authenticate Docker with ECR:
119 `aws ecr get-login-password --region {region} | docker login --username AWS --password-stdin {account_id}.dkr.ecr.{region}.amazonaws.com`
120- The Dockerfile and processor code are in `scripts/Dockerfile` and `scripts/fargate_processor.py`
121- You MUST build and push the image from the scripts directory:
122
123 ```
124 cd scripts
125 docker build --platform linux/amd64 -t {ecr_repo_name} .
126 docker tag {ecr_repo_name}:latest {account_id}.dkr.ecr.{region}.amazonaws.com/{ecr_repo_name}:latest
127 docker push {account_id}.dkr.ecr.{region}.amazonaws.com/{ecr_repo_name}:latest
128 cd ..
129 ```
130
131### Step 5: Create IAM Roles
132
133Follow the detailed instructions in `references/iam-roles.md` to create all IAM roles (Lambda, ECS task execution, ECS task, Step Functions, and EventBridge roles).
134
135- You MUST wait at least 10 seconds for IAM role propagation
136
137### Step 6: Create the Lambda Function
138
139Constraints:
140
141- The function code is in `scripts/lambda_function.py`
142- You MUST be in the skill root directory before packaging and creating the function
143- You MUST package it with: `python3 -c "import zipfile,io; z=io.BytesIO(); f=zipfile.ZipFile(z,'w'); f.writestr('lambda_function.py', open('scripts/lambda_function.py').read()); f.close(); open('/tmp/lambda_function.zip','wb').write(z.getvalue())"`
144- You MUST create the function with:
145
146 ```
147 aws lambda create-function \
148 --function-name sfn-file-processor \
149 --runtime python3.12 \
150 --handler lambda_function.lambda_handler \
151 --role arn:aws:iam::{account_id}:role/sfn-lambda-role \
152 --zip-file fileb:///tmp/lambda_function.zip \
153 --timeout 60 \
154 --architectures x86_64 \
155 --region {region}
156 ```
157
158- You MUST verify the function was created with:
159 `aws lambda get-function --function-name sfn-file-processor --region {region}`
160
161### Step 7: Create the CloudWatch Log Group
162
163Constraints:
164
165- You MUST create the log group for Fargate:
166 `aws logs create-log-group --log-group-name /StepFunctionFargateTask --region {region}`
167- You MUST encrypt the log group with a KMS key:
168 `aws logs associate-kms-key --log-group-name /StepFunctionFargateTask --kms-key-arn {kms_key_arn} --region {region}`
169
170### Step 8: Create the ECS Cluster and Task Definition
171
172Follow the detailed instructions in `references/ecs-task-definition.md` to create the ECS cluster and register the Fargate task definition.
173
174- You MUST capture the task definition ARN from the response
175
176### Step 9: Create the S3 Bucket with EventBridge Notifications
177
178Constraints:
179
180- You MUST create the bucket with:
181 `aws s3api create-bucket --bucket {bucket_name} --region {region} --create-bucket-configuration LocationConstraint={region}`
182- You MUST NOT include `--create-bucket-configuration` if region is us-east-1
183- You MUST enable EventBridge notifications on the bucket:
184 `aws s3api put-bucket-notification-configuration --bucket {bucket_name} --notification-configuration '{"EventBridgeConfiguration": {}}' --region {region}`
185- You MUST enable default encryption on the bucket:
186 `aws s3api put-bucket-encryption --bucket {bucket_name} --server-side-encryption-configuration '{"Rules":[{"ApplyServerSideEncryptionByDefault":{"SSEAlgorithm":"aws:kms"}}]}' --region {region}`
187
188### Step 10: Create the Step Functions State Machine
189
190Constraints:
191
192- The state machine definition is in `scripts/statemachine.asl.json`
193- You MUST create a working copy and replace all placeholders:
194
195 ```
196 sed -e 's|${LambdaFunction}|arn:aws:lambda:{region}:{account_id}:function:sfn-file-processor|g' \
197 -e 's|${Cluster}|arn:aws:ecs:{region}:{account_id}:cluster/sfn-cluster|g' \
198 -e 's|${TaskDefinition}|{task_definition_arn}|g' \
199 -e 's|${Subnet1}|{subnet1_id}|g' \
200 -e 's|${Subnet2}|{subnet2_id}|g' \
201 -e 's|${SecurityGroup}|{sg_id}|g' \
202 scripts/statemachine.asl.json > /tmp/statemachine.asl.json
203 ```
204
205- You MUST create the state machine with:
206
207 ```
208 aws stepfunctions create-state-machine \
209 --name {state_machine_name} \
210 --definition file:///tmp/statemachine.asl.json \
211 --role-arn arn:aws:iam::{account_id}:role/sfn-state-machine-role \
212 --type STANDARD \
213 --region {region}
214 ```
215
216- You MUST capture the stateMachineArn from the response
217
218### Step 11: Create the EventBridge Rule
219
220Constraints:
221
222- You MUST create the EventBridge rule to trigger on S3 object creation:
223
224 ```
225 aws events put-rule \
226 --name s3-to-stepfunctions \
227 --event-pattern '{
228 "source": ["aws.s3"],
229 "detail-type": ["Object Created"],
230 "detail": {
231 "bucket": {
232 "name": ["{bucket_name}"]
233 }
234 }
235 }' \
236 --region {region}
237 ```
238
239- You MUST add the state machine as a target:
240
241 ```
242 aws events put-targets \
243 --rule s3-to-stepfunctions \
244 --targets '[{
245 "Id": "StepFunctionsTarget",
246 "Arn": "{state_machine_arn}",
247 "RoleArn": "arn:aws:iam::{account_id}:role/sfn-eventbridge-role"
248 }]' \
249 --region {region}
250 ```
251
252### Step 12: Configure Monitoring
253
254Constraints:
255
256- You MUST create a Dead Letter Queue for failed EventBridge invocations:
257 `aws sqs create-queue --queue-name s3-to-stepfunctions-dlq --region {region}`
258- You MUST update the EventBridge target to attach the DLQ:
259
260 ```
261 aws events put-targets \
262 --rule s3-to-stepfunctions \
263 --targets '[{
264 "Id": "StepFunctionsTarget",
265 "Arn": "{state_machine_arn}",
266 "RoleArn": "arn:aws:iam::{account_id}:role/sfn-eventbridge-role",
267 "DeadLetterConfig": {
268 "Arn": "arn:aws:sqs:{region}:{account_id}:s3-to-stepfunctions-dlq"
269 }
270 }]' \
271 --region {region}
272 ```
273
274- You MUST create a CloudWatch alarm for Step Functions execution failures:
275 `aws cloudwatch put-metric-alarm --alarm-name sfn-execution-failures --metric-name ExecutionsFailed --namespace AWS/States --statistic Sum --period 300 --threshold 1 --comparison-operator GreaterThanOrEqualToThreshold --evaluation-periods 1 --dimensions Name=StateMachineArn,Value={state_machine_arn} --region {region}`
276
277### Step 13: Validate
278
279Constraints:
280
281- You MUST test with a small file (< 6 MB) to verify Lambda processing:
282
283 ```
284 echo 'test data' > /tmp/small-file.txt
285 aws s3 cp /tmp/small-file.txt s3://{bucket_name}/small-file.txt --region {region}
286 ```
287
288- You MUST wait 15 seconds then check the Step Functions execution:
289 `aws stepfunctions list-executions --state-machine-arn {state_machine_arn} --region {region}`
290- You MUST verify the execution succeeded and routed to Lambda
291- You MUST provide a summary of all created resources including: VPC ID, subnet IDs, security group ID, ECR repo URI, ECS cluster ARN, task definition ARN, Lambda function ARN, state machine ARN, bucket name, and EventBridge rule name
292
293## Troubleshooting
294
295### EventBridge rule not triggering
296
297- Verify EventBridge notifications are enabled on the bucket: `aws s3api get-bucket-notification-configuration --bucket {bucket_name}`
298- Verify the rule exists: `aws events describe-rule --name s3-to-stepfunctions --region {region}`
299- Check that the target has the correct state machine ARN and role
300
301### Step Functions execution fails at Fargate task
302
303- Verify the container image exists in ECR: `aws ecr describe-images --repository-name {ecr_repo_name} --region {region}`
304- Check that the subnets have internet access (route table with IGW)
305- Verify the security group allows outbound traffic
306- Check CloudWatch Logs at `/StepFunctionFargateTask`
307
308### Lambda invocation fails
309
310- Check CloudWatch Logs: `aws logs tail /aws/lambda/sfn-file-processor --region {region}`
311- Verify the Step Functions role has `lambda:InvokeFunction` permission
312
313### IAM PassRole errors
314
315- The Step Functions role must have `iam:PassRole` for both the ECS execution role and task role ARNs
316
317### Fargate task stuck in PROVISIONING
318
319- Verify the subnets have auto-assign public IP enabled
320- Verify the internet gateway is attached and route table has 0.0.0.0/0 route
321
322## Security Considerations
323
324- Fargate tasks with public IPs are exposed to the internet. Revoke the default allow-all egress rule and configure scoped egress: `aws ec2 revoke-security-group-egress --group-id {sg_id} --ip-permissions IpProtocol=-1,IpRanges='[{CidrIp=0.0.0.0/0}]'` then add `aws ec2 authorize-security-group-egress --group-id {sg_id} --protocol tcp --port 443 --cidr 0.0.0.0/0` and `aws ec2 authorize-security-group-egress --group-id {sg_id} --protocol udp --port 53 --cidr 0.0.0.0/0`. For production, consider using VPC endpoints for S3 and CloudWatch Logs instead of internet-routed traffic.
325- Scan container images for vulnerabilities before pushing to ECR. Enable ECR image scanning with: `aws ecr put-image-scanning-configuration --repository-name {ecr_repo_name} --image-scanning-configuration scanOnPush=true --region {region}`
326- Use IAM roles for credentials — never hardcode access keys in container code.
327- Enable encryption at rest for the S3 bucket: `aws s3api put-bucket-encryption --bucket {bucket_name} --server-side-encryption-configuration '{"Rules":[{"ApplyServerSideEncryptionByDefault":{"SSEAlgorithm":"aws:kms"}}]}'`
328- Enable CloudWatch Logs encryption for Fargate container logs: `aws logs associate-kms-key --log-group-name /StepFunctionFargateTask --kms-key-arn <KMS_KEY_ARN>`
329- Configure a Dead Letter Queue on the EventBridge rule for failed invocations
330- Set up CloudWatch alarms on Step Functions execution failures for operational visibility
331
332## Version information
333
334- **AWS CLI**: 2.x
335- **Python runtime**: 3.12
336- **Last validated**: 2026-04-27
337
338## Additional Resources
339
340- [Step Functions developer guide](https://docs.aws.amazon.com/step-functions/latest/dg/welcome.html)
341- [EventBridge S3 events](https://docs.aws.amazon.com/AmazonS3/latest/userguide/EventBridge.html)
342- [Fargate task definitions](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definitions.html)
343- [ECR pushing images](https://docs.aws.amazon.com/AmazonECR/latest/userguide/docker-push-ecr-image.html)
344- [Step Functions Fargate integration](https://docs.aws.amazon.com/step-functions/latest/dg/connect-ecs.html)