利用TerraCurl管控Terraform不支持的资源

举报
kaliarch 发表于 2023/07/16 10:37:42 2023/07/16
【摘要】 前言使用Terraform对基础设施进行编码是确保基础设施的可重复性和不可变性的好方法,但是当Terraform提供程序不支持所需的资源时,本文介绍使用TerraCurl提供程序将不受支持的资源置于TerraCurl管理之下。 TerraCurl简介Terraform是一个强大的工具,用于跨多个云和平台(从Azure、AWS、谷歌Cloud到Kubernetes和Nomad)自动化创建和管...

前言

使用Terraform对基础设施进行编码是确保基础设施的可重复性和不可变性的好方法,但是当Terraform提供程序不支持所需的资源时,本文介绍使用TerraCurl提供程序将不受支持的资源置于TerraCurl管理之下。

TerraCurl简介

Terraform是一个强大的工具,用于跨多个云和平台(从Azure、AWS、谷歌Cloud到Kubernetes和Nomad)自动化创建和管理基础设施资源。它这样做的能力取决于目标平台和云提供商的api。为了使Terraform能够与多个目标平台进行交互,它使用了Terraform提供者的概念,这是围绕目标api的以Terraform为中心的包装器,很像编程生态系统中的客户端库。这些提供程序实现了允许Terraform创建、读取、更新和删除提供程序资源的方法。

在某些情况下,目标API支持尚未在Terraform提供程序中实现的资源。在某些情况下,这是故意的。例如,Vault提供者故意没有资源来解封Vault集群,但是API可以这样做。提供商由HashiCorp、我们的技术合作伙伴或开源terrraform社区维护,欢迎pull请求;然而,在等待拉请求被审查和合并时,您仍然可以使用名为TerraCurl的提供程序使用Terraform部署资源。

TerraCurl 是我开发的一个实用程序提供程序,它允许您在Terraform代码中进行托管和非托管API调用。托管API调用包含关于API调用的创建和删除操作的指令,Terraform将对API调用的响应存储在状态文件中,所有这些都可以被其他资源访问引用。出于所有意图和目的,托管API调用与任何普通的Terraform资源没有什么不同。

非托管调用的操作略有不同,因为它在每次Terraform运行时都会执行指示API调用,通常是在Terraform运行的开始。这是为需要API调用中的信息以使其余Terraform代码正常工作的实例而设计的。这方面的一个例子是查找Boundary作用域ID,以便Terraform配置子作用域。

此提供程序的目标是在平台原生提供程序不支持所需资源而平台API支持的情况下提供帮助。它并不打算取代平台本地提供程序,后者应该始终优于TerraCurl。

托管API调用

托管API调用需要指令来创建和删除资源。这些说明包括:

  • The API endpoint
  • The HTTP method
  • Any HTTP headers (optional)
  • The request body (optional)
  • Expected response codes

所有托管调用都使用terracurl_request资源。下面的例子展示了这一点:

terraform {
  required_providers {
    terracurl = {
      source = "devops-rob/terracurl"
      version = "1.0.0"
    }
  }
}
 
provider "terracurl" {
}
 
resource "terracurl_request" "token" {
  name           = "rob-token"
 
  # Create instructions for Terraform
  url            = "http://localhost:8200/v1/auth/token/create"
  method         = "POST"
  request_body   = <<EOF
{
  "policies": ["web", "stage"],
  "ttl": "1h",
  "renewable": true,
  "id": "rob"
}
 
 
EOF
 
  headers = {
    X-Vault-Token = "root"
  }
 
  response_codes = [200,204]
 
  # Destroy instructions for Terraform
 
  destroy_url    = "http://localhost:8200/v1/auth/token/revoke"
  destroy_method = "POST"
 
  destroy_headers = {
    X-Vault-Token = "root"
  }
 
  destroy_request_body = <<EOF
{
  "token": "rob"
}
 
EOF
 
  destroy_response_codes = [204]
}

上面的代码示例将使用预先指定的ID创建和管理一个Vault令牌,这在设计上是Vault提供程序不支持的。然后将响应存储在状态文件中。如果没有接收到预期的响应代码,Terraform运行将失败,因为API调用可能已经失败。当terrraform销毁运行时,将遵循销毁指令。在这种情况下,它将对Vault进行API调用以撤销令牌。这个用例是TerraCurl提供程序预期用途的一个很好的示例,因为在Vault提供程序中可能永远不支持指定令牌ID的能力。
注意:使用Terraform生成Vault令牌将它们以明文形式存储在状态文件中,这可能涉及一些不适合生产环境的安全问题。

从响应中读取数据

Terraform内置了一个名为jsondecode的实用程序函数,允许您读取和访问对API调用的JSON响应的元素。将下面的代码片段添加到上面的示例中将呈现完整的JSON响应。

output "response" {
  value = jsondecode(terracurl_request.token.response)
}

要从响应中访问特定元素,可以通过指定想要读取的元素来进一步深入。例如,要输出令牌的访问器ID,它嵌套在auth对象中,您可以在输出中使用以下函数:

output "accessor" {
  value = jsondecode(terracurl_request.token.response).auth.accessor
}

从响应中读取和访问元素的过程与在诸如Golang等编程语言中解组数据的过程非常相似。

非托管API调用

非托管调用延迟托管调用,因为它们不打算用于管理资源的生命周期。因此,TerraCurl中的所有非托管API调用都使用terracurl_request数据源。
数据源的一个很好的示例用例是查找边界资源id。该功能存在于Boundary API中,但还不存在于Boundary提供程序中。

data "terracurl_request" "scope_id" {
  name           = "scope_id"
  url            = "http://127.0.0.1:9200/v1/scopes?filter=%22Rift%22+in+%22%2Fitem%2Fname%22&scope_id=global"
  method         = "GET"
}
 
output "scope_response" {
  value = jsondecode(data.terracurl_request.scope_id.response)
}

上面的示例代码对Boundary进行API调用,列出名为Rift的作用域的所有作用域和过滤器。输出包含解码后的JSON响应。

scope_response = {
  "items" = [
    {
      "authorized_actions" = [
        "no-op",
      ]
      "authorized_collection_actions" = {
        "auth-methods" = [
          "list",
        ]
        "scopes" = [
          "list",
        ]
      }
      "description" = "Scope for Rift Engineering"
      "id" = "o_u7vZIrVw3W"
      "name" = "Rift Engineering Department"
      "scope" = {
        "description" = "Global Scope"
        "id" = "global"
        "name" = "global"
        "type" = "global"
      }
      "scope_id" = "global"
      "type" = "org"
    },
  ]
}

与前面一样,我们可以进一步深入这个响应以访问特定的元素。例如,范围ID。


output "scope_response" {
  value = jsondecode(data.terracurl_request.scope_id.response).items.*.id
}

使用TLS进行身份验证和相互身份验证调用

最新版本的TerraCurl能够在API调用中可选地包含TLS材料,以及验证服务器的身份(mTLS))。托管和非托管API调用都支持这一点。
下面的示例通过对需要TLS的Vault服务器的非托管API调用演示了这一点。注意示例中的cert_file、key_file、ca_cert_file和skip_tls_verify参数。

data "terracurl_request" "test" {
  name   = "vault_seal_status"
  url    = "https://localhost:8200/v1/sys/seal-status"
  method = "GET"
 
  cert_file       = "server-vault-0.pem"
  key_file        = "server-vault-0-key.pem"
  ca_cert_file    = "vault-server-ca.pem"
  skip_tls_verify = false
 
  response_codes = [
    "200"
  ]
}

对于托管调用也可以这样做。然而,TLS材料是在创建和销毁API调用之间单独作用域的,每个API调用都是可选的。例如,您可以为创建调用提供TLS材料,而为销毁调用省略它们。这取决于目标API的工作方式。在大多数情况下,如果创建需要TLS,那么销毁可能也需要TLS。如果需要,这也将允许使用不同的TLS材料来创建和销毁调用。

resource "terracurl_request" "mount" {
  name           = "vault-mount"
  url            = "https://localhost:8200/v1/sys/mounts/aws"
  method         = "POST"
  request_body   = <<EOF
{
  "type": "aws",
  "config": {
    "force_no_cache": true
  }
}
 
EOF
 
  headers = {
    X-Vault-Token = "s.dXHglIuimE3ma89OSjSQpOhy"
  }
 
  cert_file       = "server-vault-0.pem"
  key_file        = "server-vault-0-key.pem"
  ca_cert_file    = "vault-server-ca.pem"
  skip_tls_verify = false
 
 
  response_codes = [200,204]
 
  destroy_url    = "https://localhost:8200/v1/sys/mounts/aws"
  destroy_method = "DELETE"
 
  destroy_headers = {
    X-Vault-Token = "s.dXHglIuimE3ma89OSjSQpOhy"
  }
 
  destroy_cert_file       = "server-vault-0.pem"
  destroy_key_file        = "server-vault-0-key.pem"
  destroy_ca_cert_file    = "vault-server-ca.pem"
  destroy_skip_tls_verify = false
 
 
  destroy_response_codes = [204]
}

错误处理和重试逻辑

在与目标api交互时,初始调用失败而后续调用成功的原因有很多。这可能是由于网络连接的短暂中断,也可能是API的行为最终是一致的。无论原因是什么,如果API调用中有任何错误,或者没有收到预期的响应代码,那么Terraform运行将失败。
TerraCurl的最新版本引入了重试逻辑来满足这些场景。默认情况下,此功能未启用;然而,如果你确实需要TerraCurl来重试失败的API调用,这可以通过在Terraform代码中添加重试参数来轻松完成。这在资源和数据源中都是可能的。

data "terracurl_request" "test" {
  name   = "products"
  url    = "https://localhost:5200/v1/sys/seal-status"
  method = "GET"
 
  cert_file       = "server-vault-0.pem"
  key_file        = "server-vault-0-key.pem"
  ca_cert_file    = "vault-server-ca.pem"
  skip_tls_verify = false
 
  response_codes = [
    200
  ]
 
  max_retry      = 3
  retry_interval = 10
 
}

上面的代码示例展示了使用非托管数据源的重试逻辑。如果最初的API调用返回错误,或者没有返回预期的响应代码,TerraCurl将等待10秒并重新尝试调用。这将重复最多3次(不包括初始的API调用)。
由于数据源在Terraform运行之初被调用,因此该数据源将确保在Terraform尝试在Vault中创建任何资源之前,Vault已被解封并准备好接受连接。如果在4次尝试之后(包括初始尝试),仍然存在失败,或者没有从Vault返回200响应代码,则Terraform运行将失败。
下面的代码示例显示了使用TerraCurl托管资源时的重试逻辑。这里的主要区别是额外的destroy_max_retry和destroy_retry_interval参数用于在销毁调用上启用和配置重试逻辑。

resource "terracurl_request" "mount" {
  name           = "vault-mount"
  url            = "https://localhost:8200/v1/sys/mounts/aws"
  method         = "POST"
  request_body   = <<EOF
{
  "type": "aws",
  "config": {
    "force_no_cache": true
  }
}
 
EOF
 
  headers = {
    X-Vault-Token = "s.dXHglIuimE3ma89OSjSQpOhy"
  }
 
  cert_file       = "server-vault-0.pem"
  key_file        = "server-vault-0-key.pem"
  ca_cert_file    = "vault-server-ca.pem"
  skip_tls_verify = false
 
 
  response_codes = [200,204]
  max_retry      = 3
  retry_interval = 10
 
 
  destroy_url    = "https://localhost:8200/v1/sys/mounts/aws"
  destroy_method = "DELETE"
 
  destroy_headers = {
    X-Vault-Token = "s.dXHglIuimE3ma89OSjSQpOhy"
  }
 
  destroy_cert_file       = "server-vault-0.pem"
  destroy_key_file        = "server-vault-0-key.pem"
  destroy_ca_cert_file    = "vault-server-ca.pem"
  destroy_skip_tls_verify = false
 
 
  destroy_response_codes = [204]
  destroy_max_retry      = 3
  destroy_retry_interval = 10
}

总结和后续步骤

在开发Terraform模块时有时会遇到的挑战,特别是Terraform提供程序中不受支持的资源。TerraCurl是一个灵活的Terraform实用程序提供者,可以在这些场景中提供帮助,并在工作流中打开更多的可能性和用例。

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。