You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Terraform时如何避免覆盖GitLab CI变量

解决Terraform部署GitLab项目时重复重置VAPID密钥的问题

问题场景

用Terraform部署GitLab项目时,每次运行都会重新生成VAPID密钥并覆盖GitLab CI变量,希望实现仅在变量不存在时才创建密钥和变量,避免每次运行重置密钥。

原配置中,external数据源每次执行都会生成新密钥,导致资源每次都更新,现在需要调整逻辑:

解决方案

核心是先通过gitlab_project_variable数据源检查目标变量是否已存在,仅当变量不存在时才生成密钥并创建变量。

修改后的完整配置

variable "env_scopes_all" {
  type = list(object({
    scope    = string
    env_type = string
  }))
  default = [
    { scope = "prod/live", env_type = "live" },
    { scope = "prod/staging", env_type = "staging" },
    { scope = "prod/review-*", env_type = "review" }
  ]
}

# 检查每个环境下的VAPID_PRIVATE_KEY是否已存在
data "gitlab_project_variable" "existing_vapid_private_keys" {
  count             = length(var.env_scopes_all)
  project           = gitlab_project.elybird.id
  key               = "VAPID_PRIVATE_KEY"
  environment_scope = var.env_scopes_all[count.index].scope
  # 变量不存在时不报错,返回空结果
  lifecycle {
    ignore_changes = all
  }
}

# 仅当对应环境的VAPID_PRIVATE_KEY不存在时,生成新的VAPID密钥
data "external" "vapid_keys" {
  count = length([
    for i, scope in var.env_scopes_all : scope
    if data.gitlab_project_variable.existing_vapid_private_keys[i].id == ""
  ])

  program = ["/bin/sh", "-c", <<-EOF
    pem=$(openssl ecparam -name prime256v1 -genkey -noout)
    private_key=$(echo "$pem" | openssl ec -outform DER 2>/dev/null | tail -c +8 | head -c 32 | base64 -w 0 | tr -d '=' | tr '/+' '_-')
    public_key=$(echo "$pem" | openssl ec -pubout -outform DER 2>/dev/null | tail -c 65 | base64 -w 0 | tr -d '=' | tr '/+' '_-')

    printf '{"private_key":"%s","public_key":"%s"}\n' "$private_key" "$public_key"
  EOF
  ]
}

# 仅当对应环境的VAPID_PRIVATE_KEY不存在时,创建私有密钥变量
resource "gitlab_project_variable" "VAPID_PRIVATE_KEY" {
  count             = length(data.external.vapid_keys)
  project           = gitlab_project.elybird.id
  key               = "VAPID_PRIVATE_KEY"
  value             = data.external.vapid_keys[count.index].result.private_key
  description       = "Base64-encoded VAPID private key for push notifications"
  environment_scope = var.env_scopes_all[count.index].scope
  masked            = false
  protected         = false
  raw               = true
  variable_type     = "env_var"
}

# 仅当对应环境的VAPID_PRIVATE_KEY不存在时,创建公开密钥变量
resource "gitlab_project_variable" "VAPID_PUBLIC_KEY" {
  count             = length(data.external.vapid_keys)
  project           = gitlab_project.elybird.id
  key               = "VAPID_PUBLIC_KEY"
  value             = data.external.vapid_keys[count.index].result.public_key
  description       = "Base64-encoded VAPID public key for client push subscription"
  environment_scope = var.env_scopes_all[count.index].scope
  masked            = false
  protected         = false
  raw               = true
  variable_type     = "env_var"
}

关键逻辑说明

  1. 检查变量存在性:data.gitlab_project_variable.existing_vapid_private_keys遍历每个环境scope,检查对应的私有密钥变量是否存在。如果变量不存在,id字段会为空。
  2. 条件生成密钥:data.external.vapid_keys的count通过列表推导式筛选出变量不存在的环境,只对这些环境生成新密钥,避免重复生成。
  3. 条件创建变量:资源的count和external数据源的长度保持一致,只在需要的环境下创建变量,已存在的环境不会执行创建逻辑。

额外注意事项

  • 如果后续需要重置某个环境的密钥,只需手动删除GitLab中对应的CI变量,下次运行Terraform时会自动重新生成并创建。
  • 确保Terraform使用的GitLab token具备api权限,能正常读取项目变量。

内容的提问来源于stack exchange,提问作者JT2809

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 14:52:27