Back to Checks
aws

Step Functions state machine is encrypted at rest with a customer-managed KMS key

stepfunctions_statemachine_encrypted_with_cmk
Service: stepfunctionsSeverity: medium
OfficialBuilt-inVerified
Categories:encryption
Resource Type:AwsStepFunctionStateMachine

AWS Step Functions state machines store execution history and input/output data passed between workflow states. This check verifies that each state machine uses a customer-managed KMS key (CUSTOMER_MANAGED_KMS_KEY) for encryption at rest rather than the default AWS-owned key.

Risk

Without a customer-managed KMS key, execution history containing sensitive input/output data is protected only by an AWS-owned key you cannot control, rotate, or revoke. This limits auditability via CloudTrail, prevents independent access revocation, and weakens confidentiality for regulated workloads.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler aws --checks stepfunctions_statemachine_encrypted_with_cmk

Recommendation

Configure each Step Functions state machine to use a customer-managed KMS key for encryption at rest. Assign a least-privilege key policy, enable automatic key rotation, and grant the execution role kms:GenerateDataKey and kms:Decrypt. Monitor key usage via CloudTrail.

Remediation

CLI

aws stepfunctions update-state-machine --state-machine-arn <state-machine-arn> --encryption-configuration '{"kmsKeyId": "<kms-key-id>", "type": "CUSTOMER_MANAGED_KMS_KEY", "kmsDataKeyReusePeriodSeconds": 300}'

Terraform

resource "aws_sfn_state_machine" "<example_resource_name>" {
  name       = "<example_resource_name>"
  role_arn   = "arn:aws:iam::<account-id>:role/<example_role_name>"
  definition = jsonencode({ StartAt = "Pass", States = { Pass = { Type = "Pass", End = true } } })

  encryption_configuration {
    kms_key_id                        = "arn:aws:kms:<region>:<account-id>:key/<key-id>"  # Critical: customer-managed KMS key
    type                              = "CUSTOMER_MANAGED_KMS_KEY"                         # Critical: must be CUSTOMER_MANAGED_KMS_KEY
    kms_data_key_reuse_period_seconds = 300
  }
}

NativeIaC

Resources:
  <example_resource_name>:
    Type: AWS::StepFunctions::StateMachine
    Properties:
      RoleArn: arn:aws:iam::<account-id>:role/<example_role_name>
      DefinitionString: |
        {"StartAt":"Pass","States":{"Pass":{"Type":"Pass","End":true}}}
      EncryptionConfiguration:
        KmsKeyId: arn:aws:kms:<region>:<account-id>:key/<key-id>  # Critical: customer-managed KMS key
        Type: CUSTOMER_MANAGED_KMS_KEY                             # Critical: must be CUSTOMER_MANAGED_KMS_KEY
        KmsDataKeyReusePeriodSeconds: 300

Other

1Open AWS Console > Step Functions > State machines
2Select the state machine and click Edit
3Under Encryption, select Customer managed key
4Choose an existing KMS key or create a new one
5Save changes

Check Code

from typing import List

from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.stepfunctions.stepfunctions_client import (
    stepfunctions_client,
)
from prowler.providers.aws.services.stepfunctions.stepfunctions_service import (
    EncryptionType,
)


class stepfunctions_statemachine_encrypted_with_cmk(Check):
    """Ensure Step Functions state machines are encrypted at rest with a customer-managed KMS key.

    This check evaluates whether each AWS Step Functions state machine uses a
    customer-managed KMS key (CUSTOMER_MANAGED_KMS_KEY) for encryption at rest rather
    than the default AWS-owned key (AWS_OWNED_KEY).

    - PASS: The state machine encryption_configuration type is CUSTOMER_MANAGED_KMS_KEY.
    - FAIL: The state machine has no encryption_configuration or its type is AWS_OWNED_KEY.
    """

    def execute(self) -> List[Check_Report_AWS]:
        """Execute the Step Functions state machine encryption at rest check.

        Iterates over all Step Functions state machines and generates a report
        indicating whether each state machine uses a customer-managed KMS key
        for encryption at rest.

        Returns:
            List[Check_Report_AWS]: A list of report objects with the results of the check.
        """
        findings = []
        for state_machine in stepfunctions_client.state_machines.values():
            report = Check_Report_AWS(metadata=self.metadata(), resource=state_machine)

            if (
                state_machine.encryption_configuration
                and state_machine.encryption_configuration.type
                == EncryptionType.CUSTOMER_MANAGED_KMS_KEY
            ):
                report.status = "PASS"
                report.status_extended = f"Step Functions state machine {state_machine.name} is encrypted at rest with a customer-managed KMS key."
            else:
                report.status = "FAIL"
                report.status_extended = f"Step Functions state machine {state_machine.name} is not encrypted at rest with a customer-managed KMS key."

            findings.append(report)

        return findings