PEP: 761
Title: Deprecating PGP signatures for CPython artifacts
Author: Seth Michael Larson <seth@python.org>
Sponsor: Hugo van Kemenade
Discussions-To: https://discuss.python.org/t/pep-761-deprecating-pgp-signatures-for-cpython-artifacts/67180
Status: Active
Type: Process
Created: 08-Oct-2024
Python-Version: 3.14
Post-History: `25-Sep-2024 <https://discuss.python.org/t/pre-pep-discussion-stop-providing-gpg-signatures-for-cpython-artifacts/65058>`__, `09-Oct-2024 <https://discuss.python.org/t/pep-761-deprecating-pgp-signatures-for-cpython-artifacts/67180>`__
Resolution: `06-Nov-2024 <https://discuss.python.org/t/pep-761-deprecating-pgp-signatures-for-cpython-artifacts/67180/39>`__

Abstract
========

Since Python 3.11.0, CPython has provided two verifiable digital signatures
for all CPython artifacts: PGP and Sigstore.

PGP's design requires the maintenance and protection of `long-lived private
keys <https://words.filippo.io/giving-up-on-long-term-pgp/>`_ by trusted
parties. PGP's `security and ergonomics have been criticized by security
practitioners <https://www.latacora.com/blog/2019/07/16/the-pgp-problem/>`_
for many years now, with the biggest issue being that there were few
alternatives for "artifact signing" being proposed or adopted.

`Sigstore's <https://docs.sigstore.dev>`_ design philosophy has focused on the
ergonomics of signing and verifying and `uses short-lived keys with
strongly-bound human-readable identities via OpenID Connect <https://docs.sigstore.dev/#how-sigstore-works>`_.
Sigstore has both development and adoption momentum, seeing adoption by PyPI,
NPM, Homebrew, and GitHub, among other ecosystems.

This PEP proposes to move CPython to using Sigstore exclusively for signing
artifacts through a deprecation and eventual discontinuance of providing PGP
signatures with new release managers.

Motivation
==========

CPython's releases are release-manager-centric, where a single person
maintains multiple CPython releases from pre-release to end-of-life over the
course of many years.

Requiring release managers to maintain and protect PGP private keys for seven
or more years is an unnecessary burden in the new age of ergonomic and
ephemeral signing keys. Comparatively, Sigstore only requires release managers
to click a button during the release process to OAuth sign-on to their
identity provider. Maintaining the integrity of accounts on identity providers
like GitHub is already an expectation of being a Python release manager or
core team member, such as through multi-factor authentication and strong
unique passwords.

Rationale
=========

Preserve expectations across a Python release
---------------------------------------------

To avoid breaking downstream verifiers, the expectations for verification
materials availability SHOULD NOT be changed during a feature release's
lifecycle.

Release managers, not releases
------------------------------

The discontinuation of PGP signatures doesn't necessarily have to happen
on a "release manager boundary"; a new Python release could be a potential
boundary.

Because the primary motivation for deprecating PGP is ergonomics, deciding
to drop PGP for one release while a release manager still has obligations to
provide PGP signatures for other releases for multiple years isn't much
savings of effort.

A new release manager also represents a new PGP public key that downstream
verifiers need to adopt. By choosing to make the change during this period,
this minimizes the breakage to a place in downstream maintenance where a
change will already be necessary.

Gordian knot of signing methods and verifiers
---------------------------------------------

CPython providing both PGP and Sigstore signatures concurrently creates a
"`Gordian knot <https://en.wikipedia.org/wiki/Gordian_Knot>`_" where
verifiers are disincentivized to migrate to a new signature method due to the
*continued and expected availability* of an existing signature method, thus
propagating the *apparent demand* for maintaining the existing signature
method.

This situation slows down the adoption of new signature methods like Sigstore for
both signature-producing projects and signature-verifying ecosystems by not
creating a "need" to automate and integrate the signature method into verifier
tooling.

By changing the expectation of what future signature methods will be
available, the incentive-knot can be broken by `spurring the adoption of the
new signature method in downstream tooling <https://lists.debian.org/debian-devel/2024/10/msg00025.html>`_.
This change to verifier tooling also makes other upstream projects able to
migrate to publishing only Sigstore signatures, resulting in a positive
feedback loop of adoption.

Specification
=============

Because PGP keys are tied to a release manager identity, the change to
availability of PGP signatures will be tied to release managers instead of
individual releases (3.13, 3.14, etc). This PEP both deprecates and proposes
a discontinuation timeline for PGP signatures.

Deprecation and discontinuation of PGP signatures
-------------------------------------------------

This PEP deprecates PGP signatures for future CPython releases and recommends
verifiers to adopt Sigstore to verify CPython artifacts as an alternative to
PGP.

This PEP also removes the expectation that PGP signatures be published by
future release managers that don't already maintain a stable Python release.
At the time of writing this would be Hugo van Kemenade, as 3.14 is the next
Python version without a stable release.

Releases which already have a stable release (3.13, 3.12, 3.11, etc) are not
affected and will continue to provide PGP signatures for artifacts until they
are end-of-life. All existing PGP signatures will continue to work as
expected.

Delaying discontinuation of PGP signatures
------------------------------------------

This PEP provides a mechanism to delay the *discontinuation* of PGP signatures
from active and upcoming CPython releases in case of extraordinary
circumstances. *Deprecation* of PGP signatures can't be changed without a
superseding PEP.

The Steering Council MAY at a future date after this PEP's acceptance decide
to delay the discontinuation of PGP signatures to a future CPython release.
If the Steering Council decides to delay the discontinuation of PGP signatures
then all active release managers MUST provide PGP signatures for their covered
CPython artifacts for the remainder of their tenure as a release manager. This
includes all steps required to do so, such as generating a new PGP key and
publishing their identity to python.org.

The discontinuation of PGP signatures then is automatically scheduled for the
next release manager without a stable release, to be highlighted in the
Steering Council decision.

Backwards Compatibility
=======================

This proposal would remove the ability to verify future CPython artifacts
using PGP. Any downstream verifiers using PGP for CPython artifacts would
need to either start using Sigstore, verify their source code of CPython
through other means, or stop verification altogether for future CPython
releases.

Security Implications
=====================

PGP and Sigstore have different security models, so by removing PGP
signatures this means that all users only have the option to rely on the
security model provided by Sigstore.

In general, the security model required for artifact signatures is being
able to detect whether a given artifact is from the expected source and
hasn't been modified, regardless of the security or integrity of the hosting
service (in CPython's case: python.org/downloads).

`Sigstore's security model <https://docs.sigstore.dev/about/security/>`_
depends more on centralized infrastructure compared to PGP, such as the
"public good" signature transparency log (Rekor), certificate authority and
transparency log (Fulcio), and the security of OpenID Connect identity
providers like Google and GitHub.

CPython's development already depends on the security of some of these
services and the others are better resourced than any individual release
manager to provide long-term public key management.

How to Teach This
=================

CPython `already documents <https://www.python.org/downloads/metadata/sigstore/>`_
how to verify artifacts using Sigstore based on the pre-published identities
of release managers. Documentation will be updated to indicate the deprecation
and future expectations of PGP signatures.

Verifying signatures of CPython artifacts isn't something we should expect
from new Python users. Instead, Sigstore is more likely to be a part of a
downstream integrator's build pipeline such as a Linux distro, Homebrew, pyenv,
or others that programmatically fetch and build CPython from source.

Rejected Ideas
==============

Continue publishing PGP signatures indefinitely
-----------------------------------------------

Being a release manager is already a difficult, time-consuming, and long-term
commitment that is typically done on a volunteer basis. Thus we see removal
of PGP key management duties as a step towards reducing burnout and stress
of future release managers and improving the sustainability of CPython.

Removing previous PGP signatures
--------------------------------

This PEP doesn't intend to break any infrastructure built around existing Python
versions, instead only changing the expectations around future Python versions.
Thus all PGP signatures that are already available on python.org will continue
to be available even after PGP discontinuance.

Appendix
========

Support for offline verification
--------------------------------

During the `pre-PEP discussion <https://discuss.python.org/t/pre-pep-discussion-stop-providing-gpg-signatures-for-cpython-artifacts/65058>`_,
there was a question of whether offline verification was supported by
Sigstore. Using a Sigstore bundle (:file:`.sigstore`) file, `Sigstore clients
support verifying the artifact completely offline <https://discuss.python.org/t/pre-pep-discussion-stop-providing-gpg-signatures-for-cpython-artifacts/65058/9>`_.

Using offline verification with Sigstore requires disabling root of trust
updates and "pinning" a root of trust in a file to use during verification.

Pinning a root of trust means signatures made after a *new* root of trust
is established would no longer be able to verify using a "pinned" previous
root of trust. New roots of trust are expected to be rare events, such as
when the root of trust is compromised, and in this case verifiers would
want signatures to fail to verify.

Offline verification also makes revocation checks impossible, but this
is similar to PGP's model where revocation of keys requires an online lookup.

Barring rare events like root of trust compromise, using offline verification
with Sigstore doesn't impose additional operations requirements to verifiers.

Support for a pre-compiled executable for verification
------------------------------------------------------

During discussion there were requests for a pre-compiled executable that could
be used for verifying Sigstore bundles without needing to either install
a Go build toolchain to build `sigstore-go <https://github.com/sigstore/sigstore-go>`_
from source or already have a working Python installation for
`sigstore-python <https://github.com/sigstore/sigstore-python/>`_.

`Cosign <https://github.com/sigstore/cosign/>`_ is another Sigstore project
that provides pre-compiled standalone binaries and supports verifying bundles
offline:

.. code-block::

    # Download Cosign
    wget https://github.com/sigstore/cosign/releases/download/v2.4.1/cosign-linux-amd64

    # For offline verification, also need the Root of Trust. Can be grabbed
    # from GitHub at: https://github.com/sigstore/root-signing/blob/main/targets/trusted_root.json
    wget https://raw.githubusercontent.com/sigstore/root-signing/refs/heads/main/targets/trusted_root.json

    # Download CPython artifacts
    wget https://www.python.org/ftp/python/3.13.0/Python-3.13.0.tgz
    wget https://www.python.org/ftp/python/3.13.0/Python-3.13.0.tgz.sigstore

    ./cosign-linux-amd64 verify-blob \
      --new-bundle-format \
      --certificate-oidc-issuer 'https://accounts.google.com' \
      --certificate-identity 'thomas@python.org' \
      --bundle ./Python-3.13.0.tgz.sigstore \
      # --offline and --trust-root optional for offline verification
      --offline \
      --trust-root ./trusted_root.json \
      ./Python-3.13.0.tgz

Copyright
=========

This document is placed in the public domain or under the
CC0-1.0-Universal license, whichever is more permissive.
