From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp2.migadu.com ([2001:41d0:303:e16b::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms1.migadu.com with LMTPS id uD4jGA9QNWZAJAAAe85BDQ:P1 (envelope-from ) for ; Fri, 03 May 2024 22:58:55 +0200 Received: from aspmx1.migadu.com ([2001:41d0:303:e16b::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp2.migadu.com with LMTPS id uD4jGA9QNWZAJAAAe85BDQ (envelope-from ) for ; Fri, 03 May 2024 22:58:55 +0200 X-Envelope-To: larch@yhetil.org Authentication-Results: aspmx1.migadu.com; dkim=fail ("headers rsa verify failed") header.d=gnu.org header.s=fencepost-gnu-org header.b=p5m5yFVC; spf=pass (aspmx1.migadu.com: domain of "guix-patches-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="guix-patches-bounces+larch=yhetil.org@gnu.org"; dmarc=pass (policy=none) header.from=gnu.org ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=yhetil.org; s=key1; t=1714769935; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding:resent-cc: resent-from:resent-sender:resent-message-id:list-id:list-help: list-unsubscribe:list-subscribe:list-post:dkim-signature; bh=zmD0NA+tMWls66mlTQVN5DRMRHILz04aVbV/gvsW3Ao=; b=h4oHaITaQZy61wT1PioJ4LCvZnBt23/1C81AkPn5z5IjzxZQcR/iErZ6xFNVfD7z5QqN6t d8KEAOKnI5v1Ct24JEkpBA7W4dFE1pEfifuOoSdt8n8cluU3KHwDFofBQKnVPAztqZOA1B tL99QqEWAEhM15IDM/FwQ814aLZF/jzhASGzga52v5IBgJSWgt/+9YsYr/YduWkvOAVNQF IprENtXBUCv7+T1YLQodh59vkTiLT+vg6VGw/dT5cYW+rfB8PVh9DzANpTDZzl/MrfNBtV lGw9LVdVAlBoxp0WSK9V8ZTd0mtd8hUK/fXDzRD+8Ed2/rdZ0OT0DOwm5DQV+Q== ARC-Authentication-Results: i=1; aspmx1.migadu.com; dkim=fail ("headers rsa verify failed") header.d=gnu.org header.s=fencepost-gnu-org header.b=p5m5yFVC; spf=pass (aspmx1.migadu.com: domain of "guix-patches-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="guix-patches-bounces+larch=yhetil.org@gnu.org"; dmarc=pass (policy=none) header.from=gnu.org ARC-Seal: i=1; s=key1; d=yhetil.org; t=1714769935; a=rsa-sha256; cv=none; b=fhAfwE08gvS3bOEAPNChgMAXGa2YwEU46B5GgyhxGZRyI8Ml/NgtLttH2Bf91M2ny0HDnO BJkjN9CdAnPRa1/O1tbkzBfZZOPUlA+D7H+hmZY9Vsifestvjjh6cdMhTqCzmkDWXM3iPQ m6Q7PMGmSOyu3gSRiSd1urKD5WgGdCkI3ZWLPFAoFWacvqYPxUt2f+xnGsr41DkFTy71/1 hsQUi5pgI/y0IqzRSCmSNUtAJyEYMmAHqN/quIHPt6QOWVMpHAjsR9SHPcgIvS5XXKxe7C m6vjuE5g/MuZ47BNL362oZmbyLR+6sntQ63rjVHw+z5E1xNP7wzDAaQGHkOcdA== Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id 0847D631BE for ; Fri, 3 May 2024 22:58:54 +0200 (CEST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1s2zzR-0005dU-8E; Fri, 03 May 2024 16:58:45 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1s2zzO-0005ct-G4 for guix-patches@gnu.org; Fri, 03 May 2024 16:58:42 -0400 Received: from debbugs.gnu.org ([2001:470:142:5::43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1s2zzN-00029Y-5Q; Fri, 03 May 2024 16:58:42 -0400 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1s2zzi-0007R0-6c; Fri, 03 May 2024 16:59:02 -0400 X-Loop: help-debbugs@gnu.org Subject: [bug#70759] [PATCH guix-artwork] website: Add post about =?UTF-8?Q?=E2=80=98guix?= git =?UTF-8?Q?authenticate=E2=80=99.?= Resent-From: Ludovic =?UTF-8?Q?Court=C3=A8s?= Original-Sender: "Debbugs-submit" Resent-CC: guix-blog@gnu.org, ~@wolfsden.cz, skyvine@protonmail.com, guix-patches@gnu.org Resent-Date: Fri, 03 May 2024 20:59:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 70759 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 70759@debbugs.gnu.org Cc: Ludovic =?UTF-8?Q?Court=C3=A8s?= , guix-blog@gnu.org, Tomas Volf <~@wolfsden.cz>, Skyler Ferris X-Debbugs-Original-To: guix-patches@gnu.org X-Debbugs-Original-Xcc: guix-blog@gnu.org, Tomas Volf <~@wolfsden.cz>, Skyler Ferris Received: via spool by submit@debbugs.gnu.org id=B.171476992328567 (code B ref -1); Fri, 03 May 2024 20:59:01 +0000 Received: (at submit) by debbugs.gnu.org; 3 May 2024 20:58:43 +0000 Received: from localhost ([127.0.0.1]:48684 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1s2zzO-0007Qg-Hd for submit@debbugs.gnu.org; Fri, 03 May 2024 16:58:43 -0400 Received: from lists.gnu.org ([2001:470:142::17]:42848) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1s2zzL-0007QW-9J for submit@debbugs.gnu.org; Fri, 03 May 2024 16:58:40 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1s2zyn-0005UE-Ah for guix-patches@gnu.org; Fri, 03 May 2024 16:58:05 -0400 Received: from fencepost.gnu.org ([2001:470:142:3::e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1s2zym-00025k-27; Fri, 03 May 2024 16:58:04 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=MIME-Version:Date:Subject:To:From:in-reply-to: references; bh=zmD0NA+tMWls66mlTQVN5DRMRHILz04aVbV/gvsW3Ao=; b=p5m5yFVCp2mP/6 x/WFTWPY6aY5ElIg7DPuQWeSkLoTCCyGeTGIv3i6tOSS/OGpRd2NzcJH+4/TuUQMjpmo/hsRYJ4ea TD3kXEY1HjWU8UleeY+QXOiJLLQf5ggmNa2aRCEy2XZoTYZikEmehh2piZJpgKG3ABJ4BDak+CsMV Mld4RhLEzp0gGtoJLy4tte1mXHM6yH+kUByLVP6arooLf6aItZ1dfuQfwa/C1TjZZ1dSCLJzbh4hU foc+QvbCQ8EVpnCAtw9x2Wumf8zuUxBsqxz8U2bJ39dzSok8nvWgyD3caZbU2pblDfokG7aqvhuM1 CwxXgFUIOAQmxTpydBMg==; From: Ludovic =?UTF-8?Q?Court=C3=A8s?= Date: Fri, 3 May 2024 22:57:29 +0200 Message-ID: <20240503205729.6354-1-ludo@gnu.org> X-Mailer: git-send-email 2.41.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+larch=yhetil.org@gnu.org Sender: guix-patches-bounces+larch=yhetil.org@gnu.org X-Migadu-Flow: FLOW_IN X-Migadu-Country: US X-Migadu-Spam-Score: -6.09 X-Spam-Score: -6.09 X-Migadu-Queue-Id: 0847D631BE X-Migadu-Scanner: mx13.migadu.com X-TUID: ZxXcljiW1Rxi * website/posts/git-authenticate.md: New file. --- website/posts/git-authenticate.md | 217 ++++++++++++++++++++++++++++++ 1 file changed, 217 insertions(+) create mode 100644 website/posts/git-authenticate.md Hello Guix! In my quest to make the world a better place *cough* I thought I’d take the recent improvements to ‘guix git authenticate’¹ as an opportunity to spread the word about Git checkout authentication, about the tool, and to send a call for action—I’d love to see someone implement it or a variant thereof for a broader audience. I’d like to publish this blog post in the coming days. Feedback welcome! Thanks, Ludo’. ¹ https://issues.guix.gnu.org/69780 diff --git a/website/posts/git-authenticate.md b/website/posts/git-authenticate.md new file mode 100644 index 0000000..9950b37 --- /dev/null +++ b/website/posts/git-authenticate.md @@ -0,0 +1,217 @@ +title: Authenticate your Git checkouts! +author: Ludovic Courtès +tags: Security, Software development +date: 2024-05-06 14:14 +--- + +You clone a Git repository, then pull from it. How can you tell its +contents are “authentic”—i.e., coming from the “genuine” project you +think you’re pulling from, written by the fine human beings you've been +working with? With commit signatures and “verified” badges ✅ +flourishing, you’d think this has long been solved—but nope! + +Four years after Guix [deployed its own +tool](https://guix.gnu.org/en/blog/2020/securing-updates/) to allow +users to authenticate updates fetched with `guix pull` (which uses Git +under the hood), the situation hasn’t changed all that much: the vast +majority of developers using Git simply do not authenticate the code +they pull. That’s pretty bad. It’s the modern-day equivalent of +sharing unsigned tarballs and packages like we’d blissfully do in the +past century. + +The authentication mechanism Guix uses for +[channels](https://guix.gnu.org/manual/devel/en/html_node/Channels.html) +is available to any Git user through the [`guix git +authenticate`](https://guix.gnu.org/manual/devel/en/html_node/Invoking-guix-git-authenticate.html) +command. This post is a guide for Git users who are not necessarily +Guix users but are interested in using this command for their own +repositories. Before looking into the command-line interface and how we +improved it to make it more convenient, let’s dispel any +misunderstandings or misconceptions. + +# Why you should care + +When you run `git pull`, you’re fetching a bunch of commits from a +server. If it’s over HTTPS, you’re authenticating *the server* itself, +which is nice, but that does not tell you who the code actually comes +from—the server might be compromised and an attacker pushed code to the +repository. Not helpful. At all. + +But hey, maybe you think you’re good because everyone on your project is +signing commits and tags, and because you’re disciplined, you routinely +run `git log --show-signature` and check those “Good signature” GPG +messages. Maybe you even have those fancy “✅ verified” badges as found +[on +GitLab](https://docs.gitlab.com/ee/user/project/repository/signed_commits/gpg.html) +and [on +GitHub](https://docs.github.com/en/authentication/managing-commit-signature-verification). + +Signing commits is part of the solution, but it’s not enough to +_authenticate_ a set of commits that you pull; all it shows is that, +well, those commits are signed. Badges aren’t much better: the presence +of a “verified” badge only shows that the commit is signed by the +OpenPGP key *currently registered* for the corresponding GitLab/GitHub +account. If you register a new key, or if you leave the project, your +commits lose their badge. Not helpful either, not to mention that this +is all tied to the hosting site you’re on, outside of Git’s control. + +Being able to ensure that when you run `git pull`, you’re getting code +that _genuinely_ comes from authorized developers of the project is +basic security hygiene. Obviously it cannot protect against efforts to +infiltrate a project to eventually get commit access and insert +malicious code—the kind of multi-year plot that led to the [xz +backdoor](https://tukaani.org/xz-backdoor/)—but if you don’t even +protect against unauthorized commits, then all bets are off. + +Authentication is something we naturally expect from `apt update`, +`pip`, `guix pull`, and similar tools; why not treat `git pull` to the +same standard? + +# Initial setup + +The [`guix git +authenticate`](https://guix.gnu.org/manual/devel/en/html_node/Invoking-guix-git-authenticate.html) +command authenticates Git checkouts, unsurprisingly. It’s currently +part of Guix because that’s where it was brought to life, but it can be +used on any Git repository. This section focuses on how to use it; you +can learn about the motivation, its design, and its implementation in +[the 2020 blog +post](https://guix.gnu.org/en/blog/2020/securing-updates/), in the 2022 +peer-reviewed academic paper entitled [_Building a Secure Software +Supply Chain with +GNU Guix_](https://doi.org/10.22152/programming-journal.org/2023/7/1), +or in this 20mn +[presentation](https://archive.fosdem.org/2023/schedule/event/security_where_does_that_code_come_from/). + +To support authentication of your repository with `guix git +authenticate`, you need to follow these steps: + + 0. Enable commit signing on your repo: `git config commit.gpgSign + true`. (Git now supports other signing methods but here we need + OpenPGP signatures.) + + 1. Create a `keyring` branch containing all the OpenPGP keys of all + the committers, along these lines: + + ``` + git checkout --orphan keyring + git reset --hard + gpg --export alice@example.org > alice.key + … + git add *.key + git commit -a -m "Add committer keys." + ``` + + All the files must end in `.key`. You must never remove keys from + that branch: keys of users who left the project are necessary to + authenticate past commits. + + 2. Back to the main branch, add a `.guix-authorizations` file, listing + the OpenPGP keys of authorized committers—we’ll get back to its + format below. + + 3. Commit! This becomes the _introductory commit_ from which + authentication can proceed. The _introduction_ of your repository + is the ID of this commit and the OpenPGP fingerprint of the key + used to sign it. + +That’s it. From now on, anyone who clones the repository can +authenticate it. The first time, run: + +``` +guix git authenticate COMMIT SIGNER +``` + +… where `COMMIT` is the commit ID of the introductory commit, and +`SIGNER` is the OpenPGP fingerprint of the key used to sign that commit +(make sure to enclose it in double quotes if there are spaces!). As a +repo maintainer, you must advertise this introductory commit ID and +fingerprint on a web page or in a `README` file so others know what to +pass to `guix git authenticate`. + +The commit and signer are now recorded on the first run in +`.git/config`; next time, you can run it without any arguments: + +``` +guix git authenticate +``` + +The other new feature is that the first time you run it, the command +installs *pre-push and pre-merge hooks* (unless preexisting hooks are +found) such that your repository is automatically authenticated from +there on every time you run `git pull` or `git push`. + +`guix git authenticate` exits with a non-zero code and an error message +when it stumbles upon a commit that lacks a signature, that is signed by +a key not in the `keyring` branch, or that is signed by a key not listed +in `.guix-authorizations`. + +# Maintaining the list of authorized committers + +The `.guix-authorizations` file in the repository is central: it lists +the OpenPGP fingerprints of authorized committers. Any commit that is +*not* signed by a key listed in the `.guix-authorizations` file of its +parent commit(s) is considered inauthentic—and an error is reported. +The [format of +`.guix-authorizations`](https://guix.gnu.org/manual/devel/en/html_node/Specifying-Channel-Authorizations.html#channel_002dauthorizations) +is based on [S-expressions](https://en.wikipedia.org/wiki/S-expression) +and looks like this: + +```scheme +;; Example '.guix-authorizations' file. + +(authorizations + (version 0) ;current file format version + + (("AD17 A21E F8AE D8F1 CC02 DBD9 F8AE D8F1 765C 61E3" + (name "alice")) + ("2A39 3FFF 68F4 EF7A 3D29 12AF 68F4 EF7A 22FB B2D5" + (name "bob")) + ("CABB A931 C0FF EEC6 900D 0CFB 090B 1199 3D9A EBB5" + (name "charlie")))) +``` + +The `name` bits are hints and do not have any effect; what matters is +the fingerprints that are listed. You can obtain them with GnuPG by +running commands like: + +``` +gpg --fingerprint charlie@example.org +``` + +At any time you can add or remove keys from `.guix-authorizations` and +commit the changes; those changes take effect for child commits. For +example, if we add Billie’s fingerprint to the file in commit _A_, then +Billie becomes an authorized committer in *descendants* of commit _A_ +(we must make sure to add Billie’s key as a file in the `keyring` +branch, too, as we saw above); Billie is still unauthorized in branches +that lack _A_. If we remove Charlie’s key from the file in commit _B_, +then Charlie is no longer an authorized committer, except in branches +that start before _B_. This should feel rather natural. + +That’s pretty much all you need to know to get started! [Check the +manual](https://guix.gnu.org/manual/devel/en/html_node/Invoking-guix-git-authenticate.html) +for more info. + +All the information needed to authenticate the repository is contained +in the repository itself—it does not depend on a forge or key server. +That’s a good property to allow anyone to authenticate it, to ensure +determinism and transparency, and to avoid lock-in. + +# Interested? You can help! + +`guix git authenticate` is a great tool that you can start using today +so you and fellow co-workers can be sure you’re getting the right code! +It solves an important problem that, to my knowledge, hasn’t really been +addressed by any other tool. + +Maybe you’re interested but don’t feel like installing Guix “just” for +this tool. Maybe you’re not into Scheme and Lisp and would rather use a +tool written in your favorite language. Or maybe you think—and +rightfully so—that such a tool ought to be part of Git proper. + +That’s OK, we can talk! We’re open to discussing with folks who’d like +to come up with alternative implementations—check out the articles +mentioned above if you’d like to take that route. And we’re open to +contributing to a standardization effort. Let’s [get in +touch](https://guix.gnu.org/contact/)! base-commit: a4153e25c8fc37920a56330a60734f4205f3dcb0 -- 2.41.0