正如引言中提到的,以 root 身份运行 BIND 并非明智之举。因此,在我们开始之前,让我们为 BIND 创建一个单独的用户。请注意,您绝不应该为此目的使用像 nobody
这样的通用用户。然而,一些发行版,例如 SuSE 和 Linux Mandrake,已经开始提供特定的用户(通常称为 named
);如果您愿意,您可以简单地调整此用户以用于我们的目的。
这需要在 /etc/passwd
中添加类似以下的一行
named:x:200:200:Nameserver:/chroot/named:/bin/false
并在 /etc/group
中添加类似这样的一行
named:x:200:
这将为 BIND 创建一个名为 named
的用户和组。请确保 UID 和 GID(在本例中均为 200)在您的系统上是唯一的。shell 设置为 /bin/false
,因为此用户永远不需要登录。
现在,我们必须设置目录结构,这将用于 BIND 将要生存的 chroot jail 环境中。这可以是您文件系统上的任何位置;真正偏执的人甚至可能想将其放在单独的卷上。我将假设您将使用 /chroot/named
。让我们从创建以下目录结构开始
/chroot
+-- named
+-- dev
+-- etc
| +-- namedb
| +-- slave
+-- var
+-- run
如果您使用 GNU mkdir
(例如在 Linux 系统上),您可以像这样创建此目录结构
# mkdir -p /chroot/named
# cd /chroot/named
# mkdir -p dev etc/namedb/slave var/run
假设您已经完成了 BIND 的常规安装并正在使用它,您将已经拥有现有的 named.conf
和区域文件。这些文件现在必须移动(或复制,为了安全起见)到 chroot jail 中,以便 BIND 可以访问它们。named.conf
放在 /chroot/named/etc
中,区域文件可以放在 /chroot/named/etc/namedb
中。例如
# cp -p /etc/named.conf /chroot/named/etc/
# cp -a /var/named/* /chroot/named/etc/namedb/
BIND 通常需要写入 namedb
目录,但为了加强安全性,我们将不允许它这样做。如果您的名称服务器充当任何区域的辅助服务器,它将需要更新这些区域文件,这意味着我们必须将它们存储在一个单独的目录中,BIND 对该目录具有写入权限。
# chown -R named:named /chroot/named/etc/namedb/slave
请记住,您必须将您拥有的任何辅助区域移动到此目录中,并相应地更新您的 named.conf
。
BIND 也需要写入 /var/run
目录,以将其 pid 文件和统计信息放在那里,所以让我们允许它这样做
# chown named:named /chroot/named/var/run
一旦 BIND 在 chroot jail 中运行,它将完全无法访问 jail 之外的文件。然而,它需要访问一些关键文件,尽管不像 BIND 8 那样多。
BIND 在其 jail 中需要的一个文件是好用的 /dev/null
。请注意,创建此设备节点所需的确切命令可能因系统而异;请检查您的 /dev/MAKEDEV
脚本以确保。一些系统可能还需要 /dev/zero
,可以类似地创建它。据报告,BIND 9.2.0 候选版本现在也需要 /dev/random
。对于大多数 Linux 系统,我们可以使用以下命令
# mknod /chroot/named/dev/null c 1 3
# mknod /chroot/named/dev/random c 1 8
# chmod 666 /chroot/named/dev/{null,random}
对于 FreeBSD 4.3,这是
# mknod /chroot/named/dev/null c 2 2
# mknod /chroot/named/dev/random c 2 3
# chmod 666 /chroot/named/dev/{null,random}
您还需要 jail 内 /etc
目录中的另一个文件。您必须将 /etc/localtime
(在某些系统上,有时称为 /usr/lib/zoneinfo/localtime
)复制到那里,以便 BIND 使用正确的时间记录日志。以下命令将处理此事
# cp /etc/localtime /chroot/named/etc/
与传统的囚犯不同,BIND 不能只是将日志条目乱写在墙上 :-)。通常,BIND 通过 syslogd
,系统日志守护程序记录日志。但是,这种类型的日志记录是通过将日志条目发送到特殊套接字 /dev/log
来执行的。由于它在 jail 之外,BIND 无法再使用它。幸运的是,有几种选择可以解决这个问题。
此困境的理想解决方案需要一个相对较新版本的 syslogd
,它支持 OpenBSD 引入的 -a
开关。查看您的 syslogd(8)
的手册页,看看您是否有这样的版本。
如果您有,您只需在启动 syslogd
时将开关 ``-a /chroot/named/dev/log
'' 添加到命令行即可。在使用完整 SysV-init 的系统(包括大多数 Linux 发行版)上,这通常在文件 /etc/rc.d/init.d/syslog
中完成。例如,在我的 Red Hat Linux 系统上,我更改了行
daemon syslogd -m 0
为
daemon syslogd -m 0 -a /chroot/named/dev/log
有趣的是,截至 Red Hat 7.2,Red Hat 显然使此过程更加容易。现在有一个名为 /etc/sysconfig/syslog
的文件,可以在其中定义 syslogd 的额外参数。
在 Caldera OpenLinux 系统上,他们使用名为 ssd
的守护程序启动器,它从 /etc/sysconfig/daemons/syslog
读取配置。您只需修改选项行,使其看起来像这样
OPTIONS_SYSLOGD="-m 0 -a /chroot/named/dev/log"
类似地,在 SuSE 系统上,我被告知添加此开关的最佳位置是在 /etc/rc.config
文件中。更改行
SYSLOGD_PARAMS=""
以读取
SYSLOGD_PARAMS="-a /chroot/named/dev/log"
应该可以解决问题。最后但并非最不重要,对于 FreeBSD 4.3,您显然只需编辑 rc.conf
文件并在其中放入以下内容
syslogd_flags="-s -l /chroot/named/dev/log"
-s
是出于安全原因,并且是默认设置的一部分。-l
是一个本地路径,用于放置另一个日志记录节点。一旦您弄清楚如何在您的系统上进行此更改,只需重新启动 syslogd
,方法是杀死它并再次启动它(使用额外的参数),或者使用 SysV-init 脚本为您执行此操作
# /etc/rc.d/init.d/syslog stop
# /etc/rc.d/init.d/syslog start
重新启动后,您应该在 /chroot/named/dev
中看到一个名为 log
的“文件”,它看起来像这样
srw-rw-rw- 1 root root 0 Mar 13 20:58 log
如果您有较旧的 syslogd
,那么您必须找到另一种进行日志记录的方法。有一些程序,例如 holelogd
,旨在通过充当“代理”并接受来自 chrooted BIND 的日志条目并将它们传递到常规 /dev/log
套接字来提供帮助。
或者,您可以简单地配置 BIND 以记录到文件而不是通过 syslog。如果您选择走这条路线,请参阅 BIND 文档了解更多详情。
首先,随意限制对整个 /chroot
目录的访问,仅限 root
用户。当然,并非所有人都可能愿意这样做,特别是如果您在该树中安装了其他不喜欢它的软件。
# chown root /chroot
# chmod 700 /chroot
您也可以安全地限制对 /chroot/named
的访问,仅限 named
用户。
# chown named:named /chroot/named
# chmod 700 /chroot/named
为了进一步加强,在 Linux 系统上,我们可以使用 ext2 文件系统上的 chattr
工具使一些文件和目录不可变。
# cd /chroot/named
# chattr +i etc etc/localtime var
等效地,在 FreeBSD 4.3 上,如果您希望使内容不可变,则需要查看 chflags
。例如,以下命令应将 /chroot/named/etc
目录中的所有内容更改为不可变
# chflags schg /chroot/named/etc/*(*).
对 dev
目录执行此操作也很好,但不幸的是,这将阻止 syslogd
创建其 dev/log
套接字。您也可以选择在 jail 中的其他文件上设置不可变位,例如您的主区域文件,如果它们预计不会更改。