Skip to content

Commit 507a7fa

Browse files
committed
fix(audit): apply 2026-05-05 audit findings (LAW3/LAW6/security/supply-chain)
Implements the remediation set captured in AUDIT-FINDINGS-20260505.md. Architectural laws: - LAW 3 (BOUND-IMAGES): add usr/lib/bootc/bound-images.d/ symlinks for mios-forgejo-runner, mios-forge, mios-cockpit-link (mode 120000). Fixes 3-of-12 Quadlets that had no deploy-time image binding. - LAW 6 (UNPRIVILEGED-QUADLETS): document the mios-forgejo-runner root-uid exception in INDEX.md sec 3 row 6 and the Quadlet header. The runner needs uid=0 to drive `podman build -f /Containerfile` against rootful storage and produce an image consumable by `bootc switch --transport containers-storage`. Security posture: - fapolicyd: tighten the uid=0 catch-all to `trust=1` so RPM-signed binaries (every system service) stay unblocked while ad-hoc uid=0-owned binaries dropped under /tmp, /var, /home are denied. Restores the deny-by-default posture documented in README.md. - kargs.d: drop lockdown=confidentiality from 01-mios-hardening.toml. bootc kargs.d is additive across files; the previous form put both `confidentiality` and `integrity` on the kernel command line. 30-security.toml's intent (integrity, NVIDIA-MOK-safe) is now the sole declared value. Supply chain integrity: - Pin every Quadlet Image= ref to a digest. Switches the deploy surface from floating tags to deterministic pulls; Renovate remains the path to digest bumps. - mios-ceph: :latest -> :v18@sha256:... (the value the file's own header comment claims and the only valid Reef tag on quay.io/ceph/ceph; :latest does not exist upstream). - mios-forgejo-runner: :6.5 -> :6@sha256:... (:6.5 does not exist on code.forgejo.org; only the floating :6 line is published). Hygiene: - automation/10-gnome.sh comment: install_weakdeps -> install_weak_deps. - automation/19-k3s-selinux.sh: cp -p for re-run idempotency. - mios-gpu-pv-detect / mios-sriov-init / mios-verify Description=: bare 'MiOS-OS' -> project-wide quoted 'MiOS' form.
1 parent d384a69 commit 507a7fa

23 files changed

Lines changed: 50 additions & 20 deletions

INDEX.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ their resource cost.
6666
| 3 | **BOUND-IMAGES** -- every Quadlet image symlinked into `/usr/lib/bootc/bound-images.d/`. Binder loop: `automation/08-system-files-overlay.sh:74-86`. | `usr/lib/bootc/bound-images.d/` |
6767
| 4 | **BOOTC-CONTAINER-LINT** -- final RUN of `Containerfile`. | `Containerfile` (last `RUN`) |
6868
| 5 | **UNIFIED-AI-REDIRECTS** -- every OpenAI-API-shaped client resolves through one canonical surface: `MIOS_AI_ENDPOINT` (default `http://localhost:8080/v1`, the OpenAI-SDK `base_url` slot), `MIOS_AI_MODEL` (default model id), `MIOS_AI_KEY` (api key, empty for the local proxy). No vendor-hardcoded URLs. | `/etc/profile.d/mios-env.sh`, `usr/bin/mios`, `usr/bin/mios-env`, `etc/mios/ai/` |
69-
| 6 | **UNPRIVILEGED-QUADLETS** -- every Quadlet declares `User=`, `Group=`, `Delegate=yes`. Documented exceptions: `mios-ceph` and `mios-k3s` declare `User=root`/`Group=root` because Ceph/K3s require uid 0 (see file headers). | `etc/containers/systemd/`, `usr/share/containers/systemd/` |
69+
| 6 | **UNPRIVILEGED-QUADLETS** -- every Quadlet declares `User=`, `Group=`, `Delegate=yes`. Documented exceptions: `mios-ceph` and `mios-k3s` declare `User=root`/`Group=root` because Ceph/K3s require uid 0 (see file headers); `mios-forgejo-runner` declares `User=0`/`Group=0` because the closed self-replication loop runs `podman build -f /Containerfile` on every push, which requires write access to rootful `/var/lib/containers/storage/` and `bootc switch` permissions on the resulting image (see file header for the loop). | `etc/containers/systemd/`, `usr/share/containers/systemd/` |
7070

7171
## 4. Profile + environment resolution
7272

automation/10-gnome.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# 'MiOS' v0.2.4 -- 10-gnome: GNOME 50 desktop -- PURE BUILD-UP
33
#
44
# STRATEGY: ucore has ZERO GNOME packages. We install exactly what we need.
5-
# With install_weakdeps=False (set globally in 01-repos.sh), only hard deps
5+
# With install_weak_deps=False (set globally in 01-repos.sh), only hard deps
66
# get pulled in. This means:
77
# - malcontent-libs comes in (gnome-control-center hard dep) -- CORRECT
88
# - malcontent-control/pam/tools do NOT come in (weak deps) -- CORRECT

automation/19-k3s-selinux.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ if [ -z "$POLICY_DIR" ]; then
5050
fi
5151

5252
echo "Using policy source from: $POLICY_DIR"
53-
cp "$POLICY_DIR"/k3s.* .
53+
cp -p "$POLICY_DIR"/k3s.* .
5454

5555
# Compile the policy using the Fedora 44 SELinux Makefile
5656
make -f /usr/share/selinux/devel/Makefile k3s.pp

etc/containers/systemd/mios-ai.container

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Wants=network-online.target
1212
ConditionPathIsDirectory=/etc/mios/ai
1313

1414
[Container]
15-
Image=docker.io/localai/localai:latest
15+
Image=docker.io/localai/localai:latest@sha256:a6af99e17a73a92caa134e70ae84492cc47b67645c1676268a7522ad14f4c09d
1616
ContainerName=mios-ai
1717
# Single MiOS internal network so sibling Quadlets (mios-forge,
1818
# mios-aichat, mios-mcp, ollama, etc.) reach LocalAI by container name

etc/containers/systemd/mios-ceph.container

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ ConditionPathExists=/etc/ceph/ceph.conf
1818
ConditionVirtualization=!container
1919

2020
[Container]
21-
Image=quay.io/ceph/ceph:latest
21+
Image=quay.io/ceph/ceph:v18@sha256:69cbef90eb58cf96e572e7497227a2bcb0ec9175bc2247809c0a37857db9b820
2222
ContainerName=mios-ceph
2323
Network=mios.network
2424
Volume=/var/lib/ceph:/var/lib/ceph:Z

etc/containers/systemd/mios-cockpit-link.container

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ ConditionVirtualization=!wsl
4141
ConditionVirtualization=!container
4242

4343
[Container]
44-
Image=docker.io/alpine/socat:latest
44+
Image=docker.io/alpine/socat:latest@sha256:44e7b87dfeddb0f999ce75eedfa140dc97ea5bf7decbd04b2cef6adb5cc331fe
4545
ContainerName=mios-cockpit-link
4646
# Single MiOS internal network -- KISS, every Quadlet on the same
4747
# bridge so sibling lookups by container name work without host-

etc/containers/systemd/mios-forge.container

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ ConditionVirtualization=|!container
2626
ConditionVirtualization=|wsl
2727

2828
[Container]
29-
Image=codeberg.org/forgejo/forgejo:11
29+
Image=codeberg.org/forgejo/forgejo:11@sha256:1d5f7d9e7ec970b50d5817317c3ec86d4aabb10893c5dea2e9dd4f8c3470a09c
3030
ContainerName=mios-forge
3131
Network=mios.network
3232
# 3000 = web UI (reverse-proxy via Cockpit/Caddy if desired).

etc/containers/systemd/mios-forgejo-runner.container

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,16 @@
2020
# token file -- if firstboot hasn't minted it yet (or has been deleted
2121
# for re-bootstrap), the unit no-ops at pre-boot rather than crash-
2222
# looping with "registration token missing".
23+
#
24+
# LAW 6 (UNPRIVILEGED-QUADLETS) exception: this Quadlet runs `User=0`
25+
# / `Group=0` because the build step in the self-replication loop
26+
# (`podman build -f /Containerfile`) needs write access to rootful
27+
# `/var/lib/containers/storage/` and the resulting image must be
28+
# usable by `bootc switch --transport containers-storage`. Rootless
29+
# podman would require subuid/subgid mappings against /var/lib/mios/
30+
# forge-runner with allowed write into the rootful storage path,
31+
# which the bootc immutable-/usr model does not currently support.
32+
# Documented in INDEX.md sec 3 row 6 alongside mios-ceph / mios-k3s.
2333

2434
[Unit]
2535
Description='MiOS' Forgejo Runner (self-hosted CI for /=git working tree)
@@ -35,7 +45,7 @@ ConditionVirtualization=|!container
3545
ConditionVirtualization=|wsl
3646

3747
[Container]
38-
Image=code.forgejo.org/forgejo/runner:6.5
48+
Image=code.forgejo.org/forgejo/runner:6@sha256:e8dd2880f2fc81984d2308b93f1bc064dfb41187942300676536c09a3b30043d
3949
ContainerName=mios-forgejo-runner
4050
Network=mios.network
4151

etc/containers/systemd/mios-k3s.container

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ ConditionVirtualization=!wsl
2424
ConditionVirtualization=!container
2525

2626
[Container]
27-
Image=docker.io/rancher/k3s:latest
27+
Image=docker.io/rancher/k3s:latest@sha256:5e0707cfd1239b358ef73f3254bc3eadc027dd30cd5ec6ca41e29e47652a1b8c
2828
ContainerName=mios-k3s
2929
Privileged=true
3030
Environment=K3S_TOKEN=mios-cluster-secret

etc/fapolicyd/fapolicyd.rules

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,17 @@
1-
allow perm=any uid=0 : all
1+
# Architectural Law: README.md/SECURITY.md document fapolicyd as
2+
# "deny-by-default". The previous form (`allow perm=any uid=0 : all`)
3+
# unconditionally bypassed the policy for every root process, which on a
4+
# bootc host with `/usr` mounted read-only via composefs is functionally
5+
# equivalent to "deny-by-default for non-root only". Constraining root to
6+
# `trust=1` keeps RPM-signed binaries fully unblocked (every system
7+
# service: systemd, podman, libvirt, k3s, ceph, ...) while denying
8+
# execution of arbitrary uid=0-owned scripts dropped under /tmp, /var,
9+
# or /home -- the actual escalation path that "deny-by-default" is meant
10+
# to close. If a legitimate root-executed binary is missing from the
11+
# RPM trust db, add a targeted `allow perm=execute path=/exact/path
12+
# uid=0 : all` rule above this block rather than re-broadening the
13+
# uid=0 catch-all.
14+
allow perm=any uid=0 trust=1 : all
215
allow perm=execute : ftype=application/x-executable trust=1
316
allow perm=execute : ftype=application/x-sharedlib trust=1
417
deny_audit perm=execute : all

0 commit comments

Comments
 (0)