Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@ SRC_URI += " \
file://balena-supervisor-healthcheck \
file://tmpfiles-supervisor.conf \
file://migrate-supervisor-state.service \
file://balena-supervisor-security-status.service \
"

SYSTEMD_SERVICE:${PN} = " \
balena-supervisor.service \
update-balena-supervisor.service \
update-balena-supervisor.timer \
migrate-supervisor-state.service \
balena-supervisor-security-status \
"

FILES:${PN} += " \
Expand All @@ -48,6 +50,9 @@ RDEPENDS:${PN} = " \
balena-config-vars \
systemd \
os-helpers-api \
os-helpers-supervisor \
os-helpers-fs \
os-helpers-sb \
"

python () {
Expand Down Expand Up @@ -104,6 +109,7 @@ do_install () {
install -c -m 0644 ${WORKDIR}/update-balena-supervisor.service ${D}${systemd_unitdir}/system
install -c -m 0644 ${WORKDIR}/update-balena-supervisor.timer ${D}${systemd_unitdir}/system
install -c -m 0644 ${WORKDIR}/migrate-supervisor-state.service ${D}${systemd_unitdir}/system
install -c -m 0644 ${WORKDIR}/balena-supervisor-security-status.service ${D}${systemd_unitdir}/system
# symlinks to legacy resin-supervisor systemd unit files
ln -s balena-supervisor.service ${D}${systemd_unitdir}/system/resin-supervisor.service
ln -s update-balena-supervisor.service ${D}${systemd_unitdir}/system/update-resin-supervisor.service
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[Unit]
Description=Expose Secureboot & FDE status to the supervisor

[Service]
Type=oneshot
ExecStart=/bin/sh -c ". /usr/libexec/os-helpers-supervisor && writeSecurityStatus"
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ After=\
bind-etc-systemd-system-resin.target.wants.service \
bind-etc-balena-supervisor.service \
migrate-supervisor-state.service \
extract-balena-ca.service
extract-balena-ca.service \
balena-supervisor-security-status.service
Wants=balena.service
ConditionPathExists=/etc/balena-supervisor/supervisor.conf
ConditionPathExists=/var/run/supervisor

[Service]
Type=simple
Expand All @@ -28,6 +30,7 @@ WatchdogSec=180
SyslogIdentifier=balena-supervisor
EnvironmentFile=/etc/balena-supervisor/supervisor.conf
EnvironmentFile=-/tmp/update-supervisor.conf
ExecStartPre=mkdir -p /var/run/supervisor
ExecStartPre=-@BINDIR@/balena stop resin_supervisor
ExecStartPre=-@BINDIR@/balena stop balena_supervisor
ExecStartPre=/bin/systemctl is-active balena.service
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ runSupervisor() {
--mount type=bind,source=/var/log/supervisor-log,target=/var/log \
--mount type=bind,source=/etc/ssl/certs,target=/etc/ssl/certs,readonly \
--mount type=bind,source=/usr/share/ca-certificates,target=/usr/share/ca-certificates,readonly \
--mount type=bind,source=/var/run/supervisor/,target=/var/run/supervisor/,readonly \
--mount type=bind,source=/,target=/mnt/root \
-e DOCKER_ROOT=/mnt/root/var/lib/docker \
-e DOCKER_SOCKET=/var/run/balena-engine.sock \
Expand Down
4 changes: 4 additions & 0 deletions meta-balena-common/recipes-support/os-helpers/os-helpers.bb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ SRC_URI = " \
file://os-helpers-api \
file://os-helpers-efi \
file://os-helpers-sb \
file://os-helpers-supervisor \
file://safe_reboot \
"
S = "${WORKDIR}"
Expand All @@ -39,6 +40,7 @@ PACKAGES = " \
${PN}-reboot \
${PN}-efi \
${PN}-sb \
${PN}-supervisor \
"

do_install() {
Expand All @@ -52,6 +54,7 @@ do_install() {
${WORKDIR}/os-helpers-api \
${WORKDIR}/os-helpers-efi \
${WORKDIR}/os-helpers-sb \
${WORKDIR}/os-helpers-supervisor \
${WORKDIR}/safe_reboot \
${D}${libexecdir}
sed -i "s,@@BALENA_CONF_UNIT_STORE@@,${BALENA_CONF_UNIT_STORE},g" ${D}${libexecdir}/os-helpers-config
Expand All @@ -67,6 +70,7 @@ FILES:${PN}-api = "${libexecdir}/os-helpers-api"
FILES:${PN}-reboot = "${libexecdir}/safe_reboot"
FILES:${PN}-efi = "${libexecdir}/os-helpers-efi"
FILES:${PN}-sb = "${libexecdir}/os-helpers-sb"
FILES:${PN}-sb = "${libexecdir}/os-helpers-supervisor"

do_test_api() {
if [ "${BB_NO_NETWORK}" = "1" ]; then
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,54 @@ setup_mode_enabled() {
user_mode_enabled() {
secureboot_enabled && ! setup_mode_enabled
}

# return PK and KEK keys metadata as a json array
get_SB_keys() {
tmp_dir="/tmp/efi_extract_$(openssl rand -hex 6)"
mkdir -p "$tmp_dir"

# Function to extract and process certificates
extract_and_process() {
local efi_var="$1"
local efi_readvar_output="${tmp_dir}/${efi_var}"
local certs_output_prefix="${efi_readvar_output}-certs"
local json_entries=()

# Read EFI variable and extract certificates
efi-readvar -v "$efi_var" -o "$efi_readvar_output" > /dev/null 2>&1
sig-list-to-certs "$efi_readvar_output" "$certs_output_prefix" > /dev/null 2>&1

# Process all extracted certificates
for cert_file in "${certs_output_prefix}"-*.der; do
if [[ -f "$cert_file" ]]; then
# Convert DER to PEM
pem_file="${cert_file%.der}.pem"
openssl x509 -inform der -in "$cert_file" -out "$pem_file" > /dev/null 2>&1

# Extract certificate details
issuer=$(openssl x509 -in "$pem_file" -noout -issuer | sed 's/issuer=//')
subject=$(openssl x509 -in "$pem_file" -noout -subject | sed 's/subject=//')
validity=$(openssl x509 -in "$pem_file" -noout -dates | tr '\n' ' ' | sed 's/ *$//')
serial=$(openssl x509 -in "$pem_file" -noout -serial | sed 's/serial=//')
sha256_fingerprint=$(openssl x509 -in "$pem_file" -noout -fingerprint -sha256 | cut -d'=' -f2 | tr -d ':')

# Construct JSON object for this certificate
json_entry="{\"type\":\"$efi_var\",\"issuer\":\"$issuer\",\"subject\":\"$subject\",\"validity\":\"$validity\",\"serial\":\"$serial\",\"sha256\":\"$sha256_fingerprint\"}"

# Add JSON entry to the list
json_entries+=("$json_entry")
fi
done

# Join JSON entries into a valid JSON array and return
echo "${json_entries[@]}" | jq -s .
}

pk_json=$(extract_and_process "PK")
kek_json=$(extract_and_process "KEK")

rm -rf "$tmp_dir"

# Merge PK and KEK JSON arrays
echo "$pk_json" "$kek_json" | jq -s 'add'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/bin/sh
# Copyright 2025 Balena Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# security.json is a file that is read by the supervisor to get the secureboot and encryption status
# it can be extended in the future to include more security related information
# altenratively, we could replace it with a 2-way communication channel between the supervisor and the host (gRPC or ...)

# note that the /var/run/supervisor folder is mounted in the SV container

# vi: ft=sh

# shellcheck disable=SC1091
[ -f "/usr/libexec/os-helpers-sb" ] && . /usr/libexec/os-helpers-sb
# shellcheck disable=SC1091
[ -f "/usr/libexec/os-helpers-fs" ] && . /usr/libexec/os-helpers-fs
# shellcheck disable=SC1091
[ -f "/usr/libexec/os-helpers-fs" ] && . /usr/libexec/os-helpers-efi

SUPERVISOR_RUN_DIR="/var/run/supervisor"

writeSecurityStatus() {
mkdir -p "$SUPERVISOR_RUN_DIR"

# is_secured is a function from os-helpers-sb which returns 0 if secureboot is enabled
if is_secured; then
secureboot=true
else
secureboot=false
fi

# determine if the data partition is encrypted
data_partition=$(get_dev_path_from_label "resin-data")
if is_part_encrypted ${data_partition}; then
fullDiskEncryption=true
else
fullDiskEncryption=false
fi

# get_SB_keys is a function from os-helpers-efi that returns the PK and KEK keys metadata as a json array
cat > "$SUPERVISOR_RUN_DIR/security.json" <<EOF
{
"is_secureboot_enabled": $secureboot
"is_storage_encrypted": $fullDiskEncryption
"secureboot_keys_metadata": $(get_SB_keys)
}
EOF
}