Kerberos 认证

Kerberos 身份验证是 Windows 环境中用于身份验证的一种现代方法。他允许客户端和服务器相互验证对方身份,并支持 AES 等现代加密方法。

安装 Kerberos

Kerberos 是通过作为系统软件包一部分的一个 GSSAPI 库提供的。一些发行版会默认安装 Kerberos 的那些软件包,而其他发行版则可能需要手动安装。

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

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

在基于 Debian/Ubuntu 的系统上:

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

在基于 ArchLinux 的系统上:

sudo pacman -S krb5

在基于 FreeBSD 的系统上:

sudo pkg install heimdal

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

安装好后,即可使用 kinitklistkrb5-config 包即可用。咱们可使用下面的命令测试他们:

$ krb5-config --version                                                                                                ✔  4s 
Kerberos 5 release 1.21.3

psrpwinrm 两个连接插件需要额外的 Python 库,以使用 Kerberos 验证。若在 ssh 连接下使用 Kerberos,则可以跳过以下步骤。

若咱们选择了 pipx 安装 Ansible 的那些指令,则可以通过运行以下命令来安装这些需求:

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

译注:在使用 pyenv 时,运行以下命令。

python -m pip install "pypsrp[kerberos]"
python -m pip install "pywinrm[kerberos]"

配置主机 Kerberos

一旦这些依赖项安装好,Kerberos 就需要加以配置,以便他能与某个域进行通信。大多数 Kerberos 实现都可使用 DNS,或通过 /etc/krb5.conf 文件中的手动配置,找到某个域。有关在 /etc/krb5.conf 文件中可设置的内容,请参阅 krb5.conf 了解更多详情。使用 DNS 查找 KDC 1 的一个简单 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

译注:KDC,key distribution center,密钥分发中心。

在上面的配置下,当请求服务器 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 本身的票据请求,都将发送到 domain-controller1.my.domain.com 这个 KDC,并可回退到 domain-controller2.my.domain.com

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

注意:本小节中的信息,假定咱们使用的是 MIT 的 Kerberos 实现,而这通常是大多数 Linux 发行版的默认设置。像是 FreeBSD 或 macOS 等平台,使用了名为 Heimdal 的别的 GSSAPI 实现,其作用方式与 MIT Kerberos 类似,但某些行为可能有所不同。

验证 Kerberos 配置

要验证 Kerberos 是否正常工作,咱们可使用 kinit 命令获取域中某名用户的票据。以下命令将请求域 XFOSS.NET 中用户 hector.peng 的一个票据:

$ kinit hector.peng@XFOSS.NET
Password for hector.peng@XFOSS.NET:

若密码正确,命令将不返回任何输出。要验证是否已获得该票据,咱们可使用 klist 命令:

$ klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: hector.peng@XFOSS.NET

Valid starting       Expires              Service principal
2025-03-07T19:01:10  2025-03-08T19:01:10  krbtgt/XFOSS.NET@XFOSS.NET

如果取得票据成功,那么这就验证了 Kerberos 的配置是正确的,同时该用户可从该 KDC 获取到一张票据授予票据 (Ticket Granting Ticket, TGT)。而如果 kinit 无法找到所请求域的 KDC,就要通过确保 DNS 可以通过使用 SRV 记录定位到 KDC,或在 krb5.conf 中 KDC 已被手动映射,验证咱们的 Kerberos 配置。

译注:使用 kadminsudo kadmin.local)的子命令 list_principals,可列出 KDC 上已添加用户、主机及服务 principals。

$ sudo kadmin.local
kadmin.local:  list_principals
K/M@XFOSS.NET
hector.peng@XFOSS.NET
host/almalinux-61.xfoss.net@XFOSS.NET
host/kdc.xfoss.net@XFOSS.NET
https/win10-133.xfoss.net@XFOSS.NET
https/win2k19-151.xfoss.net@XFOSS.NET
kadmin/admin@XFOSS.NET
kadmin/changepw@XFOSS.NET
krbtgt/XFOSS.NET@XFOSS.NET
root/admin@XFOSS.NET

在基于 MIT Kerberos 的系统上,咱们可使用 kvno 命令,验证是否能获取到某个特定服务的服务票据。例如,若咱们使用基于 WinRM 的连接,验证 server.my.domain.com 的身份,则可使用以下命令,验证咱们的 TGT 是否能获取到目标服务器的服务票据:

$ kvno https/win10-133.xfoss.net
https/win10-133.xfoss.net@XFOSS.NET: kvno = 2

译注:要首先添加服务 principal 到 KDC。

sudo kadmin.local
addprinc -randkey https/win10-133.xfoss.net
ktadd https/win10-133.xfoss.net

参考:How to configure Kerberos service principals

klist 命令也可用于验证票据是否已存储在 Kerberos 的缓存中:

$ klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: hector.peng@XFOSS.NET

Valid starting       Expires              Service principal
2025-03-07T19:01:10  2025-03-08T19:01:10  krbtgt/XFOSS.NET@XFOSS.NET
        Flags: FI
2025-03-07T19:23:39  2025-03-08T19:01:10  https/win10-133.xfoss.net@XFOSS.NET
        Flags: FT

在面的示例中,我们有着存储在 krbtgt 服务 principal 下的 TGT,以及存储在其自己服务 principal 下的 http/win10-133.xfoss.net 票据。

kdestroy 命令可用于移除票据缓存。

票据管理

要在 Ansible 下使用 Kerberos 验证,用户的 Kerberos TGT 必须存在,这样 Ansible 才能请求目标服务器的服务票据。像 ssh 的一些连接插件就要求 TGT 存在,并能被 Ansible 的控制进程访问。而像是 psrpwinrm 等其他连接插件,则会在仓库中提供了用户的密码时,可自动获取用户的 TGT。

要手动获取某名用户的 TGT,请按照 验证 Kerberos 配置 中所示的那样,使用该用户的用户名和域,运行 kinit 命令。当 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

译注:上述 PowerShell 脚本需要 RSAT 并启用 “AD 与 LDS 管理工具”。

参考:The term 'get-ADComputer' is not recognized as the name of a cmdlet

要验证凭据委派是否有效,咱们可在 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 这个标志,同时服务器将是目标服务器 principal,而不是 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 查找行为、时间同步问题,及服务器名称查找失败等,非常有用。

附录(译注)

Windows AD 采用的是 Kerberos 认证。在创建 AD 域过程中,DC 服务器也是 KDC 服务器,同时会在 DNS 中建立 KDC 的 SRV 记录条目。将 Windows 主机加入 AD 域的过程,就会在 KDC 上为该主机添加主机 principal。而创建域用户的过程,就会在 KDC 上添加用户 principal。

参考:

(End)

Last change: 2025-03-08, commit: 06f2806

小额打赏,赞助 xfoss.com 长存......

微信 | 支付宝

若这里内容有帮助到你,请选择上述方式向 xfoss.com 捐赠。