IIS 7 上 Web 服务的 ServicePrincipleName 设置

Luk*_*ett 7 iis-7 active-directory

我很困惑。

考虑以下:

  • 具有名为 DOM 的域的 Active Directory 环境
  • 一个带有 NetBIOS 名称 VS1 的 IIS 7 框
  • 为 VS1 提供别名的 DNS 记录为 pineapple.london.uk.corp
  • 作为 DOM\PineappleService 运行的应用程序池
  • 已启用 Windows 身份验证。
  • 客户端使用 HttpWebRequest 调用框上的 XML/JSON ASP.NET 服务。

该服务调用网络上的工作站来收集信息。这适用于我使用以我身份运行的 IIS Express 的开发,因为 IISX 只是一个 .exe

在生产中,服务工作正常,身份验证工作,但调用导致服务(作为 PineappleService 运行)访问网络上的内容的函数失败。

我怀疑是 SPN 注册问题,但我不知道要设置什么 SPN。

最近,我偶然发现了这篇文章,它似乎在其他一些文章面前说fly:

http://blogs.msdn.com/b/webtopics/archive/2009/01/19/service-principal-name-spn-checklist-for-kerberos-authentication-with-iis-7-0.aspx

请注意,它说

SPN 要求与上述相同。与在 IIS 6.0 中不同(我们必须为应用程序池标识添加形式为 http/ 的 SPN),您不必为 Domain1\Username1 添加像 http/ 这样的 SPN。

所以我不知道什么是对的了。不知道是需要注册HTTP SPN还是HOST SPN还是使用DNS别名或者NetBIOS名称,设置在PineappleService账号或者VS1电脑账号上。

我不知道当我尝试一些东西时是否存在缓慢的 AD 复制问题,这意味着我必须在反复试验之间等待一个小时。

现在一切都那么复杂。我作为系统操作员和开发人员工作了 15 年,我感觉到域和工作站以及权利和政策的终结。这一切都太过分了。

谢谢你的帮助。

Luke

Gre*_*kew 2

在开发中完全按照生产中的情况进行配置和测试之前,不应尝试此操作。通过 IIS 和自定义应用程序使用 Windows 身份验证和模拟可能非常复杂。即使它在没有准确反映生产的开发环境的情况下在生产中神奇地工作,如果您必须调查问题,您也会完全迷失方向。

SPN

创建 SPN 时,通常会为 FQDN 和短名称创建 SPN。例子:

setspn.exe -A http/computer  
setspn.exe -A http/computer.domain.com  
Run Code Online (Sandbox Code Playgroud)

建议这些名称与 Windows 2000 之前的名称(netbios 名称)和连接到服务时使用的 dns 名称相匹配。如果这两个名称都不是用于连接到服务的名称,则该名称也应该有一个 SPN。

在不同帐户/计算机上为同一服务/名称注册重复的 SPN 是 Kerberos 委派不起作用的常见原因。Setspn 很乐意让您创建重复的 SPN。Microsoft 已发布修复程序来纠正此行为:

在 Windows 7 或 Windows Server 2008 R2 中运行 setspn 命令和 -a 开关时,会注册重复的 SPN
https://support.microsoft.com/kb/2717045

服务所在的目标计算机需要 SPN。

   HTTP/computername.company.com
   HTTP/computername
Run Code Online (Sandbox Code Playgroud)

值得信赖的授权

将执行模拟的计算机或用户帐户需要指定为“受信任的委派”。如果用户帐户正在执行模拟,则执行模拟的计算机帐户也必须以相同的方式配置为“受信任的委派”。

在 Active Directory 用户和计算机中,单击计算机或用户帐户上的委派选项卡。(除非具有 SPN,否则用户帐户不会显示“委派”选项卡。可能需要将 RPC/用户名等 SPN 分配给用户帐户才能显示“委派”选项卡)。

在委派选项卡上,选择“信任此用户/计算机来委派任何服务(仅限 Kerberos)”以获得无约束委派。

对于约束委派,选择“信任此用户/计算机仅委派指定的服务”。选择“使用任何身份验证协议”。您可以单击“添加”并浏览到公布服务 SPN 的计算机,然后添加它们。请注意,当您运行 setspn.exe -L 域\用户帐户时,这些不会显示为 SPN。

委托模式

您需要确定使用哪种委托模型。这一决定可能是出于安全原因而被迫做出的。

无约束允许计算机或服务帐户冒充任何用户。这是非常强大的,并且被许多组织所避免。

约束委派将模拟活动限制为执行模拟的服务帐户可能连接到的特定目标计算机和服务(HTTP、CIFS 等)。它还具有额外的便利性,即无需帐户凭据或预先存在的 Windows/Kerberos 安全令牌即可模拟任何帐户

多个域

如果 FE/BE 服务器位于不同的域中,则约束委派不起作用。

使用约束委派,执行模拟的帐户/计算机必须与目标资源/服务位于同一域中。该域通常是“资源”域。被模拟的帐户可能位于任何受信任域中,包括其他林中的受信任域。

提升特权

执行模拟的用户帐户必须在运行执行模拟的代码的计算机上拥有 SetTCB 权限(作为操作系统的一部分)。请注意,在 Windows Vista/7/2008 上,SetTCB 权限可能仅由具有高完整性级别的进程持有,因此可能需要将该帐户添加到本地管理员组。

授权用户身份必须是要执行模拟的计算机上本地用户组的成员。

作为操作系统的一部分,可以使用 gpedit.msc 或 gpmc.msc 进行指定。它位于计算机 > Windows 设置 > 安全设置 > 本地策略 > 用户权限分配下。

Kerberos 版本 5 身份验证协议的工作原理
http://technet.microsoft.com/en-us/library/cc772815%28WS.10%29.aspx

  • 如果选择“仅使用 Kerberos”选项,则该帐户将使用约束委派,无需协议转换。
  • 如果选择“使用任何身份验证协议”选项,则该帐户将使用带有协议转换的约束委派。

哇!正确配置所有内容后,您可以将其全部提炼为易于排除故障的简单测试用例。假设您已为 CIFS\fileserver.company.com 创建了 SPN,并希望模拟 anotherUser@trustedDomain.company.com 并访问该服务器上的共享:

// no password required with constrained delegation
using (WindowsIdentity id = new WindowsIdentity("anotherUser@trustedDomain.company.com"))
using (WindowsImpersonationContext wic = id.Impersonate())
{
    // ImpersonationLevel will be "Impersonation" when constrained delegation is setup correctly
    // It will be "Identification" if the account performing impersonation does not have SetTCB privilege
    Debug.WriteLine("ImpersonationLevel: " + id.ImpersonationLevel);
    // Authentication type should be "Kerberos"
    Debug.WriteLine("AuthenticationType: " + id.AuthenticationType);
    Debug.WriteLine("Username: " + WindowsIdentity.GetCurrent().Name);

    Debug.WriteLine("Groups:");
    foreach (IdentityReference identity in id.Groups)
    {
        NTAccount ntaccount = identity.Translate(typeof (NTAccount)) as NTAccount;
        Debug.WriteLine("Account: " + ntaccount.Value + " SID: " + identity.Value);
    }

    // This will fail with access denied if constrained delegation is not setup properly.  
    // On the target server/resource, if it fails it may show an attempt to logon using anonymous
    string[] fileNames = Directory.GetFiles(@"\\fileserver.company.com\ShareName");
    foreach (string fileName in fileNames)
    {
        Console.WriteLine(fileName);
    }
}
Run Code Online (Sandbox Code Playgroud)