c4rt1y

RPM打包

0x01 介绍

RPM(Red Hat Package Manager)是用于 Linux 分发版(distribution)的最常见的软件包管理器。
制作RPM包不复杂,关键是对SPEC文件的编写,所以我们需要了解spec的文件语法。

0x02 基础环境安装

服务器ip
[root@master ~]# 10.10.10.10   master

#关闭防火墙
[root@master ~]# systemctl stop firewalld.service
[root@master ~]# systemctl disable firewalld.service

#关闭selinux,需要重启
[root@master ~]# sed -i 's:SELINUX=enforcing:SELINUX=disabled:g' /etc/selinux/config

#临时关闭seLinux
[root@master ~]# setenforce 0

#重启
[root@master ~]# reboot

0x03 rpm打包工具安装

# 安装rpm打包工具
[root@master ~]# yum -y install rpm-build rpmdevtools

# 编译打包工具
[root@master ~]# yum -y install gcc gcc-c++ autoconf automake make

# 创建rpm目录
[root@master ~]# rpmdev-setuptree

# 查看目录结构
[root@master ~]# tree ~/rpmbuild
/root/rpmbuild
├── BUILD
├── RPMS
├── SOURCES
├── SPECS
└── SRPMS
5 directories, 0 files

0x04 详细讲解

SPEC指令	定义
Name	包基本名称,应于spec文件名匹配
Version	版本号
Release	打包次数,递增。初始值为 1%{?dist}
Summary	简介
License	软件许可
URL	通常为软件官网
Source0	源代码压缩归档的路径或URL,多个时使用 SourceX
Patch0	补丁,多个时 PatchX
BuildArch	系统架构,如x86_64 noarch
BuildRequires	以逗号或空格分隔的依赖包列表,用于构建过程,可以有多个条目
Requires	以逗号或空格分隔的运行时依赖列表,用于安装过程,可以有多个条目
ExcludeArch	需要排除的系统架构

%description	软件的完整描述,可跨多行,以空行结束
%prep	准备阶段,常为解压源码归档,可包含shell脚本
%build	构建阶段
%install	安装阶段,将文件从%builddir复制到%buildroot

%pre 安装前执行的脚本

%setup 不加任何选项,仅将软件包打开。
%setup -a 切换目录前,解压指定 Source 文件,例如 `-a 0` 表示解压 `Source0`
%setup -n newdir 将软件包解压在newdir目录。
%setup -c 解压缩之前先产生目录。
%setup -b num 将第 num 个 source 文件解压缩。
%setup -D 解压前不删除目录
%setup -T 不使用default的解压缩操作。
%setup -T -b 0 将第 0 个源代码文件解压缩。
%setup -c -n newdir 指定目录名称 newdir,并在此目录产生 rpm 套件。
%patch 最简单的补丁方式,自动指定patch level。
%patch 0 使用第0个补丁文件,相当于%patch ?p 0。
%patch -s 不显示打补丁时的信息。
%patch -T 将所有打补丁时产生的输出文件删除

%post 安装后执行的脚本
%preun 卸载前执行的脚本,升级的时候会执行
%postun 卸载后执行的脚本,升级 rpm 包的时候不会执行
%pretrans 在事务开始时执行脚本
%posttrans 在事务结束时执行脚本

%check	测试阶段,通常运行单元测试
%files	指定最终需要安装的文件列表
%clean  删除缓存文件
%changelog  本段是修改日志段,记录 spec 的修改日志段
%changelog	更新记录
%pre	在安装软件包之前执行
%post	在安装软件包之后执行
%preun	在卸载软件包之前执行
%postun	在卸载软件包之后执行

%defattr(文件权限,用户名,组名,目录权限) 

rpmbuild -bp:执行%prep
rpmbuild -bc:执行%build
rpmbuild -bi:执行%install
rpmbuild -ba:编译后做成rpm包和src.rpm包
rpmbuild -bs:仅制作src.rpm包
rpmbuild -bb:仅制作rpm包

# 

0x05 案列1

# 编译一个单纯独立项目的软件,以nginx为例

# 进入目录
[root@master ~]# cd ~/rpmbuild

# 下载代码
[root@master rpmbuild]# wget http://nginx.org/download/nginx-1.14.0.tar.gz -P SOURCES

# 创建spec文件
[root@master rpmbuild]# rpmdev-newspec -o SPECS/nginx-1.14.0.spec

# 编辑nginx.spec文件
[root@master rpmbuild]# cat SPECS/nginx-1.14.0.spec
Name:           nginx
Version:        1.14.0
Release:        3%{?dist}
Summary:        010sec team
License:        GPL
URL:            http://010sec.com,http://nginx.org/download/
Source0:        nginx-1.14.0.tar.gz

%description
010sec
%prep
%setup -q
%build
./configure --prefix=/opt/nginx --without-http_rewrite_module --without-http_gzip_module
make %{?_smp_mflags}
make install DESTDIR=%{buildroot}
%clean
%files
/opt/xd/xxxxnginx
%doc
%changelog

# 编译
[root@master rpmbuild]# rpmbuild -bb SPECS/nginx-1.14.0.spec

[root@master rpmbuild]# ll /root/rpmbuild/RPMS/x86_64/
-rw-r--r-- 1 root root 1739644 Jan 23 15:02 nginx-1.14.0-3.el7.centos.x86_64.rpm

# 查看rpm信息
[root@master ~]# rpm -qpi rpmbuild/RPMS/x86_64/nginx-1.14.0-3.el7.centos.x86_64.rpm
Name        : nginx
Version     : 1.14.0
Release     : 3.el7.centos
Architecture: x86_64
Install Date: (not installed)
Group       : Unspecified
Size        : 7158015
License     : GPL
Signature   : (none)
Source RPM  : nginx-1.14.0-3.el7.centos.src.rpm
Build Date  : Wed 23 Oct 2019 03:02:37 PM CST
Build Host  : master
Relocations : (not relocatable)
URL         : http://010sec.com,http://nginx.org/download/
Summary     : 010sec team
Description :
010sec

# 安装方法很简单,方法一
[root@master rpmbuild]# rpm -ivh nginx-1.14.0-3.el7.centos.x86_64.rpm
# 方法二
[root@master rpmbuild]# yum localinstall nginx-1.14.0-3.el7.centos.x86_64.rpm -y

0x06 案列2

# 不放在rpm标准目录编译
[root@master rpmbuild]# tar zxf SOURCE/nginx-1.14.0.tar.gz -C ~/
[root@master rpmbuild]# cd ~/nginx-1.14.0

[root@master nginx-1.14.0]# cat nginx.spec
Summary: High Performance Web Server   ##
Name: nginx
Version: 1.14.0
Release: el7
License: GPL
Group: Applications/Server
Source: http://nginx.org/download/nginx-%{version}.tar.gz
URL: http://nginx.org/
Distribution: Linux
Packager: c4rt1y<c4rt1y@010sec.com>
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}
%define srcdir /root/nginx-1.14.0
%description
nginx [engine x] is a HTTP and reverse proxy server, as well as a mail proxy server
%prep
%build
cd %{srcdir}
./configure --prefix=/opt/xd/testnginx --without-http_rewrite_module --without-http_gzip_module
make -j8
%install
cd %{srcdir}
make DESTDIR=%{buildroot} install
%preun
if [ -z "`ps aux | grep nginx | grep -v grep`" ];then
 killall nginx >/dev/null
 exit 0
fi
%files
/opt/xd/testnginx

[root@master nginx-1.14.0]# rpmbuild -bb nginx-1.14.0.spec

[root@master rpmbuild]# ll /root/rpmbuild/RPMS/x86_64/
-rw-r--r-- 1 root root 1739644 Jan 09 13:02 nginx-1.14.0-3.el7.centos.x86_64.rpm
-rw-r--r-- 1 root root 273236 Jan 09 15:23 nginx-1.14.0-el7.x86_64.rpm

0x07 案列3

# 标准目录下,多文件操作

[root@master rpmbuild]# wget http://distfiles.macports.org/openssl/openssl-1.0.2l.tar.gz -P SOURCES
[root@master rpmbuild]# wget http://ftp.pcre.org/pub/pcre/pcre-8.41.tar.gz -P SOURCES
[root@master rpmbuild]# wget http://tengine.taobao.org/download/tengine-2.1.2.tar.gz -P SOURCES
[root@master rpmbuild]# wget http://www.zlib.net/fossils/zlib-1.2.11.tar.gz -P SOURCES
[root@master rpmbuild]# cat SOURCES/nginx.conf
user 010sec;

worker_processes auto;

worker_cpu_affinity auto;

error_log "pipe:/usr/sbin/cronolog /home/010sec/logs/nginx/%Y%m%d-error.log";
pid       /home/010sec/logs/nginx/nginx.pid;

events {
    use epoll;
    worker_connections 65535;
    accept_mutex off;
}

http {
     #定义日志格式
    log_format main '$remote_addr||$time_iso8601||$http_host||$server_port||$request_method||$scheme||$request_uri||$server_protocol||$status||$body_bytes_sent||$http_referer||$http_user_agent||$http_x_real_ip||$http_x_forwarded_for||$request_time||$upstream_addr||$upstream_response_time||$upstream_status||';
    access_log "pipe:/usr/sbin/cronolog /home/010sec/logs/nginx/%Y%m%d-access_log-default" main;

    sendfile            on;
    sendfile_max_chunk 512k;        #每个进程每次调用传输数量不能大于设定的值,默认为0,即不设上限
    send_timeout        30;         #客户端响应超时时间,若客户端停止读取数据,释放过期的客户端连接,默认60s

    tcp_nopush          on;         #告诉nginx在一个数据包里发送所有头文件,而不一个接一个的发送
    tcp_nodelay         on;         #是否启用 nagle 缓存算法,告诉nginx不要缓存数据
    server_tokens       off;        #Nginx打开网页报错时,关闭版本号显示
    autoindex           off;
    keepalive_timeout   65;         #HTTP连接持续时间,值越大无用的线程变的越多,0:关闭此功能,默认为75
    types_hash_max_size 2048;

    # 以上两项是设置请求头和请求体各自的超时时间
    client_header_timeout 10;
    client_body_timeout 10;

    # 告诉nginx关闭不响应的客户端连接
    reset_timedout_connection on;

    # 用于保存各种key,如:当前连接数的共享内存的参数,5m是5兆字节,这个值应该被设置的足够大,以存储(32K*5)32byte状态或者(16K*5)64byte状态
    limit_conn_zone $binary_remote_addr zone=addr:5m;

    # key最大连接数,这里key是addr,我设置的值是100,这样就允许每个IP地址最多同时打开100个连接数
    limit_conn addr 100;

    #客户端请求头部的缓冲区大小,这个可以根据你的系统分页大小进行设置
    client_body_buffer_size 10K;
    client_header_buffer_size 32k;

    # 上传文件大小设置,一般是动态应用类型
    large_client_header_buffers 4 32k;
    client_max_body_size 10m;

    #nginx启动出现could not build the server_names_hash, you should increase错误时,请提高这个参数的值一般设成64就够了
    server_names_hash_bucket_size 64;
    server_name_in_redirect off;

    # 使用的默认的 MIME-type
    include             mime.types;
    default_type        application/octet-stream;

    # GZIP性能优化
    gzip on;
    gzip_disable "msie6";
    gzip_vary on;
    gzip_proxied any;       #允许或者禁止压缩基于请求和响应的响应流,若设置为any,将会压缩所有请求
    gzip_min_length 1k;     #对数据启用压缩的最少字节数,大于1k才压缩
    gzip_comp_level 6;      #gzip压缩等级在0-9内,数值越大压缩率越高,CPU消耗也就越大
    gzip_buffers 4 16k;
    gzip_http_version 1.1;  # 版本号
    gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;

    #静态文件的缓存性能调优
    open_file_cache max=65535 inactive=20s;
    #这个将为打开文件指定缓存,max 指定缓存数量.建议和打开文件数一致.inactive 是指经过多长时间文件没被请求后删除缓存
    open_file_cache_valid 30s;
    #这个是指多长时间检查一次缓存的有效信息,例如我一直访问这个文件,30秒后检查是否更新,反之更新
    open_file_cache_min_uses 2;
    #定义了open_file_cache中指令参数不活动时间期间里最小的文件数
    open_file_cache_errors on;
    #NGINX可以缓存在文件访问期间发生的错误,这需要设置该值才能有效,如果启用错误缓存.则在访问资源(不查找资源)时.NGINX会报告相同的错误

    #响应头
    add_header X-Cache $upstream_cache_status;
    #缓存命中
    add_header X-Frame-Options SAMEORIGIN;
    #是为了减少点击劫持(Clickjacking)而引入的一个响应头
    add_header X-Content-Type-Options nosniff;

    # qps
    req_status_zone domainport "$host:$server_port" 10M;
    req_status_zone domainporturi "$host:$server_port:$uri" 10M;

    proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header        Host $http_host;

    include vhosts/*.conf;
}


[root@master rpmbuild]# cat SPECS/tengine-2.1.2.spec
Name:           tengine
Version:        2.1.2
Release:        3%{?dist}
Summary:        010sec team

License:        GPL
URL:            http://010sec.com

AutoReq:       0
AutoProv:      0

%define nginx_user admin
%define nginx_group admin

Source0:        tengine-2.1.2.tar.gz
Source1:        zlib-1.2.11.tar.gz
Source2:        openssl-1.0.2l.tar.gz
Source3:        jemalloc-5.1.0.tar.bz2
Source4:        pcre-8.41.tar.gz
Source5:        nginx.conf

%description
010sec team

%prep
%setup -q  -b 1 -b 2 -b 3 -b 4
%build
cd ../zlib-1.2.11
./configure --prefix=/opt/zlib
make %{?_smp_mflags}
make install DESTDIR=%{buildroot}

cd ../openssl-1.0.2l
./config --prefix=/opt/openssl
make %{?_smp_mflags}
make install DESTDIR=%{buildroot}

cd ../jemalloc-5.1.0
./configure --prefix=/opt/jemalloc --libdir=/usr/local/lib
make %{?_smp_mflags}
make install DESTDIR=%{buildroot}
echo /usr/local/lib >> /etc/ld.so.conf

cd ../pcre-8.41
./configure --prefix=/opt/pcre
make %{?_smp_mflags}
make install DESTDIR=%{buildroot}

cd ../tengine-2.1.2
./configure --prefix=/opt/tengine --user=%{nginx_user} --group=%{nginx_group} --without-http_memcached_module --with-http_stub_status_module --with-http_ssl_module --with-http_gzip_static_module --with-openssl=/root/rpmbuild/BUILD/openssl-1.0.2l --with-zlib=/root/rpmbuild/BUILD/zlib-1.2.11 --with-pcre=/root/rpmbuild/BUILD/pcre-8.41 --with-jemalloc=/root/rpmbuild/BUILD/jemalloc-5.1.0
make %{?_smp_mflags}
make install  DESTDIR=%{buildroot}
install -p -D -m 0644   %{SOURCE5}      %{buildroot}/opt/tengine/conf/nginx.conf
%post
cat >/etc/profile.d/nginx.sh<<EOF
PATH=$PATH:/opt/tengine/sbin
EOF
source /etc/profile
/bin/sed -i 's/010sec/'%{nginx_user}'/g' /opt/tengine/conf/nginx.conf
%preun
if [ "$1" = 0 ] ; then
    if [ -z "`ps aux | grep nginx | grep -v grep`" ];then
       /opt/tengine/sbin/nginx -s stop  > /dev/null 2>&1
       exit 0
    fi
fi
%postun
if [ "$1" = 0 ] ; then
        /bin/rm -rf /opt/tengine
        /bin/rm -rf /etc/profile.d/nginx.sh
        source /etc/profile
fi
%files
/opt/tengine
%doc
%changelog


# 这里出现问题,因为由于某些文件安装未包含,导致报错,所以我们需要屏蔽一行打包编译内容
[root@master rpmbuild]# sed  -i 's/%__check_files/#%__check_files/' /usr/lib/rpm/macros

# 编译
[root@master rpmbuild]# rpmbuild -bb SPEC/tengine-2.1.2.spec

# 查看版本
[root@master rpmbuild]# ll /root/rpmbuild/RPMS/x86_64/
-rw-r--r-- 1 root root 1739644 Jan 09 13:02 nginx-1.14.0-3.el7.centos.x86_64.rpm
-rw-r--r-- 1 root root 273236 Jan 09 15:23 nginx-1.14.0-el7.x86_64.rpm
-rw-r--r-- 1 root root 3448816 Jan 09 06:18 tengine-2.1.2-3.el7.centos.x86_64.rpm

0x08 增加证书

# 安装证书编译工具
[root@master ~]# yum install rpm-sign
[root@master ~]# yum install rng-tools -y

# 随机证书熵池,加快运行速度
[root@master ~]# cat /etc/sysconfig/rngd
EXTRAOPTIONS="-r /dev/urandom"
[root@master ~]# systemctl start rngd

# 速度会比较慢,需要等待
[root@master ~]# gpg --gen-key
Please select what kind of key you want: 默认
What keysize do you want? (2048) 默认
Key is valid for? (0) 默认
is this correct? (y/N) y 
Real name: c4rt1y
Email address: c4rt1y@010sec.com
Comment: GPG-RPM-KEY
hange (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
这步之后会要求输入密码,可以为空

# 将gpg证书运行到rpm里面
[root@master ~]# %_signature gpg' >> ~/.rpmmacros
[root@master ~]# echo '%_gpg_name c4rt1y' >> ~/.rpmmacros

# 查看熵池
[root@master ~]# cat /proc/sys/kernel/random/entropy_avail

# 对rpm软件包签名:
[root@master ~]# rpm --addsign nginx-1.14.0-3.el7.centos.x86_64.rpm
Enter pass phrase:    gpg密码,这里没有设置
Pass phrase is good.
nginx-1.14.0-3.el7.centos.x86_64.rpm

# 在rpmbuild打包时签名:
[root@master ~]# rpmbuild --sign --bb ~/rpmbuild/SPECS/nginx-1.14.0.spec
# 验证
[root@master ~]# rpm -K  rpmbuild/RPMS/x86_64/rpm -K nginx-1.14.0-3.el7.centos.x86_64.rpm
rpmbuild/RPMS/x86_64/nginx-1.14.0-3.el7.centos.x86_64.rpm: rsa sha1 (md5) pgp md5 OK

0x06 资料来源

https://blog.csdn.net/trochiluses/article/details/11179901    centos下rpm包的制作
https://blog.51cto.com/13689359/2165975
https://blog.csdn.net/zhangxuechao_/article/details/82823359
https://www.jb51.net/article/51992.htm
https://www.cnblogs.com/weijing24/p/5691283.html
https://www.cnblogs.com/zafu/p/7423758.html
http://nginx.org/download/
https://www.52os.net/articles/howto-create-and-sign-rpm-package.html
GoTop