Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions COMPATIBILITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,22 @@ binary path remains only as a compatibility fallback for older providers.
Wrappers are atomically installed as regular mode-0700 files; content, type,
and permission drift causes the selected wrappers to be restored.

The manager owns materializing Metadata's CNI configuration, including the
known IPsec filename transition. Only an unrequested `10-rancher.conf` with
the exact `rancher-cni-network` / `rancher-bridge` / `rancher-cni-ipam` contract
is retired when the desired `10-pasturestack.conf` declares
`pasturestack-cni-network` / `pasture-bridge` / `metadata-cni-ipam`. All desired
files must validate and complete atomic mode-0600 writes first. Retirement
preserves the original bytes under a `.pasturestack-retired` suffix that the
CNI loader does not execute. An existing backup must be byte-identical;
different contents, ambiguous ownership, malformed configs, symlinks, or
unsafe paths fail reconciliation without retiring the old config. Rolling
back to the exact legacy contract retires only an unrequested native file
with its complete known contract. A config still requested by Metadata is
never retired. Changes to `managed.d` stage a new symlink before replacing
the old pointer. Other administrator files are preserved; no directory-wide
cleanup or inferred ownership is used.

For a host-port container whose Metadata primary IP has not converged, the
manager may read only that running container's network namespace. The Docker
PID must remain identical across the read, the network must already expose a
Expand Down
90 changes: 25 additions & 65 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,67 +8,12 @@ PastureStack is an independent community effort to preserve, audit, and moderniz

## Runtime image

The `v0.8.14` image was published with GHCR manifest digest
`sha256:59b4bb31df28503337e9f3b8f08c18aa0dbe9749692c721fe8bdfc4cc921f263`.
Its annotated tag resolves to signed source commit
`98ffacd24436d42e33db721ab7026739d0edee41`. The release workflow passed
tests, a reproducible build, Trivy source/binary/image scans, CycloneDX source
and image SBOM checks, and asset/image provenance attestations. Image
publication is separate from Catalog integration and the complete
control-plane host lifecycle gate.

On an isolated Ubuntu 26.04.1 / Docker 29.8 VM, a source-equivalent release
candidate passed backend detection against Docker's native nftables,
iptables-nft, and iptables-legacy modes, rejected mismatched explicit choices
without changing rules, and passed a Docker restart check and a legacy-mode
host reboot check. This does not establish multi-host rollout or existing-stack
upgrade safety.

The `v0.8.15` image was published with GHCR manifest digest
`sha256:622cfb38a58f204d23152205e6d850d204d1cb9d3c50392a935afee49d780e3e`.
Its annotated tag resolves to signed source commit
`26eee48df2e3bac96fc97fcd596a16deccc9f4ad`. The release workflow passed
its build, security, checksum, SBOM, and provenance gates. This release moves
same-subnet NAT exclusion into the manager's xtables rules, matching native
nftables ownership. The isolated VM applied, reapplied, inspected, and removed
candidate host NAT and host-port rules under Docker's iptables-nft and
iptables-legacy frontends. Image publication and isolated-VM tests do not by
themselves establish a managed-service or multi-host rollout.

The `v0.8.16` image was published with GHCR manifest digest
`sha256:a042c582689561b43349fa83ed92269e849038be3b7a2342e8a9ef0149460f92`.
The `v0.8.17` image was published with GHCR manifest digest
`sha256:f13654b27b71f3fbddbcf33272c10b342d513dd402a255bdda1f341cfbe908f8`.
Its signed tag resolves to verified source commit
`e29dd5cefa373140d76e3a21da9bd95a3bec97e3`; the release workflow passed
tests, image scanning, checksums, SBOM, and provenance gates. This version adds
bounded cross-host exceptions for the per-host-subnet
network: only active hosts with distinct, valid subnet labels are peers. Their
traffic retains its container source IP and is marked before Docker's native
nft bridge filter. An active host with a missing or overlapping label fails
closed; an inactive registration does not block live peers. Network Plugin
Manager owns these NAT and forwarding rules, not the CNI driver or an ad-hoc
host firewall script.

On two isolated Ubuntu 26.04.1 / Docker 29.8 QA hosts, a source-equivalent
`v0.8.17` candidate passed bidirectional container ping and TCP 42, service
DNS, public HTTPS egress, and host port 32792 after Docker restarts and host
reboots. The second host was also explicitly switched to `iptables-nft`, then
`iptables-legacy`, with the same cross-host checks passing in each mode. It was
restored to native nft afterward. The official `v0.8.17` image was then used on
both native-nft hosts with the official IPsec/VXLAN `v0.14.34` image; manager
health, bidirectional TCP 42, Metadata HTTP 200, public HTTPS, and published
host ports all passed. The manager follows the Docker-selected backend; it
does not change the host's firewall preference. This bounded test
does not establish every existing iptables or IPsec deployment's migration safety.

The `v0.8.18` image was published with GHCR manifest digest
`sha256:1f5d44de03648a771ec9e7bc448e456ef6b21a5fcd4cc51f59f99df96a804822`.
It restores target-scoped authorization for every packet in an owned DNAT
flow, including later UDP datagrams, without accepting unrelated Docker
traffic.

The current release is `v0.8.21`. Managed bridge subnets can initiate
The current release is `v0.8.22`. Release assets include source and image
SBOMs, SHA256 checksums, and build provenance. Obtain the immutable image
identity from the checksum-covered `published.txt` in the release. Catalog
integration and real-host lifecycle checks are separate from image publication.

Managed bridge subnets can initiate
outbound traffic and receive established or related replies. Shared overlay
subnets used by IPsec and VXLAN can also receive new connections from the
same validated subnet through the exact managed bridge. Existing templates
Expand All @@ -93,7 +38,7 @@ image identity from the release's checksum-covered
[`published.txt`](https://github.com/PastureStack/network-plugin-manager/releases/latest/download/published.txt)
rather than copying an older release digest.

`v0.8.21` also closes two control-plane convergence gaps without moving
The manager also closes two control-plane convergence gaps without moving
responsibility between plugins. If Metadata temporarily omits the primary IP
of a running container that publishes a host port, the manager reads that
exact container's network namespace and accepts an address only when exactly
Expand All @@ -111,8 +56,23 @@ reselect a same-labelled container at invocation time. Binary names are
strictly validated, wrappers are installed atomically as regular mode-0700
files, and content, type, or permission drift is repaired. Older drivers that
do not yet contain a private bundle retain the existing shared-binary fallback.
The driver still owns its CNI data plane; Network Plugin Manager continues to
own only host NAT, forwarding, and host-port reconciliation.
The driver still owns its CNI data plane; Network Plugin Manager owns host
NAT, forwarding, host-port reconciliation, and materializing the CNI
configuration supplied by Metadata.

CNI configuration upgrades also reconcile the known historical IPsec file.
When current Metadata requests `10-pasturestack.conf` with the native bridge
and metadata IPAM contract, the manager validates and atomically writes all
desired configs before retiring an unrequested `10-rancher.conf` whose
network name, bridge type, and IPAM type exactly match the legacy platform
contract. Its unchanged contents remain in
`10-rancher.conf.pasturestack-retired`, outside the active `.conf`/`.json`
set. Rolling back to the exact legacy Metadata contract retires the known
native counterpart in the same way, so both configs cannot run together.
Legacy Metadata remains supported; unrelated administrator files remain
untouched. Malformed or ambiguous old files, symlinks, and conflicting backup
contents fail reconciliation explicitly. This is a bounded config migration,
not a claim that every host or firewall upgrade is safe.

The current preflight inspects already loaded legacy tables using an
independent iptables-legacy executable. Active old platform or Docker hooks
Expand Down Expand Up @@ -212,7 +172,7 @@ The Alpine 3.23 base image is digest-pinned. Direct runtime packages are exact-v
make test
make validate
bash scripts/check-build-downloads
VERSION_OVERRIDE=v0.8.21 IMAGE_NAMESPACE=local/pasturestack make package
VERSION_OVERRIDE=v0.8.22 IMAGE_NAMESPACE=local/pasturestack make package
```

Pull requests and `main` run one non-publishing gate: tests, vet/format checks, govulncheck, a reproducible binary build, one runtime image build, and Trivy scans plus CycloneDX SBOMs for the source, binary, and image. All reported vulnerabilities and secrets fail the gate. Publishing remains a separate, explicitly authorized operation.
Expand Down
6 changes: 3 additions & 3 deletions alpine-apk.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@
ALPINE_APK_BRANCH='3.23'

ALPINE_APK_BASH_VERSION='5.3.3-r1'
ALPINE_APK_CA_CERTIFICATES_VERSION='20260611-r0'
ALPINE_APK_CA_CERTIFICATES_VERSION='20260909-r0'
ALPINE_APK_CONNTRACK_TOOLS_VERSION='1.4.8-r0'
ALPINE_APK_CURL_VERSION='8.22.0-r0'
ALPINE_APK_GAWK_VERSION='5.3.2-r2'
ALPINE_APK_IPROUTE2_VERSION='6.17.0-r0'
ALPINE_APK_IPTABLES_VERSION='1.8.11-r1'
ALPINE_APK_IPTABLES_LEGACY_VERSION='1.8.11-r1'
ALPINE_APK_JQ_VERSION='1.8.2-r0'
ALPINE_APK_LIBCRYPTO3_VERSION='3.5.8-r0'
ALPINE_APK_LIBSSL3_VERSION='3.5.8-r0'
ALPINE_APK_LIBCRYPTO3_VERSION='3.5.9-r0'
ALPINE_APK_LIBSSL3_VERSION='3.5.9-r0'
ALPINE_APK_NET_TOOLS_VERSION='2.10-r3'
ALPINE_APK_NFTABLES_VERSION='1.1.5-r2'
ALPINE_APK_PROCPS_NG_VERSION='4.0.5-r0'
Expand Down
Loading
Loading