在 CentOS 下,rpm 包自带 gpg 签名,只用在 rpmbuild 的阶段考虑 gpg 签名的问题,可以使用 createrepo 工具对已有的 rpm 包非常简单的制作 yum 源,createrepo 完全不需要考虑 gpg 签名的问题。但在 Debian/Ubuntu 下,一般不对 deb 包进行 gpg 签名,而是对 apt 源(repository)的元数据进行签名,因此对制作 apt 源的工具有一定的要求,比如 dpkg-scanpackages 就不支持 gpg 签名。下面以 aptly 为例,介绍如何制作带 gpg 签名的 apt 源。
aptly 的工作流程大致如下:
- 创建空白 repo;
- 为刚才创建的空白 repo 添加 deb 包;
- 发布 repo,即创建 apt 源;
创建 apt 源
创建空白 repo,名字为 ceph:
1 | ~$ aptly repo create -architectures amd64 -comment 'Ceph distributed file system' -component main -distribution trusty ceph |
为名字为 ceph 的 repo 添加 xxx/ 目录下的所有 deb 包:
1 | ~$ aptly repo add ceph xxx/ |
列出所有的 repo,我们能看到刚才创建的 repo 里添加了 37 个 deb 包:
1 | ~$ aptly repo list |
刚才说过 apt 源的 gpg 签名是对元数据进行签名,aptly 需要我们指定合适的 gpg 参数才能进行签名,这里我们简单点,直接导出 GNUPGHOME
环境变量,aptly 就能使用默认的私钥进行签名:
1 | ~$ export GNUPGHOME=~/build/gpg |
创建 apt 源:
1 | ~$ aptly publish repo -label 'ceph' -origin 'ceph.com' ceph ceph-12.2.9 |
查看已创建的 apt 源,显然这是一个标准的 apt 源目录结构,可以把 ~/.aptly/public 下刚才创建的 apt 源整个目录拷贝至 web 服务器目录对外提供 apt 源服务:
1 | ~$ aptly publish list |
最后可以删除刚才创建的 apt 源:
1 | ~$ aptly publish drop trusty ceph-12.2.9 |
客户端配置
创建 apt 源之后,还需要在客户端进行配置才能使用。
首先添加这个源(我把刚才那个源的目录拷贝到了我的 nginx 服务器 ceph/ 目录下,并重命名为 ceph-ubuntu):
1 | ~$ sudo vi /etc/apt/sources.list |
还一个重要的操作是添加 gpg 公钥,不要忘了我们已经通过 aptly 为 apt 源的元数据进行了签名,如果客户端不导入对应的公钥,那签名就没有任何意义了:
1 | ~$ curl -o- http://example.com/release/XXX-RELEASE-GPG-KEY | sudo apt-key add - |
不导入 gpg 公钥的话 apt update
的时候会报如下的错误:
1 | Fetched 4835 kB in 8s (553 kB/s) |
查看刚才通过 apt-key add
添加的 gpg 公钥(注意到包含了上面的错误提示里的 keyid
):
1 | ~$ apt-key list |
至此,客户端就可以正常的进行 apt update && apt install ceph
了。
非 gpg 签名的 apt 源制作与使用
使用 dpkg-scanpackages
制作的 apt 源不支持 gpg 签名:
1 | ~$ dpkg-scanpackages xxx-debs/ | gzip > xxx-debs/Packages.gz |
然后在客户端配置源:
1 | ~$ sudo vi /etc/apt/sources.list |
注意 xxx-debs 后面的 /
非常重要(与是否是本地路径还是 http url 路径无关,都必须加上 /
),否则会认为是非法的地址。
然后使用 apt-get 进行 deb 包的安装:
1 | ~$ sudo apt-get update |
注意 apt (Ubuntu 16.04+)不支持这种非标准格式的 repo 且要求 repo 的元数据有 gpg 签名,可以使用 apt-get 临时进行规避。
故障解决
1. weak digest algorithm
如果使用 apt update
的过程中出现如下的警告:
1 | W: http://<server>/dists/trusty/InRelease: Signature by key <keyid> uses weak digest algorithm (SHA1) |
查看 Release.gpg 文件:
1 | ~$ gpg --list-packets dists/trusty/Release.gpg |
并对照如下的 RFC 文档,可知 algo 2
是 SHA1
算法。
Hash Algorithms
https://tools.ietf.org/html/rfc4880#section-9.4
显然,这是 gpg 签名所使用的算法问题,可以参考如下两个链接:
add support for setting gpg.conf settings
https://github.com/ros-infrastructure/buildfarm_deployment/issues/130
How to fix apt: Signature by key uses weak digest algorithm (SHA1)?
通过在 GNUPGHOME
下增加相应的配置文件即可解决该问题:
1 | ~$ vi gpg.conf |
1 | ~$ gpg --list-packets dists/trusty/Release.gpg |
其中 algo 8
对应 SHA256
。
2. Inappropriate ioctl
在容器环境中,使用 reprepro
制作 apt 源,可能会出现如下的错误:
1 | gpgme gave error GPGME:32870: Inappropriate ioctl for device |
和如下链接的现象一样:
Often fails when including package into repo
https://github.com/desc/puppet-reprepro/issues/59
链接中提供的解决方案(mount devpts)在这边并不需要,因为已经 mount 上了,但提供了思路,这个容器是通过 docker run -idt ubuntu:14.04
的方式创建的,但进入容器是通过 docker exec
的方式,尝试改成 docker attach
方式之后问题解决。
##参考资料
HOWTO: Create debian repositories with reprepro
https://blog.packagecloud.io/eng/2017/03/23/create-debian-repository-reprepro/
HOWTO: GPG sign and verify deb packages and APT repositories
https://blog.packagecloud.io/eng/2014/10/28/howto-gpg-sign-verify-deb-packages-apt-repositories/
DebianRepository Setup
https://wiki.debian.org/DebianRepository/Setup
Debian Repository Format
https://wiki.debian.org/DebianRepository/Format
reprepro manual
https://www.red-bean.com/doc/reprepro/manual.html
aptly - Debian repository management tool