跳转到主要内容

签名模型

配置元数据与 RPM 包签名、引用密钥,并轮换签名身份。

配置元数据签名,让客户端验证仓库索引。需要客户端验证 RPM 文件内嵌签名时, 另行配置 RPM 包签名。

签名对象

配置 签名内容 输出 客户端设置
signing.rpm.metadata RPM 索引清单 repodata/repomd.xml.asc DNF repo_gpgcheck=1
signing.deb.metadata APT 发布清单 InRelease、Release.gpg APT Signed-By
signing.rpm.packages RPM 包 内嵌 OpenPGP 签名 DNF gpgcheck=1

元数据签名不改变包字节。RPM 包签名会改变包字节及 SHA-256。 SOW 不给 DEB 包文件增加签名。

配置元数据签名

repos:
  demo:
    signing:
      rpm:
        metadata:
          key: file:///secure/repo-signing.asc
      deb:
        metadata:
          key: file:///secure/repo-signing.asc
    dists:
      el9:
        format: rpm
      trixie:
        format: deb

RPM 与 DEB 可使用相同或不同密钥。密钥带口令时,在 key 旁增加 passfile: /run/secrets/gpg-password,或将 SOW_GPG_PASSFILE 设置为口令文件路径。 先检查配置,再构建:

sow config check
sow build -r demo
sow check -r demo

已配置签名的空 Dist 与非空 Dist 生成相同种类的签名文件。InRelease 的签名正文与 Release 一致。未配置密钥时,SOW 生成未签名索引。 Managed 的密钥与签名策略来自 sow.yml;--passfile PATH 可为本次执行覆盖口令来源, build 同样支持。

密钥与口令引用

元数据密钥引用 含义 签名实现
keys/repo.asc 相对于工作区根的 OpenPGP 密钥文件 进程内
file:///secure/repo.asc 绝对路径的 OpenPGP 密钥文件 进程内
env://SOW_METADATA_KEY ASCII 装甲格式密钥、文件路径或 GPG 密钥标识 取决于变量值
agent://KEY_ID_OR_FINGERPRINT 本地 GPG 环境可用的密钥 外部 gpg

密钥文件支持 ASCII 装甲格式和二进制 OpenPGP 数据。GPG 密钥标识可以是 16 位 key ID, 或 40、64 位指纹。引用解析为 GPG 密钥标识时,使用外部 gpg 访问私钥; 显式指定口令文件后,通过 GPG loopback 模式非交互解锁。

签名 key 引用必须解析为一个主密钥。 trusted_keys 文件可以包含多个完整公钥,包括连续的 ASCII 装甲块。 SOW 读取整个密钥集合,拒绝格式错误或被截断的输入,不会仅使用第一个密钥而忽略后续内容。

口令来源优先级为 --passfile PATH、每个密钥的 passfile 配置、SOW_GPG_PASSFILE。 旧元数据配置的 passphrase 引用继续兼容,优先级与单个密钥配置相同; 同一密钥的两个字段不能都非空。三种签名设置都接受 passfile,包括 agent:// 密钥。

口令文件为非空 UTF-8 单行。SOW 只移除末尾一个 LF 或 CRLF,保留空格与制表符。 不搜索默认路径,所选来源不可用时直接失败。完整格式、相对路径基准、权限及恢复命令范围 见口令文件。

config show 显示引用和解析出的公钥身份,不显示私钥或口令内容。 config check 解锁元数据私钥文件并检查用途;外部 GPG 元数据密钥还会试签。 RPM 包签名只检查口令格式、工具和私钥是否可用,不会签包或证明口令正确, 详见 config check。 创建新元数据签名时,选中的签名密钥需要在发布时间和 当前时间都可用。历史验证使用保留的证书。

新 APT 签名使用 SHA-256。新的发布尝试要求两份 APT 签名都使用 SHA-256、SHA-384 或 SHA-512。 升级包含 SHA-1 元数据签名的工作区后,先运行 build,再开始新发布。 已有发布尝试继续使用其记录的文件。

配置 RPM 包签名

signing:
  rpm:
    packages:
      mode: fill
      key: agent://7F721C4AD40F4A9D8CA578BFAC7E4690B50CCF3B
      trusted_keys: [keys/upstream.asc]
模式 行为
never 原样保存输入字节
fill 已有签名可由当前密钥或受信密钥验证时保留原包,其余包签名
always 已由当前密钥签名的包保留原样,其余包重签

没有密钥时默认 never,有密钥时默认 fill。fill 和 always 都必须配置密钥。

包签名在私有副本上调用主机的 rpm --addsign 或 rpm --resign。 安装 rpm、gpg,并确保 rpm 使用的 GPG 环境中有对应私钥。 密钥引用只标识签名者,不会把私钥导入该环境。原始输入文件保持不变。

SOW 检查签名结果、包坐标及排除签名头后的包体摘要。已有对象的坐标和包体相同、 且符合当前策略时,可复用已有签名字节。never 模式要求字节完全相同才能复用。

包签名工作流请使用 RPM 格式 v4。SOW 支持验证 RSA、DSA、ECDSA 与 EdDSA RPM 签名,包括保存在 RPM 签名头 tag 267(RPMSIGTAG_DSA)中的纯头签名。SOW 不支持 RPM 格式 v6 使用的签名标签。 这与 OpenPGP 签名报文版本不同;SOW 支持历史 CentOS 的 OpenPGP v3、v4 签名。

更换密钥

只修改 passfile 路径不会让 Dist 变脏;签名身份变化会使相关 Dist 变脏。更换元数据密钥后,运行 build 生成新签名, 并在发布新元数据前把新公钥分发给客户端。

已有包池对象不可变,修改 RPM 包签名策略不会原地重签这些对象。 逐步轮换包签名密钥时:

  1. 将新密钥设为当前密钥,使用 mode: fill。
  2. 旧包仍为成员时,在 trusted_keys 中保留旧公钥。
  3. 加入由新密钥签名的新版本包。
  4. 旧签名包退出成员集合或被新版本替代后,再移除旧信任。

直接换新密钥并使用 always,要求所有期望成员 RPM 已符合新密钥策略。 若重签会使同一包 URL 对应不同字节,应使用新的包发行版本和文件名。

RPM 验证按包的签名时间检查证书和签名子钥是否有效。证书保留了所需历史自签名与子钥绑定时, 续期本身不会使旧包签名失效。导出续期公钥时保留这些历史公钥信息。

Plain 签名

sow create /srv/offline --sign-with 6D5C5A26C36B1F73 --passfile /run/secrets/gpg-password
sow create /srv/offline --sign-with 6D5C5A26C36B1F73 --overwrite --passfile /run/secrets/gpg-password

Plain 模式只签 RPM 包文件。不带 --overwrite 时,为没有可解析内嵌签名的包签名; 带该选项时,重签全部保留的 RPM。密钥标识为 16、40 或 64 位十六进制字符, 可带 0x 前缀。执行 --pigsty 清理后,至少需要剩余一个 RPM。

客户端配置见仓库签名,完整字段见 配置参考。

表格阅读