Skip to content
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
7 changes: 7 additions & 0 deletions acl/docs/BUILD_RPM_IMAGE_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,13 @@ conversion rejects active UKI addons (including the optional
`EXTRA_KERNEL_CMDLINE` debug addon) that supply another
`acl.ipe.policy_sha256` token.

IPE activation triggers a containerd systemd drop-in that imports
a base config (AgentBaker's on AKS nodes) merged with
`/usr/share/containerd/acl-erofs.toml`, which selects EROFS as the CRI
and snapshotter plugins and enables the flag to discover dm-verity OCI
referrers. This requires a matching containerd RPM with signed EROFS referrer
support. Disabled IPE leaves the base config selected.

**Build output location:** `__build__/images/images/amd64-usr/latest/`

### Phase 4: Build VM Image (Optional)
Expand Down
1 change: 1 addition & 0 deletions acl/sysexts.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ sysexts:
mode: embedded
packages:
- app-containers/containerd
- erofs-utils

# --- scenario-specific sysexts -----------------------------------------
- name: docker
Expand Down
7 changes: 7 additions & 0 deletions acl/tests/ipe/offline/test-ipe-loader-runtime.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../.." && pwd)"
LOADER="${SCRIPT_DIR}/build_library/rpm/additional_files/dracut-acl-ipe-load/acl-ipe-load.sh"
PROFILE_HELPER="${SCRIPT_DIR}/build_library/rpm/additional_files/acl-node-security-profile.sh"
CONTAINERD_EROFS_PROFILE="${SCRIPT_DIR}/build_library/rpm/additional_files/containerd2/containerd-acl-profile.conf"
TMP_DIR="$(mktemp -d)"
trap 'rm -rf "${TMP_DIR}"' EXIT

Expand All @@ -31,6 +32,7 @@ prepare_case() {
mkdir -p "${IPE_DIR}"
: > "${IPE_DIR}/new_policy"
printf '9\n' > "${IPE_DIR}/enforce"
cp "${CONTAINERD_EROFS_PROFILE}" "${CASE_DIR}/containerd-erofs-profile.conf"

command cat > "${CASE_DIR}/security-profile.sh" <<'EOF'
acl_security_profile() {
Expand All @@ -48,6 +50,8 @@ run_loader() {
ACL_IPE_CMDLINE_FILE="${CASE_DIR}/cmdline" \
ACL_IPE_CREDENTIAL_PATH="${credential}" \
ACL_IPE_SECURITY_PROFILE_HELPER="${CASE_DIR}/security-profile.sh" \
ACL_IPE_CONTAINERD_PROFILE="${CASE_DIR}/containerd-erofs-profile.conf" \
ACL_IPE_CONTAINERD_DROPIN="${CASE_DIR}/dropins/90-acl-profile.conf" \
bash "${LOADER}" 2>&1
}

Expand Down Expand Up @@ -105,6 +109,7 @@ EOF
[[ -s "${IPE_DIR}/new_policy" ]]
# enforce should remain unchanged (not set to 0)
[[ "$(<"${IPE_DIR}/enforce")" == "9" ]]
[[ ! -e "${CASE_DIR}/dropins/90-acl-profile.conf" ]]
}

# ---- Test: the removed runtime alias must not activate IPE ----
Expand Down Expand Up @@ -149,6 +154,7 @@ EOF
{ echo "loader did not report requested mode '${imds_mode}'" >&2; return 1; }
[[ "$(<"${IPE_DIR}/enforce")" == "0" ]]
[[ "$(<"${IPE_DIR}/policies/acl_ipe_boot_policy/active")" == "1" ]]
cmp "${CASE_DIR}/containerd-erofs-profile.conf" "${CASE_DIR}/dropins/90-acl-profile.conf"
)

# ---- Test: 'enforcing' is reserved; loader logs an explicit unsupported
Expand All @@ -172,6 +178,7 @@ EOF
# Verify policy was loaded but not activated, and boot was not blocked.
[[ -s "${IPE_DIR}/new_policy" ]]
[[ "$(<"${IPE_DIR}/enforce")" == "9" ]]
[[ ! -e "${CASE_DIR}/dropins/90-acl-profile.conf" ]]
Comment thread
dallasd1 marked this conversation as resolved.
}


Expand Down
27 changes: 27 additions & 0 deletions acl/tests/ipe/run-ipe-audit-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,33 @@ if [[ "$(tr -d '[:space:]' < "${POLICY_DIR}/active")" != "1" ]]; then
fail "policy ${POLICY_NAME} is not active"
fi

systemctl is-active --quiet containerd ||
fail "containerd is not running"
containerd_pid="$(systemctl show --property=MainPID --value containerd)" ||
fail "could not get containerd's PID"
containerd_cmdline="$(tr '\0' ' ' < "/proc/${containerd_pid}/cmdline")" ||
fail "could not read containerd's command line"
[[ " ${containerd_cmdline} " == *" --config /run/containerd/acl-config.toml "* ]] ||
fail "containerd is not using the IPE-selected config"
if ! /usr/bin/containerd --config /run/containerd/acl-config.toml config dump |
awk '
{
gsub(/\047/, "\"")
sub(/^[[:space:]]+/, "")
sub(/[[:space:]]+$/, "")
}
/^\[/ { section = $0 }
section == "[plugins.\"io.containerd.snapshotter.v1.erofs\"]" &&
/^enable_dmverity_referrers =/ { referrers = ($0 == "enable_dmverity_referrers = true") }
section == "[plugins.\"io.containerd.cri.v1.images\"]" &&
/^snapshotter =/ { snapshotter = ($0 == "snapshotter = \"erofs\"") }
section == "[plugins.\"io.containerd.service.v1.diff-service\"]" &&
/^default =/ { differ = ($0 == "default = [\"erofs\", \"walking\"]") }
END { if (!referrers || !snapshotter || !differ) exit 1 }
'; then
fail "effective containerd config does not enable the expected EROFS profile"
fi

policy="$(cat "${POLICY_DIR}/policy")"
grep -Fq "DEFAULT op=EXECUTE action=DENY" <<< "${policy}" ||
fail "active policy does not deny untrusted execution by default"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Imported when IPE is activated at boot
version = 4

[plugins."io.containerd.snapshotter.v1.erofs"]
enable_dmverity_referrers = true

[plugins."io.containerd.cri.v1.images"]
snapshotter = "erofs"

[plugins."io.containerd.service.v1.diff-service"]
default = ["erofs", "walking"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Installed by the IPE loader only after policy activation.
[Unit]
Wants=modprobe@erofs.service modprobe@dm_verity.service
After=modprobe@erofs.service modprobe@dm_verity.service

[Service]
ExecStartPre=/usr/libexec/containerd/acl-select-profile ${CONTAINERD_CONFIG}
ExecStart=
ExecStart=/usr/bin/containerd --config /run/containerd/acl-config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#!/bin/bash

set -euo pipefail

base_config="${1:-}"
merged_config_path="${ACL_CONTAINERD_CONFIG_PATH:-/run/containerd/acl-config.toml}"
erofs_config="${ACL_CONTAINERD_EROFS_CONFIG:-/usr/share/containerd/acl-erofs.toml}"

fail() { echo "ERROR: $*" >&2; exit 1; }

[[ -n "${base_config}" && -r "${base_config}" ]] ||
fail "containerd base config is not readable: ${base_config}"
[[ -r "${erofs_config}" ]] ||
fail "containerd EROFS profile is not readable: ${erofs_config}"

# Convert a given path to an absolute path and escape it for use in a TOML file.
get_absolute_path() {
local path="$1"
[[ "${path}" == /* ]] || path="$(pwd)/${path}"
path="${path//\\/\\\\}"
path="${path//\"/\\\"}"
printf '"%s"' "${path}"
}

# Merge the base containerd config with the EROFS profile.
mkdir -p "$(dirname "${merged_config_path}")"
temporary_merged_config="${merged_config_path}.tmp.$$"
trap 'rm -f -- "${temporary_merged_config}"' EXIT
cat > "${temporary_merged_config}" <<EOF
version = 4
imports = [
$(get_absolute_path "${base_config}"),
$(get_absolute_path "${erofs_config}")
]
EOF

# Nested imports may override the profile. Verify the EROFS settings carried over.
if ! containerd --config "${temporary_merged_config}" config dump |
awk '
{
# Normalize TOML quotes and whitespace for exact comparisons.
gsub(/\047/, "\"")
sub(/^[[:space:]]+/, "")
sub(/[[:space:]]+$/, "")
}

/^\[/ {
section = $0
}

section == "[plugins.\"io.containerd.snapshotter.v1.erofs\"]" &&
/^enable_dmverity_referrers =/ {
referrers_enabled = ($0 == "enable_dmverity_referrers = true")
}

section == "[plugins.\"io.containerd.cri.v1.images\"]" &&
/^snapshotter =/ {
erofs_snapshotter_selected = ($0 == "snapshotter = \"erofs\"")
}

section == "[plugins.\"io.containerd.service.v1.diff-service\"]" &&
/^default =/ {
erofs_differ_selected = ($0 == "default = [\"erofs\", \"walking\"]")
}

END {
if (!referrers_enabled ||
!erofs_snapshotter_selected ||
!erofs_differ_selected) {
exit 1
}
}
'; then
fail "Cannot select EROFS profile. Check for config errors or conflicting nested imports in ${base_config}"
fi
mv -Tf "${temporary_merged_config}" "${merged_config_path}"

echo "Selected EROFS containerd runtime profile (base: ${base_config})"
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ IPE_DIR="${ACL_IPE_DIR:-/sys/kernel/security/ipe}"
CREDENTIAL_PATH="${ACL_IPE_CREDENTIAL_PATH:-/.extra/credentials/acl-ipe-policy.p7b.cred}"
CMDLINE_FILE="${ACL_IPE_CMDLINE_FILE:-/proc/cmdline}"
SECURITY_PROFILE_HELPER="${ACL_IPE_SECURITY_PROFILE_HELPER:-/usr/lib/acl/acl-node-security-profile.sh}"
CONTAINERD_PROFILE_SRC="${ACL_IPE_CONTAINERD_PROFILE:-/usr/lib/acl/containerd-erofs-profile.conf}"
CONTAINERD_PROFILE_DEST="${ACL_IPE_CONTAINERD_DROPIN:-/run/systemd/system/containerd.service.d/90-acl-profile.conf}"

log() { echo "acl-ipe-load: $*" >&2; }
skip() { log "WARNING: $*; continuing boot without activating IPE."; exit 0; }
Expand Down Expand Up @@ -110,3 +112,14 @@ log "Activated policy ${POLICY_NAME}."
policy_active="$(cat "${active_file}" 2>/dev/null || true)"
[[ "${policy_active}" == "1" ]] ||
skip "policy ${POLICY_NAME} activation verification failed"

if [[ ! -r "${CONTAINERD_PROFILE_SRC}" ]]; then
log "ERROR: active IPE policy has no containerd profile at ${CONTAINERD_PROFILE_SRC}."
exit 1
fi
if ! mkdir -p "${CONTAINERD_PROFILE_DEST%/*}" ||
! cat "${CONTAINERD_PROFILE_SRC}" > "${CONTAINERD_PROFILE_DEST}"; then
log "ERROR: failed to install the containerd profile at ${CONTAINERD_PROFILE_DEST}."
exit 1
fi
log "Enabled the EROFS containerd profile at ${CONTAINERD_PROFILE_DEST}."
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ install() {
inst_script "${moddir}/acl-ipe-load.sh" \
"/usr/bin/acl-ipe-load"

inst_simple "${moddir}/containerd-erofs-profile.conf" \
"/usr/lib/acl/containerd-erofs-profile.conf"

inst_simple "${moddir}/acl-ipe-load.service" \
"${systemdsystemunitdir}/acl-ipe-load.service"

Expand Down
2 changes: 2 additions & 0 deletions build_library/rpm/dracut_install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,8 @@ SETUP_EOF
"${ipe_load_module}/acl-ipe-load.sh"
sudo cp "${BUILD_LIBRARY_DIR}/rpm/additional_files/dracut-acl-ipe-load/acl-ipe-load.service" \
"${ipe_load_module}/acl-ipe-load.service"
sudo cp "${BUILD_LIBRARY_DIR}/rpm/additional_files/containerd2/containerd-acl-profile.conf" \
"${ipe_load_module}/containerd-erofs-profile.conf"
sudo cp "${BUILD_LIBRARY_DIR}/rpm/additional_files/acl-node-security-profile.sh" \
"${ipe_load_module}/acl-node-security-profile.sh"
sudo chmod +x "${ipe_load_module}/module-setup.sh"
Expand Down
7 changes: 7 additions & 0 deletions build_library/rpm/sysext_mangle_containerd-flatcar.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ acl_cgroupfs_config="${rootfs}/usr/share/containerd/config-cgroupfs.toml"
unit="${rootfs}/usr/lib/systemd/system/containerd.service"
dropin_dir="${rootfs}/usr/lib/systemd/system/containerd.service.d"
wants_dir="${rootfs}/usr/lib/systemd/system/multi-user.target.wants"
profile_dir="$(dirname "${BASH_SOURCE[0]}")/additional_files/containerd2"

if [[ ! -f "${unit}" ]]; then
echo ">>> ERROR: $0: Azure Linux containerd unit not found at ${unit}" >&2
Expand Down Expand Up @@ -55,6 +56,12 @@ sed -E 's/^([[:space:]]*)SystemdCgroup[[:space:]]*=.*/\1SystemdCgroup = false/'
"${acl_config}" > "${acl_cgroupfs_config}"
chmod 0644 "${acl_cgroupfs_config}"

# Add the EROFS containerd configuration. The IPE loader activates it at boot.
install -Dpm 0644 "${profile_dir}/containerd-acl-erofs.toml" \
"${rootfs}/usr/share/containerd/acl-erofs.toml"
install -Dpm 0755 "${profile_dir}/containerd-acl-select-profile" \
"${rootfs}/usr/libexec/containerd/acl-select-profile"

# The RPM enables the unit from %post, which does not run when the payload is
# unpacked into a sysext, so create the enablement symlink here.
echo ">>> NOTICE: $0: enabling containerd.service"
Expand Down
Loading