docs: design notes for a Redfish/IPMI BMC driver
No code yet. The README explains why one Redfish driver with vendor quirk modules beats a Supermicro-only IPMI driver, and keeps IPMI over LAN as a read-only fallback. docs/ holds a draft for a new ManagementController role base in napalm-device-types, the getter-to-resource map, the first test device (Supermicro X10DRL-i, Redfish firmware 3.91), the security points (IPMI RAKP hash disclosure, power control, credentials) and the test plan with DMTF mockups and fixtures to record.
This commit is contained in:
commit
5f8a4ef975
9 files changed
+557
No files matched your search
@@ -0,0 +1,44 @@
|
||||
# Getters mapped to Redfish resources
|
||||
|
||||
Paths use the usual single-member IDs (`Systems/1`, `Managers/1`, `Chassis/1`); the driver
|
||||
must follow the collections instead of assuming IDs, because vendors differ (Dell uses
|
||||
`System.Embedded.1`, HPE uses `1`, Supermicro uses `1`).
|
||||
|
||||
## Authentication
|
||||
|
||||
- **Session:** `POST /redfish/v1/SessionService/Sessions` with user and password returns
|
||||
an `X-Auth-Token` header and the session's URI. Use the token, `DELETE` the session on
|
||||
close. BMCs allow few concurrent sessions, so leaking them locks out the web UI.
|
||||
- **Basic auth** works on most services and is the fallback.
|
||||
- Self-signed certificates are the norm; verification is configurable per device.
|
||||
|
||||
## NAPALM getters
|
||||
|
||||
| Getter | Resource | Fields |
|
||||
|---|---|---|
|
||||
| `get_facts` | `Systems/{id}`, `Managers/{id}` | `Manufacturer`, `Model`, `SerialNumber`, `HostName`; BMC `FirmwareVersion` as `os_version`. `uptime` is not in Redfish (return -1). `interface_list` from `Managers/{id}/EthernetInterfaces` |
|
||||
| `get_interfaces` | `Managers/{id}/EthernetInterfaces/*` | BMC ports: `MACAddress`, `SpeedMbps`, `LinkStatus`, `InterfaceEnabled` |
|
||||
| `get_interfaces_ip` | same | `IPv4Addresses`, `IPv6Addresses` |
|
||||
| `get_environment` | `Chassis/{id}/Thermal` (`Temperatures[]`, `Fans[]`), `Chassis/{id}/Power` (`PowerSupplies[]`, `PowerControl[].PowerConsumedWatts`) | Newer services move these to `ThermalSubsystem`, `PowerSubsystem` and `Sensors`; read whichever exists. CPU and memory of the host OS are unknown to a BMC |
|
||||
| `get_users` | `AccountService/Accounts/*` | `UserName`, `RoleId`, `Enabled` |
|
||||
| `get_ntp_servers` | `Managers/{id}/NetworkProtocol` | `NTP.NTPServers` (newer schema versions only) |
|
||||
| `get_snmp_information` | `Managers/{id}/NetworkProtocol` | `SNMP.ProtocolEnabled` (details vary) |
|
||||
| `get_config` | n/a | A BMC has no configuration file. Not implemented |
|
||||
|
||||
## Role methods (draft, see role.md)
|
||||
|
||||
| Method | Resource |
|
||||
|---|---|
|
||||
| `get_power_state` | `Systems/{id}`: `PowerState` |
|
||||
| `set_power_state` | `POST Systems/{id}/Actions/ComputerSystem.Reset` with `ResetType`; allowed values from `ResetType@Redfish.AllowableValues` (or the `ActionInfo` resource) |
|
||||
| `reboot_host` (the BMC) | `POST Managers/{id}/Actions/Manager.Reset` |
|
||||
| `get_hardware_inventory` | `Systems/{id}` (`ProcessorSummary`, `MemorySummary`), `Systems/{id}/Processors/*`, `Systems/{id}/Memory/*`, `Systems/{id}/Storage/*` (older: `SimpleStorage`), `Chassis/{id}/Power` PSUs, `Systems/{id}/EthernetInterfaces/*` |
|
||||
| `get_event_log` | `Systems/{id}/LogServices/*/Entries` or `Managers/{id}/LogServices/*/Entries` (where the SEL lives varies by vendor) |
|
||||
| `get_firmware_inventory` | `UpdateService/FirmwareInventory/*`: `Name`, `Version`, `Updateable` |
|
||||
| `get_management_protocols` | `Managers/{id}/NetworkProtocol`: `HTTP`, `HTTPS`, `SSH`, `IPMI`, `SNMP`, `KVMIP`, `VirtualMedia`, `SSDP`, each with `ProtocolEnabled` and `Port` |
|
||||
|
||||
## IPMI fallback (`ipmi` entry point)
|
||||
|
||||
Read-only, via `pyghmi`: device ID and FRU data for `get_facts`, sensor data repository for
|
||||
`get_environment`, chassis status for `get_power_state`, SEL for `get_event_log`. No power
|
||||
control over IPMI.
|
||||
@@ -0,0 +1,46 @@
|
||||
# References
|
||||
|
||||
Collected 2026-10-13.
|
||||
|
||||
## Standards and DMTF tools
|
||||
|
||||
| What | URL |
|
||||
|---|---|
|
||||
| DMTF Redfish standards page (specification, schemas, DSP2043 mockups) | https://www.dmtf.org/standards/redfish |
|
||||
| Redfish publications (schemas, mockups) on GitHub | https://github.com/DMTF/Redfish-Publications |
|
||||
| Redfish-Mockup-Server | https://github.com/DMTF/Redfish-Mockup-Server |
|
||||
| Redfish-Mockup-Server Docker image | https://hub.docker.com/r/dmtf/redfish-mockup-server |
|
||||
| Redfish-Service-Validator | https://github.com/DMTF/Redfish-Service-Validator |
|
||||
| Redfish-Interop-Validator | https://github.com/DMTF/Redfish-Interop-Validator |
|
||||
|
||||
## Libraries
|
||||
|
||||
| Library | Use | License | Status (2026-10) |
|
||||
|---|---|---|---|
|
||||
| `redfish` (DMTF python-redfish-library) | thin Redfish client: sessions, GET/POST | BSD-3-Clause | release 3.4.1, 2026-10-09 |
|
||||
| `sushy` (OpenStack) | object-model Redfish client | Apache-2.0 | active |
|
||||
| `sushy-tools` (OpenStack) | Redfish emulator for tests | Apache-2.0 | active |
|
||||
| `pyghmi` | IPMI over LAN, pure Python | Apache-2.0 | release 1.6.19, 2026-07-13 on PyPI (the GitHub mirror is archived) |
|
||||
|
||||
Choosing between the thin `redfish` client and `sushy` is open. The thin client keeps
|
||||
quirk handling in this driver; `sushy` brings an object model but also its own assumptions
|
||||
about Ironic's needs.
|
||||
|
||||
## Supermicro
|
||||
|
||||
| What | URL |
|
||||
|---|---|
|
||||
| BMC firmware for X10DRL-i (REDFISH_X10 3.91) | https://supermicro.com/en/support/resources/downloadcenter/firmware/MBD-X10DRL-i/BMC |
|
||||
| Redfish Reference Guide (HTML, X12/H12 and later) | https://www.supermicro.com/manuals/other/redfish-ref-guide-html/ |
|
||||
| Redfish Reference Guide 1.0a for X10 (third-party mirror) | https://update.shared.it/SUPERMICRO/X10DRL-I/IPMI/REDFISH_X10_327/Redfish_Ref_Guide_1%200a.pdf |
|
||||
|
||||
## Security
|
||||
|
||||
- CVE-2013-4786: IPMI 2.0 RAKP password hash disclosure.
|
||||
|
||||
## netOrk
|
||||
|
||||
- Discovery already fingerprints `idrac` and `ilo` by HTTP (`netork/jobs/tasks/discovery.py`),
|
||||
without a driver. Supermicro BMCs are not fingerprinted yet.
|
||||
- Default-credential audit: NetOrk/netork#141.
|
||||
- Reachability recovery (a hung host could be power-cycled through its BMC): NetOrk/netork#938.
|
||||
@@ -0,0 +1,70 @@
|
||||
# Role base draft: `ManagementControllerDriver`
|
||||
|
||||
Draft for napalm-device-types. Nothing here is decided; the decisions are tracked in the
|
||||
netOrk options issue.
|
||||
|
||||
## Why a new role
|
||||
|
||||
The existing role bases (`SwitchDriver`, `FirewallDriver`, `AccessPointDriver`,
|
||||
`HypervisorDriver`, `StorageDriver`, `OSDriver`, `PhoneDriver`, `MediaDriver`,
|
||||
`ResidentialGatewayDriver`) each describe what a device *is*. A BMC is a separate computer
|
||||
with its own network port, IP and MAC that manages *another* machine: it reads that
|
||||
machine's sensors and switches its power, whatever OS the machine runs. None of the
|
||||
existing contracts fits, and borrowing one (e.g. `OSDriver`) would make netOrk offer
|
||||
package updates and service control for a BMC.
|
||||
|
||||
## Sketch
|
||||
|
||||
```python
|
||||
class ManagementControllerDriver(DeviceTypeDriver):
|
||||
"""Contract, not code."""
|
||||
ROLE: str = "management_controller" # key exposed as device_class
|
||||
TYPE_LABEL: str = "Management Controller"
|
||||
USES_SSH: bool = False # Redfish is HTTPS; IPMI is UDP
|
||||
|
||||
if TYPE_CHECKING:
|
||||
# The managed machine
|
||||
def get_power_state(self) -> PowerStateDict: ...
|
||||
def set_power_state(self, action: PowerAction) -> None: ... # On, GracefulShutdown,
|
||||
# ForceOff, GracefulRestart,
|
||||
# ForceRestart, PowerCycle
|
||||
def get_hardware_inventory(self) -> HardwareInventoryDict: ... # CPUs, DIMMs, drives,
|
||||
# PSUs, NICs, serials
|
||||
def get_event_log(self, limit: int = 500) -> List[EventLogEntryDict]: ... # SEL
|
||||
# The controller itself
|
||||
def get_firmware_inventory(self) -> List[FirmwareDict]: ... # BMC, BIOS, others
|
||||
def get_management_protocols(self) -> ManagementProtocolsDict: ... # IPMI, SSH,
|
||||
# HTTP(S), SNMP,
|
||||
# KVM, virtual media
|
||||
```
|
||||
|
||||
Points to settle in napalm-device-types:
|
||||
|
||||
- **`reboot_host` means the BMC.** `HostRebootMixin` says a driver restarts its *own*
|
||||
host, never one it manages ("a hypervisor restarts the hypervisor, not a VM"). For a BMC
|
||||
that is `Manager.Reset`; the managed server goes through `set_power_state`. A driver for
|
||||
a BMC must not map `reboot_host` to the server.
|
||||
- **Sensors.** NAPALM's `get_environment` already has fans, temperatures and power supplies.
|
||||
It also requires CPU and memory, which a BMC does not know for the host OS. Either return
|
||||
`get_environment` with those empty, or add a `get_sensors` that also carries voltages and
|
||||
power draw. Prefer reusing `get_environment` if the empty fields are acceptable.
|
||||
- **Health metrics.** `HealthMetricsMixin` is SNMP/UCD-MIB. A BMC's health comes from Redfish,
|
||||
so this role does **not** mix it in. If netOrk needs `get_health_metrics` for BMCs, the
|
||||
driver implements it from Redfish, as `SwitchDriver` drivers do from their own sources.
|
||||
- **`CommandChannelMixin`** comes with `DeviceTypeDriver` but stays unimplemented: no shell.
|
||||
- **Write capability by `hasattr`.** `set_power_state` exists only on drivers that can do it,
|
||||
so the IPMI fallback (read-only) simply does not define it.
|
||||
- **Models.** `PowerStateDict`, `HardwareInventoryDict`, `EventLogEntryDict`,
|
||||
`FirmwareDict`, `ManagementProtocolsDict` go into `models.py`.
|
||||
- **Fingerprinting.** An unauthenticated `GET /redfish/v1/` returns the service root
|
||||
(`RedfishVersion`, `UUID`, `Vendor` on newer services) on every Redfish BMC. That is a
|
||||
vendor-neutral `PORT_SPECS`/`HTTP_FINGERPRINT` rule and can replace the hand-written
|
||||
`idrac`/`ilo` platform strings in netOrk's discovery.
|
||||
|
||||
## Relation to the managed server
|
||||
|
||||
A BMC is its own device in netOrk (own IP, own credentials, own firmware and CVEs), linked
|
||||
to the host it manages. How to link them (matching the server's serial or system UUID from
|
||||
`Systems/{id}` against the host's DMI data, or by hand) is a netOrk decision, not part of
|
||||
this contract. The driver exposes the identifiers needed for matching:
|
||||
`SerialNumber`, `UUID` and the host's MAC addresses from `Systems/{id}/EthernetInterfaces`.
|
||||
@@ -0,0 +1,43 @@
|
||||
# Security
|
||||
|
||||
A BMC can power a server off, mount virtual media and open a remote console. Its
|
||||
credentials are worth as much as root on every machine it manages.
|
||||
|
||||
## Credentials
|
||||
|
||||
- Use a dedicated BMC account for netOrk, not the factory administrator. A read-only role
|
||||
(Redfish `ReadOnly`) suffices for everything except power control, which needs
|
||||
`Operator`.
|
||||
- netOrk's credential gating applies unchanged: no job without credentials.
|
||||
- Close Redfish sessions after each poll. BMCs allow few concurrent sessions, and a leaked
|
||||
session can lock the web UI out.
|
||||
|
||||
## IPMI over LAN
|
||||
|
||||
- IPMI 2.0's RAKP handshake returns a salted hash of the user's password to any client that
|
||||
names a valid user, before authentication (CVE-2013-4786). The hash can be cracked
|
||||
offline. This is part of the protocol, not a bug a firmware update fixes.
|
||||
- Cipher suite 0 (no authentication) is enabled on some BMCs and allows login with any
|
||||
password.
|
||||
- So the `ipmi` entry point is read-only and a fallback only. `get_management_protocols`
|
||||
reporting `IPMI.ProtocolEnabled = true` should become a finding in netOrk, with the advice
|
||||
to disable IPMI over LAN where Redfish is available.
|
||||
|
||||
## Power control
|
||||
|
||||
- `set_power_state` can take a production server down. In netOrk it needs a
|
||||
`ConfirmDialog`, a permission of its own, and an audit log entry.
|
||||
- `ForceOff`/`ForceRestart`/`PowerCycle` skip the OS shutdown; offer `GracefulShutdown`/
|
||||
`GracefulRestart` first.
|
||||
- `reboot_host` restarts only the BMC (`Manager.Reset`). The managed server keeps running.
|
||||
|
||||
## Firmware
|
||||
|
||||
BMC firmware versions from `UpdateService/FirmwareInventory` feed netOrk's vulnerability
|
||||
management. Supermicro BMCs in particular have had serious published vulnerabilities, and
|
||||
the X10 Redfish firmware line is no longer updated.
|
||||
|
||||
## Network placement
|
||||
|
||||
A BMC belongs in a management network that only administrators and netOrk can reach. A BMC
|
||||
reachable from a user or guest VLAN is itself a finding for the segmentation checks.
|
||||
@@ -0,0 +1,44 @@
|
||||
# Supermicro X10 (first test device: X10DRL-i)
|
||||
|
||||
## Firmware
|
||||
|
||||
Supermicro shipped Redfish to X10 boards as a separate BMC firmware line, named
|
||||
`REDFISH_X10_<version>`. For the X10DRL-i the latest is **3.91**
|
||||
(`REDFISH_X10_391_20200806_unsigned.zip`) in Supermicro's download center. Other X10
|
||||
boards have 3.86–3.90 from 2019–2020. Users report Redfish version 1.0.x on these
|
||||
firmwares, so expect:
|
||||
|
||||
- the legacy `Chassis/{id}/Thermal` and `Power` resources, not `ThermalSubsystem`/`Sensors`,
|
||||
- an older `ManagerNetworkProtocol` schema (NTP and SNMP details may be missing),
|
||||
- fewer collections overall (storage details may be absent).
|
||||
|
||||
The X10 BMC firmware is unlikely to get further updates. For the driver that is useful
|
||||
twice: it is the oldest Redfish the driver has to survive, and a real case for flagging
|
||||
outdated BMC firmware in netOrk's vulnerability management.
|
||||
|
||||
Supermicro's **Redfish Reference Guide 1.0a** was published with the X10 Redfish firmware.
|
||||
Supermicro's own HTML guide covers X12/H12 and later.
|
||||
|
||||
## Check before starting
|
||||
|
||||
```bash
|
||||
# Service root, no login: Redfish version and available collections
|
||||
curl -sk https://<bmc>/redfish/v1/ | python3 -m json.tool
|
||||
# The managed server: model, serial, BIOS, power state
|
||||
curl -sk -u <user>:<password> https://<bmc>/redfish/v1/Systems/1 | python3 -m json.tool
|
||||
```
|
||||
|
||||
## Known Supermicro points (from memory, to verify on the device)
|
||||
|
||||
- Older Supermicro BMCs shipped with `ADMIN`/`ADMIN`; newer ones have a unique password on
|
||||
a label. A BMC still on `ADMIN`/`ADMIN` is a test case for netOrk's default-credential
|
||||
audit (NetOrk/netork#141).
|
||||
- Some out-of-band features (BIOS update and BIOS settings through the BMC) need a
|
||||
Supermicro license (SFT-OOB-LIC / SFT-DCMS-SINGLE). Reading and power control should not.
|
||||
Which resources the X10 omits without a license shows up in the recorded responses.
|
||||
- Vendor-specific data sits under `Oem.Supermicro` in several resources.
|
||||
|
||||
## IPMI on the same board
|
||||
|
||||
The X10DRL-i also speaks IPMI 2.0 over LAN (UDP 623), so the `ipmi` fallback can be tested on
|
||||
the same device, and so can the check that reports IPMI over LAN as enabled.
|
||||
@@ -0,0 +1,47 @@
|
||||
# Testing
|
||||
|
||||
## Without hardware
|
||||
|
||||
- **DMTF mockups (DSP2043).** Complete Redfish service trees as static JSON, published by
|
||||
the DMTF with each Redfish release (download from the Redfish standards page). They cover
|
||||
the current schema: `ThermalSubsystem`, `PowerSubsystem`, `Sensors`, storage, logs, and
|
||||
actions.
|
||||
- **DMTF Redfish-Mockup-Server.** Serves a mockup over HTTP (`127.0.0.1:8000` by default),
|
||||
also as a Docker image `dmtf/redfish-mockup-server`. Good for integration tests of the
|
||||
transport (sessions, collections, actions).
|
||||
- **OpenStack sushy-tools.** An emulator that serves mockups or drives libvirt VMs via Redfish,
|
||||
so `set_power_state` can be tested against something that actually changes state.
|
||||
- **DMTF Redfish-Mockup-Creator.** Records a live service into a mockup. It is the tool to
|
||||
turn the X10DRL-i into a complete fixture set in one go.
|
||||
|
||||
Unit tests use recorded JSON responses directly; the mockup server is for a small set of
|
||||
integration tests.
|
||||
|
||||
## Fixtures to record from the X10DRL-i
|
||||
|
||||
Store under `tests/fixtures/supermicro-x10drl-i-3.91/`, one file per request path, plus
|
||||
`COMMANDS.txt` with the paths and the machine's state (powered on/off, fans present).
|
||||
Scrub serial numbers, UUIDs, MACs and IPs before committing.
|
||||
|
||||
- [ ] `GET /redfish/v1/` (without login)
|
||||
- [ ] `GET /redfish/v1/Systems` and each member
|
||||
- [ ] `GET /redfish/v1/Systems/1/Processors` and each member
|
||||
- [ ] `GET /redfish/v1/Systems/1/Memory` and each member
|
||||
- [ ] `GET /redfish/v1/Systems/1/Storage` or `SimpleStorage`, whichever exists
|
||||
- [ ] `GET /redfish/v1/Systems/1/EthernetInterfaces` and each member
|
||||
- [ ] `GET /redfish/v1/Systems/1/LogServices` and the entries of each
|
||||
- [ ] `GET /redfish/v1/Chassis` and each member
|
||||
- [ ] `GET /redfish/v1/Chassis/1/Thermal`
|
||||
- [ ] `GET /redfish/v1/Chassis/1/Power`
|
||||
- [ ] `GET /redfish/v1/Managers/1`
|
||||
- [ ] `GET /redfish/v1/Managers/1/EthernetInterfaces` and each member
|
||||
- [ ] `GET /redfish/v1/Managers/1/NetworkProtocol`
|
||||
- [ ] `GET /redfish/v1/Managers/1/LogServices` and the entries of each
|
||||
- [ ] `GET /redfish/v1/AccountService` and `AccountService/Accounts`
|
||||
- [ ] `GET /redfish/v1/UpdateService/FirmwareInventory` and each member
|
||||
- [ ] `POST /redfish/v1/SessionService/Sessions` response headers (token redacted)
|
||||
- [ ] the error body of a request without credentials and of a wrong path
|
||||
- [ ] `ResetType@Redfish.AllowableValues` from `Systems/1`
|
||||
- [ ] IPMI: FRU, sensor list, chassis status, SEL (via `ipmitool` for comparison with `pyghmi`)
|
||||
|
||||
Or run the Redfish-Mockup-Creator once against the BMC and keep its output.
|
||||
Reference in new issue
Block a user