Terraform工作空间切换时重复创建IAM资源报错求助
问题描述
使用Terraform Workspaces管理资源时,首次执行terraform init和terraform apply可成功创建资源,但切换工作空间后执行相同命令,会因IAM角色和策略名称全局唯一、已存在而触发报错:
Error: creating IAM Role: EntityAlreadyExists (role): Role with name env-role already exists. Error: creating IAM Policy (policy): EntityAlreadyExists: A policy called env-with-policy already exists. Duplicate names are not allowed.
相关资源配置如下:
resource "aws_iam_role" "payload_for_lambda" { name = "${var.iam_role_name}" assume_role_policy = <<EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } EOF } resource "aws_iam_policy" "AWSLambdaBasicExecutionRole" { name = "${var.iam_policy_name}" path = "/" description = "AWS IAM Policy for managing aws lambda role" policy = <<EOF { "Version": "2012-10-17", "Statement": [ { "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": "arn:aws:logs:*:*:*", "Effect": "Allow" } ] } EOF }
解决方案
方法1:为不同工作空间的IAM资源添加工作空间标识
IAM角色和策略的名称在AWS账户内是全局唯一的,无法重复创建。可以通过在资源名称中加入当前工作空间的名称,让每个工作空间的资源名称唯一。修改资源的name字段,引入terraform.workspace变量:
resource "aws_iam_role" "payload_for_lambda" { name = "${var.iam_role_name}-${terraform.workspace}" assume_role_policy = <<EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } EOF } resource "aws_iam_policy" "AWSLambdaBasicExecutionRole" { name = "${var.iam_policy_name}-${terraform.workspace}" path = "/" description = "AWS IAM Policy for managing aws lambda role (${terraform.workspace})" policy = <<EOF { "Version": "2012-10-17", "Statement": [ { "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": "arn:aws:logs:*:*:*", "Effect": "Allow" } ] } EOF }
这样每个工作空间会创建独立的IAM资源,不会出现名称冲突。
方法2:将共享IAM资源独立管理(推荐)
如果这些IAM资源是多个工作空间共享的通用资源,不要将其放在工作空间对应的配置中。单独创建一个Terraform配置目录来管理这些全局共享资源,执行terraform apply创建一次即可。
在工作空间的配置中,通过data数据源引用已存在的IAM资源,而非重新创建:
# 引用已存在的IAM角色 data "aws_iam_role" "existing_payload_role" { name = var.iam_role_name } # 引用已存在的IAM策略 data "aws_iam_policy" "existing_lambda_exec_policy" { name = var.iam_policy_name } # 在需要使用的地方,例如Lambda资源中引用data资源 resource "aws_lambda_function" "example" { # 其他配置... role = data.aws_iam_role.existing_payload_role.arn }
方法3:将已存在资源导入当前工作空间状态(不推荐)
如果必须在多个工作空间中使用同名IAM资源(不建议,易导致状态混乱),可以将已存在的资源导入当前工作空间的Terraform状态,让Terraform识别到资源已存在:
# 导入IAM角色 terraform import aws_iam_role.payload_for_lambda env-role # 导入IAM策略 terraform import aws_iam_policy.AWSLambdaBasicExecutionRole env-with-policy
导入后执行terraform plan,Terraform会确认资源与状态匹配,不会再尝试创建。但此方法存在风险:多个工作空间管理同一个资源,可能导致状态不一致或误操作删除资源。
内容的提问来源于stack exchange,提问作者Ivo
相关产品推荐
相关产品推荐

