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

注意

如果使用 ssh 连接插件与 Kerberos 配合使用,则可以忽略 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 库将对 _kerberos._udp.my.domain.com_kerberos._tcp.my.domain.com 进行 SRV 查找以找到 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)使用不同的 GSSAPI 实现(称为 Heimdal),其作用方式类似于 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

在上面的示例中,我们将 TGT 存储在 krbtgt 服务主体下,并将我们的 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,请在 kinit 命令中添加 -f 标志,或在 krb5.conf 文件的 [libdefaults] 部分设置 forwardable = true 选项。如果您正在使用 psrpwinrm 连接插件从清单中的用户密码检索 TGT,则如果连接插件配置为使用委托,它将自动请求可转发 TGT。

要使连接插件委托凭据,它需要在清单中设置以下主机变量。

# 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 域控制器不同步。

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

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