配置虚拟子网的加密

适用于:Windows Server 2022、Windows Server 2019、Windows Server 2016,Azure Stack HCI 版本 21H2 和 20H2

虚拟网络加密允许对在标记为“启用加密”的子网内相互通信的 VM 之间的虚拟网络流量进行加密。 它还利用虚拟子网上的数据报传输层安全性 (DTLS) 来加密数据包。 DTLS 可以防止能够访问物理网络的任何人进行窃听、篡改和伪造。

虚拟网络加密需要以下各项:

  • 在每个已启用 SDN 的 Hyper-V 主机上安装的加密证书。
  • 网络控制器中引用该证书指纹的凭据对象。
  • 每个虚拟网络(包含需要加密的子网)上的配置。

在子网上启用加密后,除了可能进行的任何应用程序级加密外,该子网中的所有网络流量也会自动加密。 跨子网的流量,即使标记为加密,也会自动以未加密的方式发送。 任何跨越虚拟网络边界的流量也会以未加密的方式发送。

注意

与同一子网上的另一个 VM 通信时,无论是当前连接还是稍后连接,流量都会自动加密。

提示

如果必须将应用程序限制为仅在加密子网上通信,则可以仅使用访问控制列表 (ACL) 以允许在当前子网内进行通信。 有关详细信息,请参阅使用访问控制列表 (ACL) 管理数据中心网络流量

第 1 步:创建加密证书

每个主机都必须安装加密证书。 可以对所有租户使用同一证书,也可以为每位租户生成唯一的证书。

  1. 生成证书

    $subjectName = "EncryptedVirtualNetworks"
    $cryptographicProviderName = "Microsoft Base Cryptographic Provider v1.0";
    [int] $privateKeyLength = 1024;
    $sslServerOidString = "1.3.6.1.5.5.7.3.1";
    $sslClientOidString = "1.3.6.1.5.5.7.3.2";
    [int] $validityPeriodInYear = 5;
    
    $name = new-object -com "X509Enrollment.CX500DistinguishedName.1"
    $name.Encode("CN=" + $SubjectName, 0)
    
    #Generate Key
    $key = new-object -com "X509Enrollment.CX509PrivateKey.1"
    $key.ProviderName = $cryptographicProviderName
    $key.KeySpec = 1 #X509KeySpec.XCN_AT_KEYEXCHANGE
    $key.Length = $privateKeyLength
    $key.MachineContext = 1
    $key.ExportPolicy = 0x2 #X509PrivateKeyExportFlags.XCN_NCRYPT_ALLOW_EXPORT_FLAG
    $key.Create()
    
    #Configure Eku
    $serverauthoid = new-object -com "X509Enrollment.CObjectId.1"
    $serverauthoid.InitializeFromValue($sslServerOidString)
    $clientauthoid = new-object -com "X509Enrollment.CObjectId.1"
    $clientauthoid.InitializeFromValue($sslClientOidString)
    $ekuoids = new-object -com "X509Enrollment.CObjectIds.1"
    $ekuoids.add($serverauthoid)
    $ekuoids.add($clientauthoid)
    $ekuext = new-object -com "X509Enrollment.CX509ExtensionEnhancedKeyUsage.1"
    $ekuext.InitializeEncode($ekuoids)
    
    # Set the hash algorithm to sha512 instead of the default sha1
    $hashAlgorithmObject = New-Object -ComObject X509Enrollment.CObjectId
    $hashAlgorithmObject.InitializeFromAlgorithmName( $ObjectIdGroupId.XCN_CRYPT_HASH_ALG_OID_GROUP_ID, $ObjectIdPublicKeyFlags.XCN_CRYPT_OID_INFO_PUBKEY_ANY, $AlgorithmFlags.AlgorithmFlagsNone, "SHA512")
    
    
    #Request Certificate
    $cert = new-object -com "X509Enrollment.CX509CertificateRequestCertificate.1"
    
    $cert.InitializeFromPrivateKey(2, $key, "")
    $cert.Subject = $name
    $cert.Issuer = $cert.Subject
    $cert.NotBefore = (get-date).ToUniversalTime()
    $cert.NotAfter = $cert.NotBefore.AddYears($validityPeriodInYear);
    $cert.X509Extensions.Add($ekuext)
    $cert.HashAlgorithm = $hashAlgorithmObject
    $cert.Encode()
    
    $enrollment = new-object -com "X509Enrollment.CX509Enrollment.1"
    $enrollment.InitializeFromRequest($cert)
    $certdata = $enrollment.CreateRequest(0)
    $enrollment.InstallResponse(2, $certdata, 0, "")
    

    运行脚本后,“我的存储”中将显示新证书:

    PS D:\> dir cert:\\localmachine\my
    PSParentPath: Microsoft.PowerShell.Security\Certificate::localmachine\my
    
    Thumbprint                                Subject
    ----------                                -------
    84857CBBE7A1C851A80AE22391EB2C39BF820CE7  CN=MyNetwork
    5EFF2CE51EACA82408572A56AE1A9BCC7E0843C6  CN=EncryptedVirtualNetworks
    
  2. 将证书导出为文件。

    你需要证书的两个副本,一个包含私钥,一个没有私钥。

    $subjectName = "EncryptedVirtualNetworks"
    $cert = Get-ChildItem cert:\localmachine\my | ? {$_.Subject -eq "CN=$subjectName"}
    [System.io.file]::WriteAllBytes("c:\$subjectName.pfx", $cert.Export("PFX", "secret"))
    Export-Certificate -Type CERT -FilePath "c:\$subjectName.cer" -cert $cert
    
  3. 在每个 Hyper-V 主机上安装证书

    PS C:\> dir c:\$subjectname.*
    
    Directory: C:\
    
    Mode                LastWriteTime         Length Name
    ----                -------------         ------ ----
    -a----        9/22/2017   4:54 PM            543 EncryptedVirtualNetworks.cer
    -a----        9/22/2017   4:54 PM           1706 EncryptedVirtualNetworks.pfx
    
  4. 在 Hyper-V 主机上安装

    $server = "Server01"
    
    $subjectname = "EncryptedVirtualNetworks"
    copy c:\$SubjectName.* \\$server\c$
    invoke-command -computername $server -ArgumentList $subjectname,"secret" {
        param (
            [string] $SubjectName,
            [string] $Secret
        )
        $certFullPath = "c:\$SubjectName.cer"
    
        # create a representation of the certificate file
        $certificate = new-object System.Security.Cryptography.X509Certificates.X509Certificate2
        $certificate.import($certFullPath)
    
        # import into the store
        $store = new-object System.Security.Cryptography.X509Certificates.X509Store("Root", "LocalMachine")
        $store.open("MaxAllowed")
        $store.add($certificate)
        $store.close()
    
        $certFullPath = "c:\$SubjectName.pfx"
        $certificate = new-object System.Security.Cryptography.X509Certificates.X509Certificate2
        $certificate.import($certFullPath, $Secret, "MachineKeySet,PersistKeySet")
    
        # import into the store
        $store = new-object System.Security.Cryptography.X509Certificates.X509Store("My", "LocalMachine")
        $store.open("MaxAllowed")
        $store.add($certificate)
        $store.close()
    
        # Important: Remove the certificate files when finished
        remove-item C:\$SubjectName.cer
        remove-item C:\$SubjectName.pfx
    }
    
  5. 对环境中每个服务器都重复上述步骤。

    对每个服务器都重复操作后,应在每个 Hyper-V 主机的根和“我的存储”中都安装一个证书。

  6. 验证证书的安装。

    通过检查“我的存储”和根证书存储的内容来验证证书:

    PS C:\> enter-pssession Server1
    
    [Server1]: PS C:\> get-childitem cert://localmachine/my,cert://localmachine/root | ? {$_.Subject -eq "CN=EncryptedVirtualNetworks"}
    
    PSParentPath: Microsoft.PowerShell.Security\Certificate::localmachine\my
    
    Thumbprint                                Subject
    ----------                                -------
    5EFF2CE51EACA82408572A56AE1A9BCC7E0843C6  CN=EncryptedVirtualNetworks
    
    PSParentPath: Microsoft.PowerShell.Security\Certificate::localmachine\root
    
    Thumbprint                                Subject
    ----------                                -------
    5EFF2CE51EACA82408572A56AE1A9BCC7E0843C6  CN=EncryptedVirtualNetworks
    
  7. 记下指纹。

    必须记下指纹,因为需要指纹才能在网络控制器中创建证书凭据对象。

第 2 步:创建证书凭据

在连接到网络控制器的每个 Hyper-V 主机上安装证书后,现在必须配置网络控制器才能使用证书。 为此,必须创建一个凭据对象,其中包含安装了网络控制器 PowerShell 模块的计算机中的证书指纹。

///Replace with the thumbprint from your certificate
$thumbprint = "5EFF2CE51EACA82408572A56AE1A9BCC7E0843C6"

$uri = "https://nc.contoso.com"

///Replace with your Network Controller URI
Import-module networkcontroller

$credproperties = new-object Microsoft.Windows.NetworkController.CredentialProperties
$credproperties.Type = "X509Certificate"
$credproperties.Value = $thumbprint
New-networkcontrollercredential -connectionuri $uri -resourceid "EncryptedNetworkCertificate" -properties $credproperties -force

提示

可以对每个加密的虚拟网络重复使用此凭据,也可以为每位租户部署和使用唯一的证书。

第 3 步:为加密配置虚拟网络

此步骤假定你已创建名为“My Network”的虚拟网络,并且至少包含一个虚拟子网。 有关创建虚拟网络的信息,请参阅创建、删除或更新租户虚拟网络

注意

与同一子网上的另一个 VM 通信时,无论是当前连接还是稍后连接,流量都会自动加密。

  1. 从网络控制器检索虚拟网络和凭据对象:

    $vnet = Get-NetworkControllerVirtualNetwork -ConnectionUri $uri -ResourceId "MyNetwork"
    $certcred = Get-NetworkControllerCredential -ConnectionUri $uri -ResourceId "EncryptedNetworkCertificate"
    
  2. 添加对证书凭据的引用,并在单个子网上启用加密:

    $vnet.properties.EncryptionCredential = $certcred
    
    # Replace the Subnets index with the value corresponding to the subnet you want encrypted.
    # Repeat for each subnet where encryption is needed
    $vnet.properties.Subnets[0].properties.EncryptionEnabled = $true
    
  3. 将更新的虚拟网络对象放入网络控制器:

    New-NetworkControllerVirtualNetwork -ConnectionUri $uri -ResourceId $vnet.ResourceId -Properties $vnet.Properties -force
    

祝贺!* 完成这些步骤后,即告完成