2
0
mirror of https://github.com/xcat2/confluent.git synced 2026-11-12 11:06:17 +00:00
Files
confluent/confluent_osdeploy/el10-diskless/profiles/default/scripts/imageboot.sh
T
Markus Hilger 63cdb6b2ed Label untethered diskless roots for SELinux
On an untethered root, files the initramfs writes before policy load
and sockets that unsquashfs creates without attributes have no label.
Label every inode without one, as the upper layer is in tethered mode.
2026-10-30 15:53:03 +01:00

243 lines
11 KiB
Bash

. /lib/dracut-lib.sh
confluent_whost=$confluent_mgr
if [[ "$confluent_whost" == *:* ]] && [[ "$confluent_whost" != "["* ]]; then
confluent_whost="[$confluent_mgr]"
fi
mkdir -p /mnt/remoteimg /mnt/remote /mnt/overlay /sysroot
imagemethod=$(getarg confluent_imagemethod)
if grep installtodisk /proc/cmdline > /dev/null; then
# installimage copies from the mounted image, which an untethered or
# uncompressed boot would extract to RAM and unmount first
imagemethod=tethered
fi
set_selinux_context system_u:object_r:bin_t:s0 /opt/confluent/bin/urlmount
if [ "untethered" = "$imagemethod" -o "uncompressed" = "$imagemethod" ]; then
mount -t tmpfs untethered /mnt/remoteimg
while ! curl -f https://$confluent_whost/confluent-public/os/$confluent_profile/rootimg.sfs -o /mnt/remoteimg/rootimg.sfs; do
echo "Failed downloading image, retrying..."
sleep $((RANDOM%3)).$((RANDOM))
done
else
confluent_urls="$confluent_urls https://$confluent_whost/confluent-public/os/$confluent_profile/rootimg.sfs"
/opt/confluent/bin/urlmount $confluent_urls /mnt/remoteimg
fi
/opt/confluent/bin/confluent_imginfo /mnt/remoteimg/rootimg.sfs > /tmp/rootimg.info
loopdev=$(losetup -f)
export mountsrc=$loopdev
losetup -r $loopdev /mnt/remoteimg/rootimg.sfs
if grep '^Format: confluent_crypted' /tmp/rootimg.info > /dev/null; then
while ! curl -sf -H "CONFLUENT_NODENAME: $nodename" -H "CONFLUENT_APIKEY: $(cat /etc/confluent/confluent.apikey)" https://$confluent_whost/confluent-api/self/profileprivate/pending/rootimg.key > /tmp/rootimg.key; do
echo "Unable to retrieve private key from $confluent_mgr (verify that confluent can access /var/lib/confluent/private/os/$confluent_profile/pending/rootimg.key)"
sleep 1
done
cipher=$(head -n 1 /tmp/rootimg.key)
key=$(tail -n 1 /tmp/rootimg.key)
len=$(wc -c /mnt/remoteimg/rootimg.sfs | awk '{print $1}')
len=$(((len-4096)/512))
dmsetup create cryptimg --table "0 $len crypt $cipher $key 0 $loopdev 8"
/opt/confluent/bin/confluent_imginfo /dev/mapper/cryptimg > /tmp/rootimg.info
mountsrc=/dev/mapper/cryptimg
fi
rootimgformat=$(awk -F': ' '/^Format:/ {print $2; exit}' /tmp/rootimg.info)
if [ "$rootimgformat" = squashfs ]; then
mount -o ro $mountsrc /mnt/remote
elif [ "$rootimgformat" = confluent_multisquash ]; then
tail -n +3 /tmp/rootimg.info | awk '{gsub("/", "_"); print "echo 0 " $4 " linear '$mountsrc' " $3 " | dmsetup create mproot" $7}' > /tmp/setupmount.sh
. /tmp/setupmount.sh
cat /tmp/setupmount.sh |awk '{printf "mount /dev/mapper/"$NF" "; sub("mproot", ""); gsub("_", "/"); print "/mnt/remote"$NF}' > /tmp/mountparts.sh
. /tmp/mountparts.sh
fi
#mount -t tmpfs overlay /mnt/overlay
if [ ! "uncompressed" = "$imagemethod" ]; then
modprobe zram
memtot=$(grep ^MemTotal: /proc/meminfo|awk '{print $2}')
memtot=$((memtot/2))$(grep ^MemTotal: /proc/meminfo | awk '{print $3'})
echo $memtot > /sys/block/zram0/disksize
mkfs.xfs /dev/zram0 > /dev/null
fi
TETHERED=0
if [ "untethered" = "$imagemethod" -o "uncompressed" = "$imagemethod" ]; then
if [ "untethered" = "$imagemethod" ]; then
mount -o discard /dev/zram0 /sysroot
else
mount -t tmpfs disklessroot /sysroot
fi
extract_untethered_rootimg
else
TETHERED=1
mount -o discard /dev/zram0 /mnt/overlay
if [ ! -f /tmp/mountparts.sh ]; then
mkdir -p /mnt/overlay/upper /mnt/overlay/work
mount -t overlay -o upperdir=/mnt/overlay/upper,workdir=/mnt/overlay/work,lowerdir=/mnt/remote disklessroot /sysroot
else
for srcmount in $(cat /tmp/mountparts.sh | awk '{print $3}'); do
mkdir -p /mnt/overlay${srcmount}/upper /mnt/overlay${srcmount}/work
mount -t overlay -o upperdir=/mnt/overlay${srcmount}/upper,workdir=/mnt/overlay${srcmount}/work,lowerdir=${srcmount} disklesspart /sysroot${srcmount#/mnt/remote}
done
fi
fi
mkdir -p /sysroot/etc/ssh
mkdir -p /sysroot/etc/confluent
mkdir -p /sysroot/root/.ssh
cp /root/.ssh/* /sysroot/root/.ssh
chmod 700 /sysroot/root/.ssh
cp /etc/confluent/* /sysroot/etc/confluent/
cp /etc/ssh/*key* /sysroot/etc/ssh/
for pubkey in /etc/ssh/ssh_host*key.pub; do
certfile=${pubkey/.pub/-cert.pub}
privfile=${pubkey%.pub}
if [ -s $certfile ]; then
echo HostCertificate $certfile >> /sysroot/etc/ssh/sshd_config
fi
echo HostKey $privfile >> /sysroot/etc/ssh/sshd_config
done
mkdir -p /sysroot/dev /sysroot/sys /sysroot/proc /sysroot/run
if [ ! -z "$autocons" ]; then
autocons=${autocons%,*}
mkdir -p /run/systemd/generator/getty.target.wants
ln -s /usr/lib/systemd/system/serial-getty@.service /run/systemd/generator/getty.target.wants/serial-getty@${autocons}.service
fi
while [ ! -e /sysroot/sbin/init ]; do
echo "Failed to access root filesystem or it is missing /sbin/init"
echo "System should be accessible through ssh at port 2222 with the appropriate key"
while [ ! -e /sysroot/sbin/init ]; do
sleep 1
done
done
rootpassword=$(grep ^rootpassword: /etc/confluent/confluent.deploycfg)
rootpassword=${rootpassword#rootpassword: }
if [ "$rootpassword" = "null" ]; then
rootpassword=""
fi
if [ ! -z "$rootpassword" ]; then
sed -i "s@root:[^:]*:@root:$rootpassword:@" /sysroot/etc/shadow
fi
for i in /ssh/*.ca; do
echo '@cert-authority *' $(cat $i) >> /sysroot/etc/ssh/ssh_known_hosts
done
echo HostbasedAuthentication yes >> /sysroot/etc/ssh/sshd_config
echo HostbasedUsesNameFromPacketOnly yes >> /sysroot/etc/ssh/sshd_config
echo IgnoreRhosts no >> /sysroot/etc/ssh/sshd_config
sshconf=/sysroot/etc/ssh/ssh_config
if [ -d /sysroot/etc/ssh/ssh_config.d/ ]; then
sshconf=/sysroot/etc/ssh/ssh_config.d/01-confluent.conf
fi
echo 'Host *' >> $sshconf
echo ' HostbasedAuthentication yes' >> $sshconf
echo ' EnableSSHKeysign yes' >> $sshconf
echo ' HostbasedKeyTypes *ed25519*' >> $sshconf
curl -sf -H "CONFLUENT_NODENAME: $nodename" -H "CONFLUENT_APIKEY: $(cat /etc/confluent/confluent.apikey)" https://$confluent_whost/confluent-api/self/nodelist > /sysroot/etc/ssh/shosts.equiv
cp /sysroot/etc/ssh/shosts.equiv /sysroot/root/.shosts
chmod 600 /sysroot/etc/ssh/*_key
cp /tls/*.pem /sysroot/etc/pki/ca-trust/source/anchors/
chroot /sysroot/ update-ca-trust
curl -sf https://$confluent_whost/confluent-public/os/$confluent_profile/scripts/onboot.service > /sysroot/etc/systemd/system/onboot.service
mkdir -p /sysroot/opt/confluent/bin
curl -sf https://$confluent_whost/confluent-public/os/$confluent_profile/scripts/onboot.sh > /sysroot/opt/confluent/bin/onboot.sh
chmod +x /sysroot/opt/confluent/bin/onboot.sh
cp /opt/confluent/bin/apiclient /sysroot/opt/confluent/bin
set_selinux_context system_u:object_r:systemd_unit_file_t:s0 /sysroot/etc/systemd/system/onboot.service
set_selinux_context system_u:object_r:bin_t:s0 /sysroot/opt/confluent/bin/onboot.sh
set_selinux_context system_u:object_r:bin_t:s0 /sysroot/opt/confluent/bin/apiclient
ln -s /etc/systemd/system/onboot.service /sysroot/etc/systemd/system/multi-user.target.wants/onboot.service
cp /etc/confluent/functions /sysroot/etc/confluent/functions
if [ -x /sysroot/usr/sbin/matchpathcon ] && grep -Eq '^SELINUX=(enforcing|permissive)' /sysroot/etc/selinux/config 2> /dev/null; then
# Files written to /sysroot before policy load are unlabeled.
selinuxpolicy=$(sed -n 's/^SELINUXTYPE=//p' /sysroot/etc/selinux/config)
fcontexts=/etc/selinux/$selinuxpolicy/contexts/files/file_contexts
if [ $TETHERED -eq 1 ]; then
# Label only the upper layer, using globstar since the initramfs has no find.
shopt -s globstar dotglob nullglob
relabel=()
if [ -f /tmp/mountparts.sh ]; then
overlayparts=$(awk '{print $3}' /tmp/mountparts.sh)
else
overlayparts=/mnt/remote
fi
for srcmount in $overlayparts; do
upperdir=/mnt/overlay/upper
if [ -f /tmp/mountparts.sh ]; then
upperdir=/mnt/overlay${srcmount}/upper
fi
prefix=${srcmount#/mnt/remote}
prefix=${prefix%/}
relabel+=("${prefix:-/}")
for relpath in "$upperdir"/**; do
relabel+=("$prefix${relpath#$upperdir}")
done
done
shopt -u globstar dotglob nullglob
# Not setfiles (recurses into the image) or restorecon (no-op before policy load).
chroot /sysroot /usr/sbin/matchpathcon -f $fcontexts "${relabel[@]}" | while IFS=$'\t' read -r relpath context; do
if [ "$context" != "<<none>>" ]; then
chcon -h "$context" "/sysroot$relpath"
fi
done
elif [ -x /sysroot/usr/bin/python3 ] && [ -x /sysroot/usr/sbin/setfiles ]; then
# The root is a local copy: label every inode without a label, which
# also covers sockets that unsquashfs creates without attributes.
# setfiles only recurses into directories that are new here.
chroot /sysroot /usr/bin/python3 -c '
import errno, os, sys
out = sys.stdout.buffer
rootdev = os.lstat(b"/").st_dev
def check(path):
try:
os.getxattr(path, b"security.selinux", follow_symlinks=False)
except OSError as e:
if e.errno == errno.ENODATA:
out.write(path + b"\0")
check(b"/")
for root, dirs, files in os.walk(b"/"):
for name in dirs + files:
check(os.path.join(root, name))
dirs[:] = [d for d in dirs if os.lstat(os.path.join(root, d)).st_dev == rootdev]
' | chroot /sysroot /usr/sbin/setfiles -0 -F -f - $fcontexts
relabelstatus=("${PIPESTATUS[@]}")
if [ "${relabelstatus[0]}" != 0 ] || [ "${relabelstatus[1]}" != 0 ]; then
echo "Warning: SELinux labeling of the root filesystem failed"
fi
else
echo "Warning: python3 or setfiles missing in the image, files written at boot stay unlabeled"
fi
fi
if grep installtodisk /proc/cmdline > /dev/null; then
. /etc/confluent/functions
run_remote installimage
exec reboot -f
fi
mv /lib/modules/$(uname -r) /lib/modules/$(uname -r)-ramfs
ln -s /sysroot/lib/modules/$(uname -r) /lib/modules/
if [ -d /lib/firmware ]; then
mv /lib/firmware /lib/firmware-ramfs
fi
ln -s /sysroot/lib/firmware /lib/firmware
kill $(grep -l ^/usr/lib/systemd/systemd-udevd /proc/*/cmdline|cut -d/ -f 3)
if [ $TETHERED -eq 1 ]; then
(
sleep 86400 &
ONBOOTPID=$!
mkdir -p /run/confluent
echo $ONBOOTPID > /run/confluent/onboot_sleep.pid
wait $ONBOOTPID
dd if=/mnt/remoteimg/rootimg.sfs iflag=nocache count=0 >& /dev/null
rm -rf /lib/modules/$(uname -r) /lib/modules/$(uname -r)-ramfs /lib/firmware-ramfs /usr/lib64/libcrypto.so* /usr/lib64/systemd/ /kernel/ /usr/bin/ /usr/sbin/ /usr/libexec/
) &
while [ ! -f /run/confluent/onboot_sleep.pid ]; do
sleep 0.1
done
else
rm -rf /lib/modules/$(uname -r) /lib/modules/$(uname -r)-ramfs /lib/firmware-ramfs /usr/lib64/libcrypto.so* /usr/lib64/systemd/ /kernel/ /usr/bin/ /usr/sbin/ /usr/libexec/
fi
set_selinux_context system_u:object_r:root_t:s0 /sysroot
if grep debugssh /proc/cmdline >& /dev/null; then
exec /opt/confluent/bin/start_root
else
exec /opt/confluent/bin/start_root -s # share mount namespace, keep kernel callbacks intact
fi