创建 RPM 包:CentOS 7 制作 OpenSSH 8.4 RPM 包

创建 RPM 包:CentOS 7 制作 OpenSSH 8.4 RPM 包

  • RPM 简介
  • 理论先行
    • 准备构建 RPM
      • 规划需要构建的内容
      • 收集要打包的软件
      • 创建软件的可复制版本
      • 规划升级
      • 勾勒出任何依赖关系
    • 构建 RPM
      • 设置目录结构
      • 将源码放在目录中
      • 创建 spec 文件
      • 构建 RPMs
    • 验证 RPM
  • 知识扩展
    • 编写规范的 spec 文件
      • 语法
      • 注释
      • 存储
      • 定义包信息
      • 填写软件列表
      • 设置文件属性
      • 定义安装脚本
    • 高级 RPM 封装
      • 定义包依赖关系
      • 设置触发器
      • 编写验证脚本
      • 创建子包
      • 创建可重定位的包
  • 重在实践
    • 安装依赖包
    • 制作 RPM
      • 创建目录
      • 准备源码包
      • 创建 spec 文件
      • 构建 RPM 包
      • 安装 OpenSSH 8.4
    • 测试
      • 测试环境
      • 卸载自带 SSH 组件
      • 安装 OpenSSH 8.4
      • 配置 sshd_config
      • 配置 PAM
      • 重启 SSH 服务
      • 远程连接测试
      • 测试 PAM 保护
  • RPM 下载

RPM 简介

RPM包管理器(RPM Package Manager,RPM)是一个功能强大的包管理系统,它能够:

  • 将计算机软件从源代码构建为易于分发的软件包
  • 安装、更新和卸载套装软件
  • 查询有关打包软件的详细信息,无论是否已安装
  • 验证打包软件的完整性以及由此产生的软件安装

理论先行

准备构建 RPM

规划需要构建的内容

在这一步,需要知道要将哪些内容打包成 RPM,是应用程序或补丁、编程库、系统配置文件或者是文档包?大多数情况下,我们需要创建一个源码包( source package)和一个二进制包(binary package)。二进制包包含可以在其它系统安装的 RPM,源码包可以随时重新创建二进制包,前提是已经定义了源 RPM(source RPM)。

收集要打包的软件

收集要捆绑到 RPM 中的软件,这包括应用程序或要打包的库以及程序源代码。一般来说包含以下情况:

  • 打包自己的软件
  • 打包别人的软件
  • 在第一次定制或修补软件后打包其他人的东西

创建软件的可复制版本

RPM 系统将自动执行创建应用程序的步骤,只要您配置 RPM 使用适当的步骤,例如使目标运行。不幸的是,配置适当的步骤并不总是容易的。因此,在尝试创建RPM之前,您需要弄清楚如何构建您计划打包到RPM中的应用程序或库。一旦您弄清楚如何构建应用程序或库,您可以设置可重复生成。然后,RPM系统可以自动执行此操作建立。

要构建软件,您需要使用各种Linux工具。您需要的特定工具很大程度上取决于原始软件的来源。了解这些软件的常用技术如下:

  • 拆包软件,包括 tar、tar.gz、zip 等

  • 阅读 README 文件,包括 README 文件可能的变体,INSTALL 及其变体文件

  • 适用 Linux 构建工具构建程序,通常在 Linux,我们可能使用 make 工具,但前提是需要创建正确的 Makefile 文件,通常有以下几种方法:

    • 手段创建,下载一个程序并找到这样的文件如 Makefile.amiga、Makefile.Solaris 和 Makafile.Linux,然后根据系统架构复制为 Makefile

    • imake,使用 ImakeFile 的配置文件,应用于基于 X Window 应用程序或操作系统,并大多数情况下自带通用构建脚本:

      # 找到 ImakeFile 文件后,运行下面的命令来构建程序
      xmkmf
      make 
      make install
      # xmkmf 是用于创建 Makefile 文件的脚本
      # 如果 xmkmf 不可用或者不起作用,可能需要执行下面的命令
      make Makefile
      # 存在多个源代码目录时,可以执行
      make Makefiles
      # 了解更多:http://www.dubois.ws/software/imake-stuff/
      
    • 配置脚本,configure 脚本输出一个特定于平台的 Makefile

      # 如果在源文件中看到一个名为 configure 的文件,运行下面的命令来构建程序
      ./configure
      make
      make install
      # configure 脚本由一组工具(包括 automake 和 autoconf)创建
      # 这些工具使用通常名为 configure.in 和 makefile.am 的通用文件以及其他文件来创建通用配置脚本
      # 通常情况下 configure 需要接收参数,比如 --prefix,用来指定构建应用程序的根目录
      # 更多: https://www.airs.com/ian/configure/
      
    • 构建 Perl 模块

      # 如果在源码中看到一个 Makefile.PL 的文件,需要运行这些命令来构建应用程序或模块
      perl Makefile.PL
      make
      make test
      make install
      

规划升级

以 RPM 格式打包的任何应用程序或库都可能在某个时候得到升级。当这种情况发生时,您需要创建一个新的 RPM。这个新的 RPM 不仅必须处理软件包的安装,还必须处理任何升级问题。您需要考虑以下问题:

  • 如何安装新版本软件的RPM。是否有任何必要的安装脚本?
  • 如何删除以前的 RPM 软件包。如果您的软件包具有安装脚本,则可能需要卸载脚本,用于彻底删除安装脚本对系统所做的任何更改。RPM系统处理包中文件的删除。您需要处理在安装过程中撤消对系统所做的任何更改的任务。

勾勒出任何依赖关系

执行 make 的时候,必须保证包含了所有的依赖项。在大多数情况下,我们不希望在 RPM 中包含依赖项。相反,每个依赖项每个必要的库都应该有自己的 RPM。在许多情况下,您应该能够找到 RPM 对于这些依赖关系,并跟踪提供依赖项的包。

构建 RPM

构建 RPM 需要由 rpmbuild 命令来完成。构建 RPM,请执行以下步骤:

  • 设置目录结构
  • 将源代码放在正确的目录中
  • 创建一个 spec 文件,告诉 rpmbuild 命令执行什么操作
  • 构建源 RPM 和二进制 RPM

设置目录结构

目录 使用
BUILD rpmbuild 命令在此目录中构建软件
RPMS rpmbuild 命令将其创建的二进制 RPM 存储在此目录中,通常包含许多特定于体系结构的子目录,包括 athlon、i386、i486、i586、i686、noarch
SOURCES 将应用程序的源代码放在此目录中
SPECS 将计划创建的每个 RPM 的 spec 文件放在此目录中
SRPMS rpmbuild 命令将源 RPM 放置在此目录中

默认情况下,Red Hat Linux 系统期望在 /usr/src/redhat 目录中构建 RPM,这个目录显然是特定于 Red Hat Linux 的。在其他 Linux 发行版上,您可能会看到其他目录。

首先,使用系统目录来构建 RPM 似乎很奇怪。但请记住,RPM系统最初是为创建 Linux 发行版而构建的(可以通过修改 rpmrc 设置更改默认目录)。

目前,最简单的方法是切换到 /usr/src/redhat 目录并从该位置开始工作。首先,您需要更改这些文件的所有权或权限,以便您可以在以普通用户身份登录时构建RPM。不要在以 root 身份登录时构建 RPM。如果您以 root 身份登录,则构建包时的错误可能会导致严重的后果。
要构建RPM,实际上只需要两件事:

  • 源码放入 SOURCES 目录中
  • spec 文件放入 SPECS 目录中

将源码放在目录中

最好的策略是从自己创建的目录开始,从源代码创建 tarball(package-version.tar.gz)文件,然后将 tarball 文件复制到 /usr/src/redhat/sources 目录。

创建 spec 文件

spec(Specification File)文件定义了 rpmbuild 命令构建应用程序时应执行的所有操作,以及 rpm 命令安装和删除应用程序所需的所有操作。每个源 RPM 都应具有构建二进制 RPM 所需的规范文件。

在 spec 文件中,使用特殊语法设置软件包上信息的格式。此语法定义如何构建包、版本号、依赖关系信息以及您可以查询的有关包的其他所有内容。根据 spec 文件中的部分,此语法略有不同。以下部分介绍了这些规范文件部分以及每个部分中的必要语法。

  • The introduction section

    简介部分包含有关软件包的信息,即rpm-qi命令所显示的信息类型。例如:

    Summary: java source to bytecode compiler
    %define version 1.17
    Copyright: IBM Public License, http://ibm.com/developerworks/oss/license10.html
    Group: Development/Languages
    Name: jikes
    Prefix: /usr
    Provides: jikes
    Release: 1
    Source: jikes-%{version}.tar.gz
    URL: http://ibm.com/developerworks/opensource/jikes
    Version: %{version}
    Buildroot: /tmp/jikesrpm
    %description
    The IBM Jikes compiler translates Java source files to bytecode. It
    also supports incremental compilation and automatic makefile generation,
    and is maintained by the Jikes Project:
    http://ibm.com/developerworks/opensource/jikes/
    

    此示例来自真实的 RPM 规范文件。它并不遵循创建 RPM 的所有规则。此示例

    • 不应显式提供包的名称
    • 不应包含版权标记,因为此标记已被弃用
    • 配置 %define,执行 rpmbuild 命令可以为创建版本宏
  • The prep section

    prep(prepare)部分定义了准备构建所需的命令。如果你从源代码的压缩 tar 存档(tarball)开始,prep部分需要提取文件。

    %prep
    %setup -q
    

    此示例使用 %setup RPM宏来提取文件。

  • The build section

    spec 文件包含构建软件的命令,通常,这将只包括几个命令,因为大多数实际指令都出现在 makefile 中。例如:

    %build
    ./configure CXXFLAGS=-O3 --prefix=$RPM_BUILD_ROOT/usr
    make
    

    Build 部分以 %build 语句开头。

  • The install section

    spec 文件install 部分包含安装新构建的应用程序或库所需的命令。在大多数情况下,您的安装部分应该清除 BuildRoot 目录并运行 make install命令。例如:

    %install
    rm -fr $RPM_BUILD_ROOT
    make install
    

    install 部分以 %install 语句开头。

  • The clean section

    clean 部分清理其他部分中的命令创建的文件:

    %clean
    rm -rf $RPM_BUILD_ROOT
    

    clean 部分以 %clean 语句开头。

  • The files section

    files 部分列出了要进入二进制 RPM 的文件,以及已定义的文件属性。例如:

    %files
    %defattr(-,root,root)
    /usr/bin/jikes
    %doc /usr/doc/jikes-%{version}/license.htm
    %doc /usr/man/man1/jikes.1*
    

    files 部分以 %files 语句开头。

    %doc 宏将某些文件标记为文档。这允许 RPM 将保存文档的文件与 RPM 中的其他文件区分开来。

    编写了spec 文件并将其放在 /usr/src/redhat 下的 sources 和 specs 目录中后,将看到如下文件:

    $ ls –CF /usr/src/redhat/*
    /usr/src/redhat/BUILD:
    /usr/src/redhat/RPMS:
    athlon/ i386/ i486/ i586/ i686/ noarch/
    /usr/src/redhat/SOURCES:
    jikes-1.17.tar.gz
    /usr/src/redhat/SPECS:
    jikes.spec
    /usr/src/redhat/SRPMS:
    

    也就是说,在一个干净的系统中,没有构建其他RPM,将在 /usr/src/redhat/specs 中看到一个 spec 文件,在 /usr/src/redhat/sources 中看到源代码。在此示例中,源文件位于压缩的 tar 存档中(为此,RPM 规范文件 jikes.spec 需要在 prep 部分中有一个命令来提取文件)。

    现在,准备好可以构建 RPM。

构建 RPMs

要使用 rpmbuild 命令构建 RPM,请使用以下基本语法:

rpmbuild -bBuildStage spec_file

-b 选项告诉 rpmbuild 构建 RPM。额外的 BuildStage 选项是一个特殊的代码,它告诉rpmbuild命令在构建时要走多远。选项包括:

选项 使用
-ba 构建所有,包括二进制和源 RPM
-bb 构建二进制 RPM
-bc 构建(编译)程序,但不进行完整的RPM,在%Build部分后立即停止
-bp 准备构建二进制 RPM,并在完成 %prep 部分后立即停止
-bi 创建二进制 RPM 并在 %install 部分后立即停止
-bl 检查 RPM 的文件列表,如果 BuildRoot 缺少任何要安装的文件,则生成错误
-bs 仅构建源RPM

rpmbuild 命令参数说明:

[root@bogon /]# rpmbuild --help
Usage: rpmbuild [OPTION...]

Build options with [ <specfile> | <tarball> | <source package> ]:
  -bp                           build through %prep (unpack sources and apply patches) from <specfile>
  -bc                           build through %build (%prep, then compile) from <specfile>
  -bi                           build through %install (%prep, %build, then install) from <specfile>
  -bl                           verify %files section from <specfile>
  -ba                           build source and binary packages from <specfile>
  -bb                           build binary package only from <specfile>
  -bs                           build source package only from <specfile>
  -tp                           build through %prep (unpack sources and apply patches) from <tarball>
  -tc                           build through %build (%prep, then compile) from <tarball>
  -ti                           build through %install (%prep, %build, then install) from <tarball>
  -ta                           build source and binary packages from <tarball>
  -tb                           build binary package only from <tarball>
  -ts                           build source package only from <tarball>
  --rebuild                     build binary package from <source package>
  --recompile                   build through %install (%prep, %build, then install) from <source package>
  --buildroot=DIRECTORY         override build root
  --clean                       remove build tree when done
  --nobuild                     do not execute any stages of the build
  --nodeps                      do not verify build dependencies
  --nodirtokens                 generate package header(s) compatible with (legacy) rpm v3 packaging
  --noclean                     do not execute %clean stage of the build
  --nocheck                     do not execute %check stage of the build
  --rmsource                    remove sources when done
  --rmspec                      remove specfile when done
  --short-circuit               skip straight to specified stage (only for c,i)
  --target=CPU-VENDOR-OS        override target platform

Common options for all rpm modes and executables:
  -D, --define='MACRO EXPR'     define MACRO with value EXPR
  --undefine=MACRO              undefine MACRO
  -E, --eval='EXPR'             print macro expansion of EXPR
  --macros=<FILE:...>           read <FILE:...> instead of default file(s)
  --noplugins                   don't enable any plugins
  --nodigest                    don't verify package digest(s)
  --nosignature                 don't verify package signature(s)
  --rcfile=<FILE:...>           read <FILE:...> instead of default file(s)
  -r, --root=ROOT               use ROOT as top level directory (default: "/")
  --dbpath=DIRECTORY            use database in DIRECTORY
  --querytags                   display known query tags
  --showrc                      display final rpmrc and macro configuration
  --quiet                       provide less detailed output
  -v, --verbose                 provide more detailed output
  --version                     print the version of rpm being used

Options implemented via popt alias/exec:
  --with=<option>               enable configure <option> for build
  --without=<option>            disable configure <option> for build
  --buildpolicy=<policy>        set buildroot <policy> (e.g. compress man pages)
  --sign                        generate GPG signature (deprecated, use command rpmsign instead)

Help options:
  -?, --help                    Show this help message
  --usage                       Display brief usage message

Example:

# rpmbuild –bp specfile
rpmbuild -bp /usr/src/redhat/SPECS/jikes.spec
 
# rpmbuild -bb specfile
rpmbuild -bb /usr/src/redhat/SPECS/jikes.spec

# rpmbuild –bi specfile
rpmbuild -bi /usr/src/redhat/SPECS/jikes.spec

# rpmbuild –bs specfile
rpmbuild -bs /usr/src/redhat/SPECS/jikes.spec

# rpmbuild --clean specfile
 rpmbuild --clean /usr/src/redhat/SPECS/jikes.spec

验证 RPM

构建 RPM 完成后,使用 rpmbuild 命令的 –bl 选项来验证 RPM 中的文件列表。

# rpmbuild –bl spec_file
rpmbuild -bl /usr/src/redhat/SPECS/jikes.spec

-bl 选项检查所有必要的文件是否都位于 buildroot 目录中。buildroot 目录是一个类似于最终安装的根目录的位置。

若出现错误,可以从头开始构建,或者使用 --short 选项从 spec 文件中给定的部分重新开始构建。在创建RPM时,需要在检测和修复错误时来回重新启动构建。

需要使用 rpm 命令与 –V 等选项一起使用,以验证完整构建的软件包。例如:rpm -Vp /usr/src/redhat/RPMS/i386/jikes-1.17-1.i386.rpm

知识扩展

编写规范的 spec 文件

语法

Spec 文件时包含 RPM 指令的文本文件。这些指令使用标记名、冒号和值的简单语法:TagName: value,且标记名称不区分大小写。例如:

Version: 1.15

除指令语法外,还可使用 %define 方式定义 RPM 宏。例如:

%define major 2

定义宏后,可以使用 %{macro_name} 的方式来访问宏,例如

source: %{name}-%{version}.tar.gz

注释

注释以 # 开头,RPM 将忽略注释行。

注释行中应避免使用 %,例如: # Added new commands to %prep将会报错,如果一定要这样使用,可以用 %%,例如:# Added new commands to %%prep

存储

在构建 RPM 时,创建的 spec 文件应存储在 SPECS目录中(可以将 spec 文件永久存储在所需的任何位置)。

定义包信息

  • 包描述信息:

    • 定义包名称:NVR(Name-Version-Release)
    Name: myapp
    Version: 1.1.2
    Release: 1
    Epoch: 3
    Serial: 6
    Group: System Environment/Shells
    Distribution: Red Hat Linux
    
    • 指定公司信息
    Vendor: The Really Cool Company
    URL: http://mycompany.yow/products/coolstuff
    Packager: Bob Marley 
    Copyright: BSD
    # Copyright 已经启用,请使用 License
    License: LGPL
    
    • 填写描述
    # Summary:可设置一行,不超过 50 个字符
    Summary: A program that does exactly what you want
    # 若要添加任意多行描述,请使用 %description,可以输出空行、制表符和其它有限数量格式
    %description
    This is a really cool package. It contains the really cool
    program that provides a maximum return on investment,
    or ROI, for achieving your crucial business objectives
    utilizing world-class high-caliber componentized software
    implemented with world-class quality and performance
    metrics.
    
    • 指定平台体系结构

    Spec 文件可以声明一个包可以在多个操作系统上运行,或者绑定到特定操作系统的特定版本。

    # ExcludeArch:指令声明包不应该构建在给定的一个或多个体系结构上
    ExcludeArch: sparc s390 s390x
    # Exclusivearch:指令声明包只能在给定的一个或多个体系结构上构建
    ExclusiveArch: i386 ia64 alpha
    # Excludeos:指令限制在该操作系统上构建
    Excludeos: windows
    # ExclusiveOS:指令仅命名可以在其上构建包的一个或多个操作系统
    Exclusiveos: linux
    
  • 设置生成位置

    Buildroot: %{_tmppath}/%{name}-%{version}-root
    

    以使用 rpmbuild 命令的 --buildroot 命令行参数覆盖 Buildroot。

  • 命名源文件

    大多数包都有一个或多个源代码包,需要在规范文件中命名它们。在大多数情况下,您将拥有源文件的 tar 压缩文件。这些文件可能是自己开发的文件,也可能是从 Internet 站点下载的文件。可以定义一个或多个源标签,从0开始计数。例如:

    Source0: telnet-client.tar.gz
    Source1: telnet-xinetd
    Source2: telnet.wmconfig
    

    如果您只有一条Source指令,则可以跳过0。例如:

    Source: telnet-client.tar.gz
    

    还可以使用FTP或HTTP URL来命名源(源指令中列出的 URL 仅供方便和将来参考。RPM不会下载这些文件)。例如:

    Source0: ftp://ftp.somesite.yow/pub/linux/%{telnet_version}.tar.gz
    

    将某些源排除在源RPM之外,此示例表示第一个源项不应包含在包中:

    NoSource: 0
    

    NoPatch 指令的工作原理与 NoSource 类似,不要在任何给定的 NoSource 或 NoPatch 指令上放置多个数字。

  • 命名补丁程序

    补丁的命名类似于源代码,使用类似的语法。例如:

    Patch1: telnet-client-cvs.patch
    Patch2: telnetd-0.17.diff
    Patch3: telnet-0.17-env.patch
    Patch4: telnet-0.17-issue.patch
    Patch5: telnet-0.17-sa-01-49.patch
    Patch6: telnet-0.17-env-5x.patch
    Patch10: telnet-0.17-pek.patch
    

填写软件列表

%files 部分包含 RPM 应该从软件包安装的所有文件的列表。该列表应该是详尽的,以便 RPM 系统确切地知道您的软件包安装了什么。不过,有一些选项可以命名一个目录中的所有文件,以帮助处理包含数百个文件的包。

%files
/usr/X11R6/bin/xtoolwait
/usr/X11R6/man/man1/xtoolwait.1

可以使用通配符,可以包含文件夹(但不要直接使用系统目录):

%files
/usr/X11R6/bin/xtoolwait
/usr/X11R6/man/man1/xtoolwait.*
%dir /etc/xtoolwait

也可将文件标记为文档或者配置文件:

%files
/usr/X11R6/bin/xtoolwait
%doc /usr/X11R6/man/man1/xtoolwait.*
# %doc 指定的文件不存在,将会自动创建,如:%doc README NEWS
# %docdir 将保存文档目录和该目录下的所有文件,并标记为文档
%docdir /usr/X11R6/man/man1
# 标记为配置文件
%config /etc/yp.conf
# noreplace:本地文件已经修改,将不会覆盖本地配置文件,若本地文件未修改,则覆盖本地文件
# missingok:意味着在本地磁盘上文件可以不存在
%config(noreplace) /etc/yp.conf
%config(missingok) /etc/md.conf
# %ghost 指定文件不应该存在 RPM 包中

设置文件属性

# %attr(mode, user, group) filename
%attr(0644, root, root) /etc/yp.conf
%attr(-, root, -) /etc/yp.conf
%config %attr(-, root, -) /etc/yp.conf
%attr(0700 root root) %dir /var/tux
# %defattr 设置包照中所有文件默认属性
%files
%defattr(-,root,root)
/usr/X11R6/bin/xtoolwait
/usr/X11R6/man/man1/xtoolwait.*
# %lang 标记特定语言的文件
%files
%defattr(-,root,root)
%doc FAQ Fixes NewThings complete.tcsh eight-bit.txt tcsh.html
%{_bindir}/tcsh
%{_bindir}/csh
%{_mandir}/*/*
%lang(de) %{_datadir}/locale/de/LC_MESSAGES/tcsh*
%lang(el) %{_datadir}/locale/el/LC_MESSAGES/tcsh*
%lang(en) %{_datadir}/locale/en/LC_MESSAGES/tcsh*
%lang(es) %{_datadir}/locale/es/LC_MESSAGES/tcsh*
%lang(et) %{_datadir}/locale/et/LC_MESSAGES/tcsh*
%lang(fi) %{_datadir}/locale/fi/LC_MESSAGES/tcsh*
%lang(fr) %{_datadir}/locale/fr/LC_MESSAGES/tcsh*
%lang(it) %{_datadir}/locale/it/LC_MESSAGES/tcsh*
%lang(ja) %{_datadir}/locale/ja/LC_MESSAGES/tcsh*
%lang(pl) %{_datadir}/locale/pl/LC_MESSAGES/tcsh*
%lang(ru) %{_datadir}/locale/ru/LC_MESSAGES/tcsh*
%lang(uk) %{_datadir}/locale/uk/LC_MESSAGES/tcsh*

定义安装脚本

# %pre 安装之前运行脚本
%pre
# %post 安装之后运行脚本
%post
/sbin/chkconfig --add ypbind
# %preun 卸载之前运行脚本
%preun
if [ "$1" = 0 ] ; then
/sbin/service ypbind stop > /dev/null 2>&1
/sbin/chkconfig --del ypbind
fi
exit 0
# %postun 卸载之后运行脚本
%postun
if [ "$1" -ge 1 ]; then
/sbin/service ypbind condrestart > /dev/null 2>&1
fi
exit 0

高级 RPM 封装

定义包依赖关系

  • 命名依赖项

    # 基本语法
    Requires: capability
    Provides: capability
    Obsoletes: capability
    Conflicts: capability
    
  • 设置必备条件

    # 基本语法
    PreReq: capability
    PreReq: capability >= version
    
  • 命名生成依赖项

    # RPM 允许使用以下指令在规 spec 文件中定义构建时依赖关系:
    BuildRequires:
    BuildConflicts:
    BuildPreReq:
    
  • 自动生成依赖项

    RPM 默认会自动生成包依赖关系。

设置触发器

触发器为一个软件包提供了一种在另一个软件包的安装状态更改时执行操作的方法。触发器是在 RPM 系统运行的软件包规范文件中定义的脚本。当另一个命名包的状态更改时。如果您的包在某种程度上依赖于另一个包,则触发器可以允许您的包处理对另一个包的更改。

%triggerin -- tcsh
script commands...

此示例为 tcsh 包设置触发器。如果安装或升级了tcsh包,rpm将运行该脚本。如果您的软件包已安装或升级,并且tcsh软件包当前已安装,则RPM也将运行该脚本。

编写验证脚本

RPM 自动处理包验证,检查是否安装了正确的文件,并测试文件本身是否具有正确的大小和其他属性。当然也可以创建自己的验证脚本,并在 spec 文件中添加如下配置:

%verifyscript
your script commands ....

创建子包

一个 spec 文件可以定义多个包,这种类型的附加包称为子包。将大型文档集拆分到单独的子包中也很常见。

使用子包,您可以获得:

  • 一个 spec 文件
  • 一个 source RPM
  • 一组构建命令
  • 多个二进制RPM

在大多数情况下,创建子程序包只是作为将程序包生成的文件划分为单独程序包的一种方式。

在 spec 文件中定义子程序包:

%package sub_package_name
# %package -n 可以指定子包的命名方式,默认情况下,子包的名称将是包名、破折号和%Package 指令提供的子包名称
%package -n new_sub_package_name

创建可重定位的包

可重定位的软件包允许用户指定安装软件包的位置。例如,如果您为 Red Hat Linux 构建一个包,则二进制可执行程序的正常目录是 /usr/bin。不过,其他版本的Linux 可能会将可执行程序放入 /opt/bin 中。如果您的软件包强制使用 /usr/bin,那么您的软件包将不能在这些其他系统上工作。

要设置可重定位软件包,需要:

  • 设置 top-level(顶级)目录的 prefix 指令
  • 定义 prefix 目录下的文件

步骤:

  • 设置前缀

    Prefix: /usr
    

    以定义多个 prefix:指令,以列出多个顶级目录:

    Prefix: /usr
    Prefix: /etc
    
  • 设置文件 section

    在 spec 文件中使用 prefix:指令时,%file 部分中的所有文件必须位于以前缀 prefix:指令命名的目录下。

    Prefix: /usr
    ...
    %files
    %defattr(-,root,root)
    /usr/bin/jikes
    %doc /usr/doc/jikes-%{version}/license.htm
    %doc /usr/man/man1/jikes.1*
    

并不是所有的软件包都能像可重定位的软件包一样正常工作。有些软件包的文件必须放到某个位置,因此不能重定位。某些软件包的程序被硬编码为在特定位置查找文件,因此无法重新定位到其他位置。其他软件包的符号链接也可能是不可重定位的。此外,您的软件包可能会提供已知目录中其他软件包引用的软件。重新定位这样的软件包将禁用其他软件包,您可能甚至不知道这些软件包。如果您的包面临这些问题中的任何一个,很可能将包设置为可重定位不是一个好主意。

重在实践

安装依赖包

yum -y install gcc gcc-c++ 
yum -y install make
yum -y install pam pam-devel
yum -y install zlib zlib-devel
yum -y install openssl openssl-devel
yum -y install perl pcre-devel 
yum -y install rpm-build

制作 RPM

创建目录

mkdir -p /root/rpmbuild/{BUILD, BUILDROOT, RPMS, SOURCES, SPECS, SRPMS}

准备源码包

将 openssh-8.4p1.tar.gz 放入到 /home/workspace/rpmbuild/SOURCES 目录:

[ft@bogon SOURCES]$ pwd
/root/rpmbuild/SOURCES
[ft@bogon SOURCES]$ wget https://cdn.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-8.4p1.tar.gz
[ft@bogon SOURCES]$ wget http://ftp.riken.jp/Linux/momonga/6/Everything/SOURCES/x11-ssh-askpass-1.2.4.1.tar.gz
[ft@bogon SOURCES]$ ls
openssh-8.4p1.tar.gz  x11-ssh-askpass-1.2.4.1.tar.gz

创建 spec 文件

  • 创建 sepc 文件

    cd /root/rpmbuild/SOURCES
    tar -zxvf openssh-8.4p1.tar.gz 
    cp openssh-8.4p1/contrib/redhat/openssh.spec /root/rpmbuild/SPECS
    

    注意:

    CentOS 一定要在 /root/rpmbuild 目录下。

  • 修改 spec 文件

    • 修改 askpass 相关配置

      cd /root/rpmbuild/SPECS
      sed -i -e "s/%global no_gnome_askpass 0/%global no_gnome_askpass 1/g"  openssh.spec
      sed -i -e "s/%global no_x11_askpass 0/%global no_x11_askpass 1/g"  openssh.spec
      

      命令执行完成后,openssh.spec 文件下列配置项将修改为 1:

      # Do we want to disable building of x11-askpass? (1=yes 0=no)
      %global no_x11_askpass 1
      
      # Do we want to disable building of gnome-askpass? (1=yes 0=no)
      %global no_gnome_askpass 1
      

      说明:

      8.3 以上版本的 openssh 使用 %global 定义变量,替换之前的 %define。若使用低版本的 openssh,请将上面命令中的 %global 替换为 %define,后者可以直接打开 openssh.spec 文件,编辑 no_x11_askpass 和 no_gnome_askpass 配置项。

    • 取消 openssl 依赖

      注释掉 BuildRequires: openssl-devel < 1.1 选项,解除其依赖(在 openssh.spec 文件的第 103 行)。

      %if %{compat_openssl}
      BuildRequires: compat-openssl10-devel
      %else
      BuildRequires: openssl-devel >= 1.0.1
      #BuildRequires: openssl-devel < 1.1
      %endif
      
    • 配置 openssl 路径(可选)
      若需要使用自定义编译的 openssl,可在 openssh.spec 文件的 %configure 部分添加 --with-ssl-dir=/opt/openssl ,其中 /opt/openssl 是 openssl 的安装路径,根据实际情况赋值:

       %configure \
       	--sysconfdir=%{_sysconfdir}/ssh \
       	--libexecdir=%{_libexecdir}/openssh \
       	--datadir=%{_datadir}/openssh \
       	--with-default-path=/usr/local/bin:/bin:/usr/bin \
       	--with-superuser-path=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin \
       	--with-privsep-path=%{_var}/empty/sshd \
       	--with-ssl-dir=/opt/openssl \
       	--with-md5-passwords \
       	--mandir=%{_mandir} \
       	--with-mantype=man \
       	--disable-strip \
      

构建 RPM 包

cd /root/rpmbuild/SPECS
rpmbuild -ba openssh.spec

注意:

实际执行还是使用了 root 用户,并不像前面的章节建议使用非 root 用户。

构建完成后,在 /root/rpmbuild/RPMS/x86_64 目录下会生成二进制 RPM 包:

[root@bogon x86_64]# ls
openssh-8.4p1-1.el7.x86_64.rpm
openssh-clients-8.4p1-1.el7.x86_64.rpm
openssh-debuginfo-8.4p1-1.el7.x86_64.rpm
openssh-server-8.4p1-1.el7.x86_64.rpm

在 /root/rpmbuild/SRPMS 目录下会生成源码包:

[root@bogon SRPMS]# ls
openssh-8.4p1-1.el7.src.rpm

安装 OpenSSH 8.4

将打包好的 openssh 二进制安装包拷贝到需要 SSH 远程访问的机器,执行安装命令:

rpm -Uvh openssh-* --nodeps

下一节内容将详细讲解安装 OpenSSH 8.4

测试

测试环境

[ft@bogon ~]$ cat /etc/redhat-release 
CentOS Linux release 7.9.2009 (Core)
[ft@bogon ~]$ uname -a
Linux bogon 3.10.0-1160.15.2.el7.x86_64 #1 SMP Wed Feb 3 15:06:38 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
[ft@bogon ~]$ ssh -V
OpenSSH_7.4p1, OpenSSL 1.0.2k-fips  26 Jan 2017

卸载自带 SSH 组件

注意:

卸载自带 SSH 组件前建议先备份 /etc/ssh/sshd_config 、/etc/ssh/ssh_config 和 /etc/pam.d/sshd 文件。

# 查看系统当前 openssh 组件
[root@bogon ~]# rpm -qa | grep openssh
openssh-clients-7.4p1-21.el7.x86_64
openssh-server-7.4p1-21.el7.x86_64
openssh-7.4p1-21.el7.x86_64
# 停止 sshd 服务
[root@bogon ~]# systemctl stop sshd
# 卸载系统 SSH 组件
[root@bogon ~]# rpm -e `rpm -qa | grep openssh` --nodeps
# 查看系统当前 openssh 组件,若输出为空,则卸载成功
[root@bogon ~]# rpm -qa | grep openssh

安装 OpenSSH 8.4

# 准备 OpenSSH 8.4 RPM 安装包
[root@bogon openssh]# ls
openssh-8.4p1-1.el7.x86_64.rpm          openssh-debuginfo-8.4p1-1.el7.x86_64.rpm
openssh-clients-8.4p1-1.el7.x86_64.rpm  openssh-server-8.4p1-1.el7.x86_64.rpm
# 安装 OpenSSH 8.4
[root@bogon openssh]# rpm -Uvh openssh-* --nodeps
Preparing...                          ################################# [100%]
Updating / installing...
   1:openssh-8.4p1-1.el7              ################################# [ 25%]
   2:openssh-clients-8.4p1-1.el7      ################################# [ 50%]
   3:openssh-server-8.4p1-1.el7       ################################# [ 75%]
   4:openssh-debuginfo-8.4p1-1.el7    ################################# [100%]
# 查看安装后的组件
[root@bogon openssh]# rpm -qa | grep openssh
openssh-debuginfo-8.4p1-1.el7.x86_64
openssh-server-8.4p1-1.el7.x86_64
openssh-8.4p1-1.el7.x86_64
openssh-clients-8.4p1-1.el7.x86_64
# 查看 SSH 版本
[root@bogon openssh]# ssh -V
OpenSSH_8.4p1, OpenSSL 1.0.2k-fips  26 Jan 2017

配置 sshd_config

修改 /etc/ssh/sshd_config 文件中的下列配置项为 yes:

PasswordAuthentication yes
PermitRootLogin yes
UsePAM yes

若已经提前备份 /etc/ssh/sshd_config 文件,在这里替换回原文件即可。

配置 PAM

修改 /etc/pam.d/sshd 配置文件内容,使得它的配置和原先一致(如果已经备份该文件,在这里替换回原文件即可):

#%PAM-1.0
auth       required     pam_sepermit.so
auth       substack     password-auth
auth       include      postlogin
# Used with polkit to reauthorize users in remote sessions
-auth      optional     pam_reauthorize.so prepare
account    required     pam_nologin.so
account    include      password-auth
password   include      password-auth
# pam_selinux.so close should be the first session rule
session    required     pam_selinux.so close
session    required     pam_loginuid.so
# pam_selinux.so open should only be followed by sessions to be executed in the user context
session    required     pam_selinux.so open env_params
session    required     pam_namespace.so
session    optional     pam_keyinit.so force revoke
session    include      password-auth
session    include      postlogin
# Used with polkit to reauthorize users in remote sessions
-session   optional     pam_reauthorize.so prepare

重启 SSH 服务

[root@bogon ssh]# systemctl restart sshd
[root@bogon ssh]# systemctl status sshd
● sshd.service - SYSV: OpenSSH server daemon
   Loaded: loaded (/etc/rc.d/init.d/sshd; bad; vendor preset: enabled)
   Active: active (running) since Wed 2021-03-03 19:41:48 PST; 3s ago
     Docs: man:systemd-sysv-generator(8)
  Process: 4678 ExecStop=/etc/rc.d/init.d/sshd stop (code=exited, status=0/SUCCESS)
  Process: 4686 ExecStart=/etc/rc.d/init.d/sshd start (code=exited, status=0/SUCCESS)
 Main PID: 4696 (sshd)
    Tasks: 1
   CGroup: /system.slice/sshd.service
           └─4696 sshd: /usr/sbin/sshd [listener] 0 of 10-100 startups

Mar 03 19:41:48 bogon systemd[1]: Starting SYSV: OpenSSH server daemon...
Mar 03 19:41:48 bogon sshd[4696]: Server listening on 0.0.0.0 port 22.
Mar 03 19:41:48 bogon sshd[4686]: Starting sshd:[  OK  ]
Mar 03 19:41:48 bogon sshd[4696]: Server listening on :: port 22.
Mar 03 19:41:48 bogon systemd[1]: Started SYSV: OpenSSH server daemon.

注意:

重启 SSH 服务,可能遇到下面的问题:

[root@bogon ~]# service sshd restart
Restarting sshd (via systemctl):  Job for sshd.service failed because the control process exited with error code. See "systemctl status sshd.service" and "journalctl -xe" for details.
# 根据提示执行 systemctl status sshd.service 查看问题
[root@bogon ~]# systemctl status sshd.service
● sshd.service - SYSV: OpenSSH server daemon
   Loaded: loaded (/etc/rc.d/init.d/sshd; bad; vendor preset: enabled)
   Active: failed (Result: exit-code) since Wed 2021-03-03 19:22:44 PST; 1min 37s ago
     Docs: man:systemd-sysv-generator(8)
  Process: 4219 ExecStart=/etc/rc.d/init.d/sshd start (code=exited, status=1/FAILURE)

Mar 03 19:22:44 bogon sshd[4219]: @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Mar 03 19:22:44 bogon sshd[4219]: Permissions 0640 for '/etc/ssh/ssh_host_ed25519_key' are too open.
Mar 03 19:22:44 bogon sshd[4219]: It is required that your private key files are NOT accessible by others.
Mar 03 19:22:44 bogon sshd[4219]: This private key will be ignored.
Mar 03 19:22:44 bogon sshd[4219]: sshd: no hostkeys available -- exiting.
Mar 03 19:22:44 bogon sshd[4219]: [FAILED]
Mar 03 19:22:44 bogon systemd[1]: sshd.service: control process exited, code=exited status=1
Mar 03 19:22:44 bogon systemd[1]: Failed to start SYSV: OpenSSH server daemon.
Mar 03 19:22:44 bogon systemd[1]: Unit sshd.service entered failed state.
Mar 03 19:22:44 bogon systemd[1]: sshd.service failed.

解决方法:

根据提示信息,/etc/ssh/ssh_host_ed25519_key 文件权限有问题,我们可以尝试修改其权限。

[root@bogon ~]# cd /etc/ssh/
[root@bogon ssh]# ls -l
total 608
-rw-------. 1 root root     577834 Mar  3 01:44 moduli
-rw-r--r--. 1 root root       1531 Mar  3 01:44 ssh_config
-rw-------. 1 root root       3148 Mar  3 19:10 sshd_config
-rw-------. 1 root root       1369 Mar  3 19:21 ssh_host_dsa_key
-rw-r--r--. 1 root root        600 Mar  3 19:21 ssh_host_dsa_key.pub
-rw-r-----. 1 root ssh_keys    227 Feb 24 18:54 ssh_host_ecdsa_key
-rw-r--r--. 1 root root        162 Feb 24 18:54 ssh_host_ecdsa_key.pub
-rw-r-----. 1 root ssh_keys    387 Feb 24 18:54 ssh_host_ed25519_key
-rw-r--r--. 1 root root         82 Feb 24 18:54 ssh_host_ed25519_key.pub
-rw-r-----. 1 root ssh_keys   1679 Feb 24 18:54 ssh_host_rsa_key
-rw-r--r--. 1 root root        382 Feb 24 18:54 ssh_host_rsa_key.pub
[root@bogon ssh]# chmod 600 ssh_host_ed25519_key
[root@bogon ssh]# chmod 600 ssh_host_ecdsa_key
[root@bogon ssh]# chmod 600 ssh_host_rsa_key

然后重启 SSH 服务。

远程连接测试

# 首次连接可能需要执行 ssh-keygen -R <目标主机 IP>
C:\Users\Sunny>ssh-keygen -R 192.168.16.22
# Host 192.168.16.22 found: line 5
C:\Users\Sunny/.ssh/known_hosts updated.
Original contents retained as C:\Users\Sunny/.ssh/known_hosts.old

# 远程连接
C:\Users\Sunny>ssh [email protected]
The authenticity of host '192.168.16.22 (192.168.16.22)' can't be established.
ECDSA key fingerprint is SHA256:F0ATU27wYShI3KpIqbuDv+DH9sTMUkfvfFBWpmy6Hsk.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.16.22' (ECDSA) to the list of known hosts.
Password:
Last login: Wed Mar  3 19:22:23 2021
[root@bogon ~]# cat /etc/redhat-release
CentOS Linux release 7.9.2009 (Core)
[root@bogon ~]# ssh -V
OpenSSH_8.4p1, OpenSSL 1.0.2k-fips  26 Jan 2017
[root@bogon ~]# exit
logout
Connection to 192.168.16.22 closed.

C:\Users\Sunny>

测试 PAM 保护

安装自定义的 PAM 模块,然后在 /etc/pam.d/sshd 配置文件添加自定义的 PAM 模块:

#%PAM-1.0
# 自定义 PMA 模块 pam_otp.so
auth       required     pam_otp.so
# ---------------------------------------------------------------
auth       required     pam_sepermit.so
auth       substack     password-auth
auth       include      postlogin
# Used with polkit to reauthorize users in remote sessions
-auth      optional     pam_reauthorize.so prepare
account    required     pam_nologin.so
account    include      password-auth
password   include      password-auth
# pam_selinux.so close should be the first session rule
session    required     pam_selinux.so close
session    required     pam_loginuid.so
# pam_selinux.so open should only be followed by sessions to be executed in the user context
session    required     pam_selinux.so open env_params
session    required     pam_namespace.so
session    optional     pam_keyinit.so force revoke
session    include      password-auth
session    include      postlogin
# Used with polkit to reauthorize users in remote sessions
-session   optional     pam_reauthorize.so prepare

SSH 连接测试:

C:\Users\Sunny>ssh [email protected]
Password:
[1] Send Msg    [2] Push Phone
[3] Auth OTP    [4] Exit
choose verification mode(1/2/3/4):3
PassCode:
Last login: Wed Mar  3 19:57:41 2021 from 192.168.16.70
[ft@bogon ~]$ cat /etc/redhat-release
CentOS Linux release 7.9.2009 (Core)
[ft@bogon ~]$ exit
logout
Connection to 192.168.16.22 closed.

C:\Users\Sunny>

RPM 下载

OpenSSH 8.4 RPM 下载链接:https://download.csdn.net/download/wzfgd/15561299

你可能感兴趣的:(System,openssh,rpm)