简体   繁体   中英

Terraform Apply Error: Code="InvalidResourceName" Message="Resource name is invalid" When creating VPN-GW Module

I'm receiving the following error when executing the Terraform Apply Command.


│ Error: Creating/Updating Virtual Network Gateway: (Name "VPN-GW-HUB-dev" / Resource Group "RG-HUB-dev"): network.VirtualNetworkGatewaysClient#CreateOrUpdate: Failure sending request: StatusCode=400 -- Original Error: Code="InvalidResourceName" Message="Resource name  is invalid. The name can be up to 80 characters long. It must begin with a word character, and it must end with a word character or with '_'. The name may contain word characters or '.', '-', '_'." Details=[]
│ 
│   with module.MOD-VPN-GW.azurerm_virtual_network_gateway.vpngw,
│   on Modules/10.VPN-GW/main.tf line 31, in resource "azurerm_virtual_network_gateway" "vpngw":
│   31: resource "azurerm_virtual_network_gateway" "vpngw" {


What was I trying to do?

My Terraform code creates a complete Hub-and-Spoke infrastructure in Azure. It worked very well until I decided to modularise the VPN GW part.

My Terraform code structure is the usual format:

--Modules/{module-name}/main.tf
--main.tf

So within the {module-name} - I have a folder called:

10.VPN-GW\main.tf

What have I tried?

Well, I have tried to reformat the code, I double checked it against all other modules that worked OK. I have NO idea why this error is happening, and it has been 3 days now non stop debugging this.

The module file is here:

#------------------------------
# VPN GW MODULE FILE - ALso contains GW SUBNET
#-------------------------------

resource "azurerm_subnet" "gwSubnet" {
  name                 =    var.subnet_name
  resource_group_name  =    var.subnet_resource_group_name
  virtual_network_name =    var.subnet_virtual_network_name
  address_prefixes     =    var.subnet_address_prefixes

}

variable "subnet_name" {
    type = string
}

variable "subnet_resource_group_name" {
    type = string
}

variable "subnet_virtual_network_name" {
    type = string
}

variable "subnet_address_prefixes" {
    type = list(string)
}


output "outSubnetIDVPNGW" {
    value = azurerm_subnet.gwSubnet.id
}
 

resource "azurerm_virtual_network_gateway" "vpngw" {
  name                = "${var.vpn-gw-name}"
  location            = "${var.vpn-gw-location}"
  resource_group_name = "${var.vpngw_resource_group_name}"

  type     = "Vpn"
  vpn_type = "RouteBased"
  
  active_active = false
  enable_bgp    = false
  sku           = "VpnGw1"

  ip_configuration {
    name                          = "${var.ip_configuration_name}"
    public_ip_address_id          = "${var.ip_configuration_public_ip_address_id}"
    private_ip_address_allocation = "Dynamic"
    subnet_id                     = azurerm_subnet.gwSubnet.id
  }

    vpn_client_configuration {
        address_space = "${var.vpn_client_configuration_address_space}"

        root_certificate {
        name = "${var.root_certificate_name}"
        public_cert_data = "${var.cert}"
    }

    revoked_certificate {
      name       = "${var.revoked_certificate_name}"
      thumbprint = "${var.revoked_certificate_thumbprint}"
    }
  }
}

variable "vpn-gw-name" {
    type = string
    //default = ""
}

variable "vpn-gw-location" {
    //default = ""
    type = string
}

variable "vpngw_resource_group_name" {
    default = ""
}

variable "ip_configuration_name" {
    default = ""
}

variable "ip_configuration_public_ip_address_id" {
    default = ""
}

/*
variable "ip_configuration_private_ip_address_allocation" {
    //default = ""
   // type = string
}
*/

variable "vpn_client_configuration_address_space" {
    default = []
}

variable "root_certificate_name" {
    default = ""
}

variable "cert" {  
    default = ""
}

variable "revoked_certificate_name" {
  default = ""
}

variable "revoked_certificate_thumbprint" {
    default = ""
}

variable "ip_configuration" {
    type = map(string)
}


variable "vpn_client_configuration" {
  type = object({
    address_space           = list(string)
    root_certificate        = map(string)
    revoked_certificate     = map(string)
  })
} 

/*
variable "revoked_certificate" {
  type = map(string)
}
*/

The main.tf file -- that calls each module, is given below - (I'm only adding the snippet for the part causing the error) - ie creation of the VPN GW


#-----------------------------------------
# Create GW SUBNET & VPN GW
#-----------------------------------------

module "MOD-VPN-GW" {
  source              = "./Modules/10.VPN-GW"

  subnet_name                 = "GatewaySubnet"
  subnet_resource_group_name  = "RG-HUB-${var.environmentCode}"
  subnet_virtual_network_name =  "VNET-HUB-${var.environmentCode}"
  subnet_address_prefixes     = ["10.0.1.0/27"]

  vpn-gw-name                 = "VPN-GW-HUB-${var.environmentCode}"
  vpn-gw-location               = "westeurope"
  vpngw_resource_group_name   = "RG-HUB-${var.environmentCode}"
  
  ip_configuration = {
    name        = "VNetGatewayConfig"
    public_ip_address_id                    = "${module.MOD-VPNGW-PIP.id}"
    private_ip_address_allocation  = "Dynamic"
    subnet_id                   = module.MOD-VPN-GW.outSubnetIDVPNGW
  }

  vpn_client_configuration = {
    address_space = ["172.16.10.0/24"]

    root_certificate = {
      name = "dev.vpn.macos.com"
      public_cert_data  = data.azurerm_key_vault_certificate.akv-certificate.certificate_data_base64

    }

    revoked_certificate  = {
      name       = "Verizon-Global-Root-CA"
      thumbprint = "912198EEF23DCAC40939312FEE97DD560BAE49B1"
    }
  }

   depends_on = [
     module.MOD-RG-HUB, module.MOD-VNET-HUB, azurerm_linux_virtual_machine.label-vm-spoke-01
  ]

}

What did I search for?

I cannot seem to find this particular error code in a google search. Its not telling me that name given to my VPN GW is incorrect - its giving me the name (in the error message) and telling me that there is no name given. Which is odd. Or have I misunderstood the error message?

The terraform init command succeeds. The terraform validate command succeeds. The terraform plan command succeeds.

This fails when applying

There is an issue between the root module and the VPN GW module. The way that modules in Terraform work is similar to functions in other programming languages: they require certain input variables which are then replaced by the values provided to them. More about modules in [1].

To refactor this code, I would do the following in the root module:

  source = "./Modules/10.VPN-GW"

  subnet_name                 = "GatewaySubnet"
  subnet_resource_group_name  = "RG-HUB-${var.environmentCode}"
  subnet_virtual_network_name = "VNET-HUB-${var.environmentCode}"
  subnet_address_prefixes     = ["10.0.1.0/27"]

  vpn-gw-name               = "VPN-GW-HUB-${var.environmentCode}"
  vpn-gw-location           = "westeurope"
  vpngw_resource_group_name = "RG-HUB-${var.environmentCode}"

  ip_configuration_name                 = "VNetGatewayConfig"
  ip_configuration_public_ip_address_id = module.MOD-VPNGW-PIP.id

  vpn_client_configuration_address_space = ["172.16.10.0/24"]
  root_certificate_name                  = "dev.vpn.macos.com"
  cert                                   = data.azurerm_key_vault_certificate.akv-certificate.certificate_data_base64

  revoked_certificate_name       = "Verizon-Global-Root-CA"
  revoked_certificate_thumbprint = "912198EEF23DCAC40939312FEE97DD560BAE49B1"

}

As you can see, the only change I did was to assign the values to variables that the VPN GW module requires. The way this works is when the module is called, it will be provided with values for the variables and it will know what to do with them. There is no need to define the same blocks in the calling ( root ) and called module ( VPN GW ). So, think of the root module as of a piece of code that invokes a function, something like:

MOD_VPN_GW(subnet_name, subnet_resource_group_name, subnet_virtual_network_name, subnet_address_prefixes, vpn-gw-name, vpn-gw-location, vpngw_resource_group_name, ip_configuration_name, ip_configuration_public_ip_address_id, vpn_client_configuration_address_space, root_certificate_name, cert, revoked_certificate_name, revoked_certificate_thumbprint)

As for your question about how the su.net_id will be accessible, that is the easy part. In the VPN GW module there is a resource block for azurerm_su.net :

resource "azurerm_subnet" "gwSubnet" {
  name                 = var.subnet_name
  resource_group_name  = var.subnet_resource_group_name
  virtual_network_name = var.subnet_virtual_network_name
  address_prefixes     = var.subnet_address_prefixes
}

One of the attributes that is provided by this resource after creation is the su.net ID [2].That means that you can assign the attribute value by referencing the resulting value using this syntax [3]:

<resource type>.<resource_name>.<attribute>

In your case that is:

azurerm_subnet.gwSubnet.id

This value is already referenced in the su.net_id argument of the azurerm_virtual.network_gateway resource:

subnet_id = azurerm_subnet.gwSubnet.id

This means it is not required as one of the input variables by the module. The good thing is that the VPN GW module will know in which order to create resource as this is an implicit dependency.


[1] https://www.terraform.io/language/modules/develop

[2] https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/su.net#id

[3] https://www.terraform.io/language/expressions/references#references-to-resource-attributes

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