简体   繁体   中英

Hide secret in Terraform

I am trying to create IPSEC tunnels on Palo Alto using Terraform. The code would the be pushed via a pipeline. I want all information of the tunnels to be readable, except for the pre_shared_key . I understand how I could encrypt it for one instance, but as there is going to be several tunnel, how can encrypt the key, and map it to its instance?

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: "*******"

The module for the tunnel on which I iterate looks like this:

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"
}

Gruntwork's guide to managing secrets covers a lot of this so is probably worth reading through.

Ideally you'd use an external secrets manager such as Hashicorp Vault or AWS SSM Parameter Store/Secrets Manager and generate the key using random_password , stashing it in your secret store with one side of the tunnel and then retrieving it from the secret store when applying the other side of the tunnel.

If you intend to create both sides of the tunnel with a single terraform apply (eg you keep the configuration for both in the same directory) then you don't even need the secrets store and can just rely on the fact that the secret is only ever stored in Terraform state and never in your repo which only has the input of the random_password resource.

In your case you'd have something like the following:

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"
}

An alternative option would be to either encrypt the whole of the YAML file in your repo using something like GPG or age , selectively encrypt parts of the file using something like SOPS or Ansible Vault or separate out the secret into another file that is fully encrypted with any of the above options, leaving the rest of the non secret configuration in plain text. You could then decrypt the relevant secret before running Terraform commands.

You will need to make sure that you secure access to and encrypt your Terraform state files because these will hold the secret in plain text. Terraform remote state backends commonly provide ways to do this such as specifying a KMS key for encrypting state files in S3.

From Terraform 0.14 onwards you can also mark variables as sensitive which will mask them when writing them to stdout. With the above pattern of using random_password this is automatically handled for you but if you were to input the pre-shared key as a variable then you'd want to explicitly mark it as sensitive:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM