diff --git a/images/fedora-intune/defender.yaml b/images/fedora-intune/defender.yaml index ce12384..73561d3 100644 --- a/images/fedora-intune/defender.yaml +++ b/images/fedora-intune/defender.yaml @@ -26,11 +26,6 @@ add-files: - ["mdatp-firstboot.service", "/usr/lib/systemd/system/mdatp-firstboot.service"] - ["mdatp-firstboot.conf", "/usr/lib/systemd/system/mdatp.service.d/10-firstboot.conf"] - ["50-defender.preset", "/usr/lib/systemd/system-preset/50-defender.preset"] - # Defender health for the Intune compliance script, which can't query - # Defender itself from inside himmelblaud-tasks; see the script. - - ["mdatp-health-snapshot", "/usr/libexec/mdatp-health-snapshot"] - - ["mdatp-health-snapshot.service", "/usr/lib/systemd/system/mdatp-health-snapshot.service"] - - ["mdatp-health-snapshot.timer", "/usr/lib/systemd/system/mdatp-health-snapshot.timer"] # Enforced Defender settings (shown as "[managed]" in `mdatp health`; local # changes are refused): real-time protection, behavior monitoring, PUA # blocking, cloud protection at the "high" block level, automatic updates @@ -62,4 +57,4 @@ postprocess: # Fail the build on a typo rather than ship a config Defender can't read. python3 -m json.tool /usr/share/mdatp-managed/mdatp_managed.json > /dev/null rpm -q --qf '%{POSTIN}' mdatp > /usr/libexec/mdatp-postinst - chmod 0755 /usr/libexec/mdatp-firstboot /usr/libexec/mdatp-postinst /usr/libexec/mdatp-health-snapshot + chmod 0755 /usr/libexec/mdatp-firstboot /usr/libexec/mdatp-postinst diff --git a/images/fedora-intune/files/50-defender.preset b/images/fedora-intune/files/50-defender.preset index d16089b..dec91a5 100644 --- a/images/fedora-intune/files/50-defender.preset +++ b/images/fedora-intune/files/50-defender.preset @@ -2,5 +2,3 @@ enable mdatp-firstboot.service enable mdatp.service enable mde_netfilter_v2.socket -# Health snapshot for the Intune compliance script. -enable mdatp-health-snapshot.timer diff --git a/images/fedora-intune/files/mdatp-health-snapshot b/images/fedora-intune/files/mdatp-health-snapshot deleted file mode 100644 index c7cf1d7..0000000 --- a/images/fedora-intune/files/mdatp-health-snapshot +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env bash -# Save `mdatp health` fields to /run/mdatp-health/ for the Intune -# custom compliance script (intune/defender-compliance.sh). -# -# That script runs inside himmelblaud-tasks.service, and Defender refuses to -# answer it there: the daemon checks the calling process tree, can't read -# /proc//cmdline ("Permission denied" in -# microsoft_defender_err.log), and the script sees no daemon. This runs from a -# timer outside that service instead. Each file holds the raw -# `mdatp health --field` output; the directory is replaced as a whole. -set -euo pipefail - -MDATP=/usr/bin/mdatp -DEST=/run/mdatp-health -FIELDS=( - healthy - licensed - org_id - real_time_protection_enabled - behavior_monitoring - cloud_enabled - definitions_status - definitions_updated_minutes_ago - app_version -) - -# Right after boot the daemon may not answer yet; give it up to 2 minutes so -# the first snapshot isn't a false "not running". -for _ in $(seq 1 24); do - [[ "$("${MDATP}" health --field healthy 2>/dev/null | tail -n1)" =~ ^(true|false)$ ]] && break - sleep 5 -done - -tmp="$(mktemp -d "${DEST}.XXXXXX")" -trap 'rm -rf "${tmp}"' EXIT -for field in "${FIELDS[@]}"; do - "${MDATP}" health --field "${field}" > "${tmp}/${field}" 2>/dev/null || true -done -chmod 0755 "${tmp}" -chmod 0644 "${tmp}"/* - -# Swap in the new snapshot; readers see either the old or the new one. -rm -rf "${DEST}.old" -[[ -d "${DEST}" ]] && mv "${DEST}" "${DEST}.old" -mv "${tmp}" "${DEST}" -rm -rf "${DEST}.old" -trap - EXIT diff --git a/images/fedora-intune/files/mdatp-health-snapshot.service b/images/fedora-intune/files/mdatp-health-snapshot.service deleted file mode 100644 index 3a06042..0000000 --- a/images/fedora-intune/files/mdatp-health-snapshot.service +++ /dev/null @@ -1,7 +0,0 @@ -[Unit] -Description=Save Microsoft Defender health for the Intune compliance check -After=mdatp.service - -[Service] -Type=oneshot -ExecStart=/usr/libexec/mdatp-health-snapshot diff --git a/images/fedora-intune/files/mdatp-health-snapshot.timer b/images/fedora-intune/files/mdatp-health-snapshot.timer deleted file mode 100644 index 4e41c50..0000000 --- a/images/fedora-intune/files/mdatp-health-snapshot.timer +++ /dev/null @@ -1,11 +0,0 @@ -[Unit] -Description=Save Microsoft Defender health every 5 minutes - -[Timer] -# Early, so the compliance check at the first sign-in after boot finds a -# snapshot; Himmelblau doesn't check again for 8 hours. -OnBootSec=20s -OnUnitActiveSec=5min - -[Install] -WantedBy=timers.target diff --git a/images/fedora-intune/intune/defender-compliance.sh b/images/fedora-intune/intune/defender-compliance.sh index 78f4163..a274493 100755 --- a/images/fedora-intune/intune/defender-compliance.sh +++ b/images/fedora-intune/intune/defender-compliance.sh @@ -2,30 +2,26 @@ # Intune custom compliance discovery script for Linux: is Microsoft Defender # for Endpoint (mdatp) installed, onboarded, licensed and protecting? # -# Upload in Intune > Devices > Compliance > Scripts (Linux), and pair it with -# defender-compliance.json in a Linux compliance policy (Custom compliance). -# Himmelblau runs it as root inside himmelblaud-tasks.service and sends the -# JSON on stdout to Intune, which evaluates it against the rules. Every setting -# is always emitted, so a missing or stopped Defender reads as non-compliant -# instead of as a script error. +# Upload in Intune > Endpoint security > Device compliance > Scripts (Linux), +# and pair it with defender-compliance.json in a Linux compliance policy +# (Custom compliance). Himmelblau runs it as root inside +# himmelblaud-tasks.service and sends the JSON on stdout to Intune, which +# evaluates it against the rules. Every setting is always emitted, so a missing +# or stopped Defender reads as non-compliant instead of as a script error. MDATP=/usr/bin/mdatp -# Under Himmelblau, Defender won't answer `mdatp health` from this script, so -# a root timer may save the fields in /run/mdatp-health (the fedora-intune -# image does). Used when under 20 minutes old, otherwise mdatp is asked. -SNAPSHOT=/run/mdatp-health -if [[ -n "$(find "${SNAPSHOT}/healthy" -mmin -20 2>/dev/null)" ]]; then - raw_field() { cat "${SNAPSHOT}/$1" 2>/dev/null; } -else - raw_field() { "${MDATP}" health --field "$1" 2>/dev/null; } -fi +# Defender won't answer `mdatp health` started from inside himmelblaud-tasks +# (it can't read that process while checking the caller), so ask through +# systemd, which runs mdatp as its own child. Elsewhere, ask mdatp directly. +health="$(systemd-run --quiet --wait --pipe --collect "${MDATP}" health 2>/dev/null)" +grep -q '^healthy' <<< "${health}" || health="$("${MDATP}" health 2>/dev/null)" -# Print one `mdatp health` field without quotes or a trailing " [managed]". -# Unlicensed or unonboarded, mdatp prints "ATTENTION: ..." lines first. +# Print one field of the `mdatp health` output ("name : value") without +# quotes or a trailing " [managed]". field() { - raw_field "$1" | grep -v '^ATTENTION' | tail -n1 \ - | sed -e 's/ \[managed\]$//' -e 's/^"//' -e 's/"$//' + grep -m1 "^$1 *:" <<< "${health}" \ + | sed -e 's/^[^:]*: *//' -e 's/ \[managed\]$//' -e 's/^"//' -e 's/"$//' } bool() {