1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

TerraformでVirtual Network/Subnetを使うときの注意事項(Azure)

Last updated at Posted at 2022-08-13

自分でハマったのでメモ。

この記事のまとめ

resource "azurerm_virtual_network"の中のsubnetとresource "azurerm_subnet"を同時に使ってはいけない(戒め)

経緯

Azureの環境をterraformで作るとき、初回はApplyがうまくいく。
2回目以降Applyがうまくいかない。

 Error: creating/updating Virtual Network: (Name "mysql-vnet" / Resource Group "mysql-test"): network.VirtualNetworksClient#CreateOrUpdate: Failure sending request: StatusCode=400 -- Original Error: Code="InUseSubnetCannotBeDeleted" Message="Subnet ep-subnet is in use by /subscriptions/<Subscription ID>/resourceGroups/mysql-test/providers/Microsoft.Network/networkInterfaces/<EP-nic>/ipConfigurations/<EP-Config> and cannot be deleted. In order to delete the subnet, delete all the resources within the subnet. See aka.ms/deletesubnet." Details=[]

どうやらVirtual NetworkのSubnetを削除しようとしているものの、Private EndpointのNICがあって消せないよ、とエラーになっている模様。
そもそも削除意図なんてないので、原因を探るべくTerraformのドキュメントを見ると下記の記載が。

NOTE on Virtual Networks and Subnets:
Terraform currently provides both a standalone Subnet resource, and allows for
Subnets to be defined in-line within the Virtual Network resource. At this time you
cannot use a Virtual Network with in-line Subnets in conjunction with any Subnet
resources. Doing so will cause a conflict of Subnet configurations and will
overwrite subnets.

つまるところ、どういうことかというとサブネットの設定が競合するから両方を使うなってことですね。

従来のコード

# Resource Group
resource "azurerm_resource_group" "example" {
  name     = "example-rg"
  location = "japaneast"
}
# Virtual Network
resource "azurerm_virtual_network" "example" {
  name                = "example"
  location            = azurerm_resource_group.example.location
  resource_group_name = azurerm_resource_group.example.name
  address_space       = ["172.24.0.0/16"]
  subnet {
    name           = "subnet1"
    address_prefix = "172.24.0.0/24"
  }
}

例えば、上記の例だと下記リソースが作られます。

  • resource group: example-rg
  • virtual network: 172.24.0.0/16
  • Subnet: 172.24.0.0/24

subnetブロックは複数指定できます。
ただ、サポートされている内容が限定されています。

  • name
  • address_prefix
  • security_group
    例えば、ストレージアカウントのネットワークルールにvNETを追加したいときにServiceEndpointを指定することができません。

そのため、"azurerm_subnet"を追加します。

resource "azurerm_subnet" "subnet2" {
    name                                            = "subnet2"
    resource_group_name                             = azurerm_resource_group.example.name
    virtual_network_name                            = azurerm_virtual_network.example.name
    address_prefixes                                = ["172.24.100.0/24"]
    service_endpoints                               = ["Microsoft.Storage"]
}

そうすると、どうなるでしょうか。
初回はterraform plan → terraform applyと成功します。
2回目以降applyを実行しようとすると上記のエラーが発生します。(terraform plan時は成功する)
おそらく、resource "azurerm_virtual_network"で情報にないサブネットを削除した後に、resource "azurerm_subnet"で再度追加しようとしているのだと思います。
ただ、そこに既にリソースがある場合、Subnetの削除ができず、エラーになっているものだと思います。

コード修正後

ドキュメントにもある通り、修正します。

# Resource Group
resource "azurerm_resource_group" "example" {
  name     = "example-rg"
  location = "japaneast"
}
# Virtual Network
resource "azurerm_virtual_network" "example" {
  name                = "example"
  location            = azurerm_resource_group.example.location
  resource_group_name = azurerm_resource_group.example.name
  address_space       = ["172.24.0.0/16"]
}
# Subnet
resource "azurerm_subnet" "subnet1" {
    name                                            = "subnet1"
    resource_group_name                             = azurerm_resource_group.example.name
    virtual_network_name                            = azurerm_virtual_network.example.name
    address_prefixes                                = ["172.24.0.0/24"]
}
resource "azurerm_subnet" "subnet2" {
    name                                            = "subnet2"
    resource_group_name                             = azurerm_resource_group.example.name
    virtual_network_name                            = azurerm_virtual_network.example.name
    address_prefixes                                = ["172.24.100.0/24"]
    service_endpoints                               = ["Microsoft.Storage"]
}

できること、できないこと

こうすることで成功します。
ただ、問題点もあります。
resource "azurerm_virtual_network"のときはNSGの割当ができましたが、resource "azurerm_subnet"にはこの記載がありません。

表にまとめると、こんな感じ。

resource "azurerm_virtual_network" "azurerm_subnet"
できること NSGの割当ができる Service Endpointが作れる
できないこと Service Endpointが作れない NSGの割当ができない

めんどくさいですねえ・・・

サブネットにNSGの割当

resource "azurerm_subnet_network_security_group_association"というものがあるようです。

こちらで"azurerm_subnet"で作ったサブネットを割り当てましょう。

# Network Security Group
resource "azurerm_network_security_group" "example" {
  name                = "example-nsg"
  location            = azurerm_resource_group.example.location
  resource_group_name = azurerm_resource_group.example.name

  security_rule {
    name                       = "allow"
    priority                   = 100
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "*"
    source_port_range          = "*"
    destination_port_range     = "*"
    source_address_prefix      = "<Your Global IP>"
    destination_address_prefix = "172.24.0.0/24"
  }  
}

# NSGの割当 -> Subnet1
resource "azurerm_subnet_network_security_group_association" "subnet1" {
  subnet_id                 = azurerm_subnet.subnet1.id
  network_security_group_id = azurerm_network_security_group.example.id
}

これでサブネットにNSGを割り当てられました。

以上。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?