Skip to content

fix: fall back to Yarn-published key and pin Yarn signer - #2693

Closed
LittleGnome wants to merge 1 commit into
nodejs:mainfrom
LittleGnome:fix/yarn-key-fallback
Closed

LittleGnome wants to merge 1 commit into
nodejs:mainfrom
LittleGnome:fix/yarn-key-fallback

Conversation

@LittleGnome

Copy link
Copy Markdown

Description

Make the Yarn v1 Classic install step (Node.js 22 and 24 images) resilient to keyserver outages, and pin the expected signer of the Yarn tarball.

  1. Third key source. If neither keys.openpgp.org nor keyserver.ubuntu.com yields the key, fall back to the key that Yarn itself publishes at https://dl.yarnpkg.com/debian/pubkey.gpg.
  2. Signer pinned by full fingerprint. gpg --verify is replaced by gpg --status-fd 1 --verify … | grep VALIDSIG … 72ECF46A56B4AD39C907BBB71646B01B86E50310$. The Yarn 1.22.22 tarball is signed by primary key 72ECF46A56B4AD39C907BBB71646B01B86E50310 (Yarn Packaging <yarn@dan.cx>), so the build now only succeeds for a valid signature by that exact key, whichever source the key came from. This keeps a fingerprint embedded in the Dockerfile, as the Docker Official Images security guidance requires.

The keyserver path is unchanged and still tried first. The change is applied to the three templates and to the existing 22/* and 24/* Dockerfiles (Node.js 26+ images do not include Yarn).

Motivation and Context

PR #2692 (Node.js v22.23.5 / v24.22.3) is blocked: during the Canonical outage of 2026-11-11, all Node.js 22 and 24 builds fail while all Node.js 26 builds pass. The failing step is the Yarn key fetch:

Why the explicit signer check matters with the new fallback: pubkey.gpg contains two primary keys (72ECF46A… and the 2026 key 4EF8150F…), and a plain gpg --verify accepts a valid signature from any key in the keyring. Pinning VALIDSIG to the expected fingerprint makes the trust anchor the fingerprint in the Dockerfile rather than the contents of the downloaded key file.

Testing Details

Tested on macOS (Apple Silicon), Docker Desktop, --platform linux/amd64, while keyserver.ubuntu.com was unreachable (so the new fallback path was exercised):

Image Result node -v / npm -v / yarn --version
22/trixie built v22.23.4 / 10.9.9 / 1.22.22
22/bookworm-slim built v22.23.4 / 10.9.9 / 1.22.22
22/alpine3.23 built v22.23.4 / 10.9.9 / 1.22.22

Yarn step log (22/trixie):

+ gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys 6A010C5166006599AA17F08146C2130DFD2497F5
gpg: key 1646B01B86E50310: new key but contains no user ID - skipped
+ gpg --batch --keyserver keyserver.ubuntu.com --recv-keys 6A010C5166006599AA17F08146C2130DFD2497F5
gpg: keyserver receive failed: Connection timed out
+ curl -fsSL https://dl.yarnpkg.com/debian/pubkey.gpg
gpg: Good signature from "Yarn Packaging <yarn@dan.cx>" [unknown]

The keyserver path (when keyserver.ubuntu.com is reachable) is unchanged; the signature is made by the primary key 72ECF46A… in both cases, so the VALIDSIG pin applies equally to it.

Negative test of the signer pin (Alpine 3.23, GnuPG from apk), with pubkey.gpg plus a locally generated, ultimately-trusted "attacker" key in the keyring:

Case plain gpg --verify with pin
genuine yarn-v1.22.22.tar.gz.asc Good signature accepted
detached signature by another key Good signature rejected
tarball modified after signing BAD signature rejected

npm run lint (doctoc, prettier, eslint) passes.

Types of changes

  • Documentation
  • Version change (Update, remove or add more Node.js versions)
  • Variant change (Update, remove or add more variants, or versions of variants)
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Other (none of the above)

Checklist

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have read the CONTRIBUTING.md document.
  • All new and existing tests passed.

🤖 Generated with Claude Code

@LittleGnome

Copy link
Copy Markdown
Author

@nschonni re your note on #2692 that the Docker Hub build "will stall the same there": this PR should cover that case. With it, all 12 Node.js 22/24 variants build here while keyserver.ubuntu.com is unreachable, using Yarn's own published key as a fallback, with the signer pinned to the 72ECF46A… fingerprint. Merging it after #2692 also triggers a new official-images PR, so the fix would reach the Docker Hub builds too.

keys.openpgp.org serves the Yarn v1 key without a user ID, so
keyserver.ubuntu.com is the only working key source for the Node.js
22 and 24 images. When it is unavailable, every Yarn install step fails.

- fall back to https://dl.yarnpkg.com/debian/pubkey.gpg if both
  keyservers fail
- require a valid signature by the Yarn primary key
  72ECF46A56B4AD39C907BBB71646B01B86E50310 (VALIDSIG), so that only the
  pinned key is trusted regardless of where it was imported from

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Marco Knol <littlegnomenv@gmail.com>
@LittleGnome
LittleGnome force-pushed the fix/yarn-key-fallback branch from 5a870aa to 58ab465 Compare November 11, 2026 18:33
@LittleGnome

Copy link
Copy Markdown
Author

@tianon the official-images build for docker-library/official-images#22729 fails for all Node.js 22/24 variants on exactly this step (gpg: key 1646B01B86E50310: no user ID → keyserver receive failed: Operation timed out). This PR is now rebased on #2692 and CI is green for all 12 variants of 22.23.5 and 24.22.3 while the keyserver is still down. Regarding your earlier concern in #2265 about consuming key files safely: the fallback key is only trusted through a VALIDSIG match on the full primary fingerprint 72ECF46A56B4AD39C907BBB71646B01B86E50310, so a signature by any other key in pubkey.gpg (or an injected one) is rejected. Merging this would trigger a new official-images PR with the fix.

@MikeMcC399

Copy link
Copy Markdown
Member

The keyserver is now up and running and the builds succeed.

@LittleGnome

Copy link
Copy Markdown
Author

Thanks @MikeMcC399, great to see docker-library/official-images#22729 merged.

For what it's worth, this change should be harmless to keep regardless: the keyserver path is unchanged and still tried first, so with working keyservers the build behaves exactly as before. The dl.yarnpkg.com fallback is only used when both keyservers fail, and the stricter VALIDSIG check only accepts a signature by the Yarn primary key 72ECF46A…, which is the key that signs 1.22.22 anyway. It would just avoid a repeat of today's stall during the next keyserver outage.

That said, if you feel it isn't worth carrying, feel free to close it — no problem at all.

@MikeMcC399

Copy link
Copy Markdown
Member

Thank you very much for your suggestion! Any change that affects security would however need careful review from the team, including the representatives from the official Docker images program. Avoiding a single point of failure would certainly be beneficial. The Yarn maintainers stated that they plan to deprecate v1, so there may be other plans to be considered later this year.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants