如何使用数组而不是单个值将 sops 提供程序与 terraform 一起使用

How to use the sops provider with terraform using an array instead an single value

我是 Terraform 的新手。我正在尝试使用 sops 提供程序插件来加密来自 yaml 文件的秘密: Sops Provider

我需要为稍后的配置阶段创建一个 Terraform 用户对象,如下例所示:

users = [{
  name = "user123"
  password = "password12"
}]

我准备了一个 secrets.values.enc.yaml 文件来存储我的秘密数据:

yaml_users: 
  - name: user123
    password: password12

我已经使用“sops”命令加密了文件。为了测试目的,我可以成功解密文件。

现在我尝试使用 Terraform 中的加密文件来创建用户对象:

data "sops_file" "test-secret" {
  source_file = "secrets.values.enc.yaml"
}

# user data decryption
users = yamldecode(data.sops_file.test-secret.raw).yaml_users

不幸的是,我无法调试“用户”的数据或结构,因为 Terraform 不显示敏感数据。当我尝试在稍后的配置阶段使用该用户变量时,它似乎并不是所需要的:

Cannot use a set of map of string value in for_each. An iterable collection is required.

当我对 未加密 yaml 文件做同样的事情时,一切似乎都工作正常:

users = yamldecode(file("secrets.values.dec.yaml")).yaml_users

看来 sops 提供程序解密没有创建数组或我需要的“可迭代集合”。

有谁知道如何使用 terraform sops 提供程序来解密键值对数组?像“adminpassword”这样的单个值工作正常。

我认为此错误消息的“字符串映射集”部分是重要部分:for_each 需要直接映射(在这种情况下映射键成为实例标识符)或集合单个字符串(在这种情况下,这些字符串成为实例标识符)。

您的示例 YAML 文件显示 yaml_users 被定义为映射的 YAML 序列,对应于使用 yamldecode.

转换的对象元组

要将该数据结构与 for_each 一起使用,您需要先将其投影到地图中,地图的键将用作每个资源实例的唯一标识符。假设 name 值是唯一的,您可以投影它,以便这些值是键:

data "sops_file" "test-secret" {
  source_file = "secrets.values.enc.yaml"
}

locals {
  users = tomap({
    for u in yamldecode(data.sops_file.test-secret.raw).yaml_users :
    u.name => u
  })
}

敏感值的结果在这里增加了额外的麻烦,因为 Terraform 不允许使用敏感值作为资源实例的标识符——这样做会导致无法显示资源实例UI 中的地址,并且不可能在命令行上描述需要该地址的命令的实例。

然而,这看起来确实与我写这篇文章时 the nonsensitive function 示例中显示的 use-case 完全一样:您有一个当前完全标记为敏感的集合,但是您知道它只有一部分实际上是敏感的,因此您可以使用 nonsensitive 向 Terraform 解释如何将非敏感部分与敏感部分分开。这是我之前使用该函数的示例中 locals 块的更新版本:

locals {
  users = tomap({
    for u in yamldecode(data.sops_file.test-secret.raw).yaml_users :
    nonsensitive(u.name) => u
  })
}

如果我做出正确的假设,即只有密码是敏感的并且用户名可以公开,那么上面将产生一个合适的数据结构,其中用户名在键中可见,但单个元素 仍将被标记为敏感。

local.users 然后满足资源 for_each 的所有期望,因此您应该能够将它与您需要为每个用户系统地重复的任何其他资源一起使用。

请注意,Terraform 对敏感值的跟踪仅用于 UI 目的,不会阻止此密码作为使用它们的任何资源的一部分保存在状态中。如果您使用 Terraform 来管理敏感数据,那么您应该将生成的状态快照本身视为敏感工件,注意存储它们的位置和方式。