CentOS7-服务器部署秘籍-全-

CentOS7 服务器部署秘籍(全)

原文:annas-archive.org/md5/96c584d287a854ac38a448aada4a6b4c

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

在过去的十多年里,CentOS 项目通过重新品牌化和重新编译 Red Hat Enterprise Linux 源代码,为社区提供了一个免费的企业级操作系统。由于 CentOS 用户几乎完全依赖社区提供支持,因此当 Packt 联系我撰写关于该项目最新版本 CentOS 7 的书时,我非常愿意参与。我们选择的配方涵盖了从入门到管理许多常见 Web 服务的广泛主题,希望所有技能水平的管理员都能找到有趣的内容。

然而,写一本书是一项巨大的工作。因此,我要感谢 Packt 的工作人员、我的家人和朋友们的支持。狗需要遛弯,家庭事务需要参加,工作场所也会有突发事件。如果没有身边人的理解和鼓励,以及编辑团队的帮助,你就无法看到这本书。

本书内容

本书中提供的配方旨在通过提供逐步指导和讨论,使即使是最复杂的配置任务也变得简单。以下是你可以期待从每一章中获得的内容的简要概述。

第一章,CentOS 入门,包含了使用图形化、基于文本和 Kick-start 方法安装 CentOS 的配方。还讨论了如何为在 Docker 和 Amazon Web Services 上运行的项目设置 CentOS 平台。

第二章,网络配置,包含帮助你完成常见网络任务的配方,例如如何设置静态 IP 地址、为单个网络接口分配多个地址、使用相同地址绑定多个接口,以及如何使用 FirewallD 和 iptables 配置系统防火墙。它还提供了配置网络服务(如 DHCP、NFS 和 Samba)的配方。

第三章,用户和权限管理,展示了如何通过强制执行密码限制、调整新创建文件和目录的默认权限以及使用 sudo 避免传播 root 密码来增强系统的安全性。还讨论了如何与 SELinux 配合使用。

第四章,软件安装管理,提供了专注于软件仓库和安装软件的配方。你将学习如何注册 EPEL 和 Remi 仓库,如何优先选择软件包的安装源,以及如何自动更新软件。你还将学习如何从源代码编译和安装软件。

第五章,管理文件系统与存储,介绍了如何设置和使用 RAID 和 LVM 的操作步骤。这些服务利用系统的存储来保持可用性,增加可靠性,并保护数据免受硬盘故障的影响。

第六章,允许远程访问,旨在帮助你以安全的方式为 CentOS 系统提供远程访问。其操作指南涉及使用 SSH,配置 chroot 监狱,以及通过加密的 SSH 隧道进行 VNC 连接。

第七章,与数据库工作,汇集了提供必要步骤的操作指南,帮助你入门 MySQL、MongoDB 和 OpenLDAP 等数据库服务。你还将学习如何为这些服务提供备份和冗余。

第八章,管理域名与 DNS,带你进入 DNS 的世界。操作指南展示了如何设置一个解析 DNS 服务器,以减少由于域名查找引起的延迟,以及如何使用权威 DNS 服务器管理自己的域名。

第九章,管理电子邮件,将帮助你设置自己的邮件服务器。内容涵盖配置 Postfix 提供 SMTP 服务,配置 Dovecot 提供 IMAP 和 POP3 服务,并使用 TLS 对这些服务进行加密保护。你还将看到如何设置 SpamAssassin 来减少未经请求的大宗电子邮件。

第十章,管理 Web 服务器,包含了配置 Apache 来提供 Web 内容的操作指南。你将学习如何设置基于名称的虚拟主机,如何通过 HTTPS 提供服务器页面,以及如何进行 URL 重写。还将讨论如何设置 NGINX 作为负载均衡器。

第十一章,防范威胁,包含了帮助保护你在 CentOS 服务器上投资内容的操作指南。内容涉及日志记录、威胁监控、病毒和 Rootkit,以及网络备份。

第十二章,虚拟化,展示了如何将 CentOS 作为主机操作系统,为一个或多个虚拟化客户端提供服务。这使得你能够通过在同一物理系统上运行多个操作系统,更好地利用硬件资源。

本书所需内容

要跟随本书中的操作指南,首先,你需要一台能够运行 CentOS 7 的系统。最低要求(以及最大能力)已在 Red Hat Enterprise Linux 知识库中记录,网址为 access.redhat.com/articles/rhel-limits。简而言之,你需要一台具备以下条件的系统:

  • x86_64 处理器(RHEL/CentOS 7 不支持 x86)

  • 1 GB 内存

  • 8 GB 磁盘容量

除了安装 CentOS 的系统外,你还需要一份 CentOS 安装介质和一个正常工作的网络连接。你可以直接从www.centos.org/download/下载,或者使用 BitTorrent。

本书适用对象

本书适合具备基本 Unix/Linux 功能经验的 Linux 专业人士,可能曾经设置过服务器,想要提升自己在管理各种服务方面的知识。

部分

本书中,你会找到一些经常出现的标题(准备工作如何操作…原理介绍…更多内容…参见)。

为了提供明确的配方完成指导,我们使用以下这些部分:

准备工作

本节告诉你在配方中应期待什么,并描述了设置所需的任何软件或前期设置。

如何操作…

本节包含执行配方所需的步骤。

原理介绍…

本节通常包含对上一节内容的详细解释。

更多内容…

本节包含有关配方的附加信息,旨在使读者更全面地了解配方。

参见

本节提供有用的链接,帮助你获取配方中的其他相关信息。

约定

本书中,你将看到多种文本样式,用于区分不同类型的信息。以下是这些样式的一些示例及其含义的解释。

文本中的代码词汇、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟网址、用户输入和 Twitter 账号将按如下方式显示:“仓库的配置文件位于/etc/yum.repos.d目录下。”

代码块设置如下:

    [sshd]
    enabled=true
    bantime=86400
    maxretry=5

所有命令行输入或输出如下所示:

 firewall-cmd --zone=public --permanent --add-service=dns

新术语重要词汇以粗体显示。屏幕上显示的词汇,例如在菜单或对话框中,出现在文本中如下:“选择你希望的语言并点击继续。”

注意

警告或重要提示会以这种框体形式显示。

提示

提示和技巧以这种形式出现。

读者反馈

我们始终欢迎读者反馈。让我们知道你对这本书的看法——你喜欢或不喜欢的地方。读者反馈对我们非常重要,因为它帮助我们开发出你能真正受益的书籍。

若要向我们发送一般反馈,只需通过电子邮件 feedback@packtpub.com 联系我们,并在邮件主题中提及书名。

如果你在某个领域有专长,并且有兴趣为书籍写作或贡献内容,请参阅我们的作者指南:www.packtpub.com/authors

客户支持

现在你已经成为一本 Packt 书籍的骄傲拥有者,我们有许多帮助你从购买中获得最大收益的资源。

勘误

尽管我们已经尽最大努力确保内容的准确性,但错误还是会发生。如果你在我们的书中发现错误——可能是文本或代码中的错误——我们将非常感激你向我们报告。这样,你不仅能帮助其他读者避免困扰,还能帮助我们改进该书的后续版本。如果你发现任何勘误,请通过访问 www.packtpub.com/submit-errata 提交,选择你的书籍,点击 勘误提交表单 链接,填写勘误的详细信息。一旦勘误得到确认,你的提交将被接受,勘误将上传至我们的网站或添加到该书的勘误列表中。

要查看之前提交的勘误,请访问 www.packtpub.com/books/content/support,并在搜索框中输入书名。所需的信息将在 勘误 部分显示。

盗版

互联网版权材料的盗版问题在所有媒体中持续存在。在 Packt,我们非常重视保护我们的版权和许可证。如果你在互联网上遇到任何形式的非法复制品,请立即提供相关地址或网站名称,以便我们采取措施解决此问题。

如有盗版材料的疑虑,请通过 copyright@packtpub.com 与我们联系,并提供相关链接。

我们感谢你帮助保护我们的作者和我们为你带来有价值内容的能力。

问题

如果你在本书的任何部分遇到问题,可以通过 questions@packtpub.com 联系我们,我们将尽力解决问题。

第一章:CentOS 入门

本章包含以下教程:

  • 在图形模式下使用 Anaconda 安装 CentOS

  • 在文本模式下使用 Anaconda 安装 CentOS

  • 使用 Kickstart 协调多次安装

  • 使用 Amazon Web Services 的 EC2 运行云镜像

  • 从 Docker Registry 安装容器镜像

  • 安装 GNOME 桌面

  • 安装 KDE Plasma 桌面

介绍

本章的教程重点介绍了使用各种安装方法启动和运行 CentOS。你将学习如何通过 Anaconda 进行交互式图形安装和基于文本的安装,并通过 Kickstart 执行无人值守安装。你还将看到如何在云端通过 Amazon Web Services 运行 CentOS,或在 Docker 容器镜像中运行 CentOS。本书中的大多数教程都在命令提示符下进行,但有些教程需要图形桌面,因此我们将最后介绍如何安装 GNOME 和 KDE Plasma 桌面环境。

在图形模式下使用 Anaconda 安装 CentOS

在本教程中,你将学习如何使用图形安装程序 Anaconda 安装 CentOS。这是 CentOS 最常用的安装方式,尽管也有其他方法(其中一些将在后续的教程中讨论)。这种方法也是最简单的安装方式,尤其适合设置单台服务器的部署。

准备工作

本教程假设你已经有了一份 CentOS 7 安装介质的副本。如果没有,访问www.centos.org并下载最小的 ISO 镜像。你还需要将镜像刻录成物理光盘。刻录 ISO 镜像到光盘的说明可以在www.centos.org/docs/5/html/CD_burning_howto.html找到。

提示

如果你的系统没有光驱且其 BIOS 支持从 USB 设备启动,你也可以将 ISO 镜像写入 USB 闪存。

如何操作...

按照以下步骤使用图形安装程序 Anaconda 安装 CentOS:

  1. 将安装光盘插入系统的光驱中(或将 USB 闪存插入 USB 端口)并重新启动。系统应该会启动到 CentOS 7 安装菜单:如何操作...

    安装程序从安装菜单启动

    注意

    如果系统没有启动到安装菜单,则可能是驱动器未被配置为启动设备。验证和调整配置的具体步骤因 BIOS 厂商而异,但通常在系统启动时按下Esc, F1, F2Delete键可以进入 BIOS 设置。然后,你需要找到启动设备列表,并更改设备搜索启动记录的顺序。

  2. 使用箭头键确保Install CentOS 7选项被高亮显示,然后按Enter键。

  3. WELCOME TO CENTOS 7 屏幕确认了安装过程中使用的语言。选择你希望使用的语言,然后点击Continue如何操作...

    你可以在安装过程中更改所使用的语言。

  4. 下一屏是一个按类别组织安装选项的菜单。我们首先配置网络—点击网络和主机名,位于系统类别下:

    注意

    如果你的系统没有鼠标,你可以使用Tab键在输入框之间切换,使用方向键选择条目,按Enter键选择或激活输入。

    如何操作...

    安装总结屏幕将安装选项组织成类别

  5. 主机名字段中输入系统的主机名。然后,选择系统的主要网络接口,并将右侧的开关切换到开启以启用它。完成后,点击完成按钮返回安装总结菜单:如何操作...

    网络和主机名屏幕让我们配置系统的网络接口

  6. 点击日期和时间,位于本地化类别下。

  7. 通过选择你的区域和城市或点击地图上的位置来设置时区。然后,点击完成以返回安装总结菜单:如何操作...

    日期和时间屏幕让我们配置系统的时区

  8. 如果你知道系统在网络中的用途,并且需要更多的功能而不仅仅是最小化安装,请点击软件选择,位于软件类别下。选择环境和任何附加组件,以安装所需的软件包。完成后,点击完成如何操作...

    软件选择屏幕让我们安装基于目的的软件

    注意

    软件可以通过yum轻松安装,因此如果你在 CentOS 已经运行后需要安装额外的软件,别担心。软件选择部分仅为方便而设。

  9. 点击安装目标,位于系统类别下。

  10. 本地标准磁盘区域中点击合适的磁盘以设置安装目标。如果磁盘不可启动,或者如果选择了多个磁盘,请点击屏幕底部的完整磁盘摘要和引导加载器...链接,打开已选择磁盘窗口。然后,选择你想作为启动设备的磁盘,点击设置为启动设备按钮,再点击关闭。完成后,点击完成如何操作...

    安装目标屏幕允许我们设置 CentOS 安装的磁盘

  11. 点击开始安装按钮以启动安装过程。

  12. 点击根密码。在输入框中输入并确认你想要用于系统根账户的密码。输入完这些信息后,点击完成

    注意

    如果你指定的密码太弱,你需要按两次完成按钮才能返回配置屏幕。如果你需要帮助来创建强密码,请访问www.howtogeek.com/195430/how-to-create-a-strong-password-and-remember-it/

    如何操作...

    ROOT 密码设置屏幕允许我们设置 root 账户的密码。

  13. 点击创建用户。在输入框中,提供你的姓名、用户名和所需的密码。再次,在输入完成后按完成如何操作...

    创建用户屏幕让我们创建一个无权限的用户账户。

  14. 安装完成后,点击完成配置按钮。Anaconda 将完成系统配置,按钮的标签将更改为重启

  15. 从驱动器中移除 CentOS 安装介质,然后重启系统。

它是如何工作的...

在图形模式下使用 Anaconda 安装 CentOS 后,你现在应该已经有了一个基本的 CentOS 7 系统。这个过程始于我们从安装光盘启动系统并在安装菜单中选择安装 CentOS 7。安装程序的内核被加载到内存中,Anaconda 在图形模式下启动。

网络与主机名屏幕显示了可用网络接口的列表和一些基本信息,例如网卡的 MAC 地址和传输速率。默认情况下,启用接口时会配置为使用 DHCP 获取 IP 地址。(静态 IP 地址的配置将在后续的教程中讲解。)

系统的时区在本地化屏幕上设置。当启用 NTP 时,日期和时间字段会被禁用,因为这些值将由 NTP 服务设置。系统时钟的时间可能会出现漂移,尤其是在虚拟机上运行时,因此允许 NTP 来管理系统时间是个不错的主意,以确保时间准确。如果日期和时间字段未由 NTP 设置,确保网络时间开关已设置为开启。你可以通过点击带齿轮图标的按钮来指定一个 NTP 服务器。

安装目标屏幕让我们为 CentOS 设置安装目标,并指定系统驱动器的分区方式。如果你有特殊需求,可以选择配置分区,但在本教程中,我让 Anaconda 自动分区驱动器。

当 Anaconda 正在安装 CentOS 和你可能请求的其他软件包时,它会显示配置屏幕。此屏幕让你有机会为系统的管理员账户 (root) 设置密码,并创建一个普通用户账户。你应仅在必要时使用 root 账户登录;日常工作中应使用普通账户。Anaconda 通过配置系统的引导记录和创建用户账户来完成安装。

系统重启后,Grub 启动加载器提示符出现,使用箭头键选择启动配置。系统还会显示一个计时器,因此如果不按任何键,系统将使用默认配置启动。

另见

有关安装 CentOS 7 的更多信息,请参阅 RHEL 7 安装指南(access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Installation_Guide)。

使用 Anaconda 在文本模式下安装 CentOS

接下来,你将学习如何使用 Anaconda 在文本模式下安装 CentOS。建议你图形化安装 CentOS,因为图形模式更易于使用,且提供更多功能。然而,当系统资源不足以以图形模式运行安装程序时,例如显示适配器能力有限或内存不足时,图形模式可能不可用。

准备工作

本教程假设你已有 CentOS 7 安装介质的副本。如果没有,请访问 www.centos.org 下载 ISO 镜像,并将镜像刻录到光盘上。

如何操作...

按照以下步骤执行基于文本的 CentOS 安装:

  1. 将安装光盘插入系统的光驱(或将 USB 闪存驱动器插入 USB 端口),然后重新启动系统。系统应该会启动到 CentOS 7 安装菜单。

  2. 使用箭头键,确保安装 CentOS 7选项被高亮显示,然后按Tab键。安装程序内核的启动命令会出现在屏幕底部。

  3. 在参数列表末尾添加 text 并按 Enter 键。Anaconda 将以文本模式启动:

           vmzlinuz initrd=initrd.img inst.stage2=hd:LABEL=CentOS 
           \x207\x20x86_64 rd.live.check quiet text 
    
    

    注意

    如果系统内存小于 768 MB,Anaconda 将自动以文本模式启动。

  4. 安装菜单按类别展示安装选项。输入 2 并按 Enter 键选择时区设置:如何操作...

    基于文本的安装菜单按类别展示安装选项

  5. 时区设置菜单显示一个地区列表。输入所需选项对应的编号。

  6. 系统会显示所选地区的可用时区列表(如果列表较长,可以通过按 Enter 键翻页)。输入所需时区对应的编号。

  7. 如果你知道系统的用途,并且需要比最小安装更多的功能,输入3选择软件选择。在这里,你可以选择适合该用途的软件包组。完成后,输入c继续返回到安装菜单。

  8. 输入5选择网络设置

  9. 输入1设置系统的主机名。输入所需的名称并按Enter键。

  10. 输入数字配置系统的主要网络接口。然后,输入7标记重启后自动连接,并输入8标记在安装程序中应用配置。输入c返回到网络设置菜单,再输入c返回到安装菜单:如何操作...

    网络设置菜单让我们配置系统的网络接口。

  11. 输入6选择安装目标

  12. 如果目标驱动器尚未标记,请输入驱动器的编号。然后,输入c继续。以下截图显示了自动分区选项菜单:如何操作...

    安装目标菜单让我们设置安装目标,而自动分区选项菜单让我们指定磁盘的使用方式。

  13. 输入所需分区的编号(默认是使用所有空间),然后输入c继续。

  14. 选择所需的分区方案(默认是LVM),然后输入c返回到安装菜单。

  15. 输入8选择创建用户

  16. 输入1标记创建用户选项。输入23分别为账户设置用户名。输入4标记使用密码选项,然后输入5设置你的密码。接着,输入c返回到安装菜单:

    注意

    如果提供的密码过于简单,你必须确认是否真的要使用该密码。

    如何操作...

    创建用户菜单让我们创建一个非特权用户账户。

  17. 输入9选择设置 root 密码。输入并确认你希望用于系统 root 账户的密码。

  18. 在解决了所有需要关注的部分后,输入b开始安装过程。

  19. 安装完成后,移除驱动器中的介质并重启系统。

它是如何工作的...

本教程展示了如何使用 Anaconda 在文本模式下安装 CentOS。过程从我们通过安装光盘启动系统,选择安装 CentOS 7进入安装菜单,并将text选项添加到启动参数开始。安装程序的内核加载到内存中,Anaconda 在文本模式下启动。

基于文本的安装方式类似于在图形模式下安装 CentOS,需要回答时区、软件和网络信息的提示。然而,Anaconda 在文本模式下呈现提示的顺序不同,并且缺少某些功能。例如,我们无法进行自定义磁盘分区。尽管如此,文本模式仍然可以让我们快速安装一个基础的 CentOS 系统。

另请参见

欲了解有关安装 CentOS 7 的更多信息,请参考 RHEL 7 安装指南(access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Installation_Guide)。

使用 Kickstart 协调多个安装

如果您计划在多个服务器上安装 CentOS,自动化尽可能多的过程会更方便。在本教程中,您将学习如何使用 Anaconda 的 kickstart.cfg 文件执行无人值守的网络安装。

准备工作

本教程需要至少两台网络上的系统:一台现有系统,运行 HTTP 服务器以托管安装文件和 Kickstart 配置(教程 安装 Apache HTTP 服务器和 PHP 在 第十章,管理 Web 服务器 中展示了如何安装 Apache)和目标系统,我们将在其上安装 CentOS。您还需要安装介质和管理员权限。

如何操作...

按照以下步骤使用 Kickstart 方法执行无人值守的网络安装:

  1. 使用 root 账户登录运行 HTTP 服务器的系统。

  2. 将安装光盘放入系统的光驱。

  3. 使用 mount 命令挂载光盘,以便访问其内容:

    mount /dev/cdrom /media
    
    
  4. 在 Apache 的 Web 根目录下创建一个新目录以托管安装文件:

    mkdir -p /var/www/html/centos/7/x86_64
    
    
  5. 将安装光盘的内容复制到新目录:

    cp -r /media/* /var/www/html/centos/7/x86_64
    
    
  6. 将 Anaconda 在系统安装时创建的 kickstart.cfg 文件复制到 Apache 的 Web 根目录:

    cp /root/kickstart.cfg /var/www/html/kickstart.cfg
    
    
  7. 卸载并移除安装光盘:

    umount /media
    eject /dev/cdrom
    
    
  8. 将光盘插入目标系统的驱动器并重启。系统应启动到 CentOS 7 安装菜单。

  9. 高亮显示 Install CentOS 7 选项并按 Tab

  10. 更新用于启动安装程序内核的参数,使其如下所示。根据需要更改 IP 地址,指向托管 Kickstart 文件的系统:

           vmlinuz initrd=initrd.img ks=http://192.168.56.100/kickstart.cfg 
    
    
  11. Enter 开始安装过程。

  12. 一旦安装过程开始,您可以弹出光盘并开始安装下一个系统。对每个附加系统重复步骤 8-11。

原理...

Anaconda 会将我们在执行图形或文本安装时提供的配置值写入 kickstart.cfg。如果你计划在多台服务器上安装 CentOS,使用该文件提供界面的答案会更加方便。剩余的安装大多数可以无人值守地进行,系统配置也会更加一致。

本教程展示了如何使 kickstart.cfg 文件和 CentOS 安装文件通过网络提供给其他系统,并更新启动命令,以告诉 Anaconda 从哪里查找安装文件和回答提示。由于软件包是从安装服务器而不是光盘获取的,因此安装过程开始后,你可以立即弹出光盘,并使用它开始下一个系统的安装过程。

当然,kickstart.cfg 可以作为起点,你可以使用文本编辑器编辑响应,以进一步自定义安装。如果你愿意,也可以在 Web 根目录下创建多个 kickstart 文件,每个文件有不同的配置。只需在设置安装程序的启动参数时指定所需的文件即可。

提示

尽管你可以使用基本的文本编辑器编辑你的 kickstart 文件,但也有专门的程序用于编辑这些文件。可以查看 Kickstart Configurator (landoflinux.com/linux_kickstart_configurator.html)。

另请参见

欲了解更多有关协调多个 CentOS 7 安装的信息,请参考以下资源:

使用 Amazon Web Services 的 EC2 运行云镜像

Amazon Web Services (AWS) 是一套托管在 Amazon 网络基础设施中的服务,允许公司和个人利用其计算/存储能力和全球数据中心。弹性云计算 (EC2) 是一个虚拟化平台,允许我们按需设置虚拟系统,通常用于托管网站和 Web 应用程序。本教程将带你完成在 AWS 平台上设置运行 CentOS 的新虚拟服务器的过程。

准备工作

本教程假设你已拥有一个 AWS 账户。你可以在 aws.amazon.com 上注册。你需要提供有效的信用卡信息,尽管你将可以在 12 个月内使用 Amazon 的免费套餐。

如何操作...

要在 AWS 的 EC2 平台上设置新的 Amazon Machine Instance (AMI),请按照以下步骤操作:

  1. 登录到aws.amazon.com,并进入 AWS 管理控制台。在计算类别下,点击 EC2 链接进入 EC2 管理页面。然后,点击启动实例按钮:如何操作...

    EC2 管理控制台提供了资源的概览和快速访问方式

  2. 选择 Amazon 机器镜像(AMI)页面,侧边菜单中选择社区 AMIs,然后勾选CentOS过滤器。将显示社区创建的实例列表。选择你需要的那个:

    注意

    仔细查看可用镜像列表。有许多镜像,使用不同版本的 CentOS 和各种配置创建。

    如何操作...

    镜像选择页面展示了一个可过滤的社区用户创建的机器镜像列表。

  3. 检查实例启动页面,查看实例的资源(虚拟 CPU 数量、可用内存等),然后点击启动按钮:

    注意

    亚马逊通过向导式的方式引导你选择并配置 AMI,页面顶部列出步骤。检查启动按钮直接跳转到最后一步。你可以使用页面顶部的链接返回到早期步骤并调整实例的配置。

    如何操作...

    检查实例启动页面查看实例的资源

  4. 使用下拉列表,选择创建一个新的密钥对,输入一个合适的文件名作为密钥名,然后点击下载密钥对按钮。保存下载的私有加密密钥后,点击启动实例按钮:如何操作...

    第一次启动镜像时,你会被提示创建一对加密密钥

  5. 在启动状态页面,点击页面底部的查看实例按钮。然后,右键点击正在运行的实例,从上下文菜单中选择连接。选择首选的连接方式,并按照屏幕上显示的说明操作。

它是如何工作的...

本教程将引导你完成在 AWS 的 EC2 平台上启动新的 CentOS AMI 的步骤。要登录系统,需要一个密码或一对加密密钥,由于主要用户账户的密码可能是未知的,我们选择生成一对新的密钥。私钥被下载并随后与 SSH 客户端一起使用,以验证登录身份。

登录到运行中的系统后,查看 /etc/system-release 文件的内容,以验证当前运行的 CentOS 版本。同时,如果根账户未被锁定,建议使用 passwd 命令修改密码。这是一个重要的安全措施,因为你无法知道谁知道默认密码。关于用户权限管理的食谱请参考第三章,用户和权限管理,关于远程访问管理的食谱请参考第六章,允许远程访问:

如何工作...

登录后,验证系统的版本号并更新根密码

另见

更多关于在 Amazon EC2 平台上使用 AMI 的信息,请参阅以下资源:

从 Docker 注册表安装容器镜像

本食谱展示了如何使用 Docker 获取 CentOS 基础镜像来满足开发需求。Docker 是一种基于容器概念的虚拟化策略,每个容器将目标软件封装在自己的文件系统中,这样它就可以在安装的操作系统上运行,无论操作系统如何。开发者特别喜欢 Docker,因为它有助于在开发和部署环境之间保持一致性。

准备工作

该步骤假设你已安装 Docker。如果没有安装,可以从 www.docker.com 获取 Docker 安装程序。

如何操作...

按照以下步骤从 Docker 注册表安装 CentOS 容器镜像:

  1. 打开 Docker Toolbox 终端程序。

  2. 在终端的提示符下,调用 docker pull 命令以获取 CentOS 7 容器:

    docker pull centos:7
    
    
  3. 容器下载后,你可以使用 docker run 启动交互式 shell:

    docker run -i -t centos:7 /bin/bash
    
    

如何工作...

本食谱使用 docker pull 命令从 Docker 注册表获取官方 CentOS 容器。通过提供版本标签(:7),我们可以确保获取到的是 CentOS 7,而不是更早或更高版本。

或者,Kitematic 是一个图形化程序,允许我们从注册表中搜索并检索容器。只需启动 Kitematic,并在搜索框中输入 CentOS 作为搜索词,然后在结果列表中查找官方 CentOS 仓库。

Kitematic 获取的默认版本是最新版本。要选择 CentOS 7 或维护版本,请点击条目的省略按钮。设置所需的标签,然后点击 创建 按钮:

它是如何工作的...

Kitematic 显示了搜索 CentOS 的结果

另见:

请参考以下资源获取有关使用 Docker 的更多信息:

安装 GNOME 桌面

本步骤展示了如何安装 GNOME 桌面环境,它为你在 CentOS 系统中工作提供了一个图形用户界面(GUI)。通常,这种环境不会安装在服务器系统上,但有时拥有一个图形环境是很方便的。例如,管理员可能会觉得使用图形程序更新系统配置会更加舒适。

注意:

GNOME 并不是唯一可用的 GUI 环境——其他流行的环境包括 KDE、XFCE 和 Fluxbox。如果 GNOME 不是你的菜,下一步将展示如何安装 KDE。

准备工作

本步骤需要一个有网络连接的 CentOS 系统。还需要通过 root 账户登录以获得管理员权限。

如何操作...

按照以下步骤安装 GNOME 桌面环境:

  1. 使用 yum groupinstall 安装 GNOME Desktop 软件包组:

    yum groupinstall "GNOME Desktop"
    
    
  2. 手动使用 startx 启动桌面环境:

    startx
    
    
  3. 如果安装了多个环境,你需要指定 gnome-session 的路径:

    startx /usr/bin/gnome-session
    
    
  4. 当你完成 GNOME 的使用并从桌面注销后,你将返回到控制台。

  5. 要配置系统在启动时自动启动图形环境,请将默认启动目标设置为 graphical.target

    systemctl set-default graphical.target
    
    

它是如何工作的...

本步骤使用 yum 安装 GNOME 桌面环境。所有必要的组件和依赖项都由 GNOME Desktop 软件包组安装。软件包组可以节省时间和麻烦,因为它们允许我们一次性安装一组用于共同任务的软件包,而不是逐个安装单独的软件包。

yum groupinstall "GNOME Desktop"

与 Windows 不同,Windows 的图形桌面是操作系统的一部分,而 Linux 系统将基本的图形和输入处理委托给图形服务器。这种方法是为什么有多个桌面环境可供选择的原因之一——它将许多具体细节抽象化,并提供了一个公共平台,任何数量的环境都可以在其上运行,无论是本地的还是跨网络的。CentOS 的默认图形服务器是 X Window System。

如果 GNOME 是唯一安装的桌面环境,当我们通过 startx 启动 X 时,它会作为默认桌面启动。然而,如果安装了多个桌面环境,我们需要告诉 X 我们想要运行哪个桌面。对于 GNOME,我们需要提供 gnome-session 的路径:

startx /usr/bin/gnome-session

它是如何工作的...

GNOME 桌面提供了一个用于操作系统的图形化界面

systemd 服务管理器负责在系统启动时启动各种服务器和进程。systemctl 命令是我们与服务管理器的接口,可以用来设置默认的启动目标。默认目标决定了系统是启动到终端还是图形化登录界面:

systemctl set-default graphical.target

当设置为图形模式时,systemd 会在系统启动时启动 X 和 GNOME 显示管理器,这会为我们呈现一个图形化登录界面,让我们提供账户信息。一旦身份验证通过,桌面会话就会启动,我们会进入 GNOME 桌面。

如果你不再希望启动到图形环境,可以将默认目标设置回多用户模式,系统将再次启动到基于终端的登录屏幕:

systemctl set-default multi-user.target

提示

如果安装了多个桌面环境,你可以通过登录屏幕上的齿轮按钮来选择想要使用的桌面环境:

它是如何工作的...

你可以从登录屏幕选择你喜欢的桌面

另见

以下资源将为你提供更多关于安装图形化桌面环境和使用 GNOME 桌面的信息:

安装 KDE Plasma 桌面

将图形界面与操作系统分离,使得用户可以选择他们最喜欢的图形环境。如果你不是 GNOME 的粉丝,也不用担心,因为还有很多其他桌面环境可以探索!本教程将教你如何安装另一个流行的桌面环境 KDE Plasma Workspaces。

准备工作

本教程需要一台连接到网络的 CentOS 系统。登录时需要使用 root 账户来获取管理员权限。

如何操作...

按照以下步骤安装 KDE Plasma Workspaces 桌面环境:

  1. 安装KDE Plasma 工作空间软件包组:

    yum groupinstall "KDE Plasma Workspaces"
    
    
  2. 使用startkde手动启动桌面环境。当您退出桌面时,将返回到控制台:

    startkde
    
    
  3. 要配置系统在启动时自动启动图形环境,请使用systemctl将默认启动目标设置为graphical.target

    systemctl set-default graphical.target
    
    

它的工作原理...

此方法通过 Yum 软件包组安装 KDE Plasma 工作空间桌面环境。安装KDE Plasma 工作空间软件包组会安装运行 KDE 所需的所有必要软件组件和依赖项:

yum groupinstall "KDE Plasma Workspaces"

startkde脚本启动 X 服务器并启动 KDE 环境。与 GNOME 不同,我们不直接调用startx,因此在安装多个环境时无需提供额外的路径:

startkde

它的工作原理...

KDE Plasma 工作空间是一款受欢迎的 Linux 系统图形桌面环境。

另请参阅

以下资源将为您提供有关安装和使用 KDE Plasma 工作空间的更多信息:

第二章。网络

本章包含以下示例:

  • 设置静态 IP 地址

  • 将多个地址绑定到单个以太网设备

  • 绑定两个以太网设备

  • 使用 FirewallD 配置网络防火墙

  • 使用 iptables 配置网络防火墙

  • 安装 DHCP 服务器

  • 配置 NFS 服务器以共享文件系统

  • 配置 NFS 客户端以使用共享文件系统

  • 使用 Samba 服务 Windows 共享

简介

本章中的示例涵盖各种网络任务,这些任务对 CentOS 管理员应该很有用。您将学习如何配置静态 IP 地址,将多个地址绑定到单个以太网设备,并将两个设备绑定在一起。您还将了解如何使用 FirewallD 和 iptables 配置系统防火墙,以及如何设置 DHCP 服务器以分发 IP 地址,从而允许使用动态网络配置的其他计算机访问网络。其余示例将教您如何使用 NFS 和 Samba 设置集中式文件存储。

设置静态 IP 地址

此示例向您展示如何配置静态 IP 地址。除非在安装过程中配置了静态地址,否则 CentOS 使用动态主机配置协议(DHCP)获取 IP 地址以跨网络进行通信。对于大多数桌面和笔记本系统来说,使用动态分配的地址是可以接受的,但是那些托管电子邮件服务器、文件共享和打印服务以及 Web 服务器的系统应具有不变的地址。静态地址为用户提供了网络上的稳定、已知位置,用户可以访问系统的服务。

准备工作

此示例要求 CentOS 系统具有正常的网络连接,并通过使用 root 帐户登录来提供管理员权限。假设您的主要以太网设备命名为 enp0s3 并且当前配置为 DHCP。如果您的设备名称不同,请在以下命令中适当替换其名称。

如何做…

按照以下步骤配置静态 IP 地址:

  1. 使用文本编辑器打开以太网设备的配置文件,位于 /etc/ sysconfig/network-scripts 下:

    vi /etc/sysconfig/network-scripts/ifcfg-enp0s3
    
    
  2. BOOTPROTO 的值更改为 none:

    BOOTPROTO="none"
    
    
  3. 在文件末尾添加 IPADDRNETMASKBROADCAST 条目以设置所需的 IP 地址。分配适当反映您网络的值:

    IPADDR="192.168.56.100"
    NETMASK="255.255.255.0"
    BROADCAST="192.168.56.255"
    
    

    如何做…

    接口配置为静态 IP 地址

  4. 保存更改并关闭文件。

  5. 使用文本编辑器打开 /etc/sysconfig/network 文件:

    vi /etc/sysconfig/network
    
    
  6. 添加 GATEWAY 条目以标识您网络的网关:

    GATEWAY="192.168.56.1"
    
    
  7. 保存更改并关闭文件。

  8. 重新启动网络服务以使配置更改生效:

    systemctl restart network.service
    
    

工作原理…

在本教程中,你学习了如何为以太网设备分配静态 IP 地址。假设你主要的以太网设备名称为enp0s3,因此设备的配置文件名称为ifcfg-enp0s3。如果你的设备名称不同(例如,eth0eno1677等),则需要相应调整教程中的指示。

首先,我们将BOOTPROTO的值从dhcp(用于动态获取 IP 地址的协议)更改为none,因为我们是手动设置地址。然后我们添加了IPADDRNETMASKBROADCAST条目,以提供静态 IP 地址的详细信息。接下来,我们通过GATEWAY/etc/sysconfig/network中指定了网络的默认网关。这使得我们能够将流量路由到本地子网之外。

重启网络服务后,你可以使用ip命令确认新的地址。ip addr show将显示当前系统网络设备的状态信息:

它是如何工作的...

ip addr show命令显示系统的网络信息。

另见

要了解更多关于在 CentOS 中配置网络设置的信息,请参考 RHEL 7 网络指南中的配置 IP 网络章节 (access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Networking_Guide/ch-Configure_IP_Networking.html)。

将多个地址绑定到单一以太网设备

本教程展示了如何将多个 IP 地址绑定到单个以太网设备。将多个地址分配给同一设备的能力非常有用——最明显的好处是你无需购买多个以太网卡。虽然硬件成本已经大幅下降,但 IT 预算依然紧张。也许一个不那么显而易见,但更有价值的好处是,它在配置网络服务时提供了更大的灵活性。不同的服务,例如电子邮件和网站,可以在同一系统上运行,但可以使用不同的地址进行访问。

准备工作

本教程需要一个有工作网络连接的 CentOS 系统。假设你的主要以太网设备为enp0s3并配置了静态 IP 地址。你还需要通过以root账户登录来获得管理员权限。

如何操作...

按照以下步骤将多个地址绑定到同一以太网设备:

  1. 复制设备的配置文件:

    cp /etc/sysconfig/network-scripts/ifcfg-enp0s3  
           /etc/sysconfig/network-scripts/ifcfg-enp0s3:1
    
    
  2. 使用文本编辑器打开新文件:

    vi /etc/sysconfig/network-scripts/ifcfg-enp0s3:1
    
    
  3. 完全删除UUID条目。如果存在HWADDR条目,也删除它。

  4. 更新NAMEDEVICE的值:

    NAME="System enp0s3:1"
    DEVICE="enp0s3:1"
    
    
  5. IPADDR的值更改为你希望使用的 IP 地址:

    IPADDR="192.168.56.101"
    
    
  6. 保存更改并关闭文件。

  7. 重启网络服务以使配置更改生效:

    systemctl restart network.service
    
    

它是如何工作的...

在这个教程中,您学会了如何为同一以太网设备分配多个 IP 地址。我们复制了其中一个原始网络配置文件,并且小心地命名它,以便创建一个虚拟适配器,并编辑其配置细节。由于第一个设备的配置文件名为ifcfg-enp0s3,因此新文件命名为ifcfg-enp0s3:1,用以创建与该设备相关联的第一个虚拟适配器。如果您想添加更多适配器(分配更多 IP 地址),请按照步骤递增命名,例如enp0s3:2enp0s3:3等。

在配置文件中,我们移除了HWADDRUUID条目,因为虚拟适配器不需要这些条目。然后,我们更新了DEVICENAME条目,以便给适配器分配一个唯一的标识,当然,我们还更新了IPADDR条目来分配其 IP 地址:

它是如何工作的...

多个 IP 地址通过虚拟适配器绑定到一个以太网设备

另见

请参考以下资源以获取更多关于将多个地址绑定到同一以太网设备的信息:

绑定两个以太网设备

在这个教程中,您将学习如何将多个以太网设备组合为一个网络设备,这种配置被称为通道绑定。通道绑定允许我们将多个设备绑定在一起,使它们在 CentOS 系统上运行的服务器中表现为一个单一的接口。其目的是提升系统的整体网络性能,并在其中一个网络设备发生故障时提供冗余。

准备工作

本教程要求使用至少有两个以太网设备的 CentOS 系统。假设您的主以太网设备是enp0s3。如果您的设备名称不同,请在命令中适当替换设备名称。您还需要通过以root账户登录来获得管理员权限。

如何操作...

按照以下步骤将两个以太网设备绑定在一起:

  1. 安装bind-utilsethtool包:

    yum install bind-utils ethtool
    
    
  2. 为绑定接口创建一个新的配置文件:

    vi /etc/sysconfig/network-scripts/ifcfg-bond0
    
    
  3. 向文件中添加以下行,替换适合您网络的IPADDRNETMASKBROADCAST值:

    BOOTPROTO="none"
    DEVICE="bond0"
    USERCTL="no"
    ONBOOT="yes"
    IPADDR="192.168.56.100"
    NETMASK="255.255.255.0"
    BROADCAST="192.168.56.255"
    
    
  4. 保存您的更改并关闭配置文件。

  5. 打开您希望绑定的第一个设备的配置文件:

    vi /etc/sysconfig/network-scripts/ifcfg-enp0s3
    
    
  6. 确保BOOTPROTO设置为noneONBOOT设置为yes。然后,如果存在,删除IPADDRNETMASKBROADCAST条目。

  7. 在文件末尾添加SLAVEMASTER条目:

    SLAVE=yes
    MASTER=bond0
    
    
  8. 保存更改并关闭配置文件。

  9. 对每个额外要绑定的设备,重复步骤 5-8。

  10. 创建配置文件,用于让内核控制绑定接口的行为:

    vi /etc/modprobe.d/bonding.conf
    
    
  11. 将以下行添加到文件中:

    alias bond0 bonding
    options bond0 mode=5 miimon=100
    
    
  12. 保存更改并关闭文件。

  13. 使用系统内核注册绑定模块:

    modprobe bonding
    
    
  14. 重新启动网络服务以使更改生效:

    systemctl restart network.service
    
    

它是如何工作的...

我们首先在/etc/sysconfig/network-scripts/ifcfg-bond0创建了一个绑定接口的配置文件。BOOTPROTO设置为none,因为 IP 地址是静态设置的,DEVICE为接口命名,USERCTL设置为no,禁止非管理员用户启动和关闭该接口,ONBOOT设置为yes,使得接口在启动时自动激活。我们还使用IPADDRNETMASKBROADCAST提供了 IP 地址信息:

BOOTPROTO="none"
DEVICE="bond0"
USERCTL="no"
ONBOOT="yes"
IPADDR="192.168.56.100"
NETMASK="255.255.255.0"
BROADCAST="192.168.56.255"

然后,我们更新了每个我们想要绑定的设备的配置文件。我们确保BOOTPROTO设置为none,并且没有地址信息,因为该设备不再需要自己的 IP 地址。通过添加SLAVEMASTER条目,我们将设备标识为绑定到新的bond0设备:

SLAVE=yes
MASTER=bond0

通过执行这些步骤,我们创建了一个新的虚拟设备,称为绑定主设备,该设备将使用我们的实际以太网设备作为从设备。如果一个从设备失败,另一个从设备仍然处于活动状态,从而提供冗余。

接下来,我们创建了一个新的配置文件,包含我们对内核绑定模块的偏好。该模块是绑定设备的内核实现,负责协调物理设备:

alias bond0 bonding
options bond0 miimon=100 mode=5

miimon=100指定每100毫秒进行 MII 链路监控,以验证物理设备是否处于活动状态。mode=5表示一种基本配置,不需要任何特定类型的网络交换机支持。它允许根据每个从设备的当前负载分配外发流量。还有五种其他模式,提供了丰富的选项来配置设备如何协同工作,尽管需要注意的是某些模式可能需要特定硬件支持。更多信息请参考wiki.centos.org/TipsAndTricks/BondingInterfaces

修改设备的配置文件后,我们使用modprobe注册了绑定内核模块:

modprobe bonding

它是如何工作的...

通过绑定适配器将两个以太网设备绑定到相同的 IP 地址

另请参见

有关在 CentOS 中绑定以太网设备的更多信息,请参考 RHEL 7《网络配置指南》中的配置网络绑定章节(access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Networking_Guide/ch-Configure_Network_Bonding.html)。

使用 FirewallD 配置网络防火墙

现在你将学习如何使用 FirewallD 配置网络防火墙。从 CentOS 7 开始,FirewallD 取代 iptables 作为默认的防火墙配置工具(尽管 iptables 仍在 FirewallD 背后使用)。根据你配置的区域和服务,你可以通过控制允许或禁止进出系统的流量,来增强服务器的网络安全性。

准备工作

本教程需要一个具有有效网络连接的 CentOS 系统。你还需要通过使用root账户登录获得的管理员权限。

怎么做...

这个命令集将向你展示如何使用 FirewallD 的命令行客户端firewall-cmd执行几项基本配置任务:

  1. 要识别当前活动的区域及其分配的以太网设备,请使用--get-active-zones标志:

    firewall-cmd --get-active-zones
    
    
  2. 要临时更改设备分配到的区域,请使用--zone参数指定目标区域,并使用--change-interface指定以太网设备:

    firewall-cmd --zone=public --change-interface=enp0s3
    
    
  3. 要永久将设备分配到某个区域,请将ZONE条目添加到设备的配置文件中。此更改在服务重启之前不会生效:

    vi /etc/sysconfig/network-scripts/ifcfg-enp0s3
    ZONE="public"
    
    
  4. 要识别某个区域的当前配置,请使用--zone参数指定目标区域,并加上--list-all

    firewall-cmd --zone=public --list-all
    
    
  5. 要允许流量通过防火墙,请使用--add-service--add-port参数:

    可以通过名称允许常见服务和协议的流量,如 HTTP 和 SMTP。以下命令添加了http服务,它会打开端口80(该端口由 Apache 和其他 HTTP 服务器使用):

    firewall-cmd --zone=public --permanent --add-service=http
    
    

    流量总是可以根据端口和网络协议直接允许。以下命令打开端口 8080 以允许 TCP 流量,这是另一个常用于提供网页内容的端口:

    firewall-cmd --zone=public --permanent --add-port=8080/tcp
    
    
  6. 要禁止当前允许通过防火墙的流量,请使用--remove-service--remove-port参数:

    firewall-cmd --zone=public --permanent --remove-service=http
    firewall-cmd --zone=public --permanent --remove- port=8080/tcp
    
    
  7. 要在更改后重新加载防火墙,请使用--reload

    firewall-cmd --reload
    
    

它是如何工作的...

FirewallD 的默认安装提供了几个预配置的区域,例如publicdmzworkhometrusted。不同的接口可以分配到不同的区域,并应用不同的规则。要查看所有可用区域及其配置,可以使用firewall-cmd加上--list-all-zones标志:

firewall-cmd --list-all-zones

大多数对防火墙规则的更新会立即生效,但它们是临时的。我们之前看到过,当我们需要更新设备的配置文件并重启服务以使区域更改生效时,设置的更改是临时的。这使得我们可以在最终确定配置之前对不同的设置进行实验。当配置服务和端口时,使用--permanent标志使更改永久生效。如果未提供该标志,更改将立即生效,但仅是临时性的(在系统重启或防火墙服务重启时不会保留):

firewall-cmd --zone=public --permanent --remove-service=http

命名服务是预配置的端口设置,通常用于特定的网络服务,并且为了方便使用而提供。例如,SSH 流量通常由面向端口 22 的 TCP 数据包组成,因此ssh服务反映了这一点。在示例中,我们使用了http服务,它配置了端口 80,这是用于提供网页的标准端口。虽然直接分配端口也能达到相同效果,但服务提供了便于人类阅读的名称,应该在可能的情况下使用。要获取所有可用服务的列表,可以使用--get-services

firewall-cmd --get-services

工作原理...

firewall-cmd 是一个命令行客户端,用于配置防火墙规则

注意

命名服务被定义为/usr/lib/firewalld/services目录下的 XML 文件。如果你想允许某些流量访问,但没有定义相应的服务,并且为了可读性你希望使用服务而不是端口和协议进行配置,你可以在该目录中创建一个新的服务文件。可以复制一个现有文件作为起点,并根据需要进行修改。

另请参见

有关使用 FirewallD 的更多信息,请参阅以下资源:

使用 iptables 配置网络防火墙

在本教程中,你将学习如何用 iptables 服务替代 FirewallD 并执行基本的防火墙配置。iptables 是 CentOS 7 版本之前管理防火墙设置的默认方法。一些管理员可能偏爱 iptables,因为它更符合他们的使用习惯,或者他们可能在数据中心有多台旧服务器,并希望尽可能保持一致性。

准备工作

本教程要求系统为 CentOS,并且需要有效的网络连接。你还需要通过以 root 账户登录来获取管理员权限。

如何操作...

以下步骤将帮助你用 iptables 服务替换 FirewallD:

  1. 停止并禁用 FirewallD 服务:

    systemctl stop firewalld
    systemctl mask firewalld
    
    
  2. 安装包含该服务的 iptables-services 包:

    yum install iptables-services
    
    
  3. 启动服务并注册,使其在系统启动时自动启动:

    systemctl start iptables
    systemctl enable iptables
    
    

以下命令集合将展示如何使用 iptables 执行几个基本配置任务:

  • 使用 -L 标志打印当前配置。添加 --line-numbers 标志来显示每条规则的 ID 编号:

    iptables -L --line-numbers
    
    
  • 使用以下命令允许来自 enp0s3 接口的 TCP 流量通过防火墙进入 80 端口:

    iptables -A INPUT -i enp0s3 --dport 80 -p tcp -j ACCEPT
    
    
  • 要删除允许 TCP 流量通过 80 端口的规则,请执行 iptables -L --line-numbers 查找规则的 ID,然后使用以下命令(将 ## 替换为规则的 ID):

    iptables -D INPUT ##
    
    
  • 在配置更改后重新加载 iptables,使其生效:

    systemctl restart iptables
    
    

它是如何工作的...

为了用 iptables 服务替代 FirewallD 来管理网络防火墙,我们首先停止并禁用了 FirewallD 服务;我们不希望运行多个防火墙守护进程,因为这会导致冲突。FirewallD 在后台使用 iptables,因此 iptables 已经安装,但 iptables 服务没有安装。所以,接下来我们安装了 iptables-services 包:

yum install iptables-services

接着我们看到如何执行基本的配置来允许或拒绝流量。例如,本教程展示了添加允许通过 80 端口的 TCP 流量的命令:

iptables -A INPUT -i enp0s3 --dport 80 -p tcp -j ACCEPT

-A 参数表示我们希望添加一条防火墙规则,并紧跟规则类型。可选值包括 INPUTOUTPUTFORWARD,分别适用于进入流量、离开流量和路由流量(例如,如果系统被配置为路由器)。由于指定了 INPUT,我们的规则适用于端口 80 上的进入流量。

-i 参数指定了规则所监控的网络接口。在这个例子中,规则应用于 enp0s3。然后,--dport 指定了流量的目标端口,在此情况下是端口 80-p 指定了传输协议,例如 TCP 或 UDP。

-j 参数是 跳转到 的目标动作。使用 iptables 时,规则被串联在一起形成过滤逻辑链。可以想象 iptables 会依次检查流量是否符合每个规则;如果第一个规则不匹配,它会继续检查下一个规则,直到找到匹配的规则为止。当找到匹配规则时,iptables 停止检查并 跳转 到所需状态。可能的状态有 ACCEPT 以接受流量,REJECT 以主动拒绝连接,DROP 以静默忽略。

我们还了解了如何使用 -L 标志显示当前定义的规则,以及使用 --line-numbers 显示标识符,便于与每条规则一起显示:

iptables -L --line-numbers

它是如何工作的...

iptables 根据配置的规则接受或拒绝流量

知道规则的标识符很方便,如果我们想删除它。通过提供 -D、规则类型(INPUTOUTPUTFORWARD)和 ID,我们可以简洁地从链中删除规则:

iptables -D INPUT 6

或者,您可以重新指定整个规则,同时将 -A 替换为 -D 以删除它:

iptables -D INPUT -i enp0s3 --dport 80 -p tcp -j ACCEPT

另见

请参阅以下资源,获取更多关于使用 iptables 的信息:

安装 DHCP 服务器

本文将向您展示如何在 CentOS 上设置自己的 DHCP 服务器。DHCP 用于根据需求分配 IP 地址和其他网络配置信息给客户端。虽然配置了静态 IP 地址的系统已经知道所有必要的网络配置信息,但配置为使用 DHCP 的系统会在网络上广播请求,并等待 DHCP 服务器的响应。

准备工作

本文要求使用一个具有有效网络连接的 CentOS 系统。您还需要通过 root 账户登录来获得管理权限。

注意

网络中应该只有一个 DHCP 服务器在运行,以防止客户端收到冲突的响应,导致网络不稳定。许多路由器已经在运行 DHCP 服务,因此在继续之前请先检查您自己的网络。

如何执行...

按照以下步骤设置 DHCP 服务器:

  1. 安装 dhcp 软件包:

    yum install dhcp
    
    
  2. 复制包提供的示例配置文件,作为服务器配置的起点:

    cp /usr/share/doc/dhcp-4.2.5/dhcpd.conf.example  
           /etc/dhcp/dhcpd.conf
    
    
  3. 使用文本编辑器打开配置文件:

    vi /etc/dhcp/dhcpd.conf
    
    
  4. 根据您的环境修改配置,特别是您需要处理以下选项:domain-namedomain-name-serverssubnetdynamic-bootp 范围,broadcast-addressrouters。以下是一个包含两个子网的网络配置示例:

    # option definitions common to all supported networks
    option domain-name localdomain;
    option domain-name-servers ns1.localdomain;
    default-lease-time 600;
    max-lease-time 7200;
    # This DHCP server is the official DHCP server for the
    # local network
    authoritative;
    # No service will be given on this subnet, but declaring
    # it helps the server to understand the network topology.
    subnet 192.168.56.0 netmask 255.255.255.0 {
    }
    # This is a basic subnet declaration
    subnet 192.168.56.0 netmask 255.255.255.128 {
     range 192.168.56.110 192.168.56.120;
     option domain-name-servers ns1.localdomain;
     option domain-name "localdomain";
     option routers 192.168.56.1;
     option broadcast-address 192.168.56.127;
    }
    # This is the second subnet
    subnet 192.168.56.128 netmask 255.255.255.128 {
     range 192.168.56.200 192.168.56.210;
     option domain-name-servers ns2.sub.localdomain;
     option domain-name "sub.localdomain";
     option routers 192.168.56.129;
     option broadcast-address 192.168.56.255;
    }
    
    
  5. 保存更改并关闭文件。

  6. 启动 dhcp 服务并启用它在系统启动时自动启动:

    systemctl start dhcpd
    systemctl enable dhcpd
    
    
  7. 在系统的防火墙中打开端口 6768 以允许流量:

    firewall-cmd --zone=public --permanent --add-service=dhcp
    firewall-cmd --reload
    
    

工作原理...

配置为使用 DHCP 的系统将广播请求,并等待接收来自 DHCP 服务器的响应。服务器的响应告诉客户端使用哪个 IP 地址、子网掩码、网关信息等来连接网络。DHCP 提供的地址通常是租用的,这意味着在设定的时间后,它们会过期,客户端需要重新发送请求。除了分发连接详细信息外,DHCP 服务器还必须跟踪已经租出的地址,以免客户端收到其他系统已经使用的地址。

我们首先安装了 dhcpd 包,该包包含服务器和示例配置文件。复制示例配置文件作为我们自己配置的起点,可以避免从头编写整个配置:

cp /usr/share/doc/dhcp-4.2.5/dhcpd.conf.example  /etc/dhcp/dhcpd.conf

在配置文件中,有几个地方需要提供适合您网络的值。作为示例的最小配置文件反映了一个划分为两个子网的网络。第一个子网是 192.168.56.0/25,第二个是 192.168.56.128/25。每个子网都有自己的声明。

检查第一个子网声明,子网的 ID 为 192.168.56.0,子网掩码为 255.255.255.128range 选项将限制 DHCP 服务器在 192.168.56.110120 范围内分配 IP 地址(其他地址仍然有效,并可用于静态分配)。后续的 option 条目提供子网的广播地址和网关,并覆盖全局定义的域名和 DNS 服务器:

# This is a basic subnet declaration
subnet 192.168.56.0 netmask 255.255.255.128 {
 range 192.168.56.110 192.168.56.120;
 option domain-name-servers ns1.localdomain;
 option domain-name "localdomain";
 option routers 192.168.56.1;
 option broadcast-address 192.168.56.127;
}

正确配置 DHCP 服务器需要理解计算机网络。它是一个复杂的话题,因此我们无法详细讨论每个选项。我建议您阅读 dhcpd.conf 的手册页,以获得额外的指导。可以使用 man 命令访问该页面:

man 5 dhcpd.conf

工作原理...

dhcpd 的配置文件在手册页中有文档说明。

一旦 DHCP 服务器配置并运行,我们就需要在防火墙中开一个孔,以允许请求和响应自由流动。DHCP 请求使用 UDP 和端口 5758(可以通过为 FirewallD 定义的服务来允许它们):

firewall-cmd --zone=public --permanent --add-service=dhcp
firewall-cmd --reload

另见

有关设置 DHCP 服务器的更多信息,请参考以下资源:

配置 NFS 服务器以共享文件系统

网络文件系统(NFS)是一种分布式文件系统协议。也就是说,我们可以将文件存储到远程服务器上的某个目录中,客户端可以挂载该共享目录。远程目录在客户端看起来就像本地目录一样,尽管所有保存到该目录的数据实际上都存储在服务器上。本食谱展示了如何在服务器上配置 NFS 并将存储暴露为网络共享。(下一个食谱将展示如何在客户端配置 NFS。)

准备工作

本食谱需要一个具有有效网络连接的 CentOS 系统。你还需要通过以 root 账户登录获得管理员权限。

如何操作...

按照以下步骤设置 NFS 服务器:

  1. 安装 nfs-utilslibnfsidmap 包:

    yum install nfs-utils libnfsidmap
    
    
  2. 创建一个全局可访问的目录,作为文件共享的根目录:

    mkdir -m 777 /var/nfsshare
    
    
  3. 打开 /etc/exports 文件,并添加以下条目以标记要通过 NFS 导出的目录。完成后,保存并关闭文件:

    /var/nfsshare 192.168.56.0/24(rw,sync,root_squash)
    
    

    exports 文件非常挑剔。确保网络和括号选项之间没有空格,选项之间的逗号周围也没有空格。

  4. 启动必要的服务并注册它们,以便在服务器启动时自动启动:

     systemctl start rpcbind nfs-server
     systemctl enable rpcbind nfs-server 
    
    
  5. 在防火墙中打开端口 11120482049 以允许流量通过:

    firewall-cmd --permanent --zone public --add-service rpc-bind
    firewall-cmd --permanent --zone public --add-service mountd
    firewall-cmd --permanent --zone public --add-service nfs
    firewall-cmd --reload
    
    

它是如何工作的...

在本食谱中,你学会了如何使用 NFS 设置共享网络目录。在安装适当的包后,我们创建了共享目录,注册它以供导出,并启动了必要的系统服务。

/etc/exports 是管理导出文件系统及其方式的配置文件。我们添加了一个条目,标识了我们要导出的目录,接着列出了它们导出的客户端以及管理导出处理方式的选项:

/var/nfsshare 192.168.56.0/24(rw,sync,root_squash)

在示例中,我们将共享目录提供给 192.168.56.0/24,换句话说,网络上的任何主机。或者,你也可以将目录共享给单个主机或一系列主机。共享目录给特定主机的条目如下所示:

/var/nfsshare 192.168.56.101(rw,sync,root_squash)

rw++选项允许对共享文件夹进行读写访问。sync选项则会立即将文件的所有更改刷新到磁盘。虽然写入磁盘可能会导致文件访问变慢,但除非系统负载过高,否则延迟几乎不会被察觉,这对于在崩溃时能提供即时刷新的安全性来说,是一种值得的折衷。

当提供root_squash选项时,NFS 将有效地将根用户的所有权压缩为nfsnobody,这是一项安全措施,可以减少客户端系统上的根用户尝试以根权限将文件写入共享的风险(否则,恶意用户可以存储一个文件并将其标记为可执行,从而可能以根权限运行)。如果你想将所有文件的所有权压缩为nfsnobody,可以使用all_squash选项。

NFS 依赖于其他一些服务,因此我们还启用了 rpcbind 并为 rpcbind 和 mountd 打开了防火墙端口。NFS 基于远程过程调用(RPC)协议工作,而 rpcbind 负责将基于 RPC 的服务映射到其端口。来自客户端的传入连接首先会触及 rpcbind 服务,提供一个 RPC 标识符。rpcbind 将该标识符解析为特定服务(此处为 NFS),并将客户端重定向到相应的端口。在那里,mountd 处理请求,以确定请求的共享是否已导出,以及客户端是否被允许访问该共享。

另见

参考以下资源获取有关配置 NFS 服务器的更多信息:

配置 NFS 客户端以使用共享文件系统

本教程接续上一个教程,向你展示如何在客户端系统上配置 NFS。

准备工作

本教程需要一台具有正常网络连接的 CentOS 系统,假设你已经按照上一个教程配置了 NFS 服务器。你还需要通过root账户登录来获得管理员权限。

如何操作…

按照以下步骤配置 NFS 客户端:

  1. 安装nfs-utilslibnfsidmap包:

    yum install nfs-utils libnfsidmap
    
    
  2. 创建将作为远程文件系统挂载点的目录:

    mkdir /mnt/nfs
    
    
  3. 启动rpcbind服务并注册,以确保服务器启动时该服务也会启动:

    systemctl start rpcbind
    systemctl enable rpcbind
    
    
  4. 将 NFS 共享挂载到挂载点:

    mount -t nfs 192.168.56.100:/var/nfsshare /mnt/nfs
    
    

它是如何工作的...

与服务器端类似,NFS 客户端依赖于 RPC。因此,我们启动并启用了 rpcbind 服务。然后,使用 mount 命令挂载远程共享:

mount -t nfs 192.168.56.100:/var/nfsshare /mnt/nfs

-t 参数表示共享的文件系统类型,当然是 nfs。还需要提供远程共享的位置,服务器的 IP 地址和共享数据的目录,以冒号分隔。最后,指定挂载目标。

要手动卸载共享,使用 umount 命令并指定挂载点:

umount /mnt/nfs

我们还可以配置系统在启动时自动挂载 NFS 共享。使用编辑器打开 /etc/fstab 文件,并添加以下行:

192.168.0.100:/var/nfsshare /mnt/nfs/var/nfsshare nfs defaults 0 0

共享将在系统启动时自动挂载。由于 mount 可以在 /etc/fstab 中查找信息,因此一旦以这种方式注册,手动挂载共享的调用变得更加简便。现在,你只需提供 mount 即可手动挂载共享:

mount /mnt/nfs

另见

有关配置 NFS 客户端的更多信息,请参考以下资源:

使用 Samba 提供 Windows 共享

在这个教程中,你将学习如何使用 Samba 从 CentOS 系统共享 Windows 共享目录。与 NFS 类似,Windows 共享是远程服务器上的一个目录,客户端可以访问该目录来存储文件。Samba 是一个理解 Windows 使用的 SMB 协议的服务器,使其能够导出 Windows 客户端可以挂载的目录。

准备就绪

本教程要求使用具有有效网络连接的 CentOS 系统。你还需要通过以 root 账户登录来获取管理员权限。

配置 Samba 时需要提供 Windows 工作组的名称。在开始之前,在 Windows 系统的网络中运行 net config workstation 并记录 Workstation domain 值:

准备就绪

net config workstation 显示有关 Windows 系统的工作组和域的信息

如何操作...

按照以下步骤设置 Samba 以与 Windows 系统共享目录:

  1. 安装 samba 包:

    yum install samba
    
    
  2. 为 Samba 用户创建一个专用组:

    groupadd smbgroup
    
    
  3. 创建将作为文件共享根目录的目录。将其组所有权设置为新的 Samba 用户组:

    mkdir -m 770 /var/sambashare
    chgrp smbgroup /var/sambashare
    
    
  4. 使用文本编辑器打开 Samba 的配置文件:

    vi /etc/samba/smb.conf
    
    
  5. 更新 [global] 部分中的 workgroup 参数,以匹配 Windows 工作组名称。可以查看配置文件中的其他参数,因为每个参数都进行了详细的注释:

    Workgroup = WORKGROUP
    
    
  6. 在配置文件的末尾添加以下内容:

    [share]
    path = /var/sambashare
    guest ok = no
    valid users = @smbgroup
    writable = yes
           create mask = 0755 
    
    
  7. 保存更改并关闭文件。

  8. 启动必要的服务并注册它们,以便它们在服务器启动时自动启动:

    systemctl start smb nmb
    systemctl enable smb nmb
    
    
  9. 打开端口 137-139445,以允许网络流量:

    firewall-cmd --permanent --zone public --add-service samba
    firewall-cmd --reload
    
    
  10. 对于每个将连接到共享的用户,将其分配到用户组并注册他们将使用的密码:

    usermod -a -G smbgroup tboronczyk
    smbpasswd -a tboronczyk
    
    

它是如何工作的…

在本教程中,你学会了如何安装和配置 Samba,以共享 Windows 客户端可以访问的目录。

我们首先使用 net config 命令进行了一些研究,发现了我们的客户端所属的 Windows 工作组。这很重要,因为同一网络中的两个系统,如果它们属于不同的工作组,将无法相互通信。在本例中,工作组的名称是 WORKGROUP

接下来,我们安装了 samba 包,并创建了一个名为 smbgroup 的特殊组。我们将配置 Samba,使得 CentOS 系统上的任何用户帐户,只要其属于 smbgroup 组,就可以访问共享。然后,我们创建了要共享的目录,并将其组所有权设置为新组。

我们编辑了 Samba 的配置文件,为 workgroup 值指定了我们之前查找的 Windows 工作组名称,并添加了一个部分来定义新的共享。我们通过将 guest ok 设置为 novalid users 设置为 @smbgroup 来限制共享访问权限,确保只有属于 smbgroup 的认证用户才能访问该共享。writable 条目允许用户在共享上创建和更新文件(否则文件将是只读的),而 create mask 条目用于指定新文件在 Linux 文件系统中分配的默认文件权限。括号中的 share 名称不仅开始了该配置部分,而且还作为共享导出的名称(即 \\192.168.56.100\share)。只要每个名称都唯一,你可以导出多个共享。

对于每个将用于连接共享的用户帐户,我们确保它属于 smbgroup,并使用 smbpasswd 命令指定该帐户将用于认证其 SMB 会话的密码。此密码与系统的凭据分开维护,仅用于对 Samba 进行身份验证,因此应该选择一个与帐户登录密码不同的密码。

管理 Samba 用户可以使用smbpasswd-a选项会在 Samba 的账户数据库中添加一个条目,而我们可以使用-x选项从数据库中删除用户:

smbpasswd -x tboronczyk

在 Windows 系统上,你可以使用net use命令将远程共享映射到驱动器字母。一旦映射完成,该驱动器将出现在可用驱动器列表中:

net use Z: \\192.168.56.100\share /USER:tboronczyk

或者,你可以通过 Windows 图形界面来映射驱动器,路径是:计算机 | 映射网络驱动器 | 映射网络驱动器,在文件资源管理器中选择此电脑书签:

工作原理...

Samba 共享可以作为网络映射驱动器使用

另见

有关使用 Samba 的更多信息,请参考以下资源:

第三章:用户和权限管理

本章包含以下配方:

  • 使用 sudo 提升权限

  • 强制执行密码限制

  • 设置新文件和目录的默认权限

  • 以不同用户身份运行二进制文件

  • 使用 SELinux 增强安全性

介绍

本章中的每个配方都与用户和权限相关。您将学习如何让用户在不需要 root 密码的情况下暂时提升权限,如何为用户强制执行复杂度要求。您还将学习如何指定新文件和目录的默认访问权限,以及传统的 Unix 权限系统如何允许程序在与启动它的用户不同的安全上下文中运行。最后,我们将讨论 SELinux,这是一个增强 CentOS 服务器安全性的辅助权限系统。

使用 sudo 提升权限

root账户是 Linux 的超级用户账户,它具有执行系统上几乎所有活动的能力。出于安全考虑,您应该使用一个没有特权的用户账户进行日常操作,只有在需要管理任务时才使用root账户。保持 root 密码的机密性也非常重要;知道密码的人越多,保密就越困难。让我想起本杰明·富兰克林的一句话:三个能保守一个秘密,前提是其中两个已经死了。

如果有多个管理员负责管理系统,保持root账户的安全可能会变得困难。sudo通过提供一种让用户以其他用户(通常是root)的权限执行命令的方式来解决这个问题。每个管理员账户可以使用本教程中介绍的方法来临时提升权限,root密码可以保持机密。

准备工作

本配方需要一个 CentOS 系统,并通过登录root账户提供的管理访问权限。您还需要一两个没有特权的用户账户进行配置(有关创建用户账户的信息,请参考useradd手册页man 8 useradd)。

如何操作...

允许没有特权的账户使用sudo的一种方法是将其分配到wheel组。可以通过以下步骤完成:

  1. 使用usermod将用户账户添加到wheel组:

    usermod -a -G wheel tboronczyk
    
    
  2. 使用groups命令验证更新。wheel应该列出该账户所属于的其中一个组:

    groups tboronczyk
    
    

另一种授予sudo权限的方法是配置 sudoers 策略,指定哪些账户可以使用sudo以及以何种方式使用。您可以通过以下步骤轻松将账户添加到该策略中:

  1. /etc/sudoers.d目录下创建一个以用户账户命名的新文件:

    touch /etc/sudoers.d/tboronczyk
    
    
  2. 打开文件并添加以下指令。完成后,保存更新并关闭文件:

    tboronczyk ALL = ALL
    
    

它是如何工作的...

用户要使用sudo命令,必须以某种方式将其列入 sudoers 策略中。sudo会检查这一点,以验证该账户是否被授权执行所尝试的操作。此方法提供了两种实现方式:将用户账户分配到已在策略中注册的wheel组,或者直接将账户添加到策略中。

在第一种方法中,usermod命令将用户分配到wheel组。-G选项指定组的名称,而-a指示usermod将用户添加到该组中。提供-a非常重要,因为如果没有它,分配的组列表会被-G后面指定的内容覆盖(即账户将只属于wheel组)。

usermod -a -G wheel tboronczyk

第二种方法通过在/etc/sudoers.d下为用户创建文件来将账户注册到 sudoers 策略中。我们本可以将用户信息直接添加到/etc/sudoers配置文件中,但策略已将sudoers.d目录下的任何文件包含在其配置中。为每个用户在该目录中创建一个文件,在需要撤销访问权限时,面对大量用户会更易于管理。

这两种方法都允许用户使用sudo执行他们通常没有足够权限的命令。例如:

sudo umount /media

用户首次调用sudo时,系统会显示一条消息,提醒他们在使用新获得的权限时要负责。用户必须提供密码以验证身份;此验证将在最后一次调用后缓存五分钟,以作为对可能会走到一个未注销的终端上的恶意用户的额外保护。

它是如何工作的...

sudo 提醒用户,巨大的权力伴随着巨大的责任

sudoers 策略足够灵活,允许用户账户执行特定命令,而不是给予完全的访问权限。回忆一下我们非特权用户账户的配置指令:

tboronczyk ALL = ALL

指定用户名后,将ALL别名分配给ALL。通过查看这一点,你可能已经明白,ALL是表示所有命令的预定义别名。我们可以将给定用户的别名重新定义为一个允许的命令列表:

tboronczyk ALL = /bin/mount /bin/umount

现在该账户可以调用它通常有权限访问的任何命令,但只有在具有提升权限的情况下才可以使用mountumount命令(假设该账户不是wheel的成员)。

提示

你是否厌倦了在常用的管理命令前键入sudo?你可以为命令创建别名,获得更流畅的命令行体验。假设你的非特权账户被允许使用sudo执行mountumount命令。将以下行添加到~/.bashrc文件中,你可以在不明确键入sudo的情况下调用这些命令:

alias mount sudo /bin/mount
alias umount sudo /bin/umount

策略中的多个指令可以应用于一个账户,在这种情况下,它们是按顺序叠加应用的,从第一个到最后一个。为了演示这一点,假设一个账户已经通过分配到wheel组而具有完全的sudo使用权限。默认情况下,用户需要提供密码才能执行命令。我们可以放宽这一要求,允许用户使用ls命令显示受限目录的内容而无需输入密码:

tboronczyk ALL = NOPASSWD: /bin/ls

wheel组的策略首先应用,建立了默认行为。然后,我们的新指令使用NOPASSWD标签,授予用户对ls命令的无认证访问权限。用户仍然需要在执行mountpasswd等命令时提供密码,但在列出受限目录时则不需要提供密码。

另请参阅

请参阅以下资源,了解如何使用sudo来临时提升账户权限:

强制实施密码限制

弱密码可能是任何系统最薄弱的安全环节之一。简单密码容易受到暴力破解攻击,而长期使用的密码如果被泄露,会为恶意活动提供长时间的攻击窗口。因此,确保用户选择足够复杂的密码并定期更换非常重要。本教程展示了如何通过对用户密码施加各种限制来增强系统的安全性。您将学习如何指定密码的最低复杂性要求、密码需要多久更改一次,以及如何在多次登录失败后锁定账户。

准备工作

本教程需要一个 CentOS 系统和管理员访问权限,可以通过登录root账户或使用sudo获得。

如何执行...

按照以下步骤执行,以强制实施密码限制,从而提高您 CentOS 系统的安全性:

  1. 控制密码过期的参数位于/etc/login.defs中;使用您选择的文本编辑器打开该文件:

    vi /etc/login.defs
    
    
  2. 定位到密码过期控制部分,并更新PASS_MAX_DAYSPASS_MIN_DAYSPASS_MIN_LENPASS_WARN_AGE的值:

    PASS_MAX_DAYS  90
    PASS_MIN_DAYS  0
    PASS_MIN_LEN   8
    PASS_WARN_AGE  15
    
    
  3. 保存更改并关闭文件。

  4. login.defs中指定的值将应用于新创建的账户。现有用户必须使用chage命令单独设置他们的密码参数:

    chage --maxdays 90 --mindays 0 --warndays 15 tboronczyk
    
    
  5. 控制密码复杂性要求的参数位于/etc/security/pwquality.conf文件中;打开该文件进行编辑:

    vi /etc/security/pwquality.conf
    
    
  6. 取消注释 minlen 值以指定所需的最小密码复杂度加 1。例如,一个由小写字母组成的八字符密码,其 minlen 应该设置为 9

    minlen = 9
    
    
  7. 如果需要,你可以取消注释其他值并进行设置。每个值前面都会有简短的描述性注释,说明其功能。如果你希望密码中必须至少有一定数量的字符来自某个特定类别(大写字母、小写字母、数字和其他/特殊字符),可以将该值设置为负数。例如,如果密码必须至少包含一个数字字符和一个大写字母,则 dcreditucredit 都应设置为 -1如何操作...

    配置系统密码复杂度要求的选项可以在 pwquality.conf 文件中找到

  8. 保存更改并关闭文件。

  9. 接下来,我们将更新 PAM 的 password-authsystem-auth 模块配置,以便在多次登录失败后锁定账户。打开文件 /etc/pam.d/password-auth

    vi /etc/pam.d/password-auth
    
    
  10. 更新文件开头的 auth 行组,使其如下所示。第二行和第四行已被添加,并且包括 pam_faillock 到认证堆栈中:

    auth   required      pam_env.so
    auth   required      pam_faillock.so preauth silent audit  deny=3  
           unlock_time=600
    auth   sufficient    pam_unix.so nullok try_first_pass
    auth   [default=die] pam_faillock.so authfail audit deny=3  
           unlock_time=600
    auth   requisite     pam_succeed_if.so uid >= 1000  quiet_success
    auth   required      pam_deny.so
    
    
  11. 更新 account 行组,使其如下所示。第二行已被添加,包含 pam_faillock 到账户堆栈中:

    account  required   pam_unix.so
    account  required   pam_faillock.so
    account  sufficient pam_localuser.com
    account  sufficient pam_succeed_if.so uid < 1000 quiet
    account  required   pam_permit.so
    
    

    注意

    在更新 password-authsystem-auth 文件时要小心。模块在堆栈中的排列顺序是非常重要的!

  12. 保存更改并关闭文件。然后重复步骤 9 到 11,操作文件 /etc/pam.d/system-auth

它是如何工作的...

正确配置本地账户的认证要求是一个略显零散的过程。首先,有传统的 Unix 密码文件(/etc/passwd/etc/groups)以及 shadow-utils 包,它提供了阴影支持(/etc/shadow)。这些一起构成了本地账户凭证的核心数据库。此外,类似于大多数现代 Linux 系统,CentOS 使用 PAM,这是一个可插拔认证模块的集合。PAM 堆栈默认配置为在阴影文件中查找账户信息,但它还提供了额外的功能,PAM-aware 程序可以利用这些功能,例如密码强度检查。作为管理员,你需要负责配置这些服务,确保它们能够协同工作,并且符合组织所设定的安全标准。

在这个方案中,我们首先更新了 /etc/logins.def 中的密码过期相关控制:

PASS_MAX_DAYS  90
PASS_MIN_DAYS  0
PASS_MIN_LEN   8
PASS_WARN_AGE  15

PASS_MAX_DAYS 定义了密码必须更改之前允许经过的最大时间。将该值设置为 90,表示用户必须每 90 天至少更改一次密码。PASS_MIN_DAYS 定义了用户在更改密码后必须等待多少天才能再次更改。由于该值为 0,用户可以随时更改密码——如果他们愿意,甚至可以一天多次更改密码。PASS_WARN_AGE 定义了当 PASS_MAX_DAYS 接近时,用户将提前多少天收到密码即将过期的通知。

注意

PASS_MIN_LEN 应该设置密码的最小长度,但你会发现 PAM 的密码复杂度要求会覆盖这个设置,使得该设置几乎毫无意义。

useradd 等工具在创建密码和影子文件中的条目时,会使用这些设置作为默认值。它们不会回溯应用到现有用户,因此我们需要使用chage来更新他们的账户:

chage --maxdays 90 --mindays 0 --warndays 15 tboronczyk

chage 可以设置用户密码的最小和最大有效期以及即将过期的通知窗口,但请注意没有最小长度的要求。

我们还可以使用 chage 让用户的密码立即过期,这样他们下次登录时必须指定新密码。为此,我们提供 --lastdays 参数并设置为 0:

chage --lastdays 0 tboronczyk

提示

如果你有多个账户,可能想通过一些简单的 Shell 脚本来自动化使用 chage。这里有一系列的命令通过管道连接,能够以自动化的方式更新所有现有的用户账户:

getent shadow | awk -F : 'substr($2, 0, 1) == "$" { print $1 }' | xargs -n 1 chage --maxdays 90 --mindays 0  
--warndays 15

该方法通过获取影子文件的内容,并使用 awk: 为字段分隔符拆分每条记录。awk 查看第二个字段(加密密码)的值,看看它是否以 $ 开头,表示账户有密码,以此来筛选出没有密码的禁用账户和系统账户。每个匹配记录中的用户名随后被传递给 xargs,然后 xargs 将用户名逐个传递给 chage

由于 PAM 模块 pam_pwquality 检查密码的复杂度,我们在该模块的配置文件 /etc/security/pwquality.conf 中指定密码复杂度的要求。它通过一种信用系统来衡量密码的质量,每个字符为密码的总分加一分。这个总分必须满足或超过我们为 minlen 设置的值。

wpollock.com/AUnix2/PAM-Help.htm 页面对 pam_pwquality 如何计算密码复杂度做了很好的解释。它的算法如下:

  • 不管字符类型如何,每个密码中的字符都会加一分。

  • 每使用一个小写字母,就增加一个,最多可达 lcredit

  • 每使用一个大写字母,就增加一个,最多可达 ucredit

  • 每使用一个数字,就增加一个,最多可达 dcredit

  • 每使用一个符号,就增加一个,最多可达 ocredit

这个页面还展示了几种不同密码的复杂性计算,非常值得一读。

然后我们更新了 password-authsystem-auth 文件,以在三次不成功的登录尝试后锁定用户账户。需要配置不同的认证堆栈,因为不同的登录方法会调用不同的认证堆栈(例如通过 SSH 登录与本地登录):

auth   required      pam_env.so
auth   required      pam_faillock.so preauth silent audit deny=3    
    unlock_time=600
auth   sufficient    pam_unix.so nullok try_first_pass
auth   [default=die] pam_faillock.so authfail audit deny=3
    unlock_time=600
auth   requisite     pam_succeed_if.so uid >= 1000 quiet_success
auth   required      pam_deny.so
account  required   pam_unix.so
account  required   pam_faillock.so
account  sufficient pam_localuser.com
account  sufficient pam_succeed_if.so uid < 1000 quiet
account  required   pam_permit.so

pam_faillock 模块在认证堆栈的多个位置添加。在 auth 块中的第一次出现执行预检查(preauth),以查看账户是否已被锁定。第二次出现进行失败尝试计数(authfail)。由 deny 指定的参数是在锁定账户前允许的失败尝试次数。unlock_time 指定模块应等待的时间(以秒为单位),以解锁账户,以便进行另一次登录尝试。如示例所述,600 秒意味着用户必须等待 10 分钟才能解除锁定。模块在 account 块中的出现拒绝对已锁定账户的认证。

faillock 命令用于查看失败的登录尝试次数和解锁账户。要查看失败的尝试次数,请使用 --user 参数指定账户的用户名:

faillock --user tboronczyk

unlock_time 过去之前手动解锁账户,请使用 --reset 参数调用该命令:

faillock --user tboronczyk --reset

参见

想要了解更多关于用户账户认证和如何强制密码限制的信息,请参考以下资源:

设置新文件和目录的默认权限

Linux 的权限系统决定了用户是否能进入目录或者读取、写入或执行文件。通过设置文件和目录的权限位,可以授予或撤销不同用户和用户组的访问权限。然而,用户可能创建一个文件,并期望其他组中的用户能访问它,但是初始文件权限却阻止了这一点。为了避免这种情况,本文介绍了如何通过指定掩码值设置新文件和目录的默认权限。

准备工作

本食谱要求使用 CentOS 系统并具有管理权限,可以通过使用root帐户登录或使用sudo来获得权限。

如何操作...

按照以下步骤指定新文件和目录的默认权限:

  1. 若要全局设置掩码值,请打开/etc/profile文件:

    vi /etc/profile
    
    
  2. 在文件末尾,添加以下指令(根据需要调整值)。完成后,保存并关闭文件:

    umask 0007
    
    
  3. 若要覆盖全局掩码并为每个用户设置掩码,请打开用户的~/.bashrc文件:

    vi /home/tboronczyk/.bashrc
    
    
  4. 在文件末尾,添加以下内容(同样根据需要调整值)。然后保存并关闭文件:

    umask 0007
    
    
  5. 若要仅在当前会话期间设置掩码,请在命令提示符下执行umask命令:

    umask 0007
    
    

    注意

    您可以在命令提示符下执行umask而不提供掩码值,以查看当前的掩码值。

它是如何工作的...

本食谱介绍了设置掩码值的三种方法,该值决定了新创建的文件和目录上设置的权限。然而,要理解掩码的工作原理,您需要理解传统的读、写和执行权限系统。

Linux 文件系统中的目录和文件由用户和组所有,并为它们分配了一组权限,描述谁可以访问它们。当用户尝试访问某个资源时,系统将其所有权信息与请求访问的用户进行比较,并根据权限决定是否允许访问。

三种权限是读、写和执行。由于对每种权限的访问只能是允许或不允许这两种状态,并且这种二进制选择可以用 1 表示是,0 表示否,因此一系列的 1 和 0 可以视为位模式,每个权限在序列中有不同的位置。下图显示了如何将一系列二进制的“是”和“否”转换为人类可读的值:

它是如何工作的...

二进制值表示用户是否有权限访问某个资源

从文件或目录的角度来看,用户分为三种类型。用户要么是文件的所有者,要么是所有组的成员,要么是其他人(所有其他用户)。

该资源为每种类型的用户分配了一组权限,如下图所示:

它是如何工作的...

文件或目录的完整权限集包括三种类型的用户

这是传统 Unix 权限系统背后的逻辑,但如果你刚开始接触,它可能看起来很令人生畏,不用担心。确定用户类别的权限其实只是加法问题。从 0 开始表示完全没有访问权限。要允许读取权限,加上 4。要写入权限,加上 2。要执行权限,加上 1。这些值来源于将权限值作为二进制数在位串中查看,但它们足够容易记住。因此,要允许完全访问,我们加上 4 + 2 + 1,结果是 7。要仅允许读取和执行权限,4 + 15。你在处理权限时会越来越熟悉这些组合,渐渐地自动识别它们。

当文件被创建时,系统从 666 开始作为默认值,给予所有三个类别的用户读取和写入权限。目录从 777 开始,因为目录的执行权限使用户能够进入目录。系统接着减去创建用户的 umask 值,结果决定了资源在创建时将分配哪些权限。

假设我们创建一个新目录,并且我们的 umask 值为 0027。系统从其他用户字段中减去 7,从组字段中减去 27 - 707 - 25,因此新目录的默认权限为 750

因为我们从文件的默认值开始时少了一位,所以可能会得到一个负的权限值。如果 umask 使用 7 屏蔽了所有权限,但文件的初始值为 666,则 6 - 7-1。超出 0 是没有意义的,因此系统将其视为 0。所以,0027 的掩码会为文件的权限设置为 650

每当用户登录时,/etc/profile~/.bashrc 文件会被执行,以配置他们会话的环境。在 profile 中调用 umask 会设置所有用户的掩码。.bashrcprofile 后执行,并且是针对用户特定的,因此它对 umask 的调用会覆盖之前设置的值,为该特定用户设置掩码。

另见

有关 umask 的更多信息,请参考以下资源:

以不同用户身份运行二进制文件

在 CentOS 上,每个程序都在一个用户账户的环境中运行,无论该程序是由用户执行还是作为自动化系统进程运行。然而,有时我们希望程序在不同的限制下运行,并且访问该账户所允许的权限。例如,一个用户应该能够使用passwd命令重置他们的密码。该命令需要对/etc/passwd的写入权限,但我们不希望运行该命令的用户具有此权限。本教程将教你如何通过设置程序的 SUID 和 SGID 权限位,使其在不同用户的环境中执行。

准备工作

本教程需要一个 CentOS 系统。同时需要管理员权限,可以通过登录 root 账户或使用 sudo 来获得。

如何操作...

按照以下步骤允许程序作为不同用户执行:

  1. 使用ls命令来识别文件的所有者和组的详细信息。其输出的第三列列出了所有者,第四列列出了组:

    ls -l myscript.sh
    
    

    如何操作...

    -l 选项以长格式显示文件列表,其中包括所有权信息

  2. 如果需要,使用chown命令更改文件的所有权,使文件的所有者是你希望脚本在其环境中执行的用户:

    chown newuser:newgroup myscript.sh
    
    
  3. 设置 SUID 位,以允许程序像由其所有者调用一样执行:

    chmod u+s myscript.sh
    
    
  4. 设置 SGID 位,以允许程序像由其组成员调用一样执行:

    chmod g+s myscript.sh
    
    

工作原理...

当文件的 SUID 和 SGID 位被设置时,程序将在其所有者或组的环境中运行,而不是调用它的用户的环境中。这通常应用于需要普通用户能够访问的管理程序,但程序本身需要管理权限才能正常工作。

使用chown设置权限位时,u用于设置目标为 SUID 位。设置了 SUID 位的脚本将以其所有者的权限执行。g用于设置目标为 SGID 位,允许脚本以其组成员的权限执行。直观地,+表示设置该位,-表示移除该位,从而使程序可以在调用用户的环境中执行。

chmod u-s myscript.sh
chmod g-s myscript.sh

SUID 和 SGID 也可以用数字方式设置——SUID 的值是 4,SGID 的值是 2。这些可以相加并作为数字权限值的最左侧数字出现。例如,以下命令设置了 SUID 位、文件所有者的读、写和执行位;组成员的读、写和执行位;以及其他所有人的读和执行位:

chmod 4775 myscript.sh

然而,数字方法要求你指定文件的所有权限。如果你需要这样做,并且希望同时设置 SUID 或 SGID 位,这并不成问题。否则,使用+-来添加或删除所需的位可能更加方便。

使用chmod的助记字符设置位也适用于标准权限。uga分别表示目标位的所有者(u 代表用户)、组(g 代表组)和其他所有人(a 代表所有)。读取权限用r表示,写入权限用w表示,执行权限用x表示。以下是使用助记字符的一些示例:

  • 允许文件所有者执行该文件:

    chmod o+x myscript.sh
    
    
  • 允许组成员读取文件:

    chmod g+r myfile.txt
    
    
  • 防止非所有者或组成员写入文件:

    chmod a-w readonly.txt
    
    

另见

参考以下资源了解有关chmod以及设置 SUID 和 SGID 位的更多信息。

使用 SELinux 提高安全性

本教程展示了如何使用安全增强 Linux(SELinux)的基础知识,SELinux 是一个内核扩展,为您的 CentOS 安装增加了一层额外的安全性。由于它在内核级别运行,SELinux 可以控制传统文件系统权限之外的访问,包括限制正在运行的进程和其他资源。

不幸的是,一些管理员禁用了 SELinux,因为诚然它可能成为挫折的源头。管理员们习惯了用户/组/所有人以及读取/写入/执行的方式,突然发现当 SELinux 阻止本应可用的内容时,他们无从下手。然而,SELinux 提供的额外安全层是值得投入精力调查此类问题并在必要时调整其策略的。

准备工作

本教程要求使用 CentOS 系统。同时也需要管理员权限,可以通过以root账户登录或使用sudo命令获得。示范的命令来自policycoreutils-python包,因此请先使用yum install policycoreutils-python命令安装该包。

如何操作...

本集合命令将带您了解在不同上下文中使用 SELinux,具体如下:

  • 使用sestatus验证 SELinux 是否启用,并查看加载了哪个策略:如何操作...

    该系统已启用 SELinux,并当前强制执行目标策略。

  • 使用id -Z查看您的账户映射到的 SELinux 账户、角色和域。

  • 使用ls -Z查看文件或目录的安全上下文:如何操作...

    idls都可以显示与安全上下文相关的信息

  • 使用semodule -l查看当前策略中加载的策略模块列表。输出内容可能非常长,您可能会发现使用lessmore分页查看会更方便:

    semodule -l | less
    
    
  • 使用semodule -d并提供模块名称来禁用特定的策略模块:

    semodule -d mysql
    
    

你可以通过再次使用semodule -l查看策略模块的列表来验证模块是否被禁用。disabled一词应该会出现在模块名称的右侧。

  • 使用semodule -e来启用特定的策略模块:

    semodule -e mysql
    
    
  • 使用semanage boolean可以选择性地启用或禁用活动模块的特性。-l参数会输出可用特性的列表及其当前值和默认值:

    semanage boolean -l | less
    
    
  • 使用-m后跟--on--off及特性名称来影响所需的特性:

    semanage boolean -m --on deny_ptrace
    
    

    如何操作...

    semanage boolean -l显示策略模块中可以开启或关闭的特性。

它是如何工作的…

SELinux 从对象、主体、域和类型的角度来查看系统。对象是任何资源,无论是文件、目录、网络端口、内存空间等。主体是对对象进行操作的任何实体,如用户或正在运行的程序。域是主体操作的环境,换句话说,是主体可用资源的集合。类型仅仅是识别对象用途的类别。在这个框架下,SELinux 的安全策略将对象组织成角色,并将角色组织到域中。

域被授予或拒绝访问特定类型。例如,用户被允许打开某个特定文件,因为他们属于一个在该域中有权限打开该类型对象的角色。为了判断一个用户是否有能力做某事,SELinux 会将系统的用户账户映射到它自己数据库中的用户(以及角色和域)。默认情况下,账户会映射到 SELinux 的unconfined_u用户,后者被分配了unconfined_r角色并操作于unconfined_t域。

这个例子向我们展示了如何使用id -Z来获取我们用户账户映射到的用户、角色和域,以及如何使用ls -Z来获取文件的安全标签。当然,命令显示的值会根据文件不同而有所不同。例如,二进制文件/bin/cp作为system_u用户执行,属于object_r角色,并在bin_t域中。

sestatus命令输出关于 SELinux 的基本状态信息,例如是否启用、是否强制执行其策略,以及如何执行这些策略。SELinux 可以运行在强制模式下,在这种模式下它会积极地执行其策略;也可以运行在宽容模式下,在这种模式下它不会阻止任何操作,但如果某个操作本应被策略阻止,它会记录一条日志。你可以使用setenforce 0将 SELinux 设置为宽容模式。

semodule 命令用于管理策略模块。为了保持一切井然有序,策略是模块的集合,每个模块关注一个特定的程序或活动。针对最常见的应用程序(如 MySQL、Apache HTTP 服务器和 SSHd)有专门的模块,这些模块描述了哪些域可以访问哪些类型。这个教程展示了如何使用 semodule-e-d 参数启用或禁用这些模块:

semodule -d mysql
semodule -e mysql

最后,教程介绍了 semanage 命令,它用于管理 SELinux 的各个方面。我们看到了它的 boolean 子命令,使用它来列出可以切换开关的特定保护项。

这可能无需多说,尽管 SELinux 通过增加额外的访问控制层来有效保护系统,但完全理解它并编写自定义策略是一项严肃的任务。关于这个主题已经写了整本书,并且在线上有大量的资源可供使用。作为入门,Red Hat Enterprise Linux 7 文档中包含的 SELinux 用户和管理员指南以及 DigitalOcean 提供的三部分系列文章,介绍了 SELinux 的基本概念,都是非常好的起点,我已经在这里列出了它们的 URL。我还推荐由 David Caplan、Karl MacMillan 和 Frank Mayer 合著的书籍《SELinux by Example: Using Security Enhanced Linux》。

另见

有关使用和更好理解 SELinux 的更多信息,请参考以下资源:

第四章:软件安装管理

本章包含以下操作:

  • 注册 EPEL 和 Remi 仓库

  • 使用 Priorities 插件优先级设置仓库

  • 使用 yum-cron 自动更新软件

  • 验证已安装的 RPM 包

  • 从源代码编译程序

介绍

本章提供了在 CentOS 系统上管理软件安装的具体操作方法。你将学习如何添加新的软件包仓库,以提供比主 CentOS 仓库更多的软件选择,同时也能了解如何优先排序仓库,从中选择安装软件包的源。你还将学习如何自动更新软件,以便跟上最新的安全补丁和错误修复,如何验证已安装的软件包,以确保恶意用户未篡改你的软件。最后,你将掌握一项逐渐消失但对于修改系统中开源软件至关重要的技能:如何从源代码编译软件。

注册 EPEL 和 Remi 仓库

一个全新安装的 CentOS 系统将启用主支持仓库,通过这些仓库我们可以安装各种软件。我们还可以注册第三方仓库,以便获取更多(或更新的)软件。本教程将教你如何添加两个这样的仓库,分别是流行的 企业 Linux 扩展包(EPEL) 和 Remi 仓库。

准备工作

本教程需要一个具有工作网络连接的 CentOS 系统。还需要管理员权限,可以通过使用 root 账户登录或使用 sudo 来实现。

如何操作...

要注册 EPEL 仓库,请安装 epel-release 包:

yum install epel-release

注册并启用 REMI 仓库,请按照以下步骤操作:

  1. 下载仓库的配置包:

    curl -O http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
    
    
  2. 安装下载的包:

    yum install remi-release-7.rpm
    
    
  3. 删除文件,因为它已不再需要:

    rm remi-release-7.rpm
    
    
  4. 打开 Remi 仓库的配置文件:

     vi /etc/yum.repos.d/remi.repo 
    
    
  5. [remi] 部分找到 enabled 选项,并将其值更改为 1 以启用它:

    enabled=1
    
    
  6. 保存更改并关闭文件。

工作原理...

EPEL 仓库托管着与官方 CentOS 仓库互补的软件包。通过安装官方仓库中提供的 epel-release 包,可以自动配置它:

yum install epel-release

Remi 是一个流行的第三方仓库,提供官方仓库中没有的更新版本软件。我们通过 curl 从项目服务器下载了仓库的配置包:

curl -O http://rpms.famillecollet.com/enterprise/remi-release-7.rpm

我们使用了 -O 参数(大写字母 O,而不是数字 0),这样文件会保存到磁盘,否则其内容将显示在屏幕上。本教程没有指定应下载文件的具体目录。你可以将文件下载到你的 home 目录,甚至是 /tmp 目录,因为安装软件包后该文件不再需要。

在下载软件包后,我们可以使用 yum 安装它:

yum install remi-release-7.rpm

注意

很多时候,完成同一任务有多种方式。例如,rpm 命令也可以在下载包后用来安装软件包:

**rpm -iv remi-release-7.rpm**

-i 参数安装软件包,而 -v 指示 rpm 在输出中提供详细信息,以便我们可以看到它的操作。

remi-release 包安装了三个 Remi 仓库的配置:Remi、Safe Remi 和 Remi 的 PHP 7 仓库。默认情况下启用 Safe Remi,因为它的软件包被认为可以与官方 CentOS-Base 仓库一起使用。然而,Remi 仓库是禁用的,所以我们需要编辑 /etc/yum.repos.d/remi.repo

它是如何工作的...

通过更新配置文件来启用 Remi 仓库

REMI 以提供 PHP 的较新版本而闻名。如果你想通过 Remi 升级现有的 PHP 安装,可以在 remi.reporemi-php70.repo 中启用所需的部分。

安装了 EPEL 仓库并启用了 Remi 仓库后,你可以使用 yum 来列出可用的仓库。EPEL 和 Remi 仓库应该会出现在输出中:

yum repolist

它是如何工作的...

EPEL 和 Remi 仓库已启用并准备就绪!

小贴士

Remi 使用与官方 CentOS 仓库中相同的软件包名称。与 Remi 类似,IUS 仓库提供了官方仓库中较新的软件版本,但使用了不同的软件包名称。一些托管服务提供商推荐使用 IUS 而不是 Remi,因为他们会每晚更新服务器,而不同的软件包名称有助于防止计划外的升级。如果你与这样的服务提供商签订了合同并且没有使用 Priorities 插件(将在下一个配方中讨论),请务必听从他们的建议。有关 IUS 的更多信息,请访问他们的官方网站,ius.io/

另请参阅

有关 EPEL 和 Remi 仓库的更多信息,请参考以下资源:

使用 Priorities 插件对仓库进行优先级排序

尽管软件包管理器使安装和更新软件几乎变得不费吹灰之力,但如果我们不小心,仍然可能会遇到一些问题。例如,我们可以配置多个仓库,包括 CentOS 不维护的第三方仓库,而一个仓库中的软件包版本可能与另一个仓库中的版本发生冲突。本配方使用 Priorities 插件来对我们使用的仓库进行优先级排序,帮助避免这些问题。

准备工作

本食谱需要一个有正常网络连接的 CentOS 系统。还需要管理员权限,可以通过登录 root 账户或使用 sudo 来获得。

如何操作...

按照以下步骤优先排序 yum 下载软件的仓库:

  1. 使用文本编辑器打开 /etc/yum.conf 文件。找到 plugins 选项,并确认其值设置为 1 以启用插件支持。如有必要,更新其值:

    plugins = 1
    
    
  2. 安装 yum-plugin-priorities 包:

    yum install yum-plugin-priorities
    
    
  3. 要设置仓库的优先级,请打开其相应的配置文件,该文件位于 /etc/yum.repos.d 目录下。在每个所需部分中添加 priority 选项作为新条目:

    priority=10
    
    
  4. 完成后,保存并关闭仓库的配置文件。如何操作...

    CentOS-Base 仓库为基础软件包分配了相对较高的优先级

它是如何工作的...

在本食谱中,我们安装了 Priorities 插件并通过更新仓库配置文件来优先排序仓库。通过优先排序一个仓库,我们可以更轻松地控制系统中安装的软件包和版本。

首先,我们检查了 Yum 的插件支持是否已启用。我们打开了它的配置文件 /etc/yum.conf 并验证了 plugins 选项的值:

plugins = 1

接下来,我们安装了 yum-plugin-priorities 包:

yum install yum-plugin-priorities

Priorities 插件有一个最小的配置文件,位于 /etc/yum/plugins/priorities.conf。在该文件中,enabled 选项让我们可以切换插件是否启用。这意味着我们可以根据需要对仓库进行优先级设置,但也可以在不删除和重新添加仓库配置文件中的优先级值的情况下,暂时禁用优先级设置:

enabled = 1

最后一步是编辑 /etc/yum.repos.d 目录下的仓库配置文件。每个仓库都有自己的配置文件,例如,CentOS-Base 仓库的文件是 /etc/yum.repos.d/CentOS-Base.repo,该文件配置了每个频道的连接和安全密钥。为了优先排序仓库,我们只需打开所需的文件,并在所需的部分添加 priority 选项的新行:

priority = 10

优先级以 199 范围内的数字来分配,其中 1 为最高优先级,99 为最低优先级。任何我们没有明确设置优先级的仓库或频道将默认使用优先级 99。本应一起使用的仓库(例如 EPEL 和 Remi)可以分配相同的优先级。

注意

不要使用连续的优先级数字,如 1、2、3...。例如,设置优先级为 5、10、15... 或 10、20、30...,可以让你稍后添加其他仓库,而无需重新排序现有仓库的优先级。

当分配并启用优先级时,当我们尝试安装或更新一个在多个仓库中都能找到的软件包时,系统会从具有最高优先级的仓库中获取该软件包。通过这种方式,我们可以控制第三方仓库是否可以替代重要的基础包,或者在高度定制的系统上,来自 CentOS 支持仓库的更新是否可以替代第三方软件包。

另见

请参考 CentOS Wiki 上的yum-plugin-priorities文章,了解更多有关 Priorities 插件的信息,链接:wiki.centos.org/PackageManagement/Yum/Priorities

使用 yum-cron 自动化软件更新

我们都知道及时跟进安全警报和应用重要更新的重要性,但确保 CentOS 系统上的所有软件都得到更新可能是一项繁琐且耗时的任务,特别是当你管理多个服务器时。本教程展示了如何通过自动化更新过程来确保系统始终保持最新,无需每天手动操作。

准备工作

本教程需要一个具有正常网络连接的 CentOS 系统。同时,您需要具有管理员权限,可以通过root账户登录或使用sudo来获得权限。

如何操作...

要使用yum-cron自动化软件更新,请执行以下步骤:

  1. 安装yum-cron软件包:

    yum install yum yum-cron
    
    
  2. 启动并启用该服务:

    systemctl start yum-cron
    systemctl enable yum-cron
    
    
  3. 执行系统更新,确保在yum-cron接管之前,系统所有内容都是最新的:

    yum update
    
    

它是如何工作的……

我们的第一步是安装yum-cron软件包,但你会注意到,这个操作还会更新 Yum 本身。虽然我们只需要指定yum-cron,但包含yum可以绕过一个特定的版本问题(你可以在bugzilla.redhat.com/show_bug.cgi?id=1293713上查看该错误报告):

yum install yum yum-cron

该软件包安装了yum-cron命令,并且设置了一个每天触发它的定时任务(cron job),同时还包括一个systemctl单元,用于启用和禁用更新。通过systemctl启动该服务时,会创建一个特殊的锁文件。Cron 每天运行这个定时任务来调用yum-cron,该命令检查锁文件是否存在。如果文件存在,它会检查更新;否则,它会知道每日更新被禁用(服务被停止),并且不执行任何操作。

/etc/yum中的yum-cron.config配置文件可以用于修改yum-cron的总体行为。最重要的选项是update_cmd,因为它允许我们指定执行的更新类型。yum-cron可以执行不同的更新策略,如果你希望进行更有针对性的更新而不是默认设置,可以更改update_cmd选项的值。

执行不同角色的服务器可能需要不同的更新策略;例如,你可能只希望在生产服务器上应用关键的安全更新,而将其他软件保持在特定版本。配置文件中的注释列出了 update_cmd 的有效值及其含义。default 执行一般的系统范围更新,而像 security 这样的值则仅应用与安全相关的更新:

update_cmd = security

yum-cron.conf 中,还可以看到 emit_via 选项。stdio 值表示 yum-cron 生成的任何日志信息都将通过标准输出传递。通常,这些信息会被 cron 捕获并写入 /var/log/cron。Cron 可以配置为通过电子邮件发送输出,但你也可以特别配置 yum-cron 发送邮件。如果你希望 yum-cron 将输出发送给你,请将 emit_via 的值更改为 email,并将 email_to 的值设置为你的电子邮件地址:

emit_via = email
email_to = tboronczyk@example.com

工作原理...

yum-cron 的配置文件允许我们指定特定的更新策略和通知选项

另请参阅

请参考以下资源,了解有关自动化软件更新的更多信息:

验证已安装的 RPM 包

有人说最安全的系统就是 “关闭电源,浇筑在混凝土块中,并密封在一个有武装守卫的铅隔离室里。”(Gene Spafford)你的 CentOS 系统可能没有混凝土保护,这意味着它存在被攻击的风险。本教程将展示如何使用 rpm 审计系统,以确保已安装的软件没有被攻击者篡改。

准备就绪

该教程需要一个具有工作网络连接的 CentOS 系统。还需要管理员权限,可以通过登录 root 账户或使用 sudo 来获得权限。

如何操作...

首先备份 /var/lib/rpm 目录中的 RPM 数据库非常重要。虽然有多种方法可以做到这一点,但为了这个例子,我们将创建该目录的 ISO 镜像,然后可以将其归档或刻录到光盘:

  1. 安装 genisoimagewodim 软件包,获取创建 ISO 镜像和刻录光盘所需的工具:

    yum install genisoimage wodim
    
    
  2. 使用 genisoimage 创建 ISO 镜像:

    genisoimage -o rpm-db-bckup.iso -R -v /var/lib/rpm
    
    

    如果需要,可以使用 wodim 刻录镜像:

    wodim -v dev=/dev/cdrom rpm-db-bckup.iso
    
    

如果以后不打算使用,可以在将 ISO 文件刻录到光盘后删除它。

当需要验证你的系统时,按照以下步骤操作:

  1. 使备份数据库可用。如果你已经将 ISO 文件刻录到光盘,并且假设它位于 /dev/cdrom,使用 mount 如下:

    mount /media /dev/cdrom
    
    
  2. 如果备份是 ISO 文件,使用 mount 如下:

    mount -o loop rpm-db-bckup.iso /media
    
    
  3. 验证安装的 rpm 软件包与备份的数据库副本的完整性。rpm 会返回与原始软件包不同的文件列表,因此成功的审计应没有输出:

    rpm -V --dbpath=/media rpm
    
    
  4. 验证系统上安装的所有软件包的完整性:

    rpm -Va --dbpath=/media
    
    

它是如何工作的…

攻击者可以篡改文件并用恶意副本替换系统上的程序。幸运的是,我们可以使用 rpm 来验证从软件包安装的文件的完整性,从而识别这些更改。但是,为了做到这一点,我们还需要一个可以信任的数据库。用于比较文件详细信息的数据库的完整性非常重要,因为聪明的攻击者也可能会想到在那里进行修改。定期制作数据库的只读备份非常重要,或许在每次安装新软件包或更新之前和之后都应该进行备份。然后,你可以将系统软件的状态与可信备份进行比较,从而对结果充满信心。

你可以将备份存储到任何介质上:可移动的 USB 闪存驱动器、可写的 CD 或 DVD 光盘、远程存储,甚至是高容量磁带盒。重要的是它是可信的。这个配方演示了如何将 /var/lib/rpm 数据库备份为 ISO 文件,可以将其刻录到光盘上或按原样复制,必要时以只读模式挂载。

genisoimage -o rpm-db-bckup.iso -R -v /var/lib/rpm

注意

长期使用 Linux 的用户可能会记得 mkisofscdrecord 程序。genisoimagecdrecord 是它们的克隆程序,前者仍然以符号链接的形式存在于 CentOS 中,指向 genisoimagecdrecord

-o 参数指定将创建的 ISO 文件的名称。-R 创建必要的索引以保留镜像中文件名的长度和大小写,而 -v 表示 genisoimage 应以详细模式运行,以便我们能看到它的进度。完成后,我们将得到 rpm-db-backup.iso 文件。

注意

如果你打算将文件刻录到光盘并删除它,rpm-db-bckup.iso 是一个合适的名称。如果你打算将 ISO 文件归档,则应考虑在名称中包含备份创建的时间戳,以便保持有序。例如,以下命令使用 date 将日期和时间包含在文件名中:

**genisoimage -o rpm-db-bckup-$(date +"%Y-%m-%d_%H%M").iso -R -v /var/lib/rpm**

接下来,配方展示了如何使用 wodim 将 ISO 文件刻录到光盘:

wodim -v dev=/dev/cdrom rpm-db-bckup.iso

-v 参数将 wodim 设置为详细模式,dev 参数指定 CD/DVD 驱动器。配方假设 /dev/cdrom 是适当的设备,你可能需要根据系统的配置修改命令。

为了使可信数据库可用,我们挂载了光盘或 ISO 文件。要挂载光盘,我们将光盘放入驱动器并发出以下命令(/dev/cdrom 是设备,/media 是文件系统将挂载的挂载点):

mount /dev/cdrom /media

要挂载 ISO 文件,我们发出以下命令:

mount -o loop rpm-db-bckup.iso /media

在可信数据库可用后,我们使用带有 -V 选项的 rpm,该选项用于验证已安装的包。默认情况下,rpm 使用 /var/lib/rpm 中的文件作为数据库,因此我们使用 --dbpath 选项覆盖这一设置,并指向我们的可信副本:

rpm -V -dbpath=/media rpm

虽然我们可以提供一个或多个包名进行检查,-a 选项将会验证系统上所有已安装的包:

rpm -Va --dbpath=/media

rpm 会通过一系列测试,检查文件的大小及其权限,并报告那些未通过测试的文件。没有输出表示系统上安装的文件与最初由包安装时完全一致。否则,rpm 会显示一个点表示通过的测试,并使用以下记忆性指示符之一来显示哪些测试未通过:

  • S:文件的大小已更改

  • M:文件的权限已更改

  • 5:文件的 MD5 校验和与预期的校验和不匹配

  • L:符号链接已更改

  • D:设备已更改

  • U:文件的用户所有者已更改

  • G:文件的所属组已更改

  • T:文件的时间戳已更改

rpm 还会报告如果文件丢失的情况。

然而,并不是所有的差异都是坏的。我们需要知道哪些更改是可接受的,哪些不是。例如,配置文件的更改可能是可接受的,但二进制工具的更改无疑是问题的指示。rpm 通过在测试结果旁列出 c 来区分配置文件,这有助于我们将其与其他类型的文件区分开:

工作原理...

在验证该系统包的完整性时,会报告差异

另见

参考以下资源获取更多关于验证已安装软件完整性的信息:

从源代码编译程序

现代的包管理工具使得安装软件变得容易;只需一个命令,我们就能从任意配置的仓库中安装程序及其依赖项。然而,Linux 社区和自由软件运动中的一个重要价值是根据自己的需求修改软件(也许你想修复一个 bug 或添加一个新功能)。对于用编译语言编写的软件,如 C,这通常意味着修改程序的源代码,并将代码编译成可执行的二进制文件。此教程将引导你完成编译并安装 GNU Hello 程序的过程。

正在准备中

本步骤要求 CentOS 系统有可用的网络连接,并且需要一个能够使用sudo提升权限的非特权用户账户。

如何操作...

执行以下步骤从源代码编译和安装程序:

  1. 使用sudo提升账户权限,安装gcc包:

    sudo yum install gcc
    
    
  2. 下载 GNU Hello 源代码:

    curl ftp://ftp.gnu.org/gnu/hello/hello-2.10.tar.gz | tar - zx
    
    
  3. 进入项目的目录:

    cd hello-2.10
    
    
  4. 使用--help参数运行configure脚本,以查看项目的构建选项。输出内容可能会非常长,您可能会发现使用less分页查看内容更为方便:

    ./configure --help | less
    
    
  5. 再次运行configure脚本,这次指定任何需要的构建选项来生成Makefile文件:

    ./configure --prefix=/usr/local
    
    
  6. 调用make,它使用Makefile作为指南来编译项目:

    make
    
    
  7. 使用sudo再次提升权限,安装程序及其支持文件:

    sudo make install
    
    
  8. 现在,我们可以运行hello程序来显示友好的问候:

    hello
    
    

工作原理...

本步骤向您展示了从源代码编译和安装软件的经典configuremakemake install过程。

最小化的 CentOS 安装不包括 C 编译器(一个将 C 语言源代码翻译成二进制机器可执行格式的程序),因此我们做的第一件事就是安装 GNU 编译器集合。因为该软件包将在全系统范围内安装,所以需要使用提升的权限来运行yum

sudo yum install gcc

注意

由于 GNU Hello 项目是用 C 语言编写的,并且包括一个预生成的configure脚本,因此只需要gcc即可。不过,其他项目可能需要额外的软件,如autoconf来生成configure脚本,或其他语言(如 Fortran、C++、Objective-C 和 Go)的编译器支持。为了获得更强大的构建环境,可以考虑安装Development Tools包组:

**sudo yum groupinstall "Development Tools"**

接下来,我们从项目的 FTP 服务器下载了源代码的副本。该代码以压缩档案的形式分发,我们使用curl获取了该档案。我们省略了在之前的步骤中使用的-O参数,而是将输出直接传递给tar进行解压。这会创建一个名为hello-2.10的目录,里面包含项目的源代码:

curl ftp://ftp.gnu.org/gnu/hello/hello-2.10.tar.gz | tar -zx

项目中通常会包含几个信息性文本文件,因此可以随意查看目录中的内容。一些常见的文件包括:

  • README: 该文件提供了项目的概述(名称、版本、描述等)

  • CHANGELOG: 该文件列出了每个版本中的更改

  • INSTALL: 该文件包含安装说明

  • LICENCE: 该文件包含关于项目代码使用和分发的许可信息

如果项目使用 GNU Autotools 构建系统(如 GNU Hello 所用),我们可以预期在源文件集中找到configure脚本。configure的任务是扫描系统的构建环境,以确保任何必要的工具和依赖项可用,并生成Makefile文件。Makefile将包含编译和安装程序的指令,我们传递给configure的任何选项最终都会被包含进Makefile中。

为了查看我们可以使用的选项,我们首先运行configure并使用--help

./configure --help | less

有些选项可能是项目特有的,而其他一些则更为通用,涉及设置路径等,这些将在构建过程的后续部分使用。以下是一些重要的通用选项:

  • --prefix:程序及其文件将安装的基础目录结构

  • --disable-FEATURE:在不启用目标功能的情况下编译程序,否则该功能将被启用

  • --enable-FEATURE:在编译程序时启用可选目标功能

  • --with-PACKAGE:链接到某些功能所需的特定库

第二次运行configure时,我们提供了--prefix选项:

./configure --prefix=/usr/local

/usr/local的前缀值意味着这个目录将被加到不同文件安装路径的前面。例如,当我们安装程序时,编译后的hello文件将被复制到PREFIX/bin,即/usr/local/bin,项目的手册页面将安装到PREFIX/share/man,即/usr/local/share/man,等等。

注意

这个过程将 GNU Hello 作为系统范围内可访问的程序安装。但别忘了,你也可以使用--prefix选项将文件编译并安装到个人目录:

**./configure --prefix=/home/tboronczyk/.personal**

一旦configure生成了Makefile,我们就执行这些语句来用make编译项目:

make

默认情况下,make会在当前目录中查找名为Makefile的文件并执行。如果由于某种原因目标脚本命名不同,我们可以通过-f选项告诉make使用哪个文件:

make -f ./Makefile

此外,Makefile文件通常包含多个指令集或目标。以下是一些常见的目标:

  • all:编译程序

  • check:运行附带的测试套件,验证项目是否正常运行

  • clean:删除在编译过程中创建的任何中间文件

  • distclean:删除在配置过程或编译过程中创建的文件,仅保留原始发行版中的文件

  • dist:创建一个归档文件以分发程序

  • install:将编译后的程序和其他必要文件安装到系统的最终位置

  • uninstall:删除install安装的文件

如果未提供目标,默认目标是all

理想情况下,我们不希望以root身份编译软件,因为Makefile可以在任何位置创建任意文件,这是攻击者可以利用的一个点。以普通用户身份执行文件可以简单地阻止此攻击向量,因为非特权帐户没有对敏感目录的写访问权限。这就是为什么在将程序及其文件移动到/usr/local目录下时,我们仅为install目标使用sudo的原因。

另见

有关构建软件的更多信息,请参考以下资源:

第五章:管理文件系统和存储

本章包含以下食谱:

  • 查看文件大小和可用存储

  • 为用户和组设置存储限制

  • 创建 RAM 磁盘

  • 创建 RAID

  • 在 RAID 中更换设备

  • 创建新的 LVM 卷

  • 删除现有的 LVM 卷

  • 添加存储并扩展 LVM 卷

  • 使用 LVM 快照

介绍

本章中的食谱侧重于利用您的 CentOS 系统存储来保持可用性、提高可靠性,并保护数据免受不可避免的磁盘故障。您将学习如何确定文件占用了多少空间,以及还有多少存储空间可用。接着,您将看到如何设置限制,以确保用户公平使用系统的存储资源。我们还将创建一个 RAM 磁盘,这是一个基于内存的低延迟存储,用于频繁访问的数据。然后,您将学习如何创建和管理 RAID 阵列,以提供可靠的存储,以及如何使用 LVM 卷从存储池中分配逻辑驱动器,以更好地利用系统的总存储容量。

查看文件大小和可用存储

当存储空间紧张时,程序和服务可能会表现出意外行为或完全停止工作,因此了解系统中可用的空间非常重要。本篇介绍了一些命令,用于确定文件和目录的大小,以及已使用和可用的存储空间。

准备工作

本食谱需要一个正常工作的 CentOS 系统。根据您要检查的目录和文件的权限,可能需要管理员权限。

如何操作...

  • 要显示已挂载文件系统的存储容量,请使用df命令:

    df -h /
    
    
  • 要查看文件的大小,请使用ls命令:

    ls -sh file.txt
    
    
  • 要确定一个目录的大小(即其所有文件大小的总和),请使用du命令:

    du -sh ~
    
    

如何工作...

df命令返回有关已挂载文件系统上可用空间的信息。前面的示例请求了有关根文件系统的详细信息。

df -h /

-h参数将信息格式化为人类可读的格式,按兆字节、吉字节等显示值,而不是块计数。当没有任何参数时,df会以 512 字节的块计数显示所有已挂载文件系统的信息。我们可以使用此命令指定一个或多个挂载点,此时df只会报告这些文件系统的信息。

如何工作...

以兆字节和吉字节呈现的值比块计数提供了更多信息

输出的第一列标记为 Filesystem,最后一列标记为 Mounted on,分别标识文件系统及其挂载点。Size 列显示文件系统提供的总空间。Used 列显示该空间已占用的部分,Avail 列显示剩余可用空间。Use% 列显示占用空间的百分比。

虽然 df 给了我们总体存储使用情况的概览,但要查看单个文件的大小,我们可以使用 ls。该命令支持大量参数,可以显示文件和目录的元信息,例如所有者详情、创建时间和大小。

本教程使用了 -s 参数返回文件大小,-h 参数则再次以易读格式显示该值:

ls -hs filename.txt

如果你使用 ls 来显示目录的大小,它可能会报告 4.0 K,而不管你选择哪个目录。这是因为目录并不像我们通常想象的那样是存放文件的容器;目录实际上是一个特殊的文件,包含了一个列出其中所有文件的索引。这个索引占用了一个块的存储空间。ls 报告的是目录作为一个文件所占用的空间,而不是其中所有文件大小的总和。

要查看一个目录中所有文件的总大小,这通常是我们讨论目录大小时的目标,我们需要使用 du 命令:

du -hs ~

-s 参数仅打印当前目录的值,-h 参数则将值以易读的格式显示。没有任何参数时,du 也会显示当前目录中所有文件和目录的 512 字节块计数。然而,目录被视为容器,因此值反映了所有其包含文件的块计数。我们还可以列出一个或多个文件或目录,这样 du 只会报告这些目标的信息。通过将一个目录中的所有文件/目录作为目标并将输出通过 sort 管道处理,我们可以使用 du 来识别哪些内容占用了最多的存储空间:

du -hs ./* | sort -hr

sort-h 参数可以正确地对易读数字进行排序(例如,4.0K 小于 3M,即使在数字排序中 3 小于 4),而 -r 参数则会反转排序顺序,将最大的条目排在前面:

工作原理...

排序可以帮助识别哪些内容占用了最多的存储空间

参见

关于本教程中提到的命令的更多信息,请参考它们各自的手册页:

  • df 手册页(man 1 df

  • du 手册页(man 1 du

  • ls 手册页(man 1 ls

设置用户和组的存储限制

限制用户可使用的存储空间是有效的资源管理方式,可以确保每个人都能公平地获得资源,尤其是在多用户环境中。本教程展示了如何启用配额并按用户和组设置限制。

准备工作

本教程要求使用具有管理员权限的 CentOS 系统,管理员权限通过登录 root 账户或使用 sudo 获得。假设 /home 挂载了自己的文件系统。

如何操作...

按照以下步骤设置配额并指定存储限制:

  1. 打开 /etc/fstab 文件进行编辑:

    vi /etc/fstab
    
    
  2. 要启用用户配额,以强制基于用户账户的使用限制,请将 uquota 添加到 /home 的挂载选项中。对于组配额,添加 gquota。可以同时给出 uquotagquota 以启用两者:

    /dev/mapper/centos-home /home xfs defaults,uquota,gquota 0  0
    
    
  3. 保存更改并关闭文件。

  4. 重启系统:

    shutdown -r +5 'Reboot required for system maintenance'
    
    
  5. 系统重启后,启动 xfs_quota shell 并进入专家模式:

    xfs_quota -x /home
    
    
  6. 使用 limit 命令为用户账户设置限制:

    limit bsoft=5g bhard=6g tboronczyk
    
    
  7. 使用 quota 命令验证用户的配额限制是否已设置:

    quota -h tboronczyk
    
    
  8. 使用 limit -g 为一个组设置限制:

    limit -g bsoft=20g bhard=21g users 
    
    
  9. 使用 quota -g 验证组的限制是否已设置:

    quota -gh users
    
    
  10. 输入 quit 或按 Ctrl + D 退出 shell:

    quit
    
    

操作原理...

配额默认情况下未启用,必须在文件系统的挂载选项中显式启用。因此,我们更新了 /etc/fstab 并为 /home 添加了 uquota 和/或 gquota 选项:

/dev/mapper/centos-home /home xfs defaults,uquota,gquota 0 0

我们绝不应该卸载正在使用的文件系统,因为这样可能会导致数据损坏或丢失。因此,当我们重新挂载 /home 时,确保没有其他用户登录。如果你已经以 root 身份登录并确信只有你一个用户登录,可以使用 umount 紧接着 mount 来重新挂载文件系统。但如果其他人也登录了,最好按照本教程的建议进行重启。系统重启后,/home 会自动挂载,且配额选项将生效:

shutdown -r +5 'Reboot required for server maintenance'

接下来,我们运行了 xfs_quota 作为交互式 shell,输入命令来管理我们的配额。我们使用 -x 参数以专家模式启动 shell(管理配额所需的命令仅在专家模式下可用),并指定我们将要设置配额的文件系统挂载点:

xfs_quota -x /home

注意

传统的配额工具可以用来管理基本配额,但 xfs_quota 让我们能够利用 XFS 独有的额外配额功能。例如,使用 xfs_quota 我们还可以管理项目配额。

对我们来说,最重要的两个命令是 limitquotalimit 用于设置配额限制,quota 用于报告配额信息。

我们可以使用 limit 设置四个限制,具体如下:

  • isoft:此命令设置使用的 inode 数量的软性限制

  • ihard:此命令设置使用的 inode 数量的硬性限制

  • bsoft:此命令设置使用的块数的软性限制

  • bhard:此命令设置使用的块数的硬性限制

inode 是一种由文件系统用于跟踪文件和目录的数据结构。每个文件和目录都由一个 inode 表示,因此设置用户可以拥有的 inode 数量限制,实际上是限制他们能够拥有的文件/目录数量。

块代表物理存储,设置用户块数配额限制了他们的文件所能占用的存储空间。典型的块大小是 512 字节,这意味着存储 1KB 数据需要使用两个块。配方中的示例设置了一个 5 GB 的软块限制和 6 GB 的硬块限制。后缀 kmg 分别用于指定千字节、兆字节和吉字节的值:

limit bsoft=5g bhard=5500m tboronczyk

注意

可以在不进入交互式 Shell 的情况下,使用 -cxfs_quota 中运行命令:

**xfs_quota -x -c 'limit -u bsoft=5g tboronczyk' /home**

硬限制指定了一个用户绝对无法超过的值。例如,具有 100 个 inode 硬限制的用户,如果已有 99 个文件,只能再创建一个文件。超出此限制时,创建文件的尝试将会出错。

另一方面,软限制定义了一个用户可以在短时间内超过的限制。一旦超过限制,用户将进入宽限期。一个具有 5 GB 软限制的用户将能够使用超过 5 GB 的存储空间,但仅限于一定时间内。如果在宽限期结束时,用户仍然违反了限制,软限制将被视为硬限制,并且他们将无法再保存任何数据。

注意

宽限期默认是 7 天。我们可以通过 timer 命令来更改这一点,使用 -i 来更改 inode 计时器,使用 -b 来更改块计时器:**timer -b 3d tboronczyk**

要查看当前的配额,使用 quota 命令。-h 参数会以人类可读的格式显示值:

quota -h tboronczyk

默认输出显示了文件系统及其挂载点,以及用户的块配额详情:已使用的块数量(在Blocks标题下)、软限制(Quota)、硬限制(Limit),以及软限制违规的宽限期已过时间(Warn/Time)。使用 -i 可以获取 inode 配额的相同信息,-b-i 可以一起使用,以同时显示两组信息:

quota -bih tboronczyk

它是如何工作的...

块配额和 inode 配额可以同时显示

limitquota 命令默认与用户的配额一起工作,虽然我们可以通过 -u 参数明确管理用户的配额。要管理一个组的配额,我们使用 -g

quota -gh users

如前所述,xfs_quota 还允许我们管理项目配额。这些配额实际上是对特定目录施加的限制,不论用户或组的所有权如何,都会强制执行。要使用项目配额,请使用 pquota 挂载选项:

/dev/mapper/centos-home /home xfs defaults,uquota,pquota 0 0

注意

项目配额和组配额不能同时使用;如果同时提供 pquotagquotamount 将无法挂载文件系统。根据文件系统的不同,这可能会导致系统无法启动。

接下来,创建文件 /etc/projid。每一行是由一个任意的项目名称和一个唯一的 ID 号码组成,用冒号分隔:

echo "my_project:42" >> /etc/projid

然后,创建文件/etc/projects。其条目由项目 ID、一个分隔冒号和项目的目录组成。projectsprojid文件共同定义了项目名称与其目录之间的关系:

echo "42:/home/dev/project" >> /etc/projects

配置好这两个配置文件后,最后一步是通过project -cxfs_quota中初始化项目的配额跟踪:

project -c my_project

完成初始设置步骤后,你可以使用limitquota命令通过-p参数来管理项目的配额:

limit -p bsoft=10g bhard=11g my_project

另请参阅

参考以下资源以获取更多关于配额管理的信息:

创建 RAM 磁盘

本食谱教你如何利用 RAM 低延迟创建 RAM 磁盘,RAM 磁盘是将一部分内存当作标准存储设备来使用的内存区段。RAM 磁盘通常存储易变的数据,这些数据在内存中被不断读取和更新。例如,在桌面系统中,它们用于存储浏览器缓存,以加速网页浏览。在服务器环境中,RAM 磁盘可以存储高负载代理服务的缓存数据,从而减少延迟。

准备工作

本食谱需要一个具有管理员权限的 CentOS 系统,可以通过登录root账户或使用sudo来获得权限。

如何操作...

执行以下步骤来创建和使用 RAM 磁盘:

  1. 使用free命令检查是否有足够的内存可用于 RAM 磁盘(一个实用的 RAM 磁盘大小需要小于空闲内存的量):

    free -h
    
    
  2. 使用mount命令将tmpfs文件系统挂载到目标挂载点,并作为挂载选项指定目标大小:

    mount -t tmpfs -o size=512M tmpfs /mnt
    
    
  3. 当不再需要 RAM 磁盘时,卸载文件系统:

    umount /mnt
    
    

它是如何工作的...

每当我们访问硬盘上的数据时,它的电机必须首先旋转存储盘片,并将磁头定位到正确的位置。这些机械动作使得访问速度相较于已经驻留在系统内存(RAM)中的数据非常慢。具体的测量依赖于系统及其硬件,但磁盘访问大约需要 10 毫秒或 10,000,000 纳秒。而内存访问只需要大约 200 纳秒,因此可以安全地说,访问 RAM 的速度至少是磁盘的 10,000 倍,即便是低估值。

在创建 RAM 磁盘之前,你应该首先使用free命令检查系统上可用的空闲内存量:

free -h

free命令会显示当前可用的内存以及已使用的内存。-h参数将输出格式化为易于人类阅读的格式(将值以兆字节和吉字节列出,而不是字节)。我们可以看到有关 RAM、交换磁盘以及内核使用的任何特殊缓冲区的数字,但我们真正关心的是MemSwap条目中列出的已用和空闲内存的数量。空闲内存较少且交换空间使用量较高时,意味着我们可能没有足够的内存来创建实际的 RAM 磁盘:

工作原理...

该系统只有 1 GB 的内存,资源仅能支持相对较小的 RAM 磁盘

接下来,我们使用mount命令在指定的挂载点上提供所需的内存量。示例中使用的是/mnt,但您可以自由选择任何您认为合适的挂载点:

mount -t tmpfs -o size=512M tmpfs /mnt

调用中指定了tmpfs作为挂载设备,/mnt作为挂载点。-t指定了底层文件系统,在这种情况下是tmpfs,而-o指定了我们的文件系统挂载选项。有关tmpfs文件系统的所有可能选项,可以在mount手册页中找到,但最重要的选项是size,它设置了文件系统的所需大小。

注意

可以为size指定一个大于可用内存的值,但大多数情况下这是不推荐的。额外的数据将在内存耗尽后转移到交换空间,这将增加延迟,从而抵消使用 RAM 磁盘的好处。

请记住,RAM 磁盘作为低延迟的临时存储用于易失性数据。由于数据存储在内存中,当系统关闭或磁盘被卸载时,磁盘内容将丢失。切勿将持久数据存储在 RAM 磁盘中。

另见

请参考以下资源以了解更多关于 RAM 磁盘的信息:

创建 RAID

在本教程中,您将学习如何配置冗余磁盘阵列(RAID)。配置磁盘阵列以提供冗余存储是保护数据免受硬盘故障的极好方法。例如,如果您的数据存储在单个磁盘上,且该磁盘发生故障,那么数据将丢失。您必须更换硬盘并从最新的备份中恢复数据。但如果两个磁盘处于 RAID-1 配置中,您的数据将被镜像存储,并且当一个磁盘发生故障时,您仍然可以从正常工作的磁盘访问数据。故障不会影响数据访问,您可以在更方便的时间更换故障磁盘。

准备工作

本文档要求一个正常工作的 CentOS 系统和提升的权限。假设至少安装了两个新的磁盘(标识为 /dev/sdb/dev/sdc),我们将对其进行分区和配置。

如何操作...

执行以下步骤创建 RAID:

  1. 使用 lsblk 识别新的存储设备。

  2. 启动 cfdisk 来分区第一个驱动器:

    cfdisk -z /dev/sdb
    
    

    如何操作...

    cfdisk 提供了一个用户友好的界面,用于分区存储设备。

  3. 要创建占用整个磁盘的单个分区,请使用左右箭头键选择 New 并按 Enter 键。然后选择 Primary 并接受默认大小。

  4. 选择 Write 并在提示时键入 yes 以确认操作。选择 Quit 退出 cfdisk

  5. 重复步骤 1 到 4 来分区第二个驱动器。

  6. 安装 mdadm 软件包:

    yum install mdadm
    
    
  7. 使用 mdadm -C 创建一个新的阵列,使用两个分区。以下示例创建了一个 RAID-1(镜像)配置:

    mdadm -C md0 -l 1 -n 2 /dev/sdb1 /dev/sdc1
    
    
  8. 使用 -D 选项检查 RAID:

    mdadm -D /dev/md/md0
    
    
  9. 使用 mkfs.xfs 用 XFS 文件系统格式化 RAID:

    mkfs.xfs /dev/md/md0
    
    
  10. 挂载 RAID 以供使用:

    mount /dev/md/md0 /mnt
    
    

工作原理...

有许多方法可以配置磁盘以协同工作,特别是涉及数据镜像、条带化和奇偶校验等情况。一些配置是在硬件级别实现的,其他可以使用软件实现。本文档使用 mdadm 在 RAID 配置中设置多个磁盘,特别是 RAID-1。

存储网络行业协会标准化了几种不同的 RAID 配置。一些较常见的配置如下:

  • RAID-0:数据均匀分布在两个或更多个磁盘上。此配置不提供冗余性,阵列中的单个磁盘故障将导致数据丢失。然而,它提供了增加的性能,因为可以同时从不同的磁盘读取和写入数据。

  • RAID-1:数据在磁盘之间进行了复制。写入活动较慢,因为相同的数据必须写入每个磁盘,但该配置提供了极好的冗余性;只要至少有一个正常工作的磁盘,数据就可以访问。

  • RAID-5:数据块和奇偶校验信息分布在两个或更多个磁盘之间。如果数组的某个成员失败,可以利用另一个磁盘上的奇偶校验信息来重建丢失的数据。写入性能较慢,但读取性能增加,因为可以同时从不同的磁盘读取数据。这种配置可以抵御单个磁盘的故障,但第二个磁盘的故障将导致数据丢失。

  • RAID-6:此配置与 RAID-5 类似,但保留了额外的奇偶校验块。该阵列可以承受两个磁盘故障而不丢失数据。

还有其他标准配置(RAID-2、RAID-3 等),甚至是非标准配置,但这些在实际中很少使用。和生活中的一切一样,不同的 RAID 配置之间有权衡,选择适合你的配置将取决于你希望如何平衡冗余、容错性和延迟。

lsblk打印出附加到我们 CentOS 系统上的块设备(存储磁盘)信息,应该可以通过查看磁盘大小和没有分区的情况轻松识别新设备的名称。此过程假设新设备是/dev/sdb/dev/sdc;在运行cfdiskmdadm命令时,需根据你的系统使用适当的设备名:

它是如何工作的...

系统上安装了多个未配置的驱动器

在每个磁盘上创建一个新的主分区,完全占用其容量。此过程使用cfdisk,这是一种基于控制台的图形界面程序,用于操作分区。但是,CentOS 中还安装了其他分区工具,你可以根据自己的需求使用,例如fdisksfdiskparted

一旦磁盘完成分区,我们就可以开始配置 RAID 了。用于设置和管理 RAID 的mdadm程序可以通过yum安装:

yum install mdadm

mdadm -C创建一个新的 RAID 配置,并需要一个名称来标识它。此过程使用md0,结果是创建了设备/dev/md/md0。其他参数描述了所需的配置:

mdadm -C md0 -l 1 -n 2 /dev/sdb1 /dev/sdc1

-l(小写字母 L)选项指定标准 RAID 级别,在本例中,数字1代表 RAID-1。如果你想设置 RAID-5,则使用-l 5-n选项指定 RAID 将使用的分区数,然后列出这些分区。此过程配置了两个分区,/dev/sdb1/dev/sdc1

mdadm -D显示特定阵列的详细信息,这些信息对于检查配置和验证阵列的健康状况非常有用。输出结果列出了诸如 RAID 级别、可用存储大小、组成阵列的分区、是否有任何分区/设备发生故障、重同步状态以及其他有用的信息:

mdadm -D /dev/md/md0 

它是如何工作的...

mdadm 显示新 RAID 配置的状态

注意

mdadm -E用于获取构成阵列的一个或多个分区的信息:

**mdadm -E /dev/sdb1 /dev/sdc1**

接下来,使用mkfs.xfs命令将存储空间格式化为 XFS 文件系统:

mkfs.xfs /dev/md/md0

最后,基于 RAID 的存储空间就可以使用了。此过程展示了如何使用mount命令手动挂载存储空间,尽管你也可以在/etc/fstab中添加条目,以便在系统启动时自动挂载文件系统。

另见

有关设置 RAID 的更多信息,请参考以下资源:

在 RAID 中更换设备

当阵列成员出现故障时,尽早更换它非常重要,因为更多驱动器的故障会增加数据丢失的风险。本教程将教你如何正确地更换故障驱动器并重建阵列。

准备工作

本教程需要一个具有管理员权限的 CentOS 系统,可以通过登录 root 账户或使用 sudo 获取权限。假设已按照前一教程设置 RAID-1 配置,并且将要更换的驱动器是 /dev/sdb

如何操作...

按照以下步骤更换 RAID 中的故障磁盘:

  1. 使用 mdadm-f 选项将故障分区标记为故障:

    mdadm /dev/md/md0 -f /dev/sdb1
    
    
  2. 使用 -r 从 RAID 配置中移除分区:

    mdadm /dev/md/md0 -r /dev/sdb1
    
    
  3. 物理更换故障磁盘。

  4. 使用 cfdisk 对新磁盘进行分区:

    cfdisk -z /dev/sdb
    
    
  5. 使用 -a 选项将分区添加到 RAID:

    mdadm /dev/md/md0 -a /dev/sdb1
    
    

工作原理...

一旦发现故障,尽快更换故障成员非常重要,因为根据配置的容错能力,第二个设备的故障可能会导致完全的数据丢失。

在我们安全地移除某个成员之前,必须先将其标记为故障,因此第一步是使该分区失效。为此,我们使用了 mdadm-f 参数指定我们希望使其失效的分区:

mdadm /dev/md/md0 -f /dev/sdb1

然后,为了从 RAID 中移除分区,我们使用了 -r 参数:

mdadm /dev/md/md0 -r /dev/sdb1

现在设备不再使用时,我们可以更换物理驱动器。是否可以在系统运行时热插拔驱动器,或者是否需要关机,取决于你的硬件。

一旦替换分区准备就绪,我们就使用 -a 参数将其添加到 RAID 中。分区一旦添加,RAID 将开始自动重建,分配数据和奇偶校验信息到新分区:

mdadm /dev/md/md0 -a /dev/sdb1

上一教程演示了 mdadm-D(和 -E)参数如何用于检索 RAID 状态信息。你可以查看输出以监控重建进度,但通过 /proc/mdstat 可以获得更简洁的报告。内容显示了重建处理的速度,并估算完成所需的时间。使用 watch 重复显示 /proc/mdstat,你可以创建一个临时的仪表板来监控过程:

watch -n 10 -x cat /proc/mdstat

工作原理...

该 RAID 重建完成的预计时间大约为一个半小时。

另请参见

参考以下资源,了解如何在 RAID 中替换损坏的硬盘:

创建新的 LVM 卷

逻辑卷管理器(LVM)将数据存储从物理硬件中抽象出来,允许我们将一个或多个物理驱动器上的分区配置为一个逻辑设备。我们还可以灵活地在后续过程中添加或移除物理分区,并扩展或缩小逻辑设备。本教程将向你展示如何从组的存储中创建一个新的 LVM 组和逻辑设备。

准备工作

本教程要求有一个正常工作的 CentOS 系统并且具有提升的权限。假设至少已安装了两块新磁盘(分别标识为 /dev/sdb/dev/sdc),我们将对其进行分区并配置。

如何操作...

执行以下步骤以设置新的 LVM 组并创建一个卷:

  1. 使用 lsblk 识别新的存储设备。

    注意

    你也可以将 LVM 与 RAID 存储一起设置。跳至第 5 步并在给定的命令中将分区替换为 RAID 设备(例如 /dev/md/md0)。

  2. 启动 cfdisk 对第一个硬盘进行分区,并创建一个占用整个磁盘的单一分区:

    cfdisk -z /dev/sdb
    
    
  3. 重复步骤 2,对第二块硬盘进行分区。

  4. 使用 pvcreate 将新分区注册为物理卷:

    pvcreate /dev/sdb1 /dev/sdc1
    
    
  5. 验证物理卷是否出现在 pvs 输出中:

    pvs
    
    
  6. 使用 vgcreate 将物理卷组合成一个卷组:

    vgcreate vg0 /dev/sdb1 /dev/sdc1
    
    
  7. 验证该组是否出现在 vgs 输出中:

    vgs
    
    
  8. 使用 lvcreate 从卷组提供的存储池中创建一个逻辑卷:

    lvcreate -n myvol -L 500G vg0
    
    
  9. 使用 XFS 文件系统格式化该卷:

    mkfs.xfs /dev/vg0/myvol
    
    
  10. 挂载该卷以供使用:

    mount /dev/vg0/myvol /mnt
    
    

它是如何工作的...

LVM 是另一种配置多个存储单元协同工作的方法,侧重于以灵活的方式将它们的资源汇聚在一起。这些单元可以是磁盘分区,也可以是 RAID 阵列,因此使用了通用术语

本教程的开始假设我们有两块新的磁盘作为存储卷,并提供了使用 lsblkcfdisk 识别设备和进行分区的步骤。它使用 /dev/sdb/dev/sdc 作为设备,但你应该根据你的系统使用适当的设备。一旦磁盘被分区,我们就可以使用 pvcreate 将这些分区注册为物理卷。术语 物理卷 描述的是作为物理分区或 RAID 提供的存储。

pvcreate /dev/sdb1 /dev/sdc1

接下来,使用vgcreate将物理卷分组为卷组。食谱通过vgcreate使用sdb1sdc2分区创建了一个名为vg0的卷组。

vgcrate vg0 /dev/sdb1 /dev/sdc1

首先将期望的卷组名称传递给vgcreate,然后是我们希望组合在一起的物理卷。如果sdb1sdc1的容量各为 1 TB,它们的存储会合并,卷组的总容量将为 2 TB。如果我们稍后再向该组添加一个 500 GB 的卷,那么该组的存储容量将增加到 2.5 TB。

pvsvgs命令分别返回物理卷或卷组的基本信息,食谱使用它们来验证每个注册是否成功。pvs报告已注册的物理卷及其所属的组、任何属性以及存储容量。vgs列出卷组、组成每个卷组池的物理卷数量、使用该组存储的逻辑卷数量以及组的容量。

它是如何工作的...

使用pvsvgs查看物理卷和卷组的状态

使用lvcreate命令从卷组的池化存储中创建新的逻辑卷:

lvcreate -n myvol -L 500G vg0

-n选项提供逻辑卷的名称,-L选项提供从池中分配给卷的存储量。最后一个参数是支持该卷的卷组的名称。食谱中的示例创建了一个名为myvol的卷,容量为 500 GB,由vg0组提供支持。逻辑卷按组在/dev下组织,因此该卷可作为/dev/vg0/myvol使用。

最后,使用mkfs.xfs格式化该卷为 XFS 文件系统:

mkfs.xfs /dev/vg0/myvol

现在逻辑卷已经准备好使用,可以使用mount命令手动挂载,也可以在/etc/fstab中添加条目,以便系统启动时自动挂载该卷。

另见

要获取更多关于开始使用 LVM 的信息,请参考以下资源:

删除现有的 LVM 卷

LVM 的灵活性使我们可以根据需要分配物理卷的池化存储。这个食谱向我们展示了如何删除逻辑卷,并将其存储空间释放回卷组,供其他逻辑卷使用。

准备工作

本操作需要一个 CentOS 系统,并且需要具有管理员权限,权限可以通过使用root账户登录或使用sudo获得。假设已按照前述操作创建了一个逻辑卷。

如何操作...

按照以下步骤删除 LVM 卷:

  1. 使用umount卸载文件系统:

     umount /mnt 
    
    
  2. 打开/etc/fstab并确认没有自动挂载文件系统的条目。如果有,删除该条目,保存更改并关闭文件。

  3. 使用lvremove删除逻辑卷:

    lvremove vg0/myvol
    
    
  4. 查看vgs的输出以验证移除操作。

它是如何工作的...

删除卷将其存储释放回卷组,然后可以用于创建新的逻辑卷或支持扩展现有卷。这个操作教你如何使用lvremove命令销毁一个逻辑卷。

由于卷在使用时无法释放,第一步是确保其文件系统已卸载。如果文件系统是自动挂载的,它在/etc/fstab中的条目也应该被删除。

接下来,调用lvremove命令并提供逻辑卷名称以释放它:

lvremove vg0/myvol

注意

通过仅提供池名称,您可以删除池中的所有卷:

**lvremove vg0**

本操作建议检查vgs的输出以验证逻辑卷是否已删除。在输出中,#LV列下的逻辑卷数量应该减少,VFree列下的空闲空间应适当增加。

另请参见

有关删除卷的更多信息,请参考以下资源:

  • lvremove手册页(man 8 lvremove

  • vgs手册页(man 8 vgs

添加存储并扩展 LVM 卷

逻辑卷的大小不需要固定,我们可以从其卷组中为一个逻辑卷分配更多存储。这个操作教我们如何向卷组添加更多存储,并扩展逻辑卷的大小以利用它。

准备工作

本操作需要一个 CentOS 系统,并且需要具有管理员权限,权限可以通过使用root账户登录或使用sudo获得。假设已经安装并分区了新磁盘(识别为/dev/sdd1),并且已按照前述操作配置了逻辑卷组和卷。

如何操作...

按照以下步骤添加存储并增加 LVM 卷的大小:

  1. 将新分区注册为物理卷:

    pvcreate /dev/sdd1
    
    
  2. 查看pvs的输出以确认卷是否已注册:

    pvs
    
    
  3. 使用vgextend将物理卷添加到所需的卷组中:

    vgextend vg0 /dev/sdd1
    
    
  4. 查看vgs的输出以确认卷已添加到组中:

    vgs
    
    
  5. 使用lvextend增加所需逻辑卷的大小:

    lvextend vg0/myvol -L+500G
    
    
  6. 查看lvs的输出以确认新容量:

    lvs
    
    
  7. 使用xfs_grow扩展文件系统,以利用新容量:

    xfs_grow -d /mnt
    
    

    注意

    必须挂载 XFS 文件系统才能扩展其大小;如果尚未挂载,在执行xfs_grow之前需要挂载它。

  8. 使用df确认文件系统的新大小:

    df -h /mnt
    
    

How it works...

本文假设已经准备好一个新分区,并通过pvcreate命令将其注册为物理卷。然后,物理卷通过vgextend命令分配给vg0卷组,从而增加了该卷组的可用存储空间。

vgextend vg0 /dev/sdd1

使用lvextend来扩展逻辑卷vg0/myvol的大小:

lvextend vg0/myvol -L+500G

-L参数指定从池中分配的存储量。其值可以是绝对值,例如-L 500G,在这种情况下,卷的大小将被调整为该容量。也可以使用相对值,通过某个量增加卷的当前容量。此处使用了-L+500G,将逻辑卷的大小增加了额外的 500 GB。

注意

如果你提供的-L值小于逻辑卷当前的容量,将会收到一个错误,因为lvextend仅用于增加卷的容量。lvreduce命令用于减小逻辑卷的大小:

**lvreduce vg0/myvol -L 500GB**

给定一个绝对值,-L指定卷的总容量。在前面的命令中,vg0/myvol的容量被减少为500GB。给定一个相对值,例如-L-500GBlvreduce将把卷的容量减少指定的量。

完成后,可以通过检查lvs命令的输出确认逻辑卷的容量。该命令报告现有的逻辑卷以及它们所属的组、属性、存储容量和其他统计信息。

How it works...

逻辑卷的容量已增加,但文件系统需要调整大小以利用新的容量。

最后,需要使用xfs_growfs扩展文件系统,以利用可用的额外空间。文件系统必须已挂载才能使该工具正常工作,本文假设它已挂载在/mnt-d参数指示xfs_grow尽可能增加文件系统的大小(即整个卷的大小)。

xfs_growfs -d /mnt

另外,你也可以通过-D给出一个具体的大小。其值以块计数为单位,因此需要进行一些数学运算才能将文件系统扩展到所需的大小。例如,假设你有一个 1 TB 的文件系统,块大小是 4,096 字节(默认值)。此时块计数为 268,435,456 块。如果你想扩展文件系统 500 GB,目标块计数将是399507456

xfs_growfs -D 399507456 /mnt

为了让操作更简便,下面是一个展示常见大小对应的块计数的表格:

How it works...

这些块计数可以与 xfs_growfs 一起使用,用于扩展 XFS 文件系统。

虽然可以减小逻辑卷的大小,但只能扩展 XFS 文件系统。如果你想要减小一个 XFS 支持的卷的大小,你需要将数据移到一个安全的位置,删除并重新创建逻辑卷,设置较小的大小,之后再将数据移回来。

另见

请参考以下资源,了解更多关于扩展 LVM 卷的信息:

使用 LVM 快照

逻辑卷,也称为线性卷,是我们可以创建的卷类型之一;LVM 还允许我们创建快照卷。快照卷与逻辑卷相关联,并跟踪对逻辑卷数据所做的更改。我们可以将快照合并回逻辑卷,从而回滚数据。本教程将展示如何实现这一点。

准备工作

本教程要求使用 CentOS 系统,并通过以 root 账户登录或使用 sudo 提供管理员权限。假设已经配置了逻辑卷,并且在其卷组中有足够的存储空间来创建快照。

如何操作...

以下命令展示了如何操作 LVM 快照。在开始之前,你应该使用 vgs 命令验证卷组中是否有足够的存储空间来支持快照。

  1. 使用 lvcreate -s 创建快照卷:

    lvcreate -s -L 100M -n myvolsnap vg0/myvol
    
    
  2. 可以使用 lvremove 删除快照卷:

    lvremove vg0/myvolsnap
    
    
  3. 可以使用 mount 挂载并访问快照卷:

    mount -o ro /dev/vg0/myvolsnap /mnt
    
    
  4. 若要将逻辑卷恢复到创建快照时的状态,确保两者都未挂载,然后使用 lvconvert

    lvconvert -v --merge vg0/myvolsnap
    
    

它是如何工作的...

本教程展示了如何创建快照卷,快照卷会跟踪对逻辑卷所做的更改,并将快照合并回逻辑卷。

快照通过 lvcreate 命令并使用 -s 标志创建。-n 用于指定快照的名称,-L 用于指定将从卷组中为其分配多少存储空间。最后一个参数是创建快照的逻辑卷:

lvcreate -s -L 100M -n myvolsnap vg0/myvol

示例中给出的值会创建一个名为 myvolsnapvg0/myvol 的快照,容量为 100 MB。快照卷的存储从与其逻辑卷相同的卷组中分配,因此应该有足够的存储来支持该快照。幸运的是,快照卷不会复制原始卷的所有数据,而是采用写时复制策略,只有在数据被修改时,才会将差异记录到快照中。

如果增量数据超出快照卷的容量,LVM 将无法继续记录更改,快照将不再有效。因此,您应定期监控快照的存储使用情况,并在必要时调整快照大小,或丢弃现有快照并创建一个更大容量的新快照。与其他卷一样,lvremove 用于删除快照卷:

lvremove vg0/myvolsnap

快照也可以像其他逻辑卷一样挂载和访问。LVM 会透明地从原始逻辑卷读取未修改的数据,从而使数据看起来像是完整的副本。根据您创建快照的原因,您可能需要使用 ro 挂载选项,以只读方式挂载卷,防止无意中引入更改:

mount -o ro /dev/vg0/myvolsnap /mnt

lvconvert 用于更改卷的类型和其他特性。在调用 lvconvert 之前,您应先卸载逻辑卷和快照卷,以便合并过程可以立即开始。否则,LVM 会安排在两者都卸载后,且逻辑卷或快照卷重新挂载时再开始该过程。

要还原逻辑卷的数据,您需要定位其快照卷并使用 --merge 选项:

lvconvert -v --merge vg0/myvolsnap

将快照卷的数据合并到逻辑卷中会撤销逻辑卷数据的更改,基本上将其恢复到快照创建时的状态。完成后,快照会自动删除。-vlvconvert 设置为详细模式,这对于监控进度和了解合并完成以及快照删除的时间非常有用。

另见

请参考以下资源,获取有关操作快照的更多信息:

第六章:允许远程访问

本章包含以下内容:

  • 通过 SSH 远程执行命令

  • 配置更安全的 SSH 登录

  • 无需密码安全连接到 SSH

  • 按用户或组限制 SSH 访问

  • 使用 Fail2ban 保护 SSH

  • 将会话限制在 chroot 监狱中

  • 配置 TigerVNC

  • 通过 SSH 隧道连接 VNC

介绍

本章中的食谱将帮助你以安全的方式提供远程访问 CentOS 系统。你将学习如何通过 SSH 在远程系统上执行命令,配置 OpenSSH SSH 服务器以增强远程登录的安全性,并使用基于密钥的认证进行连接。你还将学习如何允许或拒绝不同用户的访问,配置 Fail2ban 自动阻止可疑的 IP 地址,以更好地保护你的服务器免受暴力破解攻击,并限制用户在登录后进入 chroot 监狱。结尾的食谱展示了如何通过 VNC 提供远程桌面环境的访问,并通过 SSH 隧道加密 VNC 流量来保障该访问的安全。

通过 SSH 远程执行命令

本篇展示了如何通过 安全外壳SSH)在远程系统上执行一次性命令。无需建立完整的交互式会话就能执行命令,这非常方便,因为你可以避免打开第二个终端;所有操作都可以直接在同一命令行中完成。

准备工作

本食谱要求远程系统运行 OpenSSH 服务器,并且本地计算机已安装 OpenSSH SSH 客户端(CentOS 上默认安装)。示例假设远程系统的 IP 地址为 192.168.56.100。此外,你还需要在远程系统上有一个用户账户。

如何操作...

以下示例展示了如何通过 SSH 从本地系统远程执行命令:

  • 要远程执行命令,使用 ssh 并指定目标系统的主机名或 IP 地址,然后是命令及其参数:

    ssh 192.168.56.100 uname -a
    
    
  • 若要以不同用户身份执行命令,请提供远程系统的用户名和地址:

    ssh tboronczyk@192.168.56.100 id -un
    
    
  • 如果远程命令需要 sudo,请为 ssh 提供 -t 参数:

    ssh -t 192.168.56.100 sudo mount /mnt
    
    
  • 使用 -X 参数将远程系统的 X11 显示转发,用于执行图形程序:

    ssh -X 192.168.56.100 gnome-calculator
    
    
  • 执行复杂命令时,请使用引号,例如一系列命令或使用 I/O 重定向时。这样可以避免本地和远程 shell 之间的歧义:

    ssh 192.168.56.100 "tar tvzf archive.tgz > contents.txt"
    
    
  • 你可以将来自本地系统的输入传输到远程命令,这些命令从 stdin 读取:

    cat foo.txt | ssh 192.168.56.100 "cat > foo.txt"
    
    

它是如何工作的...

ssh 主要用于登录远程系统并访问交互式 shell,因为很多人可能不知道命令可以在没有 shell 的情况下远程执行。本篇提供了几个示例,说明了如何使用 ssh 远程执行命令,每个示例都遵循这个通用调用模式:

ssh [options] [user@]host command

在远程主机后提供的任何内容都被 ssh 接受作为远程执行的命令,如以下两个示例所示。第一个命令调用 uname 打印关于远程系统的信息,例如内核、处理器和操作系统,第二个命令运行 id 显示当前有效用户的用户名:

ssh 192.168.56.100 uname -a
ssh tboronczyk@192.168.56.100 id -un

当执行这些命令时,ssh 不会启动交互式 shell,因为没有必要分配一个 tty/伪终端;它本身作为 shell 执行,处理远程和本地系统之间的输入输出。然而,一些命令需要终端才能正常运行。例如,sudo 使用终端确保用户输入密码时不会将其显示在屏幕上。如果没有终端,sudo 会拒绝运行,并报告 you must have a tty to run sudo。我们可以在执行这些命令时提供 -t 参数,强制 ssh 分配远程终端资源:

ssh -t 192.168.56.100 sudo mount /mnt

-X 参数转发 X11 显示,允许我们运行图形化程序。尽管程序实际上是在远程系统上运行,但它显示得就像是在本地桌面环境中运行一样:

ssh -X 192.168.56.100 "gnome-calculator"

它是如何工作的...

可以通过 X11 转发运行图形化应用程序

为了确保命令按您的意图被解析,您可能需要对命令加引号。当使用 I/O 重定向或运行多个命令时,尤其需要这样做。为了理解原因,请参考以下示例:

ssh 192.168.56.100 "tar tvzf archive.tgz > contents.txt"

tar 输出归档文件中的文件列表,然后将其重定向以创建 contents.txt 文件。所有操作都发生在远程系统——tar 在远程系统上运行,新文件也在远程系统上创建。

现在,这是相同的命令调用,但没有加引号:

ssh 192.168.56.100 tar tvzf archive.tgz > contents.txt

tar 仍然在远程执行,但本地 shell 解析重定向,contents.txt 文件在本地系统上创建。

I/O 重定向可以在两个方向上进行。也就是说,我们可以将本地系统的输入通过管道传输到远程系统的标准输入:

cat foo.txt | ssh 192.168.56.100 "cat > foo.txt"

在此示例中,foo.txtcat 读取,内容通过管道传送到远程系统。在远程系统上,正在运行的 cat 实例将等待读取输入。当它检测到传输结束时,cat 输出它接收到的内容,随后该内容被重定向以在远程系统上创建 foo.txt。本质上,我们刚刚将本地系统上的 foo.txt 复制到远程系统。

另见

有关通过 SSH 远程运行命令的更多信息,请参考以下资源:

配置更安全的 SSH 登录

SSH 被认为是比旧的协议(如 Telnet、rsh 和 rlogin)更安全的替代方案,因为它加密了客户端和服务器之间的连接。这种加密保护了网络中可能窃听的恶意用户免受攻击。然而,系统仍然可能遭遇拒绝服务攻击或恶意用户利用无人看管的空闲会话。此步骤通过更新服务器配置,增强了 SSH 的安全性,特别是在远程登录方面。

准备工作

本步骤适用于运行 OpenSSH 服务器的 CentOS 系统。也需要管理员权限,可以通过登录root账户或使用sudo来获得。

如何操作...

按照以下步骤增强 SSH 登录的安全性:

  1. 使用文本编辑器打开 SSH 服务器的配置文件:

    vi /etc/ssh/sshd_config
    
    
  2. 定位到LoginGraceTime选项。取消注释并将其值更改为30秒,以限制用户提供凭证的时间:

    LoginGraceTime 30
    
    
  3. 找到并取消注释PrintLastLog选项,并将其值更改为yes,以显示用户上次登录的时间和地点:

    PrintLastLog yes
    
    
  4. 取消注释Banner选项并将其值设置为/etc/banner,以便向用户显示登录警告:

    Banner /etc/banner
    
    
  5. 保存更改并关闭配置文件。

  6. 创建/etc/banner文件,并写入以下(或类似)内容:

    This computer system is for authorized use only. All  activity is 
    logged and monitored. Users accessing this  system without 
    authority, or in excess of their authority,  may be subject to 
    criminal, civil, and administrative  action. Continuing to use 
    this system indicates your consent to these terms and conditions 
    of use.
    
    
  7. 重启 SSH 服务器,使配置更改生效:

    systemctl restart sshd.service
    
    
  8. 为了在 10 分钟不活动后自动注销会话,请创建/etc/profile.d/timeout.sh文件,内容如下:

    export TMOUT=600
    
    

工作原理...

我们在 SSH 服务器配置文件中调整的第一个选项是LoginGraceTime,用于确定用户输入用户名和密码的时间长度。默认情况下,如果用户在两分钟内没有提供凭证,连接尝试会超时。我们将此时间减少到30秒,但如果您觉得时间不够,可以设置一个更合适的值:

LoginGraceTime 30

然后,将PrintLastLog选项的值设置为yes,使用户的上次登录时间和地点显示出来。这有助于因为不熟悉的时间或地点可能会警告用户其账户可能已经被入侵并用于未经授权的访问:

PrintLastLog yes

接下来,我们配置了登录横幅。虽然强烈措辞的警告不太可能威慑恶意用户,但许多组织要求在用户登录时根据法律要求显著显示这些警告信息。此类消息在一些司法管辖区被视为足够的通知,告知用户他们的行为正在被监视,且对系统上的活动不应期望隐私。这为组织提供了更强的法律依据,追究任何滥用行为。

为了在登录提示前显示警告,我们将Banner设置为指向包含消息的文件路径。然后我们创建了一个包含所需文本的文件:

Banner /etc/banner

它是如何工作的...

用户在登录远程系统之前会看到横幅信息

注意

nroff可以用来调整横幅的文本对齐:

`**(echo -e ".ll 75\n.pl 0\n.nh"; cat) | nroff > /etc/banner**`

cat从标准输入读取文本(当完成时按Ctrl + D),然后将 echo 输出的指令和文本通过管道传送到nroff进行格式化。

.ll告诉nroff将行长度设置为75个字符。建议使用小于80的值,因为传统终端每行显示80个字符。

.pl设置页面长度,将其设置为0可以防止nroff在文本后添加额外的空白,以试图填充某个假设的打印页面长度。

.nh可以防止nroff在行末进行单词分割。

如果你希望在用户登录后而不是之前显示横幅,可以使用当天消息文件。在这种情况下,取消注释PrintMotd选项并将其值设置为yes,然后将文本保存到/etc/motd中。

最后,我们创建了/etc/profile.d/timeout.sh文件来设置TMOUT环境变量。在/etc/profile.d下设置TMOUT会在用户登录时全球应用它。要针对单个用户,或者如果你想为特定用户覆盖全局值,可以将export命令放入他们的~/.bash_profile文件中:

export TMOUT=600

现在,设置了该变量后,bash 会在用户一段时间未活动时自动关闭会话,显示消息timed out waiting for input: auto-logout。该值以秒为单位,示例配方会在 10 分钟后关闭空闲会话。

另请参见

请参考以下资源,了解如何加强 SSH 登录的安全性:

无密码安全连接到 SSH

本教程教你如何生成密钥对,并为 SSH 会话设置基于密钥的认证,允许你在不使用密码的情况下秘密连接到远程系统。基于密钥的认证被认为比使用密码更安全,因为弱密码容易被猜测,而强密码则可能容易忘记且更容易被记录下来。在这两种情况下,攻击者都有较大的机会发现用户的密码。而通过基于密钥的认证,用户必须提供正确的私钥文件,几乎不可能被破解或伪造。

准备工作

本教程需要远程系统运行 OpenSSH 服务器,并且本地计算机上已安装 OpenSSH SSH 客户端。示例假设远程系统的 IP 地址为 192.168.56.100。另外,你需要在远程系统上有一个可用的用户账户。

如何操作...

按照以下步骤设置 SSH 会话的基于密钥的认证:

  1. 在本地计算机上,使用 ssh-keygen 命令创建一对认证密钥。接受默认路径/文件名并保持空白的密码短语:

    ssh-keygen -b 3072 -C "Timothy Boronczyk"
    
    
  2. 如果远程主目录下还没有 .ssh 目录,创建该目录:

    ssh 192.168.56.100 "mkdir -m 700 .ssh"
    
    
  3. id_rsa.pub 的内容追加到远程系统上的 .ssh/authorized_keys 文件中:

    cat .ssh/id_rsa.pub | ssh 192.168.56.100 "cat >>  
           .ssh/authorized_keys"
    
    
  4. 确保 authorized_keys 文件的权限:

    ssh 192.168.56.100 "chmod 640 .ssh/authorized_keys"
    
    
  5. 验证是否可以在不提供密码的情况下连接到远程系统:

    ssh 192.168.56.100
    
    
  6. 对于任何额外的远程系统,只要你希望使用基于密钥的认证登录,重复步骤 2 到 5。

工作原理...

基于密钥的认证被认为比使用密码更安全,因为破解合适的加密密钥几乎不可能,而暴力破解密码则很简单。本教程使用了 OpenSSH 套件中的 ssh-keygen 程序生成了新的密钥对,然后我们用它来验证我们的 SSH 会话:

ssh-keygen -b 3072 -C "Timothy Boronczyk"

-C 在密钥中嵌入一个简短的注释,这对于识别密钥的所有者或用途很有帮助,-b 设置用于密钥模数的位数。使用的位数越多,可以表示的数字越大,这意味着更强的破解抗性。如果没有提供 -b,默认值为 2,048 位。根据计算能力增长的估算,2,048 位的密钥通常认为适用于 2030 年之前(研究人员在 2010 年成功攻破了 1,024 位的密钥)。3,072 位的密钥被认为适用于 2030 年以后。

在提示时,我们接受了建议的 ~/.ssh/id_rsa 作为输出文件名(这是 ssh 默认在连接到远程服务器时查找我们的私钥的位置)。我们也没有提供密码短语。如果我们提供密码短语,那么密钥将被加密,并且每次使用密钥时,我们都需要提供密码来解密它。

ssh-keygen完成时,私钥id_rsa和公钥id_rsa.pub将保存在.ssh目录中:

如何工作...

密钥对用于无密码认证

然后,我们在远程系统的主目录中创建了.ssh目录。你可以在登录远程系统时执行mkdir命令,否则可以通过 SSH 远程执行该命令:

ssh 192.168.56.100 "mkdir -m 700 .ssh"

接下来,我们将公钥添加到远程系统的.ssh/authorized_keys中:

cat .ssh/id_rsa.pub | ssh 192.168.56.100 "cat >>  .ssh/authorized_keys"

由于正确的权限有助于确保密钥的安全,ssh不会考虑使用权限过于宽松的密钥。.ssh目录的权限应该仅限于所有者的读、写、执行权限(700),authorized_keys文件的权限应该是所有者和组的读权限,以及所有者的写权限(640)。通过简单的chmod命令确保一切正确:

ssh 192.168.56.100 "chmod 640 .ssh/authorized_keys"

当我们连接时,ssh会看到id_rsa文件,并将我们的私钥作为连接请求的一部分发送。服务器在authorized_keys文件中检查相应的公钥,如果一切匹配,我们就会被授权并登录。

另请参见

有关使用基于密钥的身份验证与 OpenSSH 的更多信息,请参考以下资源:

按用户或组限制 SSH 访问

根据你系统的角色和已配置的用户帐户,你可能不希望所有已注册的用户都能通过 SSH 访问。此指南向你展示了如何配置 SSH 服务器,明确授予或拒绝用户访问权限。

准备工作

本指南要求在运行 OpenSSH 服务器的 CentOS 系统上操作。还需要管理员权限,可以通过root账户登录,或者使用sudo来获取权限。

操作步骤...

按照以下步骤限制用户的 SSH 访问:

  1. 使用文本编辑器打开 SSH 服务器的配置文件:

    vi /etc/ssh/sshd_config
    
    
  2. 找到PermitEmptyPasswords选项。取消注释并将其值设置为no,以禁止使用空密码的帐户:

    PermitEmptyPasswords no
    
    
  3. 要禁用root账户的远程访问,找到并取消注释PermitRootLogin选项,将其值设置为no

    PermitRootLogin no
    
    
  4. 通过为DenyUsers添加条目,禁止特定用户帐户的远程访问。该选项的值应该是一个空格分隔的用户名列表,表示你要拒绝访问的用户:

    DenyUsers bbarrera jbhuse mbutterfield
    
    
  5. 通过为DenyGroups添加条目,拒绝特定组成员的远程访问:

    DenyGroups users noremote
    
    
  6. 添加AllowUsers条目,以拒绝所有除许可用户列表中的人以外的访问:

    AllowUsers abell tboronczyk
    
    
  7. 添加AllowGroups条目,以拒绝所有除许可组列表中的人以外的访问:

    AllowGroups itadmin remote
    
    
  8. 保存更改并关闭文件。

  9. 重启 SSH 服务器使更改生效:

    systemctl restart sshd.service
    
    

它是如何工作的...

首先,我们取消注释PermitEmptyPasswords并将其值设置为no。这可以防止没有密码的用户帐户通过 SSH 登录:

PermitEmptyPasswords no

密码是保护我们免受恶意攻击(通过被破坏的用户帐户)的第一道防线。没有强密码,任何人只需知道用户名就可以轻松登录。这是一个可怕的想法,因为用户名很容易被猜到,有时甚至以电子邮件地址等形式公开。

接下来,我们取消注释PermitRootLogin选项并将其值设置为no。这可以防止root直接建立 SSH 会话:

PermitRootLogin no

这样的限制在使用 Telnet 等协议时至关重要,因为用户名和密码经常以明文形式通过网络传输——攻击者可以轻松监控网络流量并捕获密码。然而,尽管 SSH 通过加密其流量使这个问题变得无关紧要,但密码仍然容易受到暴力破解攻击。因此,明智的做法是要求用户首先使用其无特权帐户进行身份验证,然后在必要时使用susudo提升权限(请参阅第三章,用户与权限管理)。

该方案随后介绍了DenyUsersDenyGroupsAllowUsersAllowGroups选项,作为大范围限制 SSH 访问的方法。

DenyUsers选项禁止特定用户登录。其他用户帐户仍然可以远程访问系统,但在DenyUsers下列出的用户将看到Permission Denied消息。该方案的示例拒绝bbarrerajbhusembutterfield的访问:

DenyUsers bbarrera jbhuse mbutterfield

DenyGroups选项的工作原理类似,但它根据用户的组成员资格来拒绝用户访问;以下示例拒绝所有属于users组或noremote组的用户访问:

DenyGroups users noremote

拒绝选项对于将少数用户列入黑名单非常有用。要阻止所有用户,除了几个特定的用户,我们使用允许选项。AllowUsers拒绝所有人访问,除非在指定的用户列表中。AllowGroups是其对应选项,仅允许指定组成员的用户访问:

AllowUsers abell tboronczyk
AllowGroups itadmin remote

这些选项也可以具有使用*?作为通配符的值。*匹配零个或多个字符,?匹配单个字符。例如,以下内容拒绝所有用户:

DenyUsers *

注意

AllowUsersAllowGroups 会拒绝所有未列出的用户/组。使用这些选项时要小心,特别是如果你依赖 SSH 来管理服务器,因为很容易会把自己屏蔽出去。在退出当前 SSH 会话之前,请确保你能通过第二个终端成功登录。如果出现问题,你仍然可以通过第一个会话登录并解决问题。

另见

请参考以下内容,了解如何限制远程 SSH 访问:

使用 Fail2ban 保护 SSH

一名决心十足的攻击者可能会尝试暴力破解用户密码以获取访问权限,或者进行多次尝试登录,以消耗网络和系统资源,作为拒绝服务攻击的一部分。Fail2ban 可以帮助你防范此类攻击,通过监控服务器的日志文件,识别可疑活动,并自动封禁这些活动的 IP 地址。本教程将教你如何安装 Fail2ban 来保护你的系统。

准备工作

本教程需要一台运行 OpenSSH 服务器的 CentOS 系统,并且需要管理员权限,可以通过登录 root 账户或使用 sudo 获取权限。fail2ban 包由 EPEL 仓库提供,如果仓库尚未注册,请参考 第四章中的 注册 EPEL 和 Remi 仓库 配方,软件安装管理

如何操作...

按照以下步骤使用 Fail2ban 保护你的系统:

  1. 安装 fail2ban 包:

    yum install fail2ban
    
    
  2. 使用以下内容创建监狱配置文件 /etc/fail2ban/jail.local

    [sshd]
    enabled=true
    bantime=86400
    maxretry=5
    
    
  3. 启动 Fail2ban 服务,并在系统启动时启用其自动启动:

    systemctl start fail2ban.service
    systemctl enable fail2ban.service
    
    
  4. 要查看 sshd 监狱的状态,可以使用 fail2ban-client 配合 status 命令:

    fail2ban-client status sshd
    
    

它是如何工作的...

你已经学会了如何安装 Fail2ban 并配置在多次登录失败后自动屏蔽 IP 地址。你还学会了如何使用 fail2ban-client 手动封禁和解封地址。

一个 Fail2ban 监狱配置将过滤器和操作定义结合起来,当在服务器的日志文件中观察到某些模式时,执行相应的活动。过滤器指定用于识别有意义日志条目的模式定义,例如,重复的身份验证失败。另一方面,操作定义了当过滤器匹配时要执行的命令。Fail2ban 随附了多个预定义的过滤器,适用于 Apache、MySQL、Sendmail 和 SSH 等常见服务器,并且还提供了多个预定义操作,例如管理 iptable 条目以封禁和解除封禁 IP 地址、发送电子邮件通知以及触发 DNS 更新。

/etc/fail2ban/jail.conf 中定义了多个监狱。为了激活 sshd 监狱,我们创建了 jail.local 文件,并在其中添加了覆盖和扩展默认监狱定义的条目:

[sshd]
enabled=true
bantime=86400
maxretry=5

从直观上看,enabled 选项用于启用或禁用监狱。maxretry 设置为 5,表示允许失败的登录尝试次数,在超过这个次数后,Fail2ban 将执行封禁操作。bantime 设置封禁的持续时间,我们将其设置为 86400 秒。通过这个配置,用户最多允许 5 次失败尝试,超过后他们的 IP 地址将被封禁 24 小时。

jail.conf 中已有的定义已经确定了默认端口和日志文件的位置。如果你在非标准端口上运行 SSH,可以使用 port 来覆盖原始定义的设置。SSH 的日志文件位置也可以通过 logfile 来覆盖。

fail2ban-client 用于与 Fail2ban 服务进行交互。其 status 命令输出服务当前状态的信息,如果 status 后面跟着监狱名称,则返回该监狱的状态信息。监狱状态中可能特别值得注意的是被封禁的 IP 地址列表:

fail2ban-client status sshd

它是如何工作的...

监狱的状态输出展示了被封禁地址的列表

客户端还提供 getset 命令,用于检查和更新正在运行的服务的各种属性。例如,get sshd bantime 返回配置的封禁时长。set sshd bantime 临时更新封禁时长,直到服务重启。

你可以通过设置监狱的 banip 属性来手动封禁某个 IP 地址:

fail2ban-client set sshd banip 10.25.30.107

若要手动解除封禁某个地址,请设置 unbanip

fail2ban-client set sshd unbanip 10.25.30.107

能够手动解除封禁地址非常重要,因为有时合法的地址可能会由于某些原因被误封。如果有些地址永远不应该被封禁,可能是某个测试集成服务器故意执行了失败登录,或者是管理员的计算机,你可以在 jail.local 配置文件中使用 ignoreip 选项来标识这些地址,Fail2ban 将避免封禁这些地址:

ignoreip=10.25.30.107

另见

更多关于 Fail2ban 的信息,请参考以下资源:

将会话限制在 chroot 监狱中

本食谱教你如何设置一个 chroot 监狱。chroot 调用通过将特定路径设置为根目录,改变用户对文件系统层次结构的视图;对于用户来说,这个路径看起来就像是/,并且无法越过这个路径。这就创建了一个沙盒或监狱,将用户限制在真实层次结构的一个小分支内。chroot 监狱通常用于安全目的,例如用户隔离、蜜罐以及应用程序测试和恢复程序。

准备工作

本食谱要求运行 OpenSSH 服务器的 CentOS 系统。还需要管理员权限,可以通过root账户登录或使用sudo

如何操作...

按照以下步骤配置 chroot 监狱并将用户限制在其中:

  1. 下载cpchroot脚本,必要时将命令及其依赖项复制到 chroot 环境中:

    curl -Lo ~/cpchroot tinyurl.com/zyzozdp
    
    
  2. 使用chmod使脚本可执行:

    chmod +x ~/cpchroot
    
    
  3. 创建/jail目录及其子目录,以模拟根文件系统:

    mkdir -p /jail/{dev,home,usr/{bin,lib,lib64,share}}
    cd /jail
    ln -s usr/bin bin
    ln -s usr/lib lib
    ln -s usr/lib64 lib64
    
    
  4. 执行chroot脚本以复制所需的程序和命令:

    ~/cpchroot /jail bash cat cp find grep less ls   
           mkdir mv pwd rm rmdir
    
    
  5. 复制terminfo数据库:

    cp -R /usr/share/terminfo /jail/usr/share
    
    
  6. 使用mknod/jail/dev下创建特殊设备文件:

    cd /jail/dev
    mknod null c 1 3
    mknod zero c 1 5
    mknod random c 1 8
    
    
  7. 为 chroot 用户创建一个组:

    groupadd sandbox
    
    
  8. 使用文本编辑器打开/etc/ssh/sshd_config文件,并将以下内容添加到文件的末尾:

     Match Group sandbox
               ChrootDirectory /jail 
    
    
  9. 保存更改并关闭配置文件。

  10. 重新启动 SSH 服务器以使更改生效:

    systemctl restart sshd.service
    
    

要创建一个新的 chroot 用户,使用useradd命令创建用户,并将其分配到sandbox组:

useradd -s /bin/bash -m -G sandbox rdiamond

然后,将他们的home目录移动到 chrootjail下:

mv /home/rdiamond /jail/home

要将现有用户设置为 chroot 环境,将其分配到sandbox组,并将其home目录移至jail

usermod -G sandbox bbarrera
mv /home/bbarrera /jail/home

工作原理...

手动识别和复制依赖项是繁琐且容易出错的。因此,我编写了一个辅助脚本来自动化寻找和克隆程序及其依赖项到监狱中的过程。我们的第一步是使用curl下载脚本,然后使用chmod使其可执行:

curl -Lo ~/cpchroot tinyurl.com/zyzozdp
chmod +x ~/cpchroot

该脚本托管在 GitHub 上,但其直接网址过长,因此我使用了一个网址缩短服务来缩短地址。我们需要为curl提供-L,以便跟踪任何重定向(该服务会响应一个指向 GitHub 的重定向),-o设置下载文件的名称,此处为cpchroot,并保存到home目录下。

注意

如果您遇到由于网址缩短服务而出现的问题,可以通过访问gist.github.com/tboronczyk/00d77b1baafd13daab3b,点击Raw按钮,然后复制浏览器地址栏中出现的网址来找到直接链接。

接下来,我们创建了/jail目录,并在其中创建了一个模仿根文件系统的目录结构。当用户登录并进入 chroot 环境时,他们及其所有操作都会局限在/jail目录内。他们将无法访问该目录之外的内容,因此我们需要复制程序所期望的目录布局:

mkdir -p /jail/{dev,home,usr/{bin,lib,lib64,share}}
cd /jail
ln -s usr/bin bin
ln -s usr/lib lib
ln -s usr/lib64 lib64

我们使用了带有-p选项的mkdir,并利用 Shell 扩展通过一个命令创建了大部分布局。CentOS 将其顶级的/bin/lib/lib64目录设置为指向/usr下相应目录的符号链接,我们通过在/jail目录内使用ln命令复制了这些链接。最终的布局如下所示:

它是如何工作的...

沙盒根目录的布局模仿了主机的根文件系统。

接下来,我们使用脚本将所需的命令复制到jail中。该脚本负责查找每个程序的二进制文件,识别其依赖的所有库,然后将所有文件复制到沙盒文件系统的适当位置:

~/cpchroot /jail bash cat cp find grep less ls mkdir mv pwd rm rmdir

它的第一个参数是作为我们 chroot 根目录的目录,后面跟着我们希望提供给用户的一个或多个程序列表。该配方提供了 12 个程序作为示例,您可以根据需要自由添加或删除。最低要求是必须有一个 Shell(bash)。我建议您至少包含lspwd,这样用户就可以进行导航。

然后,我们将terminfo数据库复制到jail中:

cp -R /usr/share/terminfo /jail/usr/share/

一些程序,如screenlessvi,使用terminfo数据库来确保其输出正确显示。该数据库是一个文件集合,描述了不同终端类型的功能,如每屏的行数、如何清除屏幕、支持哪些颜色等。如果这些信息无法访问,用户将被警告终端功能不完全,并且输出可能会出现乱码。

为了完成创建jail,我们使用mknod命令创建了/dev/null/dev/zero/dev/random设备:

cd /jail/dev/
mknod null c 1 3
mknod zero c 1 5
mknod random c 1 8

mknod用于创建特殊文件,如字符文件和块文件。这些文件之所以特殊,是因为它们可以生成数据(如nullzero)或表示物理设备并接收数据。nullzero都是字符文件,正如字母c所表示的那样,因为我们一次从中读取一个字符。另一方面,块文件一次操作多个字符。物理存储磁盘通常表示为块设备。

我们在创建字符设备或块设备时,还需要提供主次设备号。这些值是预定义的,内核理解这些值如何影响设备文件的行为。13 是定义空设备的主次设备号,15 定义文件为空字节源。你可以在本配方的 另请参见 部分中找到 Linux 分配的设备文档,查看完整的主次设备号分配列表。

设置 chroot 环境后,我们开始配置 SSH 服务器。首先,我们创建了一个 sandbox 组,任何我们想要隔离的用户都可以分配到该组:

groupadd sandbox

接下来,我们在 SSH 服务器的配置文件中添加了一个 Match 块,目标是新的组:

Match Group sandbox
 ChrootDirectory /jail

Match 在配置文件中开始一个新的条件块,仅在满足条件时应用。在本例中,我们将用户的组匹配为 sandbox。当用户属于该组时,ChrootDirectory 选项会被应用,并将 /jail 设置为用户的根目录。现在,当用户连接时,他们所做的一切都会被限制在 chroot 监狱中,包括自动发生的操作,如启动交互式 shell (bash)。

Bash 在用户登录后会尝试将其放入 home 目录。但是,如果他们的 home 目录无法访问,用户会看到错误信息 Could not chdir to home directory,并且会被定位到根目录。为了避免这种情况,我们将他们的 home 目录移入了 jail

mv /home/jbhuse /jail/home/

注意

你可能会想在创建新用户时指定 home 目录,如下所示:

**useradd -m -D /jail/home/jbhuse -G sandbox jbhuse**

不幸的是,这不起作用。home 目录在期望的位置创建,用户被 chroot,路径相对于 /jail 进行查看,这样 bash 就会寻找 /jail/jail/home/jbhuse。这就是为什么示例中演示了将 home 目录移到第二步的原因。/etc/passwd 中的条目保持不变,/home/jbhuse 被解释为 /jail/home/jbhuse,一切正常。

另请参见

更多关于设置 chroot 环境的信息,请参阅以下内容:

配置 TigerVNC

虚拟网络计算(VNC)通过捕获显示的帧缓冲区并通过网络提供访问。这个教程展示了如何安装 TigerVNC 并将其配置为提供远程用户访问图形桌面环境,就像他们物理上坐在系统前面一样。

准备工作

本教程需要两台系统,一台 CentOS 系统用于托管 VNC 服务器(远程系统),另一台本地计算机通过 VNC 客户端连接到它。假设远程系统正在运行 OpenSSH SSH 服务器和图形桌面环境,如 GNOME 或 KDE。需要在远程服务器上拥有管理员权限,可以通过登录root账户或使用sudo来获得。预计本地计算机已经安装了 VNC 客户端。

如何操作...

按照以下步骤安装和配置 TigerVNC:

  1. 在远程系统上安装 TigerVNC 服务器软件包:

    yum install tigervnc-server
    
    
  2. 将随软件包提供的示例单元文件复制到/etc/systemd/system,并调整其名称,以包含使用 VNC 的用户的用户名:

    cp /usr/lib/systemd/system/vncserver@.service  
           /etc/systemd/system/vncserver-tboronczyk@.service
    
    
  3. 使用文本编辑器打开新的单元文件:

    vi /etc/systemd/system/vncserver-tboronczyk@.service
    
    
  4. 替换[Service]部分中ExecStartPIDFile条目中出现的<USER>占位符:

    ExecStart=/usr/sbin/runuser -l tboronczyk -c "/usr/bin/  
           vncserver %i"
    PIDFile=/home/tboronczyk/.vnc/%H%i.pid
    
    
  5. 保存更改并关闭文件。

  6. 对每个将使用 VNC 连接到桌面的用户,重复步骤 2 到 5。

  7. 重新加载 systemd 的配置,使其意识到新的单元文件:

    systemctl daemon-reload
    
    
  8. 在系统的防火墙中开放59005903端口,以接受来自 VNC 的请求:

    firewall-cmd --zone=public --permanent --add-service=vnc- server
    firewall-cmd --reload
    
    
  9. 使用 VNC 的用户应该使用vncpasswd设置他们将用于身份验证的密码:

    vncpasswd
    
    
  10. 当用户想要连接时,在启动 TigerVNC 时在单元名称后指定一个显示号@

    systemctl start vncserver-tboronczyk@:1.service
    
    
  11. 当服务器不使用时停止它:

    systemctl stop vncserver-tboronczyk@.service
    
    

它是如何工作的...

除了 VNC 服务器,tigervnc-server软件包还安装了一个systemd单元文件,用于启动和停止服务器。然而,在使用之前我们需要进行一些配置,因为服务器是在用户账户下运行,以获取他们的桌面。

当 TigerVNC 启动时,它会连接到 X 服务器并登录到用户的桌面,就像用户坐在系统前面一样。这意味着每个用户都需要自己的服务器实例运行,我们需要为每个用户进行配置。我们复制了位于/usr/lib/systemd/system下的原始单元文件,每个用户一个副本。

cp /usr/lib/systemd/system/vncserver@.service /etc/systemd/system/  
    vncserver-tboronczyk@.service

复制文件的名称包含用户名,以便我们可以保持一切有序。它们被放置在/etc/systemd/system下,因为systemd会先在/etc/systemd中查找单元文件,然后才会搜索/usr/lib/systemd(实际上,/etc/systemd中的许多条目是指向/usr/lib/systemd下原始文件的符号链接)。因此,将副本放在这里可以让我们保持原始文件的完整,并且在升级时,如果原始单元文件被替换,这样可以保护我们不丢失配置。

它是如何工作的...

该系统已为多个用户配置了 VNC 访问

我们在每个配置文件的[SERVICE]部分中,将所有出现的<USER>占位符替换为相应的用户名:

ExecStart=/usr/sbin/runuser -l tboronczyk -c "/usr/bin/vncserver %i"
PIDFile=/home/tboronczyk/.vnc/%H%i.pid

ExecStart条目中指定的命令是在我们使用systemctl start启动服务器时调用的;它使用runuser在用户账户下运行 TigerVNC。-l(小写 L)参数提供用户名,-c指定runuser将执行的命令及其参数。PIDFile条目指定运行进程将跟踪其进程 ID 的目录。

注意

runuser的作者 Dan Walsh 写了一篇名为runuser vs su的博客,详细讲述了该命令的背景故事。你可以在danwalsh.livejournal.com/55588.html在线阅读。

@符号出现在文件名中对 systemd 具有特殊意义。它后面的内容和文件后缀之间的部分会传递给单元文件中的命令,替换%i。这让我们能够向服务器传递有限的信息,例如 TigerVNC 运行的显示号。当我们按照示例中的方法启动服务器时,@后面会跟上:1。这个值会被 systemd 解析,TigerVNC 会在显示器 1 上启动。如果我们使用:2,服务器将在显示器 2 上启动。我们可以为不同的用户或即使是同一个用户启动多个 TigerVNC 实例,只要每个显示器号不同即可:

systemctl start vncserver-tboronczyk@:1.service

显示对应端口的流量应允许通过防火墙。显示 0 使用端口5900,显示 1 使用端口5901,显示 2 使用端口5902,依此类推。如果你使用的是 FirewallD,预定义的vnc-server服务会打开端口5900-5903

firewall-cmd --zone=public --permanent --add-service=vnc-server

如果你需要额外的端口,或者不需要打开整个范围,你可以使用--add-port只打开所需的端口:

firewall-cmd --zone=public --permanent --add-port=5901/tcp

用户在连接到显示器之前需要使用vncpasswd设置 VNC 密码。密码必须至少为六个字符长,尽管只有前八个字符才是有效的。此外,密码存储在用户的~/.vnc/目录中。考虑到这些问题,建议用户不要使用与账户密码相同的密码。也建议用户仅在需要时运行 VNC 服务器,因为任何知道显示号和密码的人都可以连接。

用户还需要一个 VNC 客户端才能从本地计算机连接。CentOS 用户可以安装tigervnc包来使用 TigerVNC 的客户端。其他流行的客户端包括 Ubuntu 的 Vinagre,Windows 上 TightVNC 的 RealVNC,以及 OS X 上的 Chicken of the VNC:

yum install tigervnc

需要远程系统的 IP 地址或主机名以及 VNC 运行的显示(端口)才能建立连接。它们可以通过不同的方式提供,具体取决于客户端,但大多数客户端接受的标准格式是将显示号附加到系统地址,例如192.168.56.100:1。接下来,用户将被提示输入密码,如果一切顺利,他们将连接到远程显示:

工作原理...

用户准备通过 VNC 连接到远程显示

另请参见

请参考以下资源,了解更多关于运行 TigerVNC 和 systemd 如何在文件名中使用@的信息:

通过 SSH 隧道转发 VNC 连接

前面的教程展示了如何通过 VNC 远程访问用户的桌面。然而,如果服务运行在不受信任的网络上,显然存在一些安全问题。连接所需的仅是显示号码和密码,而由于密码的前八个字符才是有效的,恶意用户相对容易破解密码。此外,流量是未加密的,可能会被窃听。为了缓解这些风险,本教程将教你如何通过加密的 SSH 隧道转发 VNC 连接。

准备工作

本教程需要两个系统,一个是托管 VNC 服务器的 CentOS 系统(远程系统),另一个是本地计算机,具有 VNC 客户端以连接到该服务器。假设远程系统正在运行 OpenSSH SSH 服务器和 TigerVNC 服务器,并配置了 IP 地址192.168.56.100。同时假设你拥有管理员权限。VNC 服务器应按照之前的教程配置。本地计算机应安装 OpenSSH SSH 客户端(ssh)和 VNC 客户端。

如何操作...

按照以下步骤,通过加密的 SSH 隧道转发 VNC 连接:

  1. 在远程服务器上,使用文本编辑器打开vncserver@.service配置文件:

    vi /etc/systemd/system/vncserver-tboronczyk@.service
    
    
  2. 定位到ExecStart条目,并向runuser调用的vncserver命令添加-localhost参数:

     ExecStart=/usr/sbin/runuser -l tboronczyk -c "/usr/bin/vncserver
    -localhost %i" 
    
    
  3. 保存更改并关闭文件。

  4. 根据需要为其他用户的配置文件重复步骤 1 到 3。

  5. 重新加载 systemd 配置,以使其意识到更新:

    systemctl daemon-reload
    
    
  6. 启动 VNC 服务器:

    systemctl start vncserver-tboronczyk@:1.service
    
    
  7. 在本地系统上,使用 -L 参数建立 SSH 会话,以定义隧道:

    ssh -L 5901:localhost:5901 192.168.56.100
    
    
  8. 使用 VNC 客户端连接到隧道的本地端点(localhost:1)。

工作原理...

本食谱展示了如何通过将 VNC 流量通过 SSH 隧道进行加密。我们将 TigerVNC 服务器配置为仅接受来自本地主机的连接,并在本地客户端端设置隧道,以便通过 SSH 连接路由流量。这有助于减轻一些上述的安全风险,因为需要进行适当的身份验证以建立隧道并加密 VNC 流量。

首先,你编辑了用于启动 VNC 服务器实例的单元文件中的 ExecStart 命令。-localhost 参数指示 vncserver 仅与本地系统通信;任何来自网络的传入连接将被拒绝:

ExecStart=/usr/sbin/runuser -l tboronczyk -c "/usr/bin/vncserver   
    -localhost %i"

在客户端,用户现在需要使用 ssh 建立一个 SSH 隧道,才能连接到远程显示:

ssh -L 5901:localhost:5901 192.168.56.100

-L 参数定义隧道为 local-port:target-host:target-port。目标主机和端口表示与 ssh 连接的服务器的最终目的地。例如,我们知道本食谱在显示 1 上运行用户的桌面,使用端口 5901。我们还知道 TigerVNC 服务器运行在 192.168.56.100 上,但配置为仅监听其本地主机。这意味着,我们需要从 192.168.56.100 连接到 localhost:5901。因此,localhost:5901 是相对于该系统的目标。

一旦用户建立了隧道,他们可以最小化会话终端。(不要关闭它!)ssh 已连接到远程系统,同时在本地端口(也就是5901)上监听。在远程服务器上,ssh 已建立到目标主机和端口的第二个连接。VNC 客户端将通过使用地址 localhost:1 连接到本地端口,流量随后通过 SSH 隧道路由到远程服务器,然后转发到最终目的地。

远程系统充当网关,流量从客户端隧道经过它到达最终目的地。请记住,除非在远程服务器上也创建了到目标的隧道,否则数据旅程的第二段不会加密。对于本食谱来说,这不成问题,因为远程和目标主机是相同的。如果最终目的地不是本地主机,请确保网络可信,或创建第二个隧道。

注意

以这种方式通过 SSH 路由流量也可以用于保护其他服务,例如 NFS、FTP、HTTP、POP3 和 SMTP。整个过程是相同的:配置服务器以便在本地监听,然后在客户端建立隧道。

参见

参考以下资源了解更多关于 SSH 隧道的信息:

第七章:与数据库一起工作

本章包含以下配方:

  • 设置 MySQL 数据库

  • 备份和恢复 MySQL 数据库

  • 配置 MySQL 复制

  • 设置 MySQL 集群

  • 设置 MongoDB 数据库

  • 备份和恢复 MongoDB 数据库

  • 配置 MongoDB 副本集

  • 设置 OpenLDAP 目录

  • 备份和恢复 OpenLDAP 目录

介绍

本章重点介绍三种数据库。首先,您将学习如何安装最广泛使用的关系数据库服务器之一——MySQL。您还将学习如何设置主从复制以维护 MySQL 数据库的镜像副本,以及如何建立 MySQL 集群以提供可扩展的高可用数据存储。接下来,我们将进入 NoSQL 数据库的世界。您将学习如何安装流行的文档导向数据库服务器 MongoDB,并配置 MongoDB 副本集(复制)。然后,您将学习如何使用 OpenLDAP 设置 LDAP 目录服务器。对于这些数据库,本章还包含如何执行基本备份和恢复任务的配方,以确保您的数据安全。

设置 MySQL 数据库

本配方展示了如何在 CentOS 上执行 MySQL 流行数据库服务器的基本安装。MySQL 是目前第二大最广泛使用的数据库系统,广泛应用于各行各业,为从动态网站到大规模数据仓库等所有内容提供数据存储。

准备工作

本配方要求使用 CentOS 系统,具有有效的网络连接和管理员权限,您可以使用root账户或sudo

如何操作...

按照以下步骤安装 MySQL 并创建一个新数据库:

  1. 下载由 Oracle 维护的 MySQL 仓库的仓库配置包:

    curl -LO dev.mysql.com/get/mysql57-community-release-el7-
           7.noarch.rpm
    
    
  2. 安装下载的包:

    yum install mysql57-community-release-el7-7.noarch.rpm
    
    
  3. 现在 MySQL 仓库已注册,安装mysql-community-server包:

    yum install mysql-community-server
    
    
  4. 启动 MySQL 服务器,并启用它在每次系统重启时自动启动:

    systemctl start mysqld.service
    systemctl enable mysqld.service
    
    
  5. 在系统防火墙中打开端口3306,以允许外部连接到 MySQL:

    firewall-cmd --zone=public --permanent --add-service=mysql
    firewall-cmd --reload
    
    
  6. 从服务器日志文件中获取 MySQL root用户的临时密码:

    grep "temporary password" /var/log/mysqld.log
    
    
  7. 使用mysqladmin设置root的新密码。当程序提示输入当前密码时,输入从日志中找到的临时密码:

    mysqladmin -u root -p password
    
    
  8. 使用mysql连接到 MySQL 服务器,使用root账户:

    mysql -u root -p
    
    
  9. 要创建一个新数据库,执行CREATE DATABASE语句:

    CREATE DATABASE packt;
    
    
  10. 执行CREATE USER语句,为 MySQL 创建一个用户账户,用于操作数据库:

    CREATE USER "tboronczyk"@"localhost" IDENTIFIED  BY "P@$$W0rd";
    
    
  11. 执行GRANT语句,将适当的权限分配给新数据库的账户:

    GRANT CREATE, DROP, ALTER, LOCK TABLES, INDEX,  INSERT, UPDATE, 
           SELECT, DELETE ON packt.* TO 
    "tboronczyk"@"localhost";
    
    
  12. 执行FLUSH PRIVILEGES,指示 MySQL 重新构建其权限缓存:

    FLUSH PRIVILEGES;
    
    
  13. 退出 MySQL 客户端并返回终端:

    exit
    
    

它是如何工作的...

我们首先下载了一个包,用于在我们的系统上注册 Oracle 维护的 MySQL 仓库。MySQL 是从 Oracle 仓库安装的,因为 CentOS 仓库会安装 MariaDB。经过一系列收购事件(2008 至 2010 年),MySQL 的代码库和商标成为了 Oracle 的财产。由于人们普遍担心 Oracle 对 MySQL 的管理以及 MySQL 的未来,其中一位原始开发者将该项目分叉并创建了 MariaDB。2014 年,Red Hat 和 CentOS 仓库将默认数据库从 MySQL 替换为 MariaDB(欢迎来到开源政治的世界)。

注意

MariaDB 的目标是保持作为一个免费的开源项目,遵循 GNU GPL 许可证,并成为 MySQL 的“增强型、即插即用替代品”。目前,这两个之间的差异对普通用户来说几乎可以忽略不计。但在分叉替代品的世界里,主要是编程接口和通信协议保持兼容。核心功能在初期可能保持一致,但随着时间的推移,新的功能将独立添加,产品的功能集开始出现分歧。MariaDB 用版本号的跳跃来体现这一点。MariaDB 5.1 提供了与 MySQL 5.1 相同的功能,MariaDB 5.5 也同样如此。但 MariaDB 不打算实现 MySQL 5.6 的所有功能,并将其版本号更改为 10.0。对于那些在家里计算的人来说,在写这篇文章时,Oracle 维护的仓库中托管的是 MySQL 5.7,而 CentOS 仓库当前提供的是 MariaDB 5.5。

托管该包的服务器假设人们通过网页浏览器下载文件,并发出重定向以开始下载。由于我们使用的是 curl,所以我们提供了 -L 参数,以便跟随重定向到达实际的包文件:

curl -LO dev.mysql.com/get/mysql57-community-release-el7-7.noarch.rpm

接下来,我们安装了下载的包。仓库注册完成后,我们可以使用 mysql-community-server 包来安装 MySQL。该包安装了服务器二进制文件,而与 MySQL 配套的客户端工具则作为依赖项一同安装:

yum install mysql57-community-release-el7-7.noarch.rpm
yum install mysql-community-server

MySQL 维护着自己的用户账户,默认的管理员账户是 root。就像 CentOS 的 root 用户一样,你不应该用该账户进行常规活动;它应当保留用于管理任务,如创建新用户、授予权限以及刷新服务器缓存等。其他权限较低的账户应当用于日常活动。为了保护 root 账户,MySQL 在第一次启动时会随机生成其密码。我们需要查找 MySQL 记录密码的日志文件,以便设置一个我们自己选择的新密码:

grep "temporary password" /var/log/mysqld.log

知道了临时密码后,我们使用mysqladmin更改了密码。-u选项指定 MySQL 账户的用户名,-p提示我们输入密码,password是用于更改密码的子命令。我们在提示输入原始密码时输入了临时密码,然后系统提示我们输入并确认新密码:

mysqladmin -u root -p password

注意

root的默认密码是从 MySQL 5.6 开始的新行为,它会将密码写入/root/.mysql_secret,而 5.7 版本则将其写入日志文件。在旧版本中(因此 MariaDB 从 5.5 版本开始由 CentOS 仓库安装),密码是空的。validate_password插件也在 MySQL 5.7 中启用。它要求密码至少包含 8 个字符,并且至少包含一个数字、一个大写字母、一个小写字母和一个特殊字符(即标点符号)。在选择 root 的新密码时,请考虑这些要求。

它是如何工作的...

需要临时密码来设置 root 的永久密码

有多个客户端可以用来连接 MySQL 并与数据库进行交互。本示例使用了mysql,因为它会作为默认依赖项安装。再次说明,-u表示账户的用户名,-p会提示我们输入密码:

mysql -u root -p

在交互模式下运行时,客户端显示mysql>提示符,我们在此提交 SQL 语句。每执行完一个查询后,客户端会显示服务器的响应、语句执行的时间以及服务器报告的任何错误或警告。

我们在提示符下发出了CREATE DATABASE语句,以创建名为packt的新数据库:

CREATE DATABASE packt;

然后,我们创建了一个新用户账户CREATE USER,以避免在日常工作中使用root账户。该账户名为tboronczyk,并允许从本地主机进行身份验证:

CREATE USER "tboronczyk"@"localhost" IDENTIFIED BY "P@$$w0rd";

如果账户需要从不同的系统连接到服务器,可以用系统的主机名或 IP 地址替代localhost。不过,MySQL 会将每个用户名和主机名组合视为独立的账户。例如,tboronczyk@localhosttboronczyk@ 192.168.56.100是不同的账户,并且可以为它们分配不同的权限。

注意

你可以在主机名中使用通配符,创建可以从多个系统连接的账户。%通配符匹配零个或多个字符,因此可以用来表示任何系统:

**CREATE USER "tboronczyk"@"%" IDENTIFIED BY "P@$$w0rd";**

新账户创建时没有任何权限,因此我们必须通过执行GRANT语句来分配权限:

GRANT CREATE, DROP, ALTER, LOCK TABLES, INSERT, UPDATE, SELECT,  
DELETE ON packt.* TO "tboronczyk"@"localhost";

该语句为用户分配以下权限,适用于packt数据库中的所有表(用*表示):

  • CREATE:允许用户创建数据库和表

  • DROP:允许用户删除整个表和数据库

  • ALTER:允许用户更改现有表的定义

  • LOCK TABLES:允许用户锁定表,以便独占读写访问

  • INDEX:此命令允许用户创建表索引

  • INSERT:此命令允许用户向表中添加记录

  • UPDATE:此命令允许用户更新表中的记录

  • SELECT:此命令允许用户从表中检索记录

  • DELETE:此命令允许用户从表中删除记录

可以在 MySQL 官方文档中找到完整的权限列表及其允许用户执行的操作,网址为 dev.mysql.com/doc/refman/5.7/en/grant.html

接下来,我们指示 MySQL 使用 FLUSH PRIVILEGES 重建其权限缓存:

    FLUSH PRIVILEGES; 

当 MySQL 启动时,它会将用户和权限信息缓存到内存中(你会记得在第五章,《管理文件系统和存储》中提到,读取内存中的数据比从磁盘读取要快得多),然后每次用户执行操作时,都会检查缓存以验证他们是否拥有足够的权限。每当我们创建或删除用户账户,或授予或撤销账户权限时,需要告诉 MySQL 更新其缓存,否则我们所做的更改将不会被注意到,直到下次 MySQL 启动。

使用 mysql 连接到 MySQL 时,你可能经常使用额外的选项。一个常见选项是 -h,它标识远程服务器的主机名或 IP 地址,如果 MySQL 在不同的系统上运行。-e 直接执行语句,而不是启动 mysql 交互模式。此外,若要操作特定数据库,可以在其余命令后给出数据库名称,或者使用 -D 来指定。以下示例演示了如何通过连接到 192.168.56.100 上的 MySQL 服务器,并对其 sakila 数据库执行 SELECT 语句:

mysql -u tboronczyk -p -h 192.168.56.100 -D sakila -e "SELECT  
last_name, first_name FROM actor"

另见

查阅以下资源以获取有关使用 MySQL 的更多信息:

备份和恢复 MySQL 数据库

本食谱向你展示如何使用 mysqldump 备份 MySQL 数据库。该工具连接到 MySQL 服务器,查询数据库的结构及其数据,并以 SQL 语句的形式输出数据。然后,备份可以用于恢复数据库或将数据填充到新数据库中。

准备工作

本食谱要求 MySQL 服务器正在运行,并且可以访问 MySQL 的 root 用户或其他具有必要权限的用户,以执行备份。

如何操作...

按照以下步骤备份 MySQL 数据库:

  1. 连接到你想要备份的 MySQL 数据库:

    mysql -u root -p packt
    
    
  2. 执行FLUSH TABLES语句将数据库的表设置为只读:

    FLUSH TABLES WITH READ LOCK;
    
    
  3. 打开第二个终端,保持第一个终端活动,并且mysql客户端仍在运行。

  4. 在新终端中,使用mysqldump导出表的定义和数据:

    mysqldump -u root -p packt > backup.sql
    
    
  5. 备份完成后,返回第一个终端并退出mysql以解锁表。

    由于备份由 SQL 语句组成,你可以通过使用mysql导入这些语句来重建数据库:

    mysql -u root -p packt < backup.sql
    
    

它是如何工作的……

数据丢失的后果可能从轻微的烦恼到严重的经济后果不等,因此备份是保护自己的一种重要方式。想象一下,如果银行丢失了你所有的财务记录,会发生什么!你的数据对你有多重要,以及如果丢失了它有多难以重建,那么拥有备份以防万一就显得尤为重要。

在备份之前,我们连接到服务器并执行了FLUSH TABLES。该语句强制 MySQL 完成任何待处理的数据更新,然后将表设置为只读,以防止在备份过程中对数据进行修改。这确保了我们备份中的数据是一致的:

FLUSH TABLES WITH READ LOCK;

在我们释放锁之前,表将保持只读状态,可以通过执行UNLOCK TABLES语句或终止与 MySQL 服务器的连接来释放锁,因此我们保持当前会话运行,并打开第二个终端来执行备份。当表处于只读状态时,任何检索数据的查询都会执行,但那些更新或插入数据的查询会被阻止。

注意

考虑按照配置 MySQL 复制配方中所描述的设置 MySQL 复制,然后备份从服务器上的数据库副本,以避免任何停机。停止从服务器的复制,使用mysqldump导出数据,然后恢复复制。主服务器的表不需要被锁定,在复制暂停期间主服务器所做的任何更改将在从服务器重新上线后被复制。

然后,我们使用mysqldump从数据库中导出所有表的定义和数据:

mysqldump -u root -p packt > backup.sql

通过在备份文件名中包含日期,保持文件有序:

mysqldump -u root -p packt > backup-$(date +%F).sql

mysqldump查询数据库以检索数据,因此无论我们使用哪个帐户来执行备份,它都必须具有必要的权限。具体需要哪些权限,最终取决于你的数据库架构。例如,如果数据库使用视图,则帐户需要SHOW VIEW权限。用于恢复数据库的帐户也必须具备相同的权限。如果你希望为备份和恢复活动使用专用帐户,应该记住这一点。

要仅备份某些表,可以在数据库后列出它们。例如,以下命令备份customersaddresses表:

mysqldump -u root -p packt customers addresses > backup.sql

你还可以为mysqldump提供一些选项,这些选项会影响备份中包含的内容。以下是一些常用选项的列表:

  • --no-add-drop-table:此选项不包括在任何 CREATE TABLE 语句之前的 DROP TABLE 语句。如果没有先删除表,恢复备份时,已经定义了表的系统可能会在执行 CREATE TABLE 语句时失败。

  • --events:此选项导出与数据库关联的任何存储事件的定义。

  • --hex-blob:此选项使用十六进制表示法输出二进制值。这有助于防止某些字节序列被错误地解释,从而导致恢复失败。

  • --tables:此选项仅备份指定的表。这是指定表的另一种方式,而不是在数据库名称后列出它们。

  • --routines:此选项导出与数据库关联的任何存储过程的定义。

  • --where:这是一个 WHERE 条件,用于返回特定的行。例如,--tables customers --where "last_name LIKE 'B%'" 将仅导出 customers 表中姓氏以 B 开头的客户行。

你可以在在线文档中找到完整的选项列表:dev.mysql.com/doc/refman/5.7/en/mysqldump.html

另见

参考以下资源获取更多有关使用 mysqldump 进行备份的信息:

配置 MySQL 复制

本篇教程将教你如何配置 MySQL 的主从复制,以在接近实时的情况下维护数据库的镜像副本。

为了进行数据复制,主 MySQL 服务器记录所有发生的更改(如插入、更新等)的详细信息,并将其写入名为二进制日志的文件中。每个从服务器连接到主服务器系统,读取日志文件中的信息,然后复制更改,以维护自己的本地数据库副本。每个从服务器独立负责自己,这意味着我们可以将从服务器停机进行维护,而不会影响主服务器的可用性。一旦从服务器恢复上线,它将从上次停止的地方继续复制。

复制在许多情况下都非常有用。例如,如果在从服务器上维护了数据库的完整副本,您可以轻松地将主服务器切换为故障转移或灾难恢复。对于那些对可扩展性和性能有要求的环境,可以由主服务器执行写操作,而由多个只读从服务器处理密集的读操作,这些从服务器位于负载均衡器后面。

准备工作

本食谱演示了如何使用两台系统配置 MySQL 复制。第一台系统是主 MySQL 服务器,我们假设它的 IP 地址为192.168.56.100。第二台系统是从服务器,地址为192.168.56.101。你需要在两个系统上都有管理员访问权限,使用root账户或sudo来完成配置。

两台系统都应该已经安装了 MySQL,如之前的设置 MySQL 数据库食谱所述。如果你在主服务器上已创建一个或多个数据库后才设置复制,请按照备份和恢复 MySQL 数据库食谱备份并导入到从服务器,再进行复制配置。这能确保复制开始时所有数据库都保持同步。

如何做...

按照以下步骤配置 MySQL 主从复制:

  1. 使用文本编辑器打开主 MySQL 服务器的配置文件/etc/my.cnf

    vi /etc/my.cnf
    
    
  2. [mysqld]部分,为server-id选项添加一个新条目,并将其值设置为1

    server-id = 1
    
    
  3. 找到log_bin选项并取消注释:

    log_bin
    
    
  4. 保存更改并关闭配置文件。

  5. 重启服务器以使更改生效:

    systemctl restart mysqld.service
    
    
  6. 使用mysql连接到主服务器并为从服务器创建一个新账户。该账户需要REPLICATION SLAVE权限:

    CREATE USER "slave"@"192.168.56.101" IDENTIFIED BY "S3CR3t##";
    GRANT REPLICATION SLAVE ON *.* TO "slave"@"192.168.56.101";
    FLUSH PRIVILEGES;
    
    
  7. 执行SHOW MASTER STATUS以确定主服务器当前在写入二进制日志时的位置。注意返回的FilePosition值,因为这些信息在配置从服务器时会用到:

    SHOW MASTER STATUS;
    
    

    如何操作...

    主服务器的状态包括日志文件名和服务器的写入位置:

  8. 使用编辑器打开从服务器的配置文件。为server-id选项添加一个新条目,并将其值设置为2

    server-id = 2
    
    
  9. read-only选项添加一个条目:

    read-only
    
    
  10. 保存更改并关闭文件。

  11. 重启从服务器以使更改生效:

    systemctl restart mysqld.service
    
    
  12. 要配置与主服务器的通信,请使用mysql连接到从服务器,并执行CHANGE MASTER语句。该值应反映第 7 步中SHOW MASTER STATUS返回的内容:

    CHANGE MASTER TO
     MASTER_HOST = "192.168.56.100",
     MASTER_USER = "slave",
     MASTER_PASSWORD = "S3CR3t##", 
     MASTER_LOG_FILE = "localhost-bin.000003",
     MASTER_LOG_POS = 1235;
    
    
  13. 通过在从服务器系统上执行START SLAVE来启动复制过程:

    START SLAVE;
    
    
  14. 执行SHOW SLAVE STATUS以验证复制是否正在运行。返回的Slave_IO_RunningSlave_SQL_Running值都应为Yes

    SHOW SLAVE STATUS\G
    
    

    SHOW SLAVE STATUS会返回大量信息——列出为表格,由于列换行,输出几乎无法阅读。使用\G来执行语句(与分号不同)会让mysql以垂直方式显示结果,在这种情况下,阅读起来更加清晰。

  15. 要停止复制,请在从服务器系统上执行STOP SLAVE

它是如何工作的...

配置开始于主服务器的/etc/my.cnf文件,在此文件中我们添加了server-id选项,为服务器指定了一个数字标识符。复制环境中的每个服务器都使用此标识符与其他服务器进行区分,因此它必须在环境中是唯一的。然后,我们取消注释了log_bin选项,指示服务器记录每次变更的详细信息到二进制日志。

工作原理...

主服务器的配置文件设置了服务器标识符并启用了日志记录

接下来,我们在主服务器上创建了一个专用账户,并授予其REPLICATION SLAVE权限。从服务器将使用此账户连接主服务器并从日志中读取数据:

CREATE USER "slave"@"192.168.56.101" IDENTIFIED BY "S3CR3t##";
GRANT REPLICATION SLAVE ON *.* TO "slave"@"192.168.56.101";

最后,我们执行了SHOW MASTER STATUS命令。结果中FilePosition的值标识了二进制日志文件的名称以及服务器在其中的当前位置。随着主服务器向日志写入数据,位置会增加,并且当日志文件轮换时,日志文件名的后缀也会发生变化。我们需要知道当前的位置,以便配置从服务器从该点开始读取/复制。

在从服务器上,我们设置了服务器的唯一标识符,并在配置文件中添加了read-only选项。如果有人在从服务器的数据库中做出更改,并且该更改与来自二进制日志的传入更新冲突,复制将会中断。read-only选项是一个防护措施,防止用户直接更新从服务器的数据库,确保所有更新都来自主服务器。

接下来,我们使用CHANGE MASTER语句设置从服务器的复制过程。CHANGE MASTER语句指定了主服务器,设置了从服务器用于连接的用户名和密码,并指定了日志文件的名称及从当前的位置开始复制:

CHANGE MASTER TO
 MASTER_HOST = "192.168.56.100",
 MASTER_USER = "slave",
 MASTER_PASSWORD = "S3CR3t##", 
 MASTER_LOG_FILE = "localhost-bin.000003",
 MASTER_LOG_POS = 1235;

复制过程通过START SLAVE命令启动,通过STOP SLAVE命令停止。SHOW SLAVE STATUS命令返回关于当前复制状态的信息:

工作原理...

我们可以检查从服务器的状态,以查看复制是否正常运行且没有任何问题。

当复制运行时,MySQL 会创建两个后台进程——一个与主服务器通信(IO 进程),另一个执行 SQL 语句以维护本地数据库(SQL 进程)。Slave_IO_Running值显示通信进程是否正在运行,而Slave_SQL_Running值反映执行进程是否正在运行。当复制正常运行时,这两个值都应该是Yes

如果复制出现问题,Last_IO_ErrorLast_SQL_Error条目将报告各自进程抛出的任何错误。通过比较Master_Log_FileRead_Master_Log_Pos字段的值与SHOW MASTER STATUS返回的结果,也可以查看从服务器与主服务器之间的延迟情况。

当前配置允许从库复制来自主库的每个数据库,但我们也可以通过在从库的 my.cnf 文件中添加 replicate-do-db 条目来限制复制到特定的数据库。可以添加多个条目,每个条目对应一个数据库:

replicate-do-db = packt
replicate-do-db = acme
replicate-do-db = sakila

或者,我们可以使用 replicate-ignore-db 选项来复制所有数据库,除非是特定的数据库:

replicate-ignore-db = mysql

复制也可以在表级进行过滤,使用 replicate-do-tablereplicate-ignore-table 选项来定位和忽略数据库中的特定表:

replicate-do-table = acme.customers
replicate-do-table = acme.addresses

另请参见

请参考以下资源,了解更多关于 MySQL 数据库复制的信息:

搭建 MySQL 集群

本教程指导您设置 MySQL 集群的过程。集群数据库通过将数据分布到多个系统并维护副本来避免单点故障,从而应对可扩展性和高可用性的挑战。

集群中的成员被称为节点。MySQL 集群中有三种节点类型:数据节点、API 节点和管理节点。数据节点负责存储数据。用户和进程通过连接到 API 节点来访问数据库。管理节点则负责管理整个集群。尽管可以在同一系统上安装多个节点,例如,一个系统可能同时托管 API 节点和数据节点,但在同一系统上托管多个数据节点显然不是一个好主意,因为这会抵消 MySQL 将数据分布到多个系统的努力。

准备工作

本教程演示如何使用四台系统部署 MySQL 集群。第一台系统将托管管理节点,假设其 IP 地址为 192.168.56.100。第二台系统将托管 API 节点,地址为 192.168.56.101。其余系统将配置为数据节点,地址为 192.168.56.102192.168.56.103。你需要在这四台系统上具有管理员权限,可以使用 root 账户或 sudo

操作步骤...

按照以下步骤设置集群化的 MySQL 数据库:

  1. 从 MySQL 网站下载集群压缩包并使用 tar 解压其包:

    curl -L dev.mysql.com/get/Downloads/MySQL-Cluster-7.4/  
           MySQL-Cluster-gpl-7.4.10-1.el7.x86_64.rpm-bundle.tar | tar  x
    
    
  2. 在每个系统上安装 perl-Data-Dumper 并用下载的 MySQL-Cluster-shared 包替换已安装的 mariadb-libs 包:

    yum install perl-Data-Dumper MySQL-Cluster-shared-gpl-*.rpm
    yum erase mariadb-libs
    
    
  3. 在每个系统上安装MySQL-Cluster-serverMySQL-Cluster-client包:

    yum install MySQL-Cluster-{server,client}-gpl-*.rpm
    
    
  4. 在托管管理节点的系统上创建/var/lib/mysql-cluster目录:

    mkdir /var/lib/mysql-cluster
    
    
  5. 为管理节点创建集群的配置文件/var/lib/mysql-cluster/config.ini,内容如下:

    [ndbd default]
    NoOfReplicas = 2
    DataMemory = 100M
    IndexMemory = 10M
    ServerPort = 2202
    [ndb_mgmd]
    hostname = 192.168.56.100
    [mysqld]
    hostname = 192.168.56.101
    [ndbd]
    hostname = 192.168.56.102
    [ndbd]
    hostname = 192.168.56.103
    
    
  6. 启动管理节点:

    ndb_mgmd -f /var/lib/mysql-cluster/config.ini
    
    
  7. 在管理节点系统的防火墙中打开端口1186

    firewall-cmd --zone=public --permanent --add-port=1186/tcp
    firewall-cmd --reload
    
    
  8. 在每个数据节点系统上,使用以下内容创建/etc/my.cnf文件:

    [mysql_cluster]
    ndb-connectstring = 192.168.56.100
    
    
  9. 启动每个数据节点:

    ndbd
    
    
  10. 在数据节点系统的防火墙中打开端口2202

    firewall-cmd --zone=public --permanent --add-port=2202/tcp
    firewall-cmd --reload
    
    
  11. 在托管 API 节点的系统上创建/etc/my.cnf,内容如下:

    [mysqld]
    ndbcluster
    default-storage-engine = ndbcluster
    [mysql_cluster]
    ndb-connectstring = 192.168.56.100
    
    
  12. 将 MySQL 服务器作为 API 节点启动:

    mysqld_safe &
    
    
  13. 检索在安装 MySQL 服务器时创建的root账户临时密码。该密码记录在/root/.mysql_secret中:

    cat /root/.mysql_secret
    
    
  14. 使用mysqladmin为 root 账户设置新密码。当提示输入当前密码时,输入上一步中识别的密码:

    mysqladmin -u root -p password
    
    
  15. 在 API 节点系统的防火墙中打开端口3306

    firewall-cmd --zone=public --permanent --add-service=mysql
    firewall-cmd --reload
    
    
  16. 使用托管管理节点的系统上的ndb_mgm客户端验证集群的状态:

    ndb_mgm -e SHOW
    
    

工作原理...

本食谱介绍了如何设置具有两个数据节点的 MySQL 集群数据库:一个 API 节点和一个管理节点。管理节点由ndb_mgmd进程组成,该进程向其他节点提供配置信息并监控它们。在数据节点上,ndbd进程处理集群数据的存储、分区和复制。一个了解管理节点和数据节点的 MySQL 服务器充当 API 节点,供用户与集群数据库交互。

在 Oracle 维护的仓库中提供的包没有支持网络数据库(NDB)的功能,因此我们首先从 MySQL 官网上下载了一个包含支持 NDB/集群的 MySQL 版本的包:

curl -L dev.mysql.com/get/Downloads/MySQL-Cluster-7.4/MySQL- 
Cluster-gpl-7.4.10-1.el7.x86_64.rpm-bundle.tar | tar x

MySQL 抽象了数据如何在物理上组织和操作的细节,将其委托给不同的存储引擎。不同的引擎具有不同的能力。由于 NDB 引擎是实现集群的引擎,我们需要一个支持该引擎的版本。与以往将 curl 的输出写入文件不同,这次我们将输出直接传递给tar,并使用x参数即时展开压缩包。

之后,我们从 CentOS 仓库安装了perl-Data-Dumper包,并用刚下载的MySQL-Cluster-shared包替换了每个系统中已安装的mariadb-libs包:

yum install perl-Data-Dumper MySQL-Cluster-shared-gpl-*.rpm
yum erase mariadb-libs

MySQL-Cluster-shared包提供了其他程序用来与 MySQL 协作的共享库。这些库替换了从 CentOS 仓库默认安装的 MariaDB 版本,避免了库冲突,确保安装干净。由于不再需要,我们卸载了mariadb-libs包。

Yum 在安装完 MySQL-Cluster-server 包后执行的一些后安装步骤是用 Perl 脚本编写的,并使用了 Perl 的 Data::Dumper 模块。这使得 Perl-Data-Dumper 包成为 MySQL-Cluster-server 包的一个依赖项。然而,一个错误导致 Yum 没有注意到这一点,所以我们自己安装了这个包,以便 MySQL-Cluster-server 包的安装能够顺利进行。这不会阻止包的安装,但会要求我们手动完成一些额外的配置步骤。

在满足需求后,我们在每个系统上安装了 MySQL-Cluster-serverMySQL-Cluster-client 包:

yum install MySQL-Cluster-{server,client}-gpl-*.rpm

针对整个集群的配置基本上是集中在 /var/lib/mysql-cluster/config.ini 中的管理节点。该文件分为几个部分,第一个部分是 [ndb default],它提供了应该用于集群的默认配置值。这里的值适用于集群的每个节点,除非在各自节点的配置部分中被更具体的指令覆盖。

[ndbd default]
NoOfReplicas = 2
DataMemory = 100M
IndexMemory = 10M
ServerPort = 2202

NoOfReplicas 选项设置了集群中副本的数量。它的值可以设置为 12,尽管推荐值为 2。请记住,一个集群化的数据库不仅在数据节点上进行分区,还会进行复制;每个节点通常托管数据库大小的 1/n 的分区(其中 n 是数据节点的数量),并且还会有其他节点的副本。即使系统下线,集群仍然可以运行,因为其数据仍然可以在副本中找到。将 NoOfReplicas 设置为 1 表示数据库只有一个副本(没有副本),数据库的可用性取决于所有数据节点是否正常运行。

数据节点将数据库的工作副本保存在 RAM 中以减少延迟,同时定期将数据同步到磁盘。DataMemory 选项指定了节点应为数据保留多少 RAM,而 IndexMemory 指定了应为主键和唯一索引保留多少内存。无论您提供什么值,请确保有足够的资源可用以避免 RAM 交换。

ServerPort 选项指定了节点之间通信所使用的端口号。默认情况下,MySQL 会动态分配端口以便在同一系统上运行多个节点更容易,但由于此方案在每个节点上运行在其自己的主机系统上,并且我们需要知道端口以允许通过防火墙的流量,因此我们自行指定了端口。

配置中的后续部分使用 hostname 选项指定管理节点(通过 [ndb_mgmtd] 部分)、API 节点(通过 [mysqld] 部分)和数据节点(通过 [ndbd] 部分)运行的地址。如果同一类型的节点在集群中运行多个,则会显示多个相同类型的部分:

[ndb_mgmd]
hostname = 192.168.56.100
[mysqld]
hostname = 192.168.56.101
[ndbd]
hostname = 192.168.56.102
[ndbd]
hostname = 192.168.56.103

在其余系统中,/etc/my.cnf 作为数据节点和 API 节点使用的配置文件被创建。每个都包括 [mysql_cluster] 部分,其中提供了 ndb-connectstring 选项:

[mysql_cluster]
ndb-connectstring = 192.168.56.100

ndb-connectstring 选项指定托管管理节点的系统的地址。随着数据和 API 节点上线,它们将与管理器通信,以接收其配置信息。如果您的集群有多个管理节点,则可以在连接字符串中以逗号分隔列出其他节点:

ndb-connectstring = "192.168.56.100,192.168.56.105,192.168.56.106"

此外,API 节点的配置包括 [mysqld] 部分。其中包含 ndbcluster 选项以启用 NDB 引擎,并且 default-storage-engine 选项指示 MySQL 在没有在 CREATE TABLE 语句中特别指定的情况下,使用 NDB 管理所有新表:

[mysqld]
ndbcluster
default-storage-engine = ndbcluster

当用户或进程使用 CREATE TABLE 语句创建新表时,他们可以使用 ENGINE 指令指定 MySQL 的存储引擎来管理其数据,例如:

CREATE TABLE users (
 id INTEGER UNSIGNED NOT NULL PRIMARY KEY,
 first_name VARCHAR(50) NOT NULL DEFAULT '',
 last_name VARCHAR(50) NOT NULL DEFAULT ''
)
ENGINE = NDBCluster;

默认引擎是 InnoDB 引擎。但是,只有由 NDB 管理的表中的数据才会传输到集群中。如果表由其他引擎管理,则数据会留存在 API 节点本地,并且不会对集群中的其他节点可用。为了避免可能引起的意外问题和混淆,我们更改了默认引擎,使表在未提供 ENGINE 指令时使用 NDB 引擎。

在启动 MySQL 集群时,节点的启动顺序很重要,因为一个节点可能依赖于其他节点。首先启动管理节点,然后是数据节点,最后是 API 节点。

在 API 节点上,MySQL 根帐户的密码在服务器首次启动时是随机生成的,并写入 /root/.mysql_secret 文件,就像我们在 设置 MySQL 数据库 配方中使用 mysqladmin 更改它一样:

cat /root/.mysql_secret
mysqladmin -u root -p password

在管理节点系统上发送给 ndb_mgm 客户端的 SHOW 命令允许我们查看集群的状态,并确保一切正常运行。客户端可以以交互模式调用,或者可以直接使用 -e 参数传递命令:

ndb_mgm -e SHOW

How it works...

可以使用 ndb_mgm 客户端查看 MySQL 集群的状态。

另请参阅

关于使用 MySQL 集群的更多信息,请参考以下资源:

设置 MongoDB 数据库

尽管关系型数据库已经主导了数据存储领域,但一直存在其他专注于以不同方式处理数据的系统,例如文档型数据库、面向对象的数据库、键值数据库和层次型数据库。随着NoSQL大数据运动的兴起,这些替代型数据库的受欢迎程度重新回升。本教程教你如何安装 MongoDB,这是一个现代的文档型数据库系统。

准备工作

本教程要求使用一个 CentOS 系统,并具备有效的网络连接和管理员权限,可以通过root账户或sudo来获得权限。它还假设你已经注册了 EPEL 仓库(请参见第四章中的注册 EPEL 和 Remi 仓库教程,软件安装管理)。

如何操作…

按照以下步骤安装 MongoDB 并创建一个新的数据库:

  1. 从 EPEL 仓库安装mongodb-servermongodb软件包:

    yum install mongodb-server mongodb
    
    
  2. 使用文本编辑器打开/etc/mongod.conf

    vi /etc/mongod.conf
    
    
  3. 找到auth条目并取消注释,确保其值为true

    # Run with/without security
    auth = true
    
    
  4. 找到bind-ip选项并注释掉:

     # Comma separated list of ip addresses to listen on 
           # bind_ip = 127.0.0.1
    
    
  5. 保存对配置文件的更改并关闭它。

  6. 启动 MongoDB 服务器并启用其在系统重启时自动启动:

    systemctl start mongod.service
    systemctl enable mongod.service
    
    
  7. 在系统防火墙中打开27017端口:

    firewall-cmd --zone=public --permanent --add-port=27017/tcp
    firewall-cmd --reload
    
    
  8. 使用mongo连接到 MongoDB 服务器:

    mongo
    
    
  9. 设置admin为当前活动数据库:

    use admin
    
    
  10. 执行createUser()来创建一个新的用户,用于管理用户账户:

    db.createUser({
     user: "admin",
     pwd: "P@$$W0rd",
     roles: [{ role: "userAdminAnyDatabase", db: "admin" }]
    })
    
    
  11. 使用新创建的admin账户进行身份验证:

    db.auth({ user: "admin", pwd: "P@$$W0rd" })
    
    
  12. 设置packt为当前活动数据库:

    use packt
    
    
  13. 创建一个用于操作数据库的用户账户:

    db.createUser({
     user: "tboronczyk",
     pwd: "S3CR3t##",
     roles: [{ role: "readWrite", db: "packt" }]
    })
    
    
  14. 退出客户端并返回终端:

    exit
    
    

工作原理...

MongoDB 是同类数据库中最受欢迎的,被许多知名公司使用,包括 eBay、Craigslist、SAP 和 Yandex。所需的软件包可以在 EPEL 仓库中找到;mongodb-server 包含 MongoDB 服务器应用程序,而 mongodb 包含客户端和其他用于与服务器及数据库交互的工具:

yum install mongodb-server mongodb

默认情况下,MongoDB 在未启用安全性的情况下运行,任何人都可以对任何数据库执行任何操作。为了防止这种情况,我们通过取消注释 MongoDB 配置文件(/etc/mongod.conf)中的 auth 选项来启用安全性。启用安全性后,用户必须先进行身份验证才能与数据库交互,服务器会验证该账户是否有权执行请求的操作:

auth = true

当前的配置允许 MongoDB 仅在回环接口(127.0.0.1)上监听连接,因此我们还注释掉了 bind_ip 选项:

# bind_ip = 127.0.0.1

如果不绑定,MongoDB 将通过系统的所有地址进行访问。或者,如果系统有多个地址(可能系统有多个接口,或者你在第二章的绑定多个地址到单个以太网设备示例中实现了此功能,网络),并且你只希望 MongoDB 响应其中一个地址,可以保持选项激活,并将所需的 IP 地址作为其值。

更新配置文件后,我们启动了服务器,并在系统防火墙中打开了 MongoDB 的默认端口,以允许远程连接:

firewall-cmd --zone=public --permanent --add-port=27017/tcp
firewall-cmd --reload

接下来,我们使用 mongo 客户端与运行在本地主机上的 MongoDB 服务器建立连接:

mongo

我们设置 admin 为活动数据库,并执行 createUser() 方法来创建一个管理员账户,用于管理 MongoDB 的数据库用户:

use admin
db.createUser({
 user: "admin",
 pwd: "P@$$W0rd",
 roles: [{ role: "userAdminAnyDatabase", db: "admin" }]
})

createUser() 方法接受一个文档,其中列出了新账户的用户名(user)、密码(pwd)和角色(roles),并将其添加到活动数据库(admin)中的 system.users 集合中。用户账户存储在数据库级别,而存储用户详细信息的数据库被称为该用户的身份验证数据库。用户可以与其他数据库进行交互,但他们必须首先在身份验证数据库中进行身份验证。即使用户名相同,在不同数据库中创建的账户也被视为独立账户,可能具有不同的权限。

roles 属性是一个对象数组,每个对象列出用户在与给定数据库交互时所属的角色。以 admin 为例,用户是 userAdminAnyDatabase 角色的成员。MongoDB 的权限系统基于基于角色的访问控制(RBAC)。RBAC 的重点是用户及其角色,而不是向每个账户授予单独的权限。权限分配给角色,然后用户账户会成为该角色的成员,从而继承角色的权限。

userAdminAnyDatabase 是一个内置角色,配置了必要的权限,可以为任何数据库创建和删除用户账户,分配角色成员资格,并管理用户密码。MongoDB 除了 userAdminAnyDatabase 外,还提供了多个预定义的角色,包括以下角色:

  • dbAdmin:这些用户负责管理数据库

  • userAdmin:这些用户负责管理其他用户

  • read:这些用户仅从数据库中读取文档

  • readWrite:这些用户可以读取文档,并且需要写权限来插入/修改文档

  • dbOwner:这些用户拥有数据库(结合了 dbAdminuserAdminreadWrite 角色)

还有 backuprestore 角色,供负责执行数据库备份的用户使用,管理 MongoDB 集群的角色,以及一些上述角色的全局版本,如 readAnyDatabase,供需要对所有 MongoDB 数据库进行读取访问的用户使用。完整的角色列表可以在官方文档中找到,网址:docs.mongodb.com/manual/reference/built-in-roles/

注意

最小权限原则鼓励我们避免过度使用全局角色;最好是创建与自己的数据库协作的用户。如果一个账户需要与其认证数据库之外的数据库进行交互,可以按以下方式分配多个角色:

  db.createUser({
 user: "tboronczyk",
 pwd: "S3CR3t##",
 roles: [
 { role: "read", db: "admin" },
 { role: "readWrite", db: "packt" },
 { role: "readWrite", db: "acme" }
 ]
 })

接下来,我们使用新的 admin 用户为 packt 数据库创建了一个新用户(并顺便创建了 packt 数据库):

db.auth("admin", "P@$$W0rd")
use packt
db.createUser({
 user: "tboronczyk",
 pwd: "S3CR3t##",
 roles: [{ role: "readWrite", db: "packt" }]
})

当第一个文档被插入时,MongoDB 会隐式创建数据库和集合,并且由于 MongoDB 将新用户存储在活动数据库中,因此将 packt 设置为活动数据库并创建用户就足以触发它的创建。

auth() 方法假设活动数据库是提供的凭据的认证数据库。在此情况下,认证成功,因为 admin 已经是活动数据库;在切换到 packt 后再尝试以 admin 身份进行认证会失败。然而,认证后身份会一直保持,直到下次调用 auth() 或退出客户端。所以,即使我们切换了数据库,我们仍然在 admin 数据库的 admin 用户角色和权限下操作。

尽管通过一个简单的 mongo 调用连接到了服务器,活动数据库仍然可以通过命令行指定。mongo 还提供了多个选项,例如连接到运行在其他系统上的 MongoDB 服务器并提供认证凭据。--host 用于指定 MongoDB 运行的远程主机名或 IP 地址,--username--password 选项允许你提供账户的认证信息:

mongo --host 192.168.56.100 --username tboronczyk --password ""  packt

如果在调用时同时使用了--username--password,并且指定了数据库,MongoDB 会假设该数据库是帐户的认证数据库。如果帐户属于其他数据库,可以使用--authenticationDatabase选项指定其认证数据库:

mongo --authenticationDatabase admin --username admin --password 
    ""  packt

--password选项需要一个值,但如果其值为空,MongoDB 会提示你输入密码。我建议你像我这里做的那样使用空字符串("")作为值,以强制出现密码提示。

注意

出于安全原因,绝不要将密码作为命令调用的一部分输入。密码可能会出现在运行时ps的输出中,也会出现在你的 shell 历史记录中。

另请参见

请参考以下资源获取更多关于 MongoDB 使用的信息:

备份和恢复 MongoDB 数据库

本教程教你如何使用mongodump工具备份 MongoDB 数据库,并使用mongorestore恢复数据库。

准备工作

本教程要求 MongoDB 服务器正在运行,并且需要访问一个拥有userAdmin角色的用户帐户。

如何操作...

按照以下步骤备份 MongoDB 数据库:

  1. 以拥有userAdmin角色的用户身份连接到 MongoDB:

    mongo --username admin --password "" admin
    
    
  2. 创建一个拥有backuprestore角色的帐户,用于创建和恢复备份:

    db.createUser({
     user: "backupusr",
     pwd: "B@CK&4th",
     roles: [
     { role: "backup", db: "admin" },
     { role: "restore", db: "admin" }
     ]
    })
    
    
  3. 在命令行中使用mongodump导出 MongoDB 数据库:

    mongodump --authenticationDatabase admin --username  backupusr 
           --password "" --db packt
    
    
  4. 要从使用mongodump创建的备份恢复数据库,请使用mongorestore程序:

    mongorestore --authenticationDatabase admin --username  backupusr
           --password "" --drop --db packt dump/packt
    
    

它是如何工作的...

用于备份的帐户必须具备分配给backup角色的权限,而用于恢复的帐户必须具备分配给restore角色的权限。因此,我们在使用工具之前,连接到 MongoDB 服务器并创建了一个同时拥有这两个角色的帐户:

db.createUser({
 user: "backupusr",
 pwd: "B@CK&4th",
 roles: [
 { role: "backup", db: "admin" },
 { role: "restore", db: "admin" }
 ]
})

新帐户随后将与mongodump一起用于备份我们的数据库:

mongodump --authenticationDatabase admin --username backupusr 
    --password "" --db packt

上述调用将导出--db参数指定的packt数据库中的所有内容。如果没有指定--dbmongodump将导出所有可用数据库,除了服务器的local数据库。也可以使用--collection参数仅导出数据库中的特定集合:

mongodump --db packt --collection authors

默认情况下,mongodump会创建一个名为dump的本地目录来组织导出的数据。dump目录下会有每个导出数据库的目录,里面包含每个集合的两个文件。第一个文件是 BSON 文件,一种类似 JSON 的二进制格式,由于它支持比 JSON 更多的数据类型,因此被广泛使用。例如,JSON 没有定义日期类型,而 JSON 仅支持单一的数值类型,而 BSON 支持 32 位和 64 位整数以及双精度浮点数。第二个文件是一个元数据 JSON 文件,存储关于集合的详细信息,如任何集合选项或索引定义。

注意

如果dump目录已经存在,mongodump将覆盖任何现有文件。为了避免问题,可以使用--out参数指定一个不同的位置:

**mongodump --db packt --out dump-$(date +%F)**

它是如何工作的...

导出的集合数据按数据库在dump目录中组织

然后,提供集合文件的路径给mongorestore,以导入由mongodump导出的数据。将使用--db参数指定要插入集合的数据库:

mongorestore --authenticationDatabase admin --username backupusr 
    --password "" --drop --db packt dump/packt

mongorestore只会插入数据;如果集合中已存在具有相同_id字段的文档,则这些记录会被跳过,而不是更新。根据具体情况,这可能是想要的,也可能不是。因此,为了确保恢复的数据与导出的数据一致,使用--drop参数,指示mongorestore在导入备份之前先删除现有的集合。

除了mongodumpmongorestore,还有mongoexportmongoimportmongoexport将集合数据导出为 JSON 或 CSV 文件,而mongoimport从这些格式中导入数据。需要注意的是,JSON 的类型系统(特别是 CSV 中的“类型”)不如 BSON 细化,因此可能会丧失一些精度。为了确保备份的可靠性,推荐使用mongodumpmongorestore

mongoexport的默认导出格式是 JSON。如果要将集合数据导出为 CSV 格式,可以使用--csv参数:

mongoexport --db packt --collection titles --csv --out titles.csv

通过使用--fields参数提供以逗号分隔的字段名称,可以针对特定字段进行导出:

mongoexport --db packt --collection titles --fields isbn,title,     
    authors,year,language,pages --csv --out titles.csv

在使用mongoimport导入数据时,有一些值得注意的参数:--type,用于指定导入文件的类型(可以是 JSON 或 CSV),--headerline - 在 CSV 文件中,如果第一行是列标题,跳过该行数据,--fields - 只导入文件中的特定字段,以及--upsert,它对现有文档执行插入或更新操作,而不是跳过这些文档:

mongoimport --db packt --collection titles --fields isbn,title,
    authors --type csv --upsert < titles.csv

另请参阅

请参考以下资源,以获取更多关于备份和恢复 MongoDB 数据库的信息:

  • mongodump的手册页(man 1 mongodump

  • mongorestore的手册页(man 1 mongorestore

  • mongoexport的手册页(man 1 mongoexport

  • mongoimport的手册页(man 1 mongoimport

  • MongoDB 手册:MongoDB 备份方法 (docs.mongodb.org/manual/core/backups)

  • BSON: 二进制 JSON (bsonspec.org/)

配置 MongoDB 副本集

本配方教你如何使用 MongoDB 副本集配置复制。

当使用副本集执行复制时,MongoDB 的一个安装会识别为主服务器,而集群中的其他安装则为次级服务器。主服务器接受写入操作,写入会复制到次级服务器,次级服务器则处理读取请求。如果主服务器出现故障,次级服务器会自动发起法定人数投票,并将一个次级服务器提升为主服务器的角色。旧的主服务器重新上线时会重新加入集群。此配置提供了冗余、分布式的读写访问以及高可用性下的自动故障切换。

准备工作

本配方演示了如何使用三个系统配置副本集。第一个系统将作为集群的主服务器,我们假设它的 IP 地址是192.168.56.100。另外两个系统将作为次级服务器,地址分别为192.168.56.102192.168.56.103。在所有三个系统上都应安装 MongoDB。你还需要管理员访问权限来完成配置,并且需要一个具有userAdmin角色的用户账户。

MongoDB 复制依赖于主机名。在开始此配方之前,请确保系统之间能够通过主机名互相访问。如果系统无法访问且你无法在网络的 DNS 中添加必要的记录,你可以通过在/etc/hosts中添加条目来覆盖本地解析,类似于以下内容:

192.168.56.100 benito benito.localdomain
192.168.56.101 javier javier.localdomain
192.168.56.102 geomar geomar.localdomain

如何操作...

按照以下步骤使用 MongoDB 副本集配置复制:

  1. 在主系统上,导航到/var/lib/mongodb,并使用openssl创建一个共享密钥。该密钥作为每个服务器用于认证自己为复制集成员的密码:

    cd /var/lib/mongodb
    openssl rand 756 -base64 -out rs0.key
    
    
  2. 确保文件的权限已正确设置;文件应该由mongodb拥有,并且仅对其所有者可读:

    chown mongodb.mongodb rs0.key
    chmod 600 rs0.key
    
    
  3. 使用文本编辑器打开/etc/mongod.conf

    vi /etc/mongod.conf
    
    
  4. 找到replSet选项,取消注释,并将其值设置为rs0

    # Arg is <setname>[/<optionalseedhostlist>]
    replSet = rs0
    
    
  5. 取消注释keyFile选项并提供包含共享密码的文件路径:

    # Private key for cluster authentication
    keyFile = /var/lib/mongodb/rs0.key
    
    
  6. 保存更改并关闭文件。

  7. 重启 MongoDB 服务器:

    systemctl restart mongod.service
    
    
  8. 将共享密钥复制到每个次级系统:

    scp rs0.key 192.168.56.101:/var/lib/mongodb/rs0.key
    scp rs0.key 192.168.56.102:/var/lib/mongodb/rs0.key
    
    
  9. 在其他次级系统上重复步骤 2-7。

  10. 连接到主 MongoDB 服务器,并创建一个具有clusterManager角色的账户,用于配置和管理副本集:

    db.createUser({
     user: "repladmin",
     pwd: "dupl1C@t3",
     roles: [{ role: "clusterManager", db: "admin" }]
    })
    
    
  11. 使用repladmin用户进行身份验证:

    db.auth("repladmin", "dupl1C@t3")
    
    
  12. 使用rs.initiate()方法初始化集群:

    rs.initiate()
    
    
  13. 使用rs.add()注册次级成员:

    rs.add("192.168.56.101")
    rs.add("192.168.56.102")
    
    

它是如何工作的...

集群必须包含奇数个服务器,因为必须有多数票来批准次要服务器提议担任主服务器角色,若主服务器不可用。使用了三个服务器,这是提供适当冗余性和可用性的集群的最小数量。

集群成员通过共享的副本集名称和密码相互识别,我们在每个服务器的mongod.conf配置文件中提供该信息。名称通过replSet选项指定:

replSet = rs0

密码值可以是最多 1,024 个字符。出于安全原因,建议使用长随机字符串来抵抗暴力破解和字典攻击。我们可以使用openssl rand生成此类值:

openssl rand 756 -base64 -out rs0.key

rand 生成我们请求的随机字节数,在此情况下为 756 字节。-base64 使用 Base64 编码方案对其进行编码,以安全地将字节表示为纯文本。编码会带来一些开销,Base64 将三个字节编码为四个字符,并且在字节数不足三个时会进行填充。因此,Base64 编码 765 个随机字节会产生 1,024 个字符的文本,适用于我们的需求。

生成的包含密码的密钥文件被复制到每个系统。其所有权被设置为系统的mongodb用户,并且文件的访问权限会被撤销,除非是该用户。

chown mongodb.mongodb rs0.key
chmod 600 rs0.key

配置文件通过keyFile选项在配置文件中指定:

keyFile = /var/lib/mongodb/rs0.key

集群的管理需要分配给clusterManager角色的权限,因此我们创建了一个拥有该角色的帐户,并使用新帐户进行了身份验证:

db.createUser({
 user: "repladmin",
 pwd: "dupl1C@t3",
 roles: [{ role: "clusterManager", db: "admin" }]
})
db.auth("repladmin", "dupl1C@t3")

我们通过在主服务器上运行rs.initiate()启动集群,然后使用rs.add()注册次要服务器:

rs.initiate()
rs.add("192.168.56.101")
rs.add("192.168.56.102")

在调用rs.initiate()之后,您会注意到 mongo 客户端的提示符已更改为rs0:primary,以通知我们已连接到rs0复制组中的主服务器。如果您登录到次要服务器,提示符将显示为rs0:secondary

或者,可以通过传递一个对象来配置集群,该对象指定次要服务器作为rs.initiate()的参数。该对象的_id属性是集群的名称,members属性是一个包含次要主机的数组:

rs.initiate({
 _id : "rs0",
 members : [
 {_id : 0, host : "192.168.56.100"},
 {_id : 1, host : "192.168.56.101"},
 {_id : 2, host : "192.168.56.102"}
 ]
})

参见

参考以下资源,了解更多有关使用 MongoDB 副本集的信息:

设置 OpenLDAP 目录

本教程将教你如何安装 OpenLDAP,这是 X.500 目录服务器的开源实现。X.500 协议系列在 1980 年代末期开发,用于支持以层次结构方式存储和查找名称、电子邮件地址、计算机系统及其他实体。每个条目都是目录信息树(DIT)中的一个节点,并由其区分名(DN)标识。条目的信息以键/值对的形式表示,这些键值对称为属性。

准备工作

本教程要求使用一个具有工作网络连接的 CentOS 系统,并拥有管理员权限,可以通过root账户或sudo来实现:

如何操作……

按照以下步骤设置 OpenLDAP 目录:

  1. 安装openldap-serveropenldap-clients包:

    yum install openldap-servers openldap-clients
    
    
  2. 将随 OpenLDAP 一起提供的数据库配置文件复制到服务器的数据目录中。确保该文件归ldap用户所有:

    cp /usr/share/openldap-servers/DB_CONFIG.example  
           /var/lib/ldap/DB_CONFIG
    chown ldap.ldap /var/lib/ldap/DB_CONFIG
    
    
  3. 使用slappasswd为 OpenLDAP 的Manager账户生成密码哈希。在提示时输入所需的密码:

    slappasswd
    
    
  4. 启动 LDAP 服务器,并可选择设置为系统重启时自动启动:

    systemctl start slapd.service
    systemctl enable slapd.service
    
    
  5. 在系统防火墙中打开端口389,以允许外部连接到服务器:

    firewall-cmd --zone=public --permanent --add-service=ldap
    firewall-cmd --reload
    
    
  6. 使用以下内容创建文件config.ldif。DIT 的后缀基于域名ldap.example.comolcRootPW的值是第 3 步中获得的密码哈希:

    dn: olcDatabase={2}hdb,cn=config
    changetype: modify
    replace: olcSuffix
    olcSuffix: dc=ldap,dc=example,dc=com
    -
    replace: olcRootDN
    olcRootDN: cn=Manager,dc=ldap,dc=example,dc=com
    -
    add: olcRootPW
    olcRootPW: {SSHA}cb0i4Kwzvd5tBlxEtwB50myPIUKI3bkp
    dn: olcDatabase={1}monitor,cn=config
    changetype: modify
    replace: olcAccess
    olcAccess: {0}to * by dn.base="gidNumber=0+uidNumber=0,
     cn=peercred,cn=external,cn=auth" read by dn.base="cn=
     Manager,dc=ldap,dc=example,dc=com" read by * none
    
    
  7. 调用ldapmodify执行config.ldif中的操作:

    ldapmodify -Y EXTERNAL -H ldapi:/// -f config.ldif
    
    
  8. 使用ldapadd导入位于/etc/openldap/schema中的cosineinetorgpersonnis模式:

    cd /etc/openldap/schema
    ldapadd -Y EXTERNAL -H ldapi:/// -f cosine.ldif
    ldapadd -Y EXTERNAL -H ldapi:/// -f inetorgperson.ldif
    ldapadd -Y EXTERNAL -H ldapi:/// -f nis.ldif
    
    
  9. 使用以下内容创建文件root.ldif

    dn: dc=ldap,dc=example,dc=com
    objectClass: dcObject
    objectClass: organization
    o: My Company's LDAP Database
    
    
  10. 使用ldapadd导入root.ldif,并通过Manager账户进行身份验证:

    ldapadd -D "cn=Manager,dc=ldap,dc=example,dc=com" -W -H  
           ldapi:/// -f root.ldif
    
    

它是如何工作的……

我们首先安装了openldap-server包,其中包含了 LDAP 服务器(slapd)及一些辅助工具,还安装了openldap-clients包,后者包含了用于与目录服务器交互的基本工具:

yum install openldap-servers openldap-clients

OpenLDAP 使用 Berkeley DB(BDB/HDB)数据库作为后端数据存储、索引和缓存。该数据库与目录服务器分开配置,示例配置文件随服务器一起安装。我们将示例文件复制到了服务器的数据目录中,但保留了其默认值;默认值适合初始使用,尽管在部署 OpenLDAP 后,你可能希望定期检查设置,以确保最佳性能(man 5 slapd-bdb提供了文件配置选项的描述):

cp /usr/share/openldap-servers/DB_CONFIG.example  
    /var/lib/ldap/DB_CONFIG

目录的管理员用户Manager最初没有分配密码。OpenLDAP 期望密码是哈希值,因此我们使用slappasswd创建了一个合适的哈希值:

slappasswd

slappasswd 使用的默认哈希算法是加盐的 SHA(SSHA),这一点可以通过输出中的 {SSHA} 前缀看出。如果需要,也可以通过 -h 参数指定使用不同的算法来哈希密码。可选值有 {CRYPT}{MD5}{SMD5}(加盐的 MD5)、{SHA}{SSHA}。加盐算法优于非加盐算法,因为 slappasswd 随机生成的盐值使得哈希对彩虹攻击具有更高的抗性。

OpenLDAP 已弃用基于文件的配置方式,转而采用在线配置,将参数存储在配置 DIT 中,以便在不需要重新启动目录服务器的情况下进行更新。启动服务器后,我们将必要的操作写入 config.ldif,这些操作会进行更新,然后使用 ldapmodify 批量执行:

ldapmodify -Y EXTERNAL -H ldapi:// -f config.ldif

-H 参数提供了一个或多个我们想要连接的服务器 URI。我们可以指定传输协议、主机名或 IP 地址以及端口,但 URI 并不是一个完整的 RFC-4516 风格的 LDAP URI(其他组件,如基础 DN,通过其他参数指定)。支持的协议有 ldapldaps(LDAP over SSL)和 ldapi(LDAP over IPC/unix-socket)。访问本地主机时不需要主机名,因此仅使用 ldapi://

-Y 参数指定 EXTERNAL 作为认证机制,允许使用服务器的 SASL 方法之外的外部机制。当与 ldapi 配合使用时,EXTERNAL 使用我们的登录会话用户名进行认证。

ldapmodify 的默认行为是从 STDIN 读取输入,但可以通过 -f 参数指定输入文件。由于语句较为冗长,使用输入文件是一个很好的选择,这样你可以事先检查是否有错误。如果你确实希望通过 STDIN 提供输入,我建议使用 -c 参数以“连续模式”运行 ldapmodify。默认情况下,程序在遇到错误时会终止,但在连续模式下,它会继续运行。这样可以在出现问题时重新提交操作,而无需重新连接:

ldapmodify -Y EXTERNAL -H ldapi:/// -c

我们的第一个操作将 DIT 的后缀从默认的 dc=my-domain,dc=com 更改为更合适的值。这个示例使用 ldap.example.com,但当然你可以根据需要替换为自己的域名:

dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcSuffix
olcSuffix: dc=ldap,dc=example,dc=com

后缀存储在 olcSuffix 属性中,该属性位于 olcDatabase={2}hdb,cn=config 条目下,表示 DIT 的顶级结构。传统上,后缀基于域名并作为一系列域组件(DC)表达,因此域名 ldap.example.com 变为 dc=ldap,dc=example,dc=com

后缀在其他几个地方也出现了,因此我们也需要更新它们——olcRootDN属性,它列出了 DIT 的管理员用户的名称,以及在olcAccess中的权限语句,授予Manager和系统的root帐户访问权限。此外,我们添加了存储管理员密码哈希的olcRootPW属性。我们不需要为同一条目的属性多次指定 DN,而是可以用单个连字符分隔操作:

replace: olcRootDN
olcRootDN: cn=Manager,dc=ldap,dc=example,dc=com
-
add: olcRootPW
olcRootPW: {SSHA}3NhShraRoA+MaOGSrjWTzK3fX0AIq+7P
dn: olcDatabase={1}monitor,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to * by dn.base="gidNumber=0+uidNumber=0,
 cn=peercred,cn=external,cn=auth" read by dn.base="cn=
 Manager,dc=ldap,dc=example,dc=com" read by * none

接下来,我们导入了cosinenisinetorgperson模式。从零开始创建新的模式可能是一个艰巨的任务,因为需要进行大量规划,以确定需要哪些类型以及应该分配哪些 PEN/OIDs。导入 OpenLDAP 提供的这些模式使我们能够访问各种有用的预定义类型:

ldapadd -Y EXTERNAL -H ldapi:/// -f cosine.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f inetorgperson.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f nis.ldif

cosine定义了一个标准的 X.500 目录服务模式,最初为 COSINE PARADISE 项目开发,并在 RFC-4524 中进行了描述。它为我们提供了如documentdomain对象以及hostmaildocumentAuthor等属性。inetorgperson定义了inetOrgPerson类,这是一个尝试“满足今天的互联网和内部网目录服务部署中要求”的人员对象,如 RFC-2798 和 RFC-4524 中所述。nis定义了一个网络信息服务模式,包含用于设置集中式认证的用户和主机属性,如uidNumbergidNumberipNetworkNumberipNetmaskNumber

如果查看这些文件的内容,你会发现对象标识符(OIDs)在模式定义中扮演着重要角色,它们为各种对象类和属性提供全球唯一的标识。OIDs 是由点分隔的一串数字,从左到右读取,每个位置代表分布式层级中的一个级别。层级的顶层由各种标准组织和注册管理机构维护,互联网号码分配局(IANA)允许个人在 OID 1.3.6.1.4.1下注册自己的分支。例如,1.3.6.1.4.1.4203被分配给 OpenLDAP 项目。

最后,我们需要首先定义域组件对象(dcObject)。该对象是我们本地目录分支的根,未来的条目可以在其下添加。如果你的经验主要集中在使用关系型数据库如 MySQL 或现代 NoSQL 数据库如 MongoDB 上,你可以将dcObject视为数据库:

dn: dc=ldap,dc=example,dc=com
objectClass: dcObject
objectClass: organization
o: My Company's LDAP Database

在使用ldapadd导入定义时,我们提供了-D参数来指定Manager帐户,并使用-W提示输入该帐户的密码:

ldapadd -D "cn=Manager,dc=ldap,dc=example,dc=com" -W -H ldapi:///  
    -f root.ldif

另见

请参考以下资源,获取更多关于使用 OpenLDAP 的信息:

备份和恢复 OpenLDAP 数据库

本教程教你如何通过将目录导出为 LDIF 文件来备份 OpenLDAP 数据库,之后可以导入该文件以恢复数据库。

准备工作

这个教程需要一个具有工作网络连接和管理员权限的 CentOS 系统,权限可以通过root账户或sudo来获得。

如何操作...

要备份 LDAP 目录,使用slapcat工具导出目录:

slapcat -b "dc=ldap,dc=example,dc=com" -l backup.ldif

要从导出中重建目录,请按照以下步骤操作:

  1. 停止 LDAP 服务器:

    service stop slapd.service
    
    
  2. 使用slapadd导入文件:

    slapadd -f backup.ldif
    
    
  3. 确保数据文件的所有者是ldap用户:

    chown -R ldap.ldap /var/lib/ldap/*
    
    
  4. 重启 LDAP 服务器:

    service restart slapd.service
    
    

它是如何工作的...

slapcat将 LDAP 数据库的内容导出为 LDIF 格式的输出。默认情况下,内容会发送到 STDOUT,因此你应该使用 Shell 的重定向操作符(>>>)或使用命令的-l(小写 L)参数,该参数指定输出文件的名称:

slapcat -b "dc=ldap,dc=example,dc=com" -l backup.ldif

目标目录的后缀通过-b参数指定。如果有任何下级目录,它们也会默认被导出。若要从导出中排除下级目录,只导出顶级目录内容,可以使用-g参数:

slapcat -b "dc=ldap,dc=example,dc=com" -g -l backup.ldif

slapcat返回的是在扫描数据库时遇到的条目的顺序。这意味着一个对象的定义可能会出现在其属性引用的实体之后。这对于slapadd不是问题,因为它导入数据的方式不同于ldapadd,所以应该使用前者来恢复目录。否则,你必须编辑文件以确保顺序不会导致问题;我相信你会同意,在格式冗长的情况下,这种操作并不具吸引力:

slapadd -f backup.ldif

在执行导出和导入时,LDAP 服务器应当处于停止状态。这确保在过程中无法进行任何写操作,从而保证数据的完整性和一致性。

slapadd 直接将文件写入服务器的数据目录,因此这些文件将归 root 所有(slapadd 使用的用户帐户),所以在导入后但在启动服务器之前,需要将它们的所有权更改为 ldap,以便进程能够访问这些文件:

chown -R ldap.ldap /var/lib/ldap/*

另请参阅

请参考以下资源以获取更多有关 OpenLDAP 备份操作的信息:

第八章:管理域名和 DNS

本章包含以下配方:

  • 设置 BIND 为解析 DNS 服务器

  • 将 BIND 配置为权威 DNS 服务器

  • 编写反向查找区域文件

  • 设置从属 DNS 服务器

  • 配置 rndc 来控制 BIND

介绍

在本章中,你将找到一些操作 BIND 的配方,以更好地管理你的域名基础设施。你将学习如何将 BIND 配置为一个解析 DNS 服务器,能够缓存查找结果,这可以帮助减少延迟,还将学习如何将 BIND 配置为权威 DNS 服务器,以便为你的域名或私有内网资源提供权威响应。此外,还讨论了如何处理反向查找请求,并通过配置冗余的、辅助权威 DNS 服务器来确保你的资源始终可访问,这些服务器执行主从式区域记录传输。最后,你将学习如何设置和使用 rndc,这是一个非常实用的 BIND 服务器管理客户端。

设置 BIND 为解析 DNS 服务器

本配方教你如何使用 BIND 设置一个解析 DNS 服务器。域名服务(DNS)是互联网中默默奉献的工作马,它将如 facebook.comgoogle.com 这样的易记名称转换为如 172.217.18.23831.13.76.68 这样的 IP 地址。

互联网通信使用 IP 地址来标识系统,但数字很难记住。例如,我们更容易记住 google.com 而不是 172.217.18.238(或 IPv6 地址 2607:f8b0:4006:80e::200e)。因此,当你在浏览器地址栏中输入 google.com 时,你的系统会查询一个 DNS 服务器,将该名称解析为 IP 地址,并随后请求该地址上的网页。当你写电子邮件时,DNS 服务器会在消息发送之前检索收件人邮件服务器的 IP 地址。

由你的服务提供商维护的解析 DNS 服务器可能是接收此类查找请求的第一个服务器,如果它已经知道地址,它会立即响应。如果没有,它将联系请求的域名父区域中的 DNS 服务器,并获得一个指向该域名权威 DNS 服务器的引用,或者指向 DNS 层级结构中下一个区域的服务器。如果请求到达层级的顶部而没有被引导到权威服务器,那么该域名不存在。否则,权威服务器将地址发送回你的解析服务器。解析器然后缓存响应,以便未来的查找能够更快完成。

根据您的网络以及解析地址时涉及的服务器数量,DNS 查找可能会成为一个重要的延迟来源。地址记录应该在前一两个跳跃中找到,并且解析服务器应尽可能靠近用户,以获得最佳性能。因此,设置本地 DNS 服务器以缓存查找结果可以显著提高用户体验网络速度。

准备工作

该教程需要一个具有有效网络连接的 CentOS 系统。假设该系统的 IP 地址配置为 192.168.56.10。还需要管理员权限,可以通过登录 root 账户或使用 sudo 来获取权限。

如何操作...

按照以下步骤安装 BIND 作为解析 DNS 服务器:

  1. 安装 bindbind-utils 包:

    yum install bind bind-utils
    
    
  2. 用文本编辑器打开 BIND 的配置文件 /etc/named.conf

    vi /etc/named.conf
    
    
  3. options 的大括号内找到 listen-on 选项。更新其列表以反映 BIND 将使用的系统 IP 地址:

    listen-on port 53 { 127.0.0.1; 192.168.56.10; };
    
    
  4. 如果您希望服务 IPv6 请求,请类似地更改 listen-on-v6 的值。否则,将其值更新为 none

    listen-on-v6 port 53 { none; }
    
    
  5. 使用 BIND 允许接收请求的 IP 地址列表更新 allow-query 选项:

    allow-query { localhost; 192.168.56.0/24; };
    
    
  6. 保存您对配置文件的更改并关闭该文件。

  7. 使用 systemctl 启动 BIND,并可选择启用它在系统重启时自动启动:

    systemctl start named.service
    systemctl enable named.service
    
    
  8. 启用 FirewallD 的 dns 服务,打开端口 53 以允许 TCP 和 UDP 流量:

    firewall-cmd --zone=public --permanent --add-service=dns
    firewall-cmd --reload
    
    
  9. 使用 dig 请求查找以测试配置:

    dig @192.168.56.10 google.com A
    
    

工作原理...

默认情况下,BIND 被配置为解析 DNS 服务器,但我们仍然需要更新一些选项,以定义它如何接受查找请求。第一个更改是对 options 部分中的 listen-on* 选项进行调整,这些选项指定了 BIND 监听请求的端口和网络接口。listen-on 适用于 IPv4 网络,listen-on-v6 适用于 IPv6。在这两种情况下,DNS 流量的标准端口为端口 53

listen-on port 53 { 127.0.0.1; 192.168.56.10; };
listen-on-v6 port 53 { none; }

接下来,我们更新了 allow-query 选项,提供了一个 BIND 可接受请求的系统白名单。地址可以单独提供,也可以以 CIDR 表示法书写:

allow-query { localhost; 92.168.56.0/24; }

使用预定义的值,如 anylocalhostlocalnetsnone 也是可以接受的。直观地讲,any 代表所有地址,允许 BIND 监听系统配置的所有地址或接受来自任何源的请求,而 none 则禁止所有请求。localhost 代表系统的所有地址,localnets 代表系统所在所有网络的地址。

注意

请小心 localhostlocalnets 中的 local,不要让它们给你带来虚假的安全感。如果你的系统连接到多个网络,例如一个公共网络(如互联网)和一个私有内部网络,那么它们都被认为是本地网络。没有必要的安全措施,允许来自不受信任网络的访问是一个严重的风险,因为开放的 DNS 服务器可能会被恶意用户利用,进行多种拒绝服务攻击。

更新 BIND 配置并使其启动后,我们可以通过发送 dig 查询并检查响应来测试一切是否正常:

dig @192.168.56.10 google.com A

可以通过在 dig 中提供目标服务器的地址并以 @ 前缀的方式,将请求发送到特定的 DNS 服务器。如果没有在调用中提供 DNS 服务器,dig 会将请求发送到系统的 /etc/resolve.conf 文件中列出的服务器。

在 DNS 服务器的地址后,我们提供了我们感兴趣的资源名称,并跟上了所需的记录类型。在前面的示例中,查询的是 google.com 的地址(A)记录。也可以查询其他类型的记录,例如名称服务器(NS)和邮件交换(MX)记录。

工作原理...

dig 查询 DNS 服务器并显示其响应。

dig 的响应分为几个部分。ANSWER SECTION 显示了我们请求的 A 记录。AUTHORITY SECTION 列出了请求的域名配置的权威 DNS 服务器,而 ADDITIONAL SECTION 显示了权威服务器的 IP 地址。响应中还包含各种元数据,例如请求中设置了哪些标志,查询了哪个 DNS 服务器,以及查找完成所需的时间。

当你对测试结果感到满意时,可以配置网络中的系统以使用新的 DNS 服务器。通常,方法是在每个系统的 /etc/resolv.conf 文件中添加 nameserver 条目,提供 DNS 服务器的地址:

nameserver 192.168.56.10

resolv.conf 可能会根据系统接口的配置动态生成。如果是这种情况,您在文件中所做的任何更改都会被覆盖。您需要检查接口的配置文件(例如,/etc/sysconf/network-scripts/ifcfg-enp0s3),如果 PEERDNS 设置为 yes,则 resolv.conf 由网络管理器维护。请在接口配置中添加 DNS 条目,下次启动接口时,DNS 服务器的地址将被写入 resolve.conf

DNS=192.168.56.10

更新配置后,需要重新启动接口以使更改生效,并验证 resolve.conf 的内容:

ifdown enp0s3 && ifup enp0s3
cat /etc/resolv.conf

解析 DNS 服务器有时被称为递归服务器,因为它们会将查找请求发送到区域层级中的每一层,直到找到答案。转发 DNS 服务器的功能类似于解析/递归服务器,因为这两种类型都会接受查找请求并缓存结果以提高效率;然而,转发服务器将请求发送到另一个 DNS 服务器并等待响应,委托解析过程,而不是自己跟踪答案。这可以减轻解析 DNS 服务器在处理请求时产生的许多网络流量。

要将 BIND 配置为转发 DNS 服务器,请再次打开 /etc/named.conf 并将 forwardersforward 选项添加到 options 块中:

forwarders { 8.8.8.8; 8.8.4.4; };
forward only;

forwarders 选项提供了负责解析查找请求的 DNS 服务器列表。示例中列出了 Google 的公共 DNS 服务器,但您的服务提供商也应该提供可以使用的公共 DNS 服务器。

forward only 强制 BIND 将请求转发到 forwarders 中列出的负责服务器。仅当负责服务器未返回地址或转发信息时,BIND 才会联系该域的根服务器获取权威 DNS 服务器并自行处理请求。转发服务器的递归功能并未完全关闭,但大大减少了。

另请参见

以下资源将为您提供更多有关 DNS 工作原理以及如何配置 BIND 的信息:

将 BIND 配置为权威 DNS 服务器

层级结构的一个好处是可以委派下级节点的责任。尽管互联网名称与数字分配公司(ICANN)对 DNS 目录拥有管理权限,但它将责任委托给了各个认证注册商,负责管理顶级域名,如 comnetorg,并将责任委托给适当的政府机构,负责国家顶级域名,如 cadees。当您注册一个域名时,注册商会将责任委托给您,您也可以根据需要进一步委托责任给您的子域名。每个通过委托责任而形成的边界就构成了一个 DNS 区域。

本配方将教您如何将 BIND 配置为您域的权威 DNS 服务器。如果您还记得上一个配方中关于 DNS 请求传播的讨论,您会记得权威服务器对解析有最终决定权。这是因为它的信息来自 DNS 系统外部,由管理员手动配置该区域的信息。您还将学习如何编写包含信息(如将主机名映射到 IP 地址)的区域文件,我向您保证,这并不像初看时那么可怕。

准备工作

这个配方需要一个已经配置了 BIND 作为解析 DNS 服务器的 CentOS 系统,如前面的配方所述(BIND 的配置将更新为操作作为一个权威服务器)。还需要管理员权限,可以通过使用 root 账户登录或通过 sudo 提升权限。

根据 RFC-2606(保留的顶级 DNS 名称)的建议,我将使用 example.com 域名作为示例。如果您有自己的域名,可以随意替换。为了说明方便,本配方将展示一个由多台服务器组成的网络,这些服务器处理域名中常见的各种服务,如电子邮件服务器和 Web 服务器。系统如下:

  • ns1: 托管域名的主要权威 DNS 服务器,IP 地址为 192.168.56.10(这是我们将要操作的系统)

  • ns2: 托管辅助权威 DNS 服务器,地址为 192.168.56.20

  • mail: 托管主电子邮件服务器,地址为 192.168.56.12

  • mail2: 托管辅助电子邮件服务器,地址为 192.168.56.22

  • www: 托管 Web 和 FTP 服务器,地址为 192.168.56.100

如何操作...

按照以下步骤将 BIND 配置为权威 DNS 服务器:

  1. 使用文本编辑器打开 /etc/named.conf 文件:

    vi /etc/named.conf
    
    
  2. 确认 listen-on*allow-query 选项已按前一个配方所述进行配置:

    listen-on port 52 { 127.0.0.1; 192.168.56.10; };
    listen-on-v6 port 52 { none; };
    allow-query { 192.168.56.0/24; };
    
    
  3. recursion 选项的值更改为 no,完全禁用 BIND 的递归查找行为:

    recursion no;
    
    
  4. 在文件末尾,添加以下区域配置:

    zone "example.com." in {
     type master;
     file "/var/named/zones/example.com.fwd";
     allow-transfer { none; };
    };
    
    
  5. 保存更改并关闭文件。

  6. 创建 /var/named/zones 目录:

    mkdir /var/named/zones
    
    
  7. 创建区域文件/var/named/zones/example.com.fwd,并添加以下内容(我们在如何工作...部分的讨论将帮助你理解每条记录的含义):

    $TTL 1d
    $ORIGIN example.com.
    ; start of authority resource record
    @       IN SOA   ns1 hostmaster.example.com. (
     2016041501 ; serial
     12h        ; refresh
     5m         ; retry
     2w         ; expire
     3h)        ; negative TTL
    ; nameserver records
     IN NS    ns1
     IN NS    ns2
    ns1     IN A     192.168.56.10 
    ns2     IN A     192.168.56.20
    ; mail records
    @       IN MX    10 mail
     IN MX    20 mail2
    mail    IN A     192.168.56.12
    mail2   IN A     192.168.56.22
    ; webserver records
    @       IN A     192.168.56.100
    www     IN CNAME @
    ftp     IN CNAME @
    
    
  8. 确保目录和区域文件具有正确的所有权和访问权限:

    chown root.named /var/named/zones
    chmod 750 /var/named/zones
    chmod 640 /var/named/zones/*
    
    
  9. 重启 BIND 以使配置更改生效:

    systemctl restart named.service
    
    
  10. 使用 dig 请求查找以测试配置:

    dig @192.168.56.10 example.com SOA
    
    

如何工作...

一个权威 DNS 服务器应该提供的唯一记录是那些具有权威信息的区域记录,因此我们首先在 BIND 的配置文件中禁用了recursion。禁用后,BIND 不会转发请求,也不会尝试解析非权威记录的查找请求:

recursion off;

然后,我们在配置文件的末尾添加了一个简短的部分,指定了 BIND 服务器如何为example.com.区域提供服务:

zone "example.com." in {
 type master;
 file "/var/named/zones/example.com.fwd";
 allow-transfer { none; };
};

本节以关键字zone开始,用以表示区域配置,后面跟着作为完全限定域名(FQDN)给出的区域名称。FQDN 总是以点号结尾,因为它们包含所有委托的路径,包括根目录。由于 DNS 系统的根没有名称,它的分隔符表现为结尾的点。因此,example.com.是完全限定的,而example.com则不是。(有些人错误地使用 FQDN 一词,实际上他们是在谈论部分限定域名。这是我一个不合逻辑的小毛病,所以提醒你注意。)

注意

思考如何在文件系统中导航有助于你理解完全限定名和部分限定名之间的区别。当给定绝对(完全限定)路径/var/named时,导航从文件系统的根目录开始,依次进入var目录,然后进入named目录。根目录没有除分隔符以外的名称。然而,相对(部分限定)路径var/named并不以分隔符开头。它的导航从当前目录开始,无论当前目录在哪。域名也类似,但它们按相反的顺序遍历层级,朝着根目录移动,使用点号作为分隔符,而不是斜杠。

type master选项将此服务器指定为区域的主权威 DNS 服务器。一种常见的部署策略是设置多个权威服务器,在主/从配置中工作。管理员在主服务器上更新区域信息,然后将该信息传输到一个或多个从服务器,后者作为次级权威 DNS 服务器提供服务。你将在设置从属 DNS 服务器一章中学习如何设置,但现在我们只关注主服务器。

allow-transfers选项列出了在接收到区域信息传输请求时,此服务器允许响应的从属系统,但由于我们尚未配置第二个权威 DNS 服务器,我们使用none来禁用传输。这有助于保护我们免受特定类型的拒绝服务攻击。资源记录足够小,可以在正常查找活动中通过 UDP 包进行传输,而区域传输则是通过 TCP 批量传输所有记录。恶意用户快速连续发送传输请求可能会使你的网络饱和。

区域的信息存储在一个名为区域文件的文本文件中,其位置通过file选项指定。本章中遵循的约定是将文件放在/var/named下的zone目录中,并使用fwdrev作为文件扩展名,表示文件是正向查找区文件还是反向查找区文件。因此,我们的文件保存为/var/named/zones/example.com.fwd

本示例中的文件是一个正向区域文件,因为它将名称映射到它们的 IP 地址。反向查找区域则映射相反的关系,即地址到名称。它们在编写反向查找区域文件的示例中讨论。

注意

我见过许多不同的命名约定用于命名区域文件。一些管理员使用zonzone作为文件扩展名。一些则会将区域文件分开存储在名为fwd-zonerev-zone的目录中。说实话,只要你保持一致性并且文件组织得当,systemctl restart named.servicent,做什么都无所谓。

$TTL是区域文件中的第一个指令,它指定了解析 DNS 服务器可以缓存从权威服务器接收到的记录的默认时间长度。特定的记录可能会提供它们自己的 TTL 值,这会覆盖默认值:

$TTL 14400

$ORIGIN指令提供了标识区域的 FQDN。文件中出现的任何@都会被$ORIGIN的值替代:

$ORIGIN example.com.

剩余的条目统称为资源记录,由一系列字段组成,字段的顺序是name ttl class type valuesname字段给出了拥有记录的资源名称。如果为空,则其值默认为前一个记录中使用的名称。ttl也是可选的,默认为$TTL的值。为了我们的目的,class将始终是IN,因为我们编写的是互联网资源记录。其他的类包括CH(Chaos)和HS(Hesiod),但它们并不广泛使用。

文件中的第一个记录必须是权威起始(SOA)记录,它标识该服务器是该区域的授权 DNS 服务器。SOA记录的值包括该区域主授权服务器的名称(我们提供的是ns1)、负责该区域的人的电子邮件地址(hostmaster.example.com.)、序列号(2016041501)、刷新间隔(12h)、重试间隔(5m)、过期间隔(2w)以及负面响应(当请求的记录不存在时发送)从服务器缓存的最长时间(3h)。记录通常写作单行条目,但括号允许我们将记录分割成多行:

; start of authority resource record
@       IN SOA   ns1 hostmaster.example.com. (
 2016041501 ; serial
 12h        ; refresh
 5m         ; retry
 2w         ; expire
 3h)        ; negative TTL

电子邮件地址中通常会出现的@符号被更改为点号,在hostmaster.example.com.中,因为@在区域文件中有特殊含义。同时注意,哪些名称是完全限定的(FQDN)。没有完全限定的名称会自动追加 FQDN,因此ns1被理解为ns1.example.com.。如果电子邮件地址的域名部分没有完全限定,那么hostmaster.example.com将被视为hostmaster.example.com.example.com.,显然这不是我们想要的结果。

SOA记录中超出部分的值主要供从属 DNS 服务器使用。刷新值告诉从属 DNS 服务器应该多久尝试刷新其区域文件的副本。重试间隔告诉从属服务器在主服务器无法连接时,应该等待多长时间再进行重试,过期值则指定从属服务器在与主服务器完全失去联系的情况下,可以使用其副本作为授权服务器满足查询请求的时间。负面 TTL 是一个解析器应该缓存来自 DNS 服务器的负面响应的时间长度,例如NXDOMAINNODATA响应。

序列号是一个任意的 10 位数字值,主机可以使用它来区分当前版本的区域文件与之前版本的不同。每次更新文件时,必须更新序列号。一个常见的约定是使用当前日期后跟一个序列号。例如,2016 年 4 月 15 日写作20160415,然后再添加两个数字以标识同一天的多个更新(201604150120160415022016041503,依此类推)。

接下来,我们给出了用于识别区域授权 DNS 服务器的NS记录。SOANS记录在每个区域文件中都是必需的:

; nameserver records
 IN NS    ns1
 IN NS    ns2
ns1     IN A     192.168.56.10 
ns2     IN A     192.168.56.20

NS记录识别授权服务器的名称。在前面的示例中,我们将n1n2定义为区域的授权 DNS 服务器,它们被理解为ns1.example.com.ns2.example.com.,因为它们没有完全限定。A记录将一个名称映射到其地址(AAAA用于 IPv6 地址)。我们在示例中编写的记录表示ns1.example.com.可以通过192.168.56.10访问,ns2.example.com.可以通过192.168.56.20访问。

注意

NS 记录属于区域,但我将NS 记录的第一个字段留空,因为该字段默认为上一条记录中使用的名称。在本例中,名称恰好是来自 SOA 记录(即 $ORIGIN)的 @。以下任何替代方案都具有相同含义并且同样可接受:

@ IN NS n1
$ORIGIN IN NS n1
example.com. IN NS n1

但是要小心,因为 MX 记录也属于区域。随着我们开始下一组记录,最后一个名称是来自该服务器 A 记录的 ns2。这意味着第一个 MX 记录必须提供 @$ORIGINexample.com. 之一。

MX 记录定义了负责处理区域邮件的服务器名称。邮件传输器分配了相对优先级,客户端将首先尝试与优先级最低的邮件服务器通信。如果服务器无法访问,客户端将尝试连接下一个最低的服务器,直到列表耗尽:

; mail records
@       IN MX    10 mail
 IN MX    20 mail2
mail    IN A     192.168.56.12
mail2   IN A     192.168.56.22

我们的配置定义了主要邮件服务器 mail.example.com.,IP 地址为 192.168.56.12,相对优先级为 10。第二个服务器,可能是在故障时的备份,是 mail2.example.com.,位于 192.168.56.22,优先级为 20。

最后,我们定义了识别区域 Web 服务器和系统其他别名的记录:

; webserver records
@       IN A     192.168.56.100
www     IN CNAME @
ftp     IN CNAME @

在 URL 开头出现 www 的普遍性自点网时代以来已经减少。不过,许多区域将地址解析为带有和不带 www 的相同 IP。我们的配置也是如此,为 example.comwww.example.com 的查找返回 192.168.56.100。这通过创建将域映射到 Web 服务器地址的 A 记录,然后将别名 www 到域的 A 记录的规范名称(CNAME)记录来实现。我们的配置还将 ftp 别名为 A 记录,以便用户可以使用 ftp.example.com 地址将其站点文件上传到 Web 服务器。

另请参阅

查看以下资源以获取有关运行 DNS 服务器和管理您的域的更多信息:

编写反向查找区域文件

到目前为止,我们将 DNS 请求视为正向查找,将资源名称如www.example.com转换为 IP 地址。然而,服务也可以通过提供 IP 地址来请求 DNS 服务器进行反向查找,想要知道与之关联的名称。像这样的反向查找特别适用于日志记录、身份验证和安全目的。例如,系统可以查询 DNS 服务器以验证客户端是否真的从它声称的系统进行连接。为了处理这种请求,本食谱将向你展示如何编写一个反向查找区域文件。

准备工作

本食谱需要一台安装并配置好 BIND 的 CentOS 系统,如前述食谱所描述。还需要管理员权限,可以通过使用root帐户登录或使用sudo来获取。

如何实现...

按照以下步骤添加反向查找区域:

  1. 打开 BIND 配置文件:

    vi /etc/named.conf
    
    
  2. 添加以下区域条目:

    zone "56.168.192.in-addr.arpa." in {
     type master;
     file "/var/named/zones/example.com.rev";
     allow-transfer { none; };
    };
    
    
  3. 保存更改并关闭配置文件。

  4. 创建/etc/named/zones/example.com.rev文件,并添加以下内容:

    $TTL 1d
    $ORIGIN 56.168.192.in-addr.arpa.
    ; start of authority
    @   IN SOA  ns1.example.com. hostmaster.example.com. (
     2016041501 ; serial
     12h        ; refresh
     5m         ; retry
     2w         ; expire
     3h)        ; error TTL
    ; nameservers
     IN NS   ns1.example.com.
     IN NS   ns2.example.com.
    10  IN PTR  ns1.example.com.
    20  IN PTR  ns2.example.com.
    ; mail servers
    12  IN PTR  mail.example.com.
    22  IN PTR  mail2.example.com.
    ; web servers
    100 IN PTR  example.com.
    100 IN PTR  www.example.com.
    100 IN PTR  ftp.example.com.
    
    
  5. 确保区域文件具有正确的所有权和访问权限:

    chown root.named /var/named/zones/example.com.rev
    chmod 640 /var/named/zones/example.com.rev
    
    
  6. 重启 BIND 使配置更改生效:

    systemctl restart named.service
    
    
  7. 使用dig进行反向 DNS 查找,以测试该区域:

    dig @192.168.56.10 -x 192.168.56.100
    
    

工作原理...

反向查找区域就像任何其他由区域文件定义的区域一样。所以,希望本食谱中的内容不会让你感到太意外。不过,仍有一些值得回顾的要点。

首先,区域的名称是通过将网络地址与特殊域in-addr.arpa结合来构建的,该域用于定义反向映射的 IP 地址(ip6.arpa用于 IPv6)。地址的字节顺序会被反转,以保持与从最具体到最广泛的域名一致性。因此,56.168.192.in-addr.arpa.192.168.56/24地址空间反向查找的完全限定域名(FQDN):

zone "56.168.192.in-addr.arpa." in {
 type master;
 file "/etc/named/zones/example.com.rev";
 allow-transfer { none; };
};

注意

本食谱将区域文件命名为example.com.rev,以便它在目录列表中与正向区域文件example.com.fwd一起排序。其他命名惯例可能将文件命名为56.168.192.in-addr.arpa.zone。再次强调,无论你选择什么惯例,关键是保持一致性。

在编写反向区域文件时,请记住我们讨论过的扩展和替换规则,最重要的是部分限定名称在$ORIGIN的上下文中进行解释。我们可以在正向查找区域的SOA记录中只写主权威 DNS 服务器的主机名,但在反向文件中需要确保名称是完全限定的,以防止它们被当作ns1.56.168.192.in-addr.arpa.来处理:

; start of authority
@   IN SOA  ns1.example.com. hostmaster.example.com. (
 2016041501 ; serial
 12h        ; refresh
 5m         ; retry
 2w         ; expire
 3h)        ; error TTL

指针记录(PTR)将 IP 地址与资源名称关联。除了 SOANS 记录(因为它们是任何区域文件中的必需记录)之外,反向文件中可以出现的唯一其他记录类型是 PTR。这一点意味着,需要多个记录来正确反向任何在正向文件中使用 CNAME 记录创建的别名。由于我们使用 wwwftp 作为 example.com. 的别名,并解析为 192.168.56.100,因此在反向区域文件中会出现三个与该地址相关的记录,如下所示:

100 IN PTR  example.com.
100 IN PTR  www.example.com.
100 IN PTR  ftp.example.com.

我们可以使用 dig-x 参数来测试区域配置:

dig @192.168.56.10 -x 192.168.56.100

-xdig 知道我们正在执行反向查找。我们提供 IP 地址的正常写法,dig 会反转其字节并在发送请求时附加 in-addr.arpa 域名。

另见

参考以下资源以获取更多关于反向区域和查找的信息:

配置辅助 DNS 服务器

冗余性对于确保关键服务在出现问题时仍然可用至关重要。由于 DNS 是网络中最关键的组件之一,无论是私有内网还是公共互联网,只有一个权威 DNS 服务器是不明智的。事实上,IANA 的权威名称服务器技术要求文档中规定,区域内必须至少有两个不同的权威名称服务器。本配方将向你展示如何配置第二个 BIND 实例作为辅助权威服务器,从主服务器接收区域信息,形成主/从配置。然后,查询请求可以由任何一台服务器满足,并被认为是权威响应。

准备工作

本配方需要两台已安装并按之前配方配置好的 CentOS 系统,并使用配置 BIND 为权威 DNS 服务器配方中描述的网络。假设作为主服务器的系统配置为 192.168.56.10,从服务器配置为 192.168.56.20。还需要管理员权限,可以通过登录 root 账户或使用 sudo 来获得。

如何操作...

按照以下步骤配置 BIND 为接收来自主 DNS 服务器区域信息的辅助权威 DNS 服务器:

  1. 在运行从实例 BIND 的系统上,打开 named.conf 文件,并按以下方式配置 example.com. 区域:

    zone "example.com." in {
     type slave;
     file "/var/named/slaves/example.com.fwd";
     masters { 192.168.56.10; };
     allow-transfer { none; };
     notify no;
    };
    
    
  2. 按如下方式配置其反向区域:

    zone "56.168.192.in-addr.arpa." in {
     type slave;
     file "/var/named/slaves/example.com.rev";
     masters { 192.168.56.10; };
     allow-transfer { none; };
     notify no;
    };
    
    
  3. 保存更改并关闭文件。

  4. 重启从服务器以使配置更改生效:

    systemctl restart named.service
    
    
  5. 在运行主实例 BIND 的系统上,打开 named.conf 文件。

  6. 使用从属服务器的地址更新 example.com. 区域的 allow-transfer 条目。区域的配置应如下所示:

    zone "example.com." in {
     type master;
     file "/var/named/zones/example.com.fwd";
     allow-transfer { 192.168.56.20; };
    };
    
    
  7. 对反向区域配置进行相同的更改:

    zone "56.168.192.in-addr.arpa." in {
     type master;
     file "/var/named/zones/example.com.rev";
     allow-transfer { 192.168.56.20; };
    };
    
    
  8. 保存更改并关闭文件。

  9. 重启主服务器以使配置更改生效:

    systemctl restart named.service
    
    
  10. 在从属服务器上,使用 dig 测试配置并请求区域传输:

    dig @192.168.56.10 example.com. AXFR
    
    

它是如何工作的...

从属服务器在主权威 DNS 服务器通知其区域记录已更改并且从属服务器维护的区域文件副本根据 SOA 记录到期时,请求区域传输。在本食谱中,我们从两个运行 BIND 的系统开始,并编辑它们的配置以允许传输。我们从配置为从属的系统开始,配置了之前处理过的正向和反向查找区域:

zone "example.com." in {
 type slave;
 file "/var/named/slaves/example.com.fwd";
 masters { 192.168.56.10; };
 allow-transfer { none; };
 notify no;
};
zone "56.168.192.in-addr.arpa." in {
 type slave;
 file "/var/named/slaves/example.com.rev";
 masters { 192.168.56.10; };
 allow-transfer { none; };
 notify no;
};

type slave 选项指示该服务器作为区域的从属服务器运行。由于主从关系是按区域设置的,因此同一个 BIND 实例可以在一个区域中充当主服务器,而在另一个区域中充当从属服务器。masters 选项提供了主服务器的地址。

file 选项提供了 BIND 将写入传输的区域信息的路径。将传输的区域与系统上的任何主区域文件分开存放不仅有利于组织管理,而且有利于安全性。BIND 需要对目录具有写权限才能保存传输文件,但主区域文件应对除管理员(即 root)之外的任何人设置为只读,以防篡改。我们的配置将它们保存到 /var/named/slaves,该目录在我们安装 bind 包时已创建,并且已经具有适当的权限。

allow-transfers 选项列出了此服务器允许响应的区域传输请求的系统。为了防止可能的滥用,我们将其值设置为 none,这样就不允许从从属服务器进行传输。所有传输将由主权威 DNS 服务器处理,即使如此,它也只会将数据发送给从属服务器。

每当区域重新加载时,BIND 会向区域的 NS 记录中列出的从属权威服务器发送通知。由于主服务器已经通知了其他从属服务器(如果你配置了多个从属服务器),因此没有必要让从属服务器向其他从属服务器发送通知,因此我们通过 notify no 关闭了这种行为。

然而,如果需要,你可以通过 also-notify 选项将通知发送给除了区域文件中列出的服务器之外的其他服务器。如果你有额外的从属服务器,并且不想通过 NS 记录公开它们,或者如果你希望通知其他自动化过程,这将非常有用。只需提供你希望通知的服务器的地址,并通过 also-notify 进行设置:

also-notify { 192.168.56.200; 192.168.68.200; };

若只通知 also-notify 中列出的服务器,而不通知从属权威服务器,可以将 notify 设置为 explicit

also-notify { 192.168.56.200; 192.168.68.200; };
notify explicit;

接下来,我们更新了主服务器的配置,使用allow-transfers指定从服务器的地址,以允许主服务器响应来自从服务器的区域传输请求:

zone "example.com." in {
 type master;
 file "/var/named/zones/example.com.fwd";
 allow-transfer { 192.168.56.20; };
};

在重启 BIND 以使我们的更改生效后,我们可以通过在从属系统上使用dig请求主服务器的区域传输来测试配置:

dig @192.168.56.10 example.com. AXFR

注意

每次更新区域配置时,记得在SOA记录中递增序列号。从属服务器在更新其区域信息之前会检查序列号,如果值没有改变,它将不会进行更新。

另请参见

有关配置和处理区域传输的更多信息,请参考以下资源:

配置rndc来控制 BIND

rndc是用于管理 BIND 服务器的客户端工具。然而,在使用它之前,必须配置rndc和 BIND。此食谱将向您展示如何配置它们,然后展示一些用于管理服务器缓存的命令。

准备工作

本食谱需要一个已安装并按前述食谱配置的 CentOS 系统。还需要管理员权限,可以通过以root帐户登录或使用sudo来获得权限。

如何操作...

按照以下步骤配置rndc

  1. 使用rndc-confgen工具生成必要的密钥文件:

    rndc-confgen -a -c /etc/rndc.key
    
    
  2. 创建/etc/rndc.conf文件,内容如下:

           include "/etc/rndc.key";
           options {
               default-key "rndc-key";
               default-server 127.0.0.1;
               default-port 953;
           };
    
    
  3. 确保rndc.keyrndc.conf的正确所有权和访问权限:

    chown root.named /etc/rndc*
    chmod 640 /etc/rndc*
    
    
  4. 打开/etc/named.conf,并在options块的闭括号后添加以下配置设置:

           include "/etc/rndc.key";
           controls {
               inet 127.0.0.1 port 953 allow { 127.0.0.1; } keys {
               "rndc-key"; };
           };
    
    
  5. 重启 BIND 使配置更改生效:

    systemctl restart named.service
    
    
  6. 使用rndc请求 BIND 状态来测试配置:

    rndc status
    
    

它是如何工作的...

rndc与 BIND 之间的通信需要一个共享密钥进行授权。因此,首先我们使用rndc-confgen生成了一个。在没有参数的正常操作中,程序会生成密钥和必要的配置片段,并将所有内容输出到屏幕上。你可以将输出的部分复制粘贴到适当的文件中,但如果你只能通过终端和键盘访问,这可能会很困难。相反,我们运行程序时加上-a选项,让它生成密钥的定义并将其输出到自己的配置文件中,其他配置部分则手动输入。-c选项只是指定了我们希望的密钥定义文件名称:

rndc-confgen -a -c /etc/rndc.key

注意

有些人报告说,rndc-confgen在他们的系统上似乎崩溃。如果你遇到这种情况,最可能的原因是它在等待足够的数据来生成密钥,但/dev/random的熵池不足,导致rndc-confgen一直在等待。终止该进程并使用-r选项再次尝试,指定/dev/urandom作为备用来源:

**rndc-confgen -a -c /etc/rndc.key -r /dev/urandom**

快速查看/etc/rndc.key,可以看到密钥的定义如下:

key "rndc-key" {
 algorithm hmac-md5;
 secret "YBmUKeobRMlAOUjCqMcb6g==";
};

rndc使用自己的配置文件。因此,接下来我们创建了/etc/rndc.conf

include "/etc/rndc.key";
options {
 default-key "rndc-key";
 default-server 127.0.0.1;
 default-port 953;
};

我们包含了来自rndc.key的密钥定义,并将其指定为rndc使用的默认密钥。我们还指定了本地回环地址作为默认服务器,并将 953 作为默认端口。通过这些配置选项,rndc会尝试连接到本地运行的 BIND 服务器,而无需我们在命令行中提供额外的参数。

最后,我们需要配置 BIND 以允许并验证 rndc 的连接请求。因此,我们再次包括密钥定义,并在named.conf中添加一个controls块:

include "/etc/rndc.key";
controls {
 inet 127.0.0.1 port 953 allow {127.0.0.1;} keys {"rndc-key";};
};

inet语句指定了哪些地址允许连接以及它们需要的认证密钥。第一个地址列出了 BIND 将监听的地址,以接收连接请求。为了安全起见,配置故意限制,只允许我们在本地使用rndc——BIND 监听本地地址并服务于从本地地址发出的命令。

如果你想使用rndc进行远程管理,我建议你不要开放访问,而是使用 SSH 登录到远程系统并使用该系统上的rndc副本。BIND 的控制通道保持关闭,不允许任何不怀好意的人访问,你也不需要分发密钥文件的副本,两系统之间的通信是加密的:

ssh 192.168.56.10 rndc status

注意

你可以通过创建一个alias来节省输入时间:

**alias rndc-ns1="ssh 192.168.56.10 rndc"** **rndc-ns1 status**

当没有指定子命令时,rndc会显示一个使用信息,列出我们可以执行的操作。status命令输出 BIND 的当前状态,包括已配置了多少个区域,是否有区域传输正在进行,以及对于解析 DNS 服务器,它当前正在尝试通过递归解决多少个查询:

rndc status

它是如何工作的...

rndc 用于管理 BIND DNS 服务器

如果你正在运行一个解析 DNS 服务器,flush 命令可能会很有用。它会从 BIND 的缓存中删除所有的缓存查找信息。如果你只想清除与特定域名相关的记录,可以使用 flushname

rndc flushname google.com

reloadrefresh 命令在权威服务器中非常有用。reload 命令使 BIND 在不重启服务器的情况下重新解析更新后的区域文件。除非指定了特定的区域,否则所有区域都会被重新加载:

rndc reload example.com.

对于从属 DNS 服务器,如果其区域文件副本过时,我们可以使用 refresh 命令强制 BIND 更新其副本:

rndc refresh example.com.

另见

有关使用 rndc 的更多信息,请参考以下资源:

第九章:电子邮件管理

本章包含以下食谱:

  • 配置 Postfix 以提供 SMTP 服务

  • 使用 Dovecot 为 Postfix 添加 SASL

  • 配置 Postfix 以使用 TLS

  • 配置 Dovecot 以实现安全的 POP3 和 IMAP 访问

  • 使用 SpamAssassin 进行垃圾邮件防护

  • 使用 Procmail 进行邮件路由

引言

在本章中,你将找到一些食谱,帮助你为你的域名设置并保护电子邮件服务。你将学习如何配置 Postfix 作为 SMTP 服务器,并学习如何配置它以支持 SASL 身份验证和 TLS 加密。接着,我们将配置 Dovecot,提供用户通过 POP3 和 IMAP 协议访问他们的电子邮件。最后,你将学习如何设置 SpamAssassin 和 Procmail,以减少垃圾邮件进入你的收件箱。

配置 Postfix 以提供 SMTP 服务

本食谱教你如何将 Postfix 配置为你的域名的基础电子邮件服务器。电子邮件是互联网最古老的服务之一,已经成为其最普及的服务之一。此外,电子邮件也可能是最难管理的服务之一。

使用简单邮件传输协议(SMTP),一封电子邮件从发信点到达你的收件箱,经过许多处理过程。当有人给你写信时,他们使用电子邮件客户端来撰写邮件。客户端将邮件发送到他们的邮件服务器,邮件服务器查找你的域名的MX记录,并将邮件转发到你的邮件服务器进行投递。一旦邮件被你的邮件服务器接收,它就会被送到服务器上的邮件目录。至少这是基本的概念。一封邮件可以通过任意数量的中间服务器在发件服务器和你的邮件服务器之间转发;服务器可以配置为发送邮件、接收邮件,或两者兼有。不同的协议用于从服务器中检索邮件(POP3 和 IMAP),这些协议与发送邮件时使用的协议不同,且为了尽量领先于垃圾邮件发送者,可能会增加相当多的复杂性。

注意

由于电子邮件生态系统的复杂性,成为一名邮件服务器管理员通常比全职工作还要繁重,因此我只能向你展示基础知识。后续的食谱将教你如何为你的设置添加身份验证和加密,依然有很多内容需要探索和学习。我强烈建议你利用每个食谱后面“另见”部分提到的额外资源。

准备工作

本食谱要求使用具有工作网络连接的 CentOS 系统。还需要管理员权限,可以通过使用root账户登录或通过使用sudo来获得权限。你还需要在系统上准备一些用户账户以供测试。

由于 MX 记录在邮件传递过程中用于解析邮件服务器的地址,因此假设你已经完成了上一章中的配方,或者已经配置了你自己的 DNS 记录。此处使用的 IP 地址 192.168.56.20 与第 8 章 《管理域和 DNS》 中 配置 BIND 作为权威 DNS 服务器 配方中所列的示例网络一致。

如何操作...

按照以下步骤设置 Postfix:

  1. 使用文本编辑器打开 Postfix 配置文件 /etc/postfix/main.cf

    vi /etc/postfix/main.cf
    
    
  2. 查找示例中的 myhostname 参数。删除前面的 # 字符以取消注释其中一个示例,并更新其值为你的合格主机名:

    myhostname = mail.example.com
    
    
  3. 找到示例中的 mydomain 参数,取消注释并编辑它,将你的域名设置为其值:

     mydomain = example.com 
    
    
  4. 查找 inet_interfaces 参数。将 localhost 条目前面加上 # 以注释掉它,然后取消注释 all 条目:

    inet_interfaces = all
    #inet_interfaces = $myhostname
    #inet_interfaces = $myhostname, localhost
    #inet_interfaces = localhost
    
    
  5. 查找 mydestination 参数并注释掉第一个条目。取消注释包含 $mydomain 的条目:

    #mydestination = $myhostname, localhost.$mydomain,  localhost
    mydestination = $myhostname, localhost.$mydomain,  localhost,  
           $mydomain
    #mydestination = $myhostname, localhost.$mydomain,  localhost,
    #       $mydomain mail.$mydomain, www.$mydomain,  ftp.$mydomain
    
    
  6. 查找示例中的 mynetworks 参数。取消注释其中一个条目,并编辑它使其值反映你的网络:

    mynetworks = 192.168.56.0/24, 127.0.0.0/8
    
    
  7. 查找示例中的 home_mailbox 参数并取消注释带有 Maildir/ 值的条目:

    home_mailbox = Maildir/
    
    
  8. 保存更改并关闭文件。

  9. 启动 Postfix 服务器,并可选择使其在系统重启时自动启动:

    systemctl start postfix.service
    systemctl enable postfix.service
    
    
  10. 在系统防火墙中打开 25 端口,以允许外部连接到 Postfix:

    firewall-cmd --zone=public --permanent --add-service=smtp
    firewall-cmd --reload
    
    

它是如何工作的...

CentOS 系统默认安装了 Postfix,将其用作本地邮件传输代理。为了将其重新配置为我们的域名邮件服务器,我们更新了其配置文件 /etc/postfix/main.cf 中的几个参数。

首先,我们更新了 myhostname 参数以提供我们系统的合格域名(主机名和域名):

myhostname = mail.example.com

注意

配置文件中的注释提到 FQDN,但我们知道 FQDN 需要一个尾部的点。如果你提供了一个真正的 FQDN 作为值,Postfix 会启动失败,并提示该参数的值无效。

mydomain 参数指定了该系统所属的域,Postfix 正在处理该域的电子邮件。尽管 Postfix 会尝试基于系统的合格主机名来确定域名,但明确使用 mydomain 来定义它以确保正确也是一个好主意:

mydomain = example.com

inet_interface 参数标识了 Postfix 将监听连接的网络接口。原始配置仅接受来自本地主机的连接;因此,我们将其更新为监听所有接口,尽管如果你的系统连接到多个网络,你可能希望指定更具体的内容:

inet_interfaces = all

mydestination 参数列出了 Postfix 接受邮件并最终投递的域。我们更改了原始配置以包括我们的域名:

mydestination = $myhostname, localhost.$mydomain, localhost,  $mydomain

如果需要,你应该向列表中添加其他值,以便识别系统的所有主机名,类似于最后一个示例中展示的mydestination,这样做很重要,以防止 Postfix 误以为消息是发往其他域而实际上是发往自身:

mydestination = $myhostname, localhost.$mydomain, localhost,  
    $mydomain, mail.$mydomain, www.$mydomain, ftp.$mydomain

mynetworks 参数用于识别 Postfix 可以为其转发消息的可信网络。这是防止垃圾邮件发送者滥用你的邮件服务器的第一道防线,因为如果消息不是发往我们域名,或者是从不在可信网络中的系统接收的,Postfix 将拒绝接受该消息:

mynetworks = 192.168.56.0/24, 127.0.0.0/8

最后,我们使用 home_mailbox 参数来设置邮件的投递目的地:

home_mailbox = Maildir/

消息通常会以 mbox 格式附加到用户在 /var/spool/mail 中的文件中。Maildir 格式则将每条消息单独存储在用户 Maildir 目录的子目录中。默认情况下,Postfix 将邮件投递到邮件队列。我们可以在两种格式之间转换消息,但现在选择 Maildir 会让我们在稍后的配制 IMAP 用户访问时稍微更方便一些。

一旦 Postfix 重启,我们可以发送一封测试邮件来验证服务器配置是否正确。这里当然有多种方法来实现。最简单的是使用命令行电子邮件客户端,如 mailx 来发送邮件。mailx 默认没有安装,但可以通过 yum 安装:

yum install mailx

调用 mailx 发送消息。-s 参数提供消息的主题,-r 参数提供发件人的地址(你自己的电子邮件地址)。接着,收件人的地址会紧跟其后:

mailx -r abell@example.com -s "Test email" tboronczyk@example.com

mailxstdin 读取消息。一个简单的“hello world”或“this is a test”就足够用来测试了;当你输入完毕后,输入一个单独的句点或者按 Ctrl + D

如果一切顺利,mailx 会将邮件发送到 Postfix,由 Postfix 将其投递到用户的邮件目录 /home/<username>/Maildir/new。检查该目录并输出文件内容,以确保消息已成功投递:

ls /home/tboronczyk/Maildir/new
cat /home/tboronczyk/Maildir/new/146284221.Vfd00I188f5ceM9593.mail

工作原理...

接收到的消息会被传送到用户的 Maildir 目录

另外,我们也可以通过 Telnet 客户端直接连接到 Postfix。输入原始命令发送电子邮件比使用 mailx 发送稍微复杂一些,但它更灵活,并且可以更清楚地看到 Postfix 的响应。这在排查问题时非常有用。

默认情况下没有安装 Telnet 客户端,因此你需要先使用 yum 安装 telnet

yum install telnet

然后使用 telnet 连接到服务器的 25 端口,这是保留给 SMTP 的端口:

telnet mail.example.com 25

MAIL FROM 命令用于提供发件人的电子邮件地址,而 RCPT TO 用于提供收件人的地址。每输入一次,Postfix 应该会以 250 Ok 状态响应:

MAIL FROM: tboronczyk@example.com
250 2.1.0 Ok
RCPT TO: abell@example.com
250 2.1.0 Ok

DATA开始消息的内容。Postfix 会接受我们输入的所有内容作为消息,直到我们在单独的行上输入一个句点:

DATA
352 End data with <CR><LF>.<CR><LF>
Subject: Test email
Hello world! This is a test.
.
250 2.0.0 Ok: queued as 705486E22E

然后,为了关闭连接,输入QUIT

QUIT
221 2.0.0 Bye
Connection closed by foreign host.

另请参见

请参考以下资源,了解更多有关使用 Postfix 的信息:

使用 Dovecot 将 SASL 添加到 Postfix

如果邮件服务器将消息转发到另一个域(即收件人的地址不在我们的域中),并且该消息来自我们网络外部,则该服务器被称为开放转发。垃圾邮件发送者经常寻找开放转发,因为这种宽松的行为容易被利用,而 Postfix 默认通过只转发来自我们网络的消息来保护我们。不幸的是,限制合法用户仅在我们网络内发送电子邮件是不可行的。本食谱教你如何使用 Dovecot 将简单身份验证和安全层(SASL)身份验证添加到 Postfix 配置中。然后,Postfix 将非常高兴地为我们经过身份验证的用户转发消息,无论他们的网络位置如何,同时仍然拒绝为其他任何人转发邮件。

准备工作

本食谱需要一个已经按照前面食谱配置了 Postfix 的 CentOS 系统。还需要管理员权限,可以通过 root 账户登录或使用sudo来实现。

如何操作...

按照这些步骤将 Postfix 安全配置为 SASL:

  1. 安装dovecot软件包:

    yum install dovecot
    
    
  2. 使用文本编辑器打开/etc/dovecot/conf.d/10-master.conf文件:

    vi /etc/dovecot/conf.d/10-master.conf
    
    
  3. 定位到unix_listener部分,查找/var/spool/postfix/private/auth。通过移除前导的#字符来取消注释该部分:

    # Postfix smtp-auth
    unix_listener /var/spool/postfix/private/auth {
     mode = 0666
    }
    
    
  4. mode更新为0660,并将usergroup参数添加到值为postfix的部分:

    # Postfix smtp-auth
    unix_listener /var/spool/postfix/private/auth {
     mode = 0660
     user = postfix
     group = postfix
    }
    
    
  5. 保存更改并关闭文件。

  6. 使用文本编辑器打开/etc/dovecot/conf.d/10-auth.conf文件:

    vi /etc/dovecot/conf.d/10-auth.conf
    
    
  7. 定位到auth_mechanisms选项,并将login添加到其值中:

    auth_mechanisms = plain login
    
    
  8. 保存更改并关闭文件。

  9. 启动 Dovecot 服务器,并可选择启用它在系统重启时自动启动:

    systemctl start dovecot.service
    systemctl enable dovecot.service
    
    
  10. 使用文本编辑器打开/etc/postfix/main.cf文件:

    vi /etc/postfix/main.cf
    
    
  11. 在配置文件的末尾,添加以下选项和值:

    smtpd_sasl_auth_enable = yes
    smtpd_sasl_type = dovecot
    smtpd_sasl_path = private/auth
    smtpd_sasl_security_options = noanonymous
    
    
  12. 保存更改并关闭文件。

  13. 重启 Postfix:

    systemctl restart postfix.service
    
    

它是如何工作的...

Dovecot 主要是一个邮件检索服务器,允许用户使用 POP 和 IMAP 协议访问电子邮件,它还允许 Postfix 接入其 SASL 认证机制。我们需要一个检索服务器供用户从系统中获取电子邮件,Dovecot 和 Postfix 整合得很好,因此选择 Dovecot 而非其他选项是合理的。

Dovecot 的配置分为多个文件,每个文件处理一个特定的功能或特性。在这个步骤中,我们需要更新主配置文件/etc/dovecot/conf.d/10-master.conf和认证配置文件/etc/dovecot/conf.d/10-auth.conf

10-master.conf中,我们找到了定义 SMTP 认证服务的unix_listener参数,该服务将与 Postfix 共享。取消注释该参数会创建一个套接字文件/var/spool/postfix/private/auth,Dovecot 和 Postfix 将通过该文件进行通信。然后我们更新了mode参数,并添加了usergroup参数以确保套接字的所有权和访问权限:

unix_listener /var/spool/postfix/private/auth {
 mode = 0660
 user = postfix
 group = postfix
}

10-auth.conf中,我们找到了auth_mechanism参数,并将login添加到它的值中。该参数设置了 Dovecot 使用的认证机制列表,login是专门用于 SMTP 认证的机制:

auth_mechanisms = plain login

plain允许用户以明文形式提供用户名和密码。login也被视为明文机制,但不用担心;你将在下一个步骤中学习如何保护它。

最后的配置步骤是将必要的 SASL 相关参数添加到 Postfix 的main.cf文件中:

smtpd_sasl_auth_enable = yes
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_security_options = noanonymous

smtpd_sasl_auth_enable启用 SASL 认证,smtpd_sasl_type通知 Postfix 它将使用 Dovecot 的认证服务。smtpd_sasl_path参数指定了相对于 Postfix 工作目录,用于与 Dovecot 通信的套接字文件的路径。smtpd_sasl_security_options禁止匿名连接,要求所有用户都必须认证。

Postfix 期望用户名和密码是 Base64 编码的,因此我们需要在用 Telnet 测试配置之前先进行编码。可以使用base64,但要小心不要在提供原始值时引入尾随换行符。调用base64后,你可以在stdin中输入用户名或密码,并立即按Ctrl + D两次,但不要按Enter。你可能想将base64的输出重定向到一个单独的文件,这样可以更容易地将编码值与原始值区分开,因为它们在终端中会连在一起显示而没有换行符:

base64 > ./username
tboronczyk
base64 > ./password
P@$$W0rd
cat ./username ./password

注意

尽管“换行符警惕性”有些麻烦,但这种方法比将值通过管道传输的方式要好:

**echo -n tboronczyk | base64**

命令的调用将保留在你的 shell 历史记录中。虽然对于用户名来说这样没问题,但由于这个原因,密码等敏感数据绝不能作为命令的一部分在命令行中提供。

通过在 25 端口使用 telnet 连接到服务器后,发送 AUTH LOGIN 命令以启动身份验证。Postfix 应该回应 VXNlcm5hbWU6,这是 Username: 的 Base64 编码值:

AUTH LOGIN
334 VXNlcm5hbWU6

提供你的编码后的用户名并按 Enter。然后 Postfix 会返回 UGFzc3dvcmQ6,这显然是 Password: 的编码版本。提供编码后的密码后,系统会告知你身份验证是否成功:

它是如何工作的...

身份验证交换要求凭证进行 Base64 编码

另见

请参考以下资源,获取更多有关 Postfix、Dovecot 和 SASL 的信息:

配置 Postfix 使用 TLS

实现邮件中继的身份验证是保护邮件服务器安全的重要步骤。但正如你在之前的教程中所学,用户名和密码是以明文方式发送的。Base64 编码使用 ASCII 字符编码二进制数据,这使得用户的密码可以包含非 ASCII 字符,但编码并不是加密。如果用户的邮件客户端和服务器之间的流量通过不受信任的网络传输,恶意用户可以轻易捕获凭证并冒充用户。因此,本教程通过配置传输层安全性(TLS)加密来保护通信,避免窃听。

准备工作

本教程需要一个已经按照之前教程配置了 Postfix 的 CentOS 系统。同时需要管理员权限,可以通过使用 root 账户登录或使用 sudo

如何操作...

按照以下步骤配置 Postfix 使用 TLS:

  1. 使用 openssl 生成一个新的密钥文件和安全证书:

    openssl req -newkey rsa:2048 -nodes \
     -keyout /etc/pki/tls/private/mail.example.key \
     -x509 -days 730 -subj "/CN=mail.example.com" -text \
     -out /etc/pki/tls/certs/mail.example.pem
    
    
  2. 使用文本编辑器打开 /etc/postfix/main.cf 文件:

    vi /etc/postfix/main.cf
    
    
  3. 在文件的末尾,添加以下选项和值:

    smtpd_tls_security_level = may
    smtpd_tls_cert_file = /etc/pki/tls/certs/mail.example.pem
    smtpd_tls_key_file = /etc/pki/tls/private/mail.example.key
    
    
  4. 保存更改并关闭文件。

  5. 重启 Postfix:

    systemctl restart postfix.service
    
    

它是如何工作的...

SSL/TLS 通信需要一个加密密钥和确认密钥所有权的安全证书。自签名证书足以用于个人用途或在私人网络上使用,因此本教程将教你如何使用 openssl 生成自签名证书:

openssl req -newkey rsa:2048 -nodes \ 
  -keyout /etc/pki/tls/private/mail.example.key \ 
  -x509 -days 730 -subj "/CN=mail.example.com" -text \ 
  -out /etc/pki/tls/certs/mail.example.pem

req选项创建一个新的证书请求,-newkey要求openssl生成一个新的私钥,并在签署证书时使用该密钥(这就是我们所说的自签名证书)。rsa:2048表示密钥将是一个 2048 位的 RSA 密钥。根据计算能力增长的预估,2048 位密钥通常被认为足够抵抗攻击,直到大约 2030 年。2048 位以上的密钥适用于此之后。-nodes防止密钥文件使用密码进行加密。重要的是不要用密码加密密钥文件,因为 Postfix 需要访问该密钥。如果加密了,我们每次启动 Postfix 时都需要提供密码来解密密钥。

-x509指定证书将是 X.509 证书(SSL 和 TLS 连接使用的类型),-days设置证书的过期日期,单位为未来的天数,在本例中为 730 天(3 年)。-subj用于指定证书的CN(常用名称)字段的值,该值应为证书所标识的系统的主机名或 IP 地址。或者,你可以省略该参数,openssl会交互式提示你为其他字段提供值。最后,-text参数指定证书应以文本格式编码,这是 Postfix 所期望的格式:

工作原理...

更多的身份信息可以嵌入到证书中。

自签名证书基本上就是说,这是我的加密密钥,你知道这是我的,因为我这么说。如果你的系统服务是面向公众的,你很可能需要投资购买一个由受信任证书颁发机构(CA)签署的证书。受信任的证书表示,你可以信任这个密钥是我的,因为一个共同的朋友会为我担保。要获得受信任的证书,你需要一个证书签名请求(CSR):

openssl req -new -newkey rsa:2048 -nodes \
 -keyout mail.example.key -out mail.example.csr

然后,你将钱和 CSR 发送给 CA。稍等片刻,你将收到你的证书。

注意

根据 CA 和请求的具体情况,受信任的证书可能非常昂贵。而且,信任也不像以前那样可靠。当一家知名 CA 的员工被揭露为签署伪造证书时,引发了丑闻,据称这些伪造证书是为了内部测试目的。人们只能对 Web 信任体系缺乏监管感到惊讶。希望最糟糕的时期已经过去。浏览器厂商开始推动更严格的指南和更多的审计工作。也有像Let's Encrypt这样的项目,使得可以自动生成免费的安全受信任证书。

接下来,我们将必要的配置参数添加到 Postfix 的main.cf文件中:

 smtpd_tls_security_level = may
    smtpd_tls_cert_file = /etc/pki/tls/certs/mail.example.pem
    smtpd_tls_key_file = /etc/pki/tls/private/mail.example.key 

smtp_tls_security_level 配置 Postfix 在加密连接方面的强制行为。may 启用机会性 TLS——服务器会声明支持加密,客户端可以利用它,但加密不是必须的。你也可以将该参数设置为 encrypt,强制要求使用加密。

smtpd_tls_cert_filesmtpd_tls_key_file 分别指定我们之前生成的自签名证书和加密密钥的路径。如果你使用的是受信任的证书,那么还需要提供 smtpd_tls_CAfile 参数,并为其指定一个值,来标识签名 CA 的公钥证书。

如果你发现安全连接的协商速度较慢,可以尝试一些调整参数。例如,我们可以显式地指定 Postfix 使用的熵源,使用 tls_random_source

 tls_random_source = dev:/dev/urandom 

此外,我们还可以缓存服务器和邮件客户端之间加密会话的详细信息。smtpd_tls_session_cache_database 参数定义了 Postfix 存储缓存详细信息的文件,而 smtpd_tls_session_cache_timeout 则指定了会话可以缓存的时间。这可以减少每次客户端连接时建立新会话的开销:

 smtpd_tls_session_cache_database =
      btree:/var/lib/postfix/smtpd_tls_cache
    smtpd_tls_session_cache_timeout = 3600s 

要测试配置,可以使用 telnet 连接并发出 STARTTLS 命令。Postfix 应该会响应,表示它准备好开始协商安全连接:

STARTTLS
220 Ready to start TLS

另请参见

请参阅以下资源以了解如何使用 Postfix 和 TLS:

配置 Dovecot 以进行安全的 POP3 和 IMAP 访问

当你检查电子邮件时,电子邮件程序会连接到你的邮件服务器,查看邮件目录中是否有新消息。如果配置为使用邮局协议(POP3),它会将邮件下载到本地并从服务器中删除。如果配置为使用互联网消息访问协议(IMAP),邮件会保留在服务器上,你可以远程管理它。

Dovecot 原生支持这两种协议。由于我们已经安装了 Dovecot 来提供其 SASL 功能,所以我们只需要在系统防火墙中打开 POP3 和 IMAP 流量的标准端口即可。然而,连接将是未加密的,信息将以明文形式通过网络传输。本篇教程教你如何使用 SSL 加密这些连接。

准备工作

该配置要求一个已配置好 Postfix 和 Dovecot 的 CentOS 系统,如之前的配方所述。还需要管理员权限,可以通过登录 root 账户或使用 sudo 来实现。

如何做到...

按照以下步骤配置对 Dovecot 的访问:

  1. 使用文本编辑器打开 /etc/dovecot/dovecot.conf

    vi /etc/dovecot/dovecot.conf
    
    
  2. 定位到 protocols 参数。去掉前面的 # 字符,并将其值设置为 imaps pop3s

    protocols = imaps pop3s
    
    
  3. 保存更改并关闭文件。

  4. 使用文本编辑器打开 /etc/dovecot/conf.d/10-ssl.conf

    vi /etc/dovecot/conf.d/10-ssl.conf
    
    
  5. 定位到 ssl 参数并将其值设置为 yes

     ssl = yes
    
    
  6. 定位到 ssl_certssl_key 参数。用证书和密钥文件的路径更新它们的值(请注意,两个路径前面都有 <):

    ssl_cert = </etc/pki/tls/certs/mail.example.pem
    ssl_key = </etc/pki/tls/private/mail.example.key
    
    
  7. 保存更改并关闭文件。

  8. 重启 Dovecot 使更改生效:

    systemctl restart dovecot.service
    
    
  9. 在防火墙中打开端口 993 以支持 IMAP SSL 和端口 995 以支持 POP3 SSL:

    firewall-cmd --permanent --add-service=imaps \
     --add-service=pop3s
    firewall-cmd --reload
    
    

它是如何工作的...

Dovecot 使得为 POP3 和 IMAP 连接保护流量变得简单;事实上,配置它只花了几秒钟。我们首先编辑了 /etc/dovecot/dovecot.conf 文件中的 protocols 参数,以便让 Dovecot 知道我们希望这些协议是安全的:

protocols = imaps pop3s

然后,我们更新了 /etc/dovecot/conf.d/10-ssl.conf 文件,以启用 SSL 使用 ssl 参数,并使用 ssl_certssl_key 来标识证书和加密密钥。由于 Postfix 和 Dovecot 运行在同一系统上,并且我们已经为 Postfix 生成了密钥和证书,因此可以在 Dovecot 的配置中引用相同的文件。Dovecot 使用路径前的 < 来指定它应该使用文件的内容作为参数的值,而不是字面字符串本身:

ssl = yes
ssl_cert = </etc/pki/tls/certs/mail.example.pem
ssl_key = </etc/pki/tls/private/mail.example.key

Dovecot 仍然会允许来自本地主机的 POP 和 IMAP 的非 SSL 访问(分别在端口 110143 上),但是一旦我们重启它以使配置更改生效,所有其他用户将需要使用 SSL 来访问他们的邮件。

我们可以使用 mailx 来测试配置。首先,我们检查 POP3:

mailx -f pop3s://tboronczyk@mail.example.com

-f 参数指定了 mailx 用来读取并获取我们邮件的目录。给定为 URI 时,这个值指示 mailx 使用 POP3 SSL (pop3s) 从 mail.example.com 系统读取我们用户的默认目录。

除了更改 URI 的协议外,检查 IMAP 的命令是一样的:

mailx -f imaps://tboronczyk@mail.example.com

由于我们使用的是自签名证书,mailx 会提示证书没有被用户标记为信任,并询问是否继续。对这个提示输入 y,然后会提示输入用户密码。之后,mailx 会显示用户的收件箱。在提示符下输入 quit 退出程序:

它是如何工作的...

mailx 可以用来测试我们配置的 POP3 和 IMAP SSL。

注意

如果mailx提示缺少nss-config-dir变量,你可以在命令行中使用-S来定义该变量。其值应为mailx可以用来验证证书信任的证书数据库的路径:

mailx -S nss-config-dir=/etc/pki/nssdb \
   -f pop3s://tboronczyk@mail.example.com

当我们第一次配置 Postfix 时,我们调整了其home_mailbox参数,将邮件存储在不同的目录中。我当时知道这只是可选的,但在我们设置检索访问时,它会使事情变得更容易、更清晰。如果当时没有设置home_mailbox,那么收到的邮件将被附加到/var/spool/mail下的用户邮件队列文件中,且 Dovecot 访问它们时需要一些额外的配置。这些更改可以在/etc/dovecot/conf.d/10-mail.conf中进行。

或者,你可以此时将邮件队列文件转换为Maildir目录中的单独邮件。首先,安装mb2md包:

yum install ftp://ftp.pbone.net/mirror/atrpms.net/el7- 
    x86_64/atrpms/stable/mb2md-3.20-2.at.noarch.rpm

打开/etc/postfix/main.cf文件,找到home_mailbox参数。去掉值为Maildir/的条目前的#字符:

home_mailbox = Maildir/

保存更改后,重新启动 Postfix 以使更新生效。然后,对于每个账户,使用mb2md转换邮件队列文件。该工具需要在目标用户的上下文中运行,因此使用su命令临时切换到该用户的上下文:

su -l -c "mb2md -m" tboronczyk

参见

请参阅以下资源,以获取有关本食谱中讨论的不同主题的更多信息,包括 Dovecot、POP3 和 IMAP。

使用 SpamAssassin 过滤垃圾邮件

一些估算认为超过 90%的电子邮件是未请求的广告(垃圾邮件)!不管这些估算是否正确,不可否认的是垃圾邮件是一个巨大问题。垃圾邮件会给邮件服务器增加额外的负载,占用存储空间,甚至可能带来安全风险。此外,虽然有很多法律手段试图管理垃圾邮件,但这些尝试大多失败了。

本食谱教你如何设置 SpamAssassin 来识别垃圾邮件。SpamAssassin 通过检查各种垃圾邮件特征,如缺少头部信息和无效的返回地址,来过滤传入的邮件,并使用启发式方法分析邮件内容。每项检查都会为邮件的总体垃圾邮件评分做出贡献,如果该评分超过设定的阈值,则该邮件会被标记为垃圾邮件。

准备工作

本文需要一个已按照上一篇食谱配置好 Postfix 的 CentOS 系统。此外,还需要管理员权限,可以通过以 root 账户登录或使用sudo来获取。

操作步骤如下...

按照以下步骤使用 SpamAssassin 识别垃圾邮件:

  1. 安装 spamassassin 包:

    yum install spamassassin
    
    
  2. 启动 SpamAssassin,并可选择使其在系统重新启动时自动启动:

    systemctl start spamassassin.service
    systemctl enable spamassassin.service
    
    
  3. 创建 SpamAssassin 的贝叶斯分类器数据库:

    sa-learn --sync
    
    
  4. 创建一个非特权系统用户帐户,Postfix 可以使用它与 SpamAssassin 进行通信:

    useradd -r -s /sbin/nologin spamd
    
    
  5. 打开 Postfix 的 master.cf 文件进行编辑:

    vi /etc/postfix/master.cf
    
    
  6. 定位定义 smtp 服务的行,并附加 -o 参数指定 spamassassin 作为内容过滤器:

    smtp inet n - n - - smtpd -o content_filter=spamassassin
    
    
  7. 在配置文件末尾,添加 spamassassin 过滤器的定义:

    spamassassin unix - n n - - pipe user=spamd  argv=/usr/bin/spamc -e 
           /usr/sbin/sendmail -oi -f ${sender}  ${recipient}
    
    
  8. 保存更改并关闭文件。

  9. 重新启动 Postfix 以使配置更新生效:

    systemctl restart postfix.service
    
    

工作原理如下...

SpamAssassin 的初始安装非常简单。我们安装了 spamassassin 包,并启动并启用了运行 spamd 守护程序的 spamassassin 服务。客户端程序 spamc 用于与守护程序通信,其余的步骤则专注于配置 Postfix 以使用 spamc 对电子邮件进行评分。

我们创建了一个名为 spamd 的新用户帐户,供 Postfix 在调用 spamc 时使用。该帐户旨在作为非交互式系统帐户,因此我们提供了 -r 参数。这导致不会创建任何 home 目录,并且该帐户的用户 ID 被分配一个小于 100 的值。-s 参数将 /sbin/nologin 指定为帐户的 shell,以防止某人使用该帐户登录:

useradd -r -s /sbin/nologin spamd

要让 Postfix 将消息传递给 SpamAssassin,我们需要在其 master.cf 配置文件中定义一个新的 spamassassin 服务,并要求 Postfix 使用该服务作为内容过滤器。master.cf 的组织方式与我们之前见过的配置文件大不相同——每行定义邮件传递管道中的一个进程及其特定属性。

文件中的第一个活动条目是 smtp 服务的条目,看起来像这样:

smtp inet n - n - - smtpd

第一列是服务的名称,第二列指定服务将如何通信。例如,inet 表示进程使用 TCP/IP 套接字,而 unix 表示使用本地 Unix 域套接字。接下来的三列指示进程是否私有(仅对 Postfix 可访问)、是否以非管理员权限运行以及是否进行了 chroot。它们的值可以是 y 表示是,n 表示否,或 - 表示使用 Postfix 的默认值。剩余的列提供了进程定时运行的唤醒计时器、同时运行的实例数限制以及提供服务的调用命令。

要将我们的 spamassassin 服务设置为过滤器,我们更新了 smtp 服务的命令,使用 -o 选项来设置 content_filter 参数为我们服务的名称:

smtp inet n - n - - smtpd -o content_filter=spamassassin

然后我们在文件底部定义了 spamassassin 服务:

spamassassin unix - n n - - pipe user=spamd argv=/usr/bin/spamc -e  
/usr/sbin/sendmail -oi -f ${sender} ${recipient}

pipe 命令是 Postfix 配送系统的一部分,旨在将邮件传递到外部进程。user 参数指定调用的进程将在哪个用户帐户下运行,argv 是将要执行的命令及其参数。我们的定义引用了我们之前创建的 spamd 用户,并将邮件传递给 spamc 客户端。

spamd 审查邮件后,默认情况下 spamc 会将邮件返回给标准输出。为了避免丢失邮件,我们将输出通过管道传递给另一个进程以交付邮件。-e 告诉 spamc 将输出通过管道传递进行处理,在这种情况下是传递给名为 sendmail 的程序。

Sendmail 是一个比 Postfix 更老的邮件服务器。它主宰了电子邮件领域数十年,因此许多程序尝试与它对接以发送邮件。这个 sendmail 实例实际上是 Postfix 的 Sendmail 兼容接口,它允许其他进程认为它们正在调用 Sendmail,而实际上它们在与 Postfix 配合工作。-oi 参数告诉 sendmail 将包含单个点的行视为常规输入,而不是将其解释为消息的结束。-f 参数将邮件的发件人地址设置为 ${sender} 的值,这是一个由 Postfix 填充的特殊变量,包含发件人的电子邮件地址,而邮件将发送到 ${recipient},即收件人的电子邮件地址。

为了测试配置,我们可以发送一封邮件,主题为已知值,SpamAssassin 总是将其标记为垃圾邮件:

XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST- EMAIL*C.34X

它是如何工作的...

发送一封带有已知签名的邮件来测试 SpamAssassin

当您检查收件箱中的邮件时,您会注意到 SpamAssassin 会在主题行前添加 [SPAM],从而使您能够轻松识别不需要的邮件。它还会向邮件添加附加头部,概述它得出邮件为垃圾邮件的结论的相关发现:

它是如何工作的...

SpamAssassin 更新邮件的主题行,并添加附加头部,解释它为何认为邮件是垃圾邮件

请记住,垃圾邮件的世界在不断变化;程序员们正在努力构建更好的垃圾邮件过滤器,但垃圾邮件发送者也在同样努力寻找规避方法。因此,保持 SpamAssassin 数据库的更新非常重要。SpamAssassin 安装时会添加一个 cron 任务,用于每天更新数据库,但您也可以随时手动运行更新,方法是运行:

sa-update

如果 SpamAssassin 错误地将大量合法邮件识别为垃圾邮件,或反之,您可以使用 sa-learn 来训练其贝叶斯分类器,从而更好地识别不需要的邮件。我们可以提供一组已知为垃圾邮件的邮件,并使用 --spam 参数标识它们,同时用 --ham 参数标识好的邮件,供程序学习:

sa-learn --ham /home/tboronczyk/Maildir/cur
sa-learn --spam /home/tboronczyk/Mail/.Spam

sa-learn会跟踪它已看到的消息。如果你之前标记某个邮件为垃圾邮件,然后后续将其作为正常邮件使用,该程序会将其从垃圾邮件数据库中删除,反之亦然,如果你标记某邮件为正常邮件,但后来决定它应作为垃圾邮件使用。

另请参见

参阅以下资源,了解更多关于使用 SpamAssassin 的信息:

使用 Procmail 路由消息

根据你的偏好,仅将消息标记为垃圾邮件可能不够。也许你希望在电子邮件客户端中设置规则,将所有不需要的邮件从收件箱移动到专门的垃圾邮件目录。或者,你希望这种路由在服务器端自动完成。我们可以使用 Procmail 来配置这一点,它是一个邮件过滤和投递代理。

在本教程中,我们将查看如何配置 Procmail 来路由消息。我们将扫描传入的邮件,查找 SpamAssassin 添加到邮件中的特殊头部(如果它认为邮件是垃圾邮件),然后将其投递到一个单独的目录,而不是收件箱。

准备工作

这个教程需要一个已按前面的教程配置好 Postfix 的 CentOS 系统。同时也需要管理员权限,可以通过登录root账户或使用sudo来获得。

如何操作...

按照以下步骤设置 Procmail 路由消息:

  1. 创建/etc/procmailrc文件,内容如下:

    MAILDIR=$HOME/Maildir
    DEFAULT=$MAILDIR/new
    INCLUDERC=/etc/mail/spamassassin/spamassassin-spamc.rc
    :0
    * ^X-Spam-Status: Yes
    .Spam
    
    
  2. 为每个用户创建垃圾邮件目录:

    echo Spam >> /home/tboronczyk/Maildir/subscriptions
    mkdir /home/tboronczyk/Maildir/.Spam
    
    
  3. 如果你是以root身份创建了用户的垃圾邮件目录,请修复该目录和订阅文件的所有权和权限:

    chown tboronczyk /home/tboronczyk/Maildir/subscriptions
    chmod 0600 /home/tboronczyk/Maildir/subscriptions
    chown tboronczyk.tboronczyk /home/tboronczyk/Maildir/.Spam
    chmod 0700 /home/tboronczyk/Maildir/.Spam
    
    
  4. 用编辑器打开 Postfix 的main.cf配置文件:

    vi /etc/postfix/main.cf
    
    
  5. 查找示例的mailbox_command参数。取消注释第二个示例,并将其路径修改为procmail可执行文件的路径:

    mailbox_command = /bin/procmail -a "$EXTENSION"
    
    
  6. 保存更改并关闭文件。

  7. 重启 Postfix 以使更新的配置生效:

    systemctl restart postfix.service
    
    

它是如何工作的...

像 Postfix 一样,Procmail 在 CentOS 系统上默认安装。但是,我们需要创建它的配置文件,以便让它为我们服务。主要的配置文件是/etc/procmailrc,我们通过定义MAILDIRDEFAULTINCLUDERC变量来启动它。

MAILDIR=$HOME/Maildir
DEFAULT=$MAILDIR/new
INCLUDERC=/etc/mail/spamassassin/spamassassin-spamc.rc

MAILDIR提供了用户邮件目录的位置。procmailrc是一个全局配置文件,我们使用$HOME来表示用户的主目录,其中包含MaildirDEFAULT提供了接收邮件的默认位置,即邮件目录的new目录。

INCLUDERC给出了在 Procmail 处理配置文件时应该包含的其他文件的名称。在这种情况下,SpamAssassin 安装了一个配置文件来与 Procmail 集成,我们在此引用它。

配置的第二部分看起来像一段神秘的咒语——即匹配规则的定义。在 Procmail 术语中,它们被称为食谱(recipes):

:0
* ^X-Spam-Status: Yes
.Spam

配置文件中可以给出多个规则,在这种情况下,它们会按出现的顺序自上而下地处理。

所有规则以:0开头,并包含条件和后续的动作。这里,条件以*开始,指定一个正则表达式模式,Procmail 会在邮件及其头部中搜索该模式。动作行则列出匹配的邮件将被投递到的目录。如果给出的路径是相对路径,那么该目录将相对于$MAILDIR来确定。因此,该规则要求 Procmail 将任何带有X-Spam-Status头部并由 SpamAssassin 标记的邮件路由到用户的Maildir/.Spam目录。

原始的 Maildir 规范只允许newcurtmp目录,但其他一些实现已经扩展了它以支持额外的目录。用户可以通过他们的电子邮件客户端通过 IMAP 创建他们的垃圾邮件目录,在这种情况下,所有细节都由 Dovecot 处理。或者,我们可以在文件系统中为他们创建该目录。当我们手动创建目录时,subscriptions文件必须列出附加的目录,每行一个条目,以便它们在用户的邮件客户端中可见。目录本身将以一个点号(.)作为前缀命名:

echo Spam >> /home/tboronczyk/Maildir/subscriptions
mkdir /home/tboronczyk/Maildir/.Spam

Procmail 还允许每个用户进行个性化设置。例如,如果只有一个用户希望将标记的邮件移动到他们的垃圾邮件文件夹,那么匹配的规则可以从全局配置(位于/etc)移到他们home目录下的一个名为.procmailrc的文件中。仍然建议将变量定义保留在全局配置中,这样它们对所有用户都可用,因为 Procmail 首先执行全局文件,然后执行用户的本地.procmailrc(如果它可用)。

可以在:0后面给出各种标志,以修改 Procmail 的行为或规则的解释方式。例如,默认情况下,Procmail 只搜索邮件的头部。要搜索邮件的正文,我们需要提供B标志。以下规则是一个示例,它在邮件正文中搜索文本"Hello World",并将匹配的邮件路由到/dev/null

:0 B
* Hello World
/dev/null

你可能会发现一些有用的标志:

  • H:搜索邮件的头部

  • B:搜索邮件正文

  • D:以区分大小写的方式匹配正则表达式

  • e: 只有在前一条规则未成功时,才执行该规则

  • c: 创建消息的副本

  • h: 仅将消息的头部发送到管道程序

  • b: 仅将消息的正文发送到管道程序

如果操作以 | 开头,则该值被解释为命令,消息将通过管道发送到该命令。以下是一个示例,它将任何来自人力资源部门的邮件副本通过 lpr 打印出来:

:0 c
* ^From: hr-dept@example.com
| lpr

如果操作以 ! 开头,则该值被视为电子邮件,消息将被转发。此示例将来自已知收件人的电子邮件转发到个人电子邮件帐户:

:0
* ^From: secret-admirer@example.com
! tboronczyk@another-example.com

另请参见

有关 Procmail 的更多信息,请参阅以下资源:

第十章:管理 Web 服务器

本章包含以下食谱:

  • 安装 Apache HTTP 服务器和 PHP

  • 配置基于名称的虚拟主机

  • 配置 Apache 通过 HTTPS 提供页面

  • 启用重写并执行 URL 重写

  • 安装 NGINX 作为负载均衡器

介绍

本章包含了如何使用 Apache HTTP 服务器来托管网站的食谱。首先,您将学习如何安装服务器以及 PHP,这是一个非常常见的服务器端脚本引擎,用于生成动态的 Web 内容。接下来,您将了解如何通过基于名称的虚拟主机在同一个服务器实例上托管多个网站,如何加密连接并通过 HTTPS 提供内容,以及如何动态重写传入的 URL。最后,我们将介绍 NGINX 及其作为反向代理的使用,能够减少服务器负载,同时加速用户访问我们的网站。

安装 Apache HTTP 服务器和 PHP

你可能听过 LAMP 这个缩写,它代表 Linux、Apache、MySQL 和 PHP。它指的是提供网站和 Web 应用程序的流行技术组合。本食谱将教你如何安装 Apache HTTP 服务器(简称 Apache)并配置它与 PHP 一起工作,以提供动态的 Web 内容。

Apache 最早在二十多年前发布,是最早的 Web 服务器之一,并且一直是最受欢迎的服务器之一。它在 LAMP 堆栈中的任务是通过响应用户对 Web 资源的请求与用户互动。它的一个卖点可能就是它的设计,允许通过模块扩展其功能。有许多模块,例如 mod_ssl,它为 Apache 添加了 HTTPS 支持,以及 mod_rewrite,它允许您动态修改请求的 URL。

PHP 是一种用于创建动态 Web 内容的脚本语言。它在后台工作,脚本的输出通常由 Apache 提供,以响应请求。PHP 通常作为模块(mod_php)安装,将语言的解释器嵌入到 Apache 的处理过程中,但现在,运行 PHP 作为独立进程更受欢迎。这就是我们在这个食谱中采用的方法。

准备工作

这个食谱要求使用具有有效网络连接的 CentOS 系统。假设系统已配置为 IP 地址 192.168.56.100。还需要管理员权限,可以通过登录 root 账户或使用 sudo 来获得权限。

请注意,官方 CentOS 仓库安装的是 PHP 5.4。如果您想安装更新的版本,Remi 仓库提供了 PHP 5.5、5.6 和 7.0。要安装 5.x 版本之一,请打开 /etc/yum.repos.d/remi.repo 文件,找到 [remi-php55][remi-php56] 部分中的 enabled 选项,并将其值设置为 1。对于 7.0 版本,请更新 /etc/yum.repos.d/remi-php70.repo 文件中的 enabled 选项。

注意

PHP 6 发生了什么事?这是一个很长的故事……。开发 PHP 的志愿者团队曾致力于第 6 版的开发,但该项目遇到了许多困难,最终被搁置。为了避免与关于 PHP 6 的博客文章产生混淆,决定将其版本号提升到 7。简而言之,PHP 6 确实存在过,但从未达到正式发布状态,大多数为 6 版规划的酷炫功能最终被包含在 PHP 5.3、5.4 和 7.0 中。

如何操作...

按照以下步骤安装 Apache HTTP 服务器和 PHP:

  1. 安装 httpdphp-fpm 包:

    yum install httpd php-fpm
    
    
  2. 使用文本编辑器打开 Apache 的配置文件:

    vi /etc/httpd/conf/httpd.conf
    
    
  3. 找到 ServerName 选项。去掉行首的 # 以取消注释,并将该选项的值更改为反映服务器的主机名或 IP 地址:

    ServerName 192.168.56.100:80
    
    
  4. 找到 DirectoryIndex 选项,并将 index.php 添加到列表中:

     <IfModule dir_module>
              DirectoryIndex index.html index.php
           </IfModule> 
    
    
  5. 在文件末尾添加以下配置:

     <IfModule proxy_fcgi_module>
              ProxyPassMatch ^/(.*\.php)$  
              fcgi://127.0.0.1:9000/var/www/html/$1
           </IfModule> 
    
    
  6. 保存您的配置更改并关闭文件。

  7. 验证 mod_proxy(列为 proxy_module)和 mod_proxy_fcgi(列为 proxy_fcgi_module)扩展模块是否已启用:

    httpd -M | grep proxy
    
    
  8. 输出中应该出现这两个模块。

  9. 启动 Apache 和 PHP 的 FPM 服务,并启用它们在系统重启时自动启动:

    systemctl start httpd.service php-fpm.service
    systemctl enable httpd.service php-fpm.service
    
    
  10. 打开系统防火墙的 80 端口,以允许 HTTP 请求通过:

    firewall-cmd --zone=public --permanent --add-service=http
    firewall-cmd --reload
    
    

它是如何工作的...

有多种方式可以将 PHP 与 Apache 的 HTTP 服务器集成以生成动态网页内容。历史上,使用 Apache 的 mod_php 模块是常见的做法,但现在推荐的方法是将 PHP 作为独立进程运行,Web 服务器通过 FastCGI 协议与其通信。因此,我们安装了 Apache HTTP 服务器的 httpd 包和 PHP 解释器及其进程管理器的 php-fpm 包:

yum install httpd php-fpm

PHP FastCGI 进程管理器(FPM)从 5.3 版本起包含在核心 PHP 分发包中。将 PHP 与 Apache 分离有助于构建更具可扩展性的架构,使用持久的 PHP 进程可以减少 CPU 的负担,因为每个请求不需要重新启动新的解释器。

Apache 的主配置文件是 /etc/httpd/conf/httpd.conf,我们在其中更新了 ServerName 选项以反映服务器的主机名或 IP 地址。虽然这一步不是严格必要的,但如果不设置该选项,服务器将会在日志文件中写入警告消息。此外,服务器能够识别自身是有益的:

ServerName 192.168.56.100:80

接下来,我们通过将 index.php 添加到 DirectoryIndex 选项的值列表中进行了更新。当用户请求一个解析为目录的资源时,服务器会在该目录中查找与 DirectoryIndex 列表中的名称匹配的文件。如果找到,Apache 将返回该文件以满足请求。这种行为使得访客可以通过类似 www.example.com 而不是 www.example.com/index.html 的 URL 访问网站的首页:

DirectoryIndex index.html index.php

文件列出的顺序是有意义的。例如,如果目录中同时存在index.htmlindex.php,则返回index.html,因为它在选项列表中排在index.php之前。

然后,我们导航到文件的末尾添加了以下代理配置。如果ProxyPassMatch的正则表达式匹配到传入的请求,那么服务器将获取指定的 URL 并返回该内容:

 <IfModule proxy_fcgi_module>
      ProxyPassMatch ^/(.*\.php)$ fcgi://127.0.0.1:9000/var/www/html/$1
    </IfModule> 

正则表达式是使用一种特殊的符号书写的,描述了如何匹配文本。大多数字符是按字面意思匹配的,但有些字符具有特殊的意义:

  • .:这匹配任何字符。模式bu.匹配文本budbugbunbus等。

  • +:这表示前面的元素可以匹配一次或多次。模式fe+t可以匹配fetfeetfeeet等,但不能匹配ft

  • *:这表示前面的元素可以匹配零次或多次。模式fe*t可以匹配ftfetfeetfeeet等。

  • ?:这表示前面的元素可以选择性地匹配一次。模式colou?r匹配colorcolour

  • ^:这将匹配文本行的开头。模式^abc仅在abc出现在文本的开头时才匹配abc^[ ]中使用时具有特殊含义)。

  • $:这将匹配文本行的结尾。模式xyz$仅在xyz出现在行末时才匹配xyz

  • [ ]:这表示匹配括号内的任意字符。模式co[lr]d匹配coldcord。当[ ]中的第一个字符是^时,列表会被取反;co[^lr]d匹配coed,但不匹配coldcord

  • ( ):这将元素分组并捕获匹配项。模式jump(ed)?可以匹配jumpjumped

如果你希望匹配这些特殊字符的字面意义,则应在前面加上反斜杠进行转义,例如foo\.html将匹配foo.html,而不是fooahtmlfoobhtml等。

特殊的数字变量如$1$2包含任何捕获到的匹配项的值。它们被赋值的顺序与括号捕获匹配项的顺序相同,因此(foo)\.(html)$1设置为foo$2设置为html

有了这些理解,你现在应该能够解读正则表达式^/(.*\.php)$,它捕获以.php扩展名结尾的请求资源的路径和文件名。$1变量表示捕获到的路径,因此请求/about/staff.php将被代理为fcgi://127.0.0.1:9000/var/www/html/about /staff.php,其中 PHP 的 Fast-CGI 监听器正在本地接口的9000端口上监听。

Apache 的功能通常通过模块扩展,作为一种安全措施,最好将特定模块的配置选项包装在 IfModule 块中。此类块的开头包含模块的名称,并出现在尖括号 < > 中。块的结束则是 </IfModule>,就像关闭一个 HTML 元素一样。

服务器提供文件的目录是通过选项 DocumentRoot 设置的。默认值为 /var/www/html,因此我们放置在那里或其子目录中的任何文件都可以访问。例如,为了说明这一点,发行版包含一个示例的 index.html 文件,我们可以用它来验证服务器是否正常运行;将 /usr/share/httpd/noindex/index.html 文件复制到 /var/www/html 中:

cp /usr/share/httpd/noindex/index.html /var/www/html

然后,打开浏览器并访问系统的域名或 IP 地址。你应该看到欢迎页面:

它是如何工作的...

你可以将 Apache 的默认首页复制到 Web 目录中,以测试服务器是否已启动并正常运行

对于 PHP,你需要将 PHP 文件放置在 Fast-CGI 服务可以读取的位置。代理 URL 是 fcgi://127.0.0.1:9000/var/www/html/$1,因此我们也可以将 PHP 文件放置在 /var/www/html 中。

创建 info.php 文件,并添加以下内容:

 <?php
    phpinfo(); 

现在保存文件,然后在浏览器中访问该页面。你应该看到 PHP 的 phpinfo() 函数的输出,提供有关 PHP 配置的详细信息,以及哪些模块可用:

它是如何工作的...

PHP 报告有关其环境和请求的信息

注意

出于安全考虑,建议在验证一切正常后删除你复制的欢迎 index.html 文件以及 info.php 脚本。它们提供的信息可能会让恶意用户比你希望的更多地了解你的 Web 服务器配置。

另请参见

请参考以下资源以获取更多关于 Apache 和 PHP 的工作信息:

配置基于名称的虚拟主机

正如你在我们讨论 DNS 时回忆起的内容,在第八章中,管理域名和 DNS 用户的浏览器需要通过 DNS 查询将网站的主机名转换为其 IP 地址,才能连接并检索所需的网页内容。你也许还记得,这并不需要一一对应映射——多个站点可以解析到相同的 IP 地址。Apache 足够灵活,允许同一服务器通过名为基于名称的虚拟主机的配置来提供多个站点。

本教程将教你如何设置基于名称的虚拟主机。每个站点都有自己的配置(通常会保存在单独的配置文件中以便于管理)。根据请求中出现的站点名称,Apache 然后从可用的配置中选择,以正确地提供所需的站点。

准备工作

本教程要求你使用已连接网络的 CentOS 系统,并且安装了运行如前一教程所述的 Apache。因为我们将通过域名而不是 IP 地址连接到服务器,所以你需要通过更新 DNS 记录或首先向 /etc/hosts 文件添加条目,确保域名解析到正确的地址。还需要管理员权限,可以通过登录 root 账户或使用 sudo 来获取。

如何操作…

按照以下步骤设置基于名称的虚拟主机:

  1. 使用文本编辑器打开 Apache 的配置文件:

    vi /etc/httpd/conf/httpd.conf
    
    
  2. 在文件底部添加以下 Include 选项:

    Include sites/*.conf
    
    
  3. 保存更新后的配置并关闭文件。

  4. 创建配置中引用的 sites 目录:

    mkdir /etc/httpd/sites
    
    
  5. 在新 sites 目录中为第一个站点创建一个虚拟主机配置文件:

    vi /etc/httpd/sites/www.example.conf
    
    
  6. 向站点的配置文件中添加以下代码:

     <VirtualHost *:80>
             ServerName www.example.com
             DocumentRoot "/var/www/example.com/www/html"
    
             <IfModule proxy_fcgi_module>
                ProxyPassMatch ^/(.*\.php)$ 
                fcgi://127.0.0.1:9000/var/www/example.com/www/html/$1
             </IfModule>
           </VirtualHost> 
    
    
  7. 保存更改并关闭文件。

  8. 创建配置选项中引用的站点文档根目录:

    mkdir -p /var/www/example.com/www/html
    
    
  9. 对于每个额外要托管的站点,重复步骤 4-8,使用主机或域名为每个站点创建唯一的目录路径。

  10. 重新启动 HTTP 服务器以使配置更改生效:

    systemctl restart httpd.service
    
    

它是如何工作的…

配置 Apache 以服务多个域名就是为每个站点创建一个 VirtualHost 定义。本教程将这些定义组织到 /etc/httpd/sites 目录下的各自文件中,并通过 Include 指令在主 httpd.conf 配置文件中引用它们:

Include sites/*.conf

如何组织你的网站由你决定。本教程使用了一种方案,其中每个网站都从基于域名的路径提供,路径以/var/www为根。路径/var/www/example.com/www/html包含www.example.com网站的文件。web.example.com网站的文件将放在/var/www/example.com/web/html中。html目录仅仅是网站的可通过 Web 访问的根目录。通过包含它而不是直接从example.com/www提供文件,我们可以将任何不打算直接访问的支持文件放在根目录之外(例如,包含 PHP 网站配置选项的脚本),同时仍然将它们与网站的其他文件保持组织性。

注意

将公开可访问的目录根目录命名为html是一种约定,但我认为它已经过时,因为不仅仅是 HTML 文件通常被提供。我通常将自己的根目录命名为publicpublic_files,并在配置文件中相应更新它们的引用。

每个虚拟主机的定义都包含在VirtualHost块内。开头提供了服务器监听的接口的 IP 地址,后面是端口号。*表示该定义适用于系统的所有接口,而80是 HTTP 流量的默认端口:

 <VirtualHost *:80> 

在定义中没有明确出现的选项假定具有与主配置中相同的设置,因此至少需要定义ServerNameDocumentRoot选项,以使定义具有唯一性。如果你使用 PHP,你还需要提供ProxyPassMatch选项,以便将请求映射到正确的 PHP 文件:

 <VirtualHost *:80>
      ServerName www.example.com
      DocumentRoot "/var/www/example.com/www/html"
      <IfModule proxy_fcgi_module>
        ProxyPassMatch ^/(.*\.php)$ fcgi://127.0.0.1:9000/var/www/  
        example.com/www/html/$1
      </IfModule>
    </VirtualHost> 

注意

虚拟主机定义加载的顺序是有一定重要性的;第一个加载的定义作为默认设置,将处理任何不匹配任何虚拟主机定义的请求。可以通过为配置文件添加数字前缀,例如10-www.example.conf,来帮助你控制加载顺序。

每个请求都被记录到/var/log/httpd/access_log,任何错误都会被记录到error_log。当然,如果你只提供一个站点,这样做是没问题的。但当提供多个站点时,你可能会发现将日志条目路由到不同站点的不同文件会更有帮助。CustomLog选项指定了一个文件,访问和一般日志消息将写入该文件,并且条目的格式。ErrorLog指定了写入错误消息的文件。这两个选项都可以出现在虚拟主机的配置中:

    <VirtualHost *:80>
      ServerName www.example.com
      DocumentRoot "/var/www/example.com/www/html"
      CustomLog "/var/log/httpd/example.com/www/access_log" "%h %u 
      %t "%r" %>s %b"
      ErrorLog  "/var/log/httpd/example.com/www/error_log"
      <IfModule proxy_fcgi_module>
        ProxyPassMatch ^/(.*\.php)$ fcgi://127.0.0.1:9000/var/www/
        example.com/www/html/$1
      </IfModule>
    </VirtualHost>

CustomLog的第二个参数可以是格式字符串本身或表示格式字符串的别名。格式字符串仅仅定义了日志消息中包含的详细信息。

有许多格式说明符可以使用,这些都已在 Apache HTTPd 服务器的文档中记录。以下是一些常见的格式说明符,你可以在httpd.apache.org/docs/current/mod/mod_log_config.html#formats找到完整的列表:

  • %b:这是返回给客户端的响应大小(以字节为单位)

  • %D:这是处理请求所花费的时间,单位为毫秒(%T表示所花费的时间,单位为秒)

  • %h:这是发起请求的系统的 IP 地址或主机名

  • %H:这是发起请求时使用的协议

  • %m:这是发起请求时使用的方法

  • %q:这是请求的 URI 中的查询字符串部分

  • %r:这是请求的第一行

  • %>s:这是请求的最终状态码(%s表示重定向请求的初始状态)

  • %t:这是接收到请求的时间

  • %u:这是接收到请求时经过身份验证的用户名

  • %v:这是处理请求的服务器名称(ServerName

LogFormat选项指定了一个带别名的格式字符串。例如,httpd.conf文件使用LogFormat定义了名为commoncombined的字符串,这些字符串可以在其他地方使用。定义你自己的虚拟主机日志别名,并在各个配置文件中使用该别名,而不是将复杂的格式字符串分散在各处,是一个不错的主意。在httpd.conf中,只需在commoncombined条目的相同区域添加自定义的LogFormat条目:

LogFormat "%v %h %u %t "%r" %>s %b" vhostcommon

然后,你可以在你的网站配置文件中引用该别名:

CustomLog "/var/www/example.com/www/logs/access_log" vhostcommon

在做出更改后,重新启动 Apache 以使配置生效。

无论日志的目标位置是什么,请确保安全上下文的所有权/权限允许 Apache 能够写入日志文件。如果日志位于/var/log/httpd下,那么创建必要的子目录应该就足够了。服务器将在启动时自动创建日志文件:

mkidr -p /var/log/httpd/example.com/www

然而,如果你希望将日志保存在另一个目录中,例如/var/www/example.com/www/logs,可能会遇到服务器无法写入日志的情况。无论文件系统权限看起来多么正常,SELinux 都会启用。为了解决这个问题,首先使用ls -Z验证安全上下文:

ls -Z /var/www/example.com/www | grep logs
drwxr-xr-x. apache apache unconfined_u:object_r:httpd_sys_content_  
t:s0 logs

在这种情况下,logs目录属于 Apache 运行的apache用户,并且目录的权限应该允许服务器创建日志文件。然而,我们也可以看到该目录继承了标识为 web 内容的标签,标签为httpd_sys_content_t。为了解决问题,我们需要使用chcon命令重新标记该目录以用于日志记录:

chcon -Rv --type=httpd_log_t /var/www/example.com/www/logs

另请参见

有关虚拟主机的更多信息,请参考以下资源:

配置 Apache 以通过 HTTPS 提供页面

HTTP 流量是以明文形式在网络上传输的。在不受信的环境中,恶意用户可以监视并捕获流量,窃听你正在访问的网站和阅读的内容。如果受害者只是阅读每日新闻或观看 YouTube 上的猫咪视频,窃听可能并不有趣,但如果发生未加密的电子商务交易,用户的信用卡号、邮寄地址和其他细节可能会被窃取。为了支持加密流量,Apache 支持 HTTPS。这个配方将教你如何配置 HTTPS 支持,并保护用户的流量免受窥探,无论内容多么无害。

准备工作

本配方要求使用带有有效网络连接的 CentOS 系统。假设系统已配置 IP 地址192.168.56.100,并且按前面的配方运行 Apache。还需要管理员权限,可以通过root账户登录或使用sudo

如何操作...

按照以下步骤通过 HTTPS 提供页面:

  1. 使用openssl生成新的密钥文件和安全证书:

    openssl req -newkey rsa:2048 -nodes \
     -keyout /etc/pki/tls/private/www.example.key \
     -x509 -days 730 -subj "/CN=www.example.com" -text \
     -out /etc/pki/tls/certs/www.example.pem
    
    
  2. 安装服务器的 SSL 模块:

    yum install mod_ssl
    
    
  3. 使用文本编辑器打开/etc/httpd/conf.d/ssl.conf文件:

    vi /etc/httpd/conf.d/ssl.conf
    
    
  4. 查找SSLCertificateFile选项,并更新其值以指向自签名证书文件:

    SSLCertificateFile /etc/pki/tls/certs/www.example.pem
    
    
  5. 查找SSLCertificateKeyFile选项,并将其更新为指向加密密钥:

    SSLCertificateKeyFile /etc/pki/tls/private/www.example.key
    
    
  6. 保存更改并关闭文件。

  7. 重启服务器以使更新的配置生效:

    systemctl restart httpd
    
    
  8. 在防火墙中打开端口443以允许 HTTPS 流量:

    firewall-cmd --zone=public --permanent --add-service=https
    firewall-cmd --reload
    
    

它是如何工作的...

Apache HTTP 服务器带有一个默认的 SSL/TLS 配置,包含在/etc/httpd/conf.d/ssl.conf中的一个通用虚拟主机定义内。大部分配置已经为我们完成,剩下的就是安装 SSL 模块,生成新的密钥和证书,并更新配置以指向我们的文件。

首先,我们生成了一个新的加密密钥和签名证书。如果你已经阅读了第九章中的配置 Postfix 以使用 TLS配方,那么你已经知道密钥用于安全通信,证书确认密钥的所有权:

openssl req -newkey rsa:2048 -nodes \
 -keyout /etc/pki/tls/private/www.example.key \
 -x509 -days 730 -subj "/CN=www.example.com" -text \
 -out /etc/pki/tls/certs/www.example.pem

这个方案生成一个自签名证书,足够个人使用和内网站点使用。req选项用于创建新证书,-newkey生成新的私钥。该密钥是 2048 位的 RSA 密钥,并且本身不加密(-nodes),所以我们不需要每次启动 Web 服务器时提供解密密钥的密码。证书是一个 X.509 证书(-x509),有效期为 3 年(-days 730)。证书的CN字段必须与它将用于的站点的域名匹配。

在配置文件中,SSLCertificateFile选项指定包含证书文件的文件,而密钥则通过SSLCertificateKeyFile来标识:

SSLCertificateFile /etc/pki/tls/certs/www.example.pem
SSLCertificateKeyFile /etc/pki/tls/private/www.example.key

服务器通过查看传入请求中的站点名称来确定使用哪个虚拟主机配置来处理请求。然而,原始的 HTTPS 实现加密了请求的全部内容,包括站点的主机名,这引发了一个“先有鸡还是先有蛋”的问题。服务器需要知道要提供哪个证书,但如果不读取请求,它就无法知道,而客户端希望在发送请求之前就得到与站点域名匹配的证书。在基于名称的虚拟主机上使用 TLS 几乎是不可能的,任何加密站点都需要独立的 IP 地址。

RFC-3546(传输层安全扩展)修改了协议,使主机名可以不加密地发送。这使得服务器可以选择正确的证书来满足客户端的需求,并为使用 TLS 与虚拟主机配合使用打开了大门。主流浏览器大约花了十年时间才支持这一变化,但现在我们几乎可以确认支持了。从 Internet Explorer 7 版本开始,Mozilla Firefox 2 版本开始,Google Chrome 6 版本开始,已经支持所谓的服务器名称指示(SNI)。

为了通过 HTTPS 提供虚拟主机服务,每个站点都需要自己的证书和密钥。然后,将SSLEngineSSLCertificateFileSSLCertificateKeyFile选项添加到主机的配置中。配置中还需要将端口号更改为443,这是 HTTPS 流量的默认端口:

 <VirtualHost *:443>
      ServerName www.example.com
      DocumentRoot "/var/www/example.com/www/html"
      CustomLog "/var/log/httpd/example.com/www/access_log" common
      ErrorLog  "/var/log/httpd/example.com/www/error_log"
      SSLEngine on
      SSLCertificateFile /etc/pki/tls/certs/www.example.pem
      SSLCertificateKeyFile /etc/pki/tls/private/www.example.key
      <IfModule proxy_fcgi_module>
        ProxyPassMatch ^/(.*\.php)$ fcgi://127.0.0.1:9000/var/www/
        example.com/www/html/$1
      </IfModule>
    </VirtualHost> 

尽管自签名证书对于个人使用和私有网络/内网站点来说是足够的,但对于可公开访问的大规模站点,你很可能希望使用一个受信任的证书。然而,根据证书授权机构(CA)和你的请求的具体情况,购买受信任证书可能会很昂贵。如果你只需要一个基本的受信任证书,那么你可能想要了解一下 Let's Encrypt 是否能满足你的需求。Let's Encrypt 是一个项目,提供一个自动化的自助服务模型,可以免费生成受信任的证书。

要使用 Let's Encrypt,您需要安装 EPEL 仓库中提供的 certbot 包(如果您还没有启用该仓库,请参阅第四章中的 注册 EPEL 和 Remi 仓库 章节)。然后运行 certbot certonly 命令并按照提示请求您的证书。完整的操作指南可以在 Let's Encrypt/Certbot 用户指南中找到:letsencrypt.readthedocs.io/en/latest/using.html

注意

使用 Let's Encrypt 时有一些注意事项。首先,证书的有效期只有三个月;您需要每 90 天请求一次新证书。它也不会为 IP 地址生成证书。此外,它有请求频率限制,虽然这对于防止滥用是必要的,但对于使用动态 DNS 服务(如 DynDNS 或 NoIP)使站点可访问的用户来说,会造成一些问题。要使 Let's Encrypt 成为您的可行选择,您需要一个合适的域名和对 web 系统的访问权限以自动化证书更新。如果您正在运行家庭服务器或使用共享主机提供商,那么 Let's Encrypt 可能不适合您。

另见

请参考以下资源,了解如何使用 HTTPS:

启用覆盖并执行 URL 重写

本教程教您如何使用 mod_rewrite。我之前提到过 mod_rewrite;它是 Apache 的一个模块,允许我们修改 URL 并将其解析为不同的资源。人们有很多理由需要这样做。例如,假设您移动了一些文件,且它们的 URL 已发生变化,但您不希望其他地方的链接指向旧位置导致失效。您可以编写一个重写规则,匹配旧的位置并实时更新 URL,从而成功响应请求。另一个例子是 SEO;您可能有一些长且不友好的标准 URL,但希望用更短、更易记的 URL 替代。友好的 URL 可以在后台映射到标准 URL。

准备工作

本食谱要求使用有网络连接的 CentOS 系统。假设系统配置了 IP 地址192.168.56.100并且正在运行先前食谱中描述的 Apache。还需要管理员权限,可以通过使用root账户登录或使用sudo来获得。

如何操作...

按照以下步骤进行 URL 重写:

  1. 使用文本编辑器打开/etc/httpd/conf/httpd.conf文件:

    vi /etc/httpd/conf/httpd.conf
    
    
  2. 定位到定义文档根目录各种选项的Directory部分。找到其AllowOverrides选项,并将值从None更新为All

     <Directory "/var/www/html">
           ...
               AllowOverrides All
           ...
           </Directory> 
    
    
  3. 保存更改并关闭文件。

  4. 重启 Apache 以使配置更新生效:

    systemctl restart httpd
    
    
  5. 验证mod_rewrite模块(标识为rewrite_module)是否可用:

    httpd -M | grep rewrite
    
    
  6. 在你的文档根目录下创建一个名为.htaccess的文件:

     vi /var/www/html/.htaccess 
    
    
  7. .htaccess文件中添加RewriteEngine以启用 URL 重写引擎:

    RewriteEngine on
    
    
  8. 添加描述所需重定向的Rewrite规则。例如,以下规则将所有没有文件扩展名的请求重定向到给定名称的 PHP 文件:

    RewriteRule ^/?([A-Z]+)$ $1.php [NC,L]
    
    
  9. 保存并关闭文件。

它是如何工作的...

.htaccess文件是位于站点目录结构中的补充配置文件。当配置好后,Apache 会在满足请求时搜索.htaccess文件并应用其中的选项设置。当然,每次请求时都要搜索并加载配置值会对性能产生轻微影响,但这种权衡增加了灵活性。例如,服务器不需要重启即可使.htaccess文件中的配置更改生效。在共享主机环境中,精明的用户可以在不要求服务器管理员协助或访问/etc/httpd中的主配置文件(这些文件可能包含敏感配置值)的情况下,为自己的网站调整服务器行为。即使是依赖特定服务器功能的 Web 应用程序,也可能包含一个.htaccess文件,内含必要的配置以简化其部署。

默认情况下,Apache 不允许使用.htaccess文件来覆盖服务器的配置。要启用它,我们需要在适当的上下文中更新AllowOverrides选项,然后重启服务器。本食谱在适用于 Web 根目录的部分进行了更改:

 <Directory "/var/www/html">
    ...
        AllowOverrides All
    ...
    </Directory> 

注意

如果你使用虚拟主机,确保将AllowOverrides选项放入你站点的配置文件中。

None的值会导致服务器忽略任何.htaccess文件。除此之外,并非所有选项都允许出现在.htaccess文件中。文件中最常见的选项涉及重写请求或目录特定访问。可以出现的选项按不同类别分组,我们可以指定允许覆盖的选项类别。可能的组名如下:

  • AuthConfig:此选项允许覆盖授权选项(AuthUserFileAuthDBMUserFile 等等)。

  • FileInfo:此选项允许覆盖与请求相关的选项(ErrorDocumentRedirectRewriteRule 等等)。

  • Indexes:这些选项允许覆盖与索引相关的选项(DirectoryIndexIndexOptions 等等)。

  • Limit:此选项允许覆盖访问选项(AllowDenyOrder)。

  • All:此选项允许覆盖所有选项组。

由于 AllowOverrides 应用于目录级别,因此可以允许或拒绝在不同目录中使用不同的覆盖。例如,可以在整个网站上禁用覆盖,但可以在 private 目录中允许覆盖授权选项,从而指定特定的授权数据库:

 <Directory "/var/www/html">
        AllowOverrides None
    </Directory>
    <Directory "/var/www/html/priv">
        AllowOverrides AuthConfig
    </Directory> 

注意

即使你对 Apache 有完全控制权,并且出于性能原因希望将所有内容放置在主 httpd.conf 文件中,允许通过 FileInfo 覆盖重写选项也能让你在不重启服务器的情况下设计和排查规则。然后,当你确定规则正确无误时,可以将其迁移到主配置文件中,并关闭覆盖选项。

rewrite_module 将自身注入到服务器的请求处理工作流中,并根据我们在规则集中的提供内容,实时更改请求的 URL。尽管该模块默认已安装,但我们仍需显式启用 URL 重写,使用 RewriteEngine on。除此之外,两个最重要的重写选项是 RewriteRuleRewriteCond

RewriteRule 选项指定一个正则表达式,用于与 URL 进行比较。如果匹配,则进行给定的替代操作。可以在替代操作中使用位置变量,如 "$1",来引用捕获的模式匹配。在我们的例子中,规则匹配路径(如 /about/contactus),并将其重写为指向同名的 PHP 脚本(如 about.phpcontact.php),从而隐藏我们正在使用 PHP 的事实。

 RewriteRule ^/?([A-Z]+)$ $1.php [NC,L] 

我们还可以提供一些标志来影响请求的返回方式。例如,NC 标志会执行不区分大小写的模式匹配。L 标志会停止引擎并返回 URL,而不再处理其他规则。常见的还有 R,它强制进行重定向(通常会给出 HTTP 状态码,例如 R=301),以及 QSA,它将原始 URL 的查询字符串附加到新 URL 上。

RewriteCond 选项提供了一个条件,必须满足该条件才能评估 RewriteRule。该条件是正则表达式匹配、变量和测试操作符的结合。可以使用一些特殊变量来引用 URL 的某些部分,例如主机名(%{HTTP_HOST})、请求的文件(%{REQUEST_FILENAME})以及查询字符串(%{QUERY_STRING}),或者有关环境/请求的详细信息,例如 Cookie(%{HTTP_COOKIE})和用户代理字符串(%{HTTP_USER_AGENT})。-d 操作符用于测试路径是否是目录,-f 用于测试路径是否是文件,! 用于取反匹配。RewriteCond 还可以接受一些标志,例如 NC 标志,它让比较不区分大小写,以及 OR 标志,用于将多个选项通过 关系连接(多个选项默认被视为 )。

一个非常常见的重写示例,使用了 RewriteCondRewriteRule,当请求不匹配现有的文件或目录时,会将用户引导到一个主 index.php 文件。这在许多将所有请求通过中央控制点路由的 Web 应用程序中使用得非常多:

 RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*) index.php [L,QSA] 

第一个 RewriteCond 选项检查请求是否是现有文件,第二个检查请求是否是现有目录。如果请求既不是文件也不是目录,那么 RewriteRule 选项会将请求映射到 index.php。任何可能存在的查询字符串都会被包括在内,并且它被标记为最后的操作,因此不会再进行进一步的重写。

许多人开玩笑说 URL 重写是黑魔法。的确,mod_rewrite 功能强大,能够将请求转换得如此神奇,当你无法找到正确的写法时,它会让人感到沮丧。在这种情况下,你可能需要开启日志记录,以便深入了解引擎如何看待请求。要启用日志记录,可以使用 RewriteLog 选项指定日志文件,并使用 RewriteLogLevel 来指定日志的详细程度。通常,RewriteLogLevel 设置为 5 足够了。它们可以被添加到 .htaccess 文件中,待确认规则正确后再删除:

 RewriteLog /var/log/httpd/rewrite_log
    RewriteLogLevel 5 

参见

请参阅以下资源,以获取有关 URL 重写的更多信息:

安装 NGINX 作为负载均衡器

高流量网站可以分布到不同的服务器上,要么更好地分配工作负载,要么实现冗余。集群中的每台服务器都有自己的一份网站或 Web 应用文件,并能够满足用户的请求。诀窍在于按顺序将用户的请求路由到这些服务器之一。实现这一点的方法有很多种,但常见的一种是设置负载均衡器或反向代理服务器。

NGINX 在登场时间上略晚于 Apache;它大约十多年前为了处理高负载连接而特别编写,可以作为 web 服务器、代理、缓存和负载均衡器。在本例中,我们将看到如何将 NGINX 设置为负载均衡器,在客户端和一组 Apache 服务器之间代理请求。

准备工作

本例需要一个具有工作网络连接的 CentOS 系统。假设你已经配置了其他系统,使用 Apache 提供网站,如前面章节所述;我们将使用 IP 地址192.168.56.20192.168.56.30来引用这些系统。NGINX 的包托管在 EPEL 仓库中;如果仓库尚未注册,请参考第四章中的注册 EPEL 和 Remi 仓库一节,软件安装管理。此外,还需要管理员权限,可以通过root账户登录或使用sudo

如何操作...

按照以下步骤使用 NGINX 设置反向代理:

  1. 从 EPEL 仓库安装nginx包:

    yum install nginx
    
    
  2. 使用文本编辑器打开 NGINX 服务器的配置文件:

    vi /etc/nginx/nginx.conf
    
    
  3. http块中,添加一个新的upstream块以标识集群中的服务器:

     upstream cluster {
             server 192.168.56.20;
             server 192.168.56.30;
           } 
    
    
  4. 找到location块并添加一个引用upstream块的proxy_pass选项:

     location / {
               proxy_pass http://cluster;
           } 
    
    
  5. 保存配置文件的更改并关闭文件。

  6. 启动服务器并使其在系统重启时自动启动:

    systemctl start nginx.service
    systemctl enable nginx.service
    
    
  7. 在系统的防火墙中打开端口80,允许 HTTP 请求通过:

    firewall-cmd --zone=public --permanent --add-service=http
    firewall-cmd --reload
    
    

工作原理...

一如既往,我们首先安装了程序包,这次是nginx。该包可以在 EPEL 仓库中找到。安装后,我们更新了它的配置,标识了集群中的服务器,并代理了请求。首先,我们添加了一个upstream块:

 upstream cluster {
      server 192.168.56.20;
      server 192.168.56.30;
    } 

cluster仅仅是我们为这一组服务器指定的名称,方便我们通过名称引用该组。如果你有多个集群在进行负载均衡,可以有多个upstream块。每个server条目中都包含了运行网站的系统的 IP 地址或主机名。

接着,我们找到了主location块,并添加了一个proxy_pass参数。proxy_pass将把传入的请求转发到集群中的一台系统,并返回响应以满足请求:

 location / {
        proxy_pass http://cluster;
    } 

NGINX 和托管 Web 服务器之间的通信是通过http协议进行的,因为在proxy_pass的值中指定了该协议。这是可以的,因为集群系统将会在负载均衡器后面的受信任网络中运行。如果你的网站需要通过 HTTPS 提供服务,那么需要 NGINX 处理 TLS 协商,因为它是客户端所见的公有服务器点;客户端对负载均衡器后面的内容一无所知。

要配置 NGINX 处理 HTTPS 请求,需在server块内更新listen选项以监听端口 443。然后添加包含ssl_certificatessl_certificate_key选项的条目,分别标识证书和密钥:

 server {
        # listen 80 default_server;
        # listen [::]:80 default_server;
        listen 443 ssl default_server;
        listen [::]:443 ssl default_server;

        ssl_certificate /etc/pki/tls/certs/www.example.pem;
        ssl_certificate_key /etc/pki/tls/private/www.example.key;
    ...
    } 

一旦完成更改并保存配置文件,请在防火墙中打开端口443并重启 NGINX:

firewall-cmd --zone=public --permanent --add-service=https
firewall-cmd --reload
systemctctl restart nginx.service

循环轮询是负载均衡的默认方法。这意味着第一个请求会被代理到集群中的第一台服务器,然后是第二台服务器,依此类推。当 NGINX 到达列表末尾时,它会从列表顶部重新开始,将下一个请求代理到第一台服务器。我们还可以使用其他策略,例如加权均衡。

要执行加权均衡,我们为任意服务器分配一个权重,它将在每次迭代中处理该数量的请求。在这里,第一台服务器将处理五个请求,之后 NGINX 会将请求代理到第二台服务器:

 upstream cluster {
      server 192.168.56.20 weight=5;
      server 192.168.56.30;
    } 

在使用负载均衡时,请记住,没有任何一台 Web 服务器能保证接收到用户发送的下一个请求。如果你在负载均衡一个使用会话的 Web 应用时,这可能会成为问题。你可能需要考虑将会话数据存储在一个每台 Web 服务器都能访问的中央系统上,可能是使用像 Redis 或 Memcache 这样的数据库。

注意

我建议避免使用任何依赖于会话持久性的负载均衡策略。可以参考www.chaosincomputing.com/2012/05/sticky-sessions-are-evil上的帖子,它提供了关于这些问题的良好概述。

另请参见

请参阅以下资源,获取更多关于 NGINX 和负载均衡的信息:

第十一章。防范威胁

本章包含以下配方:

  • 发送消息到 Syslog

  • 使用 logrotate 旋转日志文件

  • 使用 Tripwire 检测修改文件

  • 使用 ClamAV 来抵御病毒

  • 使用 chkrootkit 检测 rootkit

  • 使用 Bacula 进行网络备份

介绍

从记录系统活动到嗅探 rootkit,本章提供了一些配方,帮助保护您在系统及其数据上投资免受各种威胁。首先,您将学习如何使用 Syslog 设置一个集中日志服务器,然后学习如何旋转日志文件以确保它们不会失控。然后,我们将看看如何使用 Tripwire 检测系统入侵,方法是检查重要系统文件是否有变化。本章还包括了一些设置 ClamAV 和 chkrootkit 的配方,以保持您的系统免受病毒、特洛伊木马、rootkit 和其他恶意软件的影响。最后,我们将介绍如何使用 Bacula 设置一个集中式备份服务器,以保护您的数据免受意外删除和硬件故障等日常威胁。

发送消息到 Syslog

Syslog 是一个进程,它监听来自其他应用程序的消息并将它们写入其日志文件,提供处理所有日志记录活动的通用服务。消息也可以发送到远程系统上运行的 Syslog 的运行实例,作为整个网络的集中日志服务器。除了便利性外,集中式日志记录出于安全原因也很有用,因为当日志记录到第二个系统时,攻击者更难掩盖其行踪。在本配方中,您将学习如何配置本地和远程 Syslog 实例来运行您自己的日志服务器。

准备工作

此配方需要两台已连接到网络的 CentOS 系统。配方将将第一台系统称为本地系统,并假定它配置有 IP 地址192.168.56.100和主机名benito。第二个系统,称为远程系统,假定具有地址192.168.56.35和主机名logs。这些系统应能够通过主机名相互访问;因此,您需要在系统的/etc/hosts文件中添加适当的 DNS 记录或覆盖条目。还需要管理权限,可以通过root帐户登录或通过sudo使用。

如何操作...

要将本地系统的日志消息转发到远程系统,请在本地系统上执行以下步骤:

  1. 使用文本编辑器打开 Syslog 的配置文件:

    vi /etc/rsyslog.conf
    
    
  2. 在文件末尾添加以下规则:

    *.*  @logs.example.com
    
    
  3. 保存更改并关闭配置文件。

  4. 重新启动 Syslog 以使更新后的配置生效:

    systemctl restart rsyslog
    
    

然后,在远程系统上执行以下步骤以接受传入的日志消息:

  1. 使用文本编辑器打开 Syslog 的配置文件:

    vi /etc/rsyslog.conf
    
    
  2. 定位负责加载imudp模块的$ModLoad指令,并通过删除前导的#字符取消注释它。紧接着取消注释紧随其后的$UDPServerRun指令:

    $ModLoad imudp
    $UDPServerRun 514
    
    
  3. 保存更改并关闭配置文件。

  4. 重启 Syslog 使更新的配置生效:

    systemctl restart rsyslog
    
    
  5. 打开防火墙以允许 UDP 流量通过514端口:

    firewall-cmd --zone=public --permanent --add-port=514/udp
    firewall-cmd --reload
    
    

它是如何工作的…

Syslog 通过多个日志设施接收消息,每条消息都有一个指定的优先级/严重性。消息可以根据它们的设施和优先级进行过滤,以便传递所需的消息,同时丢弃其余的消息。设施和优先级的列表已在 RFC-5424(Syslog 协议)中列出,而 Rsyslog(CentOS 中使用的 Syslog 版本)实现了其中的大部分。

设施提供了一种广泛的分类方法,旨在通过生成消息的服务类型来组织消息。你可以把它们想象成频道,其中记录用户登录失败的消息可以通过auth频道发送,而记录服务重启的消息可以通过daemon频道发送。Rsyslog 的设施如下:

  • auth:与安全和授权相关的消息

  • cron:来自 cron 的消息

  • daemon:来自系统守护进程的消息

  • kern:来自 Linux 内核的消息

  • lpr:来自系统打印服务的消息

  • mail:来自系统邮件服务的消息

  • news:来自 NTTP 服务的消息

  • syslog:由 Syslog 本身生成的消息

  • user:用户级消息

  • uucp:来自 UUCP 服务的消息

  • local0-local7:用于处理其他设施无法处理的用户级消息

优先级表示消息的严重性,例如,生成错误消息的情况比生成信息或调试消息的情况更严重。Rsyslog 的优先级如下:

  • emerg, panic:系统不可用

  • alert:需要立即采取行动

  • crit:发生了一个严重事件

  • err, error:发生错误

  • warn, warning:遇到重要情况

  • notice:通知消息

  • info:信息性消息

  • debug:调试消息

Syslog 配置文件中的规则指定日志的写入位置,它们由两部分组成——第一部分是一个模式,用来识别一个设施和优先级。它由设施和优先级名称通过点号分隔,例如auth.warnlocal2.debug。多个设施可以通过逗号分隔,例如auth,daemon,cron.warn。此外,*可以作为通配符,用来匹配所有设施或优先级。auth.*表示来自auth设施的任何优先级的消息,*.warn表示来自任何设施的warn优先级或更高的消息,*.*表示所有消息,无论设施或优先级。

与模式匹配的消息将由规则的第二部分处理,即动作。通常,动作是将消息写入文件的位置,但它也可以丢弃消息(使用~作为位置)、将消息发送到一个命名管道,由外部进程处理(将位置前缀加上|),或者将消息转发到另一个系统(提供一个以@为前缀的主机名作为位置)。

由于已安装 Rsyslog,服务的配置文件是/etc/rsyslogd.conf。在本地系统上,我们添加了以下规则:

*.*  @logs.example.com

该规则匹配所有消息并将其发送到服务器logs.example.com。一个@表示消息将通过 UDP 发送,而两个@则表示消息将通过 TCP 发送:

*.*  @@archive.example.com

然后,我们在远程系统上取消注释了以下配置:

$ModLoad imudp
$UDPServerRun 514

$ModLoad加载一个 Syslog 模块,在本例中是imudp,它处理通过 UDP 接收的消息。$UDPServerRun指令指定该模块监听消息的端口。传统上,Syslog 消息发送到514端口。

注意

Syslog 可以配置为使用 TCP 传输消息,但除非有特定的需要,我建议你使用 UDP。UDP 可靠性较差,但 TCP 会带来更多的开销,并可能在大量日志记录事件期间导致更严重的网络拥塞。

它是如何工作的...

配置文件包含规则,将消息根据其设施和优先级引导到不同的文件。

许多应用程序能够将消息发送到 Syslog,即使它们默认写入自己的日志文件。例如,MySQL 在命令行中提供合适的参数时,会接受--syslog参数。其他程序,如 BIND 和 Apache,则需要在其配置文件中进行更改。即使是你编写的 Shell 脚本,也可以通过以下方式使用logger命令将消息发送到 Syslog:

logger -n logs.example.com -p user.notice "Test notice"

logger接受多个参数,然后是日志消息。-n指定消息发送的服务器(如果没有提供,消息将发送到本地系统的 Syslog 实例),-p指定消息的设施和优先级。

另见

请参考以下资源,了解更多关于 Syslog 的操作信息:

使用 logrotate 轮换日志文件

日志文件非常重要,因为它们能更好地了解系统上发生的事情。日志中的调试和错误消息可以用来追踪问题的根源并迅速解决。认证消息记录了谁在何时访问了系统,反复的认证失败可能是攻击者试图获得未授权访问的迹象。然而,日志的实用性通常会随着时间的推移而减少,而生成大量日志条目的活跃应用程序如果不加以管理,可能会轻易地消耗系统的所有存储资源。本食谱将向您展示如何旋转日志文件,以防止日志文件过大失控,并避免过时的日志浪费空间。

准备工作

本食谱要求使用具有有效网络连接的 CentOS 系统。还需要具有管理员权限,可以通过以 root 账户登录或使用 sudo 获得。

如何操作...

按照以下步骤使用 logrotate 配置日志文件旋转:

  1. 创建 /etc/logrotate.d/example 文件:

    vi /etc/logrotate.d/example
    
    
  2. 将以下内容写入文件:

    /var/log/example.log {
     monthly
     rotate 4
     missingok
     notifempty
     create 0600 root root
     postrotate
     kill -HUP $(cat /var/run/example.pid)
     endscript
    }
    
    
  3. 保存您的更新并关闭文件。

它是如何工作的...

logrotate 通过将日志文件重命名为顺序备份并创建一个新的文件供应用程序写入来旋转日志文件。在旋转 example.log 时,它将 example.log 重命名为 example.log.1。如果 example.log.1 已存在,它首先将该文件重命名为 example.log.2(以此类推,其他按序号排列的文件也是如此)。

为了这个示例,本食谱创建了一个新的配置来旋转 /var/log/example.log 文件。logrotate 的主配置文件是 /etc/logrotate.conf,而附加文件可以放置在 /etc/logrotate.d 目录中。您需要检查 logrotate.d 目录,查看您希望管理的应用程序日志的旋转是否已经配置好(许多软件包会在那里放置一个配置文件作为一种方便)。如果软件包维护者的配置不符合您的需求,您可以更新该配置。主文件中的指令设置全局行为,而附加文件中的指令会根据每个配置文件的情况进行覆盖。

配置提供了目标日志文件的名称,后跟一组大括号指令,用于指定 logrotate 如何管理该文件。* 可以作为通配符匹配多个文件,这在应用程序写入多个日志文件时很有用。例如,Apache HTTP 服务器将消息写入 /var/log/http 目录下的 access_logerror_log 文件。所以它的配置将如下所示:

/var/log/http/*log {
...
}

monthly 指令指示 logrotate 每月旋转一次文件。其他选项包括 daily(每天)、weekly(每周)和 yearly(每年)。或者,您可以指示 logrotate 根据文件大小来管理文件——size 指令指定一个大小,logrotate 将旋转那些大于该大小的文件。

size 30k

如果给定的值没有单位,默认单位为字节。logrotate 还支持 k 表示千字节,M 表示兆字节,G 表示吉字节。

rotate 指令指定轮换中保留多少个日志文件。在我们的例子中,最多允许保留四个文件;因此,example.log.3 会覆盖 example.log.4,并且不会有 example.log.5missingok 指令告知 logrotate 如果某个日志文件不存在也可以继续运行(其默认行为是报错)。同时,notifempty 指令指示 logrotate 如果文件为空,则跳过轮换。create 指令告知 logrotate 在重命名原始日志文件后创建一个新文件,并为新文件提供模式、用户和组:

rotate 4
missingok
notifempty
create 0600 root root

工作原理...

轮换的日志文件按顺序编号

注意

原始的 example.log.4 文件的内容不一定会丢失。一个选项是使用 mail 指令,在覆盖文件之前指示 logrotate 将其内容通过电子邮件发送给你。

**mail tboronczyk@example.com**

个人建议,只有在文件相对较小的情况下使用 mail,因为发送大型文件可能会对邮件服务器造成不必要的负担。此外,包含敏感信息的日志文件不应该通过电子邮件传输。对于敏感日志和较大的文件,我建议使用 prerotate 来调用 scp 或其他工具,在轮换之前将文件复制到其他地方。

prerotate
 scp /var/log/example.log.4  storage@archive.example.com:example.log-$ (date +%F)
endscript

我们可以指定在日志文件轮换前后执行的外部操作。prerotate 指令提供一组在轮换开始前执行的 shell 命令,postrotate 指令提供在轮换后执行的命令。两个指令都使用 endscript 来标记命令集的结束,如前面的提示和配方配置中所示。配置中调用 kill 发送挂起信号(HUP)到示例进程,这将重新加载该守护进程。如果日志文件被移动并重新创建,一些程序可能会出现混乱,重新加载后程序会重新打开日志文件的连接,从而继续记录日志:

postrotate
 kill -HUP $(cat /var/run/example.pid)
endscript

logrotate 是通过 cron 每日运行的,因此一旦你创建/调整了轮换配置,就可以完成设置。下次 logrotate 运行时,它会重新读取所有配置文件并获取更新。

另见

参见以下资源,获取更多关于使用 logrotate 的信息:

使用 Tripwire 检测修改过的文件

本教程向你展示了如何设置 Tripwire,这是一个用于检测系统中文件更改的审计工具。Tripwire 通常被作为入侵检测系统来使用,因为重要配置文件的意外修改通常是入侵或恶意活动的标志。能够监控这些变化,可以帮助你及时发现并制止可能发生的恶意活动。

准备工作

本教程要求使用有网络连接的 CentOS 系统。tripwire包位于 EPEL 仓库中,因此必须按第四章《软件安装管理》中讨论的内容注册该仓库。还需要管理员权限,或者登录root账户,或者使用sudo命令。

如何操作...

按照这些步骤使用 Tripwire 监控系统入侵:

  1. 从 EPEL 仓库安装tripwire包:

    yum install tripwire
    
    
  2. 运行tripwire-setup-keyfiles来生成 Tripwire 的密钥文件、配置文件和策略文件:

    tripwire-setup-keyfiles
    
    

    系统会提示你输入站点密钥文件和本地密钥文件的密码,并再次输入站点密码来签名生成的配置文件和策略文件。

  3. 初始化 Tripwire 的数据库。系统会提示你输入本地密码短语:

    tripwire --init 2>output.txt
    
    
  4. 检查输出中的警告,以确定在策略中定义但在系统上不存在的文件:

    cat output.txt
    
    
  5. 注释掉/etc/tripwire/twpol.txt中引用output.txt中不存在的文件的条目。如果output.txt中的所有警告都由于文件不存在而引起,那么你可以通过以下方式自动化此步骤:

    for f in $(grep "Filename:" output.txt | cut -f2 -d:); do
     sed -i "s|\($f\) |#\\1|g" /etc/tripwire/twpol.txt
    done
    
    
  6. 重新生成已签名的策略文件。系统会提示你输入站点密钥文件的密码:

    twadmin --create-polfile -S /etc/tripwire/site.key  
           /etc/tripwire/twpol.txt
    
    
  7. 删除原始数据库并初始化一个新的数据库。这次,过程应该在没有任何警告的情况下完成:

    rm /var/lib/tripwire/benito.twd
    tripwire --init
    
    

它是如何工作的...

Tripwire 审计你的系统以检测哪些文件发生了变化。其背后的理念是,如果攻击者获得了你的系统访问权限,他们不可避免地会创建或修改关键文件来确保其存在。然而,攻击者很容易修改 Tripwire 的策略文件,制造出没有变化的假象;因此,配置文件、策略文件和关键文件都需要用密钥文件进行签名。当我们运行以下命令时,配置文件、策略文件和密钥文件都会生成:

tripwire-setup-keyfiles 

由于默认策略试图尽可能全面地涵盖大多数用户,可能会包含与我们的 CentOS 系统不相关的条目。如果我们使用未经修改的默认策略运行,Tripwire 会报告缺失的文件,筛选出误报的文件会使我们更难辨别是否有人删除了真正需要关注的文件。与其手动审查策略文件,特别是如果你不是专家并不熟悉某些文件,最好的做法是在已知干净的系统上进行初步扫描,然后让 Tripwire 报告不存在的文件。这将帮助节省时间,并帮助我们将策略调整到我们的系统上。

初始化 Tripwire 数据库使用命令 tripwire --init。程序将扫描系统,比较文件系统与策略文件中的信息,并收集现有文件的统计数据。这些统计数据将存储在数据库中,作为下次运行 Tripwire 时与文件进行比较的基准指标。该过程将包含缺失文件的错误输出重定向到单独的文本文件,原因有二:列表可能很长,有时翻阅文件比滚动终端会话更方便;另外,我们可以基于该输出脚本化地定制策略:

tripwire --init 2>output.txt

sed 是传统的搜索和替换工具,而 grep 非常适合查找和提取感兴趣的行,因此我们可以使用这两个工具来更新策略文件 /etc/tripwire/twpol.txt。首先,我们需要知道 output.txt 中的消息格式如下:

cat output.txt

它是如何工作的...

不存在的文件在初始化 Tripwire 数据库时会产生警告

注意

如果输出文件中的所有警告都与不存在的文件有关,那么就可以安全地自动更新策略。这就是我们在继续之前仔细检查内容的原因。

我们使用 grep 来筛选包含 Filename: 的行,然后使用 cut 按冒号分割该行并提取第二部分——不存在的文件名。for 循环捕获每个文件名,并将其赋值给变量 f,然后我们可以在 sed 的模式中引用它。该模式执行全局查找和替换,使用捕获括号和数字反向引用将文件名替换为以 # 开头:

for f in $(grep "Filename:" output.txt | cut -f2 -d:); do
 sed -i "s|\($f\) |#\\1|g" /etc/tripwire/twpol.txt;
done

注意

确保文件名后面有一个空格非常重要,这样可以确保我们只匹配整个文件名。例如,我们想避免 /etc/rc.d 也会匹配到 /etc/rc.d/init,因为它们有共同的前缀。

策略的未签名纯文本副本存储在 /etc/tripwire/twpol.txt。在我们进行更改后,我们希望创建一个签名的策略文件,Tripwire 将出于前面提到的安全原因使用它。这可以通过 twadmin--create-policy 参数完成。-S 参数为命令提供签名密钥的路径,然后我们提供策略的纯文本副本作为输入:

twadmin --create-polfile -S /etc/tripwire/site.key
/etc/tripwire/twpol.txt

twadmin 会签署策略并将结果写入 /etc/tripwire/tw.pol。在策略文件修改后,我们可以重新初始化数据库。实际上,每次更新策略文件时,你都应该重新生成数据库,该数据库存储在 /var/lib/tripwire 中,并以系统的主机名命名:

rm /var/lib/tripwire/benito.twd
tripwire --init

要扫描系统中的违规行为,可以运行带有 --check 选项的 Tripwire:

tripwire --check

工作原理...

Tripwire 在执行扫描后会报告其发现。

当然,为了有效,扫描必须至少每天执行一次。为此,tripwire 包在 /etc/cron.daily 中安装了一个 cron 任务,该任务会运行 Tripwire 扫描。根据 cron 的配置,扫描的输出很可能会通过 cron 发送到系统的 root 用户的邮箱(并很可能最终进入 /var/spool/mail/root)。你可以编辑 /etc/cron.daily/tripwire-check,让输出发送到你的邮箱:

test -f /etc/tripwire/tw.cfg && /usr/sbin/tripwire --check |  
/bin/mailx -s "Tripwire Report" tboronczyk@example.com 2>&1

如果你愿意,你也可以配置 Tripwire 自行发送电子邮件。首先,你需要确保 Tripwire 能够向你的地址发送邮件。执行以下命令发送测试邮件,然后检查确保它到达了你的收件箱:

tripwire --test --email tboronczyk@example.com

注释

在运行手动扫描时,你可以使用 --email-report 选项,让 Tripwire 将结果发送到你的电子邮件。

**tripwire --check --email-report**

默认情况下,Tripwire 会尝试通过 sendmail(或 Postfix 的 sendmail 接口)发送电子邮件。如果你需要通过 SMTP 服务器发送邮件,可以查看 man 4 twconfig 中的 电子邮件通知变量 部分。

在 Tripwire 配置中,指定目标电子邮件地址会稍微复杂一些。Tripwire 策略文件中定义的测试被分组到规则集中,这样可以将文件按逻辑方式进行分组。例如,有一个规则集测试 Tripwire 可执行文件的完整性,这与测试系统管理程序的规则集是分开的。每个规则集可以有一个定义的电子邮件地址来发送通知,这对于灵活性非常好,允许一个管理员接收关于某一组文件的修改通知,另一个管理员接收关于其他文件的通知:

(
 rulename = "Tripwire Binaries",
 emailto = tboronczyk@example.com,
 severity = $(SIG_HI)
)

如果你是唯一的管理员,反复指定相同的地址可能会很麻烦。一个更好的方法是将电子邮件地址定义为全局变量,然后通过巧妙地使用 sed 来简化操作。

首先,编辑twpol.txt文件,在全局变量定义部分添加你的电子邮件地址的变量赋值:

@@section GLOBAL
TWROOT=/usr/sbin;
TWBIN=/usr/sbin;
TWPOL=/"/etc/tripwire";
TWD="/var/lib/tripwire";
TWSKEY="/etc/tripwire";
TWLKEY="/etc/tripwire";
TWREPORT="/var/lib/tripwire/report";
HOSTNAME=benito;
EMAILADDR="tboronczyk@example.com";

保存更改并关闭文件。然后,考虑到每个规则集中都包含severity指令,我们可以使用替换模式来插入mailto指令:

sed -i "s|\( \+\)\(severity = \)|\\1mailto =  \$(EMAILADDR),\n\\1\\2|g" 
    /etc/tripwire/twpol.txt

最终结果应该在每个规则集的定义中包含emailto指令:

(
 rulename = "Tripwire Binaries",
 emailto = $(EMAILADDR),
 severity = $(SIG_HI)
)

在检查结果后,重新签署策略文件并重新初始化数据库。

另请参见

请参阅以下资源,了解更多关于使用 Tripwire 的信息:

使用 ClamAV 抵御病毒

病毒、木马以及其他形式的恶意软件威胁是真实存在的。它们在数量和复杂性上都呈指数级增长,防病毒软件不得不采用复杂的检测方法。虽然无法保证你的系统不会成为这些恶意代码的受害者,但在使用互联网和共享文件时保持警惕,实施常识性的安全策略,并使用最新的防病毒程序,能够在很大程度上保护你。这个教程将向你展示如何安装 ClamAV 这一专业级开源防病毒程序,保持其威胁数据库的最新状态,并扫描你的系统。

准备工作

这个教程需要一个具有有效网络连接的 CentOS 系统。ClamAV 软件包可以在 EPEL 仓库中找到,因此必须注册该仓库,如第四章《软件安装管理》中所讨论的那样。还需要具有管理员权限,可以通过登录root账户或使用sudo来获取。

如何做到这一点...

按照以下步骤安装 ClamAV 并扫描病毒和木马:

  1. 从 EPEL 仓库安装clamavclamav-update软件包:

    yum install clamav clamav-update
    
    
  2. 使用文本编辑器打开freshclam配置文件:

    vi /etc/freshclam.conf
    
    
  3. 找到Example行并在行首添加#以将其注释掉:

    # Comment or remove the line below
    #Example
    
    
  4. 保存更新并关闭文件。

  5. 运行freshclam以更新扫描器的威胁数据库:

    freshclam
    
    
  6. 创建一个systemd服务文件来管理freshclam守护进程,以实现自动更新:

    vi /lib/systemd/system/freshclam.service
    
    
  7. 使用以下内容作为文件的内容:

    [Unit]
    Description = freshclam daemon to update clamav
    After = network.target
    [Service]
    Type = forking
    ExecStart = /usr/bin/freshclam -d
    Restart = on-failure
    [Install]
    WantedBy=multi-user.target
    
    
  8. 强制systemd重新加载其服务:

    systemctl daemon-reload
    
    
  9. 启动新的freshclam服务并启用它在系统重启时自动启动:

    systemctl start freshclam.service
    systemctl enable freshclam.service
    
    
  10. 使用clamscan扫描home目录中的文件以检查威胁:

    clamscan -ir /home/tboronczyk
    
    

它是如何工作的...

首先,我们安装了clamavclamav-update软件包。clamav软件包包含病毒扫描器,而clamav-update包含freshclam程序,该程序用于更新 ClamAV 的病毒定义,以保持其最新:

yum install clamav clamav-update

freshclam/etc/freshclam.conf读取其配置文件。该文件包含一行包含单词Example,以防止用户盲目使用默认设置,我们必须在使用freshclam之前将其删除或注释掉。默认设置适合我们的目的,这更多的是一种烦恼,但它确实迫使我们查看文件并查看哪些行为可以调整。每个指令都有注释,说明其默认行为是什么。

然后,我们运行了freshclam以更新扫描器的数据库:

freshclam

注意

该过程将其进度输出到终端,您可能会看到几个错误消息。例如,它可能会报告无法下载某个每日文件。不要惊慌;freshclam会尝试多个镜像。只要它报告main.cvddaily.cvdbytecode.cvd在完成时是最新的,您就知道已经拥有最新的定义。

我们可以随时运行freshclam以确保定义数据库是最新的,但每次手动运行它会不太方便。当以-d参数启动时,freshclam将在守护进程模式下运行,并定期检查更新(默认每两小时检查一次)。为了保持整洁,我们创建了一个服务文件来运行freshclam并将其注册到systemd

[Unit]
Description = freshclam clamav update daemon
After = network.target
[Service]
Type = forking
ExecStart = /usr/bin/freshclam -d
Restart = on-failure
[Install]
WantedBy=multi-user.target

[Unit]部分定义了服务的基本属性,如描述和它依赖于网络连接。[Service]部分定义了服务本身,ExecStart将运行freshclam并带有-d参数,Type让 systemd 知道该进程将分叉并在后台以守护进程方式运行,Restart将使 systemd 监控该服务,如果它崩溃,将自动重启。[Install]部分定义了当我们运行systemctl enable时,它将如何被链接。

注意

系统文件的内容相当基础,可以作为您编写其他自定义服务的起点。

使用clamscan扫描文件中的威胁:

clamscan -ir /home/tboronczyk

-i参数指示扫描器仅输出感染的文件,而不是每个扫描的文件名。-r触发递归扫描,深入子目录。给定的路径可以是要扫描的单个文件或目录,在本例中是我们的home目录:

它是如何工作的...

ClamAV 提供其扫描结果的总结

注意

您可以使用 EICAR 的测试文件,从www.eicar.org/85-0-Download.html下载,来验证 ClamAV 是否正常工作。有关更多信息,请阅读它们的预期用途页面,网址为www.eicar.org/86-0-Intended-use.html

ClamAV 通常有两种使用方式——作为扫描器检查现有文件以检测威胁,或作为过滤器实时检测数据流中的威胁。设置定期扫描的最简单方法是通过设置 cron 作业。

要创建一个个人的 cron 作业,以运行clamav扫描home目录,请使用crontab

crontab -e

crontab将启动默认编辑器,供您输入作业计划。然后,crontab将在您保存计划并关闭文件后自动激活该作业。

一个每天凌晨 3:00 运行clamscan的示例计划可能如下所示:

0 3 * * * clamscan >> $HOME/clamscan.log

前五列指定作业运行的时间。第一列是分钟,第二列是小时,第三列是日期,第四列是月份,最后一列是作业运行的星期几。*用作简写,表示整个范围,因此该示例将每天的每个月运行。更多信息可以在crontab文件的格式手册页中找到(man 5 crontab)。

在服务器系统上,ClamAV 通常作为实时扫描器作为邮件过滤器运行。邮件服务器(例如 Postfix)接收邮件,然后将其传递给 ClamAV 进行扫描。假设您正在运行 Postfix,正如第九章中讨论的那样,管理电子邮件,以下是设置 ClamAV 与 Postfix 协同工作的步骤。

首先,我们需要安装一些额外的软件包。clamav-scanner-systemd软件包将安装我们需要的功能,使得clamscan可以作为守护进程运行,这样它始终可用,而clamav-milter-systemd软件包则安装了一个邮件过滤器,作为 Postfix 和扫描器之间的代理:

yum install clamav-scanner-systemd clamav-milter-systemd

然后,编辑配置文件/etc/clamd.d/scan.conf。注释掉Example行,并取消注释LocalSocket选项:

LocalSocket /var/run/clamd.scan/clamd.sock

LocalSocket给出的值是扫描守护进程用于与外部进程通信的套接字文件。

接下来,编辑/etc/mail/clamav-milter.conf文件,这是clamav-milter邮件过滤器的配置文件。注释掉Example行,取消注释第一个MilterSocket指令,并添加ClamdSocket指令。ClamdSocket的值应与scan.conf中的LocalSocket相同,但需以unix:为前缀,表示这是一个 Unix 套接字:

MilterSocket /var/run/clamav-milter/clamav.socket
ClamdSocket unix:/var/run/clamd.scan/clamd.sock

启动并启用扫描守护进程和过滤服务:

system start clamd@scan.service clamav-milter.service
system enable clamd@scan.service clamav-milter.service

最后,打开/etc/postfix/main.cnf并添加smtpd_milters条目,让 Postfix 知道过滤器的存在:

smtpd_milters=unix:/var/run/clamav-milter/clamav.socket

更新 Postfix 配置后,别忘了重启 Postfix:

systemctl restart postfix.service

另见

有关与 ClamAV 合作的更多信息,请参考以下资源:

使用 chkrootkit 检查 rootkit

如果不幸的是攻击者获得了系统访问权限,他们首先会做的事情之一就是隐藏自己的入侵,同时尽可能长时间地保持访问权限,可能会安装 rootkit。rootkit 是一个潜伏在系统中的程序,攻击者通过它获得管理员权限。它们会嵌入到 Linux 内核中以防止被检测到,甚至有些 rootkit 可以隐藏在系统固件的专用内存中,让攻击者即使在系统断电时也能控制系统。本食谱展示了如何使用 chkrootkit 检查系统是否存在 rootkit。

准备工作

本食谱要求使用 CentOS 系统,并且需要有效的网络连接。同时需要管理员权限,可以通过登录 root 账户或使用 sudo 来获得权限。

如何操作...

按照以下步骤使用 chkrootkit 检查是否存在 rootkit:

  1. 安装编译 chkrootkit 二进制文件所需的 gccglibc-static 软件包:

    yum install gcc glibc-static
    
    
  2. 下载 chkrootkit 源代码:

     curl -O ftp://ftp.pangeia.com.br/pub/seg/pac/chkrootkit.tar.gz
    
    
  3. 提取下载的源代码归档并进入代码目录:

    tar xzvf chkrootkit.tar.gz
    cd chkrootkit-0.50
    
    
  4. 运行 make 来编译 chkrootkit 的二进制组件:

    make
    
    
  5. chkrootkit 需要 netstat 来进行网络测试,netstat 包含在 net-tools 软件包中:

    yum install net-tools
    
    
  6. 运行 chkrootkit 扫描是否存在 rootkit:

    ./chkrootkit
    
    

它是如何工作的...

chkrootkit 由一个 shell 脚本和一小部分编译工具组成,作为源代码分发,因此需要编译。为了完成编译,你需要在系统中安装一个编译器。最基本的 gcc 就足够了。此外,我们还需要安装 glibc-static 包,因为该项目的 Makefile 会构建一个静态编译的二进制文件——所有二进制文件的依赖都会被编译进去;它不会动态引用系统共享库的副本:

yum install gcc glibc-static

chkrootkit 的源代码可以在项目网站上找到。食谱中使用的链接是指向最新源代码归档的直接链接,并通过 curl 下载:

curl -O ftp://ftp.pangeia.com.br/pub/seg/pac/chkrootkit.tar.gz

下载完成后,构建 chkrootkit 只需提取归档文件,进入新创建的目录并运行 make

make

当你在 第四章的《从源代码编译程序》一节中学习如何从源代码编译程序时,你使用了常见的 configuremakemake install 方法。然而,chkrootkit 并没有附带 configure 脚本,而且它的 Makefile 中没有包含 install 目标。我们在这里需要做的,就是直接运行 make 来启动编译过程。

chkrootkit 会运行一系列测试以检查已知的 rootkit 特征。部分测试使用其编译好的工具,而其他测试则使用常见的系统工具。其中一个网络测试会使用 netstat 检查哪些端口是开放的,netstat 在 CentOS 中默认没有安装,但可以从 net-tools 软件包中获取。因此,在使用 chkrootkit 之前,我们需要先安装这个依赖:

 yum install net-tools

一旦安装完成,我们可以执行 chkrootkit 脚本。没有任何参数运行时,chkrootkit 会执行所有测试。否则,我们可以指定一个或多个测试,只有这些测试会运行。-l(小写 L)参数将显示可能的测试列表:

 ./chkrootkit -l

另见

查看以下资源,了解更多关于使用 chkrootkit 的信息:

使用 Bacula 进行网络备份

事实上,我们生活在一个越来越依赖数据的世界中。此外,从意外删除到灾难性的硬盘故障,数据安全面临着许多威胁。你的数据越重要,如果丢失后再创建越困难,那么备份就越重要。因此,本教程将向你展示如何使用 Bacula 设置备份服务器,并配置网络中的其他系统将它们的数据备份到此服务器。

准备工作

本教程要求至少有两台具有有效网络连接的 CentOS 系统。第一台是本地系统,我们假设它的主机名为 benito,IP 地址为 192.168.56.41。第二台是备份服务器。你需要在这两台系统上都有管理员权限,可以使用 root 账户登录或通过 sudo 使用权限。

如何操作...

在本地系统上执行以下步骤以安装和配置 Bacula 文件守护进程:

  1. 安装 bacula-client 包:

     yum install bacula-client
    
    
  2. 使用文本编辑器打开文件守护进程的配置文件:

     vi /etc/bacula/bacula-fd.conf
    
    
  3. FileDaemon 资源中,更新 Name 指令的值,以反映系统的主机名,并加上后缀 -fd

     FileDaemon { 
             Name = benito-fd 
           ... 
           }
    
    
  4. 保存更改并关闭文件。

  5. 启动文件守护进程,并设置为系统重启时自动启动:

     systemctl start bacula-fd.service 
           systemctl enable bacula-fd.service 
    
    
  6. 打开防火墙,允许 TCP 流量通过端口 9102

     firewall-cmd --zone=public --permanent --add-port=9102/tcp 
           firewall-cmd --reload
    
    
  7. 在每个需要备份的系统上重复步骤 1-6。

在指定为备份服务器的系统上执行以下步骤,安装和配置 Bacula 主控、存储和文件守护进程。

  1. 安装 bacula-consolebacula-directorbacula-storagebacula-client 包:

    yum install bacula-console bacula-director bacula-storage 
           bacula-client
    
    
  2. 重新链接目录库以使用 SQLite 数据库存储:

    alternatives --config libbaccats.so
    
    
  3. 在提示提供选择编号时,输入 2。

  4. 创建 SQLite 数据库文件并导入表格架构:

     /usr/libexec/bacula/create_sqlite3_database 
           /usr/libexec/bacula/make_sqlite3_tables 
    
    
  5. 使用文本编辑器打开主控配置文件:

    vi /etc/bacula/bacula-dir.conf
    
    
  6. Job 资源中,Name 的值为 BackupClient1,将 Name 指令的值更改为本地系统的名称。然后添加一个 Client 指令,值与该系统的 FileDaemon Name 相匹配:

     Job { 
             Name = "BackupBenito" 
             Client = benito-fd 
             JobDefs = "DefaultJob" 
           }
    
    
  7. 复制 Job 资源,并根据需要更新其指令值,以便为每个需要备份的系统定义一个 Job 资源。

  8. 对于每个需要备份的系统,复制Client资源,其中Name指令设置为bacula-fd。在复制的资源中,更新NameAddress指令以标识该系统:

     Client { 
             Name = bacula-fd 
             Address = localhost 
             ... 
           } 
           Client { 
             Name = benito-fd 
             Address = 192.168.56.41 
             ... 
           } 
           Client { 
             Name = javier-fd 
             Address = 192.168.56.42 
             ... 
           }
    
    
  9. 保存更改并关闭文件。

  10. 打开存储守护进程的配置文件:

           vi /etc/bacula/bacula-sd.conf 
    
    
  11. Device资源中,NameFileStorage的条目,将Archive Device指令的值更改为/bacula

           Device { 
             Name = FileStorage 
             Media Type = File 
             Archive Device = /bacula 
           ...
    
    
  12. 保存更新并关闭文件。

  13. 创建/bacula目录并分配适当的所有权:

           mkdir /bacula 
           chown bacula:bacula /bacula
    
    
  14. 如果启用了 SELinux,请重置新目录的安全上下文:

           restorecon -Rv /bacula
    
    
  15. 启动管理程序和存储守护进程,并使它们在系统重启时自动启动:

           systemctl start bacula-dir.service bacula-sd.service 
           bacula-fd.service 
           systemctl enable bacula-dir.service bacula-sd.service 
           bacula-fd.service
    
    
  16. 打开防火墙,允许 TCP 流量通过端口9101-9103

           firewall-cmd --zone=public --permanent --add-port=9101-9103/tcp 
           firewall-cmd -reload
    
    
  17. 启动 Bacula 的控制台界面:

           bconsole 
    
    
  18. 输入label创建备份的目标。在提示输入卷名称时,使用Volume0001或类似的值。当提示选择池时,选择File池:

           label 
    
    
  19. 输入quit退出控制台界面。

它是如何工作的

配置 Bacula 大多数时候可能是一个令人生畏的任务,因为该套件的分布式架构以及在组织和调度备份与恢复作业方面提供的灵活性。然而,一旦一切都顺利运行,我相信你会放心,因为你知道你的数据已经远离意外和灾难的风险。

Bacula 由多个组件组成。在这个例子中,我们的重点是三个守护进程——管理程序、文件守护进程和存储守护进程。文件守护进程安装在每个需要备份的客户端系统上,并监听来自管理程序的连接。管理程序按计划连接到每个文件守护进程,并告诉它备份哪些文件以及将其复制到哪里(存储守护进程)。存储守护进程接收备份的数据,并将其写入备份介质,例如磁盘或磁带驱动器。

首先,我们在客户端系统上使用bacula-client软件包安装了文件守护进程。然后,我们编辑了位于/etc/bacula/bacula-fd.conf的文件守护进程配置文件,以指定进程的名称。约定是将系统主机名后缀添加-fd

 FileDaemon { 
      Name = benito-fd 
      FDPort = 9102 
      WorkingDirectory = /var/spool/bacula 
      Pid Directory = /var/run 
      Maximum Concurrent Jobs = 20 
    }

在更新配置后,我们启动了服务并在系统防火墙中打开了适当的端口。文件守护进程现在正在监听,等待管理程序连接并告诉它需要执行的操作。

在备份服务器上,我们安装了bacula-directorbacula-storagebacula-client软件包。这为我们提供了管理程序和存储守护进程,以及另一个文件守护进程。文件守护进程在备份服务器上的作用是备份 Bacula 的目录:

它是如何工作的

这张从 Bacula 文档中复制的图像展示了不同应用程序之间的关系:

Bacula 维护了一个关于之前备份任务的元数据数据库,称为目录,它可以由 MySQL、PostgreSQL 或 SQLite 管理。SQLite 是一个嵌入式数据库库,意味着使用它的程序会链接到 SQLite 库并管理自己的数据库文件。为了支持多个数据库,Bacula 的代码编写方式使得所有数据库访问程序都包含在不同的共享库中,每个数据库都有一个不同的库。然后,当 Bacula 想要与数据库交互时,它通过 libbaccats.so 进行,这个 库实际上只是一个指向特定数据库库的符号链接。这样,Bacula 就能在不需要重新编译源代码的情况下支持不同的数据库。

为了创建符号链接,我们使用了 alternatives 并选择了我们想要使用的真实库:

 alternatives --config libbaccats.so

然后,我们使用随 Bacula 附带的脚本初始化了数据库的模式:

 /usr/libexec/bacula/create_sqlite3_database 
    /usr/libexec/bacula/make_sqlite3_tables

How it works

Bacula 支持多个数据库而无需重新编译

注意

这个方案利用了 Bacula 的 SQLite 支持,因为它方便且不需要额外的设置工作。如果你想使用 MySQL,请按照 第七章,使用数据库 中的说明安装 MySQL,创建一个专门供 Bacula 使用的 MySQL 用户,然后使用以下脚本初始化模式:

/usr/libexec/bacula/grant_mysql_privileges
 /usr/libexec/bacula/create_mysql_database
 /usr/libexec/bacula/make_mysql_tables

你还需要查看 Bacula 的配置文件,以便为 Bacula 提供所需的 MySQL 凭证。

不同的资源在导演的配置文件 /etc/bacula/bacula-dir.conf 中定义,其中许多资源不仅包含它们自己的值,还引用其他资源。例如,FileSet 资源指定备份和恢复时包含或排除的文件,而 Schedule 资源指定何时进行备份。JobDef 资源可以包含多个备份任务共用的配置指令,并且还引用特定的 FileSetSchedule 资源。Client 资源标识运行文件守护进程的系统的名称和地址,而 Job 资源将 JobDefClient 资源组合起来,定义特定系统的备份或恢复任务。某些资源在更细粒度的级别上定义内容,并作为构建其他资源的基础,从而灵活地创建复杂的定义。

提示

默认的资源定义定义了足够的基本备份和恢复任务,适用于此方案。你应该研究配置,了解不同资源如何协同工作,以便根据你的备份需求进行调整。

How it works

这张图片摘自 Bacula 的文档,展示了不同资源之间的关系。

要开始,我们通过更改名称和客户端定制了现有的备份Job。然后我们通过更改名称和地址,将现有的Client资源定制为指向特定的运行文件守护进程的系统。JobClient资源的配对被复制,为我们要备份的每个系统都创建了一对。请注意,我们还保留了一个默认的Client资源,定义了本地主机的bacula-fd。这是本地备份服务器上的文件守护进程,将作为恢复作业和目录备份等操作的目标:

    Job { 
      Name = "BackupBenito" 
      Client = benito-fd 
      JobDefs = "DefaultJob" 
    } 

    Job { 
      Name = "BackupJavier" 
      Client = javier-fd 
      JobDefs = "DefaultJob" 
    } 

    Client { 
      Name = bacula-fd 
      Address = localhost 
      ... 
    } 

    Client { 
      Name = benito-fd
 Address = 192.168.56.100 
      ... 
    } 

    Client { 
      Name = javier-fd 
      Address = 192.168.56.100 
      ... 
    }

提示

如果你有很多客户端系统或许多作业定义,可以通过将这些资源定义在各自的文件中,并将它们读入bacula-dir.conf,以便更好地组织。创建目录/etc/bacula/config.d,并将单独的配置文件放在该目录下。然后在bacula-dir.conf中添加以下行以读取它们:

**@|"find /etc/bacula/config.d -name '*.conf' f -exec echo @{} \;"**

为了完成设置,我们需要为备份卷打标签。这个任务和其他大多数任务一样,是通过bconsole完成的,bconsole是 Bacula 控制台接口。

我们使用label命令为备份卷定义了一个标签,当被提示选择池时,我们将标签卷分配到File池中。与逻辑卷的工作方式非常相似(参见第五章,管理文件系统和存储),单个设备或存储单元被分配为一个卷,并且这些卷被分组到存储池中。例如,如果一个池包含两个由磁带驱动器支持的卷,而其中一个驱动器已满,则存储守护进程会将备份数据写入有空闲空间的磁带上。即使在我们的配置中,我们将备份存储到磁盘,但仍然需要创建一个卷作为数据写入的目标。

在这一点上,你应该考虑哪种备份策略最适合你。完全备份是数据的完整副本,增量备份仅捕获自上次完全备份以来发生变化的文件,差异备份则仅捕获自上次完全备份以来发生变化的文件(无论备份类型如何)。通常,管理员会采用这些备份策略的组合,例如在每周开始时进行完全备份,然后每天进行差异备份或增量备份。这样可以节省存储空间,因为差异备份和增量备份较小,并且在需要恢复文件时也非常方便,因为只需要搜索少量备份就能找到文件。

另一个考虑因素是每次备份的预期大小以及备份完成所需的时间。全量备份显然需要更长的时间,在一个 9 到 5 的工作时间的办公室(周一至周五),晚上可能无法进行全量备份。在周五进行全量备份可以利用周末的时间进行备份。较小的增量备份可以在其他时间进行,当时间较少时。

另一个在备份策略中需要注意的重要点是备份会保存多久以及保存的位置。这涉及到更大的问题——灾难恢复。如果你的办公室发生火灾,一年的备份将毫无用处,如果它们仍保存在办公室的 IT 机房中。在我曾工作的一个地方,我们将最后的全量备份和最后一天的增量备份保存在本地磁盘上,然后将它们复制到磁带并运送到异地。

无论你选择实施什么样的策略,你的备份的有效性取决于你从备份中恢复数据的能力。你应该定期测试备份,以确保你能恢复文件。

要按需运行备份任务,在 bconsole 中输入 run。系统将提示你从当前配置的任务中选择一个。然后,你将看到该任务的选项,例如将执行哪种级别的备份(全量、增量或差异备份),优先级以及何时运行。你可以输入 yesno 来接受或取消它,或者输入 mod 来修改某个参数。接受后,任务将排队并分配一个任务 ID。

要从备份中恢复文件,请使用 restore 命令。系统将提供一系列选项,允许你指定要从哪个备份中恢复所需的文件。根据你的选择,提示会有所不同。Bacula 的提示信息非常清晰,所以仔细阅读它们,它会引导你完成整个过程。

除了 runrestore 命令外,另一个有用的命令是 status。它允许你查看 Bacula 组件的当前状态,是否有任何正在运行的任务,以及哪些任务已完成。你可以通过在 bconsole 中输入 help 来获取所有命令的完整列表。

它是如何工作的

bconsole 是 Bacula director 的控制台界面

另请参见

参考以下资源获取有关使用 Bacula 的更多信息:

第十二章:虚拟化

本章包含以下配方:

  • 创建新的虚拟机

  • 克隆虚拟机

  • 向虚拟机添加存储

  • 连接 USB 外部设备到来宾系统

  • 配置来宾的网络接口

简介

本章的配方重点介绍如何在 CentOS 系统上使用虚拟化运行第二个操作系统作为来宾操作系统。你将学习如何设置虚拟机来安装来宾操作系统,如何通过克隆正确创建虚拟机的副本,并添加额外的存储资源。你还将学习如何共享对连接到宿主系统的 USB 外设的访问权限,并配置来宾的虚拟网络接口来访问网络。

创建新的虚拟机

本章节将教你如何安装 KVM 虚拟化软件并创建一个新的虚拟机。虚拟化使我们能够通过在同一物理系统上运行多个操作系统来利用可用的硬件资源。主操作系统是裸金属安装的,称为宿主操作系统(Host OS)。然后,安装特殊软件,使宿主操作系统能够提供硬件资源的仿真或直接访问。这些资源被分配为虚拟机,并且可以在宿主操作系统上安装并运行多个来宾操作系统,每个操作系统在其自己的虚拟机中运行。

准备工作

本配方需要一个具有工作网络连接和已安装图形用户界面的 CentOS 系统(请参阅 第一章中的 安装 GNOME 桌面安装 KDE Plasma 桌面 配方)。还需要管理员权限,可以通过登录 root 账户或使用 sudo 获得。

如何操作...

按照以下步骤安装来宾操作系统:

  1. 使用软件包组安装必要的虚拟化包:

    yum groupinstall "Virtualization Platform"   
           "Virtualization Client" "Virtualization Tools"
    
    
  2. 启动虚拟机管理器应用程序:

     virt-manager
    
    
  3. 通过从 文件 菜单选择 新建虚拟机 来创建新的虚拟机。这将打开 新虚拟机 向导。

  4. 选择所需的安装方法并点击 下一步。对于本配方,我们将选择 本地安装媒体 选项:如何操作...

    新虚拟机向导收集创建新机器所需的详细信息

  5. 选择媒体源。如果媒体是 CD 或 DVD,选择 使用 CDROM 或 DVD 选项。如果媒体是 ISO 文件,选择 使用 ISO 镜像 选项并指定镜像文件的路径。然后,点击 下一步如何操作...

    新机器将使用 ISO 文件作为其安装媒体

  6. 设置你想要分配给虚拟机的 RAM 大小和 CPU 数量,然后点击 下一步如何操作...

    1 GB 的 RAM 和 1 个 CPU 分配给虚拟机

  7. 指定分配给机器的存储容量,然后点击下一步:如何操作...

    该机器设置了 8 GB 的存储空间

  8. 提供一个名称以标识虚拟机,然后点击完成:如何操作...

    向导已准备好创建虚拟机并启动安装介质

  9. 虚拟机将自动启动并从指定的安装介质启动。现在,您可以像在物理系统上一样在机器上继续安装您的客户操作系统:如何操作...

    可以像在物理系统上安装操作系统一样,在虚拟机上安装操作系统

它是如何工作的...

必要的软件通过安装三个软件包组来完成;虚拟化平台组安装基础虚拟化库,虚拟化客户端包安装用于创建和管理虚拟机的客户端程序,虚拟化工具包安装用于维护机器的工具:

yum groupinstall "Virtualization Platform" 
"Virtualization Client"  "Virtualization Tools"

安装软件后,我们使用虚拟机管理器创建了一台机器。虚拟机定义了一个虚拟系统,指定了可供客户使用的资源以及客户如何访问这些资源。在 GNOME 桌面环境下,管理器可以从系统工具类别的应用程序菜单启动。在 KDE 中,可以通过 Kickoff 应用程序启动器在应用程序|系统工具下找到。管理器也可以通过命令行使用virt-manager启动:

virt-manager

注意

也可以通过命令行创建新的虚拟机,使用virt-install并指定资源分配作为参数。这对于希望通过脚本化方式快速创建新客户机的用户特别有用。

管理器的新虚拟机使得创建新的虚拟机定义变得容易,它会提示我们输入必要的资源分配。例如,我们需要提供内存大小、CPU 数量以及可供客户使用的存储空间。提供完这些值后,管理器会创建并启动虚拟机,从指定的安装介质启动并安装客户操作系统。从那时起,安装操作系统就像在物理系统上安装一样。

要启动虚拟机,从可用的虚拟机列表中选择目标虚拟机,使其高亮显示,然后点击管理工具栏上的播放箭头图标。或者,右键点击列表条目,并从上下文菜单中选择运行。这样虚拟机将启动,状态变为运行中。完成后,可以通过点击工具栏上的电源图标或在上下文菜单中选择关机选项来关闭虚拟机。虚拟机状态将变为已关闭。要在虚拟机运行时与其交互,可以双击条目,或者高亮条目后点击工具栏上的打开图标。

注意

如果客户机的显示内容过大,无法完全显示,窗口的侧边和底部会出现滚动条。调整显示以适应窗口可以改善体验。要调整显示设置,可以在查看菜单中选择显示

另见

请参考以下资源获取更多关于虚拟机操作的信息:

克隆虚拟机

由于虚拟机本质上只是数据文件,因此可以轻松复制和共享。这很有用,因为你可以根据自己的需求设置一个金牌服务器,然后制作多个副本用于不同的目的。然而,使用cp命令并不是实现克隆的正确方式。本教程将展示如何通过克隆这一过程来正确地复制一台虚拟机。

准备工作

本教程要求先按照前一个教程中的说明设置好虚拟机。虽然克隆过程本身不需要管理员权限,但根据文件存放位置,访问虚拟机文件时可能需要管理员权限。默认情况下,文件存放在/var/lib/libvirt/images,这需要管理员访问权限。

如何操作...

按照以下步骤克隆虚拟机:

  1. 请确保你想要克隆的虚拟机没有在运行。

  2. 在虚拟机管理器中,右键点击列表中的目标虚拟机,并从上下文菜单中选择克隆。这将打开克隆虚拟机对话框:如何操作...

    克隆虚拟机对话框使克隆虚拟机镜像变得容易

  3. 为新镜像指定一个唯一名称,然后点击克隆按钮。这将创建一个虚拟机及其选定存储的独立副本。

它是如何工作的...

本教程使用虚拟机管理器创建了一个机器副本,称为克隆。机器应以这种方式克隆,而不是仅仅复制底层文件,因为克隆过程还会更新应在机器之间唯一的各种标识符,例如网络接口的 MAC 地址。

注意

virt-clone命令可用于通过命令行克隆客户机。有关更多信息,请通过man 1 virt-clone查看该程序的手册页。

如果您希望在启动克隆机器之前更新其各个方面,可以使用诸如virt-sysprepvirt-configure之类的工具。这些程序将在一个 chroot 环境中挂载机器的磁盘镜像,执行所请求的修改,然后卸载镜像。virt-sysprep通过libguestfs-tools-c安装:

 yum install libguestfs-tools-c 

要查看virt-sysprep可以执行的可用维护操作列表,可以使用--list-operations命令启动程序。每个选项将显示并附带简短的描述,说明它的功能。要执行某项操作,请使用--operation参数,后跟一个或多个操作标签,标签之间用逗号分隔。例如,以下命令会清除系统中所有账户的 bash 历史记录,并删除可能位于/tmp中的任何文件。-a参数提供机器磁盘镜像的路径:

virt-sysprep -a /var/lib/virt/images/Ubuntu-clone.qcow2 
--operations bash-history,tmp-files

根据原始机器镜像的用途,您可能还会发现以下清理操作有用:

  • ca-certificates:此命令删除任何 CA 证书

  • logfiles:此命令用于删除日志文件

  • ssh-hostkeys:此命令用于删除 SSH 主机密钥

  • ssh-userdir:此命令用于删除用户的.ssh目录

  • user-account:此命令删除所有用户账户,除 root 外

virt-sysprepvirt-customize的功能有所重叠;然而,virt-customize执行更多的一般性定制操作,而virt-sysprep则侧重于清理镜像。virt-customize可以执行诸如移动和设置系统主机名、重置密码、安装和卸载包等操作。

要重置系统的主机名,请使用--hostname参数并提供所需的名称:

virt-customize -a /var/lib/virt/images/Ubuntu-clone.qcow2 
--hostname ubuntu2

--install--uninstall参数用于添加或删除包,并指定一个或多个包名称,包名称之间用逗号分隔:

virt-customize -a /var/lib/virt/images/Ubuntu-clone.qcow2 
--install build-essential

以下是一些您可能会在virt-customize中找到有用的参数:

  • --chmod:此命令用于更改文件权限

  • --copy:此命令用于创建文件或目录的副本

  • --delete:此命令用于删除文件或目录

  • --mkdir:此命令用于创建一个新的目录

  • --move:此命令将文件或目录移动到新位置

  • --password:此命令用于更新用户的密码

  • --run-command:此命令在镜像上运行命令

另请参见

请参考以下资源,获取有关克隆和定制虚拟机的更多信息:

向虚拟机添加存储

即使你不是数据囤积者,可能也会遇到需要为来宾系统添加额外存储的情况。别担心!这很简单!本配方教你如何添加和修改附加到机器上的虚拟硬件。

准备工作

该配方需要按照前面的配方描述设置虚拟机。

如何操作...

按照以下步骤为虚拟机添加存储:

  1. 确保你想要修改的虚拟机没有在运行。

  2. 通过双击可用机器列表中的目标条目来打开虚拟机。

  3. 可以点击菜单栏中的灯泡图标或从视图中选择详情来显示虚拟机的硬件详细信息:如何操作...

    机器的虚拟硬件会显示出来,资源可以添加、修改或移除。

  4. 点击窗口左下角的添加硬件按钮,打开添加新虚拟硬件窗口。

  5. 从可用资源列表中选择存储。指定要分配给新磁盘的存储空间,并点击完成如何操作...

    向机器添加了一个虚拟的 8GB 存储驱动器

  6. 通过点击菜单栏中的计算机图标或从视图中选择控制台来离开硬件视图。

如何运作...

本配方展示了如何配置与机器相关的虚拟硬件定义。为了增加给来宾操作系统可用的存储空间,我们导航到该视图并添加了一个新的虚拟硬盘。可以通过界面创建存储设备,如配方所示,或者选择一个现有的硬盘文件并将其附加到系统中。

注意

如果你要创建一个新磁盘,你需要对存储进行分区、格式化和挂载,这样它才能使用。你可能会发现第五章,管理文件系统和存储对你有所帮助。

其他硬件也可以通过硬件视图进行管理。最显著的是,你可以添加和配置新的网络接口,并分配额外的 RAM 和 CPU 资源。增加 RAM/CPU 的目的是在系统上运行资源密集型进程——最好先分配少量资源,然后在需要时增加资源。

另一项有用的配置是更改显示服务器。默认情况下,显示配置为使用 SPICE 协议,这是一种比 VNC 更强大的协议。SPICE 服务器内置于虚拟化平台中,因此即使客户机仅运行控制台显示,你也可以使用 SPICE 客户端连接虚拟机并访问其显示(参阅www.spice-space.org/以获取 SPICE 客户端)。如果你想改用 VNC 连接,请在硬件列表中选择显示 SPICE项,并将其类型设置为VNC 服务器。将地址值更改为所有接口,以接受来自本地主机以外的连接,指定连接密码,然后点击应用按钮。

硬件列表中的显示标签将更改为显示 VNC

它是如何工作的...

用户可以使用 SPICE 或 VNC 客户端连接到虚拟系统的显示

另请参见

请参考以下资源,了解更多关于虚拟硬件操作的信息:

将 USB 外设连接到客户系统

本配方教你如何将连接到主机系统的 USB 设备共享给虚拟机。这意味着你可以从客户操作系统中使用 USB 打印机、网络摄像头和存储设备。

准备工作

本配方要求按照之前的配方设置虚拟机。

如何操作...

按照以下步骤将 USB 外设连接到客户系统:

  1. 确保你想要修改的虚拟机未运行。

  2. 将 USB 设备连接到物理系统。

  3. 通过双击可用机器列表中的目标条目打开虚拟机。

  4. 通过点击菜单栏中的灯泡图标或从视图中选择详细信息来显示虚拟机的硬件详细信息。

  5. 点击添加硬件按钮以打开添加新虚拟硬件窗口。

  6. 从资源列表中选择USB HOST 设备

  7. 选择所需的 USB 设备,然后点击完成按钮:如何操作...

    附加到主机系统的 USB 设备可以分配给虚拟机

  8. 通过点击菜单栏中的计算机图标或从视图中选择控制台来离开硬件视图。

  9. 启动虚拟机并验证 USB 设备是否可用。

它是如何工作的...

连接到主机系统的 USB 设备可以通过硬件详情分配给虚拟机。我们选择了USB 主机设备类别,显示了所有当前已注册在主机上的设备,我们可以从中进行选择。使用 USB 设备时有几个需要注意的事项。首先,只支持 USB 1.1 协议。对于大多数外设(如网络摄像头、打印机和 USB 麦克风),传输速度并不是问题。然而,如果你打算连接一个 USB 存储设备并传输大量数据,则可能会成为一个问题。其次,设备必须在启动虚拟机之前插入并由主机可访问。这是因为运行在主机上的虚拟化平台负责提供对虚拟机的访问。

注意

本教程展示了如何将连接到主机系统的 USB 设备分配给虚拟机。如果你是通过 SPICE 客户端远程访问虚拟机,你可以将 USB 设备插入本地计算机并通过 USB 重定向将其重定向到远程虚拟机。更多信息请参见 RHEL 7 虚拟化部署与管理指南。

另见

参阅以下资源以获取有关共享 USB 设备的更多信息:

配置虚拟机的网络接口

本教程教你如何配置虚拟网络接口的行为。通过更改接口的行为,你可以为虚拟机提供直接访问或过滤访问网络的方式,甚至可以设置一个仅对主机系统和其他虚拟机可见的本地网络。

准备工作

本教程需要一个具有有效网络连接的 CentOS 系统,还需要按照前面教程的描述设置好虚拟机。

如何操作...

按照以下步骤配置虚拟机的网络接口:

  1. 确保你要修改的虚拟机未在运行。

  2. 双击列表中所需的虚拟机条目以打开虚拟机。

  3. 通过点击菜单栏中的灯泡图标或从视图中选择详细信息来查看虚拟机的硬件详情。

  4. 指定所需的网络源(NAT 或主机设备)。

  5. 如果选择主机设备,请指定所需的模式(桥接、VEPA、私有或直通):如何操作...

    虚拟网络接口可以配置为以不同方式处理来宾的流量。

  6. 点击应用按钮保存配置。

  7. 通过点击菜单栏中的计算机图标或从视图中选择控制台,离开硬件视图。

  8. 启动虚拟机,并根据需要进行来宾网络配置。

它是如何工作的...

管理来宾的网络连接性是指定虚拟机网络适配器行为的问题。为了正确操作,我们首先需要了解可用选项的行为。

第一个选项是网络地址转换NAT),这是新虚拟机的默认设置。虚拟化平台为来宾提供一个虚拟网络接口,并处理其所有流量。平台通过主机的物理接口转发流量,表现得像是来宾与主机之间的路由器。

第二个选项是将虚拟接口直接绑定到主机的物理接口。共有四种共享模式,具体如下:

  • 桥接:虚拟化平台连接来宾和主机的接口,使来宾可以直接访问互联网。来宾需要获取自己的 IP 地址,并可以完全访问网络。

  • VEPA:此选项适用于支持 VEPA 的网络设备(必须满足特殊硬件要求)。

  • 私有:平台创建一个私有网络,路由数据包使得同一主机上的虚拟机能够相互通信以及与外部网络通信,但来自网络的连接无法到达虚拟机。

  • 直通:主机的接口直接共享(必须满足额外的技术要求)。

由于主题的技术性,文档和术语相当专业。而且,许多非网络专家的人在决定正确的配置时常常遇到困难。根据我的经验,非网络专业人员使用虚拟化的两种常见场景是:本地虚拟化用于提供备用环境,以及虚拟化用于提供多个服务器系统。如果你将虚拟机作为典型的桌面系统使用,用户需要通过互联网访问电子邮件和浏览网页,则使用 NAT 网络,并配置来宾使用 DHCP。如果你将这些机器用作服务器,则在桥接模式下共享主机适配器,并为来宾配置静态 IP 地址。

另请参见

请参考以下资源,获取更多关于配置虚拟网络接口的信息:

posted @ 2025-07-05 15:45  绝不原创的飞龙  阅读(3)  评论(0)    收藏  举报