fedora-intune: fix boot issues, add Himmelblau variant
Build containers / Compute changes (pull_request) Successful in 2s
Build containers / fedora-remote (44) (pull_request) Successful in 11m9s
Build containers / fedora-cosmic (rawhide) (pull_request) Successful in 12m8s
Build containers / fedora-cosmic (44) (pull_request) Successful in 14m20s
Build containers / fedora-intune (44) (pull_request) Canceled after 10m35s
Build containers / fedora-intune-himmelblau (44) (pull_request) Canceled after 9m41s
Build containers / Prune old releases and tags (pull_request) Skipped

Fixes found by building and inspecting the image:

- Select the Intune authselect profile with-altfiles. Without it system
  users in /usr/lib/passwd (gdm, pipewire, mdatp) do not resolve and the
  login screen never starts. The build now fails if gdm does not resolve.
- Ship /opt as a plain directory (opt-usrlocal: root). Defender installs
  to /opt/microsoft/mdatp and keeps state in /var/opt/microsoft/mdatp;
  with the default /opt -> /var/opt symlink those were the same
  read-only directory. rpm-ostree still relocates /opt content to
  /usr/lib/opt, so finalize.d/60-opt-links links it back (only for images
  where /opt is a directory; fedora-cosmic/remote are unaffected).
- Run Defender's %post on first boot (mdatp-firstboot.service): in a
  compose /var is read-only and the machine GUID/state must not be
  shared. mdatp.service waits for it.

New image fedora-intune-himmelblau: the same workstation with Entra ID
sign-in through Himmelblau (Community Nightly packages), which joins the
device at the first sign-in and enrolls it in Intune (apply_policy)
instead of the Microsoft Intune app. Workstation, Edge and Defender
manifests move to images/shared so both images use them; build.sh copies
images/shared/*.yaml and CI builds both images in one matrix job.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
MisthiosandClaude Opus 5.5 committed 2026-10-19 11:06:50 +00:00
1 parent 6f27bfb4dc
commit 4f71d350fa
25 files changed
+304 -65

No files matched your search

+46
View File
@@ -0,0 +1,46 @@
# Microsoft Defender for Endpoint on Linux (mdatp), RHEL 10 build, from the
# microsoft-rhel10 repo (shared/repos/microsoft.repo).
#
# mdatp's %post does the real install: units, SELinux module, and per-machine
# state under /var/opt/microsoft/mdatp (machine GUID, definitions database,
# logs). In a compose /var is read-only, and that state must not be shared
# between machines anyway, so the %post is saved into the image and run once on
# first boot by mdatp-firstboot.service. mdatp.service waits for it.
#
# Onboarding is per tenant and not part of the image: run the onboarding script
# from the Defender portal on the device.
repo-packages:
- repo: microsoft-rhel10
packages:
- mdatp
packages:
# The %post is a bash script; Defender's inventory scripts and the
# onboarding script are Python.
- bash
- python3
add-files:
- ["mdatp-firstboot", "/usr/libexec/mdatp-firstboot"]
- ["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"]
postprocess:
- |
#!/usr/bin/env bash
set -xeuo pipefail
# The %post wrote the units during the compose; fail the build if a newer
# mdatp stops doing that, rather than shipping a Defender that never starts.
for unit in mdatp.service mde_netfilter_v2.service mde_netfilter_v2.socket; do
test -f "/usr/lib/systemd/system/${unit}"
done
# rpm-ostree keeps /opt content in /usr/lib/opt until the commit.
for root in /usr/lib/opt /opt; do
pp="${root}/microsoft/mdatp/conf/selinux_policies/out/mdatp_service.pp"
[[ -f "${pp}" ]] && break
done
semodule -n -i "${pp}"
rpm -q --qf '%{POSTIN}' mdatp > /usr/libexec/mdatp-postinst
chmod 0755 /usr/libexec/mdatp-firstboot /usr/libexec/mdatp-postinst
@@ -0,0 +1,6 @@
# Key-only SSH for local accounts (add keys to ~/.ssh/authorized_keys).
PubkeyAuthentication yes
PermitRootLogin no
PasswordAuthentication no
PermitEmptyPasswords no
KbdInteractiveAuthentication no
+4
View File
@@ -0,0 +1,4 @@
# Defender: first-boot setup, the daemon and its network filter.
enable mdatp-firstboot.service
enable mdatp.service
enable mde_netfilter_v2.socket
@@ -0,0 +1,3 @@
enable gdm.service
enable qemu-guest-agent.service
enable sshd.service
+20
View File
@@ -0,0 +1,20 @@
#!/bin/bash
# Runs in the target root during `rpm-ostree compose image` (edition 2024
# finalize.d hook). rpm-ostree relocates RPM content under /opt to
# /usr/lib/opt. With `opt-usrlocal: root` /opt is a plain directory in the
# image and nothing links it back, so link each vendor directory. Images on the
# default (/opt -> /var/opt, linked by tmpfiles.d) are left alone.
set -euo pipefail
root="${PWD}"
[[ -d "${root}/usr/lib/opt" ]] || exit 0
if [[ -L "${root}/opt" || ! -d "${root}/opt" ]]; then
exit 0
fi
for dir in "${root}"/usr/lib/opt/*; do
name="$(basename "${dir}")"
ln -sfn "../usr/lib/opt/${name}" "${root}/opt/${name}"
echo "Linked /opt/${name} -> /usr/lib/opt/${name}"
done
+17
View File
@@ -0,0 +1,17 @@
#!/usr/bin/env bash
# Finish the Defender (mdatp) install on first boot by running the package's
# own %post, saved at build time: it creates the machine GUID, state, logs and
# definitions database under /var and then enables and starts mdatp.service.
set -euo pipefail
MARKER=/var/lib/mdatp-firstboot.done
[[ -f "${MARKER}" ]] && exit 0
# mdatp.service only starts once the marker exists (10-firstboot.conf), and the
# %post starts it, so create the marker first and drop it again on failure.
touch "${MARKER}"
if ! bash /usr/libexec/mdatp-postinst 1; then
rm -f "${MARKER}"
exit 1
fi
+3
View File
@@ -0,0 +1,3 @@
# Don't start Defender before mdatp-firstboot.service has created its state.
[Unit]
ConditionPathExists=/var/lib/mdatp-firstboot.done
@@ -0,0 +1,15 @@
[Unit]
Description=Finish the Microsoft Defender for Endpoint install on first boot
Documentation=https://learn.microsoft.com/en-us/defender-endpoint/microsoft-defender-endpoint-linux
After=network-online.target
Wants=network-online.target
ConditionPathExists=!/var/lib/mdatp-firstboot.done
[Service]
Type=oneshot
ExecStart=/usr/libexec/mdatp-firstboot
RemainAfterExit=yes
TimeoutStartSec=15min
[Install]
WantedBy=multi-user.target
+7
View File
@@ -0,0 +1,7 @@
# Microsoft Edge, from the microsoft-edge repo (shared/repos/microsoft.repo).
# Conditional Access to Microsoft 365 web apps on Linux requires Edge.
repo-packages:
- repo: microsoft-edge
packages:
- microsoft-edge-stable
+19
View File
@@ -0,0 +1,19 @@
# packages.microsoft.com, limited with includepkgs to the packages the images
# use, so nothing else from the RHEL repo can replace a Fedora package.
[microsoft-rhel10]
name=Microsoft Production (RHEL 10)
baseurl=https://packages.microsoft.com/rhel/10/prod/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.microsoft.com/keys/microsoft-2025.asc
includepkgs=intune-portal microsoft-identity-broker mdatp
[microsoft-edge]
name=Microsoft Edge
baseurl=https://packages.microsoft.com/yumrepos/edge/
enabled=1
gpgcheck=1
gpgkey=https://packages.microsoft.com/keys/microsoft.asc
includepkgs=microsoft-edge-stable
+56
View File
@@ -0,0 +1,56 @@
# Minimal GNOME workstation, shared by the fedora-intune images. Include it
# from a manifest that sets `opt-usrlocal: root` (finalize.d/60-opt-links).
packages:
# Fedora integration normally provided by the upstream fedora.yaml (which we
# opt out of to avoid the Firefox RPM).
- fedora-release
- fedora-release-ostree-desktop
- fedora-flathub-remote
# GNOME desktop: gdm pulls gnome-session, gnome-settings-daemon,
# accountsservice, dconf and gnome-keyring-pam. gnome-initial-setup creates
# the first local user on first boot.
- gdm
- gnome-shell
- gnome-control-center
- gnome-initial-setup
- nautilus
- ptyxis
- pipewire
- pipewire-pulseaudio
- wireplumber
- xdg-desktop-portal-gnome
- xdg-user-dirs-gtk
- flatpak
# Session infrastructure base-atomic lacks with recommends off; see
# fedora-remote/custom.yaml.
- dbus-daemon
- systemd-pam
- mesa-dri-drivers
- mesa-libEGL
# The upstream initramfs config adds dracut's tpm2-tss module, which needs the
# tpm2 binary. fedora-remote gets it through Kanidm; list it explicitly here.
- tpm2-tools
# Proxmox guest integration (agent, console clipboard and resizing).
- qemu-guest-agent
- spice-vdagent
# Microsoft Edge is the browser (Conditional Access needs it).
exclude-packages:
- firefox
add-files:
- ["50-workstation.preset", "/usr/lib/systemd/system-preset/50-workstation.preset"]
# Key-only SSH for local accounts.
- ["10-workstation-sshd.conf", "/etc/ssh/sshd_config.d/10-workstation-sshd.conf"]
postprocess:
# uresourced breaks the GDM greeter's user manager; see fedora-remote.
- |
#!/usr/bin/env bash
set -xeuo pipefail
ln -sf /dev/null /etc/systemd/system/uresourced.service