CentOS-系统管理精要-全-
CentOS 系统管理精要(全)
原文:
annas-archive.org/md5/0c46a408c06e03abcd5f12d553b4e92f
译者:飞龙
序言
欢迎来到 CentOS 系统管理基础。我是 Andrew Mallett,我将为您提供专业的指导和培训,使您掌握管理这个强大而流行的 Linux 发行版的技能。我选择主要写关于 CentOS 是因为它在学习和生产过程中都不需要您支付费用。此外,CentOS 紧密遵循 Red Hat Enterprise Linux 发行版,因此您在这里学习和开发的技能可以在 CentOS 和 Red Hat 上得到很好的应用。如果您有兴趣,您的阅读可以作为追求 Red Hat 认证路径的一种投资。尽管本书并非直接编写为适应任何现有的课程,但 Red Hat 的考试都基于实际练习,因此您对 Linux 操作的了解越多,就越好。
CentOS 代表社区企业操作系统,尽管社区是一个小词,但它包含了很多。支持来自社区,通过论坛和 Linux 社区来帮助开发服务和应用程序,并提供解决发生的错误的方法。社区已经接管了这个发行版。随着社区的不断参与,发行版变得更加强大。
当我们谈论社区时,我想要感谢 Say Mistage(在 Twitter 上的 @sayomgwtf
可用)给予我的灵感和涂鸦。
写关于企业 Linux 发行版的重要性在于我们看到越来越多的组织部署 Linux,并因此需要有经验的专业人员来管理这些系统。在 2013 年,Linux 基金会与专业招聘公司 Dice 进行了调查,涉及许多大型组织,并得出以下结果:
-
93% 的被调查组织正在寻找雇佣 Linux 专业人员。
-
91% 的招聘经理报告称他们发现很难找到技能熟练的 Linux 管理员。
-
作为这一点的附注,还额外注意到 Linux 专业人员的薪水在过去的 12 个月内增加了 9%。
在如此多组织对 Linux 如此有信心的情况下,本书的重点必须是商业驱动,既是对我自己也是对你,读者。我希望你能够提升自己的职业前景以及 Linux 知识。
企业级 Linux 发行版,如 CentOS、Red Hat、Debian 和 SUSE 企业版 Linux,通常不会部署你在家用或爱好者导向的发行版(如 Fedora 或 openSUSE)中可能找到的最新和最尖端的技术。相反,它们将这些技术作为开发平台,先进行打磨和完善,再将其迁移到企业平台,这一过程可能会持续几个月甚至几年。企业级 Linux 必须是可靠、稳定且具有弹性的。除此之外,它还必须得到部署它的组织的良好支持,以及来自社区或付费支持团队的后端支持。从定义上讲,最新的软件开发技术并不适合这种需求;因为它们是最为新近的,关于这些进展的知识及最佳实践,毫无疑问需要时间来演变和发展。
本书内容概览
第一章,驯服 vi,将确保你熟练掌握 shell 中的快捷键,使其更加高效地导航,然后再进入 vi 的精通之路。你可能有过使用 vi 的经验,但我发现大多数人的经验并不愉快。我将确保你成为 vi 的主人,而不是相反。
第二章,冷启动,将帮助你理解 CentOS 中的启动过程,学习如何不仅修改 GRUB 菜单以增强安全性,还将学习如何使用 GRUB 命令行来调试和修复启动问题。我们还将包括一些使用 Plymouth 进行的启动动画,并解释何时根文件系统实际上并不是根文件系统。
第三章,CentOS 文件系统深入探讨,告诉我们,虽然我们有文件和目录,但它们都只是不同的文件类型。然而,当涉及到链接、管道和套接字时,我们将讨论它们是什么,以及它们如何使用。关于链接,我们将讨论硬链接和软链接之间的区别。我们还将挑战传统的文件系统设计;你可能曾经使用过逻辑卷管理器(LVM),但让我告诉你,它已经是上世纪的技术了。你将会惊讶于使用 BTRFS 进行企业级文件系统管理的强大与便捷,它的发音是 Better FS。
第四章,YUM——软件从未如此美丽,将让你掌握 YUM 仓库和软件管理;你一定会喜欢这个的。你将学会如何下载软件包而不立即安装它们,这样你就可以轻松地在企业中分发软件包。如果这还不够好,那么你将学会如何设置本地仓库,通过局域网共享软件包,并创建你自己的 RPM 包。
第五章,驯服猫 – 控制进程,告诉我们,管理员们常常没有你我这般的洞察力,随意让不必要的服务继续运行,并且不理解他们管理进程所需的工具。在这里,你将学习如何使用 upstart 和传统的服务脚本控制服务和进程,并且通过 kill 和 pkill 这些“致命武器”学会如何清除不必要的进程。
第六章,用户 – 我们真的需要他们吗?,当然告诉我们,我们并不希望系统上有这些用户,但这往往是被要求的,因此我们别无选择。与其对此心生不满,你将学会如何微笑着管理用户,并把他们牢牢掌控。
第七章,LDAP – 更好的用户管理方式,告诉我们,与其在每台机器上创建用户和组的孤岛,不如花更多时间在系统上进行优化,少花时间管理用户,这样你就可以回到高尔夫球场。将用户添加到中央目录并在需要时跨所有系统共享,是通向自由的门户。
第八章,Nginx – 部署以性能为中心的 Web 服务器,告诉我们,通常 Linux 管理员和出版物会集中讨论 Apache Web 服务器;我将向你介绍这个新兴的角色——Nginx(发音为 Engine X)。Nginx 自 2004 年推出以来,迅速从 Apache 手中抢占市场份额,且在全球多个部署的 Web 服务器中已经超过了 IIS。我们将一起部署 Nginx 和 PHP。
第九章,木偶 – 现在你是木偶师,将我们的焦点从企业中的 Linux 转移到通过 Puppet Labs 的著名 Puppet 软件来控制你的企业系统。集中配置控制和集中用户管理一样好,它能让你有更多的时间去高尔夫球场,而不是让我给你留下“高尔夫占据了我生活”的印象。
第十章,安全中心,向你介绍了可插拔身份验证模块(PAM)。它是你的朋友,帮助你管理用户何时以及如何连接。SELinux 同样是朋友,尽管它有些脾气。只要好好对待,它会帮助你确保系统的正确使用。你将学习如何加固你的 Linux 系统,并获得一套最佳实践!
第十一章,毕业典礼,告诉我们,在我们准备离开并带着新学到的技能时,我们将提醒自己需要关注安全问题,并遵循最佳实践。我们可以重新回顾一些我们之前见过的产品,比如 Puppet 和 Nginx,并概述一些行业公认的部署这些服务的准则,以及 CentOS 7 的一些新特性。
本书所需资源
你需要有一些 Linux 使用的基础知识,并希望将这些知识快速提升到专家级别。建议并鼓励你在本书及其中的练习中进行实际操作。虽然本书也可以作为“阅读和学习”的工具,但我更推荐“阅读、实践并终身学习”。中间的“实践”对于真正理解和掌握知识至关重要;这是经过时代验证的教育法。
在撰写本书时,CentOS 6.5 版本已发布,尽管任何版本的 CentOS 都适用于大多数练习,包括后续版本。CentOS 的各个版本可以从 wiki.centos.org/Download
下载。它是免费的且开放使用的,正如你将看到的,符合 GPL 许可协议。CentOS 6.5 将免费支持更新,直到 2020 年 11 月 30 日。
本书适用对象
我认为可以公平地说,我了解 Linux,更重要的是,我知道如何让你保持参与。我将以一种旨在帮助你理解和记住的方式传授我的知识,通过将复杂的理念拆解成易于消化的智慧小块,使你在每翻一页时都能在知识和信心上成长。我们将集中讨论命令行的强大功能和易用性。例如,让我问你一个问题:
73 天前是什么日期?
我很惊讶你居然不知道。Linux 命令行知道,简单地执行以下命令即可:
$ date --date "73 days ago"
本书是为那些有一定 Linux 知识的管理员编写的,目的是让他们获得更多的经验,并且不怕通过命令行外壳操作来动手实践。
理解 Linux 命令行的强大功能,并通过这些小小的增强技巧掌握它,将是你作为 Linux 管理员成功的关键。这也是我将本书与其他书籍区分开来的地方。你可能还想查看我的 YouTube 频道 www.youtube.com/theurbanpenguin
,在该频道中,我创建了超过 700 个教程,涵盖了各种产品,主要以 Linux 为主,并且包含大量脚本编写和编程内容。
或者,你可以访问我自己的站点 theurbanpenguin.com
,那里内容组织得更好。
约定
在本书中,你会看到多种文本样式,它们用于区分不同类型的信息。以下是一些样式示例及其含义解释。
文本中的代码词、数据库表名、文件夹名称、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 用户名会以如下方式显示:“将.vimrc
设置为你喜欢的方式。”
一段代码块设置如下:
default=0
timeout=5
hiddenmenu
password --md5 <password-hash>
任何命令行输入或输出都会如下所示:
# vi /etc/httpd/conf/httpd.conf
# service httpd restart
w3m localhost
新术语和重要词汇会以粗体显示。你在屏幕上看到的单词,例如菜单或对话框中的内容,会以这样的方式呈现:“在主欢迎页面,我们应该选择用户和组标签页,然后点击搜索按钮。”
注意
警告或重要说明会以这样的框框形式出现。
提示
提示和技巧会以这样的方式展示。
读者反馈
我们始终欢迎读者的反馈。告诉我们你对这本书的看法——你喜欢或不喜欢什么。读者反馈对我们非常重要,因为它帮助我们开发出能让你从中获得最大价值的书籍。
要向我们提供一般反馈,只需通过电子邮件发送到<feedback@packtpub.com>
,并在邮件主题中提及书名。
如果你在某个领域拥有专业知识,并且有兴趣撰写或为书籍做贡献,请参阅我们的作者指南:www.packtpub.com/authors。
客户支持
现在你已经成为一本 Packt 书籍的骄傲拥有者,我们提供了一些帮助你从购买中获得最大收益的资源。
下载本书的彩色图像
我们还为你提供了一份 PDF 文件,其中包含本书中使用的截图/图表的彩色图像。彩色图像将帮助你更好地理解输出中的变化。你可以从以下链接下载该文件:www.packtpub.com/sites/default/files/downloads/5920OS_coloredimages.pdf
。
勘误
虽然我们已尽一切努力确保内容的准确性,但错误还是会发生。如果你在我们的书籍中发现错误——可能是文本或代码错误——我们将非常感谢你能报告给我们。通过这样做,你可以帮助其他读者避免困扰,并帮助我们改进后续版本的书籍。如果你发现任何勘误,请访问www.packtpub.com/submit-errata
报告它们,选择你的书籍,点击勘误提交表单链接,并填写勘误的详细信息。一旦你的勘误被验证,你的提交将被接受,勘误将被上传到我们的网站或添加到该书的勘误部分。
要查看之前提交的勘误,请访问 www.packtpub.com/books/content/support
并在搜索框中输入书名。所需的信息将在勘误部分显示。
盗版
网络上对版权材料的盗版问题在所有媒体中都持续存在。在 Packt,我们非常重视版权和许可证的保护。如果您在互联网上遇到我们作品的任何非法复制,请立即提供相关的地址或网站名称,以便我们采取补救措施。
请通过 <copyright@packtpub.com>
与我们联系,并提供涉嫌盗版材料的链接。
我们感谢您在保护作者权益以及我们为您提供有价值内容方面的帮助。
问题
如果您对本书的任何方面有问题,您可以通过 <questions@packtpub.com>
与我们联系,我们会尽力解决问题。
第一章。驾驭 vi
你可能对 vi 有一些了解,或者现在被称为 Vim(简单来说,vi 的改进版)。我常常发现,很多人第一次接触 vi 时的经历并不愉快,回想起来也没有什么好感。带领你走过最初难以理解的 vi 使用过程,我们会确保你成为 vi 的大师,并且渴望使用这个神奇的工具。vi 就像其他一切一样,你只需要在早期坚持下去,不断练习。还记得小时候你骑自行车时,尽管膝盖被摔伤过,你仍坚持了许久,最终成为了高手吗?我希望你也能在 vi 上坚持下去。我们将从一些命令行魔法开始,使整个命令行界面(CLI)体验更好。然后,我们就可以开始我们的 vi 黑带之旅了。
在本章中,我们将讨论以下主题:
-
CLI 魔法——你将喜欢的快捷方式
-
Vim 和 vi:在这一部分,你将学会区分这对双胞胎,并认识它们的图形化“表亲”
-
获取你喜欢的 .vimrc 设置
-
查找和替换:在这一部分,你将学会如何快速在文件中查找并替换文本,无论是在 Vim 内部还是外部
-
学习用几次巧妙的按键删除文件中的多余注释
CLI 魔法——你将喜欢的快捷方式
所以,在我们深入探讨 vi 的精彩文本编辑世界之前,我们将先通过一些键盘练习来热身。Linux 是我的激情所在,自动化也是如此。我总是热衷于创建脚本来执行任务,使这些任务能够重复正确地完成。一旦脚本创建并测试通过,我们就会知道它每次都能以相同的方式运行,我们也不会犯错或遗漏关键步骤,不管是因为任务变得无聊,还是因为我们在周五晚上的加班时,只想早点回家。脚本编写本身就是对命令行的深入了解,并能够以最佳方式使用它。这一点在你将使用的所有系统中都适用。
在命令行中,我们可能会通过执行以下命令来尝试一些黑魔法:
$ cd dir1 || mkdir dir1 && cd dir1
这样,我们使用了 cd
命令进入 dir1
目录。双竖线(或管道符)表示只有在第一个命令失败时,我们才会执行下一个命令。这意味着如果我们无法切换到 dir1
目录,我们将运行 mkdir dir1
命令来创建该目录。如果目录创建成功,我们会进入该目录。
提示
||
部分表示只有在第一个命令失败时,第二个命令才会执行。&&
部分表示只有在第一个命令成功时,第二个命令才会执行。
命令历史记录比仅仅使用上箭头键要更强大得多!请看以下命令:
$ mkdir dir1
$ cd !$
!$
部分表示最后一个参数,因此第二行的命令会被解析为以下内容:
$ cd dir1
这样,我们可以通过结合这两个概念,重写最初的命令序列,生成以下命令:
$ cd dir1 || mkdir !$ && cd !$
我们可以重复上一个命令以及最后一个参数。更重要的是,我们可以指定最后命令的起始字符。如果只是最后一条命令,按上箭头键就足够了。如果我们正在处理网络服务器的配置,可能需要用 vi 编辑配置文件,启动服务,然后用命令行浏览器进行测试。我们可以通过以下三个命令来表示这些任务:
# vi /etc/httpd/conf/httpd.conf
# service httpd restart
w3m localhost
在正确顺序下运行这三条命令,并希望成功后,我们可能会注意到我们仍然遇到问题,需要重新编辑 Apache(网络服务器)的配置文件。现在我们可以将命令列表缩短为以下内容:
# !v
# !s
# !w
!v
命令将重新运行我历史记录中以 v
开头的最后一条命令,s
和 w
同理。通过这种方式,我们看起来非常熟练,工作得也很迅速,从而可以有更多时间做我们真正感兴趣的事情,也许打个短的 9 洞高尔夫?
类似于我们第一次查看历史记录时,使用 !$
符号表示最后一个参数,我们可以使用 !?73
。这将查找 73
作为参数或参数的一部分。在我当前的历史记录中,这将与我们之前运行的 date
命令相关。我们来看一下:
$ !?73
使用我的历史记录,序列将扩展并运行以下命令:
$ date --date "73 days ago"
从我执行的最后一条命令到第一条命令查看我的命令历史记录,我们搜索 73
作为命令参数。我们注意到,我们只搜索 73
,意味着我们在寻找字符 7
后跟字符 3
。我们还必须记住,如果历史记录中存在 273
或 733
,也会匹配到它们。
掌握了 Bash shell 历史功能后,我们应该练习使其成为第二天性。
Vim 和 vi
啊,是的,Vim 和 vi!它们听起来像是某种古老的神秘药水,能够确保长寿和智慧。然而,它们并非如此。
命令行文本编辑器 vi 最早写于 1976 年,并在 1978 年成为 BSD Unix 首次发布的一部分。尽管它是基于命令行的,没有 图形用户界面 (GUI) 或菜单,但 Linux Journal 在 2009 年进行的调查发现,vi 是最受欢迎的编辑器,甚至超过了图形界面的 GNOME 编辑器 gedit,排在第二位。我并不反对 GUI,但我发现 GUI 编辑器限制多,速度较慢。我可以诚实地说,大部分甚至是所有任务,在 vi 中我能更快速地完成。
话虽如此,在 CentOS 中,你不会找到 vi;vi 只是一个默认的别名,提供给用户方便使用,并链接到 vim
命令。我们可以通过以下命令在我的 CentOS 6.5 控制台上查看这一点:
$ alias | grep vi
命令的输出应类似于以下屏幕截图:
Vim 是Vi IMproved的缩写,最初由 Bram Moolenaar 在 1991 年发布,最初针对 Amiga 系统。自 2000 年代初以来,它在 Linux 平台上变得非常流行。顾名思义,它基于 vi 并加以改进;在 CentOS 中,它通过vim-enhanced
包分发。这些改进最常用的功能是针对 PERL、Python 和 PHP 等语言的语法高亮功能。另一个改进是它可以在命令行上传统使用,或者使用 GUI 前端。要安装 Vim 的图形界面,你需要添加vim-X11
包,方法如下:
# yum install -y vim-X11
提示
当然,有一个限制,你需要运行 X11 服务器。在企业环境中,服务器通常不带 GUI,你可以通过安全外壳连接仅提供命令行的环境。
如果你是 vi 的新手,那么使用图形版本可能会很有帮助,因为菜单中还会显示命令行快捷键。要在命令行中用 vi 或 Vim 编辑文件,我们可以简单地使用类似下面的命令:
$ vi <filename-to-edit>
当你在 CentOS 桌面上工作时,可以通过以下方式使用编辑器的图形版本:
$ gvim <filename-to-edit>
或者
$ vimx -g <filename-to-edit>
我建议使用gvim
命令,因为它不需要额外的选项,也更少引起混淆。直接启动vimx
而不加-g
选项,只会启动普通的 Vim 程序。
设置.vimrc
文件以符合你的喜好
和许多 Linux 程序一样,Vim 也可以从运行控制文件中读取设置。设置可以通过/etc/vimrc
文件集中管理,或者通过~/.vimrc
文件为每个用户配置。通过这个文件,尤其是我们的个人版本,你可以自定义 Vim 的外观并控制其功能。
首先,我们来看看行号。当我们编辑文件时,通常是在控制台报告某一行出错之后,我们刚尝试运行脚本或启动服务时;我们知道我们有语法错误。假设我们想直接跳转到test.php
文件中的第97
行。那么,我们应该输入:
$ vi +97 test.php
这是假设我们在与文件相同的目录中。类似地,如果我们想直接跳转到readme
文件中第一次出现的install
单词,我们可以执行以下命令:
$ vi +/install readme
然后,仿佛凭空魔力,我们就被带到了所需的正确行。不过,在search
这个词的情况下,search
这个词会被高亮显示。如果不希望这样,可以简单地关闭这个功能。在 Vim 中,我们可以输入:
:nohlsearch
如果我们想在 Vim 中做一些永久性的设置,可以编辑我们家目录下的.vimrc
文件。这是我们个人的设置文件,因此,做出的更改不会影响到其他人。如果我们想影响全系统的设置,则可以使用/etc/vimrc
文件。尝试在~/.vimrc
文件中添加以下行,来持久地禁用高亮显示search
功能:
set nohlsearch
有了这个设置,每次启动 Vim 时,设置都会为我们准备好。然而,在我们查看文件时,可能会更倾向于开启行号显示。有时这会让工作变得更加简单,但有时我们可能更希望关闭行号显示,特别是当文件中某些行以数字开头时(因为显示可能会变得混乱)。要启用行号显示,请运行以下命令:
:set number
要关闭行号显示,我们可以使用以下命令:
:set nonumber
如之前所述,我们始终可以将期望的启动值放入 .vimrc
文件中。然而,在此之前,让我们看看 Vim 中的键映射以及如何创建一个快捷键来切换行号的显示与隐藏。我们希望为 Vim 中的普通模式创建一个映射。这是我们首次进入 Vim 时的模式,在此模式下我们并不进行编辑,只是浏览文件;通过按 Esc 键,我们始终可以返回到普通模式。执行以下命令:
:nmap <C-N> : set invnumber<CR>
nmap
命令表示我们仅为普通模式创建一个映射。我们将 Ctrl + N 键映射为运行子命令 :set invnumber
,然后按 <CR>
。
配置好这些后,我们可以使用 Ctrl + N 的组合键来切换行号的显示与隐藏。现在我们已经开始在这个工具上有所进展,你也许能体会到它为什么如此受欢迎。在我们对 .vimrc
文件进行最终编辑之前,我们将看到如何在 vi 或 Vim 中按行号跳转。确保我们处于普通模式下(通过按 Esc 键),我们可以使用 2G
或 2gg
跳转到当前文件的第 2 行;同样,234G
或 234gg
会跳转到第 234 行,G
或 gg
会跳转到文件的末尾。这很简单,但仍不够简单;我更希望输入行号并按 Enter 键。为此,我们将 Enter 键映射为 G。如果我们选择在没有数字前缀的情况下按 Enter 键,那么将直接跳转到文档的末尾,就像单独使用 G 键一样。执行以下命令:
:nmap <CR> G
现在,我们只需输入期望的行号并按 Enter 键。此操作会被解释为输入的行号后跟 G。通过这种方式,我们可以轻松跳转到正确的行。我们可以通过将以下内容添加到 .vimrc
文件来保存这个设置,当我们查看这个子章节中所做的所有设置时,文件内容应该类似如下:
set nohlsearch number
nmap <C-N> : set invnumber<CR>
nmap <CR> G
现在坐下来享受你所取得的成就,但请记住,练习是知识保持的关键。
查找与替换
所以我们并不是在执行“搜索并摧毁”任务,但如果这能增加学习的乐趣,我们也可以开始一个搜索和替换任务。Linux 的命令行上有大量的强大功能,其中之一就是流编辑器 sed。即使不进入 Vim 编辑器,我们也可以在单个文件甚至多个文件中搜索和替换文本。无需使用交互式编辑器为我们提供了更多的管理范围,能够在单个或多个服务器上脚本化更新。sed
命令中的功能可以在 Vim 中使用,也可以作为独立应用程序使用。在本小节中,我们将学习如何使用 sed 和 Vim 在文件中搜索和替换文本,掌握在 CentOS 及其他操作系统(包括 Mac 上的 OS X)中使用的技能。
首先,假设我们最近更改了公司名称,并且需要将文本文件中所有的Dungeons
引用替换为Dragons
。使用 sed,我们可以直接从控制台运行命令:
$ sed -i 's/Dungeons/Dragons/g' /path/file
这将逐行读取文件,并将所有出现的Dungeons
替换为Dragons
。-i
选项允许就地编辑,意味着我们可以直接编辑文件,而不需要将 sed 的输出重定向到新文件。g
选项允许替换在每行中出现的所有Dragon
实例,即使它出现多次。
在 Vim 中打开文件并做相同的操作,运行以下命令:
:%s/Dungeons/Dragons/g
百分号符号用于指定范围为整个文档;而如果我们使用以下命令,则只会搜索包含搜索字符串的第 3 到第 12 行。在这种情况下,范围被称为第 3 到第 12 行,而使用%
时,范围是整个文档。
:3,12s/Dungeons/Dragons/g
当我们想要缩进文件中的某些代码时,范围非常有用。在以下的代码中,我们再次搜索第 3 到第 12 行,并在每行的开始处添加一个 Tab:
:s/3,12s/^/\t/
我们已经在上一个命令中将 Vim 中的范围设置为表示第3
到12
行。这些行可能代表我们想要缩进的if
语句的内容。例如,我们首先搜索符号^
(行的开始),并将其替换为一个 Tab(\t
)。由于每行的开始位置显然只有一次,因此不需要使用全局选项。使用这种方法,我们可以根据需要快速为文件添加缩进,再次成为 Vim 的 Zen 超级英雄。
学会用几下巧妙的按键删除文件中的多余注释
既然我们是管理员,搜索和替换的禅宗大师,我们可以利用这些技巧来整理那些通常包含数百行注释的配置文件。我不介意文档,但当它成为压倒性的多数时,它会占据一切。考虑一下 /etc/httpd/conf/
下的 httpd.conf
Apache 配置文件。这个文件有 675 行注释。我们或许希望保留原始文件作为参考。于是我们首先通过执行以下命令来做个备份;我们从本书的前言中已经学会了如何做,如果你还没有阅读前言,现在是时候阅读它了,免得以后收到父母的来信。
# cd /etc/httpd/conf
# cp httpd.conf httpd.conf.$(date +%F)
我们可以轻松地使用以下命令列出注释行,该命令统计以 #
符号开头的行,即注释:
# egrep -c '^#' httpd.conf
在我的系统中,我们发现有 675 行这样的注释。使用 sed
或 Vim,我们可以首先通过 sed 删除注释,方法如下:
# sed -i '/^#/d' httpd.conf
然后,在 Vim 中打开文件时,操作会稍有不同:
:g/^#/d
两个示例中的结果是相同的,我们都通过大约三分之二的行数减少了文件的行数。
总结
在每一章中,我都希望确保你至少能获得一项有价值的内容,能带走并应用到实际中;这一章我做得如何?如果你还记得,我们回顾了一些有助于有效导航命令历史的快捷键。接着,我们迅速了解了文本编辑器 vi 或更常用的 Vim。对于那些需要一些帮助才能入门 Vim 的人,我们还有 gVim 可供使用,如果我们在桌面上工作的话。定制任何系统都很重要,它能让我们感觉自己拥有这个系统,并且它为我们服务。使用 Vim 时,我们可以编辑位于主目录中的 .vimrc
文件。通过一些额外的按键映射和期望的选项,我们为 Vim 添加了一些装饰。从那时起,我们就直奔工作,看看 Vim 能做什么,如何使用我们之前复习过的搜索、替换和删除选项。
第二章。冷启动
在北半球,我想我们都能理解冷启动的比喻:那些寒冷的 1 月早晨,你拼命尝试启动汽车。当它最终勉强发动时,我们还得忍受方向盘冰冷得无法握住。幸运的是,启动 Linux 系统并不那么不愉快;或许空调服务器房间与此有关系,我也不太确定……
在本章的学习过程中,我们将基于你已掌握的内容,帮助你更好地理解你的 Linux 系统。你将学习以下主题:
-
GRUB 与 MBR:在这一节中,你将学习GRand Unified Bootloader(GRUB)与主引导记录(MBR)之间的关系,GRUB 能够轻松地将它那仅有的 466 字节放入 512 字节的限制内。
-
当根文件系统不是根文件系统时?:在这一节中,我们将理解在 GRUB 配置段中使用的root指令的含义,这是我们需要克服的小障碍。
-
在 GRUB 控制台工作:在这一节中,你将学习如何启用一些强大的恢复工具。
-
用密码保护 GRUB 菜单:在这一节中,你将学习如何加强系统的物理安全性:无论是桌面还是服务器。
-
通过 plymouth 进行启动界面显示:为了让本节内容更加有趣,我们将看看可以在 CentOS 中使用的启动界面。到本章结束时,你的 Linux 系统将变得前所未有地“华丽”。
GRUB 与 MBR
这不仅仅是一场比赛,看看我们能在章节标题中塞进多少个首字母缩略词,尽管在四个单词中,已经用了两个也算是一个不错的开始。GRUB是 CentOS 和 Red Hat Enterprise Linux 6 自带的引导加载程序。这个小小的启动代码用来加载内核,并允许我们双启动不同的 Linux 版本,甚至是与 Microsoft Windows 操作系统的双启动。GRUB 多年来一直是首选的引导加载程序,尽管也存在其他引导加载程序。这些包括:
-
Lilo:这是最早的 Linux 加载程序
-
EXTLinux:这是 SYSLinux 家族的一部分,包括以下内容:
-
使用 EXTLinux 从固定磁盘启动
-
使用 ISOLinux 从 CD 和 DVD 启动
-
使用 SYSLinux 从 USB 设备启动
-
使用 PXELinux 从网络启动
-
-
GRUB2:最近,GRUB2 开始作为 GRUB 的替代品出现,或者说作为现在所称的传统 GRUB 的替代。预计 GRUB2 将在 2014 年的 CentOS 7 中首次亮相。
GRUB 引导加载程序通常存储在可启动磁盘的 MBR 中。
提示
尽管通常存储在 MBR 中,但也可以将 GRUB 安装到分区的超级块中,或分区的前 512 字节中。
MBR 构成了磁盘的前 512 字节,允许最多存储 466 字节的引导加载程序;其余的空间将用来存储该驱动器的分区表。
我们可以使用 dd
命令将 MBR 备份到文件中,如下所示:
# dd if=/dev/sda of=/tmp/sda.mbr count=1 bs=512
dd
命令用于复制磁盘。在前面的命令中,我们从第一个磁盘 /dev/sda
读取数据,并将其备份到 /tmp/sda.mbr
文件中。我们没有复制整个磁盘,而是将备份限制为一个 512 字节大小的块。
现在我们已经有了 MBR 的备份,可以通过运行以下命令进一步调查此事实:
提示
以下命令可能会有破坏性,因为它们将销毁 MBR,所以如果你将在自己的系统上运行这些命令,请小心。我建议仅在测试系统上运行以下演示命令。
# dd if=/dev/zero of=/dev/sda count=1 bs=512
使用前述命令,我们已清除了磁盘 /dev/sda
中前 512 字节存储的数据。现在,MBR 已有效清除。我们可以使用以下命令来验证这一点:
$ lsblk /dev/sda
输出应该显示一个空的分区表。系统仍然可以使用,因为分区表驻留在运行系统的 RAM 中;然而,直到我们能够恢复 MBR,重新启动时将很快显示出我们面临的灾难。别担心,我们可以从备份中恢复 MBR。dd
删除的东西,dd
也能恢复,只需使用如下的 dd
命令。赶快,在别人注意到之前!
# dd if=/tmp/sda.mbr of=/dev/sda
我们不需要限制从指定文件读取的数据量。请记住,它仅包含组成 MBR 的 512 字节。稍微幸运一些,使用 fdisk
命令现在应该能正确显示以前的分区表,你可以开始松一口气了:
$ fdisk /dev/sda
提示
使用 dd
命令将磁盘完全擦除,并使用 /dev/zero
输入文件是非常有用的,尤其是当你希望在出售计算机之前清除磁盘,确保操作系统、应用程序,以及最重要的数据不随设备一起出售时。我们在第二个示例中使用 fdisk
,因为 lsblk
从内存读取数据,而不是从磁盘。
一旦进入 GRUB,菜单将会显示,允许用户选择要进入的操作系统(OS)。通常,默认选择会在没有用户交互的情况下加载。我们可以使用 /boot/grub/menu.lst
文件来配置菜单选项。稍后你将了解更多关于此文件的信息。
根文件系统何时不是根文件系统?
现在我们需要分解文件中的菜单条目,识别出核心组件,以便理解它们如何与系统相关联,最重要的是,如何修正错误。
编辑 GRUB 诗句
GRUB 菜单中的每个条目被称为诗句,每个诗句将以 title
单词开头,包含以下三个指令:
-
root
-
kernel
-
initd
诗句的标题也将成为菜单中显示的项目。我们来考虑一个以以下标题开始的诗句:
title CentOS 6.5 OS
菜单将显示CentOS 6.5 OS
作为可选择项,重要的是要注意,我们不会在文本周围添加引号,因为它们也会显示给用户。当然,除非你希望或需要显示这些引号;在 Packt Publishing,我们绝对不反对使用引号!
向节中添加根分区条目
紧接着节标题后面会有一行以root
指令开始。这会告诉 GRUB 根文件系统的位置,而不是操作系统的根文件系统;简单来说,这应该指向分区表中被标记为可启动的分区。
我们可以使用fdisk
或parted
命令显示可启动分区。如果你使用fdisk
命令显示分区信息,命令会类似于以下内容,我们希望列出系统中第一块硬盘的分区:
# fdisk -l /dev/sda
被标记为可启动的分区会用星号(*
)表示。如果你使用parted
命令显示分区表,你可以通过执行以下命令,按照启动标志来识别可启动的分区:
# parted /dev/sda print
提示
fdisk
会用*
标记可启动分区,而parted
则会标记为boot
。
可启动的分区可以是/boot
,也可以是实际的根文件系统/
。这与系统在安装时的配置方式有关。通常情况下,/boot
会有自己的分区,以便引导加载程序更方便地访问。例如,传统的 GRUB 无法访问基于逻辑卷管理(LVM)构建的文件系统;这是 CentOS 6 中的默认分区方案。冗余阵列的廉价磁盘(RAID)阵列也适用相同的情况。
考虑以下节:
title CentOS 6.5 OS
root (hd0,0)
从中我们可以确定,GRUB 应该将第一块硬盘上的第一个分区(驱动器和分区编号都从 0 开始)作为可启动分区。
总结来说,GRUB 节中的root
指令指示 MBR 标记为可启动的分区。
向节(stanza)中添加内核条目
kernel
指令将引导加载程序指向目标操作系统内核。该内核的路径将与 GRUB 根分区或可启动分区相关。如果路径是/vmlinuz.version
,则表示内核位于可启动分区的根目录下,而路径/boot/vmlinuz.version
则表示可启动分区是 Linux 或操作系统根分区。路径必须包含/boot
目录,才能找到内核。
在内核文件名之后是加载内核时使用的参数,通常被称为内核选项。这些选项包括:真实根文件系统所在的设备名称和交换文件系统的设备名称,这些选项可以用于挂起系统,例如在笔记本电脑上构建。操作系统根的一个例子是 root=/dev/sda2
;这是第一块硬盘上的第二个分区,或者 root=/dev/mapper/vg_centos-vg_root
。这表示操作系统根是基于 LVM 构建的。需要挂起的交换文件系统通过 resume
选项进行指示。
以下是一个条目的摘录,表示启动分区是 /dev/sda1 (hd0,0)
,操作系统根是 /dev/sda2
,交换分区位于 /dev/sda3
:
title CentOS 6.5 OS
root (hd0,0)
kernel /vmlinuz.version root=/dev/sda2 resume=/dev/sda3
如果操作系统根分区同时也是可启动分区,则相应的 GRUB 条目将类似如下:
title CentOS 6.5 OS
root (hd0,0)
kernel /boot/vmlinuz.version root=/dev/sda1 resume=/dev/sda2
我们可以看到,现在内核的路径是完整的操作系统路径,GRUB 根和操作系统根对应的是同一个分区。
在启动过程完成并且我们已登录的运行系统中,可以使用以下任一命令查看内核版本:
-
$ cat /proc/version
-
$ uname -r
你应该查看这两个命令,看看哪个最适合你的需求;/proc/version
文件会提供更多信息。不过,uname -r
命令总结了信息。这个系统是属于你的,你可以做出选择。
如果我们需要列出内核启动时使用的选项,可以通过以下命令显示这些选项:
$ cat /proc/cmdline
到这个阶段,我希望你对什么时候根文件系统实际上并不是真正的根文件系统,以及什么时候它可以是根文件系统有了更多的理解。现在,你准备好随时使用这个谜题来困惑你的同事了。实际上,这只是知道存储内核的分区在哪儿的问题;它将成为可启动分区的根。操作系统根是我们通常认为的根文件系统,但只有当系统完成启动过程后,才会这样认为。内核指令简单地指向内核文件,其路径是相对于启动分区根的路径,可能还包括我们希望在加载内核时传递给内核的任何选项。
提示
/proc
目录是一个伪文件系统,这意味着它是临时的,只存在于内存中。它包含当前运行系统的最新信息。这个目录值得你去熟悉。
向一个条目中添加 initrd
与kernel
指令类似,initrd
指令将指向初始化 RAM 磁盘;它是一个与访问操作系统根文件系统所需的驱动程序一起编译的迷你操作系统。RAM 磁盘在内核之前加载,并将操作系统根文件系统以只读模式挂载。在将其交给内核继续启动过程并挂载为读写之前,会执行文件系统完整性检查。这意味着内核不必将根文件系统的驱动程序内部编译,从而允许对操作系统根目录进行更多灵活的更改,并且内核更加精简。如果根文件系统发生变化或需要访问硬件的驱动程序发生变化,可以使用mkinitrd
命令重新编译 RAM 磁盘。
继续我们的示例配置段,我们可以插入一行initrd
指令,如下所示:
title CentOS 6.5 OS
root (hd0,0)
kernel /boot/vmlinuz.version root=/dev/sda1 resume=/dev/sda2
initrd /boot/initramfs.version
为了不被前面简单的文本超越,以下截图展示了我的 CentOS 6.5 系统中一个实际 GRUB 配置段的摘录。
在 GRUB 控制台工作
当看到 GRUB 菜单时,除了选择我们希望启动的项外,我们还可以编辑现有项或进入 GRUB 控制台。通过在 GRUB 控制台工作,我们可以输入自己的一组命令。记住每个配置段应伴随的三部曲:
-
root
-
kernel
-
initrd
我们可以输入这些命令,但如果需要,也可以重新安装 GRUB。更简单地说,在控制台中,我们还可以编辑或附加到现有条目;使用e键,我们可以编辑一个条目,a键可以用来将选项附加到内核行。从以下截图中,我们可以查看这些选项:
编辑内核参数允许你指定要启动的运行级别目标;使用此方法,可以重置 root 用户的密码。
为了恢复忘记的 root 密码,我们可以将系统启动到运行级别 1;默认情况下,这将直接以 root 身份登录。
-
首先,我们必须选择菜单中要启动的项。如果有多个选项,请不要按Enter键。
-
高亮菜单项后,选择字母a。
-
这将直接带你到内核行的末尾,在那里你可以添加数字 1 以启动到运行级别 1。
注意
需要注意的是,CentOS 系统管理要点假设内核参数中尚未指定先前的运行级别。
添加数字后,只需按Enter键,系统将启动到单用户模式并以 root 身份登录。一旦系统启动后,你可以使用passwd
命令有效地更改密码。
是可以防止这种行为的;我们必须小心,以避免阻止服务器的真正恢复机制。如果服务器有足够的物理保护,或许我们不需要做任何修改。然而,如果我们无法确保服务器的物理安全性,我们可以编辑/etc/sysconfig/init
文件,将SINGLE=/sbin/sushell
行更改为以下内容:
SINGLE=/sbin/sulogin
sulogin
命令将提示输入 root 用户的密码。
提示
如果已设置sulogin
并且你仍然需要以 root 身份进行紧急访问,可以通过将运行级别指定为init=/bin/bash
而不是 1 来实现。
如果我们的启动情况有点严重,或者用人话说,系统无法启动,那么我们可以使用选项c
进入 GRUB 命令提示符。通过使用help
命令,我们可以确定在最小化的 shell 中可以使用哪些命令。要重新安装 GRUB 并正确加载驱动程序以访问启动分区,可以执行以下命令:
grub> setup(hd0)
上述命令将检查/boot/grub/stage1
或/grub/stage1
是否存在于可启动分区上。通过这种方式,它确定要使用哪个分区作为根,并将stage1
文件复制到 MBR 中,并附带访问可启动分区所需的驱动程序。然后,我们可以选择通过reboot
命令重新启动系统。
我们不仅可以使用 GRUB 控制台来修复 GRUB,还可以用它来启动系统并验证菜单项。通过指定用于启动的根文件系统,我们可以检查访问内核和initrd
所需的路径。我们可以在 GRUB shell 中使用正常的 Tab 键补全来查看目录和文件名。
用密码保护 GRUB 菜单
现在我可以想象,所有关于从物理服务器获取 root 访问权限的谈话可能会让人感到相当震惊;事实是,这其实不应该让人担心,因为保护物理服务器的访问通常并不难或繁重。然而,如果希望或需要进一步加强安全性,可以通过 GRUB 密码轻松实现。任何密码设置通常会添加到在任何小节之前的全局部分。首先,让我们在设置密码之前回顾一些 GRUB 的全局选项。
在访问 CentOS 中的/boot/grub/menu.lst
文件时,我们会看到文件的第一行是被注释掉的,并且是由安装程序anaconda生成的,文件名为grub.conf
。
menu.lst
文件确实存在于 Red Hat 和 CentOS 中,但它是作为指向/boot/grub/grub.conf
的符号链接。根据传统 GRUB 文档,文件应该是menu.lst
;CentOS 提供了这个链接,但我认为这个文件更合理的名称应该是grub.conf
。
为了方便访问,符号链接/etc/grub.conf
通过/boot/grub/grub.conf
文件链接。然后,可以按如下方式访问该文件:
/boot/grub/grub.conf
/boot/grub/menu.lst
/etc/grub.conf
default
指令将在超时前如果没有做出选择时,指引 GRUB 到默认的小节或条目。
default=0
timeout=5
hiddenmenu
在此,如果菜单加载后 5 秒内没有做出选择,我们将选择第一个段落,即段落 0。指令 hiddenmenu
会阻止菜单显示,除非按下 Esc 键。这在菜单中只有一个条目时尤为有用,这种情况很常见,因此非常合理且实用。
如果你需要防止用户选择菜单以外的选项,那么我们可以在全局设置中添加密码。这将确保,除非输入密码,否则只能选择菜单中提供的条目,且进入 GRUB shell 或附加、编辑条目的选项将被限制。以下代码片段演示了如何实现这一点:
default=0
timeout=5
hiddenmenu
password=secret
如果你不喜欢在 GRUB 菜单文件中看到明文密码,那么可以使用 grub-md5-crypt
命令。你可以按如下方式添加加密的密码:
default=0
timeout=5
hiddenmenu
password --md5 <password-hash>
你也可以直接为某个段落添加密码。为段落添加密码确保用户只有在知道密码的情况下才能从菜单中选择该选项。这样,如果你愿意,你总可以在菜单中设置一个运行级别 1 的条目,但可以通过密码进行保护,如下所示。
title CentOS 6.5 Single User
password --md5 <password-hash>
root (hd0,0)
kernel /boot/vmlinuz.version root=/dev/sda1 resume=/dev/sda2 1
initrd /boot/initramfs.version
使用 plymouth 启动画面
一旦我们开始引导过程,并在将控制权交给内核之前,就可以显示启动画面。如其名所示,这控制了你在启动过程中可能看到的启动画面。在 CentOS 中,默认使用的是 plymouth 主题:rings。Plymouth 是启动画面管理器;如果需要,我们可以使用其他主题。部分主题是作为标准预装的,其他则包含在标准仓库中。更多主题可以在第三方仓库中找到。
当然,你可以构建自己的主题。实际上,一个最小的主题仅仅是一个壁纸。
应用不同的主题
在大多数启动过程中,除非 CentOS 是你的桌面机器,否则你不会看到启动画面。然而,我仍然建议使用 plymouth 将默认启动画面从 rings 更改为 basic。使用 basic 主题时,我们可以看到在启动过程中加载的服务,而不是仅仅显示启动进度的圆环。我谦虚地建议,如果你在启动过程中看到服务器界面,可能表示有问题,你可能希望看到加载的服务及其返回的消息。如果你想采取更轻松的方式,可以尝试 solar 主题。这个主题展示了一个行星和一些绕行的陨石,以说明启动过程。
在命令行中,我们显示默认主题如下所示:
$ plymouth-set-default-theme
要显示系统上可用的主题,我们可以使用如下命令:
$ plymouth-set-default-theme --list
CentOS 默认提供三个主题,如下所示:
-
details:此主题显示我们加载的服务
-
rings:这是默认主题,包含 CentOS 标志,标志下方有一个旋转的圆环
-
text:这是一个空白启动画面,只有显示器底部的水平进度条
所有这些主题都位于路径 /usr/share/plymouth/themes
的子目录中。如果我们想要将主题更改为details
,可以使用以下命令进行。请注意,此命令需要几分钟来运行,因为该过程会重新构建 RAM 磁盘以包含新主题。
# plymouth-set-default-theme --rebuild-initrd details
完成这些步骤后,您可以重新启动系统,看到系统关闭时的不同之处。不再是无尽的环形进度条,我们将看到来自服务的有意义的关闭消息。
如果我们想要更加冒险,那么标准的 CentOS 软件仓库中还包括额外的主题:
-
渐显
-
太阳
-
spinfinity
要安装并设置主题spinfinity
,请执行以下命令:
# yum -y install plymouth-theme-spinfinity
# plymouth-set-default-theme --rebuild-initrd spinfinity
从 spinfinity 主题的部分截图如下所示:
摘要
好了,我们到了又一个辉煌章节的结尾!你,我亲爱的读者,是的,就是你(这里只有你一个人),离进入 Linux 名人堂又近了一步。
我们现在应该已经能够理解,GRUB 是企业版 Linux 中常用的引导加载程序,它将包含用于启动操作系统的各种段落。每个段落包括三个命令。这三个命令组成的三巨头分别是 root、kernel 和 initrd。我们还确保能够编辑 GRUB 菜单并通过加密和非加密的密码牢固保护 GRUB 控制台。
最后,我们来到了浅水池,一个夏日傍晚的 Linux 水上游泳池,在这里,学习使用 plymouth 启动画面。这为 Linux 一天的黎明和黄昏增添了一抹色彩,或者在 spinfinity 的情况下增添了大量红色。
在接下来的部分中,我们将进入 CentOS 中的 Linux 文件系统,了解它们的组成和结构。从基于磁盘或逻辑卷的传统系统开始,我们将调查文件名与索引节点之间的关系,以及索引节点与数据之间的关系。然后,我们将深入研究链接、管道和套接字,最后,以查看Better FS(btrfs)结束。
第三章:CentOS 文件系统——更深入的探索
所以我们知道我们的文件系统由文件和目录组成;它们都是文件,只是类型不同。那么,链接、管道和套接字呢?它们是什么,又是如何使用的?为什么我们要谈论链接?硬链接和软链接有什么区别?我想我需要坐下来思考一下。我能感觉到一阵晕眩即将来临。
让我们也挑战传统的文件系统设计;你可能曾经使用过逻辑卷管理器(LVM),但是让我告诉你那已经是上个世纪的事了。你将会被 BTRFS(Better FS)强大和简便的企业级文件系统管理所震撼。我们将在本章涵盖以下几个部分:
-
魔术师的秘密:我们揭示如何在不实际计算的情况下计算子目录的数量。
-
特殊权限:这将涵盖
wall
命令的尾部以及它如何与 GUID 位结合使用。 -
命名你的管道:我敢肯定你不希望没有名字,而你的管道也是如此。我们来探讨如何使用命名管道来实现进程间通信(IPC)。
-
理解命令 stat:这将涵盖你需要了解的所有有关 inode 和文件元数据的知识。
-
企业级文件系统对决:在 BTRFS 与 LVM 的对决中,BTRFS 毫无悬念地获胜。我们将看看 BTRFS 中的新特性,并探讨如何使用快照和扩展卷。
一个魔术师的秘密
我们知道这个世界上有很多团体的人可以也常常让我们烦恼;魔术师可能就是这些人之一。他们让我们烦恼是因为我们不知道他们是如何做到他们所做的;简单来说,我们知道自己被愚弄了,但却不知道具体怎么回事。好了,让我来打破魔术师圈子的荣耀,揭示一个可以用来愚弄你同事的小技巧,确保你会觉得这个技巧值得知道。
让我给你演示一下,如果我在我的 CentOS 6.5 系统上运行以下命令,我将看到指定的doc
目录的长列表:
$ ls -ld /usr/share/doc
我系统上的输出如下:
drwxr-xr-x. 758 root root 36864 May 1 09:09 /usr/share/doc
显示的第一个数字,758
,是链接计数。这表示与文件元数据硬链接的文件名数量;简单来说,这个目录有 758 个不同的名称。
从这个值出发,我可以明确地声明这个目录有 756 个子目录!
“这不是火箭科学,就是从一个数字中减去 2”
公式很简单!对于给定的目录,子目录的数量等于硬链接计数的两倍。
我想是时候进一步调查一下了。当一个新目录被创建时,它的链接计数会初始化为 2;换句话说,每个新目录必须有两个指向它的名称。这包括目录名和名为 .
(就是一个句点)的文件。
事实上,在一个新目录中,通常会同时创建两个新文件: .
和 ..
文件。
-
.
文件代表目录本身 -
..
文件代表父目录
自己试试;这样理解会更容易,也许能防止你过于迷惑:
$ cd
$ mkdir newdir
$ ls -a newdir #Note the two files
$ ls -ld newdir # Note the hard link count of 2
以下截图显示了新目录以及其中两个隐藏文件的列表。BASH 中的颜色编码将这两个文件突出显示为蓝色,表示它们代表目录:
我相信,当你仔细思考时,你会发现我们总是使用点符号作为一种简写形式。请看以下使用 cp
复制命令的代码:
$ cp /etc/hosts .
在这里,我们使用单点符号从 /etc
目录复制 hosts
文件到当前目录。在下面的示例中,我们使用 cd
命令切换到父目录:
$ cd ..
现在我们可以开始理解目录的链接计数是如何与子目录数量相关的。如果文件名由两个点组成,表示父目录,那么对于我们在给定目录中创建的每个子目录,我们将会有一个新文件指向父目录。这些双点文件是硬链接到子目录的父目录的。
硬链接
在 Linux 文件系统中,我们有两种类型的链接:硬链接和软链接(或符号链接)。硬链接,正如我们所见,是文件的名称或多个名称。一个普通文件在首次创建时只有一个名称。我们可以使用 ln
命令为文件添加更多名称:
$ cd
$ echo "Hello" > my_newfile
$ ln my_newfile the_samefile
$ ls -li my_newfile the_samefile
我们将按照以下步骤演示我们在系统上执行的操作:
-
我们移动到主目录。
-
然后,我们创建一个新文件,内容是
Hello
。 -
ln
命令将原始文件链接到一个新名称the_samefile
。现在我们有两个文件名指向相同的元数据。两个文件的硬链接计数将为二;这两个名称指向相同的元数据。 -
使用
ls
命令并带上长列表选项-l
,将显示硬链接计数。选项-i
将显示文件的 inode 号。两个文件的 inode 号将是相同的。由于硬链接共享相同的 inode 号,源文件和目标文件必须位于同一个文件系统中。inode 是单个文件系统中的一个条目。
符号链接
符号链接,或有时称为软链接,是完全独立的文件,其数据指向另一个文件名;因此,它们可以跨越文件系统边界,比硬链接更有用。符号链接的文件类型为l
,表示它们是一种特殊类型的文件。硬链接是常规文件,仅能通过硬链接计数来识别为链接。符号链接不会影响文件的硬链接计数;它们是完全独立的文件,拥有自己的名称、inode 和数据。符号链接的数据是指向目标文件的指针。在以下代码段中,我们可以看到符号链接的创建和显示:
$ cd
$ ln -s my_newfile the_linkedfile
$ ls -l the_linkedfile
让我们按照以下步骤在我们的主目录中创建一个符号链接:
-
我们首先移动到我们的主目录。
-
ln
命令将原始文件链接到一个新名称the_linkedfile
。选项-s
将创建一个软链接。 -
使用
ls
命令,其中选项-l
用于长列表格式,我们可以从输出中看到,第一个字符表示文件类型,显示l
表示该文件是符号链接。扩展输出还会显示目标文件的位置。
特殊权限
文件的权限或模式是我们熟悉的读取、写入和执行(RWX)。这些权限可以应用于三个对象:
-
用户
-
组
-
其他用户
标准权限通过其八进制表示形式展示,如果你想快速复习,可以参考如下:
在用户、组和其他权限之前,还有一个权限块。这一块用于特殊权限;但是,它并不表示 RWX,而是包含以下内容:
-
设置用户 ID 位(SUID)
-
设置组 ID 位(SGID)
-
Sticky 位
使用符号表示法,这些权限可以添加到file1
,在接下来的演示中file1
充当文件名的公理:
$ chmod u+s file1 #adding the SUID Bit
$ chmod g+s file1 #adding the SGID Bit
$ chmod o+t file1 #adding the Sticky Bit
设置用户 ID 位(SUID)
设置用户 ID 位(SUID)用于程序需要以除运行该程序的用户之外的其他用户 ID 运行时。当设置该位时,程序将以文件所有者的权限运行,而不是当前用户的用户 ID。这通常应用于某些简单程序;例如,密码程序/usr/bin/passwd
就设置了这个权限。这样做是因为普通用户可以更改自己的密码,但没有权限写入/etc/shadow
文件,密码正是存储在该文件中。无论谁启动该程序,程序都将始终以 root 用户身份执行。
如果你感到好奇,想看看系统中有多少文件包含此权限,那么find
命令可能会对你有所帮助:
$ find / -perm +4000
命令会按原样搜索操作系统根目录/
,查找包含 SUID 位的文件,-perm +4000
。
设置组 ID 位(SGID)
与设置 UID 位类似,如果在可执行文件上设置了 SGID 权限,则程序将以文件所属组的组 ID 而不是当前用户的组 ID 来运行。这在 /usr/bin/wall
文件中默认设置,我们将通过执行以下命令再次深入了解:
$ ls -l /usr/bin/wall
从输出结果来看,权限为 r-xr-sr-x
。小写字母 s
表示已经设置了 SGID 和执行权限。如果是大写字母 S
,则表示没有为组设置执行权限。
查看 /usr/bin/wall
程序时,我们应该理解,这个程序用于向用户控制台发送消息;它是由 tty
组拥有的。通过设置 SGID 位,当任何用户执行这个程序时,他或她将以 tty
组的权限来运行。
登录到控制台的用户可以通过在 mesg
命令中使用 y
或 n
选项来控制这些消息:
$ mesg #without options displays the current messaging state
$ mesg y #enables messages to be received in the console
$ mesg n #disables messages from being received in the console
我们本可以在这里结束,理解我们只是在启用和禁用控制台的消息传递功能。我们可以这么做,但这样我们就无法学习到与 SGID 位和 wall 程序之间的关系,也无法解锁理解所带来的知识泉源。在控制台中,我们将确定当前连接的是哪个控制台;tty
命令将在这里帮助我们。我的系统输出显示 /dev/pts/1
。使用以下命令获取该设备文件的详细列表,将显示文件类型和权限。文件类型为 c
,表示这是一个字符设备:
$ ls -l /dev/pts/1
从输出结果来看,我们可以看到文件的权限;组所有者是 tty
,如果启用了消息传递,组将具有写权限。如果禁用了消息传递,组将没有权限。我们可以结合两条命令,使用我们在第一章《驯服 vi》中首次看到的括号扩展:
$ ls -l $(tty)
括号中的内容会首先被计算;计算结果会通过ls -l
命令进一步处理。
在下图中,由于组没有写权限,消息传递已被禁用:
当我们启用消息传递并查看以下截图中的输出时,我们可以看到,神奇的是,现在组权限中已经显示了写权限:
我们现在已经稍微了解了一下本章开头提到的 Linux 魔法。此外,我们还看到了如何通过 /usr/bin/mesg
命令控制 /usr/bin/wall
命令的使用,从而将其应用于实际的 Linux 问题。
然而,SGID 的作用不仅仅局限于可执行文件。SGID 位也可以设置在目录上。当设置在目录上时,SGID 位确保目录中创建的所有新文件都由目录中的组所有。为了更好地理解这一点,假设我们的网页服务器的文档根目录(即网页存放位置)设置为 /var/www/html/
目录。如果我们将该目录的组所有权设置为 apache
组,那么我们就可以使用 SGID 位来保持所有创建文件的正确所有权。以下命令展示了这个复杂的操作:
# chgrp apache /var/www/html
# chmod g+s /var/www/html
# ls -ld /var/www/html
现在,每个在 /var/www/html
中创建的新网页将自动由 apache
组拥有。我们现在已经看到了 SGID 位在可执行文件和目录上的有效性。
粘滞位
最后的特殊权限是粘滞位。它用于目录,并在 CentOS 默认安装时设置在 /tmp
目录上。删除文件的能力由目录权限控制,而不是如一些人所想的那样,由文件的权限控制。当你创建或删除文件时,你实际上是在对目录进行操作。这意味着,在一个像 /tmp
这样的共享目录中,所有用户都可以写入该目录,因此,用户有可能删除任何文件。为了将删除权限限制为用户拥有的文件,粘滞位被应用于该目录。要将粘滞位权限添加到 /data
目录,我们可以使用以下命令:
# chmod +t /data
给管道命名
我相信我们都遇到过竖线或管道字符 |
;我们可以使用它来创建命令管道,将一个命令的输出传递到另一个命令的输入。作为简单示范,我们可以使用以下命令,来说明我们通常会如何使用无名管道:
$ yum list installed | grep plymouth
第一个命令 yum list installed
列出所有已安装的软件包,结果会非常庞大;为了减少内容,我们使用第二个命令 grep
搜索 plymouth
字符串。两行代码通过一个无名管道连接在一起。之所以说它是无名的,是因为它是暂时的,只在两个命令运行的实例中存在,而这段时间的长度要比蜉蝣的寿命还短。
这种短暂的特性在每种情况下可能并不总是有用,这时我们可以创建命名管道,它是具有管道类型的文件。文件可以是以下几种类型之一:
-
普通文件
-
目录
-
符号链接
-
套接字
-
命名管道
-
字符设备
-
块设备
你应该对前三种类型非常熟悉,但我们通常较少看到其他类型,尽管我们在前一节中看到过字符设备文件/dev/pts/1
,当时我们在查看 SGID 位时。字符设备实际上就是我们可以访问的终端。在这里,我们希望将焦点保持在管道的文件类型上,其中一些可能已经存在于你的文件系统中。我们可以使用find
命令来查找它们,搜索文件类型为p
的文件:
$ find / -type p 2>/dev/null
作为标准用户运行此命令时,你可能会遇到与我们没有权限的目录相关的错误;在这种情况下,通常更容易将错误重定向到/dev/null
,正如我们在这里所做的那样。系统上运行autofs
服务将创建命名管道:/var/run/autofs.fifo-misc
和/var/run/autofs.fifo-net
。
命名管道允许不同的进程相互通信或进行进程间通信。使用无名管道时,进程总是运行在同一父级层次结构中,换句话说,它们运行在相同的 BASH shell 中。因此,它们有用,但仅限于我们和我们狭隘的世界。然而,命名管道则打开了一个命令的输入,允许任何在该系统上运行的进程访问,而不考虑进程层级结构。这或许类似于你第一次意识到,世界上有比怀特岛更多的度假地的那一刻。像autofs
服务这样的服务进程可能会连接到命名管道的输出,等待系统上客户端的输入,将我们从面对内向的小圈子(即无名管道)解放出来,进入更广阔的通信空间。
解释命名管道如何工作的最简单方法是通过演示它们。那么,为什么不打开两个终端窗口呢?如果更方便的话,这些可以是桌面上的图形终端。我将通过我的标准帐户保持登录状态,进入这两个窗口。
在第一个终端窗口中,我们可以输入以下一组命令:
$ cd #move to your home directory
$ mkfifo my-pipe #create a named pipe called "my-pipe"
$ ls -l my-pipe #will list the file as type p
$ wc -l < my-pipe #We read in from the pipe and count the lines. As nothing is connected to the input we wait for something to process.
当第一个窗口等待输入时,我们可以切换到第二个终端窗口,并将数据输入到管道的输入端:
$ cd #move to your home directory where the pipe is located
$ ls > my-pipe #send the output of the ls command to the pipe
当我们在第二个终端中输入ls
命令并查看输出时,第一个窗口将立刻显示结果。通过这样做,我们已经使两个独立的进程能够相互通信。
理解命令 stat
CentOS 命令行充满了工具,尝试学习它们所有的工具可能是一辈子的工作。就像所有任务一样,到达终点线的第一步始于第一步。我们的第一步将是深入了解/usr/bin/stat
命令的世界。通过使用此命令,我们可以查询文件的元数据。CentOS 中的文件由以下部分组成:
-
文件名(硬链接)
-
文件元数据(inode)
-
数据
仅使用stat
命令和文件名,我们可以查看完整的 inode 元数据。通过以下命令组可以演示这一点:
$ cd #move to your home directory
$ ls > my_newfile #list the contents and redirect the output to the new file
$ stat my_newfile #display the inode metadata
以下截图显示了stat
命令的输出:
我们可以看到完整的元数据被显示出来,但如果我们选择的话,也可以只显示元数据的某些元素;例如,要以八进制格式显示文件权限,请运行以下命令:
$ stat -c%a my_newfile
要以人类可读的格式显示权限,请运行以下命令:
$ stat -c%A my_newfile
输出将显示664
和-rw-rw-r
,分别表示权限。inode 始终以八进制格式存储权限,但许多命令,如ls
和stat
,可以将其转换为更友好的格式。
inode 中存储了三个时间戳:
-
最后访问时间
-
最后修改时间
-
最后更改时间
最后访问时间
文件的最后访问时间列出了文件最后被读取的时间。这取决于文件系统是否维护最后访问时间;有一个挂载选项noatime
可以防止最后访问时间被更新。要列出文件的最后访问时间,可以运行以下命令:
$ stat -c%x my_newfile
对我来说,当前时间是 10:12。如果我现在读取文件并再次运行命令,时间将发生变化:
$ less my_newfile
$ stat -c%x my_newfile
当前时间显示为 10:28。这对于了解系统中文件是否被读取非常有用。如果没有被读取,则可能意味着这些文件不再需要,可以归档到其他设备上。
最后修改时间
文件的最后修改时间表示文件本身何时被更改,即文件的数据。如果我们编辑文件然后检查最后修改时间,它将发生变化。
$ ls >> my_newfile #we now append another listing to the file
$ stat -c%y my_newfile #displays the last modified time
现在的时间是 10:36,而原始内容创建时是 10:12。
提示
ls -l
命令的输出还会显示文件的最后修改时间。
最后更改时间
文件的最后更改时间与元数据更改的时间相关,而不是文件数据的更改时间。例如,改变文件权限将会更改最后更改时间:
$ chmod 640 my_newfile
$ stat -c%z my_newfile
我的系统现在显示文件的元数据在 10:41 时被更改。
企业文件系统对抗
LVM 已经是管理磁盘增长的方式多年,允许逻辑卷跨多个磁盘并通过快照进行备份。尽管 LVM 非常好,但仍然需要文件系统放在逻辑卷之上,因此会涉及额外的管理层级;需要记住的是,LVM 系统本身有三层管理:
-
物理卷:这些是提供给 LVM 系统的磁盘空间。
-
卷组:这些用于组织物理卷,以便提供给用户使用。
-
逻辑卷:这些占用了通过卷组提供的磁盘空间,并被呈现给文件系统工具进行格式化。
现在,仅仅因为我们在过去的十年左右使用过这些软件,并不意味着它可以毫无挑战地继续存在,即便是在企业中。我们现在看到B 树文件系统(BTRFS)被称为更好的文件系统,正在 Linux 中逐步普及。BTRFS 在版本 0.20 中可以安装,并且可以在 CentOS 6.5 上使用,尽管需要注意,它被标记为实验性。
BTRFS 的优势
目前 Linux 内核树中有超过 55 种基于内核的文件系统,我们真的需要另一个吗?这里的第一个问题是,许多文件系统有着有限的或非常特定的使用场景;只有像 ext2、ext3 和 ext4 这样的 extN 文件系统才是通用的,尽管这些文件系统的最新版本 ext4 的大小限制为 16TB。BTRFS 扩展到 16 艾字节(EB),并带来了以前未曾出现的可靠性功能,具体如下:
-
非常快速的文件系统创建
-
数据和元数据校验和
-
快照功能
-
在线修复以解决问题
安装 BTRFS
在我使用的 CentOS 6.5 演示系统上,我们首先需要安装 BTRFS:
# yum install -y btrfs-progs
现在我们已经安装了相关工具,可以开始体验 BTRFS 的强大与简洁。我的实验室计算机当前在第二块硬盘上有四个额外的空闲分区;每个分区大小为 1GB,用于以下演示。
创建 BTRFS 文件系统
为了开始今天的演示,我们首先将在一个 1GB 的单一分区上创建一个 BTRFS 文件系统,将其挂载到/data
目录,并按如下方式复制一些数据:
# mkfs.btrfs /dev/sdb5
# mount /dev/sdb5 /data
# find /usr/share/doc -name '*.pdf' -exec cp {} /data \;
# btrfs filesystem show /dev/sdb5
从这些命令中,你会看到我们复制了一些现有的 PDF 文件,为演示提供了真实数据,确保在演练过程中不会丢失数据。最后的命令行显示了文件系统并确认其大小为 1GB。
扩展 BTRFS 文件系统
我们可能会发现/data
结构中的空间即将用完;虽然目前还没有用完,但我们可以设想一下。如果我们使用的是 LVM 结构,我们就必须运行几个命令来扩展现有文件系统,跨越新的分区或磁盘。这将是 LVM 中的过程:
旧方式的卷管理要求我们执行以下命令:
# pvcreate /dev/sdb6
# vgextend vg1 /dev/sdb6
# lvextend -L+1000M /dev/vg1/data_lv
# resize2fs /dev/vg1/data
使用 BTRFS 进行卷管理
如我们所见,执行这些命令时有四个步骤,所有命令都有一定的语法难度,容易让我们出错。我们现在可以看到如何使用 BTRFS 来完成这一过程:
# btrfs add device /dev/sdb6 /data
就是这样!我们所需要做的就是这些,现在我们已经有了一个 2GB 的卷。我们可以通过以下命令确认这一点:
# df -h /data
# btrfs filesystem show /dev/sdb5
两个命令将确认我们现在在卷中有 2GB 的可用磁盘空间,数据仍然存在且可以访问。卷的元数据被复制到两个分区中。通过这种方式,我们可以从任意设备查看卷信息:
# btrfs filesystem show /dev/sdb5
# btrfs filesystem show /dev/sdb6
两个命令将显示相同的数据,因为它们的元数据存储在两个设备上。
平衡文件系统
如果我们真的因为原始卷的磁盘空间不足而添加了额外的分区,那么我们现在可以按照以下方式平衡整个卷中的数据:
# btrfs balance start -d -m /data
-m
参数表示元数据,-d
表示数据。通过这种方式,磁盘会均衡使用。
添加条目到 /etc/fstab
一般来说,我们希望 /data
目录在启动时挂载,因此我们会在 /etc/fstab
文件中添加条目。在从该文件挂载时,我们必须引用所有的设备:
/dev/sdb5 /data btrfs device=/dev/sdb5,device=/dev/sdb6 0 0
通过这种方式,我们在 BTRFS 扫描不可用时指示设备构建的早期挂载过程。
创建一个 RAID1 镜像
软件冗余便宜磁盘阵列(RAID)也被 BTRFS 支持。目前支持的 RAID 级别如下:
-
RAID 0: 没有冗余的条带化
-
RAID 1: 磁盘镜像
-
RAID 10: 条带化镜像
如果需要,我们可以使用 BTRFS 软件镜像创建一个镜像设备。这并不会为我们提供额外的磁盘空间,但在磁盘故障的情况下提供容错能力。我们可以在我们的设置中模拟这一点,但因为所有分区都在同一块磁盘上,它对磁盘故障没有帮助,但这个概念是成立的。
# mkfs.btrfs -m raid1 -d raid1 /dev/sdb7 /dev/sdb8
# mount /dev/sdb7 /mirror
创建镜像时,我们分别使用 RAID1 为元数据和数据 -m
和 –d
。可用的磁盘空间是 1 GB。我们写入/dev/sdb7
的内容会镜像到/dev/sdb8
;使用镜像时,我们失去 50% 的数据存储,但获得了较高的冗余性。
我们需要再次向 /etc/fstab
文件添加条目,如前所见,以确保系统在启动时正确挂载:
/dev/sdb7 /mirror btrfs device=/dev/sdb7,device=/dev/sdb8 0 0
使用 BTRFS 快照
分析到目前为止,BTRFS 还是挺酷的,你不觉得吗?不过,我们还没有完全挖掘它所能提供的所有优势。快照可以作为只读或读/写的数据副本来使用。实际上,没必要复制数据,因为它们在未改变的情况下是有效链接的。通过这种方式,可以瞬间创建一个大型文件系统的快照。你可以通过以下方式使用快照:
-
作为备份解决方案的一部分,如果你担心打开的文件会影响备份,可以创建只读快照,随后你可以备份该快照。通过这种方式,备份将是快照创建时主机文件系统的状态。
-
快照在你知道很多文件会在某个结构中发生变化,并且你可能希望快速恢复原始文件的情况下非常有用。比如当你使用脚本修改多个文件时,如果脚本的效果不如你预期、想象或希望的那样,你可以轻松地恢复到快照副本。
快照必须在与目标数据相同的文件系统中创建;正如我们之前提到的,快照的快速创建受到文件系统内部链接方式的影响。在 BTRFS 文件系统中,我们可以创建子卷。子卷允许在 BTRFS 文件系统中进行独立的管理标识。我们将对一个 BTRFS 子卷进行快照,并将其存储在同一文件系统中的另一个子卷中。
为了实现这一点,我们将在/data
BTRFS 文件系统中定义两个子卷。定义子卷将创建文件系统中的目录以及 BTRFS 子卷实体。我们将创建第一个子卷的快照,并将其存储在同一/data
文件系统中的第二个子卷中。我们不能对整个文件系统创建快照,因为快照的更改需要写回自身,这会导致无限递归;相信我,无限递归不是一件好事,不是好事,不是好事……
让我们首先创建这两个子卷:
# btrfs subvolume create /data/working
# btrfs subvolume create /data/backup
我们可以使用以下命令轻松列出子卷:
# btrfs subvolume list /data
在子卷到位之后,我们可以将现有数据移动到/data/working
目录,从而让一些数据准备好进行快照。顾名思义,工作目录应该是存储我们实际数据的地方,它是我们组织的命脉。如果这些数据发生故障,我们的组织也会随之崩溃,我们也会失去工作。因此,理应小心管理这些数据。
# mv /data/*.pdf /data/working
我们的场景是测试可能根据最后访问时间删除文件的脚本;我意识到我们不应该使用实时数据,但生活在边缘的感觉能让我们原本单调的生活充满活力。话虽如此,我们还没有完全失去对这些数据重要性的感知。在运行脚本之前,我们会创建一个数据的只读快照。
要创建工作子卷的只读快照,请执行以下命令:
# btrfs subvolume snapshot -r /data/working /data/backup/first-run
我们可以像之前一样使用以下命令列出可用的子卷:
# btrfs subvolume list /data
从输出中,我们可以看到快照显示为一个新的子卷。列出两个目录的内容应该表明它们的内容是相同的:
# ls /data/working
# ls /data/backup/first-run
first-run
这个名称并不重要,但也许我们可以根据脚本第一次运行前、第二次运行前的数据创建多个快照。在这个阶段,快照实际上并没有占用任何空间,因为源和目标中的数据是相同的。如果我们删除了/data/working
中的所有文件,那么 BTRFS 中的写时复制(COW)技术将会在/data/backup/first-run
中创建这些文件。如果这些文件以任何方式被修改而不是删除,情况也是一样的;快照会保留文件在创建快照时的状态。在发生灾难时,我们可以简单地将文件复制回原始位置。
摘要
本章带领我们深入了解了 CentOS Linux 中的文件系统结构,并使我们能够探索像 BTRFS 这样的新技术。我们从了解如何通过ls
或stat
命令查看硬链接数量开始。这个数量显示了多少个文件名与一个 inode 或文件元数据相关联。理解文件的元数据使我们进一步研究了/usr/bin/stat
以及它提供的选项,包括三种时间戳,它们不是末日预兆,而是文件本身的时间戳:最后访问时间、最后修改时间和最后更改时间。
一点关于特殊权限的探讨让我们了解了用户如何启用和禁用控制台消息,控制台文件由tty
组拥有,写入权限可以被添加或移除。
最后,我们沐浴在 BTRFS 文件系统的荣耀中。这真的是一个现在就开始使用的技术,因为它将是未来几年内企业级文件系统的首选。将文件系统和卷管理合并在一个任务中,简化并极大地提升了管理效率。
现在你需要为 YUM 以及软件仓库管理工具 Yellowdog Update Manager 的盛宴做好准备,确保我们掌握的不仅仅是yum install
这一点。
第四章:YUM – 软件如此美妙
现在是时候全面了解 Yellowdog Updater Modified(YUM)软件仓库系统,以及我们可以使用的各种工具来使其为我们服务。YUM 提供了 Red Hat 包管理器(RPM)软件包背后的强大动力。没有 YUM,你作为管理员需要自己找到 RPM 文件进行安装,并且所有的依赖 RPM 也需要手动处理;而 YUM 会为你做这一切。你将学习到有价值的、不为人知的选项,创建你自己的 RPM 文件,并将其添加到本地仓库中。在本章中,我们将涵盖以下内容:
-
使用 RPM 文件管理软件安装:我们将回顾 RPM 包管理的基础知识。
-
创建你自己的 RPM 文件:你将学习如何创建一个 RPM 文件,在此过程中了解 RPM 软件安装的工作原理。
-
使用 YUM:我们将发现 YUM 的强大,并学习所需的技能,以帮助我们更好地利用系统和网络。
-
YUM 插件:我们将概述 YUM 插件及可以添加到此系统的扩展功能。
-
创建 YUM 仓库:我们将使用 CentOS 的标准软件和我们自己的自定义 RPM 创建自己的仓库。拥有自己的仓库意味着安装源是我们系统的一部分,我们不需要依赖外部连接来安装软件。我们也可以选择与网络中的其他主机共享此仓库,从而增加我们自己仓库的好处。
使用 RPM 文件管理软件安装
Linux 管理中的一个元素,可以提供几乎每天的娱乐体验,就是管理你在 CentOS 桌面和服务器上的软件生命周期;这包括安装、更新和删除软件,软件的形式可以是程序、文档、驱动程序,或者任何在 Linux 中由一个或多个文件组成的内容。使用 RPM 文件安装软件比使用安装脚本更为推荐。通过基于 RPM 的安装,我们始终可以查询数据库,获取当前系统上已安装软件的信息。软件删除变得更加简化,因为我们有一个软件包添加的清单,并且知道哪些内容需要被删除。RPM 管理的一个大缺点是我们在安装需要其他软件的 RPM 文件时可能遇到的依赖地狱。我们可能能够找到所需的 RPM 文件,但在尝试安装第一个依赖包时,肯定会有更多的依赖关系需要追踪。
一个简单的演示可以是尝试安装 Foxit PDF 阅读器;它是 Adobe Reader 的轻量级替代品。如果我们直接从 Foxit 网站下载 RPM 文件www.foxitsoftware.com/downloads/
,我们可以在 CentOS 桌面上安装或尝试安装它。由于缺少依赖项,下面的命令几乎肯定会失败:
# rpm -i FoxitReader-1.1-0.fc9.i386.rpm
我们可以使用以下命令列出依赖项:
# rpm -qpR FoxitReader-1.1-0.fc9.i386.rpm
当我统计系统中的依赖项时,发现直接从这个 RPM 包中需要解决 32 个依赖项;安装这些包时可能还会出现其他依赖项。仅使用rpm
命令安装将需要很长时间。如果我们选择使用以下yum
命令来维护安装,并且连接到具有所需依赖包的仓库,我们会发现整个过程变得容易得多,我也可以回去打高尔夫了!
# yum install FoxitReader-1.1-0.fc9.i386.rpm
回顾一些常用的基本 RPM 命令行语法,我们可以列出以下常用选项:
-
从 RPM 文件安装软件:
rpm -i <example.rpm>
-
卸载 RPM:
rpm -e <example>
-
更新现有的 RPM 或在未安装的情况下安装它。同时,显示进度为哈希标记或百分比:
rpm -Uvh <example.rpm>
或rpm -Uv --percent <example.rpm>
-
列出所有已安装的基于 RPM 的软件:
rpm -qa
-
列出某个文件所属的 RPM:
rpm -qf /etc/hosts
-
列出已安装包中的所有文件:
rpm -ql <example>
-
列出 RPM 文件中的所有文件:
rpm -qpl <example.rpm>
-
查看 RPM 版本:
rpm --version
如果你需要定位 RPM 数据库,它位于/var/lib/rpm
目录下。
你可能注意到,当引用已安装的包时,可以单独使用 RPM 名称,而在使用rpm
命令与 RPM 文件时,必须使用完整的文件名和扩展名。文件名由以下组件组成:
<package><version><release><architecture>.rpm
例如,来看一下Z shell(ZSH)包的 RPM 文件。文件名为:
zsh-4.3.10-7.el6.x86_64.rpm
-
包名称:
zsh
-
版本:
4.30.10
-
版本:
7-el6
-
架构:
x86_64
要验证这一点,可以使用-i
或信息选项查询包文件。在下面的命令中,我们使用-q
进行查询,-p
表示包,前面提到的–i
。
$ rpm -qpi zsh-4.3.10-7.el6.x86_64.rpm
创建你自己的 RPM 文件
尽管我提倡使用 YUM 来管理软件安装,但我们仍然需要 RPM 文件。YUM 完全依赖于底层的 RPM 文件和基础设施;RPM 文件仍然是yum
命令安装的软件包,这些 RPM 文件是 CentOS 软件管理的核心部分。
你可能会想起本书中的第二章,冷启动,当时我们在引导过程中研究了 Plymouth 主题;现在我们将创建一个简单的主题,在系统启动和关机时为我们的桌面或服务器添加公司品牌的壁纸。创建主题后,将其作为 RPM 文件分发到多个系统是最简单的安装方式。本章稍后我们将把 RPM 添加到 YUM 仓库中。
创建 Plymouth 主题
首先,我们必须创建主题,完成后,我们可以将其打包为 RPM 文件。我们的主题将包含三个文件,这些文件将位于一个目录内。该目录需要与它包含的三个文件一起添加到目标 CentOS 系统的/usr/share/plymouth/themes
中的themes
文件夹。
包含主题三个文件的顶级目录通常会以它所属的主题命名。我们正在创建tup
目录来表示我们的主题,如下所示:
# mkdir /usr/share/plymouth/themes/tup
该主题,The Urban Penguin(tup),将包含三个文件:
-
800.png
:这是将在启动画面中显示的壁纸。它必须是一个 PNG 文件。 -
tup.plymouth
:这是包含主题清单的主主题文件。 -
tup.script
:这是主题将运行的操作。这是最简单的基于脚本的主题形式,因此我们需要这个指令文件。
tup.plymouth
tup.plymouth
文本文件是主要的主题文件。
[Plymouth Theme]
Name=tup
Description=The Urban Penguin
ModuleName=script
[script]
ImageDir=/usr/share/plymouth/themes/tup
ScriptFile=/usr/share/plymouth/themes/tup/tup.script
正如我们在之前的示例中看到的,ModuleName
设置为script
意味着我们需要确保在自己的 RPM 中列出 RPM plymouth-plugin-script
作为依赖项。在构建过程中,我们将使用所需的指令将其构建到 RPM 中。
tup.script
Plymouth 脚本模块将在主题运行时执行tup.script
文件。我们创建的脚本将只有一个精灵。精灵会将元素放置到启动画面或在系统启动和关机时看到的壁纸上。壁纸将根据屏幕的大小进行缩放,并确保每一行的末尾包括分号。这里使用的图片是800.png
文件,但你可以使用任何添加到theme
文件夹中的 PNG 文件。以下是一个示例脚本:
wallpaper_image=Image("800.png");
screen_width=Window.GetWidth();
screen_height=Window.GetHeight();
resized_wallpaper_image=wallpaper_image.Scale(screen_width,screen_height);
wallpaper_sprite=Sprite(resized_wallpaper_image);
wallpaper_sprite.SetZ(-100);
创建主题 RPM
为了构建 RPM,我们将作为标准用户工作,可以通过你自己的账户或专门用于构建 RPM 的账户(如果创建该账户,只需添加具有标准权限的本地或网络账户)。不过,最初我们需要 root 权限来安装构建环境所需的包:
# yum install -y rpm-build rpmdevtools
上述命令将安装我们用来创建 RPM 的工具。通过 YUM,我们需要能够连接到一个包含软件的仓库,但无需关心仓库的位置。设置好这些后,我们可以切换到用于打包 RPM 的账户。登录后,我们必须确保自己在主目录中,在那里我们将创建顶级目录,如下所示:
$ cd
$ rpmdev-setuptree
这将创建一个名为rpmbuild
的目录,其中包含五个子目录,可以在下图中看到:
这些目录在构建 RPM 时成为工作目录。
首先,我们将在SOURCES
目录下创建我们需要的目录结构:
$ cd ~/rpmbuild/SOURCES
$ mkdir -p plymouth-theme-tup-1/usr/share/Plymouth/themes/tup
我们创建的顶级文件夹基于将表示最终 RPM 的名称和版本号。名称将是plymouth-theme-tup
,版本将是1
。以下目录代表目标文件系统中的结构;我们需要将目标指向/usr/share/plymouth/themes/tup
目录。
在目录设置好后,我们现在可以将构成主题的三个文件复制到新创建的目录中:
$ cp /usr/share/plymouth/themes/tup/* \
plymouth-theme-tup-1/usr/share/plymouth/themes/tup
现在我们需要创建一个包含文件夹结构的 gzipped 压缩包;在~/rpmbuild/SOURCES/
目录下,我们可以运行以下命令来创建压缩包:
$ tar -czvf plymouth-theme-tup-1.tar.gz plymouth-theme-tup-1/
构建阶段之前的最后一步是创建指令或规格文件。我们可以使用自己喜欢的文本编辑器在~/rpmbuild/SPECS/
目录中创建此文件。我们将命名为~/rpmbuild/SPECS/tuptheme.spec
文件:
Name: plymouth-theme-tup
Version: 1
Release: 0
Summary: TUP Corporate Theme
Group: System Environment/Base
License: GPL
URL: http://theurbanpenguin.com
Source0: plymouth-theme-tup-1.tar.gz
BuildArch: noarch
BuildRoot: %{_tmppath}/%{name}-buildroot
Requires: plymouth-plugin-script
%description
Corporate Plymouth theme displaying the TUP wallpaper
%prep
%setup -q
%install
mkdir -p "$RPM_BUILD_ROOT"
cp -R * "$RPM_BUILD_ROOT"
%clean
rm -rf "$RPM_BUILD_ROOT"
%post
echo ..
echo "Adding theme…"
%files
%defattr(-,root,root,-)
/usr/share/plymouth/themes/tup/800.png
/usr/share/plymouth/themes/tup/tup.script
/usr/share/plymouth/themes/tup/tup.plymouth
这个文件看起来可能很复杂,但大多数设置都很直观。更重要的是?这可以作为任何交付文本文件、脚本、文档或几乎任何不需要编译的内容的 RPM 的模板。如果有需要编译的 C 源文件,我们需要添加一个%build
部分。
有关 SPEC 文件的更多信息,请参阅可以在www.rpm.org/max-rpm/s1-rpm-build-creating-spec-file.html
找到的文档。
现在让我们来构建一个 RPM!
$ cd
$ rpmbuild -bb rpmbuild/SPECS/tuptheme.spec
RPM 文件将被创建在~/rpmbuild/RPMS/noarch/
目录中。我们可以通过命令树的输出查看这个结构,如下图所示:
我们可以验证这些文件是否已正确添加到 RPM 中。这些文件是我们在本章早些时候查看过的主题,并且在 SPEC 文件的%files
部分中进行了引用:
$ rpm -qpl ~/rpmbuild/RPMS/noarch/plymouth-theme-tup-1-0.noarch.rpm
我们还应该验证通过Requires
指令添加到 SPEC 文件中的依赖项:
$ rpm -qpR ~/rpmbuild/RPMS/noarch/plymouth-theme-tup-1-0.noarch.rpm
如果没有脚本插件,RPM 现在无法安装。如果通过 YUM 安装,则依赖项会自动解析并根据需要安装。
使用 YUM
正如我们已经看到的,使用 YUM 管理 RPM 依赖关系要求大大简化了软件管理;几乎可以肯定,CentOS 的软件管理将像 高级打包工具 (APT) 在基于 Debian 的系统中的作用一样,依赖于 YUM。
使用 YUM 安装软件时,不需要知道文件系统路径,甚至不需要知道 RPM 文件的位置。所需的软件包位于软件仓库中,仓库位置配置在 /etc/yum.repos.d/
目录下。该目录中创建的任何文件都应具有 .repo
扩展名。
在标准构建中,这些文件将被指向基于互联网的软件仓库;然而,你可以在自己的网络、文件系统或 CD-ROM 上配置本地仓库。稍后我们会讨论这一点。现在,我们将专注于 YUM 命令:
-
yum install nmap
:从仓库中安装nmap
包。我们知道这是从仓库而非本地文件中安装的。对于本地文件,需包括完整的文件名及.rpm
扩展名,若需要,路径也应包括。在本节前面,我们已经看过如何使用 YUM 安装 Foxit PDF 阅读器的 RPM。 -
yum list nmap
:这将显示包的信息,以及它是否已安装或可用。输出中还将列出安装该包或可用包的仓库。 -
yum list installed
:这将列出所有已安装的软件包。 -
yum check-update
:这将显示可用的更新。 -
yum update nmap
:如果有更新可用,这将仅更新nmap
。 -
yum update
:这将更新系统中的所有软件。 -
yum remove nmap
:这将卸载nmap
包。
YUM 插件
尽管 YUM 是最常用的打包系统之一,许多用户和管理员并未意识到通过插件扩展可以使用更多的功能。
使用 CentOS,并阅读本书后,你将非常熟悉使用 yum
命令来安装包和更新系统。我们已经看到如何通过 YUM 扩展 RPM 系统,但这并不意味着我们可以忽略其他更多的功能。
插件是扩展 YUM 功能的 Python 脚本或程序。你可以在 /usr/lib/yum-plugins
中找到插件,而其配置文件位于 /etc/yum/pluginconf.d/
下。要使用任何插件,必须在 YUM 配置文件 /etc/yum.conf
中启用插件指令,如下所示:
plugins=1
要搜索可用的插件,可以使用以下命令:
$ yum search yum-plugin
在标准构建中,CentOS 会包含最快镜像插件等。这款插件的作用正如你所想,它会在下载包时自动寻找最快的镜像仓库。如果启用此插件,它会在使用 yum
命令时自动调用。
如果你只需要禁用单个插件,而不是所有插件,那么你需要确保在插件的配置文件中,enabled
指令被设置为 0
。例如,要禁用最快镜像插件,你需要编辑 /etc/yum/pluginconf.d/fastestmirror.conf
文件,并将 enabled
行配置如下:
enabled=0
最快镜像插件已被禁用。要启用该插件,设置应如下所示:
enabled=1
另一个常安装的命令插件是 security
插件。它旨在与 yum
更新命令配合使用:
-
yum --security check-update #仅列出安全更新
-
yum --security update #仅安装安全更新
创建 YUM 仓库
创建 YUM 仓库的理由有很多。你可以想象一种情况,假设你的网络中有多个服务器。在这种情况下,本地获取软件会比让所有服务器都通过 WAN 访问包更有意义。同样的理由适用于 CentOS 桌面系统普及的环境。集中化软件分发是绝对必要的,它可以标准化所使用的软件,并确保你的支持团队只需要支持软件包的单一版本。
在一个仅用于测试和开发的虚拟机上建立本地仓库也非常有意义,这样就不需要依赖网络来安装软件包。我确保我的课堂虚拟机始终拥有一个本地文件系统仓库,这样系统就可以作为一个独立身份使用,而不依赖于网络或外部组件。
在这个小实验中,我们将使用产品 DVD 中的 RPM 文件创建一个本地仓库,并使用命令行工具 /usr/bin/yumdownloader
来添加以下所需的额外 RPM 文件:
-
首先,我们将创建一个本地目录作为本地仓库;为了简化操作,我们只需在文件系统的根目录下创建一个目录,并将 RPM 文件直接放入该文件夹:
# mkdir /repo
-
在产品 DVD 被挂载后,我们可以将 DVD 中的 RPM 文件填充到该目录中:
# rsync -av /media/<volume name>/Packages/ /repo
-
我们可以添加本章前面为 Plymouth 主题创建的 RPM 文件:
# cp /home/user/rpmbuild/RPMS/noarch/plymouth-theme-tup-1-0.noarch.rpm /repo
-
在有网络连接的情况下,我们将下载(而不是安装)那些不在 DVD 上的额外 RPM 文件,这些文件是我们仓库所需要的。实现这一目标的最简单方法是使用
yumdownloader
命令:# cd /repo; yumdownloader --resolve kernel-source
-
--resolve
选项将确保依赖包也被下载。默认情况下,它们会被下载到当前目录,因此请注意先将它们移入/repo
目录: -
我们需要安装
createrepo
包:# yum install createrepo
-
现在我们准备好创建仓库元数据,将文件目录转变为仓库:
# createrepo /repo
现在我们已经能够创建本地仓库;在 YUM 客户端引用之前,该仓库不会被使用。这是通过在/etc/yum.repos.d/
目录下创建一个扩展名为.repo
的文件来实现的。现在,我们可以陶醉于我们创建的成功。这里的真正重要性在于通过使用yumdownloader
获得的知识,以及它为仓库创建带来的力量,它可以将多个来源的选定软件包结合到自定义仓库中,供您和您的客户使用。
/etc/yum.repos.d/
客户端系统需要告知它们的软件源或仓库的位置,这通过使用.repo
文件来实现。虽然可以在单一文件/etc/yum.conf
中定义所有仓库,但更合理的做法是将它们作为单独的文件添加到目录中,正如下面yum.conf
文件中的摘录所示:
文件的名称其实并不重要,但扩展名必须是.repo
。我们将创建一个名为/etc/yum.repos.d/local.repo
的文件:
[c6-local]
name=CentOS-6.5 - Local
baseurl=file:///repo
gpgcheck=0
enabled=1
方括号定义了仓库的简短名称,name 指令更像是描述。baseurl
指令使用了三个正斜杠:两个用于访问方法,此处为文件协议,第三个则是文件系统路径的斜杠。我们已经禁用了公钥检查(gpgcheck=0
),但如果愿意,我们还可以为仓库元数据签名。该仓库已启用。
如果这是我们想要使用的唯一仓库,那么我们可以将现有的仓库文件移动到备份目录;这可能比通过为每个仓库添加enabled=0
指令来禁用仓库更容易。通常,每个文件定义了多个仓库,因此任务并不简单。正如我所说,最简单的方法是将它们移动到另一个目录,然后在以后需要访问外部仓库时再将其添加回来。
现在,我们已经在/etc/yum.repos.d/local.repo
文件中定义了本地仓库,我们现在可以通过 YUM 访问我们自己目录中添加的所有 RPM。如果我们需要通过网络将其共享给内部网络中的其他主机,只需添加一个 Web 服务器来提供仓库访问即可。客户端将使用http://
协议作为访问方法。
第八章,Nginx – 部署以性能为中心的 Web 服务器,我们将学习 NGINX web 服务器,除了其他内容外,我们还将学习如何将通用资源标识符(URI)定向到这个仓库。
总结
恭喜你!你已经成功迈过了本章的另一个里程碑,离成为最精英管理员专属的圣殿又近了一步。接下来,我们将回顾本章的内容,通过这次回顾,我们获得了宝贵的经验,使我们能够更有效地管理系统上的软件。从原始的 RPM 文件开始,我们能够看到它们在管理和库存方面的强大优势,但烦恼在于必须定位它们的依赖关系。喜欢 RPM 的概念后,我们开始着手创建自己的 RPM 文件,用于分发和安装 Plymouth 主题;这是我们为了塑造系统品牌并强化身份而创作的主题。
不久之后,我们便更加熟悉了 YUM 仓库管理系统,该系统让我们可以充分利用 RPM 库系统,并结合自动解析依赖项的功能。本章的高潮是创建我们自己的本地仓库,构建一个能够在没有任何网络连接的情况下安装软件的独立系统。
在下一章,我们将获得宝贵的技能,用于维护 CentOS 6.5 系统上的服务和进程管理。我们将确保理解传统的 System V 服务脚本,以及新的 upstart 系统用于服务控制。此外,我们还将研究能够有效管理 CentOS 主机上运行的进程的工具。
第五章。驯猫术 – 控制进程
很多 Linux 管理员,如果没有你这样的洞察力,通常会在 CentOS 的原生安装后就直接运行服务,而没有进行适当的配置。我们知道,能够证明我们所管理系统中的每个运行进程和服务的重要性是至关重要的,在这一章中,你将获得管理这些服务的深刻理解。与此同时,我们将看看替代了我们习惯使用的 System V 脚本的新 Upstart 服务。以下是我们将在本章中讨论的章节列表:
-
使用 Upstart 管理服务:研究如何在 CentOS 6.5 中使用 Upstart 和
/etc/init
与/etc/event.d
目录来控制服务 -
创建你自己的 Upstart 脚本:学习如何为 Upstart 创建自定义启动脚本,以便在系统启动时管理你自己的需求
-
管理进程:通过练习来自 procps 包的一系列工具来管理运行中的进程:ps、pstree、pgrep、pmap 和 pkill
使用 Upstart 管理服务
多年来,我们一直习惯于使用 System V 初始化脚本来管理服务,这些脚本可以追溯到很多年前。然而,如果没有开放源代码社区中那么多人的努力和持续改进的精神,我们就无法前进和提升。在 CentOS 6.5 中,我们现在看到一些服务通过 /etc/init
目录中的配置来管理。这些服务使用了 Upstart。虽然这可能是短期的,因为 Red Hat Enterprise Linux 7 的测试版版本使用了类似的服务管理器 systemd,systemd 很可能会取代 Upstart。不过,Upstart 和 systemd 的管理方式非常相似,因此在这里讨论 Upstart 并没有问题。
首先,我们可以通过以下命令检查是否正在使用 upstart
:
# yum list upstart
上述命令的输出应该会列出安装的包。该服务使用 /etc./init
目录作为其配置,我们可以在这里查看使用 Upstart 的服务。通过 rpm
命令,我们可以检查哪个包创建了这个目录:
# rpm -qf /etc/init
输出显示该目录属于 upstart
包。在 CentOS 中,我们只有少数几个服务是通过 Upstart 管理的;然而,我们会发现,使用这种机制配置自己的服务非常容易。
在/etc/init
目录中,我们可以看到控制台屏幕由upstart
通过tty.conf
文件进行管理,还可以看到splash-manager.conf
文件。该服务启用了重启和关机功能,在运行级别 0 和 6 时,请求 Plymouth 启动画面(记得 Plymouth 来自于第二章,冷启动)。Upstart 和 systemd 的一个优点是,我们不再需要像旧的 System V 脚本那样管理运行控制目录中的符号链接。查看/etc/init/spash-manager.conf
文件,我们可以看到服务何时启动,而且这一切都直接提供,而不依赖于旧的符号链接。以下是一个 Upstart 指令的示例:
start on starting rc RUNLEVEL=[06]
上述行表示,Upstart 将在启动时以及切换到运行级别 0 和 6 时执行配置文件中的脚本。就这么简单。配置文件也可以包含运行服务所需的所有内容;这个文件成为我们寻找的独立服务,所有内容都包含在这个单一的配置文件中。
创建您自己的 Upstart 脚本
学习这些服务的最佳方法之一是创建自己的配置文件,包含 Upstart 脚本和与服务相关的所有条件。配置文件需要以.conf
扩展名结尾,并且必须在/etc/init
目录中创建。为了演示,我们将创建一个简单的服务,名称为经过充分研究和富有创意的sample
。
使用文本编辑器 vi 创建/etc/init/sample.conf
文件,服务开始初具雏形:
#/etc/init/sample.conf
description "Simple demonstration upstart script"
author "The Urban Penguin"
start on runlevel [35]
script
logger -p local1.info "Starting upstart service"
end script
该服务本身仅使用 logger 程序写入 syslog 守护进程;我们可以从/var/log/messages
日志文件中读取输出。当然,您可以调整服务以做更多的事情;但是,这为我们展示了服务如何简洁。
我们可以使用/sbin/initctl
命令来测试服务:
# initctl start sample
# tail -n 1 /var/log/messages
如果像我们这里展示的那样,服务可以手动启动,如果没有手动启动,它将自动启动,或者至少在系统进入运行级别 3 或 5 时,发送消息到日志文件。
除了我们在这里使用的脚本选项外,我们还可以运行前置或后置脚本,尤其在服务是二进制文件时非常有用,我们需要确保它可以在某些环境中运行。可以使用exec
指令来代替script
指令,单个二进制文件将在脚本的位置运行。Upstart 服务的完整生命周期包括:
-
Pre-start
-
Post-start
-
主体(使用 exec 或 script)
-
Pre-stop
-
Post-stop
使用 Upstart 和/或 systemd 的优势在于,我们不再仅仅局限于为给定的运行级别启动服务;我们还可以为诸如磁盘(或块设备)添加或其他服务启动等事件启动这些服务。许多基于事件的服务可以在/etc/event.d
目录中找到。
我们可以使用/sbin/initctl
命令来控制 Upstart 服务。要查看可用的选项,可以使用带有help
选项的以下命令:
# initctl help
输出将显示可以使用version
选项检查正在使用的 Upstart 版本,如下图所示:
管理进程
本章的大部分内容将介绍procps
软件包和一系列我们可以使用的 p 命令,以帮助我们管理进程,确保我们能充分理解这些工具从命令行中提供的强大功能。
许多管理员习惯使用ps
命令来确定正在运行的进程,并且经常将输出通过管道传递给grep
来搜索给定的进程名称。虽然这样做没有错,但我们可能更倾向于使用能简化这些步骤、专门为此目的设计的工具。目前,我们将忽略/ps
命令,而倾向于使用具有明确用途的更专业工具。
使用pgrep
命令
/usr/bin/pgrep
命令实际上成为了我们经常使用的ps
和grep
管道的轻松替代。例如,如果我启动了 Apache Web 服务器,我可以轻松检查该服务正在使用的进程 ID(PID):
# service httpd start
# pgrep httpd
命令的输出如下:
从输出中,我可以看到最低的 PID,在我的例子中是3950。这将是主要的守护进程,它将生成子进程。考虑到我们喜欢轻松的生活,可以看出通过将父进程作为参数,使用pstree
命令,我们可以毫不费力地将子进程添加到父进程。在我的例子中有八个子进程,根本不需要用拇指去数它们。
# pstree 3950
这是前一个命令的输出:
使用pstree
命令
这个工具被低估了;我相信许多管理员只知道执行命令而不加任何参数或选项。我们已经看到在前面的示例中它有多强大,但当然还有更多功能。
pstree
命令在没有任何参数或选项的情况下运行时,将列出从 PID 1 开始的所有正在运行的进程树,以层级结构的形式显示每个进程,并通过父进程 ID(PPID)和 PID 相互连接。
更进一步,我们可以使用-h
选项,它将高亮显示我们运行pstree
的进程树:
$ pstree -h
以下截图显示了从pstree
中高亮显示的摘录:
从之前的截图中可以看到,我们是在gnome-terminal
中运行pstree
命令的,并且我们曾在替代用户(SU)环境中运行 Bash shell;这一切都清晰地展现在我们眼前。
执行类似的命令,我们可以用以下命令高亮显示运行在 PID 3950
的httpd
进程树:
$ pstree -h 3950
在我的系统上,可以从下面的截图摘录中看到这一点:
使用pstree
命令并加上-a
选项,会显示进程及其启动时使用的任何参数。这对于查看某个服务是否使用了正确的配置选项非常有用:
$ pstree -a
使用 pkill 命令
当我们从本章开始的地方重新考虑时,了解到许多管理员习惯使用ps
命令并将其与grep
结合使用,我们应该质疑首先运行ps
命令的必要性。也许我们这么做是为了终止一个进程。我们之前已经展示了如何通过pgrep
简化和精简ps
/grep
管道;然而,现实是,我们可以通过pkill
进一步简化这一过程。假设我们正在运行 CentOS 桌面,并且在使用 Firefox 浏览器时注意到它变得没有响应,我们可以直接使用pkill
命令来解决这个问题:
$ pkill firefox
当然,Linux 中的进程名称是区分大小写的,但你会习惯那些你可能经常需要通过pkill
来清理的进程名称。
我们也可以终止某个特定用户所拥有的所有进程。也许他们做了什么很糟糕的事情,他们的会话完全没有响应。我们可以尝试:
# pkill -9 -U bob
上述命令将向用户bob
所拥有的所有进程发送-9
终止信号。
如果我们只需要关注一个终端中的进程,那么我们可以使用以下命令:
# pkill -9 -t tty2
这将终止在tty2
控制台中运行的所有进程。如果我们拥有这些正在运行的进程,我们可以以自己的账户执行pkill
命令。如果我们没有拥有这些进程,那么命令需要以 root 用户身份运行。在之前的示例中,我们一直使用-9
信号,因为我们希望确保删除所有进程。为了最佳实践,最好以以下方式运行命令:
# pkill -15 -t tty2
# pkill -9 -t tty2
这样,我们首先发送终止信号(-15
),然后再发送杀死信号(-9
)。这样,如果进程响应初始的终止请求,则会优雅地关闭;那些对终止信号没有反应的进程,则会在最终的终止信号下被清理。
仅仅因为一个进程没有响应终止请求,并不意味着该进程已经挂起;例如,bash shell 不会响应终止请求,它必须被直接杀死。这就是程序的编写方式。
要查看可以发送的信号列表,我们应该使用/usr/bin/kill
命令并加上-l
(列出)选项,如下所示:
$ kill -l
以下屏幕截图中可以看到部分输出:
尽管存在许多可能的信号,但如果程序要响应信号,必须将它们写入程序中。这就是 -9
或 -sigkill
选项有用的地方,尽管它比较突然,但该信号直接与 init
交互来移除进程,而不是依赖应用程序做出响应。
使用 pmap 命令
procps
包中的另一个有用工具是 pmap
命令,我们可以用它来获取正在运行的进程的信息。简而言之,它会显示进程正在使用多少内存,以及它使用的任何库模块。
要获取当前 shell 的 PID 信息,我们可以使用特殊变量 $$
;因此,pmap $$
将显示我当前 shell 的进程映射:
$ pmap $$
输出看起来非常令人印象深刻;首先,我们看到在此系统中,$$
被解析为 PID 7259 和 /bin/bash
。随着进程映射的继续,我们看到地址列,接着是 /bin/bash
每个组件所使用的内存大小。
从以下部分截图中,我们可以看到从 pmap
命令获取的输出:
总结
在本章中,我们花了一些时间了解 CentOS Linux 中的 procps
包及其能揭示的所有宝贵资源。包中的工具对管理员来说是一个金矿,在我们选择最有效的工具来检查进程时,它们可以节省我们大量宝贵的时间。通过实践,我们已经看到了如何轻松使用 pgrep
和 pkill
命令来简化我们的进程管理,而像 pmap
这样的工具则更适用于诊断系统资源的使用。
在我们准备进入下一章之前,我们将了解一些在 CentOS 6.5 系统上管理用户时可以使用的宝贵快捷方式。
第六章。用户——我们真的想要他们吗?
我承认,这个问题有点儿反问的意味,但有时候我们会幻想,如果没有麻烦的用户干扰,生活会有多么美好,系统的运作也会更加顺畅;然而,我们越是有效地管理 Linux 系统上的用户,CentOS 对我们来说就越好。实际上,我们对用户的控制越多,他们的工作就越不受系统停机的干扰,生活也就越好。
本章中,我们将开发一些技巧来保持对系统的低调控制,让我们保持理智,同时让用户感到满意。这将包括:
-
管理公共组和私有组:了解如何使用公共组以及覆盖 CentOS 默认的私有组,可以让我们在为用户分配权限时有更多选择。我们需要注意每种解决方案的潜在陷阱。
-
Getent:它可以为我们提供关于用户和组的全局视图,并在本章中为我们打开
nsswitch.conf
文件(名称服务切换文件)的理解之门。 -
配额:使用配额可以让我们监控并在必要时限制用户的空间分配,这在用户的主目录所在位置尤为重要。
-
脚本化用户创建:在创建用户时,我们需要设置密码,并可能设置用户的磁盘配额限制;因此,将这些活动组合成一个脚本是有意义的,这样就不会遗漏任何内容。
管理公共组和私有组
Red Hat 和因此也包括 CentOS 的用户管理系统采用了私有用户组系统。每个创建的用户都会属于一个同名的主组;换句话说,创建用户 bob 时,也会创建一个名为 bob 的组,而该用户是唯一的成员。
Linux 组
首先,我们需要了解一些关于 Linux 组的知识。每个用户有一个主组和多个次级组。
用户 ID 和组 ID(UID/GID)用于 Linux 的权限管理结构。任何文件的所有者和所属组都是通过将 UID 和 GID 存储在文件的元数据中来实现的。权限可以分配给用户、组或其他人。
每个用户都有一个 UID 和 GID,但只能属于一个组,这有些限制,因此用户还可以加入次级组。用户可以使用/usr/bin/newgrp
命令将当前的 GID 改为其次级组中的一个,从而有效地切换他们的 GID。在实际操作中,这并不是必需的,接下来我们将描述用户的主组和次级组之间的区别。
创建新文件时,用户的 UID 和当前的 GID 用于创建新文件的所有权。如果用户创建新文件,用户将是该文件的所有者,并且该文件将由其自己的私有组作为组所有。这样就能创建一个固有安全的系统,无需用户干预。次级组在访问当前存在的资源时被使用。用户在访问资源时会显示其所有的次级组。因此,一个对users
组可读但对others
不可读的文件,将能够被其 GID 设置为私有组的用户访问,但他们所属的次级组列表中包括了users
组。
在评估用户的 ID 时,设置/usr/bin/id
命令非常有用。若不带任何选项或参数运行,输出将显示与您关联的 ID。在下图中,我们可以看到用户andrew
仅属于私有用户组,并没有额外的次级组成员资格:
$ id
我们将使用相同的命令,但这次我们将使用用户u1
作为参数。输出将显示该帐户的关联 ID;此命令可以作为标准用户运行:
$ id u1
从下图中,我们可以看到用户u1
的主组或 GID 被分配给私有组u1
;然而,u1
还属于users
组。
对于当前设置的u1
用户 ID,任何新创建的文件将由 GID 501(u1
)作为组所有;但u1
可以访问任何users
和u1
组可访问的资源,无需u1
做任何额外操作。从管理员的角度来看,我们需要确保为用户分配正确的次级 ID。
这点与我们查看的第一个例子不同。用户andrew
目前仅属于andrew
的私有组,因此他只能访问权限设置为:
-
他们的 UID(
andrew
) -
他们的私有 GID(
andrew
) -
其他
用户帐户andrew
无法像用户u1
那样访问users
组分配的权限。
将用户添加到组中
现在我们可以看到用户u1
已经获得了共享给users
组的资源访问权限,那么andrew
呢?我们该如何帮助他呢?
如果用户已存在,并且我们需要将其添加到一个公共组中,那么可以使用usermod
命令将用户添加到额外的组中。当我们将andrew
添加到users
组时,我们还需要保持其任何现有的次级组成员资格。
运行以下命令:
# usermod -G users andrew
如果我们选择运行上述命令,那么andrew
将被添加到users
组中,但与他的主要组一起,这将是他唯一的二级组成员。换句话说,如果andrew
属于多个二级组,-G
选项会覆盖这个组列表,这是不好的做法。
id
命令可以通过-G
选项显示当前的二级组:
# id -G andrew
如果我们将这两个命令结合在一起,那么我们可以有效地将users
组附加到andrew
当前的组列表中。为此,我们还需要将id
命令提供的组列表中的空格转换为逗号:
# usermod -G$(id -G andrew | tr ' ' ','),users
括号中的命令首先会被评估。id
命令会生成一个由空格分隔的二级组列表,tr
命令会将空格转换为逗号(在这种情况下)。我们提供给usermod
的组列表需要用逗号分隔,但可以使用组名或 ID。不过,更简单的方法是使用usermod
的附加选项,如下所示的代码示例:
# usermod -a -G users andrew
创建新用户时,我们只需指定用户应属于的二级组。我们无需关注现有的组成员身份:
# useradd -G users u4
# id u4
从以下输出可以看出,新用户u4
已被创建并添加到二级组users
中。
评估私有组使用情况
你不需要使用私有groups
方案。它们是默认的,但与所有默认设置一样,我们可以指定选项来修改它。使用useradd
命令的-N
选项将不会创建私有组,并且如果未指定,用户的主要组或 GID 将是users
组。让我们执行以下命令:
# useradd -N u5
# id u5
输出结果显示在下面的截图中,我们可以看到用户的主要组是users
组:
我们可能需要面对的唯一安全问题是,现在默认情况下,用户u5
创建的任何文件将由一个共享组拥有。根据具体情况,这可能是不希望的;然而,默认将所有文件设为用户私有也并不是理想选择。最终,由管理员团队决定哪种模型最适合组织的需求。
Getent
/usr/bin/getent
命令将显示一个条目列表,获取条目。这些条目由名称服务切换库解析,这些库在/etc/nsswitch.conf
文件中进行配置。该文件包含一个数据库和库的列表,用于访问这些数据库。
例如,我们可以使用getent passwd
命令显示所有用户,或者使用getent group
显示所有组。然而,我们也可以将其扩展到诸如getent hosts
来显示主机文件条目,和getent aliases
来显示系统上的用户别名等命令。
nsswitch.conf
文件将定义用于访问passwd
数据库的库。在标准 CentOS 系统上,/etc/passwd
通常是唯一的本地文件,但企业系统可能包括轻量级目录访问协议(LDAP)模块。在下一章中,我们将学习如何使用目录服务。
我们使用grep
命令在/etc/nsswitch
文件中搜索passwd
数据库:
# grep passwd /etc/nsswitch.conf
我们可以看到在我的系统上,我们只是使用本地文件来解析用户名:
getent
命令是一个非常有用的工具,可以快速列出系统中的用户或组,输出可以根据需要通过grep
和sort
命令进行过滤或排序。例如,如果我们想查看系统中所有以字母u
开头并且名称中只有一个额外字符的组,可以使用以下命令:
# getent group | grep 'u.:' | sort
以下截图展示了这个命令:
配额
在几乎所有用户管理的领域,我们都必须为磁盘空间分配某种配额,以便将磁盘空间管理的责任交还给用户。如果我们不这么做,用户将永远无法了解我们在为他们提供无限磁盘空间时所面临的困难。让用户看到他们的空间正在填满,可能会促使他们进行一些清理工作。
在 Linux 中,磁盘配额应用于挂载点;如果你想限制用户在其主目录中的空间,则/home
目录需要有自己的分区。如果它是根文件系统的一部分,那么用户的空间将被限制在该分区内的所有目录中。
配额限制是通过quota
包中的工具实现的。你可以使用yum
命令来验证它是否已安装:
$ yum list quota
如果命令的输出显示它可用而不是已安装,那么请使用以下命令安装配额:
# yum install quota
设置配额
我的系统包含一个/home
分区并安装了quota
包。现在,我们需要为/home
分区设置正确的挂载选项。目前,它没有启用配额。
为了启用此功能,我们需要编辑/etc/fstab
文件并为/home
分区设置挂载选项。以下两个挂载选项应该被添加以启用选定分区的日志配额:
usrjquota=aquota.user,jqfmt=vfsv0
usrjquota=aquota.user
部分指定了配额文件,而jqfmt=vfsv0
指定了配额格式。
问题行在以下截图中显示:
我们已启用基于日志的用户配额,因为我们使用的是ext4
,一种基于日志的文件系统。用户空间限制是在写入日志时检查的,而不是等到更改刷新到磁盘时才检查。我们还设置了日志配额的格式。
为了使这些设置生效,我们可以使用以下命令重新挂载/home
分区:
# mount -o remount /home
现在我们需要初始化配额数据库;它在挂载选项中被引用为aquota.user
,并将位于启用配额的分区根目录下。启用文件系统的配额可能需要一些时间,具体取决于文件系统中的数据量:
#quotacheck -muv /home
使用这些选项和/sbin/quotacheck
命令,我们可以设置以下选项:
-
-m
:这表示在操作过程中不重新挂载为只读模式 -
-u
:这是用于用户配额的选项 -
-v
:这是详细输出 -
/home
:这是要操作的分区,或者使用-a
来处理所有启用配额的分区
可能值得将quotacheck
命令和选项添加到你的crontab
中,以确保quotacheck
命令每天至少执行一次。尽管日志配额比传统配额更可靠,但定期重新评估文件空间的使用情况仍然有助于确保维护的数据准确。
配额可以通过edquota
或setquota
命令设置;我更喜欢setquota
命令,但传统上edquota
会教授给新管理员。/usr/sbin/edquota
命令将带你进入编辑器进行更改,而/usr/sbin/setquota
命令则直接在命令行中设置配额:
# setquota -u u1 20000 25000 0 0 /home
上述命令将为用户u1
设置配额。为该用户设置软限制,当超过 20 M(20 x 1k 块)时仅给出警告,并设置硬限制为 25 M,超出此限制时用户将无法再在/home
目录中保存数据。我没有限制用户u1
的文件数量,只限制了他们使用的磁盘空间。
/usr/sbin/repquota
命令可以用来显示磁盘使用情况:
# repquota -uv /home
我的系统输出如下所示的屏幕截图:
脚本化用户创建
用户创建现在将包括三个步骤:
-
useradd
:这用来创建用户 -
passwd
:这用于设置密码 -
setquota
:这用于设置磁盘配额
我们可以通过脚本确保这些操作的正确性和一致性,以确保用户创建过程的程序完整性。这还将节省时间。作为一种非常快速的解决方案,以下脚本提供了我们所需的一切:
#!/bin/bash
useradd -m -G users $1
echo Password123 | passwd --stdin $1
passwd -e $1
setquota -u $1 20000 25000 0 0 /home
我们需要使用新用户名作为参数来运行脚本,如下例所示:
# userscript.sh bob
按行阅读脚本可以解释脚本内容如下:
-
#!/bin/bash
:这是要使用的脚本解释器 -
useradd -m -G users $1
:这将创建作为脚本第一个参数$1
传入的用户。用户的主目录将被创建,并且会被加入到users
组。 -
echo Password123 | passwd --stdin $1
:这将用户的密码设置为一个标准密码。 -
passwd -e $1
:密码已过期,因此用户在第一次登录时需要设置自己的密码。 -
setquota -u $1 20000 25000 0 0 /home
:最后,配额将为用户实现。
当然,我们可以在脚本中加入更多功能来设置不同的群组和配额;然而,作为程序完整性和功能脚本的示范,这已经是一个很好的起步。
总结
当我们结束这一章节时,可以总结一下我们在过程中学到的所有内容。本节的主要任务是更加熟悉 CentOS 群组管理的变化,并能够正确区分用户的主群组和次群组。在此过程中,我们花时间评估了公共和私人群组方案的使用,以及在用户创建时使用-N
选项禁用用户的私人群组。
不久后,我们便深入到了/etc/nsswitch.conf
和getent
命令(获取条目)。从这里,我们直接开始实施用户磁盘限制或配额,然后再通过脚本将这一切串联起来。
在下一章中,我们仍然围绕用户这一主题,但将目光投向将我们的账户集中在一个中央 LDAP 目录中,通过实现 CentOS 6.5 上的 389 目录服务器,使用来自 Red Hat 目录服务器的开源代码。
第七章:LDAP——一种更好的用户类型
在每个服务器和工作站上定义本地用户账户和密码来进行访问并不是很实际。想象一下,当你可能需要在你使用的 10 或 12 个系统中实施密码更改时,要强制执行密码更改会是多么麻烦。你可能还会想考虑当用户离开时会发生什么;你真认为每次都会从每个系统中删除账户吗?现实情况是,当有多个系统时,必须有某种形式的目录解决方案;这可能是 OpenLDAP,也可能是 Active Directory。是的,CentOS 可以加入 Windows 域。我们将探讨 389-ds,这是 CentOS 对 Red Hat 目录服务器的实现。389-ds 基于 OpenLDAP,但有一些非常聪明的管理工具。我们将在本章中讨论以下主题:
-
LDAP 概念:在本节中,您将了解在谈论目录服务时使用的术语
-
安装 389-ds:本节涉及安装 389 目录服务器,确保所有的基础设施就绪
-
LDAP 用户账户管理:本节包含目录中用户生命周期的管理
-
LDAP 认证:本节将介绍如何认证第二台 CentOS 服务器到共享目录
LDAP 概念
LDAP 代表轻量级目录访问协议;顾名思义,它最初是一个用于访问目录的客户端-服务器协议,但由于目录发展的非常缓慢,它很快就承担了整个目录服务器的角色。如果我们分解一个目录,目录访问协议 (DAP) 只是 LDAP 服务器众多组成部分中的一小部分:
-
目录信息数据库 (DIB):这是存储目录的数据库
-
目录信息树 (DIT):这是表示 DIB 中条目、组织、组织单位等的层次结构
-
目录系统协议 (DSP):它代表服务器与服务器之间的通信
-
目录访问协议 (DAP):这代表客户端到服务器的通信
-
目录服务器代理 (DSA):这是服务器软件
-
目录用户代理 (DUA):这是客户端软件
-
目录信息影射协议 (DISP):这是目录的复制
-
架构:这些是条目数据定义
这些元素在所有 LDAP 目录和常见目录中都有一定的表示方式,包括 OpenLDAP、Red Hat 目录服务器和 389-ds。我们将重点关注基于 Red Hat 目录服务器的 389-ds,它是 OpenLDAP 的实现,并具备一些增强功能。最终,目录被用于创建通常所说的身份管理,集中存储用户账户,以减轻账户管理的负担并提升安全性。如果用户只需记住一组凭证,那么他/她更有可能记住强密码。
安装 389-ds
在接下来的章节中,我们将看到安装 389-ds 所涉及的步骤。
配置 DNS 或主机名记录
在安装 OpenLDAP 或 389-DS 时,必须确保能够解析安装目录的系统主机名。我的系统名为 ldap1.tup.com
,我为此配置了本地 DNS 记录,但也可以通过主机系统上的 /etc/hosts
文件中的条目来维护。我可以使用 host
命令或类似命令验证名称是否正确:
$ host ldap1.tup.com
你应该能看到返回的 IP 地址。你可以在我的系统上执行此命令时看到结果,如下截图所示:
设置 TCP 保活
TCP 连接的默认超时时间为 120 分钟。我们将其配置为五分钟。这样做可以减少由于丢失 TCP 连接所带来的开销;连接将更快速地关闭。编辑 /etc/sysctl
文件,添加以下行:
net.ipv4.tcp_keepalive_time = 300
使用 sysctl
加载设置,使其生效并成为下次重启时的默认设置:
# sysctl -p
设置文件描述符
编辑 Linux 系统上的文件描述符数量可以帮助目录服务器更高效地访问文件,因此我们将从查看当前设置开始:
# cat /proc/sys/fs/file-max
如果值小于 64,000,则需要在 /etc/sysctl
文件中增加限制:
fs.file-max = 64000
运行以下命令以读取我们刚刚设置的新值,无需重启系统:
# sysctl -p
为了使此设置生效,我们还必须允许所有用户拥有足够的打开文件权限。编辑 /etc/security/limits.conf
文件,添加以下行:
* soft nofiles 8192
* hard nofiles 8192
这允许所有用户(*
)最多有 8,192 个打开文件(nofiles
)。我们将两者的限制设置为相同的值,但软限制可以通过警告超出,而硬限制则无法超出。
创建目录服务器用户和组
在配置目录时,我们需要为服务分配一个用户和组 ID;默认是 nobody
账户,但我们应当为目录创建一个非特权的用户和组,具体如下:
# useradd -m ldap389
useradd
命令将创建 ldap389
用户和组。
在此阶段,最好重新启动系统,以确保设置已生效,然后再开始安装目录服务器。有了这些准备,我们可以进一步准备安装。
EPEL 仓库
我们需要实现 EPEL 仓库。使用wget
命令,你可以下载 RPM 文件来配置仓库:
$ wget http://epel.mirror.net.in/epel/6/i386/epel-release-6-8.noarch.rpm
下载后,以 root 用户身份安装 RPM。这将为你创建仓库文件。运行yum repolist
命令的输出应该显示 EPEL 仓库。以下截图来自我的演示系统:
安装和配置 389-ds
配置好仓库后,我们可以使用yum
来安装目录服务器:
# yum install -y 389-ds openldap-clients
其中,你会发现会安装 Java,因为有一个 Java 管理控制台,它简化了连接到目录并管理目录中的条目。
通过实施一个脚本,使得配置变得简单,这个脚本将引导我们完成 CentOS 上管理和目录服务的配置。管理服务代表 LDAP 服务器;目录服务本身代表托管在管理服务器上的单个目录。一台管理服务器可以管理公司 A 和公司 B 的目录。两个目录可以分别管理。
设置通过运行脚本setup-ds-admin.pl
来完成。该脚本已安装在你的 PATH 中。默认情况下,脚本是交互式运行的,但特别是在频繁设置服务器的情况下,你可以使用回答文件来配合脚本使用。
运行以下命令将交互式配置目录和管理服务:
# setup-ds-admin.pl
运行该命令后,会进入一个菜单,具体内容如下:
-
继续设置:在第一个提示时选择
yes
以继续脚本。 -
dsktune:将运行调整分析,以检查你的 RAM 是否大于 1024 MB,并确保其他预检项都已设置好。
-
选择设置类型:
-
快速安装
-
典型设置
-
自定义
我们将选择
2
作为典型配置。 -
-
设置计算机名称:接下来,我们设置计算机名称。这个名称默认应该与你的主机名相同;在我的例子中是
ldap1.tup.com
。 -
设置目录服务器运行的用户:在我们的案例中,我们将其设置为
ldap389
,这是我们创建的专用用户。 -
设置目录服务器运行的组:我们将使用
ldap389
组。 -
将新目录服务器注册到现有服务器:我们选择
No
,因为这是第一台服务器。如果已有其他服务器,可以将此安装与该服务器注册。 -
为配置目录服务器设置用户名和密码:我们可以接受默认的管理员名称。我们使用该账户登录目录服务器。
-
配置目录服务器域:我使用的域名是
tup.com
。我们将创建一个 LDAP 域来反映这一点。 -
设置目录服务器端口:LDAP 的默认端口是
389
,我们将保持此默认设置。 -
设置目录服务器标识符:接下来,我们将被提示输入一个唯一的服务器名称,这将默认为主机名的第一部分,在我的情况是
ldap1
。 -
设置目录后缀:LDAP 名称由逗号分隔。LDAP 后缀现在将显示如下,并将构成 LDAP 树中的顶部容器:
dc=tup, dc=com
-
设置目录管理器 ID:这是 LDAP 目录管理器,默认名称为
cn=Directory Manager
。我们需要为此设置一个安全的密码。 -
设置管理服务器端口:管理端口可用于通过 Java 控制台管理服务器。我们将保持默认端口
9830
。
交互式设置现在已完成,配置将与默认条目一起创建。在最后阶段,服务应启动,并且会显示成功消息。我们应确保服务在启动时能够正确启动,使用 chkconfig
:
# chkconfig dirsrv on
# chkconfig dirsrv-admin on
提示
请记住,dirsrv
运行在端口 389
上,是 LDAP 目录;dirsrv-admin
是管理服务器,监听端口 9830
。
测试安装
恭喜!现在你已经拥有了一个 LDAP 服务器,我们可以通过几种方式测试配置。首先,我们可以使用 ldapsearch
命令显示目录中的条目,然后我们将使用 389-console,这是一个可以管理 LDAP 的 GUI 工具。在以下命令中,-x
选项用于简单身份验证,-b
选项指定搜索基础:
$ ldapsearch -x -b dc=tup,dc=com
这个输出将列出以 轻量级目录交换格式(LDIF)显示的某些容器和在配置过程中创建的组。以下截图显示了我的系统输出中的一个组:
389-ds 的一个大优势是 GUI。我们可以从服务器上运行它,或者我们可以将控制台安装在客户端机器上。我们将从服务器上使用以下命令运行它:
$ 389-console -a http://ldap1.tup.com:9830
我们将看到一个图形化控制台,如以下截图所示,在此我们可以以管理员身份登录:
LDAP 用户账户管理
目录的目的是存储用户账户。这些账户不一定用于身份验证,但我们可以用它们进行身份验证。这可能适用于其他 CentOS 或 Linux 系统,以及如 Apache 这样的服务。现在我们将查看如何通过命令行和 GUI 控制台在目录中创建用户账户。如果从 GUI 控制台开始,我们可以创建并导出用户,再从命令行重新导入。
使用 GUI 控制台添加用户
我们可以像之前一样使用管理员帐户登录到控制台。从主欢迎页面,我们应该选择用户和组选项卡,然后选择搜索按钮。在搜索对话框中没有任何内容时,搜索将返回所有用户、组和容器。我们可以看到的容器对象是组织单位;组织单位(OU)有点像文件系统中的文件夹。在目录中,OU 用于组织对象。导航到名为"people"的 OU,我们可以使用菜单创建 | 用户(位于屏幕底部)。这将打开一个表单,供我们填写用户的详细信息。在用户表单上,我们将添加以下数据:
名字 | Bob |
---|---|
姓氏 | Bloggs |
常用名称 | Bob Bloggs |
用户 ID | bbloggs (建议全部小写) |
密码 | Password1 |
确认密码 | Password1 |
如果我们只需要一个用户来支持应用程序登录,例如来自 Apache Web 服务器的登录,这些就足够了。由于我们最终想要从 Linux 登录,我们还将完成如下的Posix 用户表单:
-
启用 Posix 用户属性:
已选择
-
UID 号码:
5000
-
GID 号码:
100
-
主目录:
/home/bbloggs
-
登录 Shell:
/bin/bash
这些属性然后结合起来创建我们的用户。它将在 389-console 以及ldapsearch
中显示。如果我们重新运行之前的搜索,这次我们将添加一个筛选器,仅显示与posixAccount
匹配的对象:
$ ldapsearch -x -b dc=tup,dc=com objectClass=posixAccount
这应该只显示一个条目。
从命令行添加用户
要从命令行创建用户,我们有一个类似于ldapsearch
的工具。ldapadd
命令将创建目录中的用户。用户帐户的详细信息将在一个 LDIF 文件中定义,并作为ldapadd
命令的参数使用。我们还需要进行身份验证才能执行此操作,因为匿名连接无法在目录中创建条目。我们将首先确保身份验证正确,方法是使用ldapsearch
;这也将允许我们查看新用户bbloggs
的所有属性。编辑此输出后,我们将在导入时使用ldapadd
创建新用户。
$ ldapsearch -x -D "cn=directory manager" -w Password1 -b dc=tup,dc=com objectClass=posixAccount > /tmp/user.ldif
使用此搜索,我们现在以目录管理器身份进行身份验证,并将输出重定向到/tmp/user.ldif
文件中。使用-W
选项代替-w
,可以在操作过程中请求密码,而不是将其放在命令行上。
我们应该使用你喜欢的文本编辑器编辑该文件,使其看起来类似于以下内容:
dn: uid=ssmith,ou=People,dc=tup,dc=com
givenName: Sally
sn: Smith
loginShell: /bin/bash
uidNumber: 5001
gidNumber: 100
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetorgperson
objectClass: posixAccount
uid: ssmith
cn: Sally Smith
homeDirectory: /home/ssmith
userPassword: Password1
提示
我们手动设置uidNumber
,并且它必须随着其他基于名称的字段的更改而递增。
编辑文件后,我们可以使用命令行中的ldapadd
命令创建用户:
$ ldapadd -x -D "cn=directory manager" -w Password1 -f /tmp/user.ldif
如果你输入正确,你应该会看到类似于以下截图的成功信息,这张截图来自我的系统:
新用户的密码将以加密形式存储,尽管我们从 LDIF 文件中添加时是以明文形式输入的。
我们现在已经看到如何使用标准的 OpenLDAP 工具来搜索和添加目录条目,并且如果我们愿意,也可以使用图形化工具。现在系统中有两个用户,可以将其配置到客户端 Linux 系统上。
LDAP 身份验证
我们将使用另一台 CentOS 6.5 服务器,在该服务器上配置 OpenLDAP 客户端进行身份验证,以便使用我们在 389-ds 服务器上建立的中央账户数据库。
从客户端机器上,我们需要安装以下软件包:
-
openldap
-
openldap-client
-
nss-pam-ldapd
这将通过标准的yum
仓库进行管理:
# yum install openldap openldap-clients nss-pam-ldapd
安装完成后,我们需要对/etc/sysconfig/authconfig
文件进行一次更改。我们将编辑其中的FORCELEGACY=no
这一行,将其改为FORCELEGACY=yes
。此更改将允许我们使用 LDAP 而非 LDAPS。尽管使用 LDAPS 更安全,因为它加密了数据交换,但使用 LDAP 可以避免为服务器创建证书,这在局域网环境中已足够。
配置身份验证时,我们可以使用authconfig
命令:
# authconfig --enableldap --enableldapauth --enablemkhomedir \
--enablemkhomedir --ldapserver=ldap://192.168.0.76:389/ \
--ldapbasedn="dc=tup,dc=com" \
--enablecache -- disablefingerprint --update
这将配置身份验证并将配置写入正确的文件。你会注意到,我们包括了创建用户家目录的选项--enablemkhomedir
;如果用户的家目录不存在,登录时将会创建该目录。在创建用户时我们添加了家目录路径,但这并没有创建实际的家目录。除非我们将客户端机器上的/home
目录重新映射到一个中央位置,否则这些家目录不会被共享。
我们现在可以使用上一章提到的getent
命令来验证配置:
# getent passwd
这应该会列出来自中央 LDAP 服务器的bbloggs
和ssmith
账户。可以在我的系统输出中看到这一点:
现在我们可以注销并以我们的一个用户身份重新登录。选择ssmith
账户后,我们登录到图形化的 gnome 桌面,进入系统 | 首选项,并点击关于我按钮。我们可以看到我们以Sally身份登录。以下是我的系统输出的截图:
总结
在本章中,我们向您介绍了身份管理的概念,并展示了如何在 CentOS 上使用 389-ds,即增强版 OpenLDAP 服务器。它通过简化的设置脚本和图形化工具进行了增强;然而,我们也展示了如何使用传统的 OpenLDAP 工具在目录中创建和搜索条目。我们通过允许第二台 CentOS 服务器使用由 389-ds 共享的账户数据库来结束本章,使得我们能够在多个系统之间实现单点登录。
在下一章,我们将讨论 Nginx web 服务器,作为新兴的竞争者,它是 Apache 的一种清新替代方案。
第八章:Nginx – 部署一个以性能为中心的 Web 服务器
在谈到 web 服务器时,似乎 Apache 总是占据着所有的关注点,你可能会被引导认为几乎没有竞争对手;因此让我来向你介绍一下 Nginx。我们已经看过很多实现Linux Apache MySQL 和 PHP(LAMP)技术的文章。我们将在此稍作调整,看看Linux Nginx MySQL 和 PHP(LEMP);LEMP 中的 E 来自于该 web 服务器的发音版本 engine-x,这个发音让我们得以为这个首字母缩写加上一个必要的元音字母。该 web 服务器首次推出是在 2004 年,Nginx 开始逐步进入企业级 web 空间,并且在提供 web 内容的速度上超过了相同的 Apache 服务器。
本章将涵盖以下主题:
-
安装和配置 Nginx:我们将安装并配置 Nginx web 服务器
-
安装 PHP:我们将安装 PHP5 并与 Nginx 集成
-
安装 MySQL:我们将安装并配置 MySQL 数据库服务器
-
创建动态 web 内容:使用 LEMP 堆栈,我们将学习创建简单的动态网页
安装和配置 Nginx
为了开始本章内容,我们需要在 CentOS 系统上安装 web 服务器 Nginx。Nginx 是 web 服务器的新星,但根据 NetCraft 最近的调查,www.netcraft.com
,我们看到互联网对 Apache 的喜爱有所减少,自 2004 年 Nginx 推出以来,它稳步增长。尽管如此,在 2014 年 5 月,Apache 仍然占有 37% 的 web 服务器份额,微软占 33%,而 Nginx 占 14%。
安装 Nginx
Nginx 并不包含在标准的软件仓库中,但我们可以使用在安装 第七章中提到的 EPEL 仓库,LDAP – 一种更好的用户类型。有了 企业 Linux 扩展包(EPEL)仓库后,我们可以使用 yum 安装,然后在安装了 Nginx 后,我们可以启动服务并使用 chkconfig
配置它在系统启动时自动启动:
# yum install nginx
# service nginx start
# chkconfig nginx on
默认站点的配置中已配置了一个欢迎页面,该页面指向 /usr/share/nginx/html/
。我们将保留此设置,但很快会创建我们自己的文档根目录。我们可以通过访问 http://localhost
来测试 web 服务器的功能,如下图所示:
这真的非常简单,不是吗!我们可能需要用我们自己的网页替换这个页面,并整理一些其他配置;但这个简单的测试足以证明网站已经启动并运行了。
配置 Nginx
Nginx 的配置目录,或称为 ServerRoot
,是 /etc/nginx
。主配置文件是 /etc/nginx/nginx.conf
;但是,Web 服务器采取了一种非常模块化的配置方法,主配置文件中有一个包含语句,它会引用 conf.d
中的所有 .conf
文件。nginx.conf
中的语句如下:
include /etc/nginx/conf.d/*.conf
通过这种方式,可以轻松地添加其他配置,而无需编辑现有文件,也不会冒犯代价高昂的错误。定义初始服务器的默认配置文件是 /etc/nginx/conf.d/default.conf
。为了帮助理解 Nginx 配置文件的一些结构,让我们看一下以下的图示:
为了更好地理解 Nginx 的配置,通常最好从自己的配置开始。先从简单的配置开始,然后逐步添加。为此,我们将 default.conf
重命名为其他名称,并创建我们自己的配置。对于一个简单的服务器配置,我们只需要不到五行代码:
server {
listen 80;
root /var/www/html;
index index.html;
}
前面的几行可以将此配置保存到新文件 /etc/nginx/conf.d/main.conf
。然后,我们将原始配置 /etc/nginx/conf.d/default.conf
重命名为 /etc/nginx/conf.d/default.conf.old
。只有 .conf
文件会被包含进来,因此通过这种方式,我们可以保持原始配置而不影响 Web 服务器的运行。
我们的新配置非常简单且稀疏,我们可以解释有限的指令:
-
listen
:我们将监听所有接口的 TCP 80 端口。 -
root
:在这里,我们将文档根目录设置为/var/www/html
。最好将像这样的变量内容放在/var
结构中,而不是默认的/usr
位置。 -
index
:我们将默认页面(通常称为欢迎页面)设置为index.html
。如果客户端的 URL 只输入服务器名称,或者是服务器名称加上目录路径而没有指定网页,那么服务器将寻找名为index.html
的页面。
我们需要为文档根目录创建目录结构,并制作一个简单的网页:
# mkdir /var/www/html
#echo '<h1>Welcome to NGINX</h1>' > /var/www/html/index.html
在理想情况下,在重新启动 Nginx 服务器之前,我们应该尽量测试任何配置更改。通过这种方式,我们可以避免因配置异常导致的服务器重启中断的尴尬问题。当我们发出重启命令时,首先需要停止服务然后再启动 Nginx。停止服务不会有问题,但如果我们遗漏了分号或其他小错误,启动时可能会出现问题。因此,可能需要几分钟才能找出问题并恢复正常服务。在对 Nginx 配置做出任何更改后,我们应始终测试这些修改的完整性,然后再重启。使用 /usr/sbin/nginx -t
命令,我们可以进行此检查,确保如果停止服务器,我们能够重新启动它。如果你更喜欢,也可以通过使用 service nginx configtest
命令来进行相同的测试。
nginx
命令的其他选项包括 -v
用于显示 Nginx 的版本,-V
显示版本和配置选项。如果我们遇到错误,可以检查日志文件 /var/log/nginx/error.log
。tail
命令通常对这个很有用,因为它只会显示最后 10 行。错误日志的路径在 /etc/nginx/nginx.conf
中配置,以下行进行设置:
error_log /var/log/nginx/error.log
如果需要,你可以将其更改为其他日志文件;但默认设置似乎是合理的。现在,我们可以确保配置正常并通过以下方式重新启动服务:
# nginx -t && service nginx restart
提示
在这个命令序列中,&&
运算符确保只有在第一个命令成功且配置检查没有错误时才会重新启动。
我们现在可以重新访问我们的网站了。它可能看起来不那么华丽,但正如我们在以下截图中看到的那样,它完全是我们自己的工作:
配置 404 文档未找到错误页面
另一个我们将实现的小改动是控制“页面未找到”或 HTTP 404 错误。如果用户输入了一个不存在的页面,那么他们将看到一个非常简单的错误页面。我们可以稍微自定义一下,至少给用户提供一个返回主索引页面的链接。如果我们重新编辑配置文件 /etc/nginx/conf.d/main.conf
,它现在会显示如下:
server {
listen 80;
root /var/www/html;
index index.html;
error_page 404 not_found.html;
}
额外的 error_page
行会查找 HTTP 404 错误并返回 not_found.html
页面。我们当然需要创建该页面,它可能看起来像这样,作为一个非常简单的示例,提供错误信息和返回首页的链接:
<h2>We could not locate the document</h2>
<a href='/index.html'>Home</a>
记得测试配置;我们可以通过以下方式重新启动 Web 服务器:
# nginx -t && service nginx restart
然后,访问一个我们知道不存在的页面,例如 http://localhost/page1.html
。我们应该能看到新的错误页面,如果你使用了我的示例,它可能看起来像这样:
虽然网页的设计简单且裸露,但我们并不是在这里教 HTML 或 CSS 技巧,而是更多地探讨如何通过 Nginx 指令实现自定义错误页面的思路。
安装 PHP
现在我们已经让 Web 服务器启动并运行,我们可以添加需要的 PHP 处理器,从而能够在页面中添加 PHP 元素,并随后创建动态的 Web 内容。Nginx 使用 PHP FastCGI 进程管理器,这个也可以从 EPEL 仓库中获取。我们已经在 Nginx 安装时以及之前安装 389-ds 时设置好了它。为了安装 PHP 和 PHP-FPM,我们可以使用 yum
:
# yum install php-fpm
安装完成后,我们需要编辑 FPM,以便它使用正确的 Nginx 账户。为此,我们可以编辑/etc/php-fpm.d/www.conf
文件。我们需要将用户和组的行从apache
修改为nginx
:
user = nginx
group = nginx
我们还需要确保 Nginx Web 服务器知道将 PHP 文件转发到 FPM 服务的 9000 端口。我们可以重新编辑/etc/nginx/conf.d/main.conf
文件并将其添加到服务器部分:
server {
listen 80;
root /var/www/html;
index index.html;
error_page 404 not_found.html;
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name
include fastcgi_params;
}
}
我们添加的代码都在原始服务器块内。文件会以两个右括号正确结束。我们正在关闭新的 location 块和原始的服务器代码块。回顾一下编辑内容,我们可以看到我们定义了一个 location
块。这个块在我们访问以 .php
结尾的网页时使用,或者更简单地说,访问 PHP 页面。location 块的定义看起来有点像漫画书中的脏话,这应该能让你识别出它实际上是一个正则表达式;波浪符号(~
)表示我们在寻找正则表达式匹配。我们要查找的表达式是以 .php
结尾的 URL。$
符号表示字符串的结束。完整的表达式以转义字符\
开始;这是必要的,因为句点(dot)在正则表达式中有特殊含义。为了保护它,我们使用 \
告诉 Nginx 将其视为字面上的句点,而不是正则表达式语言元素。接下来的代码块则表示我们应该通过本地主机的 9000 端口将 PHP 代码传递给 PHP 解释器。include
语句用于读取一个预配置的 PHP 文件,以设置各种参数值。
现在我们可以测试并重启 Nginx Web 服务器,并启动 FPM 服务,配置它为自动启动:
# nginx -t && service nginx restart
# service php-fpm start
# chkconfig php-fpm on
凭借一点运气和顺风,一切都已成功,但当然,我们现在需要测试一个 PHP 页面;这可以通过调用一个简单的phpinfo()
函数轻松实现。这是一个非常简单的测试,它将证明 PHP 在你的 CentOS 系统上正常运行。我们将返回到 Nginx 的文档根目录/var/www/html
并创建一个新页面info.php
。PHP 扩展很重要,因为这是我们在位置块中寻找的:它将指引我们进入 PHP 解释器。我们将创建的页面再简单不过了;然而,这个功能背后的强大作用将在你的网页浏览器中展示出很多内容,输入几行代码就能实现。我们可以在同一个文件中混合 HTML 代码和 PHP 代码,但在这里我们只使用 PHP。PHP 代码块以<?php
开始,并以关闭标签?>
结束。每行 PHP 代码后面都需要加一个分号。编辑后的/var/www/html/info.php
文件将如下所示:
<?php
phpinfo();
?>
当我们将浏览器指向http://127.0.0.1/info.php
页面时,我们应该看到一个详细的页面,展示了 PHP 在我们 CentOS 主机上的配置。请看以下截图,展示了我系统的输出:
很快,我们就通过这个简单的测试展示了 PHP 背后的强大功能。我们也可以确信,PHP 已经在我们的系统上正确配置并与 Nginx 一起运行。接下来我们将添加 MySQL 数据库。
安装 MySQL
MySQL 是由 Oracle 管理的开源数据库解决方案,当然,这也是我们实现的 LEMP 栈中的关键组件。MySQL 服务器可以存储数据,稍后在我们的网页中显示。我们将通过 PHP 与数据库服务器进行 Nginx 的通信。我们可以使用yum
来安装 MySQL 及 PHP 模块:
# yum install php-mysql mysql-server
# service mysqld start
# chkconfig mysqld on
一旦安装了 MySQL,我们需要进一步确保安装的安全性;即使只是设置 MySQL 的 root 密码。许多系统的开箱安全性通常有些薄弱。通过mysql_secure_installation
命令,我们可以增加一些额外的安全性。运行该程序将引导你进入一个简单的交互式提示会话:
# mysql_secure_installation
生成的向导将引导你完成以下过程:
-
输入当前 root 密码:目前为空,所以直接按 Enter 键。
-
设置 root 密码:我们将选择
Y
。 -
新密码:输入新密码并确认。
-
删除匿名用户:选择
Y
。这样,只有配置好的账户才能访问。 -
禁止远程 root 登录:这通常是一个好主意,可以防止远程 MySQL root 访问。我们只需要从此主机进行访问,所以我们将回答
Y
。 -
删除测试数据库及其访问权限:有一个空的数据库测试。如果我们不需要它,应该删除它。
-
现在重新加载权限表:我们将回答
Y
以使这些设置生效。
如果仅仅为了这个目的,这是设置 MySQL 根账户密码的最简单方法之一,并提醒我们在执行简单脚本时验证其他设置。当我们准备好时,我们可以通过 Linux 命令行测试数据库服务器的运行:
$ mysql -u root -p -e 'show databases;'
我们以 root 身份进行身份验证,并且系统会提示我们输入之前设置的密码。-e
选项允许我们直接从命令行执行 MySQL 查询,随后的查询将列出所有数据库。当然,这些将是系统数据库,因为我们还没有创建自己的数据库。我们可以在网页中使用相同的查询,稍后用来显示我们是否能够从 Nginx 连接到数据库。从查询结果中,我们应该看到列出两个数据库:information_schema
和 mysql
。
创建动态网页内容
为了展示我们如何轻松地创建动态网页,并通过 PHP 从 Nginx 服务器连接到数据库,我们将在/var/www/html
中创建一个新的 PHP 页面。所以,启动你最喜欢的编辑器,我们将在文档根目录下创建页面,路径为/var/www/html/db.php
:
<h2>Databases</h2>
<?php
$dbh=mysqli_connect("localhost","root","Password1");
$result=mysqli_query($dbh, "SHOW DATABASES");
while ($row = mysqli_fetch_assoc($result)) {
echo $row['Database'] . "<BR>";
}
?>
代码再次保持尽可能简单,理想情况下,我们会将连接凭证存储在另一个无法被 Web 服务器访问的文件中,只允许 PHP 进程访问;然而,在这个早期阶段,保持代码简洁有助于学习过程。
在这个 PHP 文件中,你可以看到我们将一些 HTML 代码与 PHP 代码混合使用,先使用标题标签,然后进入 PHP 代码块。PHP 代码首先连接到 MySQL 服务器,然后我们执行之前在命令行中演示过的相同查询。在我们进行测试之前,我们需要重新启动 Nginx 和php-fpm
服务:
# service nginx restart
# service php-fpm restart
这一次,结果将在网页浏览器中显示,并说明我们已经创建了一个简单的动态页面,内容来自数据库。在这个阶段,我们可以为自己已经启动并运行的 LEMP 服务器感到高兴。有了这个概念验证,我们现在可以考虑在 LEMP 堆栈上构建进一步的项目,我也真心希望你能带着一些热情离开,去阅读更多关于你可以通过 PHP 和 MySQL 实现的内容。
这是你将看到的主页:
总结
在本章中,我们了解了如何基于 CentOS 主机和 LEMP 堆栈构建,并实现 Nginx、MySQL 和 PHP。Nginx 配置起来相当简单,但比 Apache 提供更快的网页内容访问速度,同时也可以配置与 PHP 和 MySQL 进行后台通信。掌握 PHP 和 MySQL 与 Web 服务器一起工作的基本知识,可以为你进一步开发 Web 应用程序打下基础。
在接下来的章节中,我们将看到如何在 CentOS 上实现 Puppet 作为中央配置服务器,允许在一台服务器上进行配置更改,然后将其复制到其他配置的客户端。
第九章:Puppet – 现在您是 Puppet Master
Puppet 来自 Puppet Labs,允许集中管理您的 Linux 设备。中央 Puppet 服务器被称为 Puppet master,延续了木偶戏的类比。这个主设备当然可以让您通过单一设备控制服务器和桌面(在 Puppet 术语中称为节点),尽管不需要用线操控木偶。Puppet master 向每个节点指定所需状态,每隔 30 分钟,节点会连接到 Puppet master 并发送关于其资源的事实;如果不符合所需状态,节点将自行修复以达成目标。在本章过程中,我们将研究 Puppet 配置,包括:
-
安装 Puppet master:我们将从 Puppet Labs 仓库安装和配置 Puppet master。Puppet master 将作为中央配置服务器,并存储每个节点所需的配置状态。
-
Puppet 资源:我们将使用
puppet resource
命令手动管理节点上的资源。资源代表所需状态的基本构建块,包括文件、用户、服务、定时任务和软件包等。 -
管理软件包、服务和文件:这三种资源代表了 Puppet 管理中的主要三要素,如果我们能管理这些,就几乎能够管理整个节点。我们将在清单文件中创建资源声明,并在本地和远程的 Puppet 代理上进行测试。
安装 Puppet master
正如我们所知,许多必须在 CentOS 上安装的服务,开始之前我们必须确保基础配置正确。在 Puppet master 的情况下,基础配置包括:
-
必须通过防火墙开放 TCP 端口
8140
-
Puppet master 应该能够通过 DNS 或本地主机文件解析为主机名
puppet
-
时间应同步
-
配置好的 Puppet Labs yum 仓库
我已在以下部分详细说明了这些内容。
配置防火墙
我在演示机上没有使用基于主机的防火墙。您的系统可能不是这样,如果您使用防火墙,则需要允许 TCP 端口 8140
通过 INPUT 链。可以使用以下命令检查防火墙的状态:
# iptables -L
这将列出已设置的规则以及默认策略。如果没有规则且默认策略是 ACCEPT,则您将不会遇到与防火墙相关的问题,可以放心。
DNS
Puppet 代理在每个客户端或节点上运行,并将尝试使用默认主机名puppet
与 Puppet 主服务器进行通信。此设置可以在/etc/puppet.conf
文件中更改。此更改需要在每个代理上实施,因此通常最简单的方法是在本地 DNS 中创建一个 ADDRESS 记录或 CNAME 记录,以便将主机名 puppet 解析到你想要的 Puppet 主服务器的 IP 地址。在示范实验室中,我已经设置了正确的 CNAME 记录。使用ping
命令,我们可以看到主机名是可解析的,输出如下所示:
网络时间协议
如果你尚未配置 Puppet 主服务器和代理节点的时间,那么你应该使用网络时间协议(NTP)进行配置。这将确保它们都共享相同的准确时间。所有设备都需要准确的时间,因为 Puppet 主服务器将作为证书服务器,向受信任的节点发放证书,并且证书上的时间戳不能位于未来。为了在 Puppet 主服务器上设置 NTP,我们将首先将时间与 NTP 服务器同步,然后使用 NTP 和存储在/etc/ntp.conf
文件中的条目配置定期更新时间,如下所示:
# ntpdate uk.pool.ntp.org
之前的命令使用一个基于英国的 NTP 服务器进行了一次性更新时间。这将设置时间,以便可以进行定期更新。如果没有设置这一点,时间可能无法同步,因为 NTP 客户端必须与 NTP 服务器的时间误差不超过 1000 秒,才能进行定期更新。现在我们可以启动 NTP 服务并配置它为自动启动。如果我们没有对配置文件/etc/ntp.conf
进行任何更改,那么时间将与来自 NTP 池的服务器进行同步。如果你已经在网络中有本地的时间服务器,那么使用该设备作为时间源是值得的,具体如下:
# service ntpd start
# chkconfig ntpd on
Puppet 实验室仓库
Puppet 主服务器在标准的 CentOS 仓库中不可用,也不幸地在我们已经配置的 EPEL 仓库中。这要求我们添加 Puppet Labs 软件仓库。这些仓库将提供最新的 Puppet 代理和主服务器软件。所有节点都需要安装 Puppet 代理,服务器则需要安装主服务器软件。我们将通过从 Web URL 安装 RPM 直接创建 Puppet 的 YUM 仓库。该 RPM 将仅在/etc/yum.repos.d
中定义仓库文件。
# rpm -ivh http://yum.puppetlabs.com/puppetlabs-release-el-6.noarch.rpm
这个过程会很快完成,因为它只需要创建一个仓库定义文件。仓库设置好后,我们现在可以准备安装 Puppet 主服务器。以下命令将安装最新版本的 Puppet 主服务器和代理,版本来自 Puppet Labs 仓库:
# yum install puppet-server
如常,我们应启动服务并启用自动启动。当完成此操作后,我们可以使用netstat
命令显示 Puppet 主节点正在监听 TCP 端口8140
:
# service puppetmaster start
# chkconfig puppetmaster on
# netstat -antl | grep :8140
Puppet 资源
从 Puppet 2.6 版本及以后的版本(当前版本为 3.6)开始,使用单一的puppet
二进制文件并通过子命令处理特定任务。早期版本为所有子命令提供了单独的二进制文件。在之前的命令集中,我们使用传统的 CentOS 语法启动 Puppet 主节点,并启用服务以实现自动启动;我们也可以通过/usr/bin/puppet
命令和resource
子命令实现相同的结果:
# puppet resource Service puppetmaster enable=true ensure=running
使用此命令,我们将关注puppetmaster
服务,启用它的自动启动(enable=true
),并在需要时启动它(ensure=running
)。这代表了 Puppet 工作的本质。当然,为了管理多个客户端,我们将创建具有类似资源规则的清单文件来强制执行期望状态。但就其本身而言,我们将通过使用puppet resource
命令来配置节点的期望状态。
除了设置期望状态外,我们还可以使用类似的命令查看所有服务或单个命名服务的状态;以下是两个这样的命令,第一个命令将显示所有服务,第二个命令将只显示puppetmaster
服务:
# puppet resource Service
# puppet resource Service puppetmaster
puppetmaster
服务的命令输出如以下屏幕截图所示:
如前所述,在本章的介绍中,我们通过 Puppet 管理的三个主要资源包括:
-
服务
-
文件
-
软件包
除了这些主要资源外,我们还有其他资源,包括以下内容:
-
用户
-
用户组
-
定时任务
-
通知
-
Yum 仓库
-
ssh_authorized_key
-
接口
为了了解 Puppet 如何管理这些资源,我们将通过一个示例来演示,使用puppet resource
命令手动强制将节点的状态设置为期望状态。即使我们运行命令的节点是 Puppet 主节点,但就目的而言,我们仅使用客户端,即在此阶段的 Puppet 代理。我们之前使用puppet resource
的示例展示了使用 Puppet 可以实现的目标,然后将期望的状态配置移动到 Puppet 主节点的清单文件中。
使用puppet resource user
,我们可以确保系统上存在某个用户帐户,通过引用一个不存在的帐户,Puppet 会创建该帐户并设置给定属性的密码。如果需要删除一个帐户,我们可以使用ensure=>absent
属性。
首先,我们必须获取新用户帐户的加密密码。可以使用不同的机制来实现这一点,但在这里我将使用命令行中的 Python 来生成密码:
# python -c 'import crypt; print crypt.crypt("Password1","$5$RA")'
该命令的输出将是新用户使用的 SHA-256 密码。我们现在准备好使用 Puppet 创建用户:
# puppet resource User newuser ensure=present uid='2222' gid='100' home='/home/newuser' managehome=true shell='/bin/bash' password='<encrypted password>'
提示
像这样描述资源的代码块称为资源声明。
这将使用一组期望的属性值创建用户。用户的主目录将会与用户帐户一同创建。此行为由 managehome
属性控制;将其设置为 true
将创建目录。
尽管我们不希望手动在所有服务器上设置这个集合,就像在这种情况下一样,但我们可以使用类似的方法来允许所有节点上的 root 账户定期更改密码,并确保其他系统账户存在。
管理软件包、服务和文件
我们将从手动配置转向将 Puppet 作为中央配置服务器,并在清单文件中定义需要分发到所需节点的设置。为了开始这个过程,我们将创建清单文件;这些只是文本文件,并且在 Puppet 主控服务器上使用 puppet apply
进行本地应用。一旦验证了清单的工作状态并强制执行所需状态,我们将注册客户端并看到真正的 Puppet 自动化工作。
Puppet 的构建块始于我们已经查看过的资源声明。这些声明被写入具有扩展名 .pp
的清单文件中。在清单文件中,资源可以被分组成类。一个类通常表示相关的资源,例如 openssh-server
软件包、sshd
服务以及 /etc/ssh/sshd_config
配置文件。将这些资源组合到类定义中似乎是合理的做法。
我们可以通过查看示例清单文件的内部来查看这些构建块,如下图所示:
类
类是可重用的,因为一个类可以被多个节点定义使用,并且在某个节点上使用过给定类之后,它只能使用一次,不能重新声明。我们在这里创建的类名为 ssh
。必须先定义类,然后才能声明。以下代码块是一个类定义的示例:
class web-servers {
code……
}
下面的示例代码展示了同一类的声明方式:
include web-servers
资源定义
资源定义,比如我们之前为用户资源所看到的内容,不需要被包含在类中;然而,通常通过类的方式将相关资源组合起来,以便于分配给节点。在这个例子中,我们定义了一个文件资源和一个服务资源。服务资源的名称必须与将要分配到的节点上的服务名称匹配;在 CentOS 的情况下,OpenSSH 服务器是 sshd
服务。
在 Puppet 中,资源是特定资源类型的实例。要列出 CentOS 中所有可用的类型,我们可以使用 describe
子命令:
# puppet describe -l
资源类型有一个定义的模式,说明了哪些属性是可用的。要列出资源类型的模式详细信息,我们可以再次使用 describe
子命令:
# puppet describe -s User
# puppet describe User
使用 -s
选项和不使用 -s
选项时都会显示简短描述;资源类型模式的完整列表将列出。在前面的命令中,我们显示了 user
资源类型的信息。
在本章早些时候,我们通过命令行使用 puppet resource
创建了一个新用户账户。如果我们需要在多个节点上创建系统账户,并希望 Puppet 为其配置账户,我们可以在类似于以下的清单文件中创建 user
资源定义:
user { 'puppetuser' :
ensure => present,
uid => '99',
gid => '99',
shell => '/bin/false',
password => '$5$RA$e7cMcsFNqvFkZrlm62fnzy0vpN2GxrOjzpsLaVQzIc4',
home => '/tmp',
managehome => false,
}
Puppet 事实
在我们之前列出的示例清单中,我们为 /etc/motd
文件定义了一个文件资源。当用户登录系统时,无论是本地登录还是通过远程 SSH 连接,都会显示该文件。Puppet 代理将比较节点配置中的事实,以查看是否与期望的状态匹配。这些事实通过 /usr/bin/facter
命令从机器配置中收集。我们可以通过以下方式显示这些事实:
$ facter
上述命令将显示所有事实,而以下命令仅显示 IP 地址:
$ facter ipaddress
我们可以通过使用附加属性来进一步扩展资源定义,并用一些事实填充内容,如下所示:
file {'/etc/motd' :
ensure => file,
mode => 0644,
content => "Welcome to TUP
This is a ${operatingsystem} ${operatingsystemrelease} host with IP ${ipaddress}
",
}
如果此资源定义应用于某个节点,它将确保该文件类型为“文件”;而不是目录,权限将设置为 rw- r-- r--
,并且内容将随着三个基于事实的变量扩展。这将创建如下所示的内容:
请记住,我们只需要创建一次资源定义。在 Puppet 服务器上,这个定义将应用于所有分配给它的节点。然而,通过使用基于每个节点的事实的变量,我们可以为每个独立的 /etc/motd
文件创建独特的内容。
使用 include
include
语句声明了类的使用。如果我们定义了一个类,但没有使用 include
语句,那么任何资源定义都不会被使用。类可以在声明它的同一个清单中定义,但更常见的是,类定义在单独的清单文件中,这些文件是通过 Puppet 模块路径创建的。modulepath
默认指向 /etc/puppet/modules
和 /usr/share/puppet/modules
目录。你可以使用以下命令查看模块路径,它是以冒号分隔的:
# puppet config print modulepath
我在 CentOS 系统上的输出显示了默认设置,如以下屏幕截图所示:
创建和测试清单
清单是具有.pp
扩展名的 ASCII 文本文件。这些文件包含类声明和/或资源定义。类也在清单中定义和声明;然而,正如前面所提到的,它们通常在与声明它们的清单文件不同的独立文件中定义。这允许代码具有更大的模块化。清单文件可以作为本地文件提供,并通过 Puppet 的apply
子命令调用,或者更常见的是通过 Puppet 主服务器进行调用。我们将使用puppet apply
在本地应用清单。我们将创建的文件将与客户端-服务器部署一致,这样一旦在本地测试完成,我们可以重用相同的文件;为此,我们将创建文件/etc/puppet/manifests/site.pp
。节点在连接到 Puppet 主服务器时,将查找site.pp
文件以获取其配置。示例清单如下所示:
class tup {
file {'/etc/motd' :
ensure => file,
mode => 0644,
owner => 'root',
group => 'root',
content => "Welcome to TUP
This is a ${operatingsystem} ${operatingsystemrelease} host with IP ${ipaddress}
",
}
service {'sshd':
ensure => running,
enable => true,
}
package { 'openssh-server' :
ensure => installed,
}
}
include tup
在清单已创建并保存在/etc/puppet/manifests/site.pp
后,我们可以使用以下命令验证文件的语法:
# puppet parser validate /etc/puppet/manifests/site.pp
如果看到错误,可以重新编辑文件以修正这些错误,当输出没有错误时,我们可以手动应用该文件:
# puppet apply /etc/puppet/manifests/site.pp
使用cat
命令,我们可以验证/etc/motd
文件的内容:
$ cat /etc/motd
如果现在停止sshd
服务并更改文件的权限,我们可以看到 Puppet 如何确保配置的一致性:
# service sshd stop
# chmod 777 /etc/motd
由于所做的更改,我们已偏离所需的状态,现在可以重新应用清单;在正常的客户端-服务器操作中,Puppet 代理每 30 分钟会检查一次服务器。
# puppet apply /etc/puppet/manifests/site.pp
输出应包括类似以下截图的通知,表明服务已经启动并且模式已更改:
注册远程 Puppet 代理
如我们所见,Puppet 在保持一致的配置方面非常有效,但我们不希望在每台设备上创建清单并手动运行 Puppet 命令。为了看到 Puppet 作为中央配置服务器的真正强大功能,我们需要注册客户端,并让 Puppet 代理作为服务运行。正如我们之前提到的,当代理服务运行时,代理将每 30 分钟自动检查其期望的状态。
从远程 CentOS 6.5 系统,我们将使用以下命令检查是否能够解析 Puppet 主服务器的主机名:
$ host puppet
如前所述,我们需要确保在远程节点上进行时间同步:
# ntpdate uk.pool.ntp.org
# service ntpd start
# chkconfig ntpd on
我们将把远程 Puppet Labs 仓库添加到远程客户端 CentOS 系统:
# rpm -ivh http://yum.puppetlabs.com/puppetlabs-release-el6.noarch.rpm
最后,我们将在客户端系统上安装 Puppet 代理并显示 Puppet 的版本:
# yum install puppet
# puppet --version
在撰写本文时,Puppet Labs 仓库的版本为 3.6.2。
我们现在准备测试客户端。第一步是手动启动代理,这样我们可以将节点注册到服务器。这将向 Puppet 主节点提交证书签名请求,因为该节点尚未注册:
# puppet agent test
现在返回到 Puppet 主节点的控制台,我们可以检查代理签名请求的证书颁发机构:
# puppet ca list
我们应该能在我们的实验室设置中看到来自客户端机器的请求;客户端请求显示centos65.tup.com
。我们可以使用以下命令接受并签署此请求:
# puppet ca --sign centos65.tup.com
现在我们返回到客户端机器并重新运行测试代理;这将下载签名证书,代理随后将下载并应用site.pp
清单:
# puppet agent test
现在我们可以检查/etc/motd
文件的内容。我们应该能看到之前看到的内容,但加上了该节点的 IP 地址。从远程客户端机器使用cat
命令,输出将类似于以下截图:
现在我们已经在客户端安装了签名证书,可以启动代理服务并让系统自我管理;现在我们可以有更多时间去高尔夫球场了!
# service puppet start
# chkconfig puppet on
在 CentOS 上,代理服务就是 Puppet,并且在服务运行时,代理每 30 分钟检查一次配置。
总结
本章中,我们探讨了如何使用 Puppet 实现中央配置管理。虽然我们仅在 CentOS 上进行了演示,但该配置可以在多个操作系统上工作,包括 Linux、Windows 和 Unix。主服务器是 Puppet 主节点,代理通过 TCP 端口8140
连接以下载站点清单。该清单可以包括其他类,但会确定节点的期望配置。
在进入下一个章节时,我们将探讨如何使用可插拔认证模块(PAM)来帮助强化 CentOS 主机,并进一步了解 SELinux 的世界。
第十章:安全中心
Linux 安全不仅仅是书中的一章,它是一种生活方式。在你执行 CentOS 中的每一项任务时,你都应该考虑安全影响,以及如何让你的操作变得更加安全。当然,安全有很多形式,其中很多都很简单(例如,服务器房里上锁的物理安全等等)。在这一部分,我们将深入了解 可插拔认证模块(PAM)和 SELinux。不要害怕这两者,尤其是 SELinux;它们是你的朋友。在本章中,我们将涵盖以下内容:
-
理解 PAM 配置文件:PAM 的核心是位于
/etc/pam.d
中的文件;我将带你了解它们的语法和含义。 -
PAM 的限制:通过 PAM 的限制模块,我们可以限制用户会话中可以使用的系统资源。
-
SELinux:这是一个快速指南,涵盖了 SELinux 从文件系统到用户视角的内容。
-
加固 Linux:这是一个关于如何保护你的 Linux 服务器的检查清单。
理解 PAM 配置文件
与其将认证功能构建到每一个需要它的应用程序中,大多数 Linux 服务会使用如 PAM 这样的模块。这些模块具有 .so
扩展名,用于标识它们是标准模块,并且是由程序而不是内核直接使用的。它们通常位于 /lib/security
或 /lib64/security
目录下,具体位置取决于你的系统是 32 位还是 64 位。每个具有 PAM 功能的服务或程序都有自己的配置文件,规定如何强制执行认证和会话设置;这些文件位于 /etc/pam.d
中。快速查看这个文件夹,你会看到一些熟悉的名称,如 sshd
、sudo
、su
和 login
,它们都代表了具有一定认证功能的服务。
/etc/pam.d/login
文件将由控制台登录程序使用,/etc/pamd/sshd
则由 OpenSSH 服务器使用。每个配置文件中会有多行内容,每一行都包含类型、控制、模块路径以及可选的模块参数设置。
从下图中,你可以对文件语法有所了解,并看到四种类型的设置:账户、认证、会话和密码。
以以下这一行作为例子:
account required pam_nologin.so
这一行来自 /etc/pam.d/login
文件,并且已为指定模块 pam_nologin.so
设置了 account
类型,控制设定为 required
:此模块会检查 /etc/nologin
文件的存在情况;如果该文件存在,即使身份验证成功,用户也无法访问系统。他或她将看到 /etc/nologin
文件的内容或一个通用消息,说明无法登录。此方法本身成为一种临时禁用登录服务器的简单方式,只需创建 nologin
文件;删除文件即可重新启用登录。
PAM 配置文件的每个元素如下所示。
类型
类型定义了模块何时会被调用。共有四种有效的类型:
-
账户: 通常用于根据一天中的时间、最大用户数、并发登录等条件来限制或允许访问服务。可以将这些视为账户限制。
-
认证: 用于确定用户身份,通常是通过提示输入密码。此模块也可以用于授予用户组成员资格。
-
密码: 此类型用于更新用户的认证令牌;通常是密码。通常,每个挑战和响应认证方法需要加载一个模块。
-
会话: 关联于在用户访问服务器之前必须完成的事件,例如创建主目录(如果需要)。
控制
控制字段表示基于模块返回的成功或失败,PAM-API 的行为。
-
required (
success=ok new_authtok_reqd=ok ignore=ignore default=bad
): 失败最终会导致 API 返回failure
,但只有在其他模块执行完后才会返回。 -
必需 (
success=ok new_authtok_reqd=ok ignore=ignore default=die
): 类似于“required”,但是控制和失败会立即返回给调用服务。 -
足够 (
success=done new_authtok_reqd=done default=ignore
): 此类型模块的成功足以满足认证要求,除非先前的必需模块失败。此类型模块的失败不会致命。 -
可选 (
success=ok new_authtok_reqd=ok default=ignore
): 此模块的成功或失败不重要。
提示
最近,第二种标记(括号内的内容)用于表示控制值,认为这是对含义更好的解释。
模块路径
模块路径将包括引用模块的完整文件系统路径,路径以 /
文件系统开头,或者是相对于 /lib/security
或 /lib64/security
目录的路径。
模块参数
模块参数是一个以空格分隔的标记列表,可以修改模块的行为。以下是一个示例:
silent umask=077 skel=/etc/skel
我们可以将参数组合在一起,举个例子,在用户首次登录时为他们创建家目录。这在我们一次性创建许多账户时很有用,可以避免同时创建家目录时过载服务器。这在大学等地方非常常见,很多账户是批量创建的。
用户很可能通过 SSH 连接到服务器,因此我们应该考虑将以下行添加到 /etc/pam.d/sshd
文件中:
session required pam_mkhomedir.so umask=0077 skel=/etc/skel
该机制利用 PAM 在用户登录时创建家目录。
PAM 的限制
目前我们继续使用 SSH 登录。许多用户可能只通过 SSH 访问服务器,可能在 Windows 上使用 PuTTY SSH 客户端。如果我们想控制对系统资源的访问,可以通过 PAM 和 pam_limits.so
来实施限制。我们应该将以下行添加到 /etc/pam.d/sshd
文件中:
session required pam_limits.so
这将实现该模块,但我们仍然需要在 /etc/security/limits.conf
文件中设置限制;该模块从此文件中读取。文件的结构如下,以下元素构成 limits 文件中的一行:
<domain> <type> <item> <value>
域
域表示限制适用的对象。通常,这是一个用户名,例如 user1
,或者一个组条目,例如 @users
;@
符号用于区分用户名和组名。要对所有没有自己条目的账户应用默认限制,可以使用通配符 *
。
类型
类型可以设置为 soft
、hard
或两者的组合(用 -
)。使用 hard
限制来强制执行硬资源限制。这些限制由 root 用户设置并由内核强制执行。用户不能将其系统资源需求提高到这些值之上。强制执行限制前请小心测试,因为如果无法创建足够的进程,可能会导致系统崩溃。
soft
限制用于强制执行软资源限制。这些限制是用户可以在允许的范围内上下调整的,前提是没有预设的硬性限制。使用这个标记指定的值可以视为正常系统使用的默认值。使用 -
符号则是同时强制执行软性和硬性资源限制。
项
项表示正在进行限制的系统资源。可以限制的命令项包括以下内容:
-
nofile: 这设置了最大打开文件数
-
maxlogins: 这是除 uid=0 用户外,此用户的最大登录次数
-
maxsyslogins: 这是系统上所有登录的最大数量
-
priority: 这是运行用户进程的优先级(负值提升进程优先级)
-
nice: 这是允许提升的最大优先级(适用于 Linux 2.6.12 及更高版本)值:[-20,19]
从前面的部分项目列表中可以看到,确实可以为某些用户分配比其他用户更高的 CPU 优先级,这对于那些访问时间要求较高的呼叫中心群体非常有用。以下示例会给销售团队分配比普通用户更高的优先级,普通用户的优先级通常为 0:
* - priority 0
@telesales - priority -5
限制并发登录也可能会很有用,类似于以下条目的设置:
@users - maxlogins 1
这些限制对于服务器的运行和安全可能非常重要。因此,请花时间研究在你的环境中最适合的设置,更多信息可以参考手册页面:
$ man 5 limits.conf
SELinux
我不太确定我是否能量化在互联网上我所读到的多少博客,其中“解决方案”是禁用 SELinux,或者至少将其设置为宽容模式。虽然我并不反对即时问题可能因此得到解决,但这有点像将文件系统权限设置为所有用户都可以读写执行,无论是否经过认证。同样,我们也开玩笑说用户把密码写在便签纸上贴在屏幕上;管理员不当禁用 SELinux 与此没有太大区别。
强制访问控制(MAC)列表存在是有原因的,我们作为管理员应该利用它。传统上,我们习惯于使用自主访问控制(DAC)列表,这些列表可以由用户或 root 设置。MAC 被称为强制性的,因为它只能由 root 应用或撤销。
首先应用 DAC 列表,然后是 MAC 列表。SELinux 永远不会赋予本来没有的额外权限。我们真正的优势在于,可以根据进程启动时的 SELinux 上下文或它访问的内容,赋予同一进程不同的权限。因此,通过init
守护进程启动的服务进程,可以拥有与普通用户在非init
进程中启动的相同进程不同的权限。SELinux 非常强大,我们只需要了解如何有效利用它的力量。
查看当前 SELinux 模式
SELinux 有两种模式,但如果包括禁用模式,它可以在三种模式下运行。操作模式如下:
-
强制
-
宽容
SELinux 在这两种模式下都是启用的,但只有强制
模式会应用并执行 SELinux 策略。在宽容
模式下,策略会被读取,但不会被执行;不过,我们仍然可以从审计日志中查看任何拒绝的记录。即使在宽容
模式下没有强制执行这些拒绝,日志条目仍然会显示为拒绝。可以使用/usr/sbin/getenforce
命令来显示当前的 SELinux 模式:
$ getenforce
这个设置也可以从/selinux/enforce
文件中读取:
$ cat /selinux/enforce
整数 1 和 0 分别代表 SELinux 模式:Enforcing
和 Permissive
。请注意,/selinux
目录是 CentOS 中的 SELinux 挂载点;在其他系统中,可能是 /sys/fs/selinux
,或者可以检查 sestatus
的输出,如以下截图所示:
可以通过 sestatus
(/usr/bin/sestatus
) 命令读取模式;此命令返回更多信息,包括当前模式以及在 /etc/selinux/config
中配置的模式。
设置 SELinux 模式
与 Linux 中的大多数任务一样,设置 SELinux 模式非常灵活,可以通过多种方式设置。首先,我们将看看使用 setenforce
(/usr/sbin/setenforce
) 的方法:
# setenforce 1
# setenforce Enforcing
# setenforce 0
# setenforce Permissive
前两个选项用于将模式设置为 Enforcing
,底部两个选项用于设置为 Permissive
,这两种方法都可以使用,因为单词和数字与 setenforce
命令的含义相同。
我们也可以通过直接写入 SELinux 挂载点中的控制文件来设置模式:
# echo 1 > /selinux/enforce
# echo 0 > /selinux/enforce
如果我们需要更多设置方式,还可以在启动时使用内核选项。向 GRUB 配置文件中的内核条目追加内容将覆盖 /etc/selinux/config
文件中的默认模式:
enforcing=1
enforcing=0
最后,我们可以在 /etc/selinux/config
文件中配置模式。
防止从命令行更改模式
我知道很多系统管理员会轻易将系统设置为 Permissive
以便提供一个 快速修复;如果这与你的管理政策相悖,则可以在启动时使用 setsebool
(/usr/sbin/setsebool
) 命令强制设置模式;也许在系统启动时作为脚本:
# setsebool secure_mode_policyload on
一旦设置,模式就不能从启动过程中的文件或内核启动参数更改。这可以通过以下截图看到,当尝试更改模式时。
以这种方式设置的设置将持续到下次启动。如果我们希望此设置始终生效,可以通过 -P
选项将其设置为真正持久。使用时要小心,因为它的作用就是按照字面意思操作,设置将被持久化。
提示
实施以下命令时需要小心:
# setsebool -P secure_mode_policyload on
理解 SELinux 上下文
SELinux 将尝试将进程的上下文与正在访问的资源的上下文匹配;生效的 SELinux 策略将指定从给定上下文访问资源时允许的权限。SELinux 上下文由四个字段组成,请注意,用户是 SELinux 用户,而非标准 Linux 用户:
-
用户
-
角色
-
类型
-
敏感度
提示
从技术上讲,文件有一个类型,而用户或进程有一个域,但实际上,类型和域都以 -t
结尾。
我们可以使用 ls -Z
查看文件的上下文,如下所示:
$ ls -Z /etc/hosts
请参阅以下截图:
输出显示 /etc/hosts
文件的 SELinux 用户、角色、类型和敏感度:
-
system_u
-
object_r
-
net_conf_t
-
s0
我们可以使用 ID 命令查看用户的 SELinux 上下文:
$ id -Z
请参阅以下截图:
从命令输出中我们可以看到,当前该用户(user
)的 SELinux 上下文是:
-
unconfined_u
-
unconfined_r
-
unconfined_t
-
s0
敏感度(s0
从s0
开始并停止)和任何类别(c0
到c1023
)
要查看进程的 SELinux 上下文,我们可以使用 ps
命令。在这个示例中,进程 ID 为 1629
表示 Nginx 服务器:
# ps -Z 1629
超过 90% 的 SELinux 策略与类型 (_t
) 一起工作,因此通常我们会在这里进行故障排除。
故障排除 SELinux
现在我们来看看当文件资源和进程的上下文与 SELinux 策略不匹配时会发生什么。
为了演示,我将使用 CentOS 6.5 和 Apache httpd web 服务器。为了制造 SELinux 命令问题,web 服务器将配置为访问一个别名目录,这个目录位于正常的 /var/www
结构之外。这个设置可以模拟一个常见的过程,即你希望通过 HTTP 提供 kickstart 文件,以帮助自动安装工作站和服务器。
当然,一旦我们在 /var/www/
目录之外工作,文件的上下文或标签将不再与 web 服务器的预期匹配,尽管我们满足 DAC(文件权限)的要求,访问仍会被拒绝。
提示
web 服务器配置正确,允许 URL /ks
指向 /install/ks
,因为它已经通过别名添加了这一点。
请考虑以下命令:
# mkdir -m 755 -p /install/ks
# cp /root/anaconda-ks.cfg /install/ks
# chmod 644 /install/ks/anaconda-ks.cfg
配置完成后,我们可以重启 web 服务器并测试访问正常的 web 根目录以及 URL /ks
。为了演示方便,我安装了命令行浏览器 w3m
:
$ w3m localhost
这个操作有效并显示标准的欢迎页面。现在使用以下命令:
$ w3m localhost/ks
我们将看到一个相当不祥的 禁止访问 页面,如下图所示:
如果我们启用了审计,SELinux 拒绝的信息将写入审计日志文件 /var/log/audit/audit.log
。我们可以使用 ausearch
(位于 /sbin/ausearch
)来查询此文件:
# ausearch -m avc -ts recent
我们在命令中使用的选项解释如下:
-
-m
:这是要搜索的消息。我们查找avc
,即 SELinux 拒绝的信息。 -
-ts
:这是时间开始。如果我们使用recent
,意味着从 10 分钟前开始。输入today
也可以常用。
ausearch
命令的输出如以下截图所示:
从输出结果来看,我们被拒绝了对 PID 为 1731
的进程的读取访问。在访问 /ks
目录时,我们正在运行 httpd
命令,而该目录在 sda3
文件系统中的 inode 为 22341
。这一细节给我留下了深刻印象!主体上下文是 httpd_t
类型,目标是 default_t
类型。主体是进程 1731,目标是文件,在这种情况下它们的上下文不匹配,因此访问被拒绝。
我们可以使用命令chcon
(位于/usr/bin/chcon
),通过直接修改目标的 SELinux 上下文或通过引用我们已知有效的目录上下文(例如 /var/www/html
)来改变目标的 SELinux 上下文。
# chcon -Rv --reference /var/www/html /install/ks
-
-v
:这使文件变得详细。 -
-R
:这个选项会递归所有文件和子目录。 -
--reference
:这意味着从此文件复制上下文。
或者,我们可以直接设置上下文;不过,为了准确和简便起见,我更倾向于使用 --reference
方法。
# chcon -Rv --type httpd_sys_content_t /install.ks
httpd_t
类型的进程可以访问包括 httpd_sys_content_t
在内的资源,因此通过这个简单的更改,我们现在应该可以通过 Web 服务器访问 /ks
目录,而不需要禁用 SELinux。
加固 Linux
我们可以通过前面使用 SELinux 的例子来探讨“加固 Linux”的含义,但这通常并非简单的选择。以 SELinux 为例,简单的做法是设置为 Permissive
模式,但这并不符合我们系统的最佳安全要求。
从密码开始,问问自己:你的系统上密码多久更换一次?root 密码上次更换是什么时候?多少人可以访问 root 密码?我遇到过许多情况,root 密码从未更改过,所有管理员似乎都有 root 密码的访问权限。尽管这种做法可能在短期内有助于管理系统,但这并不是一种安全的操作方式。想想有多少曾经在你公司工作过的人仍然能够访问 root 用户密码。
当然,系统安全必须为你和公司服务,但安全系统的需求永远不应被低估。对于 root 访问,考虑使用 sudo
而不是 su
,并且不要将 root 密码提供给每个管理员。
同样,要确保对具有sudo
权限的账户以及 root 账户使用强密码。
密码审计
我将使用“密码审计”这个术语,因为我确实认为这个工具突出了对密码策略进行充分监控的必要性。你可以要求用户使用强密码,在一定程度上我们可以通过使用 PAM 模块来强制执行这一点。然而,有多少用户使用相同的密码呢?也许是经理们的密码是由助理设置的。也有可能你没有意识到禁止使用弱密码的重要性,通常为了避免遗忘用户出现的问题。Openwall 的 john
包(www.openwall.com
)是一个不容错过的工具,帮助你理解强密码和密码算法的必要性。
RPM 不在仓库中,但可以从 Openwall 网站获得。
准备密码文件
密码审计工具 john 会期待用户和密码在一个文件中,因此我们将使用pwunconv
(/usr/sbin/pwunconv
)命令将/etc/shadow
文件中的密码添加到/etc/passwd
文件中。虽然这并非理想做法,但你拥有密码文件;你可以将其复制到自己的目录,并使用pwconv
切换回/etc/shadow
文件。john 的目的是展示如果密码安全不到位,可能发生的情况,而获得服务器的恶意 root 权限并非闻所未闻。即使 john 是作为演示运行,它也成了展示弱密码可能造成后果的一个好工具,实验室机器用作演示完全没问题。
pwunconv
命令以 root 身份运行足以将密码从 shadow 文件读取到/etc/passwd
文件中。
破解密码
现在我们已经准备好了密码文件,可以将其复制到我们自己的主目录中:
# cp /etc/passwd /root/passwd
这一步并非严格要求,但如果这不是实验室机器,执行该操作将使你能够尽可能快速地转换回 shadow 文件。运行以下john
命令,指定你希望破解的密码文件路径。密码文件应包含用户和密码。
# john /root/passwd
这将开始破解它找到的密码。在我的文件中,只有一个用户有密码,并且使用的是默认的 SHA512 加密。
提示
在我的系统上,一个简单的密码Password1
只用了 1 分钟 45 秒就被破解了。
削弱算法
密码足够弱,但如果我们也削弱了算法呢?MD5 只有 128 位或 16 字节加密;这会对结果产生什么影响?我们可以使用chpasswd
(位于/usr/sbin/chpasswd
)命令生成使用 MD5 而非 SHA512 加密的密码:
# echo andrew:Password | chpasswd -c MD5
该命令会写入/etc/passwd
文件;如果你需要写入到自己的文件中,可以使用-S
将输出发送到stdout
,并将显示的文本添加到自己的密码文件中:
# echo andrew:Password | chpasswd -S -c MD5
现在我们可以再次尝试运行 john。然而,为了确保新密码能够公平破解,请删除包含原始密码的john.pol
文件:
# rm ~/.john/john.pot
john.pot
文件包含以前破解的密码;因此,为了进行真实的比较,我们应该确保该文件不存在。现在,在我的系统上运行相同的测试,使用相同的密码设置,但仅使用 128 位加密,破解只花了 0.8 秒。
强化密码
设置了更安全的密码后,我们可以看到破解密码所需的时间差异,因为这将需要暴力破解攻击。在这个示例中,我们使用的密码是27csg0TNWoUS
。对我来说,这更像是一个密码短语,因为我会记住它作为美国西北部第 27 侦察小组。无论如何,我相信你有自己的方式来记住复杂的密码,而不需要用便签纸。
设置了密码并启用了 MD5 加密后,我让程序运行了 20 分钟,程序仍未破解密码。随着时间的推移,从 0.8 秒(使用简单密码)到 20 分钟的变化,充分展示了使用安全密码的意义,以及与依赖强算法相比,强密码的效果要强大得多。
从这几步开始,你的 Linux 系统将从一开始就更加安全。
概述
在这一章中,我们走在了安全的路上。从了解 PAM 模块如何工作开始,探索我们如何利用这些模块帮助我们进行管理和安全性。我们看到,我们可以创建用户的主目录,因为他们是通过 PAM 和即时创建方法登录的。我们还看了如何使用 /etc/security/limits.conf
限制或授予用户和组更多的访问权限。随后,我们花了一些时间了解 SELinux 并保护我们的 CentOS 主机。
下一章将讨论一些通用的最佳实践指南,涵盖本书中介绍的一些元素。
第十一章:毕业日
我们已经到达了 CentOS 系统管理精要 的最后一章,你已经接近 Linux 忍者;然而,在你可以大获成功之前,你将学习一些在部署 CentOS Linux 时需要考虑的最佳实践。本章将涵盖我们专门研究过的主题以及一些其他更通用的 CentOS 最佳实践。此外,我们还将快速浏览 Red Hat 和 CentOS 的企业版 Linux 7 中的新功能。
-
保护远程访问您的系统:在这里,我们将查看 OpenSSH 和您可能需要审查的一些考虑因素
-
OpenLDAP 最佳实践:在这里,我们确保您的目录服务按您的意愿运行
-
Nginx 最佳实践:配置 web 服务器时 dos 和 don'ts 的快速指南
-
精通 Puppet:在您的 Linux 服务器上安全的事项和如何进行安全设置的清单。
-
CentOS 7 的新特性:这份指南主要针对 CentOS 6.5,但现在 Red Hat 和 CentOS 都已推出企业版 Linux 7,我们将快速浏览其亮点
保护远程访问您的系统
使用 安全外壳(SSH)是一种通过命令方法远程访问您的服务器的方式。安全性主要通过数据加密来实现,但默认情况下还通过服务器认证进行增强。客户端可以将服务器提供的公钥与信任主机列表(或 SSH 称为 known_hosts
)进行比较。这有点像使用您的 Web 浏览器访问 HTTPS 站点;有时我们可能会收到警告,说远程主机不受信任或无法识别。对于 SSH,我们不是像浏览器保存服务器的公钥那样,而是使用 ~/.ssh/known_hosts
文件存储我们连接到的主机的 SSH 公钥。
SSH 公钥
CentOS 和大多数 Linux 发行版上 SSH 客户端的默认行为是,在用户首次连接到远程主机时,提示用户接受远程主机的公共 SSH 密钥。除非密钥已经存在并且可能已经预共享,否则一旦接受,远程 SSH 主机的公钥将存储在该用户的 SSH 客户端存储中。在任何后续的连接中,只要是同一用户连接到同一远程主机,客户端将无需提示即可连接,因为主机已经是可信的。
分析默认设置的风险
默认设置提供了一个方便且大多安全的机制,用于获取远程主机的公钥。但有一个潜在问题,即我们在首次连接时连接的远程主机可能不是我们希望连接的受信任主机。由于没有认证机制,我们必须依赖信任和概率,在第一次连接时,连接将与正确的主机建立而不是冒名顶替者。
为了更安全地工作,我们可以调整客户端设置,使其仅连接到已经信任的主机,或者换句话说,只有当主机的公钥存储在本地密钥库中时才能连接。为了做出此调整,我们需要编辑/etc/ssh/ssh_config
文件。StrictHostKeyChecking
指令默认设置为ask
,应该编辑为yes
,以确保只有在我们拥有预共享密钥时才进行连接。
填充密钥库
如果我们选择后者方法,要求密钥已经预共享,那么我们需要解决填充密钥库的方法。我们可以手动将服务器的公钥复制到客户端存储,或者更容易地使用ssh-keyscan
命令。虽然这个命令很方便,但它也带来了客户端提示接受密钥时固有的风险。如果在扫描过程中有恶意服务器,我们就会存储错误的密钥。现实情况是,唯一安全的方法是将密钥的物理副本发送给客户端。能够集中管理客户端密钥库无疑会使生活更加轻松,这可以通过/etc/ssh/ssh_known_hosts
文件来实现。这样就能更方便地手动填充密钥库,因为我们只需要一个客户端文件,而不是每个用户在客户端机器上都有一个。
公钥认证
用户密码可能会对你的 SSH 服务器构成另一个安全风险。虽然密码在传输过程中是加密的,但用户——是的,我们都知道并喜爱他们——确实共享密码,并且可能会使用简单的密码,尽管不应该使用。对此的设置是哪些认证类型被允许,这由服务器上的/etc/ssh/sshd.conf
文件控制。我们可以禁用基于密码的认证,使得用户必须使用客户端密钥。要禁用用户使用密码进行认证,你需要在远程主机上编辑该文件;查找PasswordAuthentication
指令,并确保其设置为no
;同时PubKeyAuthentication
的设置应为yes
。
在此设置完成后,用户需要在客户端设备上生成自己的公钥和私钥对,可以使用ssh-keygen
命令。将公钥复制到服务器上的~/.ssh/authorized_keys
文件中;可以使用ssh-copy-id
命令来完成此操作:
ssh-copy-i <idfile> user@server
Root 登录
永远不应该允许以 root 身份登录 SSH 服务器;对于生产服务器来说,我认为这完全没有争议。需要管理设备的用户可以作为标准用户登录,并使用sudo
或su
来获取权限。这个设置同样存在于/etc/ssh/sshd.conf
文件中的PermitRootLogin
指令里。
结论
SSH 提供了一种安全的加密机制,以维护网络中的数据安全。启用客户端的 StrictHostKeyChecking
还可以实现主机认证,这样我们就可以确保将安全信息发送到正确的服务器。为了增强客户端认证,禁用服务器的 root 登录,并只允许具有预共享用户密钥的客户端进行身份验证。
OpenLDAP 最佳实践
我们在本书中看到过,我们可以将用户账户集中管理在 OpenLDAP 服务器上,或者,如果我们想简化 CentOS 上的一些管理功能,可以使用 389-ds。无论哪种方式,底层目录都是 OpenLDAP。当然,如果用户账户存在于目录中,那么我们的认证令牌(密码)也会存在。我们需要确保这既安全又有效。OpenLDAP 支持不同的认证机制,每种机制当然有其优缺点,如下所示:
-
简单绑定:使用简单绑定认证机制时,客户端将明文密码传递给服务器进行身份验证。这带来了三种潜在威胁:密码可能会被网络抓包收集,密码可能会被伪造服务器地址的主机收集,密码也可能通过对服务器的恶意攻击被获取。使用 LDAPS 可以防范前两种威胁,但无法防范第三种。最好尽可能避免使用简单绑定认证。
-
简单认证与安全层 (SASL) 外部:这允许使用外部认证,如客户端 X.509 证书(TLS 公钥)来验证用户身份,并且可以克服固有的密码问题。如果 LDAP 客户端和 LDAP 服务器在同一台机器上,也可以使用 LDAP over IPC (LDAPI) 的 SASL 认证方法,在该方法中,用户的 Linux 凭证用于访问目录。
-
SASL 密码:可以使用基于密码的认证与 SASL,但随之而来的威胁类似于简单绑定。
如果你使用基于密码的身份验证,通常认为在多次失败的尝试后实现账户锁定是谨慎的做法。虽然在 OpenLDAP 密码策略中可以实现这一点,但现实情况是,在当今环境中,密码攻击往往比这更微妙,而这些机制反而为攻击者提供了锁定账户的手段。
允许用户在忘记密码时重置密码也变得越来越常见。虽然这减轻了帮助台的负担,但这往往是安全链中的一个薄弱环节,因为通常提供的挑战响应问题太容易被潜在攻击者知道或猜到。
在任何目录系统中,都有一个描述可以创建的每个对象(如用户或组)的模式,属性是该对象可能存在的特性。虽然可以编辑任何给定对象或属性的模式,但如果需要为某个对象添加额外的属性,最好创建你自己的定义,而不是直接在现有模式中添加它们。从长远来看,修改现有对象可能会导致在其他服务器上复制时出现问题,特别是如果所有服务器上的模式不完全相同。
Nginx 的最佳实践
如果你选择部署 Nginx web 服务器,我们需要注意一些事项,以确保你的网站服务能够长时间稳定运行。
从安全角度来看,你的网站服务器可能对全世界所有人都可访问。因此,我们需要确保保护一些基本的安全威胁:
-
SELinux:确保在托管 Nginx 的 CentOS 系统上将 SELinux 设置为
Enforcing
模式。 -
DocumentRoot:将 DocumentRoot 结构独立挂载为自己的文件系统,确保恶意写入不会导致 Linux 主机崩溃(如果磁盘填满),其次,分区或磁盘可以以最小权限挂载,例如:
LABEL=web /var/www ext4 ro,nosuid,noexec,nodev,noatime 0 2
。 -
使用基于主机的防火墙:只允许传入的 TCP 端口
80
和443
。通常,只需要打开传出的 UDP 端口123
以及动态传出的 TCP 端口,端口123
用于时间同步。 -
限制 Nginx 可用的 HTTP 方法。RFC 2616 允许多种 HTTP 访问方法;大多数方法在你的服务器上是没有必要的。我们可以添加类似以下的代码,检查不等于 GET、HEAD 和 POST 的方法,然后拒绝其他不需要的访问方法,如 DELETE、SEARCH 等:
if ( $request_method !~ ^(GET|POST|HEAD)$ ) { return 403; }
-
用户代理:我们还可以选择阻止某些用户代理,这些浏览器通常与扫描器、机器人或垃圾邮件发送者相关联。HTTP 头中的
$httpd_user_agent
变量会显示浏览器的类型,例如 Internet Explorer、Mozilla 等。除了这些常规浏览器,还有一些自动化浏览器可以通过脚本如wget
和BBBike
访问你的站点。尝试将以下内容添加到你的nginx.conf
文件中,以阻止这些代理:if ($http_user_agent ~* wget|BBBike|LWP::Simple ) { return 403; }
-
限制 IP 访问:如果某个特定目录只允许内部网络访问,你可以在主机配置中使用类似以下的代码:
location /var/www/docs { allow 192.168.0.0/24 deny all }
-
限制文件所有权:Nginx Web 服务器将以名为
nginx
的用户身份运行。诱惑是将 Nginx 用户添加为 DocumentRoot 目录及其中所有 Web 内容的所有者。这样做不建议,因为文档所有者、用户或组可能会获得额外的权限,比如删除你无法写入的文档。通常,nginx
用户应通过others
获得访问权限,并且我们将others
限制为目录上的r-x
和文件上的r--
。典型的文件权限应类似于以下内容:-rw-r--r-- 1 root root 1000 Feb 1 10:00 index.html
掌握 Puppet
使用 Puppet 服务器集中管理配置时,记住在设置 Puppet 主机时的几个相关事实是很有价值的。
-
使用模块:
/etc/puppet/modules
目录允许创建模块。模块是在 PuppetModulePath
指令下创建的子目录,包含需要分发到客户端的文件和配置,作为其期望状态的一部分。这简化了 Puppet 配置,因为相关的文件都在模块目录中。 -
使用版本控制:Puppet 本身没有版本控制,但我们可以使用类似 GIT 或 subversion (svn) 的工具来维护配置的历史版本。
-
风格:在编写 Puppet 配置时,标准化语法风格有助于维护和可读性。Puppet Labs 的风格指南可以在
docs.puppetlabs.com/guides/style_guide.html
找到。
CentOS 7 的新特性
CentOS 7 于 2014 年 6 月发布,同时也发布了早期的 Red Hat Enterprise Linux 7。随着 Linux 内核 3.10 在本次发布中的引入,发行版也有其他重要更新。
本地化
系统的本地化信息可以通过 localectl
命令方便地设置和显示:
$ localectl status
输出可以在以下截图中看到:
时间和日期信息
与本地化信息类似,CentOS 7 包含一个简单的命令,用于显示和管理主机系统的时间和日期设置:/usr/bin/timedatectl
。这对于我们管理员来说真是一个天赐之物;即使我们只使用该命令来显示输出,这个命令也会显示时间、时区和 NTP 设置。以下截图展示了没有选项的 timedatectl
命令输出:
继续使用 timedatectl
命令,我们可以使用以下命令更改日期:
# timedatectl set-time 2014-07-19
可以使用相同的选项和时间作为参数来设置时间,如下所示:
# timedatectl set-time 23:02:23
NTP 时间同步可以通过以下命令启用和禁用;不过,它使用的是新的系统服务管理器来启用和禁用时间服务:
# timedatectl set-ntp yes
这真是一个多功能的命令;你将会非常快速地学会它。
管理服务
Systemd
现在是 CentOS 7 中的系统和服务管理器,取代了 Upstart,成为默认的 init 系统。它不仅替代了 Upstart,还与传统的 System V init 脚本向后兼容。对我们管理员来说,最需要熟悉的主要命令是/usr/bin/systemctl
。
从status
子命令开始,我们可以立即看到systemctl
如何为我们提供便利。在这里,我们查看 SSH 服务的状态:
# systemctl status sshd
输出内容相当详细,包含进程 ID(PID)和最近的日志文件活动。你可以在下面的截图中查看这些内容。
我们可以使用以下命令停止服务:
# systemctl stop sshd
要禁用服务的自动启动,我们将使用disable
子命令:
# systemctl disable sshd
一个被禁用的服务仍然可以由管理员启动;“禁用”一词只是意味着该服务的自动启动被禁用了。systemd
带来的新功能是能够防止手动启动服务:
# systemctl mask sshd
即使管理员尝试在服务被掩蔽时启动该服务,服务也不会启动。如果需要重新启用服务,管理员需要使用unmask
子命令:
# systemctl unmask sshd
除了使用单用户模式修复机器之外,还可以采取其他修复方法
在传统环境中,我们可能习惯于使用运行级别 1,或单用户模式,作为将系统置于维护模式的机制。随着 system 的引入,运行级别的概念发生了变化,现在我们有了目标而不是运行级别。要将正在运行的系统置于维护模式,可以使用以下命令:
# systemctl rescue
在完成操作时,会提示你输入 root 用户密码。如果这仍然无法修复系统,那么还有一个紧急目标,它会启动更少的服务,只允许 root 访问:
# systemctl emergency
紧急目标与使用init=/bin/bash
内核参数启动 CentOS 6.5 机器非常相似。从这些命令中你可能也已经猜到,我们还可以使用systemctl
关机和重启系统:
# systemctl reboot
# systemctl halt
当然,shutdown
命令仍然存在,也可以用来执行此操作。
远程管理
使用 system 也可以管理远程系统,它也使用相同的systemctl
命令。如果我们需要查看主机s1.tup.com
上atd
服务的状态,可以执行以下命令:
$ systemctl -H root@s1.tup.com status atd
这只是利用 SSH 连接到远程主机,因此22
端口和 SSHD 必须在我们监控的远程主机上可访问。
Systemd 和非标准子命令
现在通过systemctl
和systemd
可用的子命令已标准化,而在 System V init 脚本中,任何参数或子命令都可以添加到脚本中。例如,在 CentOS 6.5 中的 Apache HTTPD 服务,我们可以发出service httpd graceful
命令。graceful
参数是 Web 服务器特有的,因此它不是作为systemctl
中的子命令构建的;然而,通过使用apachectl graceful
命令也可以实现相同的结果。谈到 Apache Web 服务器,默认的 DocumentRoot 已从/var/www
更改为/usr/share/httpd
。
Samba 4.1 包
对于 Windows 域、文件和打印服务,Samba 4.1 替代了老旧的 Samba 3,该版本曾随 CentOS 6.5 及之前版本的系统一起提供。
文件系统更改
默认文件系统现在是 XFS,取代了 ext4。XFS 已经存在很长时间,但显然现在正在引起企业 Linux 社区的关注。
密码策略
强制密码质量的 PAM 模块现在默认为pam_pwquality
,替代了较老的pam_cracklib
。编辑/etc/security/pwquality.conf
文件可以指定最低密码长度和密码复杂性。密码复杂性包括:
-
minclass:这是最少的字符类别类型数量,包括大写字母、小写字母、数字和非字母数字字符
-
maxsequence:此选项限制同一类别字符的连续数量,例如
12345
或bcfag
;这两个序列都有五个连续字符,而bcafG
只有四个来自同一类别(小写字母)的字符。 -
maxrepeat:此选项限制重复字符的数量
现有的文件可以作为示例,或者我们可以使用man 5 pwqulality.conf
命令查看手册以获取更详细的信息。
总结
现在你准备好走出这个世界,宣布你对 CentOS 的新知识。我已经帮助你通过一些简单的最佳实践目标来管理我们在本书中所涉及的服务,并介绍了 CentOS 7 的一些新元素。当然,在很长一段时间里,你仍然会遇到许多 CentOS 6 系统来保持忙碌,大部分元素从版本 6 到版本 7 保持一致,但跟上最新的增强功能始终是有用的。