首页 > 解决方案 > 在 Terraform 中隐藏秘密

问题描述

我正在尝试使用 Terraform 在帕洛阿尔托创建 IPSEC 隧道。代码将通过管道推送。我希望隧道的所有信息都是可读的,除了pre_shared_key. 我了解如何为一个实例加密它,但由于会有多个隧道,如何加密密钥并将其映射到它的实例?

vpns.yml:

vpns:
  - name: "Test"
    template: "template_name"
    ip_type: "IP"
    ip_remote: "1.1.1.1"
    firewall_interface: "vlan.xxxx"
    local_ip: "public_ip/24"
    ikev2_profile: "VerySecure"
    tunnel_interface: "tunnel1"
    pre_shared_key: "*******"

我迭代的隧道模块如下所示:

locals {
  tunnel = yamldecode(file(var.vpn_file))
}


resource "panos_panorama_ike_gateway" "gateway" {
  for_each = { for e in local.tunnel : e.Name => e }

  name                         = each.value.name
  template                     = each.value.template
  version                      = "ikev2-preferred"
  peer_ip_type                 = each.value.ip_type
  peer_ip_value                = each.value.ip_remote
  interface                    = each.value.firewall_interface
  local_ip_address_type        = "ip"
  local_ip_address_value       = each.value.local_ip
  pre_shared_key               = each.value.pre_shared_key
  ikev2_crypto_profile         = each.value.ikev2_profile
  enable_dead_peer_detection   = true
  dead_peer_detection_interval = "10"
  dead_peer_detection_retry    = "3"
  liveness_check_interval      = "5"
}

标签: terraform

解决方案


Gruntwork 的机密管理指南涵盖了很多内容,因此可能值得一读。

理想情况下,您将使用外部密钥管理器(例如 Hashicorp Vault 或 AWS SSM Parameter Store/Secrets Manager)并使用 生成密钥random_password,将其存储在隧道一侧的密钥存储中,然后在应用时从密钥存储中检索它隧道的另一边。

如果您打算使用单个创建隧道的两侧terraform apply(例如,您将两者的配置保存在同一个目录中),那么您甚至不需要秘密存储并且可以只依赖于秘密只被存储的事实处于 Terraform 状态,永远不会出现在只有random_password资源输入的仓库中。

在您的情况下,您将拥有以下内容:

locals {
  tunnel = {
    "vpns" = [
      {
        "firewall_interface" = "vlan.xxxx"
        "ikev2_profile"      = "VerySecure"
        "ip_remote"          = "1.1.1.1"
        "ip_type"            = "IP"
        "local_ip"           = "public_ip/24"
        "name"               = "TestLeft"
        "template"           = "template_name"
        "tunnel_interface"   = "tunnel1"
      },
      {
        "firewall_interface" = "vlan.xxxx"
        "ikev2_profile"      = "VerySecure"
        "ip_remote"          = "2.2.2.2"
        "ip_type"            = "IP"
        "local_ip"           = "public_ip/24"
        "name"               = "TestRight"
        "template"           = "template_name"
        "tunnel_interface"   = "tunnel1"
      },
    ]
  }
}

resource "random_password" "pre_shared_key" {
  length = 32
}

resource "panos_panorama_ike_gateway" "gateway" {
  for_each = { for e in local.tunnel : e.Name => e }

  name                         = each.value.name
  template                     = each.value.template
  version                      = "ikev2-preferred"
  peer_ip_type                 = each.value.ip_type
  peer_ip_value                = each.value.ip_remote
  interface                    = each.value.firewall_interface
  local_ip_address_type        = "ip"
  local_ip_address_value       = each.value.local_ip
  pre_shared_key               = random_password.pre_shared_key.result
  ikev2_crypto_profile         = each.value.ikev2_profile
  enable_dead_peer_detection   = true
  dead_peer_detection_interval = "10"
  dead_peer_detection_retry    = "3"
  liveness_check_interval      = "5"
}

另一种选择是使用GPGage之类的东西加密你的 repo 中的整个 YAML 文件,使用SOPSAnsible Vault之类的东西有选择地加密文件的一部分,或者将秘密分离到另一个完全加密的文件中上述任何选项,其余的非秘密配置以纯文本形式保留。然后,您可以在运行 Terraform 命令之前解密相关机密。

您需要确保安全访问和加密您的 Terraform 状态文件,因为这些文件将以纯文本形式保存秘密。Terraform 远程状态后端通常提供执行此操作的方法,例如指定用于加密 S3 中的状态文件的 KMS 密钥。

从 Terraform 0.14 开始,您还可以将变量标记为敏感变量,这将在将它们写入标准输出时屏蔽它们。使用上面的使用模式random_password会自动为您处理,但如果您要将预共享密钥作为变量输入,那么您需要明确地将其标记为敏感:

variable "pre_shared_key" {
  description = "The pre-shared key for the VPN tunnel"
  type        = string
  sensitive   = true
}

推荐阅读