如何将映射对象转换为 JSON 以上传到 Hashicorp Vault

问题描述 投票:0回答:1

我正在尝试使用 Terraform 在 Azure 中创建 SQL 服务器,并创建一个 JSON 用于将登录信息上传到 Hashicorp 金库。 这是我的代码:

resource "random_string" "password" {
  length      = 20
  upper       = true
  min_upper   = 1
  lower       = true
  min_lower   = 1
  number      = true
  min_numeric = 1
  special     = false
}

resource "azurerm_mssql_server" "server" {
  for_each            = var.sql_servers
  name                = each.key
  location            = each.value.location
  resource_group_name = each.value.resource_group_name
}

variable "sql_servers" {
  type = map(object({
    location            = string
    resource_group_name = string
  }))

variable "administrator_login" {
  type        = string
  description = "Admin login for the sql servers"
  default     = "admin_user"
}

locals {
  sql_server_login_info = [
    for key, server in var.sql_servers : {
      server_name             = key
      administrator_password  = random_string.password.result
      administrator_login     = var.administrator_login
    }
  ]
}

我希望输出看起来像这样:

{
  server_name = server1
  admin_user = admin_user
  admin_password = password
}
{
  server_name = server2
  admin_user = admin_user
  admin_password = password
}
{
  server_name = server3
  admin_user = admin_user
  admin_password = password
}

我正在尝试使用以下块将其上传到 Hashicorp 金库:

resource "vault_kv_secret_v2" "sql_vault" {
  depends_on = [azurerm_mssql_server.server]
  mount       = "dba-info"
  name       = "/some/path/in/hashicorp/vault"
  cas        = 1
  data_json  = jsonencode(local.sql_server_login_info)
}

但是,我收到以下错误:

Error: json: cannot unmarshal array into Go value of type map[string]interface {}

我做了一些研究,认为我需要在编码之前将 local.sql_server_login_info 转换为不同的类型。 但我不知道这是否正确,如果是,我不知道该怎么做。

谢谢。

json terraform hashicorp
1个回答
0
投票

您收到的错误看起来是由于

jsonencode()
需要一个映射,但您传递的是一个列表 (
local.sql_server_login_info
),并且 Vault 期望
data_json
是一个键值映射.

您需要修改

local.sql_server_login_info
的结构,使其成为一个映射而不是一个列表,以服务器名称作为键。这将解决这个问题。

您应该创建一个地图,而不是一个列表,以便每个服务器的信息的关键是它的服务器名称。尝试使用以下方法:

locals {
  sql_server_login_info = {
    for key, server in var.sql_servers : key => {
      administrator_password = random_string.password.result
      administrator_login    = var.administrator_login
    }
  }
}

然后将

sql_server_login_info
地图直接传递到
data_json
字段中,就像您已经做的那样:

resource "vault_kv_secret_v2" "sql_vault" {
  depends_on = [azurerm_mssql_server.server]
  mount      = "dba-info"
  name       = "/some/path/in/hashicorp/vault"
  cas        = 1
  data_json  = jsonencode(local.sql_server_login_info)
}

此更改会将数据编码为映射,并以服务器名称作为键,这正是 Vault 所期望的。请注意,根据我的建议,您的输出将如下所示:

{
  "server1": {
    "admin_user": "admin_user",
    "admin_password": "password1"
  },
  "server2": {
    "admin_user": "admin_user",
    "admin_password": "password2"
  },
  "server3": {
    "admin_user": "admin_user",
    "admin_password": "password3"
  }
}

但这应该可以解决

jsonencode
错误的问题,并允许您成功将登录信息上传到 HashiCorp Vault。

这就是我要采取的方法。


注意 - 您想要的确切输出格式有点棘手,因为 JSON 不支持多个独立对象,而不将它们包装在数组或其他结构中。

解决方法是使用 Terraform 的

join()
和字符串插值。

您可以更新 locals 块以生成所需的字符串输出:

locals {
  sql_server_login_info_string = join("\n", [
    for key, server in var.sql_servers : <<EOT
{
  server_name = ${key}
  admin_user = ${var.administrator_login}
  admin_password = ${random_string.password.result}
}
EOT
  ])
}

然后将格式化的字符串传递到Vault(或输出)。 如果您想将其存储在 Vault 中,可以将其编码为字符串:

resource "vault_kv_secret_v2" "sql_vault" {
  depends_on = [azurerm_mssql_server.server]
  mount      = "dba-info"
  name       = "/some/path/in/hashicorp/vault"
  cas        = 1
  data_json  = jsonencode({
    sql_info = local.sql_server_login_info_string
  })
}

local.sql_server_login_info_string
看起来完全如您所愿,但作为单个连接字符串。

{
  server_name = server1
  admin_user = admin_user
  admin_password = password1
}
{
  server_name = server2
  admin_user = admin_user
  admin_password = password2
}
{
  server_name = server3
  admin_user = admin_user
  admin_password = password3
}
© www.soinside.com 2019 - 2024. All rights reserved.