Repository navigation
v0.2.0
Pre-release
Pre-release
·
14 commits
to main
since this release
Immutable
release. Only release title and notes can be modified.
v0.1 watched and wrote things down. v0.2.0 is the first release that
acts. Audit mode is still the default and still changes nothing, so an
upgrade alone won't touch a single process. Set mode = "enforce" and
the tiers you've been reading about become real: a throttle-tier
incident is slowed down, and a quarantine-tier one is held in the
kernel, frozen and cut off from the network, where it waits until you
release it or kill it.
Added
- Enforce mode.
mode = "enforce"is no longer refused outright.
aegisd now refuses it only when the BPF LSM is missing from
/sys/kernel/security/lsmornftisn't installed, and points at the
modeline when it does. (#29, #30) - Throttle. At the throttle tier the process tree moves into
aegis-incident-<id>.scopeunderaegis-throttle.slice, limited by
the new[throttle]settings:cpu_quota_percent(25% of one CPU)
andmemory_high_mb(256 MiB). It keeps running, and keeps being
scored. (#29) - Quarantine. At the quarantine tier the tree's members are held in
the kernel, then moved intoaegis-incident-<id>-q.scopeunder
aegis-quarantine.slicewith any children aegisd finds under them in
/proc, frozen, and cut off by an nftables rule. A second walk after
the freeze attaches anything new. For 30 seconds after the decision,
each child the tree forks gets its own job: held and frozen under a
quarantine, moved into the scope under a throttle. Pid 1, kthreadd,
aegisd and the tree's ancestors are never touched. (#29) - Delegated incident scopes. Both incident scopes are started with
Delegate=yes, because systemd only lets a process join a running
scope that way. Their cgroups stay root-owned, so a tree that isn't
root gains nothing, and limits, freezing and kill still cover
everything below the scope. The end-to-end suite now fails any
enforce-mode scenario whose incident records a failed action. - The hold. Thirteen BPF LSM programs refuse a held process fork and
clone, connect, send, mount,bpf(), module loading, ptrace, writes
through any file descriptor, new user namespaces, and any signal to
aegisd. A process that isn't held costs one map lookup per hook.
Separately, in audit mode too, no other process can ptrace aegisd,
root included:strace -p,gdb -pand/proc/<pid>/memget
EPERM. Root can still stop it. (#26) aegisctl incidents releaseandkill. Release lifts a
quarantined tree's holds while it's still frozen, thaws it and
restores its network, or lifts a throttle's limits. Kill sends
SIGKILL to a quarantined tree, frozen or not. Both work from the
recorded actions, so they still work after a daemon restart and in
audit mode. After a reboot there's nothing left to release: either
one, on an incident from an earlier boot, touches nothing on the host
and records it as ended. (#30)- Actions on the record. Each incident now carries an
actions
list: what was done, to which pids, with the unit name or nft handle
needed to undo it, and any error. Verdicts gainthrottledand
quarantined, which an incident only reaches once the action worked.
Reaching one sends a record to telemetry with a reason starting
enforcement done:. Incidents written by v0.1 still load. (#28) - Webhooks.
[[telemetry.webhook]]posts JSON or a Slack message
each time an incident's verdict rises (would_throttle,throttled,
would_quarantine,quarantined), and on every enforcement failure,
including a job dropped because the enforcer's queue was full. They
fire in audit mode too. (#33) - OTLP metrics. Every 60 seconds aegisd sends its event, drop,
enforcement and telemetry counters, and its open incidents by
verdict, to<endpoint>/v1/metrics. (#34) - Signed releases. Releases are published with a cosign signature
overSHA256SUMS, build provenance attestations, and SPDX and
CycloneDX SBOMs. Installation
shows how to verify them. (#38)
Changed
- SELinux policy 0.2.0.
aegisd_tmay now runbusctl,
systemctlandnft, talk to systemd over D-Bus, and handnftto
its own domain. Each rule fixes a denial seen on Rocky 10 while a
throttle, a quarantine, a release and a kill ran. The unit gains
CAP_NET_ADMINandAF_NETLINKfornft, which makes six
capabilities. (#31) - Dependencies.
which8,toml1.1 andsha20.11. (#24)
Fixed
- A preloaded library could scrub
LD_PRELOADbefore the check.
v0.1 read/proc/<pid>/environa few milliseconds after each exec,
and that's the process's own memory. The environment is now read in
the kernel at exec, before any of the new image's code runs.
Processes that were already running when aegisd started still get
the/procread. (#25) - Uninstalling left systemd holding on. After
dnf remove,
aegis.slicestayed active and the removed unit stayed loaded. On
erase the package now reloads systemd, and stops the aegis slices and
deletes theinet aegistable when no incident scope is left. If any
tree aegisd moved is still there, released ones included, it keeps
all of that, warns you, and the
uninstall steps
say how to end it. - The end-to-end SELinux check never looked. Over ssh,
ausearch
read its stdin instead of the audit log and answered<no matches>
every time, so the suite's "no denials" result for v0.1 proved
nothing. It now reads the log and fails if it finds no events at all.
The suite also gains eight enforce-mode scenarios, all run on Rocky
10 with SELinux enforcing. (#49)
Security
- OTLP failures could log a credential. The first failed export
logged the HTTP client's error text, which can quote the request URL,
and a URL can carry a token. aegisd now logs the status code or the
kind of error instead, for OTLP and webhooks alike. (#33)
Known limits
- The hold starts when aegisd writes the process into the kernel's
map, not when the score crosses the line, so a few milliseconds of
activity can land first. - Writes made before the hold, including through a shared memory
mapping, reach the disk. The overlay that would catch them arrives in
v0.4.0. - Holds don't survive an aegisd restart. The freeze and the network
rule do. - A child aegisd finds in
/procbut never saw fork is frozen and cut
off, not held, so it can act until the freeze. If the enforcer falls
more than 30 seconds behind, children a throttled tree starts in that
time can stay outside its limits. - If the move into the quarantine scope fails, aegisd doesn't retry it.
The tree stays held but not frozen, atwould_quarantine. A restart
doesn't retry the move either, and it lifts the holds, so after one
the tree runs free until you kill or release it. systemctl reload nftables, or any full ruleset flush, deletes the
inet aegistable and with it every quarantined tree's drop rule.
They stay frozen. After that, rule handles can be reused
within the boot, so release affected incidents one at a time. A fix
that puts the table back is planned for v0.2.1.- A frozen process looks frozen to anything that inspects it, and a
released one stays underaegis-quarantine.slice. - An environment longer than 32 KiB counts as unreadable, so the
process gets no allowlist credit. - The quarantined tree's traffic is dropped, not answered. The honeypot,
and the nftables redirection that feeds it, are planned for v0.3.0.
The full list is in the
threat model.