如何为SOPS配置AWS别名,实现跨账号密钥部署与状态分离?
我有一套可用的SOPS方案:使用aws_sops AWS账号的KMS加密文件,再将密钥部署到aws_secrets AWS账号的Secrets Manager中。
当前方案通过连接aws_sops账号,让.sops.yaml指向其KMS,并借助Provider别名完成密钥部署。但该方案会将aws_secrets工作区的状态保存到aws_sops账号的状态文件中,导致无法在已托管于aws_secrets账号的Terraform工作区部署此方案。
想调整方案,为aws_sops配置Provider别名,直接连接aws_secrets账号,但不清楚如何指定SOPS使用此AWS别名而非默认配置。
当前可行但不满意的方案
provider "aws" { alias = "development" profile = "development" } provider "aws" {} provider "sops" {} terraform { backend "s3" { bucket = "xxx-statefile" encrypt = true key = "pat/terraform.tfstate" } } data "sops_file" "sops-secret" { source_file = "../secrets.json" } resource "aws_secretsmanager_secret" "pipeline" { provider = aws.development name = "service-accounts/pipeline/resource-access-pat" recovery_window_in_days = 0 force_overwrite_replica_secret = true } resource "aws_secretsmanager_secret_version" "pipeline" { provider = aws.development secret_id = aws_secretsmanager_secret.pipeline.id secret_string = jsonencode( { "pat" : data.sops_file.sops-secret.data["token"] }) }
尝试过的失败方案
方案1:给sops_file数据源添加Provider别名
移除密钥资源的Provider别名,将别名配置到sops_file数据源块中,出现如下错误:
│ 错误:无效的数据源 │ │ 在../data.tf第1行,data "sops_file" "test"块中: │ 1: data "sops_file" "test" { │ │ HashiCorp/aws提供商不支持数据源"sops_file"。
该错误符合预期,因为sops_file仅用于读取本地文件。
方案2:为KMS添加IAM角色
给aws_sops的KMS配置拥有管理权限的IAM角色,配置如下:
"sops": { "kms": [ { "arn": "arn:aws:kms:eu-west-2:xxx:key/xxx", "role": "arn:aws:iam::xxx:role/TerraformAccountAccessRole", "created_at": "2023-02-10T13:53:05Z", "enc": "xx==", "aws_profile": "" }
同时尝试添加aws_profile配置:
"sops": { "kms": [ { "arn": "arn:aws:kms:xxx:xxx:key/xxx", "role": "arn:aws:iam::xxx:role/TerraformAccountAccessRole", "created_at": "2023-02-10T13:53:05Z", "enc": "xx==", "aws_profile": "aws_sops" }
但出现权限错误:
│ 错误:获取解密SOPS文件所需的数据密钥失败。 │ │ 组0:失败 │ arn:aws:kms:xxx:xxx:key/xxx: 失败 │ - | 创建AWS会话时出错:无法扮演角色 │ | "arn:aws:iam::xxx:role/TerraformAccountAccessRole": │ | 访问被拒绝:用户: │ | arn:aws:sts::089449186373:assumed-role/AWSReservedSSO_DevOps_xxx/xxx@xxx.com │ | 无权执行:sts:AssumeRole 操作,资源: │ | arn:aws:iam::xxx:role/TerraformAccountAccessRole │ | 状态码:403,请求ID: │ | d9327e8c-8ffc-4873-9279-112c1c8c7258 │ │ 恢复失败,因为没有主密钥能够解密文件。SOPS要恢复文件,至少需要一个密钥解密成功,但所有密钥均失败。
核心思路
让SOPS通过角色切换访问aws_sops账号的KMS,同时将Terraform状态托管在aws_secrets账号,避免状态跨账号存储问题。
步骤1:修复IAM角色信任关系
解决方案2中的403权限错误:在aws_sops账号的TerraformAccountAccessRole角色的信任策略中,添加当前Terraform执行身份(即arn:aws:sts::089449186373:assumed-role/AWSReservedSSO_DevOps_xxx/xxx@xxx.com)的信任许可,允许其调用sts:AssumeRole。
示例信任策略:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:sts::089449186373:assumed-role/AWSReservedSSO_DevOps_xxx/xxx@xxx.com" }, "Action": "sts:AssumeRole" } ] }
步骤2:调整Terraform配置
修改配置,让默认AWS Provider连接aws_secrets账号,Terraform状态存储在该账号的S3桶中,部署Secrets Manager无需额外别名,SOPS通过文件内的角色配置自动切换身份解密:
# 默认Provider连接aws_secrets账号,用于状态存储和Secrets Manager部署 provider "aws" { profile = "aws_secrets" # 替换为你的aws_secrets账号本地配置名 } # sops Provider保持默认,自动读取本地配置和环境变量 provider "sops" {} terraform { backend "s3" { bucket = "aws-secrets-state-bucket" # aws_secrets账号下的状态存储桶 encrypt = true key = "pat/terraform.tfstate" region = "eu-west-2" # 替换为你的区域 } } data "sops_file" "sops-secret" { source_file = "../secrets.json" # 无需指定Provider,SOPS会根据文件内的KMS角色配置切换身份 } resource "aws_secretsmanager_secret" "pipeline" { name = "service-accounts/pipeline/resource-access-pat" recovery_window_in_days = 0 force_overwrite_replica_secret = true } resource "aws_secretsmanager_secret_version" "pipeline" { secret_id = aws_secretsmanager_secret.pipeline.id secret_string = jsonencode( { "pat" : data.sops_file.sops-secret.data["token"] }) }
步骤3:确认SOPS文件配置
确保加密后的secrets.json中,SOPS配置指向aws_sops账号的KMS和已配置信任关系的IAM角色,无需指定aws_profile:
"sops": { "kms": [ { "arn": "arn:aws:kms:eu-west-2:xxx:key/xxx", # aws_sops账号的KMS ARN "role": "arn:aws:iam::xxx:role/TerraformAccountAccessRole", # aws_sops账号的目标角色 "created_at": "2023-02-10T13:53:05Z", "enc": "xx==" } ] }
验证步骤
- 手动执行角色假设命令,确认权限配置生效:
aws sts assume-role --role-arn arn:aws:iam::xxx:role/TerraformAccountAccessRole --role-session-name test-sops - 用SOPS手动解密文件,确认解密正常:
sops decrypt ../secrets.json - 运行
terraform init和terraform apply,确认部署流程正常。
内容的提问来源于stack exchange,提问作者Staggerlee011

