diff --git a/base/mkosi.skeleton/init b/base/mkosi.skeleton/init index b6f1256..b210f83 100755 --- a/base/mkosi.skeleton/init +++ b/base/mkosi.skeleton/init @@ -7,6 +7,7 @@ mount -t sysfs none /sys mount -t devtmpfs none /dev mount -t tmpfs none /run mount -t configfs none /sys/kernel/config +mount -t securityfs none /sys/kernel/security # Workaround to make pivot_root work # https://aconz2.github.io/2024/07/29/container-from-initramfs.html diff --git a/bob/bob.conf b/bob/bob.conf index a7d024a..88fbb42 100644 --- a/bob/bob.conf +++ b/bob/bob.conf @@ -28,6 +28,7 @@ Packages=podman openssh-sftp-server udev libsnappy1v5 + apparmor BuildPackages=build-essential git diff --git a/bob/kernel.config b/bob/kernel.config index 58b7808..c46a3c7 100644 --- a/bob/kernel.config +++ b/bob/kernel.config @@ -34,7 +34,17 @@ CONFIG_IP_NF_TARGET_REDIRECT=y CONFIG_IP_NF_MANGLE=y CONFIG_IP_NF_RAW=y CONFIG_NET_SCHED=y +CONFIG_SECURITY_APPARMOR=y +CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1 +CONFIG_DEFAULT_SECURITY_APPARMOR=y +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +CONFIG_AUDIT_GENERIC=y +CONFIG_SECURITY_PATH=y +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_LSM="landlock,lockdown,yama,apparmor,loadpin,safesetid,bpf" CONFIG_CRYPTO_USER_API_HASH=y CONFIG_CRYPTO_USER_API_SKCIPHER=y CONFIG_CRYPTO_USER_API_RNG=y -CONFIG_CRYPTO_USER_API_AEAD=y \ No newline at end of file +CONFIG_CRYPTO_USER_API_AEAD=y diff --git a/bob/mkosi.extra/etc/apparmor.d/searcher-container b/bob/mkosi.extra/etc/apparmor.d/searcher-container new file mode 100644 index 0000000..d8d4d22 --- /dev/null +++ b/bob/mkosi.extra/etc/apparmor.d/searcher-container @@ -0,0 +1,46 @@ +#include + +profile searcher-container flags=(attach_disconnected,mediate_deleted) { + #include + + network, + capability, + file, + umount, + + # Allow signals from privileged profiles and from within the same profile + signal (receive) peer=unconfined, + signal (send,receive) peer=searcher-container, + # Allow signals from podman/runc/crun + signal (receive) peer={/usr/bin/,/usr/sbin/,}{podman,runc,crun*}, + + deny @{PROC}/* w, # deny write for all files directly in /proc (not in a subdir) + # deny write to files not in /proc//** or /proc/sys/** + deny @{PROC}/{[^1-9],[^1-9][^0-9],[^1-9s][^0-9y][^0-9s],[^1-9][^0-9][^0-9][^0-9/]*}/** w, + deny @{PROC}/sys/[^k]** w, # deny /proc/sys except /proc/sys/k* (effectively /proc/sys/kernel) + deny @{PROC}/sys/kernel/{?,??,[^s][^h][^m]**} w, # deny everything except shm* in /proc/sys/kernel/ + deny @{PROC}/sysrq-trigger rwklx, + deny @{PROC}/kcore rwklx, + + deny mount, + + deny /sys/[^f]*/** wklx, + deny /sys/f[^s]*/** wklx, + deny /sys/fs/[^c]*/** wklx, + deny /sys/fs/c[^g]*/** wklx, + deny /sys/fs/cg[^r]*/** wklx, + deny /sys/firmware/** rwklx, + deny /sys/devices/virtual/powercap/** rwklx, + deny /sys/kernel/security/** rwklx, + + # suppress ptrace denials when using 'ps' inside a container + ptrace (trace,read,tracedby,readby) peer=searcher-container, + + # Additional rules for searcher-specific paths + /persistent/** rw, + /etc/searcher/** r, + /var/log/searcher/** w, + /var/log/lighthouse/** r, + /secrets/** r, + /tmp/jwt.hex r, +} diff --git a/bob/mkosi.extra/etc/systemd/system/searcher-container.service b/bob/mkosi.extra/etc/systemd/system/searcher-container.service index eccf0d0..f6c2c9f 100644 --- a/bob/mkosi.extra/etc/systemd/system/searcher-container.service +++ b/bob/mkosi.extra/etc/systemd/system/searcher-container.service @@ -1,7 +1,7 @@ [Unit] Description=Searcher SSH Container -After=dropbear.service searcher-firewall.service persistent-mount.service -Requires=dropbear.service searcher-firewall.service persistent-mount.service +After=dropbear.service searcher-firewall.service persistent-mount.service apparmor.service +Requires=dropbear.service searcher-firewall.service persistent-mount.service apparmor.service [Service] Type=oneshot diff --git a/bob/mkosi.extra/usr/bin/init-container.sh b/bob/mkosi.extra/usr/bin/init-container.sh index cc10cc7..f76c8f4 100755 --- a/bob/mkosi.extra/usr/bin/init-container.sh +++ b/bob/mkosi.extra/usr/bin/init-container.sh @@ -9,6 +9,9 @@ ENGINE_API_PORT=8551 EL_P2P_PORT=30303 SEARCHER_INPUT_CHANNEL=27017 +# Enabling apparmor profile +/usr/sbin/apparmor_parser -r /etc/apparmor.d/searcher-container + echo "Starting $NAME..." su -s /bin/sh searcher -c "cd ~ && podman run -d \ --name $NAME --replace \ diff --git a/bob/mkosi.postinst b/bob/mkosi.postinst index b7c85d0..40ead52 100755 --- a/bob/mkosi.postinst +++ b/bob/mkosi.postinst @@ -33,6 +33,7 @@ for service in \ fluent-bit.service \ wait-for-key.service \ searcher-firewall.service \ + apparmor.service \ dropbear.service \ lighthouse.service \ searcher-container.service \ @@ -43,6 +44,10 @@ do ln -sf "/etc/systemd/system/$service" "$BUILDROOT/etc/systemd/system/minimal.target.wants/" done +# Monkey-patch runc to add apparmorProfile to config.json on "create" +mv "$BUILDROOT/usr/bin/runc" "$BUILDROOT/usr/bin/runc.real" +install -m 755 $SRCDIR/bob/runc-apparmor.sh "$BUILDROOT/usr/bin/runc" + # Don't reserve port 22 mkosi-chroot systemctl disable ssh.service ssh.socket mkosi-chroot systemctl mask ssh.service ssh.socket diff --git a/bob/runc-apparmor.sh b/bob/runc-apparmor.sh new file mode 100755 index 0000000..68c880b --- /dev/null +++ b/bob/runc-apparmor.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +# Check if "create" appears anywhere in arguments +if echo "$@" | grep -q " create "; then + # Find bundle path (comes after --bundle) + BUNDLE=$(echo "$@" | sed -n 's/.*--bundle \([^ ]*\).*/\1/p') + + if [ -n "$BUNDLE" ] && [ -f "$BUNDLE/config.json" ]; then + # Add apparmorProfile right after '"process":{' + sed -i 's/"process":{"user":/"process":{"apparmorProfile":"searcher-container","user":/' "$BUNDLE/config.json" + fi +fi + +# Run real runc +exec /usr/bin/runc.real "$@"