Repository navigation
Bottlerocket and EKS Auto Mode with nothing to set up (beta), SELinux with
a label per pod, and a new license: Apache-2.0.
Added:
- SELinux on nodes whose container runtime labels every pod with
categories of its own (containerd withenable_selinux = trueand
container-selinux, as on RHEL and Bottlerocket). Before, the first
pre-dump was denied – CRIU, built without libselinux, could not label
its parasite's socket – and the migration rolled back. Now CRIU is built
with libselinux; its work directories and logs carry the container's
file label; restored processes and mounts get the replacement's labels
(--lsm-profile,--lsm-mount-context); files restored into volumes
take the volume's label on the target node instead of the source's.
Tested on EKS 1.37, Amazon Linux 2023, SELinux enforcing: freeze
381/408 ms, the replacement with categories of its own, no denial.
Enforcing without labelling (the AMI's containerd configuration) and
permissive (its default) worked before and still do. - Bottlerocket (beta), with nothing to set up: the same
helm install. The
controller labels Bottlerocket nodespaguro.dev/os=bottlerocket, and
the chart runs the agent there aspaguro-agent-bottlerocketwith the
SELinux typesuper_t(Bottlerocket starts privileged containers as
control_t, which may not prepare the node). The node installer works
with a read-only root (paguro-runc and its tools in/opt/paguro),
without a host shell, with containerd'sconfig.dand with
Bottlerocket's second containerd; the bundle bringsnsenter,ip,
ss,cat,tee,rmandtar. Checkpoints run in the runtime's SELinux
context (runtime_t, through a transient systemd unit), where CRIU's
parasite may hand over the pod's memory. Three CRIU patches, no-ops
elsewhere: the pod's process clears its own soft-dirty bits (no other
domain may write itsclear_refs); tmpfs contents are archived as plain
tar (GNU tar starts gzip through/bin/sh, which Bottlerocket's shell
refuses; Paguro compresses its transfers anyway, and gzip ran inside the
freeze); restored memory becomes executable only in the pod's domain
(runtime_tmay never map memory writable and executable). Tested on
EKS 1.37 with Bottlerocket 1.67.0: four migrations of a pod with state
in memory, emptyDir and root filesystem (freeze 366–459 ms) and two of a
JVM with JIT-compiled code, each with SELinux categories of its own on
the target. With clients in Phantom mode (2026-10-27, EKS cluster with
two Bottlerocket and two AL2023 nodes): a UDP game server and a TCP
echo server, each moved back and forth; players through the ClusterIP
and a NodePort kept their sessions (36–48 of 3000 inputs lost, within
the freeze), no new TCP connection through the ClusterIP failed, the
long-lived connection survived – as on AL2023. A rebooted node gets its
handler again from the agent (one containerd restart) and takes and
gives migrations; an EBS volume moves with the pod;helm uninstall
and the documented node cleanup leave the node as it was. - EKS Auto Mode (beta): its nodes are Bottlerocket, and Paguro runs there
the same way, nothing to set up. Three migrations, freeze 315–406 ms. - In clusters with Bottlerocket and other nodes, pods move only between
nodes of the same kind: a checkpoint does not restore across them
(tried on EKS: CRIU fails on SELinux contexts one side does not know and
on the containers' mounts, and the replacement cold-starts). Placement
never picks such a target; an explicit target is refused.
Changed:
- License: Apache-2.0 instead of AGPL-3.0-only – Paguro may now be built
into other products, proprietary ones included, as long as the license
and the notices (NOTICE) go with it. Releases up to and including 0.1.2
stay under AGPL-3.0-only. The eBPF program of Phantom mode keeps
GPL-2.0-only OR BSD-2-Clause, the patches to CRIUGPL-2.0-only. - The chart's controller may patch nodes – only the label
paguro.dev/os,
held to that by an admission policy (agent.restrictionPolicy.enabled;
checked on Kubernetes 1.30–1.37). - tmpfs contents in a checkpoint are plain tar instead of gzip'ed tar:
gzip ran inside the freeze, and Paguro compresses what it transfers
anyway.
Fixed:
- Security: a user who may create pods could take over a node
(releases 0.1.0–0.1.2). paguro-runc took the pod annotation
paguro.dev/restore-idas a directory name: with../in it and
runtimeClassName: paguro, a pod made paguro-runc – root on the node –
restore a checkpoint from a directory the pod controlled (its own
emptyDir), or claim another namespace's waiting checkpoint. Now the
annotation must be a migration UID, a waiting checkpoint is restored
only into a pod of the migration's namespace (recorded by the target
agent), the webhook admits new pods carrying the annotation only from
Paguro's controller, and an admission policy keeps anyone from adding
or changing it on an existing pod. Found in an internal review; tried
on EKS: the attempts are refused by the webhook, the policy and – with
both bypassed – by paguro-runc on the node. - Security: the node installer could run a pod's program as root
(releases 0.1.0–0.1.2) on
hosts without acontainerd.serviceunit (k3s, RKE2). It took the
first process namedcontainerdfor the node's containerd and ran
programs from that process's PATH and binary; a pod can name a process
so. Only a system service (its cgroup a*.serviceoutsidekubepods)
that sees the host's root qualifies now. Not affected: hosts where
containerd runs ascontainerd.service(kubeadm, EKS AL2023,
Bottlerocket). - Known vulnerabilities: Go 1.26.10 for Paguro's binaries (GO-2026-6809
incrypto/x509); crictl in the node installer is rebuilt from its
v1.37.0 source with Go 1.26.10 andgolang.org/x/netv0.60.0 – the
release binary carries net/http and x/net vulnerabilities its code
reaches (govulncheck).
Known limitations:
- An RWO EBS volume moves inside the freeze: measured 17–24 s on AL2023
and 25–45 s on Bottlerocket (detach and attach). io2 Multi-Attach
takes the attach out of the freeze. - Bottlerocket: every migration logs two expected SELinux denials –
CRIU's first attempt to write the pod'sclear_refsand to map
executable memory asruntime_t, before it takes the way the policy
allows. Security tooling may report them. - Pods do not move between Bottlerocket and other nodes (above).
Security advisories
- GHSA-jj9m-449r-pxjj (critical): node takeover by a user who can create pods –
paguro.dev/restore-idtaken as a path. Affects 0.1.0–0.1.2. - GHSA-vj5j-q9v9-4c9r (high): node installer could run a pod's program as root on hosts without
containerd.service(k3s, RKE2). Affects 0.1.0–0.1.2.
Upgrade: helm upgrade paguro oci://ghcr.io/dpicillo/charts/paguro --version 0.1.3 -n paguro-system