Terraform中aws_scheduler_schedule与IAM角色循环依赖问题求解
解决AWS调度器与IAM角色的Terraform循环依赖问题
问题概述
创建用于启停EC2实例的aws_scheduler_schedule资源时,配置对应的IAM角色后执行terraform plan报错:
Error: Cycle: aws_scheduler_schedule.gh_runners_ubuntu_stop, aws_iam_role.gh_runners_ubuntu_scheduler_role, aws_scheduler_schedule.gh_runners_ubuntu_start
原配置代码如下:
# --------------------------------------------------------------------------------------------------------------------- # GITHUB-RUNNER EC2 SCHEDULERS # --------------------------------------------------------------------------------------------------------------------- resource "aws_scheduler_schedule" "gh_runners_ubuntu_start" { for_each = var.gh_runners name = format("%s-%s", "gh_runners_ubuntu_start", each.value.runner_id) flexible_time_window { mode = "OFF" } schedule_expression = each.value.start_time target { arn = "arn:aws:scheduler:::aws-sdk:ec2:startInstances" role_arn = aws_iam_role.gh_runners_ubuntu_scheduler_role[each.key].arn input = jsonencode({ InstanceIds = [ module.gh_runners_ubuntu[each.key].id ] }) } } resource "aws_scheduler_schedule" "gh_runners_ubuntu_stop" { for_each = var.gh_runners name = format("%s-%s", "gh_runners_ubuntu_stop", each.value.runner_name) flexible_time_window { mode = "OFF" } schedule_expression = each.value.stop_time target { arn = "arn:aws:scheduler:::aws-sdk:ec2:stopInstances" role_arn = aws_iam_role.gh_runners_ubuntu_scheduler_role[each.key].arn input = jsonencode({ InstanceIds = [ module.gh_runners_ubuntu[each.key].id ] }) } } resource "aws_iam_role" "gh_runners_ubuntu_scheduler_role" { for_each = var.gh_runners name = format("%s-%s", "gh_runners_ubuntu_scheduler_role", each.value.runner_name) assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [ { Action = "sts:AssumeRole" Effect = "Allow" Principal = { Service = "events.amazonaws.com" } Condition = { ArnEquals = { "aws:SourceArn" = [ aws_scheduler_schedule.gh_runners_ubuntu_start[each.key].arn, aws_scheduler_schedule.gh_runners_ubuntu_stop[each.key].arn, ] } } } ] }) } resource "aws_iam_role_policy" "gh_runners_ubuntu_scheduler_role_policy" { for_each = var.gh_runners name = format("%s-%s", "gh_runners_ubuntu_scheduler_role_policy", each.value.runner_name) role = aws_iam_role.gh_runners_ubuntu_scheduler[each.key].id policy = jsonencode({ Version = "2012-10-17" Statement = [ { Effect = "Allow" Action = ["ec2:StopInstances", "ec2:StartInstances"] Resource = module.gh_runners_ubuntu[each.key].arn } ] }) }
问题原因
循环依赖产生的核心逻辑:
- 调度器资源(
aws_scheduler_schedule)需要IAM角色的ARN才能创建,因为目标配置中指定了role_arn - IAM角色的信任策略又需要调度器的ARN作为
aws:SourceArn条件,来限制只有特定调度器能扮演该角色
两者互相依赖,导致Terraform无法确定资源的创建顺序。
解决方案
方案1:移除信任策略中的源ARN限制(快速解决)
如果不需要严格限制信任源,直接删除IAM角色中的Condition块,打破循环:
resource "aws_iam_role" "gh_runners_ubuntu_scheduler_role" { for_each = var.gh_runners name = format("%s-%s", "gh_runners_ubuntu_scheduler_role", each.value.runner_name) assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [ { Action = "sts:AssumeRole" Effect = "Allow" Principal = { Service = "events.amazonaws.com" } } ] }) }
方案2:手动构造调度器ARN(保持权限严格性)
若需保留aws:SourceArn的安全限制,可通过Terraform数据源获取账户ID和区域,手动构造调度器的ARN(AWS调度器ARN格式固定:arn:aws:scheduler:<region>:<account-id>:schedule/<schedule-name>):
- 添加数据源获取当前账户和区域信息:
data "aws_caller_identity" "current" {} data "aws_region" "current" {}
- 修改IAM角色的信任策略,用构造的ARN替代对调度器资源的直接引用:
resource "aws_iam_role" "gh_runners_ubuntu_scheduler_role" { for_each = var.gh_runners name = format("%s-%s", "gh_runners_ubuntu_scheduler_role", each.value.runner_name) assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [ { Action = "sts:AssumeRole" Effect = "Allow" Principal = { Service = "events.amazonaws.com" } Condition = { ArnEquals = { "aws:SourceArn" = [ format("arn:aws:scheduler:%s:%s:schedule/%s-%s", data.aws_region.current.name, data.aws_caller_identity.current.account_id, "gh_runners_ubuntu_start", each.value.runner_id ), format("arn:aws:scheduler:%s:%s:schedule/%s-%s", data.aws_region.current.name, data.aws_caller_identity.current.account_id, "gh_runners_ubuntu_stop", each.value.runner_name ) ] } } } ] }) }
额外修复:IAM角色策略的引用错误
原代码中aws_iam_role_policy的role字段引用名称错误,需修正为正确的IAM角色资源名:
resource "aws_iam_role_policy" "gh_runners_ubuntu_scheduler_role_policy" { for_each = var.gh_runners name = format("%s-%s", "gh_runners_ubuntu_scheduler_role_policy", each.value.runner_name) role = aws_iam_role.gh_runners_ubuntu_scheduler_role[each.key].id policy = jsonencode({ Version = "2012-10-17" Statement = [ { Effect = "Allow" Action = ["ec2:StopInstances", "ec2:StartInstances"] Resource = module.gh_runners_ubuntu[each.key].arn } ] }) }
内容的提问来源于stack exchange,提问作者pkaramol
相关产品推荐
相关产品推荐

