Author SHA1 Message Date
Wesley van TilburgandClaude Opus 5.5 e8cfa8d4cf fedora-intune: don't repeat the version in the reported OS version
Build containers / fedora-cosmic (44) (pull_request) Canceled after 0s
Build containers / fedora-cosmic (rawhide) (pull_request) Canceled after 0s
Build containers / fedora-remote (44) (pull_request) Canceled after 0s
Build containers / fedora-intune (44) (pull_request) Canceled after 0s
Build containers / Compute changes (pull_request) Canceled after 13s
Build containers / Prune old releases and tags (pull_request) Skipped
libhimmelblau reports "PRETTY_NAME VERSION_ID" as the OS version, and
Fedora's PRETTY_NAME already contains the version, so Entra showed
"Fedora Linux 44.20261020.0 (Forty Four) 44.20261020.0". In the
os-release the Himmelblau daemons see, set PRETTY_NAME to NAME, giving
"Fedora Linux 44.20261020.0". Nothing else in Himmelblau reads
PRETTY_NAME.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-20 12:48:44 +00:00
Wesley van TilburgandClaude Opus 5.5 5504f4e7aa fedora-intune: install the Defender managed config when Defender starts
The managed config shipped in /etc never reached updated devices:
mdatp-firstboot creates /etc/opt/microsoft/mdatp on the device, so ostree's
/etc merge treats that directory as local and doesn't add new image files
under it. VM 123 had the file in /usr/etc but not in /etc, and Defender
kept its defaults.

Ship it in /usr/share/mdatp-managed/ and install it into
/etc/opt/microsoft/mdatp/managed/ from an ExecStartPre in mdatp.service.
This also applies changes from newer images and undoes local edits.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-20 12:48:44 +00:00
Misthios 561036582c Merge pull request 'Misthios/defender onboarding validation' (#4) from misthios/defender-onboarding-validation into main
Build containers / Compute changes (push) Successful in 21s
Build containers / fedora-cosmic (44) (push) Skipped
Build containers / fedora-cosmic (rawhide) (push) Skipped
Build containers / fedora-remote (44) (push) Skipped
Build containers / fedora-intune (44) (push) Successful in 12m40s
Build containers / Prune old releases and tags (push) Successful in 28s
Reviewed-on: #4
2026-10-20 12:23:30 +00:00
Wesley van TilburgandClaude Opus 5.5 86039eeb9d fedora-intune: enforce Defender protection settings
Defender's defaults left behavior monitoring off and every setting
unmanaged. Ship /etc/opt/microsoft/mdatp/managed/mdatp_managed.json:
real-time protection, behavior monitoring, PUA blocking, cloud-delivered
protection at the high block level, automatic definition updates and
sample submission, and scheduled scans (daily quick at 12:00, weekly full
on Wednesday 12:30, low priority). Users can't change managed settings.
The build fails if the file isn't valid JSON.

Network protection (Insiders channels only) and tamper protection
(audit-only preview on Linux) are left out.

The compliance script and rules now also check behavior monitoring and
cloud-delivered protection.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-20 12:23:30 +00:00
Wesley van TilburgandClaude Opus 5.5 3afef0d821 fedora-intune: validate the onboarding JSON in the Defender script
A paste into Intune that lost the first "{" line produced an unreadable
mdatp_onboard.json, and Defender reported "No license found". Check that
the pasted JSON parses and has onboardingInfo before writing it, and log
what to fix otherwise.

The placeholder also appeared twice, so a find-and-replace of it broke
the script; match it by prefix so it appears only once.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-20 12:23:30 +00:00
Misthios 07434cedab Merge pull request 'fedora-intune: grant sudo to the Linux admins Entra group' (#3) from misthios/fedora-intune-sudo-groups into main
Build containers / fedora-cosmic (44) (push) Canceled after 0s
Build containers / fedora-cosmic (rawhide) (push) Canceled after 0s
Build containers / fedora-remote (44) (push) Canceled after 0s
Build containers / fedora-intune (44) (push) Canceled after 0s
Build containers / Compute changes (push) Canceled after 12s
Build containers / Prune old releases and tags (push) Successful in 26s
Reviewed-on: #3
2026-10-20 12:22:57 +00:00
Wesley van TilburgandClaude Opus 5.5 0e76505715 fedora-intune: grant sudo to the Linux admins Entra group
Build containers / fedora-cosmic (44) (pull_request) Canceled after 0s
Build containers / fedora-cosmic (rawhide) (pull_request) Canceled after 0s
Build containers / fedora-remote (44) (pull_request) Canceled after 0s
Build containers / fedora-intune (44) (pull_request) Canceled after 0s
Build containers / Compute changes (pull_request) Canceled after 12s
Build containers / Prune old releases and tags (pull_request) Skipped
local_sudo_group was set to wheel but sudo_groups was empty, so no Entra
user ever got sudo. Members of the Entra group
c3b1cfcc-7834-47eb-948b-a22204276453 now get wheel at sign-in, and lose
it again after leaving the group.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-20 11:30:20 +00:00
Misthios f48a0ffaf6 Merge pull request 'Misthios/fedora intune os version defender' (#2) from misthios/fedora-intune-os-version-defender into main
Build containers / Compute changes (push) Successful in 20s
Build containers / fedora-intune (44) (push) Canceled after 0s
Build containers / fedora-cosmic (44) (push) Canceled after 33s
Build containers / fedora-cosmic (rawhide) (push) Canceled after 33s
Build containers / fedora-remote (44) (push) Canceled after 34s
Build containers / Prune old releases and tags (push) Successful in 24s
Reviewed-on: #2
2026-10-20 09:22:41 +00:00
8 changed files with 104 additions and 2 deletions

No files matched your search

+14
View File
@@ -26,6 +26,18 @@ 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"]
# 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
# and sample submission, a daily quick scan at 12:00 and a weekly full scan
# on Wednesday 12:30 (low priority, up to 2 h later at random). Settings
# reference: https://learn.microsoft.com/defender-endpoint/linux-preferences
# Not set here: network protection (Insiders channels only) and tamper
# protection (audit-only preview on Linux).
- ["mdatp_managed.json", "/usr/share/mdatp-managed/mdatp_managed.json"]
# Installed into /etc/opt/microsoft/mdatp/managed/ whenever Defender starts;
# see the drop-in.
- ["mdatp-managed-config.conf", "/usr/lib/systemd/system/mdatp.service.d/20-managed-config.conf"]
postprocess:
- |
@@ -42,5 +54,7 @@ postprocess:
[[ -f "${pp}" ]] && break
done
semodule -n -i "${pp}"
# 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
@@ -5,16 +5,23 @@
# "44". Himmelblau reports VERSION_ID as the device's OS version and has no
# setting for it. The rest of the system keeps the stock VERSION_ID, which
# toolbox, flatpak and dnf expect to be the plain release.
#
# PRETTY_NAME becomes just NAME: libhimmelblau reports "PRETTY_NAME VERSION_ID"
# as the OS version string, and Fedora's PRETTY_NAME already contains the
# version ("Fedora Linux 44.20261020.0 (Forty Four) 44.20261020.0"). Nothing
# else in Himmelblau reads PRETTY_NAME.
set -euo pipefail
SRC=/usr/lib/os-release
DEST=/run/himmelblau-os-release
version="$(. "${SRC}" && echo "${OSTREE_VERSION:-${IMAGE_VERSION:-}}")"
name="$(. "${SRC}" && echo "${NAME:-Linux}")"
tmp="$(mktemp "${DEST}.XXXXXX")"
if [[ -n "${version}" ]]; then
sed "s/^VERSION_ID=.*/VERSION_ID=${version}/" "${SRC}" > "${tmp}"
sed -e "s/^VERSION_ID=.*/VERSION_ID=${version}/" \
-e "s/^PRETTY_NAME=.*/PRETTY_NAME=\"${name}\"/" "${SRC}" > "${tmp}"
else
# No image version (not an ostree/bootc deployment): pass it through as-is.
cat "${SRC}" > "${tmp}"
@@ -11,6 +11,9 @@ apply_policy = true
# Fedora's admin group; members of sudo_groups (Entra group object IDs) are
# added to it.
local_sudo_group = wheel
# Linux admins: members get wheel (sudo) at sign-in, and lose it again within
# local_groups_reconcile_interval after leaving the group.
sudo_groups = c3b1cfcc-7834-47eb-948b-a22204276453
# Home directories named after the account (e.g. /home/jdoe), with a UPN alias.
home_attr = CN
home_alias = SPN
@@ -0,0 +1,7 @@
# Install the image's enforced Defender settings each time Defender starts.
# The image can't ship them in /etc directly: mdatp-firstboot creates
# /etc/opt/microsoft/mdatp on the device, so on updates that directory counts
# as local and ostree's /etc merge never adds new files under it. Copying on
# every start also picks up changes from newer images and undoes local edits.
[Service]
ExecStartPre=+/usr/bin/install -D -Z -m 0644 /usr/share/mdatp-managed/mdatp_managed.json /etc/opt/microsoft/mdatp/managed/mdatp_managed.json
@@ -0,0 +1,29 @@
{
"antivirusEngine": {
"enforcementLevel": "real_time",
"behaviorMonitoring": "enabled",
"scanAfterDefinitionUpdate": true,
"scanArchives": true,
"disallowedThreatActions": ["allow", "restore"],
"threatTypeSettingsMergePolicy": "admin_only",
"threatTypeSettings": [
{ "key": "potentially_unwanted_application", "value": "block" },
{ "key": "archive_bomb", "value": "audit" }
],
"scheduledScan": "enabled"
},
"scheduledScan": {
"dailyConfiguration": { "timeOfDay": 720 },
"weeklyConfiguration": { "dayOfWeek": 4, "scanType": "full", "timeOfDay": 750 },
"lowPriorityScheduledScan": true,
"checkForDefinitionsUpdate": true,
"randomizeScanStartTime": 2
},
"cloudService": {
"enabled": true,
"diagnosticLevel": "required",
"automaticSampleSubmissionConsent": "safe",
"automaticDefinitionUpdateEnabled": true,
"cloudBlockLevel": "high"
}
}
@@ -84,6 +84,34 @@
}
]
},
{
"SettingName": "DefenderBehaviorMonitoring",
"Operator": "IsEquals",
"DataType": "Boolean",
"Operand": true,
"MoreInfoUrl": "https://learn.microsoft.com/en-us/defender-endpoint/linux-install-manually",
"RemediationStrings": [
{
"Language": "en_US",
"Title": "Behavior monitoring is off.",
"Description": "Microsoft Defender behavior monitoring must be enabled. Update the device to the latest image or contact IT."
}
]
},
{
"SettingName": "DefenderCloudProtection",
"Operator": "IsEquals",
"DataType": "Boolean",
"Operand": true,
"MoreInfoUrl": "https://learn.microsoft.com/en-us/defender-endpoint/linux-install-manually",
"RemediationStrings": [
{
"Language": "en_US",
"Title": "Cloud-delivered protection is off.",
"Description": "Microsoft Defender cloud-delivered protection must be enabled. Update the device to the latest image or contact IT."
}
]
},
{
"SettingName": "DefenderDefinitionsUpToDate",
"Operator": "IsEquals",
@@ -28,6 +28,8 @@ healthy=false
licensed=false
onboarded=false
rtp=false
behavior_monitoring=false
cloud_protection=false
definitions_ok=false
definitions_age=-1
version=""
@@ -40,6 +42,8 @@ if [[ -x "${MDATP}" ]]; then
healthy="$(bool "$(field healthy)")"
licensed="$(bool "$(field licensed)")"
rtp="$(bool "$(field real_time_protection_enabled)")"
[[ "$(field behavior_monitoring)" == enabled ]] && behavior_monitoring=true
cloud_protection="$(bool "$(field cloud_enabled)")"
[[ -n "$(field org_id)" ]] && onboarded=true
[[ "$(field definitions_status)" == up_to_date ]] && definitions_ok=true
age="$(field definitions_updated_minutes_ago)"
@@ -57,6 +61,8 @@ cat <<EOF
"DefenderLicensed": ${licensed},
"DefenderOnboarded": ${onboarded},
"DefenderRealTimeProtection": ${rtp},
"DefenderBehaviorMonitoring": ${behavior_monitoring},
"DefenderCloudProtection": ${cloud_protection},
"DefenderDefinitionsUpToDate": ${definitions_ok},
"DefenderDefinitionsAgeDays": ${definitions_age},
"DefenderVersion": "${version}"
@@ -71,8 +71,16 @@ if ! wait_for_daemon; then
fi
if [[ -z "$(field org_id)" ]]; then
if [[ "${ONBOARDING_JSON}" == REPLACE_WITH_MDATP_ONBOARD_JSON ]]; then
# Prefix match, so the placeholder appears only once in this file and a
# find-and-replace of it can't hit this line.
if [[ "${ONBOARDING_JSON}" == REPLACE_WITH_* ]]; then
log "Defender is not onboarded and this script has no onboarding JSON."
elif ! printf '%s\n' "${ONBOARDING_JSON}" \
| python3 -c 'import json, sys; assert "onboardingInfo" in json.load(sys.stdin)' 2>/dev/null; then
# A paste that lost the first "{" or last "}" line would otherwise leave
# Defender with an unreadable onboarding file ("No license found").
log "The onboarding JSON in this script is not valid; paste mdatp_onboard.json again, including its first '{' and last '}' lines."
exit 1
else
log "Defender is not onboarded; writing ${ONBOARD_FILE}."
install -d -m 0755 "$(dirname "${ONBOARD_FILE}")"