Kerberos 身份验证

Kerberos 身份验证是 Windows 环境中用于身份验证的现代方法。它允许客户端和服务器验证彼此的身份,并支持 AES 等现代加密方法。

安装 Kerberos

Kerberos 通过 GSSAPI 库提供,该库是系统软件包的一部分。某些发行版默认安装 Kerberos 软件包,但其他发行版可能需要手动安装。

要在基于 RHEL/Fedora 的系统上安装 Kerberos 库

$ sudo dnf install krb5-devel krb5-libs krb5-workstation python3-devel

对于基于 Debian/Ubuntu 的系统

$ sudo apt-get install krb5-user libkrb5-dev python3-dev

对于基于 Arch Linux 的系统

$ sudo pacman -S krb5

对于基于 FreeBSD 的系统

$ sudo pkg install heimdal

注意

如果将 Kerberos 与 ssh 连接插件一起使用,则可以忽略 python3-devel / python3-dev 软件包。只有在使用基于 WinRM 的连接并使用 Kerberos 身份验证时才需要它们。

安装后,将可以使用 kinitklistkrb5-config 软件包。您可以使用以下命令对其进行测试

$ krb5-config --version

Kerberos 5 release 1.21.3

psrpwinrm 连接插件需要额外的 Python 库才能进行 Kerberos 身份验证。如果将 Kerberos 与 ssh 连接一起使用,则可以跳过以下步骤。

如果您为 Ansible 选择 pipx 安装说明,则可以通过运行以下命令来安装这些要求

pipx inject "pypsrp[kerberos]<=1.0.0"  # for psrp
pipx inject "pywinrm[kerberos]>=0.4.0"  # for winrm

或者,如果您选择了 pip 安装说明

pip3 install "pypsrp[kerberos]<=1.0.0"  # for psrp
pip3 install "pywinrm[kerberos]>=0.4.0"  # for winrm

配置主机 Kerberos

安装依赖项后,需要配置 Kerberos,以便它可以与域通信。大多数 Kerberos 实现都可以使用 DNS 或通过在 /etc/krb5.conf 文件中手动配置来查找域。有关可以在 /etc/krb5.conf 文件中设置的内容的详细信息,请参阅 krb5.conf 以了解更多详细信息。一个使用 DNS 查找 KDC 的简单 krb5.conf 文件是

[libdefaults]
    # Not required but helpful if the realm cannot be determined from
    # the hostname
    default_realm = MY.DOMAIN.COM

    # Enabled KDC lookups from DNS SRV records
    dns_lookup_kdc = true

使用以上配置,当为服务器 server.my.domain.com 请求 Kerberos 票证时,Kerberos 库将执行 SRV 查找 _kerberos._udp.my.domain.com_kerberos._tcp.my.domain.com 来查找 KDC。如果您希望手动设置 KDC 领域,可以使用以下配置

[libdefaults]
    default_realm = MY.DOMAIN.COM
    dns_lookup_kdc = false

[realms]
    MY.DOMAIN.COM = {
        kdc = domain-controller1.my.domain.com
        kdc = domain-controller2.my.domain.com
    }

[domain_realm]
    .my.domain.com = MY.DOMAIN.COM
    my.domain.com = MY.DOMAIN.COM

使用此配置,任何带有 DNS 后缀 .my.domain.commy.domain.com 本身的票证请求都将发送到 KDC domain-controller1.my.domain.com,并回退到 domain-controller2.my.domain.com

有关 Kerberos 库如何尝试查找 KDC 的更多信息,请参阅 MIT Kerberos 文档

注意

本节中的信息假设您正在使用 MIT Kerberos 实现,这通常是大多数 Linux 发行版上的默认实现。某些平台(如 FreeBSD 或 macOS)使用另一种名为 Heimdal 的 GSSAPI 实现,其行为方式与 MIT Kerberos 类似,但某些行为可能有所不同。

验证 Kerberos 配置

要验证 Kerberos 是否正常工作,您可以使用 kinit 命令来获取域中用户的票证。以下命令将为域 MY.DOMAIN.COM 中的用户 username 请求票证

如果密码正确,该命令将返回,不输出任何内容。要验证是否已获得票证,您可以使用 klist 命令

> klist
Ticket cache: KCM:1000
Default principal: [email protected]

Valid starting     Expires            Service principal
29/08/24 13:54:51  29/08/24 23:54:51  krbtgt/[email protected]
        renew until 05/09/24 13:54:48

如果成功,则验证 Kerberos 配置正确,并且用户可以从 KDC 获取票证授予票证 ( TGT)。如果 kinit 无法找到请求领域的 KDC,请通过确保 DNS 可以使用 SRV 记录定位 KDC 或 KDC 在 krb5.conf 中手动映射来验证您的 Kerberos 配置。

在基于 MIT Kerberos 的系统上,您可以使用 kvno 命令来验证您是否能够检索特定服务的服务票证。例如,如果您使用基于 WinRM 的连接使用 server.my.domain.com 进行身份验证,则可以使用以下命令来验证您的 TGT 是否能够获取目标服务器的服务票证

$ kvno http/server.my.domain.com
http/[email protected]: kvno = 2

还可以使用 klist 命令来验证票证是否存储在 Kerberos 缓存中

$ klist
Ticket cache: KCM:1000
Default principal: [email protected]

Valid starting     Expires            Service principal
29/08/24 13:54:51  29/08/24 23:54:51  krbtgt/[email protected]
        renew until 05/09/24 13:54:48
29/08/24 13:55:30  29/08/24 23:55:30  http/[email protected]
        renew until 05/09/24 13:55:30

在上面的示例中,我们在 krbtgt 服务主体下存储了 TGT,并在其自己的服务主体下存储了 http/server.my.domain.com

kdestroy 命令可用于删除票证缓存。

票证管理

为了使 Kerberos 身份验证能够与 Ansible 一起工作,必须存在用户的 Kerberos TGT,以便 Ansible 可以为目标服务器请求服务票证。某些连接插件(如 ssh )要求 TGT 已经存在,并且 Ansible 控制进程可以访问。其他连接插件(如 psrpwinrm)如果用户的密码在清单中提供,则可以自动获取用户的 TGT。

要手动检索用户的 TGT,请使用用户的用户名和域运行 kinit 命令,如 验证 Kerberos 配置 中所示。当 Ansible 中的连接插件请求 Kerberos 身份验证时,将自动使用此 TGT。

如果您正在使用 psrpwinrm 连接插件,并且在清单中提供了用户的密码,则连接插件将自动获取用户的 TGT。这是通过使用用户的用户名和密码运行 kinit 命令来完成的。TGT 将存储在临时凭据缓存中,并将用于任务。

委派

Kerberos 委派允许凭据遍历多个跃点。当您需要对服务器进行身份验证,然后让该服务器代表您对另一台服务器进行身份验证时,这非常有用。要启用委派,您必须

  • 使用 kinit 获取票证时,请求一个可转发的 TGT

  • 请求连接插件允许委派到服务器

  • AD 用户未标记为敏感,不能被委派,并且不是 Protected Users 组的成员

  • 根据 krb5.conf 的配置,目标服务器可能需要通过其 AD 对象委派设置允许非约束委派

要请求可转发的 TGT,请将 -f 标志添加到 kinit 命令,或者在 krb5.conf 文件的 [libdefaults] 部分设置 forwardable = true 选项。 如果您使用 psrpwinrm 连接插件从 inventory 中用户的密码检索 TGT,如果连接插件配置为使用委派,它将自动请求一个可转发的 TGT。

要让连接插件委派凭据,它需要在 inventory 中设置以下主机变量

# psrp
ansible_psrp_negotiate_delegate: true

# winrm
ansible_winrm_kerberos_delegation: true

# ssh
ansible_ssh_common_args: -o GSSAPIDelegateCredentials=yes

注意

也可以在 ~/.ssh/config 文件中设置 GSSAPIDelegateCredentials yes,以允许所有 SSH 连接进行委派。

要验证是否允许用户委派其凭据,您可以在同一域中的 Windows 主机上运行以下 PowerShell 脚本

Function Test-IsDelegatable {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [string]
        $UserName
    )

    $NOT_DELEGATED = 0x00100000

    $searcher = [ADSISearcher]"(&(objectClass=user)(objectCategory=person)(sAMAccountName=$UserName))"
    $res = $searcher.FindOne()
    if (-not $res) {
        Write-Error -Message "Failed to find user '$UserName'"
    }
    else {
        $uac = $res.Properties.useraccountcontrol[0]
        $memberOf = @($res.Properties.memberof)

        $isSensitive = [bool]($uac -band $NOT_DELEGATED)
        $isProtectedUser = [bool]($memberOf -like 'CN=Protected Users,*').Count

        -not ($isSensitive -or $isProtectedUser)
    }
}

Test-IsDelegatable -UserName username

较新版本的 MIT Kerberos 在 krb5.conf 文件的 [libdefaults] 部分中添加了一个配置选项 enforce_ok_as_delegate。 如果此选项设置为 true,则只有在目标服务器帐户允许非约束委派的情况下,委派才会起作用。 要检查或设置 Windows 计算机主机上的非约束委派,您可以使用以下 PowerShell 脚本

# Check if the server allows unconstrained delegation
(Get-ADComputer -Identity WINHOST -Properties TrustedForDelegation).TrustedForDelegation

# Enable unconstrained delegation
Set-ADComputer -Identity WINHOST -TrustedForDelegation $true

要验证委派是否正常工作,您可以使用 Windows 节点上的 klist.exe 命令来验证票证是否已转发。 输出应显示票证服务器为 krbtgt/MY.DOMAIN.COM @ MY.CDOMAIN.COM,并且票证标志包含 forwarded

$ ansible WINHOST -m ansible.windows.win_command -a klist.exe

WINHOST | CHANGED | rc=0 >>

Current LogonId is 0:0x82b6977

Cached Tickets: (1)

#0>     Client: username @ MY.DOMAIN.COM
        Server: krbtgt/MY.DOMAIN.COM @ MY.DOMAIN.COM
        KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
        Ticket Flags 0x60a10000 -> forwardable forwarded renewable pre_authent name_canonicalize
        Start Time: 8/30/2024 14:15:18 (local)
        End Time:   8/31/2024 0:12:49 (local)
        Renew Time: 9/6/2024 14:12:49 (local)
        Session Key Type: AES-256-CTS-HMAC-SHA1-96
        Cache Flags: 0x1 -> PRIMARY
        Kdc Called:

如果出现任何问题,klist.exe 的输出将不会有 forwarded 标志,并且服务器将是目标服务器主体,而不是 krbtgt

$ ansible WINHOST -m ansible.windows.win_command -a klist.exe

WINHOST | CHANGED | rc=0 >>

Current LogonId is 0:0x82c312c

Cached Tickets: (1)

#0>     Client: username @ MY.DOMAIN.COM
        Server: http/winhost.my.domain.com @ MY.DOMAIN.COM
        KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
        Ticket Flags 0x40a10000 -> forwardable renewable pre_authent name_canonicalize
        Start Time: 8/30/2024 14:16:24 (local)
        End Time:   8/31/2024 0:16:12 (local)
        Renew Time: 0
        Session Key Type: AES-256-CTS-HMAC-SHA1-96
        Cache Flags: 0x8 -> ASC
        Kdc Called:

Kerberos 故障排除

Kerberos 依赖于正确配置的环境才能工作。 导致 Kerberos 身份验证失败的一些常见问题是

  • 为 Windows 主机设置的主机名是别名或 IP 地址

  • Ansible 控制节点上的时间与 AD 域控制器未同步

  • KDC realm 在 krb5.conf 文件中未正确设置或无法通过 DNS 解析

如果使用 MIT Kerberos 实现,您可以设置环境变量 KRB5_TRACE=/dev/stdout 以获取有关 Kerberos 库正在执行的操作的更多详细信息。 这对于调试 Kerberos 库的问题(例如 KDC 查找行为、时间同步问题和服务器名称查找失败)非常有用。