Skip to content

Paguro v0.1.3

Latest

Choose a tag to compare

@github-actions github-actions released this 27 Oct 19:42
· 1 commit to main since this release

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 with enable_selinux = true and
    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 nodes paguro.dev/os=bottlerocket, and
    the chart runs the agent there as paguro-agent-bottlerocket with the
    SELinux type super_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's config.d and with
    Bottlerocket's second containerd; the bundle brings nsenter, ip,
    ss, cat, tee, rm and tar. 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 its clear_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_t may 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 CRIU GPL-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-id as 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 a containerd.service unit (k3s, RKE2). It took the
    first process named containerd for 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 *.service outside kubepods)
    that sees the host's root qualifies now. Not affected: hosts where
    containerd runs as containerd.service (kubeadm, EKS AL2023,
    Bottlerocket).
  • Known vulnerabilities: Go 1.26.10 for Paguro's binaries (GO-2026-6809
    in crypto/x509); crictl in the node installer is rebuilt from its
    v1.37.0 source with Go 1.26.10 and golang.org/x/net v0.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's clear_refs and to map
    executable memory as runtime_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-id taken 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