AWS Step Functionsでログを有効化したときにAWS CloudFormationスタック作成が失敗する原因
困っていること
AWS Step FunctionsのステートマシンでCloudWatch Logsを有効化し、AWS CloudFormationスタックで作成しようとすると、以下のエラーで失敗しました。
ステートマシンにはIAMインラインポリシーで必要な権限を付与しているにも関わらず、このエラーが発生します。
Resource handler returned message: "The state machine IAM Role is not authorized to access the Log Destination (Service: Sfn, Status Code: 400, Request ID: cddcdb65-5400-4746-8b4e-4899c6470676) (SDK Attempt Count: 11)" (RequestToken: 92d4f4db-14a7-cf2a-33b3-93c2e18d5b28, HandlerErrorCode: AccessDenied)
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Simple Step Functions with CloudWatch Logs enabled'
Parameters:
StateMachineName:
Type: String
Default: simple-success-state-machine
Description: Name for the Step Functions State Machine
Resources:
# CloudWatch Logs ロググループ
StepFunctionsLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub '/aws/vendedlogs/states/${StateMachineName}'
RetentionInDays: 14
# Step Functions ステートマシン
SimpleStateMachine:
Type: AWS::StepFunctions::StateMachine
Properties:
StateMachineName: !Ref StateMachineName
StateMachineType: STANDARD
RoleArn: !GetAtt StepFunctionsRole.Arn
Definition:
Comment: A description of my state machine
StartAt: 成功
States:
成功:
Type: Succeed
QueryLanguage: JSONata
LoggingConfiguration:
Level: ALL
IncludeExecutionData: true
Destinations:
- CloudWatchLogsLogGroup:
LogGroupArn: !GetAtt StepFunctionsLogGroup.Arn
# Step Functions 実行用 IAM ロール
StepFunctionsRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub '${StateMachineName}-execution-role'
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: states.amazonaws.com
Action: sts:AssumeRole
Condition:
StringEquals:
aws:SourceAccount: !Sub ${AWS::AccountId}
ArnLike:
aws:SourceArn: !Sub 'arn:aws:states:${AWS::Region}:${AWS::AccountId}:stateMachine:*'
# Step Functions 用 IAM ポリシー
StepFunctionsPolicy:
Type: AWS::IAM::RolePolicy
Properties:
PolicyName: StepFunctionsLoggingPolicy
RoleName: !Ref StepFunctionsRole
PolicyDocument:
Version: '2012-10-17'
Statement:
# CloudWatch Logs 権限
- Effect: Allow
Action:
- logs:CreateLogDelivery
- logs:CreateLogStream
- logs:GetLogDelivery
- logs:UpdateLogDelivery
- logs:DeleteLogDelivery
- logs:ListLogDeliveries
- logs:PutLogEvents
- logs:PutResourcePolicy
- logs:DescribeResourcePolicies
- logs:DescribeLogGroups
Resource: '*'
ログの権限は以下のドキュメントの通りに設定しています。
原因
原因は、CloudFormationでリソースが並行作成される際に、ステートマシンの作成がIAMポリシーの適用完了前に実行されるためです。
最新のデプロイタイムラインでも確認できます。
CloudFormationでは、明示的な依存関係が指定されていない場合、リソースが並行して作成されます。上記のテンプレートでは以下の順序で処理されていると考えられます。
- StepFunctionsRole(IAMロール)が作成完了
- SimpleStateMachine(ステートマシン)が作成開始 ← この時点でロールにまだ権限がない
- StepFunctionsPolicy(IAMポリシー)が作成完了
この場合、ステートマシンの作成時点ではログ出力用の権限がIAMロールに付与されていないため、「The state machine IAM Role is not authorized to access the Log Destination」というエラーが発生します。
解決方法
方法1: DependsOnを使用した依存関係の明示
ステートマシンの作成前にIAMポリシーが確実に作成されるよう、DependsOnで依存関係を明示します。
# Step Functions ステートマシン
SimpleStateMachine:
DependsOn:
- StepFunctionsPolicy # ポリシー作成後にステートマシンを作成
Type: AWS::StepFunctions::StateMachine
Properties:
# ... 他の設定は同じ
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Simple Step Functions with CloudWatch Logs enabled'
Parameters:
StateMachineName:
Type: String
Default: simple-success-state-machine
Description: Name for the Step Functions State Machine
Resources:
# CloudWatch Logs ロググループ
StepFunctionsLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub '/aws/vendedlogs/states/${StateMachineName}'
RetentionInDays: 14
# Step Functions ステートマシン
SimpleStateMachine:
DependsOn:
- StepFunctionsPolicy
Type: AWS::StepFunctions::StateMachine
Properties:
StateMachineName: !Ref StateMachineName
StateMachineType: STANDARD
RoleArn: !GetAtt StepFunctionsRole.Arn
Definition:
Comment: A description of my state machine
StartAt: 成功
States:
成功:
Type: Succeed
QueryLanguage: JSONata
LoggingConfiguration:
Level: ALL
IncludeExecutionData: true
Destinations:
- CloudWatchLogsLogGroup:
LogGroupArn: !GetAtt StepFunctionsLogGroup.Arn
# Step Functions 実行用 IAM ロール
StepFunctionsRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub '${StateMachineName}-execution-role'
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: states.amazonaws.com
Action: sts:AssumeRole
Condition:
StringEquals:
aws:SourceAccount: !Sub ${AWS::AccountId}
ArnLike:
aws:SourceArn: !Sub 'arn:aws:states:${AWS::Region}:${AWS::AccountId}:stateMachine:*'
# Step Functions 用 IAM ポリシー
StepFunctionsPolicy:
Type: AWS::IAM::RolePolicy
Properties:
PolicyName: StepFunctionsLoggingPolicy
RoleName: !Ref StepFunctionsRole
PolicyDocument:
Version: '2012-10-17'
Statement:
# CloudWatch Logs 権限
- Effect: Allow
Action:
- logs:CreateLogDelivery
- logs:CreateLogStream
- logs:GetLogDelivery
- logs:UpdateLogDelivery
- logs:DeleteLogDelivery
- logs:ListLogDeliveries
- logs:PutLogEvents
- logs:PutResourcePolicy
- logs:DescribeResourcePolicies
- logs:DescribeLogGroups
Resource: '*'
この方法により、以下の順序でリソースが作成され、スタックが正常に作成できました。
- StepFunctionsRole(IAMロール)が作成完了
- StepFunctionsPolicy(IAMポリシー)が作成完了
- SimpleStateMachine(ステートマシン)が作成完了
方法2: IAMロール内にポリシーを統合
IAMロールのPolicies
プロパティを使用して、ポリシーをロール定義内に統合します。
別リソースとして定義した場合の処理順序
- StepFunctionsRole → 作成完了(権限なし)
- SimpleStateMachine → 作成開始 → 権限チェック → エラー!
- StepFunctionsPolicy → 作成完了
ロール内に統合した場合の処理順序
- StepFunctionsRole → 作成完了(権限も同時に付与)
- SimpleStateMachine → 作成開始 → 権限チェック → 成功!
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Simple Step Functions with CloudWatch Logs enabled'
Parameters:
StateMachineName:
Type: String
Default: simple-success-state-machine
Description: Name for the Step Functions State Machine
Resources:
# CloudWatch Logs ロググループ
StepFunctionsLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub '/aws/vendedlogs/states/${StateMachineName}'
RetentionInDays: 14
# Step Functions ステートマシン
SimpleStateMachine:
Type: AWS::StepFunctions::StateMachine
Properties:
StateMachineName: !Ref StateMachineName
StateMachineType: STANDARD
RoleArn: !GetAtt StepFunctionsRole.Arn
Definition:
Comment: A description of my state machine
StartAt: 成功
States:
成功:
Type: Succeed
QueryLanguage: JSONata
LoggingConfiguration:
Level: ALL
IncludeExecutionData: true
Destinations:
- CloudWatchLogsLogGroup:
LogGroupArn: !GetAtt StepFunctionsLogGroup.Arn
# Step Functions 実行用 IAM ロール(ポリシー統合版)
StepFunctionsRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub '${StateMachineName}-execution-role'
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: states.amazonaws.com
Action: sts:AssumeRole
Condition:
StringEquals:
aws:SourceAccount: !Sub ${AWS::AccountId}
ArnLike:
aws:SourceArn: !Sub 'arn:aws:states:${AWS::Region}:${AWS::AccountId}:stateMachine:*'
Policies: # ロール定義内にポリシーを統合
- PolicyName: StepFunctionsLoggingPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
# CloudWatch Logs 権限
- Effect: Allow
Action:
- logs:CreateLogDelivery
- logs:CreateLogStream
- logs:GetLogDelivery
- logs:UpdateLogDelivery
- logs:DeleteLogDelivery
- logs:ListLogDeliveries
- logs:PutLogEvents
- logs:PutResourcePolicy
- logs:DescribeResourcePolicies
- logs:DescribeLogGroups
Resource: '*'
この方法により、IAMロールとその権限が同時に作成されるため、ステートマシン作成時には既に必要な権限が付与されています。結果として、スタックが正常に作成できました。