fedora-intune: cron for Intune config scripts, Defender remediation script
Himmelblau installs Intune Linux custom configuration scripts as /etc/cron.d jobs, and the image had no cron, so a script policy failed to apply. Add cronie and enable crond. Add a custom configuration script that repairs Microsoft Defender on its schedule: finishes first-boot setup, restarts a stopped daemon, onboards with the tenant's mdatp_onboard.json (pasted into the script in Intune), and re-enables real-time protection and updates definitions when needed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
75c3b502d7
commit
6afa1d21e6
3 files changed
+107
No files matched your search
@@ -2,3 +2,5 @@
|
||||
enable himmelblaud.service
|
||||
enable himmelblaud-tasks.service
|
||||
enable himmelblau-hsm-pin-init.service
|
||||
# Runs the Intune custom configuration scripts Himmelblau puts in /etc/cron.d.
|
||||
enable crond.service
|
||||
@@ -20,6 +20,8 @@ packages:
|
||||
# himmelblau-selinux compiles its policy module at install time.
|
||||
- make
|
||||
- selinux-policy-devel
|
||||
# Intune custom configuration scripts are installed as /etc/cron.d jobs.
|
||||
- cronie
|
||||
|
||||
add-files:
|
||||
- ["himmelblau.conf", "/etc/himmelblau/himmelblau.conf"]
|
||||
@@ -44,6 +46,7 @@ postprocess:
|
||||
done
|
||||
grep -q pam_himmelblau.so /etc/pam.d/system-auth
|
||||
chmod 0755 /usr/libexec/himmelblau-os-release
|
||||
test -d /etc/cron.d
|
||||
|
||||
# himmelblau-selinux builds and loads its module in %posttrans, which does
|
||||
# nothing in a compose; do it here.
|
||||
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
#!/bin/bash
|
||||
# Intune custom configuration script for Linux: bring Microsoft Defender for
|
||||
# Endpoint (mdatp) back to the state defender-compliance.sh checks for.
|
||||
#
|
||||
# Intune has no "run only when non-compliant" trigger for Linux, so this runs
|
||||
# on the policy's schedule and only acts on what is wrong; on a healthy device
|
||||
# it only reads `mdatp health`. Himmelblau installs it as an /etc/cron.d job.
|
||||
#
|
||||
# Intune > Devices > Configuration > Create > Linux > Settings catalog >
|
||||
# Custom Configuration:
|
||||
# Execution context: root
|
||||
# Execution frequency: every 1 hour (or 15 minutes while rolling out)
|
||||
# Execution retries: 1
|
||||
# Script: this file, with ONBOARDING_JSON filled in
|
||||
#
|
||||
# Exit status is non-zero when Defender is still not healthy afterwards.
|
||||
|
||||
# Contents of mdatp_onboard.json from the Defender portal: Settings > Endpoints
|
||||
# > Onboarding > Linux Server > "Local Script (Python)". The downloaded
|
||||
# MicrosoftDefenderATPOnboardingLinuxServer.py writes this file to
|
||||
# /etc/opt/microsoft/mdatp/ on the machine it runs on; paste that file's
|
||||
# contents here. Leave the placeholder to skip onboarding.
|
||||
ONBOARDING_JSON=$(cat <<'JSON'
|
||||
REPLACE_WITH_MDATP_ONBOARD_JSON
|
||||
JSON
|
||||
)
|
||||
|
||||
MDATP=/usr/bin/mdatp
|
||||
ONBOARD_FILE=/etc/opt/microsoft/mdatp/mdatp_onboard.json
|
||||
|
||||
log() {
|
||||
logger -t defender-remediation -- "$*"
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
# Print one `mdatp health` field without quotes, a trailing " [managed]" or
|
||||
# the "ATTENTION: ..." lines mdatp prints while unlicensed.
|
||||
field() {
|
||||
"${MDATP}" health --field "$1" 2>/dev/null | grep -v '^ATTENTION' | tail -n1 \
|
||||
| sed -e 's/ \[managed\]$//' -e 's/^"//' -e 's/"$//'
|
||||
}
|
||||
|
||||
# Wait up to 2 minutes for the daemon to answer.
|
||||
wait_for_daemon() {
|
||||
local i
|
||||
for i in $(seq 1 24); do
|
||||
[[ "$(field healthy)" =~ ^(true|false)$ ]] && return 0
|
||||
sleep 5
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
if [[ ! -x "${MDATP}" ]]; then
|
||||
log "mdatp is not installed; it ships in the image, so update or rebase the device."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# The image finishes the Defender install on first boot (mdatp-firstboot).
|
||||
if [[ ! -f /var/lib/mdatp-firstboot.done ]]; then
|
||||
log "Defender first-boot setup has not completed; starting it."
|
||||
systemctl start mdatp-firstboot.service
|
||||
fi
|
||||
|
||||
if ! systemctl is-active --quiet mdatp.service; then
|
||||
log "mdatp.service is not running; restarting it."
|
||||
systemctl restart mdatp.service
|
||||
fi
|
||||
if ! wait_for_daemon; then
|
||||
log "The Defender daemon does not respond."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$(field org_id)" ]]; then
|
||||
if [[ "${ONBOARDING_JSON}" == REPLACE_WITH_MDATP_ONBOARD_JSON ]]; then
|
||||
log "Defender is not onboarded and this script has no onboarding JSON."
|
||||
else
|
||||
log "Defender is not onboarded; writing ${ONBOARD_FILE}."
|
||||
install -d -m 0755 "$(dirname "${ONBOARD_FILE}")"
|
||||
printf '%s\n' "${ONBOARDING_JSON}" > "${ONBOARD_FILE}.tmp"
|
||||
chown root:mdatp "${ONBOARD_FILE}.tmp"
|
||||
chmod 0600 "${ONBOARD_FILE}.tmp"
|
||||
mv -f "${ONBOARD_FILE}.tmp" "${ONBOARD_FILE}"
|
||||
systemctl restart mdatp.service
|
||||
wait_for_daemon || { log "The Defender daemon does not respond after onboarding."; exit 1; }
|
||||
fi
|
||||
fi
|
||||
|
||||
# Settings Defender's own policy manages show " [managed]" and can't be
|
||||
# changed locally; this only fixes a locally disabled real-time protection.
|
||||
if [[ "$(field real_time_protection_enabled)" != true ]]; then
|
||||
log "Real-time protection is off; enabling it."
|
||||
"${MDATP}" config real-time-protection --value enabled
|
||||
fi
|
||||
|
||||
if [[ "$(field definitions_status)" != up_to_date ]]; then
|
||||
log "Definitions are not up to date; updating them."
|
||||
"${MDATP}" definitions update
|
||||
fi
|
||||
|
||||
healthy="$(field healthy)"
|
||||
log "healthy=${healthy} licensed=$(field licensed) org_id=$(field org_id) rtp=$(field real_time_protection_enabled) definitions=$(field definitions_status)"
|
||||
[[ "${healthy}" == true ]]
|
||||
Reference in new issue
Block a user