安全故障排除

 

适用于:Windows Azure Pack

本主题介绍与 Windows Server 的 Windows Azure Pack 中的安全和身份验证相关的故障排除问题。 可以通过查看本主题中的凭据清单来解决许多问题。 针对以下问题提供了建议:

  • 集成 AD FS 后,重置管理门户以使用 AD

  • 集成 AD FS 后,无法访问租户门户

  • 使用 Get-MgmtSvcToken cmdlet 获取令牌

  • 以编程方式使用租户证书

  • 将自签名证书替换为受信任的证书

  • 解决证书警告

  • 从多个帐户登录到管理门户

  • 查看 SSL/TLS 设置

凭据清单

以下清单提供了为 Windows Azure Pack 及其使用的产品和提供程序配置证书、用户名和密码的最佳做法。

  • 对于测试或非面向 Internet 的组件(例如面向管理员的管理门户或管理员 API),可以使用 Microsoft 证书颁发机构创建自签名证书。

  • 对于面向 Internet 的组件(例如租户的管理门户和租户公共 API),请使用受信任的公共证书颁发机构。

  • 在运行 Service Provider Foundation 的服务器上为 Service Provider Foundation (IIS) 配置 Service Provider Foundation 的应用程序池标识,以便它们使用域用户凭据帐户。 不建议使用网络服务。

  • 在运行 System Center 2012 R2 Virtual Machine Manager 和 Service Provider Foundation 的服务器上配置应用程序池标识,以使用具有 “登录即服务” 权限的同一域帐户。

  • 配置 Service Provider Foundation 以在 IIS 中使用基本身份验证。

  • 将具有管理权限的本地用户帐户配置为运行 Service Provider Foundation 的服务器上的 VMM、管理员、提供程序和使用情况组的成员。 使用此本地用户帐户将 Service Provider Foundation 终结点注册到适用于 Windows Server 的 Windows Azure Pack。

有关详细信息,请参阅博客文章 故障排除 Windows Azure Pack、Service Provider Foundation & Virtual Machine Manager。 有关 Service Provider Foundation Web 服务的概述,请参阅在 Service Provider Foundation 中管理 Web 服务和Connections。 另请参阅 Windows Azure Pack 身份验证概述

集成 AD FS 后,无法访问租户门户

涉及为 Windows Azure Pack 配置Active Directory 联合身份验证服务

问题

配置 AD FS (Active Directory 联合身份验证服务) 后不显示租户登录屏幕,或者无法访问租户的管理门户。

建议

在安装了 Windows Azure Pack 的域中集成 AD FS 后,将绕过登录页直接转到门户。 这是预期的浏览器行为。

如果无法访问租户的管理门户,请使用服务器管理器运行 ADSI Edit,并验证 AD SF 服务器是否具有服务主体名称 (SPN) 。 SPN 应采用 http/myADFSServer 格式。

返回页首

集成 AD FS 后,重置管理门户以使用 AD

涉及为 Windows Azure Pack 配置Active Directory 联合身份验证服务

问题

想要在集成 Active Directory 联合身份验证服务 (AD FS) 后,返回到对管理门户使用 Active Directory (AD) 。

建议

必须重新建立管理员管理门户与Windows 身份验证站点之间的信任关系,就像对 AD FS 所做的那样。 Windows 身份验证站点为端口 30072。 可以使用 Windows PowerShell cmdlet Set-MgmtSvcRelyingPartySettignsSet-MgmtSvcIdentityProviderSettings

使用 Get-MgmtSvcToken cmdlet 获取令牌

涉及Windows Azure Pack for Windows Server Automation with Windows PowerShell

问题

Get-MgmtSvcToken 不会按预期返回令牌。

建议

这可能是 Get-MgmtSvcToken cmdlet 未正确使用 Active Directory 联合身份验证服务 (AD FS) 的问题。 以下脚本将函数 Get-AdfsToken 定义为解决方法。

function Get-AdfsToken([string]$adfsAddress, [PSCredential]$credential)
{
    $clientRealm = 'http://azureservices/AdminSite'
    $allowSelfSignCertificates = $true

    Add-Type -AssemblyName 'System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
    Add-Type -AssemblyName 'System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'

    $identityProviderEndpoint = New-Object -TypeName System.ServiceModel.EndpointAddress -ArgumentList ($adfsAddress + '/adfs/services/trust/13/usernamemixed')
    $identityProviderBinding = New-Object -TypeName System.ServiceModel.WS2007HttpBinding -ArgumentList ([System.ServiceModel.SecurityMode]::TransportWithMessageCredential)
    $identityProviderBinding.Security.Message.EstablishSecurityContext = $false
    $identityProviderBinding.Security.Message.ClientCredentialType = 'UserName'
    $identityProviderBinding.Security.Transport.ClientCredentialType = 'None'

    $trustChannelFactory = New-Object -TypeName System.ServiceModel.Security.WSTrustChannelFactory -ArgumentList $identityProviderBinding, $identityProviderEndpoint
    $trustChannelFactory.TrustVersion = [System.ServiceModel.Security.TrustVersion]::WSTrust13

    if ($allowSelfSignCertificates)
    {
        $certificateAuthentication = New-Object -TypeName System.ServiceModel.Security.X509ServiceCertificateAuthentication
        $certificateAuthentication.CertificateValidationMode = 'None'
        $trustChannelFactory.Credentials.ServiceCertificate.SslCertificateAuthentication = $certificateAuthentication
    }

    $ptr = [System.Runtime.InteropServices.Marshal]::SecureStringToCoTaskMemUnicode($credential.Password)
    $password = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($ptr)
    [System.Runtime.InteropServices.Marshal]::ZeroFreeCoTaskMemUnicode($ptr)

    $trustChannelFactory.Credentials.SupportInteractive = $false
    $trustChannelFactory.Credentials.UserName.UserName = $credential.UserName
    $trustChannelFactory.Credentials.UserName.Password = $password #$credential.Password

    $rst = New-Object -TypeName System.IdentityModel.Protocols.WSTrust.RequestSecurityToken -ArgumentList ([System.IdentityModel.Protocols.WSTrust.RequestTypes]::Issue)
    $rst.AppliesTo = New-Object -TypeName System.IdentityModel.Protocols.WSTrust.EndpointReference -ArgumentList $clientRealm
    $rst.TokenType = 'urn:ietf:params:oauth:token-type:jwt'
    $rst.KeyType = [System.IdentityModel.Protocols.WSTrust.KeyTypes]::Bearer

    $rstr = New-Object -TypeName System.IdentityModel.Protocols.WSTrust.RequestSecurityTokenResponse

    $channel = $trustChannelFactory.CreateChannel()
    $token = $channel.Issue($rst, [ref] $rstr)

    $tokenString = ([System.IdentityModel.Tokens.GenericXmlSecurityToken]$token).TokenXml.InnerText;
    $result = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($tokenString))
    return $result
}

# Fill in values
$adfsAddress = 'https://adfshost'
$username = 'domain\username'
$password = 'password'
$securePassword = ConvertTo-SecureString -String $password -AsPlainText -Force
$credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $username,$securePassword

$token = Get-AdfsToken -adfsAddress $adfsAddress -credential $credential 
$token

返回页首

以编程方式使用租户证书

涉及Service Provider Foundation 开发人员指南

问题

需要创建一个证书并将其上传到租户的管理门户,然后才能以编程方式使用它。

建议

请按以下过程操作:

  1. 创建一个证书, (该证书可以) 自签名。 它应具有 .cer 文件扩展名。

  2. 在租户管理门户的“ 我的帐户 ”页上,单击“ 管理证书”。

  3. 将请求标头中的证书传递给租户公共 API 进行身份验证,如以下示例所示。

    注意

    只能访问此证书分配到的订阅。 无法通过租户公共 API 删除订阅。

    X509Certificate2 mycert3 = new X509Certificate2("C:\\WorkDocs\\Test\\Management Certs\\myCert.cer");
    HttpClient httpClient = new HttpClient();
    var handler = new WebRequestHandler();
    handler.ClientCertificates.Add(mycert3);
    handler.PreAuthenticate = true;
    httpClient = new HttpClient(handler);
    
    string tenantPublicEndpoint = "https://test.fabrikam.com:30006/";
    string subscriptionid = " 7d31eb89-bb1e-4b16-aa3c-993f978b6bc1";
    
    string subscriptionEndpoint = tenantPublicEndpoint + subscriptionid+ "/services/webspaces/defaultwebspace/sites";
    var response = httpClient.GetAsync(subscriptionEndpoint);
    var resultsStr = response.Result.Content.ReadAsStringAsync().Result;
    

返回页首

将自签名证书替换为受信任的证书

涉及管理 Windows Server 的 Windows Azure 包

问题

对测试环境使用自签名证书后,需要将证书替换为从受信任的颁发机构颁发的证书。

建议

在本地计算机的个人存储中安装证书,并将证书映射到 Internet Information Services (IIS) 管理器中的每个网站。 证书应满足以下要求:

  • 来自受信任的证书颁发机构

  • 具有有效的日期范围

  • 提供有效的用法和预期用途声明

  • 提供服务器身份验证

  • 将证书的域名与网站名称匹配

  • 具有 RSA-1024 位加密或更高版本

  • 包括私钥

返回页首

解决证书警告

涉及部署适用于 Windows Server 的 Windows Azure Pack

问题

证书警告与来自受信任颁发机构的证书一起持续存在。

建议

在证书验证期间,某些浏览器不会处理证书中的“颁发机构信息访问”字段。 解决方法是在证书存储中显式安装中间证书。 有关支持此字段的证书颁发机构列表,请参阅 Windows 和 Windows Phone 8 SSL 根证书计划 (成员 CA)

返回页首

查看 SSL/TLS 设置

涉及部署适用于 Windows Server 的 Windows Azure Pack

问题

通信安全性差可能会导致系统事件日志中出现大量 Schannel 错误。

建议

若要提高 Windows Azure Pack 信道的安全性,请考虑更新 SSL/TLS 设置。 在实施这些更改之前,应确保它们不会影响其他应用程序或服务。

可以在运行 Windows Azure Pack 的每台计算机上运行以下脚本,以便进行以下更改:

# PowerShell script to secure TLS/SSL settings.
# Copyright (c) Microsoft Corporation. All rights reserved.
# 20-Jun-2015 Update-ComputerSchannelSettings.ps1

<#
.Synopsis
   Apply HTTP.SYS settings
.NOTES
   Reference: Http.sys registry settings for Windows
   https://support.microsoft.com/en-us/kb/820129
#>
function Set-HttpSysSettings()
{
    Write-Verbose -Message "$($Myinvocation.MyCommand.Name)" -Verbose

    $regPath = "HKLM:\System\CurrentControlSet\Services\HTTP\Parameters"

    # Read original values.
    $maxFieldLength = (Get-ItemProperty -Path $regPath -Name MaxFieldLength -ErrorAction SilentlyContinue).MaxFieldLength
    $maxRequestBytes = (Get-ItemProperty -Path $regPath -Name MaxRequestBytes -ErrorAction SilentlyContinue).MaxRequestBytes
    Write-Verbose -Message "HTTP.SYS settings:`r`n  MaxFieldLength = $maxFieldLength`r`n  MaxRequestBytes = $maxRequestBytes" -Verbose

    # Is update needed?
    if ($maxFieldLength -ne 32KB -or $maxRequestBytes -ne 32KB)
    {
        # Write updated values.
        Set-ItemProperty -Path $regPath -Name MaxFieldLength -Value 32KB
        Set-ItemProperty -Path $regPath -Name MaxRequestBytes -Value 32KB

        # Read updated values.
        $maxFieldLength = (Get-ItemProperty -Path $regPath -Name MaxFieldLength).MaxFieldLength
        $maxRequestBytes = (Get-ItemProperty -Path $regPath -Name MaxRequestBytes).MaxRequestBytes
        Write-Verbose -Message "HTTP.SYS settings (updated):`r`n  MaxFieldLength = $maxFieldLength`r`n  MaxRequestBytes = $maxRequestBytes" -Verbose

        # Changes that are made to the registry will not take effect until you restart the HTTP service.
        Write-Warning -Message "HTTP.SYS settings updated; restarting the HTTP service."
        Restart-Service -Name "http" -Force -Verbose
    }

    return $false # No reboot needed.
}

<#
.Synopsis
   Apply SSL configuration settings (TLS Cipher Suite Ordering)
.NOTES
   Reference: Prioritizing Schannel Cipher Suites
   https://msdn.microsoft.com/en-us/library/windows/desktop/bb870930(v=vs.85).aspx
#>
function Set-SchannelCipherOrder()
{
    Write-Verbose -Message "$($Myinvocation.MyCommand.Name)" -Verbose
    $reboot = $false

    $regPath = "HKLM:\SOFTWARE\Policies\Microsoft\Cryptography\Configuration\SSL\00010002"

    # The ordered suites names need to be specified as a single string (REG_SZ)
    # with each suite separated by commas and with no embedded spaces.
    # The list of cipher suites is limited to 1023 characters.
    $cipherOrder = @(
        'TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384_P384'
        'TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256_P256'
        'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384'
        'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256'
        'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P384'
        'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA_P256'
        'TLS_RSA_WITH_AES_256_GCM_SHA384'
        'TLS_RSA_WITH_AES_128_GCM_SHA256'
        'TLS_RSA_WITH_AES_256_CBC_SHA256'
        'TLS_RSA_WITH_AES_128_CBC_SHA256'
        'TLS_RSA_WITH_AES_256_CBC_SHA'
        'TLS_RSA_WITH_AES_128_CBC_SHA'
    )
    $cipherOrderList = ($cipherOrder -join ',')

    # Read original values.
    $functions = (Get-ItemProperty -Path $regPath -Name Functions -ErrorAction SilentlyContinue).Functions
    Write-Verbose -Message "Schannel Cipher Order:`r`n  Functions = $($functions -split ',' | ConvertTo-Json)" -Verbose

    # Is update needed?
    if ($functions -ne ($cipherOrder -join ','))
    {
        # Write updated values.
        Set-ItemProperty -Path $regPath -Name Functions -Value $cipherOrderList -Force

        # Read updated values.
        $functions = (Get-ItemProperty -Path $regPath -Name Functions -ErrorAction SilentlyContinue).Functions
        Write-Verbose -Message "Schannel Cipher Order (updated):`r`n  Functions = $($functions -split ',' | ConvertTo-Json)" -Verbose

        # It is necessary to restart the computer after modifying this setting for the changes to take effect.
        Write-Warning -Message "Schannel Cipher Order updated; it is necessary to restart the computer."
        $reboot = $true ### TODO: Restart-Computer -Force -Verbose
    }

    return $reboot
}
<#
.Synopsis
   Apply TLS Protocol version configuration
.NOTES
   Reference: How to Disable SSL 3.0 in Azure Websites, Roles, and Virtual Machines
   https://azure.microsoft.com/blog/2014/10/19/how-to-disable-ssl-3-0-in-azure-websites-roles-and-virtual-machines/
#>
function Set-SchannelProtocols()
{
    Write-Verbose -Message "$($Myinvocation.MyCommand.Name)" -Verbose
    $reboot = $false

    $regPath = "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols"
    $protocolSettings = @(
        [PSCustomObject]@{ Path = "$regPath\SSL 2.0\Client"; Name = "Enabled"; Value = 0 }
        [PSCustomObject]@{ Path = "$regPath\SSL 2.0\Server"; Name = "Enabled"; Value = 0 }
        [PSCustomObject]@{ Path = "$regPath\SSL 3.0\Client"; Name = "Enabled"; Value = 0 }
        [PSCustomObject]@{ Path = "$regPath\SSL 3.0\Server"; Name = "Enabled"; Value = 0 }
        [PSCustomObject]@{ Path = "$regPath\TLS 1.0\Client"; Name = "Enabled"; Value = 1 }
        [PSCustomObject]@{ Path = "$regPath\TLS 1.0\Server"; Name = "Enabled"; Value = 1 }
        [PSCustomObject]@{ Path = "$regPath\TLS 1.1\Client"; Name = "Enabled"; Value = 1 }
        [PSCustomObject]@{ Path = "$regPath\TLS 1.1\Server"; Name = "Enabled"; Value = 1 }
        [PSCustomObject]@{ Path = "$regPath\TLS 1.2\Client"; Name = "Enabled"; Value = 1 }
        [PSCustomObject]@{ Path = "$regPath\TLS 1.2\Server"; Name = "Enabled"; Value = 1 }
    )

    # Read original values.
    $currentProtocolSettings = @()
    foreach ($protocolSetting in $protocolSettings)
    {
        $value = (Get-ItemProperty -Path $protocolSetting.Path -Name $protocolSetting.Name -ErrorAction SilentlyContinue).$($protocolSetting.Name)
        $currentProtocolSettings += [PSCustomObject]@{ Path = $protocolSetting.Path; Name = $protocolSetting.Name; Value = $value }
    }
    Write-Verbose -Message "Schannel Protocol Settings: $($currentProtocolSettings | Format-Table -Autosize | Out-String)" -Verbose

    $observed = $currentProtocolSettings | ConvertTo-Json -Compress
    $expected = $protocolSettings | ConvertTo-Json -Compress

    # Is update needed?
    if ($observed -ne $expected)
    {
        # Create registry nodes.
        $protocolPaths = @(
            "$regPath\SSL 2.0"
            "$regPath\SSL 2.0\Client"
            "$regPath\SSL 2.0\Server"
            "$regPath\SSL 3.0"
            "$regPath\SSL 3.0\Client"
            "$regPath\SSL 3.0\Server"
            "$regPath\TLS 1.0"
            "$regPath\TLS 1.0\Client"
            "$regPath\TLS 1.0\Server"
            "$regPath\TLS 1.1"
            "$regPath\TLS 1.1\Client"
            "$regPath\TLS 1.1\Server"
            "$regPath\TLS 1.2"
            "$regPath\TLS 1.2\Client"
            "$regPath\TLS 1.2\Server"
        )
        foreach ($protocolPath in $protocolPaths)
        {
            if (-not (Get-Item -Path $protocolPath -ErrorAction SilentlyContinue))
            {
                New-Item -Path $protocolPath -ItemType Container -Force | Out-Null
            }
        }

        # Write updated values.
        foreach ($protocolSetting in $protocolSettings)
        {
            Set-ItemProperty -Path $protocolSetting.Path -Name $protocolSetting.Name -Value $protocolSetting.Value -Force
        }

        # Read updated values.
        $currentProtocolSettings = @()
        foreach ($protocolSetting in $protocolSettings)
        {
            $value = (Get-ItemProperty -Path $protocolSetting.Path -Name $protocolSetting.Name -ErrorAction SilentlyContinue).$($protocolSetting.Name)
            $currentProtocolSettings += [PSCustomObject]@{ Path = $protocolSetting.Path; Name = $protocolSetting.Name; Value = $value }
        }
        Write-Verbose -Message "Schannel Protocol Settings (updated): $($currentProtocolSettings | Format-Table -Autosize | Out-String)" -Verbose

        # It is necessary to restart the computer after modifying this setting for the changes to take effect.
        Write-Warning -Message "Schannel Protocols updated; it is necessary to restart the computer."
        $reboot = $true ### TODO: Restart-Computer -Force -Verbose
    }

    return $reboot
}

#-------------------------------------------------------------------------------
# Main

$reboot = $false
$reboot += Set-HttpSysSettings
$reboot += Set-SchannelCipherOrder
$reboot += Set-SchannelProtocols
if ($reboot)
{
    Write-Warning -Message "Restart the computer for settings to take effect."
    # TODO: Restart-Computer -Force -Verbose
}

还可以运行 SSL/TLS 验证工具来识别其他需要改进的领域。

返回页首

从多个帐户登录到管理门户

适用于:适用于 Windows Server 自动化的 Windows Azure 包Windows PowerShell

问题

需要能够从多个帐户登录到管理门户。

建议

使用 Add-MgmtSvcAdminUser Windows PowerShell cmdlet 添加其他主体。 如果令牌包含) 安全组信息,则这些主体可以是显式用户或安全组 (。 以下示例添加用户。 (它假定已为 $pwd 变量定义了密码。)

Add-MgmtSvcAdminUser -Server 'mysqlserver' -UserName 'sa' -Password $pwd -Principal 'user7@contoso.com'

返回页首

另请参阅

Windows Azure 包故障排除