azure - 如何使用 Terraform 设置私有(private)链接来访问存储帐户?

标签 azure terraform terraform-provider-aws azure-private-link

我需要使用以下场景测试我的 azure 专用端点。

  1. 我们有一个带有两个子网的虚拟网络(vm_subnetstorage_account_subnet)
  2. 虚拟机 (vm) 应能够使用专用链接连接到存储帐户

因此,下图解释了该场景: enter image description here

然后我需要使用以下手动测试用例来测试我的端点:

  1. 使用 ssh 和 putty 连接到 Azure 虚拟机,用户名:adminuser 和密码:P@$$w0rd1234!
  2. 在终端ping formuleinsstorage.blob.core.windows.net(期望看到storage_account_subnet范围内的存储帐户的IP(10.0.2.0/24 ))

我使用以下 Terraform 代码部署所有基础设施:

provider "azurerm" {

  features {
    resource_group {
      prevent_deletion_if_contains_resources = false
    }
  }
}

resource "azurerm_resource_group" "main_resource_group" {
  name     = "RG-Terraform-on-Azure"
  location = "West Europe"
}
# Create Virtual-Network

resource "azurerm_virtual_network" "virtual_network" {
  name                = "Vnet"
  address_space       = ["10.0.0.0/16"]
  location            = azurerm_resource_group.main_resource_group.location
  resource_group_name = azurerm_resource_group.main_resource_group.name
}


# Create subnet for virtual-machine

resource "azurerm_subnet" "virtual_network_subnet" {
  name                 = "vm_subnet"
  resource_group_name  = azurerm_resource_group.main_resource_group.name
  virtual_network_name = azurerm_virtual_network.virtual_network.name
  address_prefixes     = ["10.0.1.0/24"]
}

# Create subnet for storage account

resource "azurerm_subnet" "storage_account_subnet" {
  name                 = "storage_account_subnet"
  resource_group_name  = azurerm_resource_group.main_resource_group.name
  virtual_network_name = azurerm_virtual_network.virtual_network.name
  address_prefixes     = ["10.0.2.0/24"]
}

# Create Linux Virtual machine
resource "azurerm_linux_virtual_machine" "example" {
  name                            = "example-machine"
  location                        = azurerm_resource_group.main_resource_group.location
  resource_group_name             = azurerm_resource_group.main_resource_group.name
  size                            = "Standard_F2"
  admin_username                  = "adminuser"
  admin_password                  = "14394Las?"
  disable_password_authentication = false
  network_interface_ids           = [
    azurerm_network_interface.virtual_machine_network_interface.id,
  ]


  os_disk {
    caching              = "ReadWrite"
    storage_account_type = "Standard_LRS"
  }

  source_image_reference {
    publisher = "Canonical"
    offer     = "UbuntuServer"
    sku       = "16.04-LTS"
    version   = "latest"
  }
}

resource "azurerm_network_interface" "virtual_machine_network_interface" {
  name                = "vm-nic"
  location            = azurerm_resource_group.main_resource_group.location
  resource_group_name = azurerm_resource_group.main_resource_group.name

  ip_configuration {
    name                          = "internal"
    subnet_id                     = azurerm_subnet.virtual_network_subnet.id
    private_ip_address_allocation = "Dynamic"
    public_ip_address_id          = azurerm_public_ip.vm_public_ip.id
  }
}

# Create Network-interface and public-ip for virtual-machien

resource "azurerm_public_ip" "vm_public_ip" {
  name                = "vm-public-ip-for-rdp"
  location            = azurerm_resource_group.main_resource_group.location
  resource_group_name = azurerm_resource_group.main_resource_group.name
  allocation_method   = "Static"
  sku                 = "Standard"
}

resource "azurerm_network_interface" "virtual_network_nic" {
  name                = "vm_nic"
  location            = azurerm_resource_group.main_resource_group.location
  resource_group_name = azurerm_resource_group.main_resource_group.name

  ip_configuration {
    name                          = "testconfiguration1"
    subnet_id                     = azurerm_subnet.virtual_network_subnet.id
    private_ip_address_allocation = "Dynamic"
  }
}

# Setup an Inbound rule because we need to connect to the virtual-machine using RDP (remote-desktop-protocol)

resource "azurerm_network_security_group" "traffic_rules" {
  name                = "vm_traffic_rules"
  location            = azurerm_resource_group.main_resource_group.location
  resource_group_name = azurerm_resource_group.main_resource_group.name

  security_rule {
    name                       = "virtual_network_permission"
    priority                   = 100
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "*"
    source_port_range          = "*"
    destination_port_range     = "22"
    source_address_prefix      = "*"
    destination_address_prefix = "*"
  }
}

resource "azurerm_subnet_network_security_group_association" "private_nsg_asso" {
  subnet_id                 = azurerm_subnet.virtual_network_subnet.id
  network_security_group_id = azurerm_network_security_group.traffic_rules.id

}

# Setup storage_account and its container

resource "azurerm_storage_account" "storage_account" {
  name                     = "storagaccountfortest"
  location                 = azurerm_resource_group.main_resource_group.location
  resource_group_name      = azurerm_resource_group.main_resource_group.name
  account_tier             = "Standard"
  account_replication_type = "LRS"
  account_kind             = "StorageV2"
  is_hns_enabled           = "true"

}

resource "azurerm_storage_data_lake_gen2_filesystem" "data_lake_storage" {
  name               = "rawdata"
  storage_account_id = azurerm_storage_account.storage_account.id

  lifecycle {
    prevent_destroy = false
  }
}

# Setup DNS zone
resource "azurerm_private_dns_zone" "dns_zone" {
  name                = "privatelink.blob.core.windows.net"
  resource_group_name = azurerm_resource_group.main_resource_group.name
}

resource "azurerm_private_dns_zone_virtual_network_link" "network_link" {
  name                  = "vnet_link"
  resource_group_name   = azurerm_resource_group.main_resource_group.name
  private_dns_zone_name = azurerm_private_dns_zone.dns_zone.name
  virtual_network_id    = azurerm_virtual_network.virtual_network.id

}

# Setup private-link

resource "azurerm_private_endpoint" "endpoint" {
  name                = "storage-private-endpoint"
  location            = azurerm_resource_group.main_resource_group.location
  resource_group_name = azurerm_resource_group.main_resource_group.name
  subnet_id           = azurerm_subnet.storage_account_subnet.id

  private_service_connection {
    name                           = "private-service-connection"
    private_connection_resource_id = azurerm_storage_account.storage_account.id
    is_manual_connection           = false
    subresource_names              = ["blob"]
  }
}

resource "azurerm_private_dns_a_record" "dns_a" {
  name                = "dns-record"
  zone_name           = azurerm_private_dns_zone.dns_zone.name
  resource_group_name = azurerm_resource_group.main_resource_group.name
  ttl                 = 10
  records             = [azurerm_private_endpoint.endpoint.private_service_connection.0.private_ip_address]
}

问题是,我的端点不起作用!但是,如果我尝试手动添加服务端点,那么一切都会顺利进行。所以,我认为,我的 DNS 区域是正确的,而且显然到存储帐户的链接也运行良好。所以,我认为我的私有(private)链接应该有问题!有什么想法吗?

更新:

以下是版本:

Terraform v1.2.5
on windows_386
+ provider registry.terraform.io/hashicorp/azurerm v3.30.0

最佳答案

我认为问题在于 dns_a_record 的名称。这应该是您想要通过专用链接访问的存储帐户的名称。

以下 Terraform 代码对我有用:

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "=3.30.0"
    }
  }
}

provider "azurerm" {
  features {
    resource_group {
      prevent_deletion_if_contains_resources = false
    }
  }
}

resource "azurerm_resource_group" "main_resource_group" {
  name     = "RG-Terraform-on-Azure"
  location = "West Europe"
}


# Create Virtual-Network
resource "azurerm_virtual_network" "virtual_network" {
  name                = "Vnet"
  address_space       = ["10.0.0.0/16"]
  location            = azurerm_resource_group.main_resource_group.location
  resource_group_name = azurerm_resource_group.main_resource_group.name
}


# Create subnet for virtual-machine
resource "azurerm_subnet" "virtual_network_subnet" {
  name                 = "vm_subnet"
  resource_group_name  = azurerm_resource_group.main_resource_group.name
  virtual_network_name = azurerm_virtual_network.virtual_network.name
  address_prefixes     = ["10.0.1.0/24"]
}

# Create subnet for storage account
resource "azurerm_subnet" "storage_account_subnet" {
  name                 = "storage_account_subnet"
  resource_group_name  = azurerm_resource_group.main_resource_group.name
  virtual_network_name = azurerm_virtual_network.virtual_network.name
  address_prefixes     = ["10.0.2.0/24"]
}

# Create Linux Virtual machine
resource "azurerm_linux_virtual_machine" "example" {
  name                            = "example-machine"
  location                        = azurerm_resource_group.main_resource_group.location
  resource_group_name             = azurerm_resource_group.main_resource_group.name
  size                            = "Standard_F2"
  admin_username                  = "adminuser"
  admin_password                  = "14394Las?"
  disable_password_authentication = false
  network_interface_ids           = [
    azurerm_network_interface.virtual_machine_network_interface.id,
  ]


  os_disk {
    caching              = "ReadWrite"
    storage_account_type = "Standard_LRS"
  }

  source_image_reference {
    publisher = "Canonical"
    offer     = "UbuntuServer"
    sku       = "16.04-LTS"
    version   = "latest"
  }
}

resource "azurerm_network_interface" "virtual_machine_network_interface" {
  name                = "vm-nic"
  location            = azurerm_resource_group.main_resource_group.location
  resource_group_name = azurerm_resource_group.main_resource_group.name

  ip_configuration {
    name                          = "internal"
    subnet_id                     = azurerm_subnet.virtual_network_subnet.id
    private_ip_address_allocation = "Dynamic"
    public_ip_address_id          = azurerm_public_ip.vm_public_ip.id
  }
}

# Create Network-interface and public-ip for virtual-machien
resource "azurerm_public_ip" "vm_public_ip" {
  name                = "vm-public-ip-for-rdp"
  location            = azurerm_resource_group.main_resource_group.location
  resource_group_name = azurerm_resource_group.main_resource_group.name
  allocation_method   = "Static"
  sku                 = "Standard"
}

resource "azurerm_network_interface" "virtual_network_nic" {
  name                = "storage-private-endpoint-nic"
  location            = azurerm_resource_group.main_resource_group.location
  resource_group_name = azurerm_resource_group.main_resource_group.name

  ip_configuration {
    name                          = "storage-private-endpoint-ip-config"
    subnet_id                     = azurerm_subnet.virtual_network_subnet.id
    private_ip_address_allocation = "Dynamic"
  }
}

# Setup an Inbound rule because we need to connect to the virtual-machine using RDP (remote-desktop-protocol)
resource "azurerm_network_security_group" "traffic_rules" {
  name                = "vm_traffic_rules"
  location            = azurerm_resource_group.main_resource_group.location
  resource_group_name = azurerm_resource_group.main_resource_group.name

  security_rule {
    name                       = "virtual_network_permission"
    priority                   = 100
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "*"
    source_port_range          = "*"
    destination_port_range     = "22"
    source_address_prefix      = "*"
    destination_address_prefix = "*"
  }
}

resource "azurerm_subnet_network_security_group_association" "private_nsg_asso" {
  subnet_id                 = azurerm_subnet.virtual_network_subnet.id
  network_security_group_id = azurerm_network_security_group.traffic_rules.id

}

# Setup storage_account and its container
resource "azurerm_storage_account" "storage_account" {
  name                     = <STORAGE_ACCOUNT_NAME>
  location                 = azurerm_resource_group.main_resource_group.location
  resource_group_name      = azurerm_resource_group.main_resource_group.name
  account_tier             = "Standard"
  account_replication_type = "LRS"
  account_kind             = "StorageV2"
  is_hns_enabled           = "true"

}

resource "azurerm_storage_data_lake_gen2_filesystem" "data_lake_storage" {
  name               = "rawdata"
  storage_account_id = azurerm_storage_account.storage_account.id

  lifecycle {
    prevent_destroy = false
  }
}

# Setup DNS zone
resource "azurerm_private_dns_zone" "dns_zone" {
  name                = "privatelink.blob.core.windows.net"
  resource_group_name = azurerm_resource_group.main_resource_group.name
}

resource "azurerm_private_dns_zone_virtual_network_link" "network_link" {
  name                  = "vnet-link"
  resource_group_name   = azurerm_resource_group.main_resource_group.name
  private_dns_zone_name = azurerm_private_dns_zone.dns_zone.name
  virtual_network_id    = azurerm_virtual_network.virtual_network.id
}

# Setup private-link
resource "azurerm_private_endpoint" "endpoint" {
  name                = "storage-private-endpoint"
  location            = azurerm_resource_group.main_resource_group.location
  resource_group_name = azurerm_resource_group.main_resource_group.name
  subnet_id           = azurerm_subnet.storage_account_subnet.id

  private_service_connection {
    name                           = "storage-private-service-connection"
    private_connection_resource_id = azurerm_storage_account.storage_account.id
    is_manual_connection           = false
    subresource_names              = ["blob"]
  }
}

resource "azurerm_private_dns_a_record" "dns_a" {
  name                = azurerm_storage_account.storage_account.name
  zone_name           = azurerm_private_dns_zone.dns_zone.name
  resource_group_name = azurerm_resource_group.main_resource_group.name
  ttl                 = 10
  records             = [azurerm_private_endpoint.endpoint.private_service_connection.0.private_ip_address]
}

此外,我不确定是否可以 ping 存储帐户。为了测试我跑了 nslookup <STORAGE_ACCOUNT_NAME>.blob.core.windows.net来 self 的本地计算机和 Azure VM。在前一种情况下,我获得了一个公共(public) IP,而在后者中,我获得了 Terraform 配置中定义的范围内的私有(private) IP,这似乎是您正在寻找的行为。

关于azure - 如何使用 Terraform 设置私有(private)链接来访问存储帐户?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74381950/

相关文章:

azure - Kubernetes 挑战正在等待 http-01 传播 : dial tcp: no such host

Azure REST 访问 token

Azure 服务总线空闲时自动删除

postgresql - 如何使用 Terraform 销毁 RDS 中其他用户拥有的 Postgres 数据库?

amazon-web-services - 如何使用 Terraform 创建与 AWS S3 的 Snowflake 存储集成?

azure - EventGridTrigger Azure Functions 与 Blob 触发器

azure - Azure 上的 Terraform 公共(public) IP 输出

terraform 无法重命名多个 aws 资源

amazon-web-services - Terraform 错误创建子网依赖

amazon-web-services - 使用 terraform 动态 block 构建 S3 存储桶策略