Step Functions state machines should have logging enabled
Step Functions orchestrate distributed workflows across Lambda functions, ECS tasks, and other AWS services. Without logging, execution failures, timeout conditions, and unexpected state transitions vanish silently. Debugging a multi-step workflow without execution logs means replaying traffic in a lower environment and hoping you can reproduce the issue.
Logging at ALL or ERROR sends structured execution data to CloudWatch Logs, enabling post-incident analysis and automated alerting on failed executions. For workflows that process sensitive data or financial transactions, these logs also produce the audit trail regulators expect.
Retrofit consideration
Enabling logging requires an IAM role with permission to write to CloudWatch Logs. Existing state machines may use a role that lacks logs:CreateLogDelivery, logs:GetLogDelivery, logs:UpdateLogDelivery, and related actions, requiring a policy update.
Implementation
Choose the approach that matches how you manage Terraform.
Use the compliance.tf module to enforce this control by default. See get started with compliance.tf.
module "step_functions" {
source = "pcidss.compliance.tf/terraform-aws-modules/step-functions/aws"
version = ">=5.0.0"
definition = "${jsonencode({ "Comment" : "Pofix compliance test", "StartAt" : "Pass", "States" : { "Pass" : { "Type" : "Pass", "End" : true } } })}"
name = "pofix-abc123"
type = "STANDARD"
}
module "step_functions" {
source = "acscessentialeight.compliance.tf/terraform-aws-modules/step-functions/aws"
version = ">=5.0.0"
definition = "${jsonencode({ "Comment" : "Pofix compliance test", "StartAt" : "Pass", "States" : { "Pass" : { "Type" : "Pass", "End" : true } } })}"
name = "pofix-abc123"
type = "STANDARD"
}
module "step_functions" {
source = "eugmpannex11.compliance.tf/terraform-aws-modules/step-functions/aws"
version = ">=5.0.0"
definition = "${jsonencode({ "Comment" : "Pofix compliance test", "StartAt" : "Pass", "States" : { "Pass" : { "Type" : "Pass", "End" : true } } })}"
name = "pofix-abc123"
type = "STANDARD"
}
module "step_functions" {
source = "pcidssv321.compliance.tf/terraform-aws-modules/step-functions/aws"
version = ">=5.0.0"
definition = "${jsonencode({ "Comment" : "Pofix compliance test", "StartAt" : "Pass", "States" : { "Pass" : { "Type" : "Pass", "End" : true } } })}"
name = "pofix-abc123"
type = "STANDARD"
}
If you use terraform-aws-modules/step-functions/aws, set the right module inputs for this control. You can later migrate to the compliance.tf module with minimal changes because it is compatible by design.
module "step_functions" {
source = "terraform-aws-modules/step-functions/aws"
version = ">=5.0.0"
definition = "${jsonencode({ "Comment" : "Pofix compliance test", "StartAt" : "Pass", "States" : { "Pass" : { "Type" : "Pass", "End" : true } } })}"
name = "pofix-abc123"
type = "STANDARD"
}
Use AWS provider resources directly. See docs for the resources involved: aws_sfn_state_machine.
resource "aws_sfn_state_machine" "this" {
definition = jsonencode({ Comment = "A minimal state machine", StartAt = "Pass", States = { Pass = { Type = "Pass", End = true } } })
logging_configuration {
include_execution_data = true
level = "ALL"
log_destination = "arn:aws:logs:us-east-1:123456789012:log-group:example-log-group:*"
}
name = "pofix-abc123"
role_arn = "arn:aws:iam::123456789012:role/example-role"
}
What this control checks
To pass, the aws_sfn_state_machine resource must include a logging_configuration block with level set to anything other than "OFF". Valid passing values are "ALL" or "ERROR". The log_destination argument must point to a CloudWatch Logs log group ARN suffixed with :*. Setting include_execution_data = true captures full input/output payloads.
The state machine's IAM role, set via role_arn, must carry CloudWatch Logs delivery permissions: logs:CreateLogDelivery, logs:GetLogDelivery, logs:UpdateLogDelivery, logs:DeleteLogDelivery, logs:ListLogDeliveries, and logs:PutResourcePolicy. It fails when no logging_configuration block exists or when level is "OFF".
Common pitfalls
Missing :* suffix on log group ARN
The
log_destinationargument requires the CloudWatch log group ARN with a:*suffix. Usingaws_cloudwatch_log_group.example.arnalone produces an ARN without the wildcard, and Step Functions will either fail to deliver logs or error out during state machine creation. Append it explicitly:"${aws_cloudwatch_log_group.example.arn}:*".IAM role missing CloudWatch Logs delivery permissions
Log delivery silently fails when the execution role referenced by
role_arnlacks the full set of CloudWatch Logs delivery permissions:logs:CreateLogDelivery,logs:UpdateLogDelivery,logs:DeleteLogDelivery,logs:GetLogDelivery,logs:ListLogDeliveries,logs:PutResourcePolicy,logs:DescribeResourcePolicies, andlogs:DescribeLogGroups. A role scoped only to invoke Lambda or other downstream services won't have these, and the state machine will apply without error while producing no logs.Express vs Standard workflow logging differences
Express workflows (
type = "EXPRESS") have no long-term execution history in the console or API. CloudWatch Logs is the only durable record of what happened, makinglogging_configurationnon-negotiable for troubleshooting and retention. Standard workflows have a 90-day execution history fallback, but the control applies to both types and logging should be configured regardless.Log level mismatch with control parameter
If the control is configured with a custom
logLevelparameter requiringALL, a state machine set tolevel = "ERROR"fails even though logging is technically on. Check the expected level in your compliance policy before assuming any non-OFF value passes. Teams that default to ERROR-only often get tripped up when a policy requires ALL.
Audit evidence
Config rule evaluation results showing all AWS::StepFunctions::StateMachine resources as COMPLIANT are the primary artifact. To confirm the configuration, aws stepfunctions describe-state-machine returns the loggingConfiguration object; the level field should show something other than OFF and destinations should contain a valid log group ARN. The same information is visible in the Step Functions console under the Logging tab.
CloudWatch Logs Insights queries against the destination log group, showing actual entries from recent executions, confirm data is flowing. CloudTrail records for UpdateStateMachine establish when logging was enabled or last changed.
Framework-specific interpretation
PCI DSS v4.0: Requirements 10.2 and 10.3 call for capturing and protecting audit log content across all system components in the cardholder data environment. Step Functions workflows that route, process, or transform payment data are in scope, and execution logs at ERROR or ALL provide the event record those requirements ask for, covering both log content and the integrity protections that Requirement 10.3 adds.
Related controls
Tool mappings
Use these identifiers to cross-reference this control across tools, reports, and evidence.
Compliance.tf Control:
sfn_state_machine_logging_enabledAWS Config Managed Rule:
STEP_FUNCTIONS_STATE_MACHINE_LOGGING_ENABLEDCheckov Check:
CKV_AWS_285Powerpipe Control:
aws_compliance.control.sfn_state_machine_logging_enabledProwler Check:
stepfunctions_statemachine_logging_enabledAWS Security Hub Control:
StepFunctions.1Trivy Check:
AWS-0119
Last reviewed: 2026-03-09