Changes
Page history
add documentation for Git commit signature verification
authored
Oct 13, 2025
by
zen
refs
#42099
Hide whitespace changes
Inline
Side-by-side
howto/git.md
0 → 100644
View page @
0dc60207
# Git
[[
_TOC_
]]
TPA uses Git in several places in its infra. Several services are managed via
repos hosted in
[
GitLab
][]
, but some services are managed by repos stored
directly in the target systems, such as
[
Puppet
][]
,
[
LDAP
][]
,
[
DNS
][]
,
[
TLS
][]
,
and probably others.
[
GitLab
]:
howto/gitlab
[
Puppet
]:
howto/puppet
[
LDAP
]:
howto/ldap
[
DNS
]:
howto/dns
[
TLS
]:
howto/tls
## Commit signature verification
In order to resist tampering attempts such as GitLab compromise, some key
repositories are configured to verify commit signatures before accepting ref
updates. For that, TPA uses
`sequoia-git`
to authenticate operations against
certificates and permissions stored in a centralized OpenPGP policy file. See
[
TPA-RFC-90: Signed commits
][]
for the initial proposal.
[
TPA-RFC-90: Signed commits
]:
policy/tpa-rfc-90-signed-commits
### `sequoia-git` basics
In order to authenticate changes in a Git repository,
`sequoia-git`
uses two
pieces of information:
-
an OpenPGP policy file, containing authorized certificates and a list of
permissions for each certificate, and
-
a "trust-root", which is the ID of a commit that is considered trusted.
With these,
`sequoia-git`
goes through commit by commit checking whether the
signature is valid and authorized to perform operations.
Note that, by default,
`sequoia-git`
will use the
`openpgp-policy.toml`
file in
the root of the repo it's checking, but it can also perform the checks against
an external policy file.
### The TPA setup
In TPA we use one file to authenticate changes for all our repositories, namely
the
[
`openpgp-policy.toml`
][]
file in the root of the Puppet repository. Using
one centralized file allows for updating certificates and permissions in only
one place and have it deployed to the relevant places.
The trust-root for the Puppet repos is stored both in
[
hiera data for the
puppetserver role
][]
inside the Puppet repo (for deployment in servers) and in
tpo/tpa/repos> (for configuration and verification in the client-side).
[
hiera data for the puppetserver role
]:
https://gitlab.torproject.org/tpo/tpa/puppet-control/-/blob/production/data/roles/puppetserver.yaml
When the trust-roots for these repositories change, they need to be updated in
both places.
### Authentication in the Puppet Server
The
[
Puppet repositories
][]
stored in the Puppet server are configured with
hooks to verify authentication of the incoming commits before performing ref
updates.
[
Puppet repositories
]:
howto/puppet#file-layout
Puppet deploys in the Puppet server:
-
the TPA OpenPGP policy file (
[
`openpgp-policy.toml`
][]
),
-
global Git configuration containing per-repo policy file and trust-root
configs, and
-
Git update-hooks in the
[
Puppet repositories
][]
that only allow ref updates
if authentication is valid
[
`openpgp-policy.toml`
]:
https://gitlab.torproject.org/tpo/tpa/puppet-control/-/blob/production/openpgp-policy.toml
With this, ref updates in the Puppet Git repos are only performed if all
commits since the trust-root are signed with authorized certificates contained
in the TPA OpenPGP policy file.
### Permission updates
During bootstrap of this mechanism, the TPA OpenPGP policy file was first
deployed to the Puppet server. This way, all changes are checked against the
policy file that is already installed in
`/etc/openpgp-policy`
in the server.
While a certificate is still valid, it should then be able to push any change
to the server, which includes the ability to perform updates of the
`openpgp-policy.toml`
file itself.
Note that, because we use a centralized OpenPGP policy file, when permissions
are removed for a certificate, we may need to update the trust-root, otherwise
old commits may fail to be authenticated against the new policy file.
### Expired certificates
If a certificate expires before being it's been updated in the
`openpgp-policy.toml`
file, changes signed by that certificate will not be
accepted, and you'll need to (1) ask another sysadmin with a valid certificate
to perform the needed changes and (2) wait for or force deployment of the new
file in the server.
### Manual override
There may be extreme situations in which you need to override the
authentication check, for example if your certificate expired and you're the
only sysadmin in duty. In these cases, you can manually remove/update the
corresponding Git hooks in the server and push the needed changes. If you do
this, make sure to:
-
update the trust root both in the
[
hiera data for the puppetserver role
][]
and in tpo/tpa/repos>.
-
instruct the other sysadmins to pull tpo/tpa/repos> and run
`mr update`
, so
their local Git configs for trust-roots is automatically updated. If you
don't do that, their local checks will start failing when they pull commits
that can't be authenticated.
### Other repositories
Even though we initially deployed this mechanism to Pupper repositories only,
the current implementation of the
[
OpenPGP policy profile
][]
allows for
configuration of the same setup for arbitrary repositories, which can be
configured via hiera. See the
[
hiera data for the puppetserver role
][]
for an
example.
[
OpenPGP policy profile
]:
https://gitlab.torproject.org/tpo/tpa/puppet-control/-/blob/production/site/profile/manifests/openpgp_policy.pp
Setting trust-roots is mandatory, while policy files are optional. If no policy
file is explicitly set, the Git hook will perform the authentication checks
against the policy file in the root of the repository itself.