Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add script to wrap filesystem image in DDI #24

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,14 @@ In case you have an existing Torcx image you can convert it with the `convert_to
```

Please make also sure that your don't have a `containerd.service` drop in file under `/etc` that uses Torcx paths.


### Verity

To generate sysext protected by dm-verity with a signed root hash pass `FORMAT=verity` before invoking any of the scripts. This requires `systemd-repart` with a version >= v255. This also requires passing a path to a private key and certificate through `KEY` and `CERT`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A sentence on how these can be loaded would be good.

Suggested change
To generate sysext protected by dm-verity with a signed root hash pass `FORMAT=verity` before invoking any of the scripts. This requires `systemd-repart` with a version >= v255. This also requires passing a path to a private key and certificate through `KEY` and `CERT`.
To generate sysext protected by dm-verity with a signed root hash pass `FORMAT=verity` before invoking any of the scripts. This requires `systemd-repart` with a version >= v255. This also requires passing a path to a private key and certificate through `KEY` and `CERT`. To load the image, add the certificate file to `/etc/verity.d/`.


Here's an example:
```
openssl req -batch -new -x509 -sha256 -newkey rsa:2048 -nodes -out root_key.crt -keyout root_key.pem -days 3650
FORMAT=verity KEY=root_key.pem CERT=root_key.crt ./create_kubernetes_sysext.sh v1.27.3 k8s
```
29 changes: 24 additions & 5 deletions bake.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ FORMAT="${FORMAT:-squashfs}"
ARCH="${ARCH-}"
SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH-0}"
export SOURCE_DATE_EPOCH
KEY="${KEY-}"
CERT="${CERT-}"

die() {
echo >&2 "$@"
exit 1
}

# This script is to be called as helper by other scripts but can also be used standalone
if [ $# -lt 1 ]; then
Expand All @@ -22,12 +29,20 @@ elif [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
exit 1
fi

if [ "${FORMAT}" = "verity" ]; then
[ -z "${KEY}" ] && die "\$KEY required for verity"
[ -z "${CERT}" ] && die "\$CERT required for verity"
fi

SYSEXTNAME="$1"

if [ "${FORMAT}" != "squashfs" ] && [ "${FORMAT}" != "btrfs" ] && [ "${FORMAT}" != "ext4" ] && [ "${FORMAT}" != "ext2" ]; then
echo "Expected FORMAT=squashfs, FORMAT=btrfs, FORMAT=ext4, or FORMAT=ext2, got '${FORMAT}'" >&2
exit 1
fi
case ${FORMAT} in
squashfs) ;;
btrfs) ;;
ext4|ext2) ;;
verity) ;;
*) die "Unsupported format: '${FORMAT}'" ;;
esac

# Map to valid values for https://www.freedesktop.org/software/systemd/man/os-release.html#ARCHITECTURE=
if [ "${ARCH}" = "amd64" ] || [ "${ARCH}" = "x86_64" ]; then
Expand Down Expand Up @@ -57,7 +72,11 @@ elif [ "${FORMAT}" = "ext4" ] || [ "${FORMAT}" = "ext2" ]; then
# Note: We didn't chown to root:root, meaning that the file ownership is left as is
mkfs."${FORMAT}" -E root_owner=0:0 -d "${SYSEXTNAME}" "${SYSEXTNAME}".raw
resize2fs -M "${SYSEXTNAME}".raw
else
elif [ "${FORMAT}" = "squashfs" ]; then
mksquashfs "${SYSEXTNAME}" "${SYSEXTNAME}".raw -all-root
elif [ "${FORMAT}" = "verity" ]; then
systemd-repart --private-key="${KEY}" --certificate="${CERT}" --root="${SYSEXTNAME}" --no-pager --empty=create --size=auto --definitions=repart.d "${SYSEXTNAME}.raw"
Copy link
Member

@pothos pothos Sep 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assumes to be running in the script's folder, we need to add a cd or use an absolute path for --definitions=

else
die "Unsupported format: ${FORMAT}"
fi
echo "Created ${SYSEXTNAME}.raw"
7 changes: 7 additions & 0 deletions repart.d/01-root.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[Partition]
Type=root
CopyFiles=/:/
Format=squashfs
Minimize=best
Verity=data
VerityMatchKey=sysext
7 changes: 7 additions & 0 deletions repart.d/02-verity.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[Partition]
Type=root-verity
Verity=hash
VerityMatchKey=sysext
# Only works from v255
Minimize=best
SizeMinBytes=4K
4 changes: 4 additions & 0 deletions repart.d/03-verity-sig.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[Partition]
Type=root-verity-sig
Verity=signature
VerityMatchKey=sysext
70 changes: 70 additions & 0 deletions wrap-verity.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/bin/bash

set -e

data=$1

verity_hdr=$(veritysetup format $data ${data}.verity)
root_hash=$(echo $(awk -F: '/Root hash:/ { print $2 }' <<<$verity_hdr))

data_size=$(stat -c %s $data)
hash_size=$(stat -c %s ${data}.verity)
root_hash_front=${root_hash:0:32}
root_hash_back=${root_hash:32:32}

# 512-byte sectors
data_sectors=$(( $data_size >> 9 ))
hash_sectors=$(( $hash_size >> 9 ))
data_type=4f68bce3-e8cd-4db1-96e7-fbcaf984b709
hash_type=2c7357ed-ebd2-46d9-aec1-23d437ec2bf5

openssl req -batch -new -x509 -sha256 -newkey rsa:2048 -nodes -out root_key.crt -keyout root_key.pem -days 3650
echo -n "$root_hash" >${data}.roothash
openssl smime -sign -nocerts -noattr -binary -in "${data}.roothash" -inkey "root_key.pem" -signer "root_key.crt" -outform der -out "${data}.roothash.p7s"

cat <<EOF | tr -d '\n' >${data}.verity.sig
{"rootHash":"$root_hash","signature":"$(base64 -w 0 <${data}.roothash.p7s)"}
EOF
sig_size=$(stat -c %s ${data}.verity.sig)
# rounded up to 4096 bytes
sig_size=$(( ( $sig_size + 4095 ) / 4096 * 4096 ))
sig_sectors=$(( $sig_size >> 9 ))
sig_type=41092b05-9fc8-4523-994f-2def0408b176

# signature + GPT header + PMBR (?)
disk_size=$(( $data_size + $hash_size + 4096 + 2048 * 512 + 33 * 512))
rm -f disk.img
fallocate -l $disk_size disk.img

as_hex() {
str=$1
printf "%.8s-%.4s-%.4s-%.4s-%.12s" \
"${str:0:8}" "${str:8:4}" "${str:12:4}" \
"${str:16:4}" "${str:20:12}"
}
data_uuid=$(as_hex $root_hash_front)
hash_uuid=$(as_hex $root_hash_back)

cat <<EOF >sda.sfdisk
label: gpt
unit: sectors
sector-size: 512

/dev/sda1 : start=2048, size= ${data_sectors}, type=${data_type}, uuid=${data_uuid}
/dev/sda2 : start=$(( $data_sectors + 2048 )), size= ${hash_sectors}, type=${hash_type}, uuid=${hash_uuid}
/dev/sda3 : start=$(( ${hash_sectors} + $data_sectors + 2048 )), size= ${sig_sectors}, type=${sig_type}
EOF

sfdisk disk.img <sda.sfdisk

loop=$(sudo losetup --find --show disk.img)
sudo partx -u $loop
sudo dd bs=512 if=$data of=${loop}p1
sudo dd bs=512 if=${data}.verity of=${loop}p2
sudo dd bs=512 if=${data}.verity.sig of=${loop}p3
sudo losetup -d $loop

echo
echo "Finished!"
echo "Copy disk.img to /etc/extensions/$(basename $data)"
echo "Copy root_key.crt to /etc/verity.d/root_key.crt"