pgsty / pgsty/pigsty

apt: remote repositories are written with [trusted=yes], disabling GPG verification on network sources

Open
#784 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Shell
Stars
5.7k
Forks
384
Avg merge
2h 36m
Merged PRs (30d)
2

Description

Summary

When Pigsty renders APT source lists, it marks remote repositories as [trusted=yes]. That option tells APT to accept packages from those sources without verifying their signatures.

The result is that a default Pigsty installation fetches and installs packages from the network — including repo.pigsty.io, PGDG and the OS mirrors — with authentication switched off. Any party able to interfere with those transports (a compromised or hijacked mirror, a DNS answer, an intercepting proxy, a plain-HTTP hop) can serve an arbitrary package, and dpkg will execute its maintainer scripts as root at install time.

This is not about the local repository: see "Scope" below.

Scope — 2 of the 6 occurrences are legitimate, 4 are not

I want to be precise, because half of these are fine and should stay as they are.

Legitimate (please keep): the machine-local repository, which is unsigned by construction and reached over no network at all:

{# roles/repo/tasks/build.yml:236 and roles/repo/tasks/main.yml:86 #}
echo "deb [trusted=yes] file:{{ repo_home }}/{{ repo_name }}/ ./" > /etc/apt/sources.list.d/pigsty-local.list

The actual issue — remote sources:

{# roles/repo/tasks/build.yml:83 and :85 #}
deb [trusted=yes] {{ repo.baseurl[region] | replace('${admin_ip}', admin_ip) | ... }}
deb [trusted=yes] {{ repo.baseurl.default | replace('${admin_ip}', admin_ip) | ... }}
{# roles/node/tasks/pkg.yml:60 and :62 — same pattern #}
deb [trusted=yes] {{ repo.baseurl[region] | ... }}
deb [trusted=yes] {{ repo.baseurl.default | ... }}

repo.baseurl here resolves to upstream network endpoints, so GPG verification is disabled on exactly the sources where it matters most.

Environment
Pigsty v4.4.0 and v4.5.0 (unchanged between the two tags)
OS Ubuntu 24.04 LTS
Files roles/repo/tasks/build.yml, roles/repo/tasks/main.yml, roles/node/tasks/pkg.yml

Occurrence counts are identical in both tags (build.yml: 3, main.yml: 1, pkg.yml: 2).

Why the fix is known to work

Pigsty already installs the keyrings it needs/etc/apt/keyrings/pigsty.gpg and /etc/apt/keyrings/pgdg.gpg are present on a stock install, and the OS keyring ships with the distribution. The signing material is therefore in place; only the reference to it is missing from the rendered source lines.

The Pigsty repositories themselves do publish signed indexes. #673 shows a user hitting NO_PUBKEY E7935D8DB9BD8B20 on repo.pigsty.cc/apt/infra and /apt/pgsql — an error that can only occur when APT is verifying signatures. So the signing material exists on both ends: the repository signs, the keyring is installed, and only the rendered source line tells APT to skip the check.

I have been running a Pigsty node for two months with every remote repository rewritten by hand from [trusted=yes] to [signed-by=…], across repo.pigsty.io, PGDG, the OS mirrors and one third-party repo. Package installation, upgrades and repository refreshes all behave normally — including the Pigsty-built packages. So this is not a theoretical hardening request: the signed configuration is a working one, it simply is not what Pigsty renders by default.

Suggested fix

Emit signed-by= instead of trusted=yes for remote repositories, pointing at the keyring Pigsty already deploys for that source, e.g.:

deb [signed-by=/etc/apt/keyrings/pigsty.gpg] https://repo.pigsty.io/apt/infra/ generic main

A per-repository key/keyring attribute in the repository definition would let each entry declare its own keyring, with the local file: repository keeping trusted=yes since it has no signature to verify.

If a fully signed default is considered too disruptive for existing offline or air-gapped setups, exposing it as a variable (defaulting to the current behaviour) would already let operators opt into verified sources without patching the roles — which is what has to be done today, and re-done after every version bump.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the remote repository entries in roles/repo/tasks/build.yml and roles/node/tasks/pkg.yml, then compare them with the local file repository entries in roles/repo/tasks/main.yml. Check how each repository's keyring is deployed and how the rendered APT source lines reference it. Done means remote sources retain GPG verification while the machine-local source keeps its existing trusted=yes behavior, with package installation and repository refreshes still working.

Written by the indexing model from the issue text.

Assessment

Tech stack
ansible, shell
Domain
devops, infrastructure, security
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
74/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.