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.
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.listThe actual issue — remote sources:
repo.baseurlhere resolves to upstream network endpoints, so GPG verification is disabled on exactly the sources where it matters most.Environment
roles/repo/tasks/build.yml,roles/repo/tasks/main.yml,roles/node/tasks/pkg.ymlOccurrence 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.gpgand/etc/apt/keyrings/pgdg.gpgare 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 E7935D8DB9BD8B20onrepo.pigsty.cc/apt/infraand/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=…], acrossrepo.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 oftrusted=yesfor remote repositories, pointing at the keyring Pigsty already deploys for that source, e.g.:A per-repository
key/keyringattribute in the repository definition would let each entry declare its own keyring, with the localfile:repository keepingtrusted=yessince 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.