FreeBSD 使用手册
上一页 | 第14章 　安全 | 下一页

# 14.7 Kerberos5

撰写者 Tillman Hodgson. 原文来自 Mark Murray.

Kerberos 是一组附加的网络系统/协议， 用以让用户通过一台安全服务器提供的服务来验证身份。 包括远程登录、远程复制、在系统间安全地复制文件， 以及其它高危险性的操作， 由于其存在而显著地提高了安全型并且更加可控。

Kerberos 可以理解为一种身份验证代理系统。 它也被描述为一种以受信第三方为主导的身份验证系统。 Kerberos 只提供一种功能 ── 在网络上安全地完成用户的身份验证。 它并不提供授权功能 (也就是说用户能够做什么操作) 或审计功能 (记录用户作了什么操作)。 一旦客户和服务器都使用了 Kerberos 来证明各自的身份之后， 他们还可以加密全部的通讯以保证业务数据的私密性和完整性。

因此， 强烈建议将 Kerberos 同其它提供授权和审计服务的安全手段联用。

接下来的说明可以用来指导如何安装 FreeBSD 所附带的 Kerberos。 不过， 您仍然需要参考相应的联机手册以获得完整的描述。

为了展示 Kerberos 的安装过程， 我们约定：

- DNS 域 (“zone”) 为 example.org。

- Kerberos 领域是 EXAMPLE.ORG。

> 注意: 在安装 Kerberos 时请使用实际的域名即使您只是想在内部网上用一用。 这可以避免 DNS 问题并保证了同其它 Kerberos 之间的互操作性。

## 14.7.1 历史

Kerberos 最早由 MIT 作为解决网络安全问题的一个方案提出。 Kerberos 协议采用了强加密， 因此客户能够在不安全的网络上向服务器 (以及相反地) 验证自己的身份。

Kerberos 是网络验证协议名字， 同时也是用以表达实现了它的程序的形容词。 (例如 Kerberos telnet)。 目前最新的协议版本是 5，在 RFC 1510 中有所描述。

该协议有许多免费的实现， 这些实现涵盖了许多种不同的操作系统。 最初研制 Kerberos 的麻省理工学院 (MIT) 也仍然在继续开发他们的 Kerberos 软件包。 在 US 它被作为一种加密产品使用， 因而历史上曾经受到 US 出口管制。 MIT Kerberos 可以通过 port (`security/krb5`) 来安装和使用。 Heimdal Kerberos 是另一种第 5 版实现， 并且明确地在 US 之外的地区开发， 以避免出口管制 (因此在许多非商业的类 UNIX® 系统中非常常用。 Heimdal Kerberos 软件包可以通过 port (`security/heimdal`) 安装， 最新的 FreeBSD 的最小安装也会包含它。

为使尽可能多的读者从中受益， 这份说明以 FreeBSD 附带的 Heimdal 软件包为准。

## 14.7.2 配置 Heimdal KDC

密钥分发中心 (KDC) 是 Kerberos 提供的集中式验证服务 ── 它是签发 Kerberos tickets 的那台计算机。 KDC 在 Kerberos 领域中的其它机器看来是 “受信的”， 因此必须格外注意其安全性。

需要说明 Kerberos 服务器只需要非常少的计算资源， 尽管如此， 基于安全理由仍然推荐使用独占的机器来扮演 KDC 的角色。

要开始配置 KDC， 首先请确认您的 `/etc/rc.conf` 文件包含了作为一个 KDC 所需的设置 (您可能需要适当地调整路径以适应自己系统的情况)：

    kerberos5_server_enable="YES"
    kadmind5_server_enable="YES"

接下来需要修改 Kerberos 的配置文件， `/etc/krb5.conf`：

    [libdefaults]
        default_realm = EXAMPLE.ORG
    [realms]
        EXAMPLE.ORG = {
            kdc = kerberos.example.org
            admin_server = kerberos.example.org
        }
    [domain_realm]
        .example.org = EXAMPLE.ORG

请注意这个 `/etc/krb5.conf` 文件假定您的 KDC 有一个完整的主机名， 即 `kerberos.example.org`。 如果您的 KDC 主机名与它不同， 则应添加一条 CNAME (别名) 项到 zone 中去。

> 注意: 对于有正确地配置过的 BIND DNS 服务器的大型网络， 上述例子可以精简为：

>     [libdefaults]
>           default_realm = EXAMPLE.ORG

> 将下面的内容加入到 `example.org` zone 数据文件中：

>     _kerberos._udp      IN  SRV     01 00 88 kerberos.example.org.
>     _kerberos._tcp      IN  SRV     01 00 88 kerberos.example.org.
>     _kpasswd._udp       IN  SRV     01 00 464 kerberos.example.org.
>     _kerberos-adm._tcp  IN  SRV     01 00 749 kerberos.example.org.
>     _kerberos           IN  TXT     EXAMPLE.ORG

> 注意: 要让客户机能够找到 Kerberos 服务， 就 必须 首先配置完整或最小配置的 `/etc/krb5.conf` 并且 正确地配置 DNS 服务器。

接下来需要创建 Kerberos 数据库。 这个数据库包括了使用主密码加密的所有实体的密钥。 您并不需要记住这个密码， 它会保存在一个文件 (`/var/heimdal/m-key`) 中。 要创建主密钥， 需要执行 `kstash` 并输入一个口令。

主密钥一旦建立， 您就可以用 `kadmin` 程序的 `-l` 参数 (表示 “local”) 来初始化数据库了。 这个选项让 `kadmin` 直接地修改数据库文件而不是通过 `kadmind` 的网络服务。 这解决了在数据库创建之前连接它的鸡生蛋的问题。 进入 `kadmin` 提示符之后， 用 `init` 命令来创建领域的初始数据库。

最后， 仍然在 `kadmin` 中， 使用 `add` 命令来创建第一个 principal。 暂时使用全部的默认设置， 随后可以在任何时候使用 `modify` 命令来修改这些设置。 另外， 也可以用 `?` 命令来了解可用的选项。

典型的数据库创建过程如下：

    # kstash
    Master key: xxxxxxxx
    Verifying password - Master key: xxxxxxxx

    # kadmin -l
    kadmin> init EXAMPLE.ORG
    Realm max ticket life [unlimited]:
    kadmin> add tillman
    Max ticket life [unlimited]:
    Max renewable life [unlimited]:
    Attributes []:
    Password: xxxxxxxx
    Verifying password - Password: xxxxxxxx

现在是启动 KDC 服务的时候了。 运行 `/etc/rc.d/kerberos start` 以及 `/etc/rc.d/kadmind start` 来启动这些服务。 尽管此时还没有任何正在运行的 Kerberos 服务， 但您仍然可以通过获取并列出您刚刚创建的那个 principal (用户) 的 ticket 来验证 KDC 确实在正常工作， 使用 KDC 本身的功能：

    % kinit tillman
    tillman@EXAMPLE.ORG's Password:

    % klist
    Credentials cache: FILE:/tmp/krb5cc_500
        Principal: tillman@EXAMPLE.ORG

      Issued           Expires          Principal
    Aug 27 15:37:58  Aug 28 01:37:58  krbtgt/EXAMPLE.ORG@EXAMPLE.ORG

完成所需的操作之后， 可以撤消这一 ticket：

    % kdestroy

## 14.7.3 为 Kerberos 启用 Heimdal 服务

首先我们需要一份 Kerberos 配置文件 `/etc/krb5.conf` 的副本。 只需简单地用安全的方式 (使用类似 scp(1) 的网络工具， 或通过软盘) 复制 KDC 上的版本， 并覆盖掉客户机上的对应文件就可以了。

接下来需要一个 `/etc/krb5.keytab` 文件。 这是提供 Kerberos 服务的服务器和工作站的一个主要区别 ── 服务器必须有 `keytab` 文件。 这个文件包括了服务器的主机密钥， 这使得 KDC 得以验证它们的身份。 此文件必须以安全的方式传到服务器上， 因为如果密钥被公之于众， 则安全也就毁于一旦。 也就是说， 通过明文的通道， 例如 FTP 是非常糟糕的想法。

一般来说， 您会希望使用 `kadmin` 程序来把 `keytab` 传到服务器上。 由于也需要使用 `kadmin` 来为主机建立 principal (KDC 一端的 `krb5.keytab`)， 因此这并不复杂。

注意您必须已经获得了一个 ticket 而且这个 ticket 必须许可使用 `kadmind.acl` 中的 `kadmin` 接口。 请参考 Heimdal info 中的 “Remote administration(远程管理)” 一节 (`info heimdal`) 以了解如何设计访问控制表。 如果不希望启用远程的 `kadmin` 操作， 则可以简单地采用安全的方式连接 KDC (通过本机控制台， ssh(1) 或 Kerberos telnet(1)) 并使用 `kadmin -l` 在本地执行管理操作。

安装了 `/etc/krb5.conf` 文件之后， 您就可以使用 Kerberos 上的 `kadmin` 了。 `add --random-key` 命令可以用于添加主机 principal， 而 `ext` 命令则允许导出服务器的主机 principal 到它的 keytab 中。 例如：

    # kadmin
    kadmin> add --random-key host/myserver.example.org
    Max ticket life [unlimited]:
    Max renewable life [unlimited]:
    Attributes []:
    kadmin> ext host/myserver.example.org
    kadmin> exit

注意 `ext` 命令 (这是 “extract” 的简写) 默认会把导出的密钥放到 `/etc/krb5.keytab` 中。

如果您由于没有在 KDC 上运行 `kadmind` (例如基于安全理由) 因而无法远程地使用 `kadmin` 您可以直接在 KDC 上添加主机 principal (`host/myserver.EXAMPLE.ORG`) 随后将其导出到一个临时文件中 (以免覆盖 KDC 上的 `/etc/krb5.keytab`)， 方法是使用下面的命令：

    # kadmin
    kadmin> ext --keytab=/tmp/example.keytab host/myserver.example.org
    kadmin> exit

随后需要把 keytab 复制到服务器上 (例如使用 `scp` 或软盘)。 一定要指定一个不同于默认的 keytab 名字以免覆盖 KDC 上的 keytab。

到现在您的服务器已经可以同 KDC 通讯了 (因为已经配置了 `krb5.conf` 文件)， 而且它还能够证明自己的身份 (由于配置了 `krb5.keytab` 文件)。 现在可以启用一些 Kerberos 服务。 在这个例子中， 我们将在 `/etc/inetd.conf` 中添加下面的行来启用 `telnet` 服务， 随后用 `/etc/rc.d/inetd restart` 重启 inetd(8) 服务来使设置生效：

    telnet    stream  tcp     nowait  root    /usr/libexec/telnetd  telnetd -a user

关键的部分是 `-a` (表示验证) 类型设置为用户 (user)。 请参考 telnetd(8) 联机手册以了解细节。

## 14.7.4 使用 Heimdal 来启用客户端 Kerberos

设置客户机是非常简单的。 在正确配置了 Kerberos 的网络中， 只需要将位于 `/etc/krb5.conf` 的配置文件进行一下设置就可以了。 这一步骤可以简单地通过安全的方式将文件从 KDC 复制到客户机上来完成。

尝试在客户机上执行 `kinit`、 `klist`， 以及 `kdestroy` 来测试获取、 显示并删除 刚刚为 principal 建立的 ticket 是否能够正常进行， 如果能， 则用其它的 Kerberos 应用程序来连接启用了 Kerberos 的服务。 如果应用程序不能正常工作而获取 ticket 正常， 则通常是服务本身， 而非客户机或 KDC 有问题。

在测试类似 `telnet` 的应用程序时， 应考虑使用抓包程序 (例如 tcpdump(1)) 来确认您的口令没有以明文方式传输。 尝试使用 `telnet` 的 `-x` 参数， 它将加密整个数据流 (类似 `ssh`)。

许多非核心的 Kerberos 客户应用程序也是默认安装的。 在 Hemidal 的 “最小” 安装理念下， `telnet` 是唯一一个采用了 Kerberos 的服务。

Heimdal port 则提供了一些默认不安装的客户应用程序， 例如启用了 Kerberos 版本的 `ftp`、 `rsh`、 `rcp`、 `rlogin` 以及一些更不常用的程序。 MIT port 也包括了一整套 Kerberos 客户应用程序。

## 14.7.5 用户配置文件： `.k5login` 和 `.k5users`

在某个领域中的用户往往都有自己的 Kerberos principal (例如 `tillman@EXAMPLE.ORG`) 并映射到本机用户帐户 (例如本机上名为 `tillman` 的帐户)。 客户端应用程序， 如 `telnet` 通常并不需要用户名或 principal。

不过, 有时您可能会需要赋予某些没有匹配 Kerberos principal 的人使用本地用户帐户的权限。 例如 `tillman@EXAMPLE.ORG` 可能需要访问本地的 `webdevelopers` 用户帐号。 其它 principal 可能也会需要访问这个本地帐号。

用户 home 目录中的 `.k5login` 和 `.k5users` 这两个文件可以配合 `.hosts` 和 `.rhosts` 来有效地解决这个问题。 例如， 如果 `.k5login` 中有如下内容：

    tillman@example.org
    jdoe@example.org

并放到了本地用户 `webdevelopers` 的 home 目录中， 则列出的两个 principals 都可以使用那个帐号， 而无须共享口令。

建议您在开始实施之前首先阅读这些命令的联机帮助。 特别地， `ksu` 的联机手册包括了 `.k5users` 的相关内容。

## 14.7.6 Kerberos 提示、技巧和故障排除

- 当使用 Heimdal 或 MIT Kerberos ports 时， 需要确认 `PATH` 环境变量把 Kerberos 客户应用列在系统自带的版本之前。

- 同一领域内的所有计算机的时间设置是否同步？ 如果不是的话， 则身份验证可能会失败。 第 29.10 节 描述了如何使用 NTP 来同步时钟。

- MIT 和 Heimdal 能够很好地互操作。 一个例外是 `kadmin`， 因为这个协议没有被标准化。

- 如果您改变了主机名， 您还需要修改您的 `host/` principal 并更新 keytab。 这一规律也适用于类似 Apache 的 `www/mod_auth_kerb` 所使用的 `www/` principal 这样的特殊 keytab 项。

- 您的领域中的每一台主机必须在 DNS (或至少在 `/etc/hosts` 中) 可以解析 (同时包括正向和反向)。 CNAME 能够正常使用， 但必须有正确的对应 A 和 PTR 记录。 此时给出的错误信息可能很让人困惑： “`Kerberos5 refuses authentication because Read req failed: Key table entry not found`”。

- 某些作为客户使用您的 KDC 的操作系统可能没有将 `ksu` 设置为 setuid `root` 的权限。 这意味着 `ksu` 将不能够正常工作， 从安全角度说这是一个不错的主意， 但可能令人烦恼。 这类问题并不是 KDC 的错误。

- 使用 MIT Kerberos 时， 如果希望允许一个 principal 拥有超过默认的十小时有效期的 ticket 则必须使用 `kadmin` 中的 `modify_principal` 来修改 principal 本身以及 `krbtgt` 的 maxlife(最大有效期)。 此后， principal 可以使用 `kinit` 的 `-l` 参数来请求一个有更长有效期的 ticket。

- > 注意: 如果在 KDC 上运行了听包程序， 并在工作站上执行 `kinit`， 您可能会注意到 TGT 是在 `kinit` 一开始执行的时候就发出了的 ── 甚至在您输入口令之前！ 关于这个现象的解释是 Kerberos 服务器可以无限制地收发 TGT (Ticket Granting Ticket) 给任何未经授权的请求； 但是， 每一个 TGT 都是使用用户的口令派生出来的密钥进行加密的。 因此， 当用户输入口令时它并不会发送给 KDC， 而是直接用于解密 `kinit` 所拿到的 TGT。 如果解密过程得到了一个包含合法的时间戳的有效 ticket， 则说明用户的 Kerberos 凭据有效。 这些凭据包含了一个会话密钥用以在随后建立 Kerberos 服务器的加密通讯， 传递由服务器自己的私钥加密的实际的 ticket-granting ticket。 这个第二层加密对于用户来说是看不到的， 但它使得 Kerberos 服务器能够验证每一个 TGT 的真实性。

- 如果需要有效期更长的 ticket (例如一周) 而且您使用 OpenSSH 连接保存您的 ticket 的机器， 请确认 `sshd_config` 中的 Kerberos `TicketCleanup` 被设置为 `no` 否则在注销时会自动删除所有的 ticket。

- 切记主机的 principals 的 ticket 有效期一定要比用户的长。 如果您的用户 principal 的有效期是一周， 而所连接的主机的有效期是九个小时， 则缓存的主机 principal 将先行过期， 结果是 ticket 缓存无法正常工作。

- 当配置 `krb5.dict` 文件来防止使用特定的简单口令 (`kadmind` 的联机手册中简要介绍了它)， 请切记只有指定了口令策略的 principals 才会使用它们。 `krb5.dict` 文件的格式很简单： 每个串占一行。 创建一个到 `/usr/share/dict/words` 的符号连接会很有用。

## 14.7.7 与 MIT port 的区别

MIT 和 Heimdal 主要的区别在于 `kadmin` 程序使用不同 (尽管等价) 的命令和协议。 如果您的 KDC 是 MIT 的， 则其影响是不能使用 Heimdal 的 `kadmin` 程序来远程管理 KDC (或相反)。

完成同样工作的命令可能会有些许的不同。 推荐按照 MIT Kerberos 的网站 (http://web.mit.edu/Kerberos/www/) 上的说明来操作。 请小心关于路径的问题， MIT port 会默认安装到 `/usr/local/`， 您因此可能会执行 “普通的” 系统应用程序而非 MIT, 如果您的 `PATH` 环境变量把 把系统目录放在前面的话。

> 注意: 如果使用 FreeBSD 提供的 MIT `security/krb5` port， 一定要仔细阅读 port 所安装的 `/usr/local/share/doc/krb5/README.FreeBSD`， 如果您想知道为什么通过 `telnetd` 和 `klogind` 登录时会出现一些诡异的现象的话。 最重要地， “incorrect permissions on cache file(缓存文件权限不正确)” 行为需要使用 `login.krb5` 来进行验证， 才能够正确地修改转发凭据的属主。

除此之外， 还应修改 `rc.conf` 并加入下列配置：

    kerberos5_server="/usr/local/sbin/krb5kdc"
    kadmind5_server="/usr/local/sbin/kadmind"
    kerberos5_server_enable="YES"
    kadmind5_server_enable="YES"

这样做的原因是， MIT kerberos 会将可执行文件装到 `/usr/local` 之下。

## 14.7.8 缓解 Kerberos 的限制

### 14.7.8.1 Kerberos 是一种 all-or-nothing 方式

在网络上启用的每个服务都必须进行修改以便让其能够配合 Kerberos 工作 (否则就只能使用其它方法来保护它们不受网络攻击的侵害)， 如果不是这样， 则用户的凭据就有可能被窃取并再次使用。 一个例子是对所有的远程 shell (例如通过 `rsh` 和 `telnet`) 启用了 Kerberos 但没有将使用明文验证的 POP3 邮件服务器 Kerberos化。

### 14.7.8.2 Kerberos 是为单用户工作站设计的

在多用户环境中 Kerberos 的安全性会被削弱。 这是因为它把 ticket 保存到 `/tmp` 目录中， 而这个目录可以被任何用户读取。 如果有用户与其它人同时共享一台计算机 (也就是 multi-user)， 则这个用户的 ticket 就可能被其它用户窃取 (复制)。

可以通过使用 `-c` 文件名 这样的命令行选项， 或者(推荐的)改变 `KRB5CCNAME` 环境变量来避免这个问题， 但很少有人这么做。原则上， 将 ticket 保存到用户的 home 目录并简单地设置权限就能够缓解这个问题。

### 14.7.8.3 KDC 会成为单点崩溃故障点

根据设计， KDC 必须是安全的， 因为主密码数据库保存在它上面。 决不应该在 KDC上面运行其它服务， 而且还应确保它的物理安全。 由于 Kerberos 使用同一个密钥 (传说中的那个 “主” 密钥) 来加密所有的密码， 而将这个文件保存在 KDC， 因此其安全尤为重要

不过， 主密钥的泄露并没有想象中的那么可怕。 主密钥只用来加密 Kerberos 数据库以及产生随机数发生器的种子。 只要 KDC 是安全的， 即使攻击者拿到了主密钥也做不了什么。

另外， 如果 KDC 不可用 (例如由于拒绝服务攻击或网络故障) 则网络服务将由于验证服务无法进行而不能使用， 从而导致更大范围的拒绝服务攻击。 通过部署多个 KDC (一个主服务器， 配合一个或多个从服务器) 并采用经过仔细设计和实现的备用验证方式可以避免这种问题 (PAM 是一个不错的选择)。

### 14.7.8.4 Kerberos 的不足

Kerberos 允许用户、主机和服务之间进行相互认证。 但它并没有提供机制来向用户、主机或服务验证 KDC。 这意味着种过木马的程序，例如 `kinit` 有可能记录用户所有的用户名和密码。 尽管如此， 可以用类似 `security/tripwire` 这样的文件系统完整性检查工具来避免此类情况的发生。

## 14.7.9 相关资源和其它资料

- The Kerberos FAQ

- Designing an Authentication System: a Dialog in Four Scenes

- RFC 1510, The Kerberos Network Authentication Service (V5)

- MIT Kerberos home page

- Heimdal Kerberos home page

上一页 | 起始页 | 下一页
TCP Wrappers | 上一级 | OpenSSL

本文档和其它文档可从这里下载：ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.

如果对于FreeBSD有问题，请先阅读文档，如不能解决再联系<questions@FreeBSD.org>.
关于本文档的问题请发信联系 <doc@FreeBSD.org>.