Operating system provisioning standards
Criteria verified as of August 2026. Re-verify on the web before committing to anything (§8).
1. Scope and triggers
Covers how an operating system reaches a disk without anyone touching a key: network boot
(PXE/BIOS, UEFI HTTP Boot, iPXE, the DHCP→TFTP/HTTP→bootloader→installer chain), the answer file
of each installer, the golden image versus scripted install decision, the
tools that build the image, the provisioning orchestrators, remote power-on of
the hardware (Redfish/IPMI) and —what is almost always missing— the closing of the loop: the freshly
installed machine registers itself in the inventory and in the configuration manager, or the provisioning
is not finished.
Guiding principle: provisioning does not end when the installer reboots; it ends when the
host appears in the inventory, in the configuration manager and in monitoring. The second
principle: a reproducible install is proven by reinstalling, not by reading the profile.
Triggers: pxelinux.0, shimx64.efi, grubx64.efi, ipxe.efi, undionly.kpxe, dnsmasq.conf
with dhcp-boot/pxe-service, DHCP options 66/67, option 60 HTTPClient, DHCPv6 option
59 bootfile-url, ks.cfg, inst.ks=, %pre/%post/%packages, preseed.cfg, d-i,
autoinst.xml, Agama JSON profile, autoinstall.yaml, subiquity.autoinstallpath,
user-data/meta-data/vendor-data/network-config, ds=nocloud, seedfrom, cloud-localds,
.bu/.ign, butane, unattend.xml, boot.wim, WinPE/ADK, mkosi.conf, osbuild,
image-builder, bootc install to-disk, Packer, Cobbler, Foreman, MAAS, Tinkerbell
(Smee/Tootles/HookOS/Tink), ipmitool chassis bootdev pxe, Redfish ComputerSystem.Boot,
"install 40 identical servers", "the kickstart used to work and now it doesn't".
Not applicable: see onprem-standards (platform umbrella and routing table §1.2; its
§1.3 invariants win, in particular no snowflakes and every server rebuildable from
code — this skill is the mechanism that makes that true), cmdb-inventory-standards (the
register where the new host lands: data model, stable identifier, reconciliation —
here only the hook that registers it), server-hardware-standards (the hardware and its BMC: firmware,
management network, warranty — here only Redfish/IPMI as a boot trigger),
iac-standards (Ansible/Terraform and the code that configures the machine after the first
boot; the exact boundary: up to the first login this skill wins, from the first login
onwards iac-standards wins — and a Kickstart %post acting as a configuration manager
is a vetoed antipattern, §7), linux-administration-standards (the already-installed OS),
rhel-fedora-standards (rpm-ostree, bootc, image mode and dnf as the ecosystem of the
Red Hat family; here bootc install only as an installation method), linux-hardening-standards (the
CIS/STIG baseline over what is installed: a hardened golden image does not replace measuring the
baseline), proxmox-ve-standards, libvirt-kvm-standards, vmware-standards (the VM
template and cloning are theirs: qm clone, virt-sysprep, vSphere templates; here the cloud-init
that customises it and the installer that creates it), windows-server-ad-standards (domain and GPO),
macos-fleet-standards (DEP/ADE and MDM: Apple provisioning does not go through PXE),
cicd-standards (the pipeline that builds the image), network-troubleshooting-standards ("PXE
does not boot" as reactive diagnosis), bcdr-standards (rebuild as a recovery
strategy), homelab-standards (proportionality: a cloud-localds and an ISO are enough, do not stand up
Foreman), datacenter-facilities-standards (rack, power and the physical
journey of the server before an IP exists), hpc-standards
(mass node provisioning, diskless boot, xCAT/Warewulf).
2. Default decisions
Verify the latest version on the web before pinning it in a real project (§8).
| Decision |
Default |
Reason / justifiable alternative |
| Boot transport |
UEFI HTTP Boot (option 60 HTTPClient + option 67 with a full URI) |
TFTP has neither flow control nor integrity and chokes on large images. PXE/TFTP only for firmware that does not support HTTP Boot; legacy BIOS only on hardware that will not boot any other way |
| Boot chain |
iPXE chainloaded from the firmware, with an embedded and signed script |
It gives you HTTP(S), scripting, retries and decisions by MAC/UUID; plain pxelinux does not. Alternative: shim+grub when Secure Boot demands the chain signed by the distribution (§5) |
| Minimum server |
dnsmasq (DHCP proxy + TFTP) + an HTTP serving the artifacts |
Enough and auditable for dozens of hosts. dnsmasq in proxy-DHCP mode if the corporate DHCP is not yours |
| Answer file |
The distribution's native one: Kickstart (RHEL/Fedora), preseed (Debian), Agama JSON (SLES 16+), autoinstall.yaml (Ubuntu), Butane→Ignition (CoreOS/RHCOS), unattend.xml (Windows) |
There is no common abstraction worth having; multi-distro wrappers break at every release |
| SUSE |
Agama (JSON/Jsonnet profile) |
SLES 16 replaces YaST/AutoYaST with Agama; AutoYaST does not migrate 1:1 (§8). On SLES 15 AutoYaST still applies |
| VM customisation in cloud/template |
cloud-init, NoCloud datasource for on-prem |
De facto standard. Ignition when the OS is immutable (CoreOS/RHCOS): it runs once in the initramfs and does not reconfigure on every boot |
| Image versus install |
Image built in a pipeline for a homogeneous, ephemeral fleet; scripted install for heterogeneous, long-lived hardware |
Rule: if you are going to reinstall more than you are going to patch, image; if not, install + configuration manager |
| Image builder |
mkosi (declarative, from the systemd project, UKI out of the box), osbuild's image-builder in the RHEL world, Packer when the target is a hypervisor or a cloud |
bootc-image-builder has an announced deprecation towards image-builder (§8) |
| Image OS |
bootc / image mode when the fleet tolerates the bootable-container model |
Upstream v1.16.7 (4-Aug-2026), weekly cadence; the repository lives at bootc-dev/bootc |
| Orchestrator |
Foreman with a mixed fleet and a long lifecycle; MAAS if the estate is Ubuntu and you want machines as a resource; Tinkerbell if the consumer is Kubernetes/Cluster API |
Cobbler only if it is already there: still maintained but has spent years in the 3.3.x→4.0.0 transition. None of them if there are fewer than ~20 hosts: dnsmasq + HTTP + repo |
| Power-on and boot selection |
Redfish (Boot/BootSourceOverrideTarget) |
ipmitool only where there is no Redfish. BMC detail and its network: server-hardware-standards |
3. Structure and conventions
- One provisioning repository, versioned, with: profiles by role (not by host), answer file
templates, iPXE scripts, and the artifact manifest (ISO/kernel/initrd) with
its checksum. Everything the boot server serves comes out of there.
- The profile is per role and the per-host difference is data, not template. Hostname, IP, VLAN, role and
owner are queried from the inventory at provisioning time (by MAC or by DMI serial
number), not copied into 40 files. One profile per host is the first symptom of a snowflake.
user-data, meta-data, vendor-data and network-config are four different things and
confusing them is failure no. 1 with cloud-init. Literal from the 26.2 documentation: "Cloud-init
discovers four types of configuration at runtime" (the four above, the runtime
configuration) and "The purpose of the discovery configuration is to tell cloud-init where it can find
the runtime configurations" (ds=nocloud, seedfrom, DMI or the kernel command line: the discovery
configuration). Operational consequences: the instance identity (instance-id) goes in
meta-data and changing it re-runs the per-instance modules; the network cannot be
changed from user-data (it goes in network-config, in the system config or on the kernel
command line); vendor-data belongs to the platform provider, not to you.
- NoCloud without a server: seed on an ISO/vfat with
user-data, meta-data and optionally
network-config (cloud-localds -N). With a server: ds=nocloud;s=https://…/ — and seedfrom
supports __dmi.varname__ expansion, which is the clean way to serve configuration by chassis
serial number without per-host templates.
- Butane/Ignition: you write
.bu and transpile it with butane --strict; the .ign is a
generated artifact and is not edited by hand. Pin variant: fcos and a stabilised version
(as of Aug 2026 the latest stable is 1.7.0 → Ignition 3.6.0; 1.8.0 is experimental and the
documentation itself warns: "Do not use experimental specifications for anything beyond development
and testing as they are subject to change without warning or announcement").
- Windows:
unattend.xml with Configuration Manager OSD or your own WinPE from the ADK. MDT has been
retired since 6-Jan-2026 (no updates, downloads withdrawn) and WDS no longer supports
deploying Windows 11 or Server 2025 with the boot.wim from the installation media; WDS PXE
still works with your own boot image (§5 for the security side).
- Deterministic names and partitioning: explicit partitioning scheme in the profile (never
"use the whole disk" on hardware with an array attached), disk selection by WWN/serial and not by
/dev/sda, and predictable interface names. An installer that picks by enumeration order
installs on the wrong LUN sooner or later.
4. Validation: how you know it works
- Gate 1 — syntax, on every commit:
ksvalidator (Kickstart), butane --strict,
cloud-init schema --config-file, autoinstall.yaml schema validation, mkosi in build
mode. Cheap and it catches half the failures.
- Gate 2 — real install on an ephemeral VM, on every profile change: the VM is brought up,
provisioned from scratch and assertions are checked (users, network, partitioning, packages, services,
inventory registration). Without this gate, the profile is validated in production.
- Gate 3 — install on representative hardware, per distribution release: firmware, NIC,
controller and disk change the outcome. A profile validated only on a VM is not validated for
bare metal.
- Periodic reinstall as an exercise: one host of each role is reinstalled from scratch in an agreed
window. It is the only proof that "rebuildable from code" is true and that the distribution's
artifact is still available.
- Provisioning time measured (from power-on to host in inventory and monitoring):
it decides whether the image model is worth it, and it makes a DR plan credible.
5. Security: network boot is not authenticated
The critical point of this skill. The DHCP→TFTP→bootloader sequence authenticates nothing by
default: anyone in the same broadcast domain can answer DHCP before you do and serve
their own bootloader. Controls, in order:
- Isolated provisioning network (its own VLAN, no internet egress, no users). It is the
primary control; the rest are defence in depth.
- DHCP snooping on the access switch: it blocks unauthorised DHCP servers. And it breaks your
provisioning if your server sits on an untrusted port — the conflict is real and is
resolved by declaring the boot server's port trusted, not by disabling snooping.
- HTTPS instead of TFTP/HTTP for everything you can (UEFI HTTPS Boot requires the root
certificate enrolled in the firmware) and verified integrity: artifact checksum in
the iPXE script.
- Secure Boot active during installation too:
shim→grub→kernel chain signed.
Calendar warning, Aug 2026: the Microsoft Corporation KEK CA 2011 expired on 27-Jun-2026 and
the Windows Production PCA 2011 expires in October 2026; without the 2023 CAs enrolled (KEK
2K CA 2023, UEFI CA 2023, Option ROM UEFI CA 2023) the machine still boots but can no longer
receive DB/DBX updates nor trust binaries signed with the new keys. It affects
Linux: new shim is signed with the 2023 CA. Check the state per host before retiring
the 2011 CA and treat it as a firmware task (server-hardware-standards).
- FORBIDDEN to serve secrets in
user-data, in the Kickstart or in unattend.xml. They travel in the clear over
the network, they stay in /var/lib/cloud/instance/ and in /root/anaconda-ks.cfg, and they appear in the installer's
logs. What is delivered at first boot is a single-use, short-lived, minimum-scope
credential (Ansible/Vault/Foreman registration token), and the real secret is
obtained afterwards from the secrets manager. A public SSH key, yes; a private one, a password
or a long-lived token, never.
- Verified case study: CVE-2026-0386 (WDS, CVSS 3.1 = 7.5, AV:A) — the
unattend.xml
travelled over an unauthenticated RPC channel and was accessible through the RemoteInstall share without
authentication, allowing it to be intercepted, embedded credentials to be stolen or code to be injected that
runs during deployment. Microsoft disabled hands-free deployment by default with
the 14-Apr-2026 updates (phase 2; phase 1 on 13-Jan-2026). It is not a Windows flaw:
it is exactly the threat model of any badly segmented provisioning server.
- Installation passwords:
rootpw hashed with a modern algorithm or, better, no root
password and SSH key only; delete the answer file from the installed system in the %post.
Sign your iPXE script: a generic iPXE downloaded from the internet is code with no provenance in your
boot path.
6. Closing the loop: the newborn host registers itself
Provisioning must end in three automatic registrations, performed by the host itself at its
first boot and not by a person:
- Inventory: creation or update of the asset with its stable identifier (serial number
/ DMI UUID, not the hostname nor the IP), MAC(s), role and date. Model and reconciliation:
cmdb-inventory-standards.
- Configuration manager: registration against Ansible/Foreman/Salt with a single-use token, and
a first full convergence. From here on
iac-standards wins.
- Observability: registration in metrics discovery and log shipping. The
onprem-standards
invariant is literal: no telemetry, no production.
And the inverse closing, which almost nobody implements: when the host is retired it is deregistered in all three
places. An asset that provisioned itself and was retired by hand leaves ghosts in the inventory, orphaned
alerts and live credentials.
7. Sustainability and prohibitions
Cadence: the base artifact (ISO, kernel/initrd, bootc image) is refreshed at least with every minor
release of the distribution; a year-old golden image is hundreds of patches that get
applied at the first boot of every host. Check every release that the profiles still validate: the
installers change keys between major versions with no friendly warning.
- ❌ FORBIDDEN an answer file with long-lived secrets (§5).
- ❌ FORBIDDEN one profile per host when the difference is four data points: they go to the inventory.
- ❌ Using the Kickstart
%post (or cloud-init's runcmd) as a configuration manager. Its
job ends at "it boots, it has network and identity, and it calls the configuration manager".
- ❌ A golden image built by hand from a VM "that was already fine". If it does not come out of a versioned
file and a pipeline, it is not golden: it is a snowflake replicated N times.
- ❌ Boot server on the user VLAN or with internet egress.
- ❌ Disabling DHCP snooping "so that PXE works". You declare the right port trusted.
- ❌ Disabling Secure Boot to install and "we'll enable it later". It never gets enabled.
- ❌ Pinning an experimental Butane spec version in production (§3).
- ❌ Depending on MDT (retired) or on WDS with media
boot.wim for Windows 11 / Server 2025.
- ❌ Depending on WDS hands-free deployment by re-enabling the CVE-2026-0386 override.
- ❌ Selecting the install disk by
/dev/sdX on hardware with external storage attached.
- ❌ Declaring "rebuildable from code" without ever having reinstalled that role (§4).
- ❌ Considering provisioning finished without the three registrations of §6.
8. Mandatory web verification
Before pinning anything, check on the web —with a literal quote, not an automatic summary:
- cloud-init: current version (as of Aug 2026 the published documentation is 26.2, at
docs.cloud-init.io) and, above all, the NoCloud page: the discovery /
runtime configuration nomenclature is recent and the ds= syntax has changed between versions. Declared
gap: it was not possible to verify the exact status (valid, obsolete or withdrawn) of ds=nocloud-net
nor of the old seedfrom form — the current page only documents ds=nocloud. Check it
against the version your distribution packages, which usually lags upstream.
- Butane/Ignition: the table at
coreos.github.io/butane/specs/ changes with every stabilisation.
As of Aug 2026: stable fcos 1.7.0 → Ignition 3.6.0; experimental 1.8.0 → 3.7.0-experimental.
- bootc and image-builder:
bootc version (repository at bootc-dev/bootc, not at
containers/) and, critically, the bootc-image-builder deprecation notice at
osbuild.org/docs/bootc/deprecation-notice/, whose calendar is expressed in RHEL versions
(9.8/10.2 → 9.9/10.3 → RHEL 11), not in dates. Verify which dates those correspond to today.
- SUSE: that Agama is still the SLES 16+ installer and which AutoYaST constructs do not
migrate; SUSE documents high compatibility but explicitly not 1:1.
- Windows: Microsoft's guidance on CVE-2026-0386 (13-Jan and 14-Apr-2026 phases) and the
current matrix of which versions WDS supports. Also confirm the retirement status of MDT
(announced as immediate on 6-Jan-2026).
- Secure Boot: status of the 2011 CA calendar (KEK CA 2011 expired on 27-Jun-2026;
Windows Production PCA 2011 in Oct-2026) and the availability of firmware with the 2023 CAs for
your specific server model. On out-of-support hardware it may never arrive: that is a
renewal criterion, not a detail.
- Orchestrators: current version and support of Foreman (short cycle: only two versions
supported at a time), MAAS (3.7 requires PostgreSQL 16) and Cobbler (3.3.x→4.0.0 transition still
open as of May-2026). Tinkerbell is still in CNCF Sandbox, not incubation: weigh it as an
adoption risk. Declared gap: the licences of Cobbler, Foreman, MAAS and Tinkerbell were not
verified by reading the raw
LICENSE. Read them before citing them.
- Server firmware: whether it supports UEFI HTTP(S) Boot and with which limitations (download
size, TLS, CA enrolment). It varies by manufacturer and by BIOS version, and it is what decides whether
you can abandon TFTP.
If the web contradicts this document, the web wins — flag the discrepancy.
1---2name: os-provisioning-standards3description: Unattended OS installation on bare metal and VMs — network boot and the answer file that drives the installer. Use when configuring PXE or UEFI HTTP Boot with dnsmasq, pxelinux.0, syslinux, grubx64.efi, shimx64.efi, iPXE (undionly.kpxe, ipxe.efi, chainloading, embedded scripts), DHCP option 66/67, option 60 HTTPClient vendor class or DHCPv6 option 59 bootfile-url, TFTP versus HTTP boot, writing a Kickstart ks.cfg with %packages/%pre/%post and inst.ks=, a Debian preseed.cfg with d-i directives, a SUSE Agama JSON profile replacing AutoYaST autoinst.xml, Ubuntu autoinstall.yaml or subiquity.autoinstallpath, cloud-init NoCloud seed ISOs and the user-data / meta-data / vendor-data / network-config split with ds=nocloud and seedfrom, Butane .bu transpiled to Ignition .ign for Fedora CoreOS or RHCOS, Windows unattend.xml with WDS or Configuration Manager OSD after MDT retirement, golden images versus scripted installs, building images with mkosi, osbuild, image-builder or Packer, installing an image-mode host to dis4---56# Operating system provisioning standards78Criteria verified as of **August 2026**. Re-verify on the web before committing to anything (§8).910## 1. Scope and triggers1112Covers **how an operating system reaches a disk without anyone touching a key**: network boot13(PXE/BIOS, UEFI HTTP Boot, iPXE, the DHCP→TFTP/HTTP→bootloader→installer chain), the answer file14of each installer, the **golden image versus scripted install** decision, the15tools that build the image, the provisioning orchestrators, remote power-on of16the hardware (Redfish/IPMI) and —what is almost always missing— the **closing of the loop**: the freshly17installed machine registers itself in the inventory and in the configuration manager, or the provisioning18is not finished.1920**Guiding principle**: **provisioning does not end when the installer reboots; it ends when the21host appears in the inventory, in the configuration manager and in monitoring.** The second22principle: **a reproducible install is proven by reinstalling**, not by reading the profile.2324Triggers: `pxelinux.0`, `shimx64.efi`, `grubx64.efi`, `ipxe.efi`, `undionly.kpxe`, `dnsmasq.conf`25with `dhcp-boot`/`pxe-service`, DHCP options **66/67**, **option 60 `HTTPClient`**, DHCPv6 **option2659 `bootfile-url`**, `ks.cfg`, `inst.ks=`, `%pre`/`%post`/`%packages`, `preseed.cfg`, `d-i`,27`autoinst.xml`, **Agama** JSON profile, `autoinstall.yaml`, `subiquity.autoinstallpath`,28`user-data`/`meta-data`/`vendor-data`/`network-config`, `ds=nocloud`, `seedfrom`, `cloud-localds`,29`.bu`/`.ign`, `butane`, `unattend.xml`, `boot.wim`, WinPE/ADK, `mkosi.conf`, `osbuild`,30`image-builder`, `bootc install to-disk`, Packer, Cobbler, Foreman, MAAS, Tinkerbell31(Smee/Tootles/HookOS/Tink), `ipmitool chassis bootdev pxe`, Redfish `ComputerSystem.Boot`,32"install 40 identical servers", "the kickstart used to work and now it doesn't".3334**Not applicable**: see `onprem-standards` (**platform umbrella and routing table §1.2**; its35§1.3 invariants win, in particular *no snowflakes* and *every server rebuildable from36code* — **this skill is the mechanism that makes that true**), `cmdb-inventory-standards` (**the37register where the new host lands**: data model, stable identifier, reconciliation —38here only the *hook* that registers it), `server-hardware-standards` (the hardware and its BMC: firmware,39management network, warranty — **here only Redfish/IPMI as a boot trigger**),40`iac-standards` (**Ansible/Terraform and the code that configures the machine *after* the first41boot**; the exact boundary: **up to the first login this skill wins, from the first login42onwards `iac-standards` wins** — and a Kickstart `%post` acting as a configuration manager43is a vetoed antipattern, §7), `linux-administration-standards` (the already-installed OS),44`rhel-fedora-standards` (**`rpm-ostree`, `bootc`, image mode and `dnf` as the ecosystem of the45Red Hat family**; here `bootc install` only as an installation method), `linux-hardening-standards` (the46CIS/STIG baseline over what is installed: **a hardened golden image does not replace measuring the47baseline**), `proxmox-ve-standards`, `libvirt-kvm-standards`, `vmware-standards` (**the VM48template and cloning are theirs**: `qm clone`, `virt-sysprep`, vSphere templates; here the `cloud-init`49that customises it and the installer that creates it), `windows-server-ad-standards` (domain and GPO),50`macos-fleet-standards` (DEP/ADE and MDM: **Apple provisioning does not go through PXE**),51`cicd-standards` (the pipeline that builds the image), `network-troubleshooting-standards` (**"PXE52does not boot" as reactive diagnosis**), `bcdr-standards` (rebuild as a recovery53strategy), `homelab-standards` (proportionality: a `cloud-localds` and an ISO are enough, do not stand up54Foreman), `datacenter-facilities-standards` (rack, power and the physical55journey of the server before an IP exists), `hpc-standards`56(mass node provisioning, diskless boot, `xCAT`/Warewulf).5758## 2. Default decisions5960> Verify the latest version on the web before pinning it in a real project (§8).6162| Decision | Default | Reason / justifiable alternative |63|---|---|---|64| Boot transport | **UEFI HTTP Boot** (option 60 `HTTPClient` + option 67 with a **full URI**) | TFTP has neither flow control nor integrity and chokes on large images. PXE/TFTP only for firmware that does not support HTTP Boot; **legacy BIOS only on hardware that will not boot any other way** |65| Boot chain | **iPXE** chainloaded from the firmware, with an embedded and signed script | It gives you HTTP(S), scripting, retries and decisions by MAC/UUID; plain `pxelinux` does not. Alternative: `shim`+`grub` when Secure Boot demands the chain signed by the distribution (§5) |66| Minimum server | `dnsmasq` (DHCP proxy + TFTP) + an HTTP serving the artifacts | Enough and auditable for dozens of hosts. `dnsmasq` in **proxy-DHCP mode** if the corporate DHCP is not yours |67| Answer file | The **distribution's native one**: Kickstart (RHEL/Fedora), preseed (Debian), **Agama JSON** (SLES 16+), `autoinstall.yaml` (Ubuntu), Butane→Ignition (CoreOS/RHCOS), `unattend.xml` (Windows) | There is no common abstraction worth having; multi-distro wrappers break at every release |68| SUSE | **Agama** (JSON/Jsonnet profile) | **SLES 16 replaces YaST/AutoYaST with Agama**; AutoYaST does **not** migrate 1:1 (§8). On SLES 15 AutoYaST still applies |69| VM customisation in cloud/template | **cloud-init**, **NoCloud** datasource for on-prem | De facto standard. **Ignition** when the OS is immutable (CoreOS/RHCOS): it runs once in the initramfs and does not reconfigure on every boot |70| Image versus install | **Image built in a pipeline** for a homogeneous, ephemeral fleet; **scripted install** for heterogeneous, long-lived hardware | Rule: if you are going to reinstall more than you are going to patch, image; if not, install + configuration manager |71| Image builder | `mkosi` (declarative, from the systemd project, UKI out of the box), **osbuild's `image-builder`** in the RHEL world, Packer when the target is a hypervisor or a cloud | **`bootc-image-builder` has an announced deprecation** towards `image-builder` (§8) |72| Image OS | `bootc` / image mode when the fleet tolerates the bootable-container model | Upstream **v1.16.7 (4-Aug-2026)**, weekly cadence; **the repository lives at `bootc-dev/bootc`** |73| Orchestrator | **Foreman** with a mixed fleet and a long lifecycle; **MAAS** if the estate is Ubuntu and you want machines as a resource; **Tinkerbell** if the consumer is Kubernetes/Cluster API | **Cobbler** only if it is already there: still maintained but has spent years in the 3.3.x→4.0.0 transition. None of them if there are fewer than ~20 hosts: `dnsmasq` + HTTP + repo |74| Power-on and boot selection | **Redfish** (`Boot/BootSourceOverrideTarget`) | `ipmitool` only where there is no Redfish. BMC detail and its network: `server-hardware-standards` |7576## 3. Structure and conventions7778- **One provisioning repository**, versioned, with: profiles by role (not by host), answer file79 templates, iPXE scripts, and the artifact manifest (ISO/kernel/initrd) **with80 its checksum**. Everything the boot server serves comes out of there.81- **The profile is per role and the per-host difference is data, not template.** Hostname, IP, VLAN, role and82 owner are queried from the inventory at provisioning time (by MAC or by DMI serial83 number), not copied into 40 files. One profile per host is the first symptom of a *snowflake*.84- **`user-data`, `meta-data`, `vendor-data` and `network-config` are four different things** and85 confusing them is failure no. 1 with cloud-init. Literal from the 26.2 documentation: *"Cloud-init86 discovers four types of configuration at runtime"* (the four above, the **runtime87 configuration**) and *"The purpose of the discovery configuration is to tell cloud-init where it can find88 the runtime configurations"* (`ds=nocloud`, `seedfrom`, DMI or the kernel command line: the **discovery89 configuration**). Operational consequences: the instance identity (`instance-id`) goes in90 `meta-data` and **changing it re-runs the `per-instance` modules**; the network **cannot be91 changed from `user-data`** (it goes in `network-config`, in the system config or on the kernel92 command line); `vendor-data` belongs to the platform provider, not to you.93- **NoCloud without a server**: seed on an ISO/vfat with `user-data`, `meta-data` and optionally94 `network-config` (`cloud-localds -N`). With a server: `ds=nocloud;s=https://…/` — and `seedfrom`95 supports `__dmi.varname__` expansion, which is the clean way to **serve configuration by chassis96 serial number** without per-host templates.97- **Butane/Ignition**: you write `.bu` and transpile it with `butane --strict`; **the `.ign` is a98 generated artifact and is not edited by hand**. Pin `variant: fcos` and a **stabilised version**99 (as of Aug 2026 the latest stable is **1.7.0 → Ignition 3.6.0**; 1.8.0 is experimental and the100 documentation itself warns: *"Do not use experimental specifications for anything beyond development101 and testing as they are subject to change without warning or announcement"*).102- **Windows**: `unattend.xml` with Configuration Manager OSD or your own WinPE from the ADK. **MDT has been103 retired since 6-Jan-2026** (no updates, downloads withdrawn) and **WDS no longer supports104 deploying Windows 11 or Server 2025 with the `boot.wim` from the installation media**; WDS PXE105 still works with your own boot image (§5 for the security side).106- **Deterministic names and partitioning**: explicit partitioning scheme in the profile (never107 "use the whole disk" on hardware with an array attached), disk selection by WWN/serial and not by108 `/dev/sda`, and predictable interface names. An installer that picks by enumeration order109 installs on the wrong LUN sooner or later.110111## 4. Validation: how you know it works112113- **Gate 1 — syntax, on every commit**: `ksvalidator` (Kickstart), `butane --strict`,114 `cloud-init schema --config-file`, `autoinstall.yaml` schema validation, `mkosi` in build115 mode. Cheap and it catches half the failures.116- **Gate 2 — real install on an ephemeral VM, on every profile change**: the VM is brought up,117 provisioned from scratch and assertions are checked (users, network, partitioning, packages, services,118 inventory registration). Without this gate, the profile is validated in production.119- **Gate 3 — install on representative hardware, per distribution release**: firmware, NIC,120 controller and disk change the outcome. A profile validated only on a VM **is not validated for121 bare metal**.122- **Periodic reinstall as an exercise**: one host of each role is reinstalled from scratch in an agreed123 window. It is the only proof that "rebuildable from code" is true and that the distribution's124 artifact is still available.125- **Provisioning time measured** (from power-on to host in inventory and monitoring):126 it decides whether the image model is worth it, and it makes a DR plan credible.127128## 5. Security: network boot is not authenticated129130**The critical point of this skill.** The DHCP→TFTP→bootloader sequence **authenticates nothing by131default**: anyone in the same broadcast domain can answer DHCP before you do and serve132their own bootloader. Controls, in order:133134- **Isolated provisioning network** (its own VLAN, no internet egress, no users). It is the135 primary control; the rest are defence in depth.136- **DHCP snooping** on the access switch: it blocks unauthorised DHCP servers. **And it breaks your137 provisioning if your server sits on an untrusted port** — the conflict is real and is138 resolved by declaring the boot server's port *trusted*, not by disabling snooping.139- **HTTPS instead of TFTP/HTTP** for everything you can (UEFI HTTPS Boot requires the root140 certificate enrolled in the firmware) and **verified integrity**: artifact checksum in141 the iPXE script.142- **Secure Boot active during installation too**: `shim`→`grub`→kernel chain signed.143 **Calendar warning, Aug 2026**: the **Microsoft Corporation KEK CA 2011 expired on 27-Jun-2026** and144 the **Windows Production PCA 2011 expires in October 2026**; without the 2023 CAs enrolled (KEK145 2K CA 2023, UEFI CA 2023, Option ROM UEFI CA 2023) the machine **still boots but can no longer146 receive DB/DBX updates nor trust binaries signed with the new keys**. It affects147 Linux: new `shim` is signed with the 2023 CA. **Check the state per host before retiring148 the 2011 CA** and treat it as a firmware task (`server-hardware-standards`).149- **FORBIDDEN to serve secrets in `user-data`, in the Kickstart or in `unattend.xml`.** They travel in the clear over150 the network, they stay in `/var/lib/cloud/instance/` and in `/root/anaconda-ks.cfg`, and they appear in the installer's151 logs. What is delivered at first boot is a **single-use, short-lived, minimum-scope152 credential** (Ansible/Vault/Foreman registration token), and the real secret is153 obtained afterwards from the secrets manager. A public SSH key, yes; a private one, a password154 or a long-lived token, never.155- **Verified case study**: **CVE-2026-0386** (WDS, CVSS 3.1 = 7.5, AV:A) — the `unattend.xml`156 travelled over an unauthenticated RPC channel and was accessible through the `RemoteInstall` share without157 authentication, allowing it to be intercepted, embedded credentials to be stolen or code to be injected that158 runs during deployment. Microsoft **disabled *hands-free* deployment by default** with159 the **14-Apr-2026** updates (phase 2; phase 1 on 13-Jan-2026). It is not a Windows flaw:160 it is exactly the threat model of any badly segmented provisioning server.161- **Installation passwords**: `rootpw` hashed with a modern algorithm or, better, **no root162 password and SSH key only**; delete the answer file from the installed system in the `%post`.163 **Sign your iPXE script**: a generic iPXE downloaded from the internet is code with no provenance in your164 boot path.165166## 6. Closing the loop: the newborn host registers itself167168Provisioning **must end in three automatic registrations**, performed by the host itself at its169first boot and not by a person:1701711. **Inventory**: creation or update of the asset with its **stable identifier** (serial number172 / DMI UUID, **not the hostname nor the IP**), MAC(s), role and date. Model and reconciliation:173 `cmdb-inventory-standards`.1742. **Configuration manager**: registration against Ansible/Foreman/Salt with a **single-use token**, and175 a first full convergence. From here on `iac-standards` wins.1763. **Observability**: registration in metrics discovery and log shipping. The `onprem-standards`177 invariant is literal: *no telemetry, no production*.178179**And the inverse closing, which almost nobody implements**: when the host is retired it is deregistered in all three180places. An asset that provisioned itself and was retired by hand leaves ghosts in the inventory, orphaned181alerts and live credentials.182183## 7. Sustainability and prohibitions184185Cadence: the base artifact (ISO, kernel/initrd, bootc image) is **refreshed at least with every minor186release** of the distribution; a year-old golden image is hundreds of patches that get187applied at the first boot of every host. Check every release that the profiles still validate: the188installers change keys between major versions with no friendly warning.189190- ❌ **FORBIDDEN** an answer file with long-lived secrets (§5).191- ❌ **FORBIDDEN** one profile per host when the difference is four data points: they go to the inventory.192- ❌ Using the Kickstart `%post` (or cloud-init's `runcmd`) **as a configuration manager**. Its193 job ends at "it boots, it has network and identity, and it calls the configuration manager".194- ❌ A golden image built by hand from a VM "that was already fine". If it does not come out of a versioned195 file and a pipeline, it is not golden: it is a *snowflake* replicated N times.196- ❌ Boot server on the user VLAN or with internet egress.197- ❌ Disabling DHCP snooping "so that PXE works". You declare the right port trusted.198- ❌ Disabling Secure Boot to install and "we'll enable it later". It never gets enabled.199- ❌ Pinning an **experimental** Butane spec version in production (§3).200- ❌ Depending on MDT (retired) or on WDS with media `boot.wim` for Windows 11 / Server 2025.201- ❌ Depending on WDS *hands-free* deployment by re-enabling the CVE-2026-0386 override.202- ❌ Selecting the install disk by `/dev/sdX` on hardware with external storage attached.203- ❌ Declaring "rebuildable from code" without ever having reinstalled that role (§4).204- ❌ Considering provisioning finished without the three registrations of §6.205206## 8. Mandatory web verification207208Before pinning anything, check on the web —with a literal quote, not an automatic summary:2092101. **cloud-init**: current version (as of Aug 2026 the published documentation is **26.2**, at211 `docs.cloud-init.io`) and, above all, the **NoCloud** page: the *discovery /212 runtime configuration* nomenclature is recent and the `ds=` syntax has changed between versions. **Declared213 gap: it was not possible to verify the exact status (valid, obsolete or withdrawn) of `ds=nocloud-net`214 nor of the old `seedfrom` form — the current page only documents `ds=nocloud`.** Check it215 against the version *your* distribution packages, which usually lags upstream.2162. **Butane/Ignition**: the table at `coreos.github.io/butane/specs/` changes with every stabilisation.217 As of Aug 2026: stable **fcos 1.7.0 → Ignition 3.6.0**; experimental 1.8.0 → 3.7.0-experimental.2183. **bootc and image-builder**: `bootc` version (**repository at `bootc-dev/bootc`**, not at219 `containers/`) and, critically, the **`bootc-image-builder` deprecation notice** at220 `osbuild.org/docs/bootc/deprecation-notice/`, whose calendar is expressed in RHEL versions221 (9.8/10.2 → 9.9/10.3 → RHEL 11), not in dates. Verify which dates those correspond to today.2224. **SUSE**: that Agama is still the SLES 16+ installer and **which AutoYaST constructs do not223 migrate**; SUSE documents *high* compatibility but explicitly **not 1:1**.2245. **Windows**: Microsoft's guidance on **CVE-2026-0386** (13-Jan and 14-Apr-2026 phases) and the225 current matrix of which versions WDS supports. Also confirm the retirement status of MDT226 (announced as immediate on 6-Jan-2026).2276. **Secure Boot**: status of the 2011 CA calendar (KEK CA 2011 expired on 27-Jun-2026;228 Windows Production PCA 2011 in Oct-2026) and **the availability of firmware with the 2023 CAs for229 your specific server model**. On out-of-support hardware it may never arrive: that is a230 renewal criterion, not a detail.2317. **Orchestrators**: current version and support of Foreman (short cycle: only two versions232 supported at a time), MAAS (**3.7 requires PostgreSQL 16**) and Cobbler (3.3.x→4.0.0 transition still233 open as of May-2026). **Tinkerbell is still in CNCF *Sandbox***, not incubation: weigh it as an234 adoption risk. **Declared gap: the licences of Cobbler, Foreman, MAAS and Tinkerbell were not235 verified by reading the raw `LICENSE`.** Read them before citing them.2368. **Server firmware**: whether it supports **UEFI HTTP(S) Boot** and with which limitations (download237 size, TLS, CA enrolment). It varies by manufacturer and by BIOS version, and it is what decides whether238 you can abandon TFTP.239240If the web contradicts this document, **the web wins** — flag the discrepancy.