配置网络终结点以访问 Azure 文件共享

Azure 文件存储提供两种主要类型的终结点用于访问 Azure 文件共享:

  • 公共终结点:使用公共 IP 地址,可从全球任意位置访问。
  • 专用终结点:位于某个虚拟网络中,并使用该虚拟网络的地址空间内部的专用 IP 地址。

公共和专用终结点位于 Azure 存储帐户中。 存储帐户是代表共享存储池的管理结构,你可以在其中部署多个文件共享以及其他存储资源(例如,Blob 容器或队列)。

本文重点介绍如何配置存储帐户的终结点,以便直接访问 Azure 文件共享。 本文的大部分内容也适用于 Azure 文件同步如何与存储帐户的公共和专用终结点互操作。 若要详细了解 Azure 文件同步的网络注意事项,请参阅配置 Azure 文件同步代理和防火墙设置

在阅读本指南之前,建议先阅读 Azure 文件存储的网络注意事项

适用于

文件共享类型 SMB NFS
标准文件共享 (GPv2)、LRS/ZRS 是 否
标准文件共享 (GPv2)、GRS/GZRS 是 否
高级文件共享 (FileStorage)、LRS/ZRS 是 是

先决条件

  • 本文假设你已经创建了一个 Azure 订阅。 如果还没有订阅,请在开始前创建一个试用帐户
  • 本文假设你已经在要从本地连接到的存储帐户中创建了一个 Azure 文件共享。 若要了解如何创建 Azure 文件共享,请参阅创建 Azure 文件共享
  • 如果你打算使用 Azure PowerShell,请安装最新版本
  • 如果你打算使用 Azure CLI,请安装最新版本

终结点配置

可以配置终结点,以限制对存储帐户的网络访问。 可通过两种方法来仅限虚拟网络访问存储帐户:

创建专用终结点

为存储帐户创建专用终结点时,会部署以下 Azure 资源:

  • 一个专用终结点:表示存储帐户专用终结点的 Azure 资源。 可将此资源视为连接存储帐户和网络接口的资源。
  • 一个网络接口 (NIC) :在指定的虚拟网络/子网中保留专用 IP 地址的网络接口。 此网络接口是部署虚拟机 (VM) 时部署的同一个资源,但它不会分配到 VM,而是由专用终结点拥有。
  • 专用域名系统 DNS 区域:如果你以前没有为此虚拟网络部署过专用终结点,系统将为虚拟网络部署新的专用 DNS 区域。 此外,将为此 DNS 区域中的存储帐户创建 DNS A 记录。 如果已在此虚拟网络中部署了专用终结点,则会将存储帐户的新 A 记录添加到现有 DNS 区域。 部署 DNS 区域是可选操作。 不过,强烈建议执行此操作;如果使用 AD 服务主体或 FileREST API 装载 Azure 文件共享,则必须执行此操作。

若要为存储帐户创建专用终结点,首先需要获取对存储帐户的引用,以及要将专用终结点添加到的虚拟网络子网的引用。 请替换下面的 <storage-account-resource-group-name><storage-account-name><vnet-resource-group-name><vnet-name><vnet-subnet-name>

$storageAccountResourceGroupName = "<storage-account-resource-group-name>"
$storageAccountName = "<storage-account-name>"
$virtualNetworkResourceGroupName = "<vnet-resource-group-name>"
$virtualNetworkName = "<vnet-name>"
$subnetName = "<vnet-subnet-name>"

# Get storage account reference, and throw error if it doesn't exist
$storageAccount = Get-AzStorageAccount `
        -ResourceGroupName $storageAccountResourceGroupName `
        -Name $storageAccountName `
        -ErrorAction SilentlyContinue

if ($null -eq $storageAccount) {
    $errorMessage = "Storage account $storageAccountName not found "
    $errorMessage += "in resource group $storageAccountResourceGroupName."
    Write-Error -Message $errorMessage -ErrorAction Stop
}

# Get virtual network reference, and throw error if it doesn't exist
$virtualNetwork = Get-AzVirtualNetwork `
        -ResourceGroupName $virtualNetworkResourceGroupName `
        -Name $virtualNetworkName `
        -ErrorAction SilentlyContinue

if ($null -eq $virtualNetwork) {
    $errorMessage = "Virtual network $virtualNetworkName not found "
    $errorMessage += "in resource group $virtualNetworkResourceGroupName."
    Write-Error -Message $errorMessage -ErrorAction Stop
}

# Get reference to virtual network subnet, and throw error if it doesn't exist
$subnet = $virtualNetwork | `
    Select-Object -ExpandProperty Subnets | `
    Where-Object { $_.Name -eq $subnetName }

if ($null -eq $subnet) {
    Write-Error `
            -Message "Subnet $subnetName not found in virtual network $virtualNetworkName." `
            -ErrorAction Stop
}

若要创建专用终结点,必须与存储帐户建立专用链接服务连接。 专用链接服务连接是创建专用终结点时使用的输入。

# Disable private endpoint network policies
$subnet.PrivateEndpointNetworkPolicies = "Disabled"
$virtualNetwork = $virtualNetwork | `
    Set-AzVirtualNetwork -ErrorAction Stop

# Create a private link service connection to the storage account.
$privateEndpointConnection = New-AzPrivateLinkServiceConnection `
        -Name "$storageAccountName-Connection" `
        -PrivateLinkServiceId $storageAccount.Id `
        -GroupId "file" `
        -ErrorAction Stop

# Create a new private endpoint.
$privateEndpoint = New-AzPrivateEndpoint `
        -ResourceGroupName $storageAccountResourceGroupName `
        -Name "$storageAccountName-PrivateEndpoint" `
        -Location $virtualNetwork.Location `
        -Subnet $subnet `
        -PrivateLinkServiceConnection $privateEndpointConnection `
        -ErrorAction Stop

创建 Azure 专用 DNS 区域可将存储帐户的原始名称(例如 storageaccount.file.core.chinacloudapi.cn)解析为虚拟网络内部的专用 IP。 尽管从创建专用终结点的角度来看,此操作是可选的,但如果直接使用 AD 用户主体装载或通过 REST API 访问 Azure 文件共享,则此操作肯定是必需的。

# Get the desired storage account suffix (core.chinacloudapi.cn for Azure China cloud).
# This is done like this so this script will seamlessly work for non-public Azure.
$storageAccountSuffix = Get-AzContext | `
    Select-Object -ExpandProperty Environment | `
    Select-Object -ExpandProperty StorageEndpointSuffix

# For Azure China cloud, this will generate the following DNS suffix:
# privatelink.file.core.chinacloudapi.cn.
$dnsZoneName = "privatelink.file.$storageAccountSuffix"

# Find a DNS zone matching desired name attached to this virtual network.
$dnsZone = Get-AzPrivateDnsZone | `
    Where-Object { $_.Name -eq $dnsZoneName } | `
    Where-Object {
        $privateDnsLink = Get-AzPrivateDnsVirtualNetworkLink `
                -ResourceGroupName $_.ResourceGroupName `
                -ZoneName $_.Name `
                -ErrorAction SilentlyContinue
        
        $privateDnsLink.VirtualNetworkId -eq $virtualNetwork.Id
    }

if ($null -eq $dnsZone) {
    # No matching DNS zone attached to virtual network, so create new one.
    $dnsZone = New-AzPrivateDnsZone `
            -ResourceGroupName $virtualNetworkResourceGroupName `
            -Name $dnsZoneName `
            -ErrorAction Stop

    $privateDnsLink = New-AzPrivateDnsVirtualNetworkLink `
            -ResourceGroupName $virtualNetworkResourceGroupName `
            -ZoneName $dnsZoneName `
            -Name "$virtualNetworkName-DnsLink" `
            -VirtualNetworkId $virtualNetwork.Id `
            -ErrorAction Stop
}

获取对专用 DNS 区域的引用后,接下来必须创建存储帐户的 A 记录。

$privateEndpointIP = $privateEndpoint | `
    Select-Object -ExpandProperty NetworkInterfaces | `
    Select-Object @{ 
        Name = "NetworkInterfaces"; 
        Expression = { Get-AzNetworkInterface -ResourceId $_.Id } 
    } | `
    Select-Object -ExpandProperty NetworkInterfaces | `
    Select-Object -ExpandProperty IpConfigurations | `
    Select-Object -ExpandProperty PrivateIpAddress

$privateDnsRecordConfig = New-AzPrivateDnsRecordConfig `
        -IPv4Address $privateEndpointIP

New-AzPrivateDnsRecordSet `
        -ResourceGroupName $virtualNetworkResourceGroupName `
        -Name $storageAccountName `
        -RecordType A `
        -ZoneName $dnsZoneName `
        -Ttl 600 `
        -PrivateDnsRecords $privateDnsRecordConfig `
        -ErrorAction Stop | `
    Out-Null

验证连接性

如果你在虚拟网络中有一个 VM,或者已按配置 Azure 文件存储的 DNS 转发所述配置了 DNS 转发,你可通过运行以下命令来测试是否已正确设置专用终结点:

$storageAccountHostName = [System.Uri]::new($storageAccount.PrimaryEndpoints.file) | `
    Select-Object -ExpandProperty Host

Resolve-DnsName -Name $storageAccountHostName

如果成功,应会看到以下输出,其中 192.168.0.5 是虚拟网络中专用终结点的专用 IP 地址:

Name                                        Type   TTL   Section    NameHost
----                                        ----   ---   -------    --------
storageaccount.file.core.chinacloudapi.cn   CNAME  60    Answer     storageaccount.privatelink.file.core.chinacloudapi.cn


Name       : storageaccount.privatelink.file.core.chinacloudapi.cn
QueryType  : A
TTL        : 600
Section    : Answer
IP4Address : 192.168.0.5

限制公共终结点访问

若要限制公共终结点访问,首先需要禁用对公共终结点的一般访问。 禁用对公共终结点的访问不会影响专用终结点。 禁用公共终结点后,可选择可继续访问它的特定网络或 IP 地址。 通常,大多数针对存储帐户的防火墙策略仅限一个或多个虚拟网络进行网络访问。

禁止对公共终结点的访问

禁止对公共终结点的访问时,仍可通过存储帐户的专用终结点来访问该存储帐户。 否则,对存储帐户的公共终结点发出的有效请求将被拒绝,除非这些请求来自特别指定的源

以下 PowerShell 命令将拒绝发往存储帐户公共终结点的所有流量。 请注意,此命令的 -Bypass 参数设置为 AzureServices。 这会允许受信任的第一方服务(例如 Azure 文件同步)通过公共终结点访问存储帐户。

# This assumes $storageAccount is still defined from the beginning of this of this guide.
$storageAccount | Update-AzStorageAccountNetworkRuleSet `
        -DefaultAction Deny `
        -Bypass AzureServices `
        -WarningAction SilentlyContinue `
        -ErrorAction Stop | `
    Out-Null

仅限从特定的虚拟网络访问公共终结点

如果仅限从特定的虚拟网络访问存储帐户,则会允许从指定的虚拟网络内部对公共终结点发出请求。 为此,可以使用称作“服务终结点”的虚拟网络功能。 在具有或没有专用终结点的情况下都可以使用此功能。

若要仅限特定的虚拟网络使用服务终结点访问存储帐户的公共终结点,首先需要收集有关该存储帐户和虚拟网络的信息。 填写 <storage-account-resource-group><storage-account-name><vnet-resource-group-name><vnet-name><subnet-name> 以收集此信息。

$storageAccountResourceGroupName = "<storage-account-resource-group>"
$storageAccountName = "<storage-account-name>"
$restrictToVirtualNetworkResourceGroupName = "<vnet-resource-group-name>"
$restrictToVirtualNetworkName = "<vnet-name>"
$subnetName = "<subnet-name>"

$storageAccount = Get-AzStorageAccount `
        -ResourceGroupName $storageAccountResourceGroupName `
        -Name $storageAccountName `
        -ErrorAction Stop

$virtualNetwork = Get-AzVirtualNetwork `
        -ResourceGroupName $restrictToVirtualNetworkResourceGroupName `
        -Name $restrictToVirtualNetworkName `
        -ErrorAction Stop

$subnet = $virtualNetwork | `
    Select-Object -ExpandProperty Subnets | `
    Where-Object { $_.Name -eq $subnetName }

if ($null -eq $subnet) {
    Write-Error `
            -Message "Subnet $subnetName not found in virtual network $restrictToVirtualNetworkName." `
            -ErrorAction Stop
}

要使 Azure 网络结构允许来自该虚拟网络的流量进入存储帐户公共终结点,该虚拟网络的子网必须公开 Microsoft.Storage 服务终结点。 以下 PowerShell 命令将 Microsoft.Storage 服务终结点添加到子网(如果其中不存在该服务终结点)。

$serviceEndpoints = $subnet | `
    Select-Object -ExpandProperty ServiceEndpoints | `
    Select-Object -ExpandProperty Service

if ($serviceEndpoints -notcontains "Microsoft.Storage") {
    if ($null -eq $serviceEndpoints) {
        $serviceEndpoints = @("Microsoft.Storage")
    } elseif ($serviceEndpoints -is [string]) {
        $serviceEndpoints = @($serviceEndpoints, "Microsoft.Storage")
    } else {
        $serviceEndpoints += "Microsoft.Storage"
    }

    $virtualNetwork = $virtualNetwork | Set-AzVirtualNetworkSubnetConfig `
            -Name $subnetName `
            -AddressPrefix $subnet.AddressPrefix `
            -ServiceEndpoint $serviceEndpoints `
            -WarningAction SilentlyContinue `
            -ErrorAction Stop | `
        Set-AzVirtualNetwork `
            -ErrorAction Stop
}

限制发往存储帐户的流量的最后一步是创建网络规则并将其添加到存储帐户的网络规则集。

$networkRule = $storageAccount | Add-AzStorageAccountNetworkRule `
    -VirtualNetworkResourceId $subnet.Id `
    -ErrorAction Stop

$storageAccount | Update-AzStorageAccountNetworkRuleSet `
        -DefaultAction Deny `
        -Bypass AzureServices `
        -VirtualNetworkRule $networkRule `
        -WarningAction SilentlyContinue `
        -ErrorAction Stop | `
    Out-Null

另请参阅