#git-commit #git-repository #git-version #git #openpgp #signing #supply-chain

bin+lib sequoia-git

用于管理和强制执行提交签名策略的工具

1 个不稳定版本

0.1.0 2023 年 9 月 19 日

#16#supply-chain

LGPL-2.0-or-later

170KB
3K SLoC

Sequoia git

sequoia-git 是一个可以用于提高项目供应链安全性的工具。

简介

版本控制系统如 git 不仅仅是跟踪变更,还提供了变更的记录。这些信息可以用来检查提交是否获得授权,从而提高软件供应链的安全性。特别是,检查变更的来源可以用来从用户的信任计算基础中移除中间人如伪造者、包注册表。但是,作者信息很容易被伪造。

防止伪造的一个明显解决方案是要求提交必须是数字签名。但是,仅凭有效的数字签名本身并不能防止伪造。用于创建签名的证书可能声称是项目维护者之一。所需的不只是允许修改仓库的实体列表,还包括他们用于签名的密钥。换句话说,要验证提交,我们需要一个签名策略,它说明哪些密钥被授权进行更改。

创建策略并不复杂。项目的维护者可以维护一个允许添加提交的实体列表,并列出他们用于签名的证书。困难的部分是应用策略。有许多边缘情况需要处理,例如如何处理外部贡献的合并变更、谁可以更改策略以及如何处理受损的密钥。

Sequoia git 是一个项目,它指定了一套语义、定义了一种策略语言,并提供了一系列工具来管理策略文件和验证提交。

使用 Sequoia git 相对简单。您首先将策略文件 openpgp-policy.toml 添加到项目的仓库中。策略在联机维护,以便它像项目的其余部分一样进行演变。《code>openpgp-policy.toml 文件基本上是一个 OpenPGP 证书列表以及它们被授权进行何种更改的类型。《code>sq-git 可以帮助您创建它。

在合并拉取请求之前,您需要检查提交是否经过策略授权。在本地,这可以通过在您想要推送的提交范围内运行 sq-git log 来完成。如果提交有一个有效的签名,并且至少一个直接父提交的策略允许签名人进行这种类型的更改,则认为该提交已获得授权。GitHub上的项目可以使用此操作在打开或更新拉取请求时自动检查其是否获得授权。

下游用户可以使用Sequoia git检查从旧版本(已知良好的版本)到新版本的信任链。这有助于防止使用未获得项目维护者授权的修改版本。

有关语义和实现的深入讨论,请参阅规范

部署 sq-git

要开始在git仓库中使用Sequoia git,您首先需要向项目的策略中添加一个或多个证书,并授予它们一些权限。

策略名为 openpgp-policy.toml,存储在仓库的根目录下。它是一个toml文件,这意味着它可以手动编辑,但sq-git提供了使检查和修改它更简单的工具。

共有六种不同的权限:add-userretire-userauditsign-tagsign-archivesign-commit。只有拥有add-user权限的用户才能将新用户添加到策略中。同样,需要retire-user权限才能从策略中删除用户。需要audit权限才能列出(使用sq-git policy goodlist)已由后续硬撤销的证书签名的提交。需要sign-tagsign-archivesign-commit权限分别用于签名标签、存档和提交。

您可以使用sq-git policy authorize为用户授予特定的权限。例如,您可以运行

$ sq-git policy authorize --sign-commit 'Neal H. Walfield <[email protected]>' F7173B3C7C685CD9ECC4191B74E445BA0E15C957

这表示指定的证书可用于签名提交。名称纯粹是装饰性的。

为了使分配权限更容易,sq-git policy authorize了解三个角色:项目维护者(获得所有权限)、发布经理(可以签名标签、存档和提交)和提交者(只能签名提交)。这些可以传递给sq-git policy authorized。例如

$ sq-git policy authorize --project-maintainer 'Neal H. Walfield <[email protected]>' F7173B3C7C685CD9ECC4191B74E445BA0E15C957

sq-git policy authorize立即将角色扩展到相应的权限;角色不会出现在策略文件中。

您可以使用sq-git init子命令来快速了解谁为项目做出了贡献,以及他们使用了哪些证书来签名他们的提交(如果有)。sq-git init查看过去半年或最后10个提交,取较大者。因此,它专注于最近活跃的贡献者;授权已经离开项目的某人是不合理的。

尽管sq-git init通常提供了一个好的起点,但您不应该信任它。通过例如联系他们并询问他们的证书指纹等方式,验证贡献者的证书是至关重要的。由于您总是可以在以后修改策略,因此最好只添加您确信的证书,这些证书来自活跃的贡献者。

以下是初始化策略文件的示例

../sequoia-git$ sq-git init
# Examined the 136 commits in the last 183 days.
# Stopped at commit 83ce12f617c9e1dd90f812825707337f8787f69e.

# Encountered 0 unsigned commits

# Neal H. Walfield <[email protected]> added 66 commits (48%).
#
# After checking that they really control the following OpenPGP keys:
#
#   6863C9AD5B4D22D3 (66 commits)
#
# You can make them a project maintainer (someone who can add and
# remove committers) by running:
sq-git policy authorize  --project-maintainer "Neal H. Walfield <[email protected]>" 6863C9AD5B4D22D3

# Justus Winter <[email protected]> added 44 commits (32%).
#
# After checking that they really control the following OpenPGP keys:
#
#   686F55B4AB2B3386 (44 commits)
#
# You can make them a committer by running:
sq-git policy authorize --committer "Justus Winter <[email protected]>" 686F55B4AB2B3386
...
../sequoia-git$ sq-git policy authorize --project-maintainer "Neal H. Walfield <[email protected]>" 6863C9AD5B4D22D3
  - User "Neal H. Walfield <[email protected]>" was added.
  - User "Neal H. Walfield <[email protected]>" was granted the right sign-commit.
  - User "Neal H. Walfield <[email protected]>" was granted the right sign-tag.
  - User "Neal H. Walfield <[email protected]>" was granted the right sign-archive.
  - User "Neal H. Walfield <[email protected]>" was granted the right add-user.
  - User "Neal H. Walfield <[email protected]>" was granted the right retire-user.
  - User "Neal H. Walfield <[email protected]>" was granted the right audit.
../sequoia-git$ sq-git policy authorize --committer "Justus Winter <[email protected]>" 686F55B4AB2B3386
  - User "Justus Winter <[email protected]>" was added.
  - User "Justus Winter <[email protected]>" was granted the right sign-commit.

sq-git 从用户的证书存储中读取证书。使用 sq import < FILE 从文件中导入证书,使用 sq keyserver get FINGERPRINT 从密钥服务器获取证书等。或者,您可以使用 --cert-file 参数将证书提供给 sq-git policy authorize

策略文件可以按照以下方式查看

$ sq-git policy describe
# OpenPGP policy file for git, version 0

## Commit Goodlist


## Authorizations

0. Justus Winter <[email protected]>
   - may sign commits
   - has OpenPGP cert: D2F2C5D45BE9FDE6A4EE0AAF31855247603831FD
1. Neal H. Walfield <[email protected]>
   - may sign commits
   - may sign tags
   - may sign archives
   - may add users
   - may retire users
   - may goodlist commits
   - has OpenPGP cert: F7173B3C7C685CD9ECC4191B74E445BA0E15C957

如果您满意,可以按照常规方式将其添加到您的 git 仓库中。

别忘了告诉 git 通过添加以下内容到您的仓库的 .git/config 文件来签署提交

[user]
        signingkey = F7173B3C7C685CD9ECC4191B74E445BA0E15C957
        email = '[email protected]'
        name = 'Neal H. Walfield'
[commit]
        gpgsign = true

然后运行

../sequoia-git$ git add openpgp-policy.toml
../sequoia-git$ git commit -m 'Add a commit policy.'
[main 911c4eb] Add a commit policy.
 1 file changed, 119 insertions(+), 1831 deletions(-)
 rewrite openpgp-policy.toml (94%)

创建一个新的提交,并验证新版本

../sequoia-git$ echo 'hello world' > greeting
../sequoia-git$ git add greeting
../sequoia-git$ git commit -m 'Say hello.'
[main 698876a] Say hello.
 1 file changed, 1 insertion(+)
 create mode 100644 greeting
../sequoia-git$ sq-git log --trust-root 911c4eb1e9832d6df8e733bf103ca4c9f4637eb9
911c4eb1e9832d6df8e733bf103ca4c9f4637eb9..698876a7ff11fff2f8cd0df55bbe8fc5c5d224d9: Neal H. Walfield <[email protected]> [74E445BA0E15C957]

为了避免手动输入可能出错,您可以在仓库的 git 配置文件中设置信任根

../sequoia-git$ git config sequoia.trust-root 911c4eb1e9832d6df8e733bf103ca4c9f4637eb9
../sequoia-git$ sq-git log
911c4eb1e9832d6df8e733bf103ca4c9f4637eb9..698876a7ff11fff2f8cd0df55bbe8fc5c5d224d9: Cached positive verification

您还可以使用标签或分支,但是请注意,当您使用例如 git fetch 从远程仓库获取时,这些可能会更新。

拒绝未经授权的提交

将以下行插入共享 git 服务器的 hooks/update,以强制执行从给定信任根(<COMMIT>)开始的仓库中嵌入的策略,该信任根指定为哈希值

sq-git update-hook --trust-root=<COMMIT> "$@"

在 CI 中使用 sq-git

sequoia-git 以 OCI 图像的形式提供,以便在 CI 管道中易于使用。

Gitlab

要从 Gitlab CI 管道中验证提交,在 scripts/gitlab.sh 中包含了一个脚本,可以在项目的 .gitlab-ci.yml 清单中作为作业运行

authenticate-commits:
  stage: test
  image: registry.gitlab.com/sequoia-pgp/sequoia-git:latest
  script:
    - sq-git policy describe
    - ./scripts/gitlab.sh
  rules:
    # TODO: We currently only authenticate the changes on non-merged
    # branches where we use the default branch as the trust root.  For
    # the default branch, the project needs to set an explicit trust
    # root.
    - if: '$CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH'

GitHub

要使用 sq-git 在 GitHub 中验证拉取请求,您可以使用 sequoia-pgp/authenticate-commits 操作。此操作检查提交是否由合并基的最后一个提交授权。此视频 展示了操作演示。

注意:GitHub 的合并拉取请求的界面提供三种合并策略,但不幸的是,它们都不适用于 Sequoia git,因为它们都修改了提交。在使用 Sequoia git 时,必须要么重新合并并快速前进更改,要么添加一个已签名的合并提交。可以使用 sequoia-pgp/fast-forward 操作 来快速前进拉取请求。当为仓库启用时,授权用户可以在拉取请求中添加包含 /fast-forward 的评论,操作将快速前进合并基。

依赖关系

~72MB
~1.5M SLoC