feat: Intel AMT driver over WS-Management (0.1.0)
An `amt` driver (napalm_amt.AmtDriver), a ManagementControllerDriver for the management controller of Intel vPro machines, with its own lean WS-Management client (requests + ElementTree, HTTP Digest, ports 16992/16993). It reads the machine's identity, hardware with the SMBIOS system UUID, firmware (AMT with build, BIOS), power state and the hardware event log, reports what AMT listens on (plain HTTP or TLS, KVM incl. port 5900, IDE-R), and switches the machine's power. AMT cannot be reset over WS-Management, so there is no reboot_host. Discovery recognises AMT by its ports and its Server header. Tested against Intel's published AMT 12 recordings (go-wsman-messages, Apache-2.0, see NOTICE). `python -m napalm_amt.record` records a real AMT read-only; the first test devices are two Lenovo ThinkCentre M910x.
This commit is contained in:
commit
0052ba7884
61 files changed
+4303
No files matched your search
@@ -0,0 +1,44 @@
|
||||
# Getters and the WS-Management classes behind them
|
||||
|
||||
Classes are named by their prefix: `AMT_` and `IPS_` are Intel's
|
||||
(`http://intel.com/wbem/wscim/1/{amt,ips}-schema/1/`), `CIM_` the DMTF's
|
||||
(`http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/`). "Enum" is `Enumerate` + `Pull`.
|
||||
|
||||
## Connection
|
||||
|
||||
| Step | Request |
|
||||
|---|---|
|
||||
| `open()` | Get `AMT_GeneralSettings`. Exists on every AMT and needs a valid login, so it proves both |
|
||||
|
||||
Every read is cached for the connection, except the power state.
|
||||
|
||||
## NAPALM getters (describe AMT)
|
||||
|
||||
| Getter | Source | Notes |
|
||||
|---|---|---|
|
||||
| `get_facts` | `AMT_GeneralSettings` (HostName, DomainName), `CIM_Chassis`/`CIM_Card`, `CIM_SoftwareIdentity`, `AMT_EthernetPortSettings` | `os_version` = AMT version with build (`12.0.67.1579`); vendor/model/serial are the machine's (chassis, baseboard where the chassis holds SMBIOS placeholders); `uptime` -1 |
|
||||
| `get_interfaces` | `AMT_EthernetPortSettings` | `wired`/`wireless`; a port without a MAC (no WLAN card) is left out; description says DHCP/static and whether AMT shares the host's IP |
|
||||
| `get_interfaces_ip` | `AMT_EthernetPortSettings` (IPAddress, SubnetMask) | Only where AMT reports an address of its own (static configuration) |
|
||||
| `get_environment` | none | Empty: client AMT has no sensor readings. `CIM_Fan`/`CIM_Sensor` exist but report placeholders (EnabledState 5, no speed) |
|
||||
|
||||
## Role methods (describe and control the machine)
|
||||
|
||||
| Method | Source | Notes |
|
||||
|---|---|---|
|
||||
| `get_power_state` | Enum `CIM_AssociatedPowerManagementService` (PowerState, AvailableRequestedPowerStates) | 2 = On; 3/4 (sleep), 7 (hibernate), 6/8/12/13 (off) = Off; actions = role actions whose CIM state AMT lists |
|
||||
| `set_power_state` | Invoke `CIM_PowerManagementService.RequestPowerStateChange` | On → 2, ForceOff → 8, ForceRestart → 10, PowerCycle → 5, GracefulShutdown → 12, GracefulRestart → 14. ReturnValue 0 or 4096 (job started) = accepted |
|
||||
| `get_hardware_inventory` | `CIM_Chassis`, `CIM_Card`, `CIM_ComputerSystemPackage` (PlatformGUID), `CIM_Processor` + `CIM_Chip`, `CIM_PhysicalMemory`, `CIM_MediaAccessDevice`, `AMT_EthernetPortSettings` | `system_uuid`: PlatformGUID with the first three groups byte-swapped (SMBIOS order, as dmidecode and Intel's console decode it). Drive size: `MaxMediaSize` × 1000. No cores/threads, no drive models, no PSUs |
|
||||
| `get_event_log` | Invoke `AMT_MessageLog.PositionToFirstRecord`, then `GetRecords` (390 per call) until `NoMoreRecords` | 21-byte PET records, decoded after Intel's go-wsman-messages; `id` = position in the log |
|
||||
| `get_firmware_inventory` | `CIM_SoftwareIdentity` (AMT, Build Number), `CIM_BIOSElement` | `updateable` unknown: AMT updates neither itself nor the BIOS |
|
||||
| `get_management_protocols` | `AMT_TLSSettingData`, `AMT_RedirectionService`, `IPS_KVMRedirectionSettingData`, `CIM_KVMRedirectionSAP` | http/https from the "802.3" TLS setting; kvm/virtual_media on 16994 (16995 with TLS), kvm on 5900 when that port is on; ipmi/ssh/snmp always off |
|
||||
| `reboot_host` | none | Not offered: WS-Management cannot restart AMT itself |
|
||||
|
||||
A class this AMT does not know (older versions know fewer) answers with a
|
||||
`DestinationUnreachable` fault; its part of the inventory stays empty.
|
||||
|
||||
## Not read yet
|
||||
|
||||
- `AMT_AuthorizationService` (accounts and realms) for `get_users`.
|
||||
- `AMT_AuditLog` (who logged in, who switched power). The event log covers hardware only.
|
||||
- `AMT_SetupAndConfigurationService` (provisioning state and mode, ACM/CCM). Recorded by
|
||||
`napalm_amt.record` to decide later whether it is worth a warning.
|
||||
@@ -0,0 +1,54 @@
|
||||
# First test devices: Lenovo ThinkCentre M910x
|
||||
|
||||
Two ThinkCentre M910x (Tiny, Intel Q270, vPro) with Intel ME/AMT 11.x, plus possibly a
|
||||
third to experiment on. Nothing has been recorded from them yet; the driver is tested
|
||||
against Intel's AMT 12 recordings (see [testing.md](testing.md)).
|
||||
|
||||
## Setting up AMT
|
||||
|
||||
Menu names vary between BIOS and ME firmware versions.
|
||||
|
||||
1. **BIOS** (F1): under *Advanced → Intel Manageability*, enable Intel Manageability
|
||||
Control and the Ctrl+P prompt for MEBx.
|
||||
2. **MEBx** (Ctrl+P at boot): log in with the default password `admin` and set a new one
|
||||
(8 to 32 characters with upper and lower case, a digit and a special character).
|
||||
3. *Intel AMT Configuration → Manageability Feature Selection*: enabled.
|
||||
4. *Network Setup → TCP/IP Settings → Wired LAN IPv4*: **turn DHCP off** and give AMT a
|
||||
**static address of its own**, with mask, gateway and DNS. In DHCP mode AMT uses the
|
||||
operating system's address, and netOrk keeps one device per address.
|
||||
5. *Network Access State*: activate network access.
|
||||
6. *User Consent*: for KVM without a code from the person at the machine, set opt-in to
|
||||
none. Admin Control Mode, which manual MEBx setup gives, allows that.
|
||||
7. *Redirection Features*: SOL, storage redirection (IDE-R) and KVM as wanted.
|
||||
|
||||
Afterwards `http://<amt-ip>:16992/` answers with AMT's web UI, and the `Server` header
|
||||
names the version.
|
||||
|
||||
## Recording
|
||||
|
||||
From a machine that reaches AMT, with the password in a file:
|
||||
|
||||
```bash
|
||||
python -m napalm_amt.record <amt-ip> --user admin --password-file ~/.amt-m910x \
|
||||
--out tests/fixtures/lenovo-m910x-<amt-version>
|
||||
```
|
||||
|
||||
The recorder only reads (see [testing.md](testing.md)). It redacts the provisioning OTP
|
||||
and the RFB password and keeps serial numbers.
|
||||
|
||||
## What the recordings have to settle
|
||||
|
||||
These are assumptions the driver makes from Intel's AMT 12 recordings and documentation:
|
||||
|
||||
- [ ] **System UUID byte order.** `get_hardware_inventory()["system_uuid"]` should equal
|
||||
`dmidecode -s system-uuid` on the machine's OS. netOrk links AMT to its host by it.
|
||||
- [ ] **Chassis versus board.** Whether `CIM_Chassis.Model` holds Lenovo's machine type
|
||||
(`10MU…`) and `CIM_Card` the board.
|
||||
- [ ] **Event log timestamps.** Taken as UTC. Some AMT versions keep local time.
|
||||
- [ ] **Drives.** Whether AMT 11 lists `CIM_MediaAccessDevice` at all.
|
||||
- [ ] **Graceful power states.** Whether AMT lists 12 and 14 with the OS running, and
|
||||
whether that needs the Intel ME driver (LMS) on the host.
|
||||
- [ ] **Sleep.** A sleeping machine is reported as Off. Check that On wakes it.
|
||||
- [ ] **Static address.** `AMT_EthernetPortSettings.IPAddress` present with a static
|
||||
configuration.
|
||||
- [ ] **AMT version and CVE state.** Which 11.8 build Lenovo's latest ME firmware gives.
|
||||
@@ -0,0 +1,12 @@
|
||||
# References
|
||||
|
||||
- DMTF DSP0226, *Web Services for Management (WS-Management)*: operations, faults.
|
||||
- DMTF DSP0227, *WS-Management CIM Binding*: resource URIs, enumeration.
|
||||
- Intel AMT SDK / *Intel AMT Implementation and Reference Guide*: the AMT_ and IPS_
|
||||
classes, power state codes, the event log record format.
|
||||
- Intel Device Management Toolkit, `go-wsman-messages`
|
||||
(github.com/device-management-toolkit/go-wsman-messages, Apache-2.0): request envelopes,
|
||||
the event record decoder, and the recorded responses used as fixtures.
|
||||
- Intel security advisories, e.g. INTEL-SA-00075 (CVE-2017-5689).
|
||||
- napalm-redfish (git.netork.io/NAPALM/napalm-redfish): the server BMC drivers with the
|
||||
same role.
|
||||
@@ -0,0 +1,57 @@
|
||||
# Security
|
||||
|
||||
## Plain HTTP (16992) versus TLS (16993)
|
||||
|
||||
Out of the box, AMT talks WS-Management on **16992 over plain HTTP**. HTTP Digest (MD5)
|
||||
keeps the password off the wire. Everything else travels in the clear, including the
|
||||
machine's inventory and every power command, and nothing stops a man in the middle from
|
||||
replaying or changing them. TLS on 16993 needs a certificate and key provisioned into AMT
|
||||
(`AMT_PublicKeyManagementService`, `AMT_TLSSettingData`); MEBx alone cannot set it up.
|
||||
|
||||
`get_management_protocols` reports `http` enabled while AMT accepts plain connections from
|
||||
the network. Like IPMI over LAN for a server BMC, that is worth a finding in netOrk.
|
||||
|
||||
The driver verifies AMT's certificate on 16993 by default (`verify_ssl=True`). A
|
||||
self-signed certificate needs `verify_ssl` set to its CA file, or `False`.
|
||||
|
||||
## Accounts
|
||||
|
||||
MEBx setup leaves one account, `admin`, with every right. AMT can hold more Digest
|
||||
accounts, each limited to *realms* (`AMT_AuthorizationService`). Reading needs the
|
||||
hardware asset, general info and event log realms; power control needs remote control.
|
||||
A separate account for netOrk keeps `admin` out of it, but is not required.
|
||||
|
||||
AMT locks an account out for a while after repeated failed logins and writes the failures
|
||||
to its event log ("Authentication failed N times"). The driver reports that entry as
|
||||
Critical.
|
||||
|
||||
## KVM, SOL and IDE-R
|
||||
|
||||
- The **KVM console** goes over the redirection port (16994, or 16995 with TLS), behind
|
||||
the AMT login. With **port 5900** enabled, AMT additionally speaks plain VNC, protected
|
||||
only by an eight-character RFB password. Worth a finding when on.
|
||||
- **User consent** (opt-in) asks the person at the machine for a code before KVM starts.
|
||||
It is mandatory in Client Control Mode and optional in Admin Control Mode, which MEBx
|
||||
setup gives.
|
||||
- **IDE-R/USB-R** (virtual media) lets whoever holds the login boot the machine from a
|
||||
remote image.
|
||||
|
||||
## Known vulnerabilities
|
||||
|
||||
AMT's firmware has a long CVE history. Most important is **CVE-2017-5689**
|
||||
(INTEL-SA-00075): AMT 6 to 11.6 accepted an empty Digest response, so anyone on the
|
||||
network got in without a password. Fixed firmware came through the PC vendors (Lenovo:
|
||||
ME firmware updates). Many later advisories cover ME/AMT 11.x (SA-00086, SA-00112,
|
||||
SA-00213, SA-00241, SA-00295 and others).
|
||||
|
||||
`get_firmware_inventory` reports AMT's version with its build (`11.8.50.3399`), and AMT
|
||||
sends the same version without a login in its `Server` header. That version is what netOrk
|
||||
needs to match advisories, and what a finding for outdated AMT firmware would rest on.
|
||||
|
||||
## Power control
|
||||
|
||||
`set_power_state` switches the machine itself, like a power button. It checks the action
|
||||
against the power state and AMT's list of accepted states first, and refuses `On` for a
|
||||
running machine. `ForceOff`, `ForceRestart` and `PowerCycle` do not ask the operating
|
||||
system. The graceful actions need the operating system's cooperation, and AMT lists them
|
||||
only where the host supports them.
|
||||
@@ -0,0 +1,35 @@
|
||||
# Testing
|
||||
|
||||
## Without hardware
|
||||
|
||||
`tests/conftest.py` serves recorded WS-Management answers over mocked HTTP
|
||||
(`responses`): `Get` → `<Class>.get.xml`, `Pull` → `<Class>.pull.xml`, a method →
|
||||
`<Class>.<Method>.xml`. A class without a file answers with the fault for an unknown
|
||||
resource URI, as AMT does. A test changes one answer with `AmtServer.override` and a
|
||||
recorded file with `patched(name, old, new)`, which fails when `old` is not in it.
|
||||
|
||||
| Fixtures | Source |
|
||||
|---|---|
|
||||
| `tests/fixtures/dmt-wsman-messages/` | Intel's go-wsman-messages (Apache-2.0), `pkg/wsman/wsmantesting/responses` at commit 00402b9: AMT 12.0.67 on an Intel NUC9, a few values replaced by placeholders. `fault_destination_unreachable.xml` is written by hand after DSP0226 |
|
||||
|
||||
There is no AMT simulator worth the name. Intel's Device Management Toolkit talks to
|
||||
real AMT or to its own recordings, the ones used here.
|
||||
|
||||
## Recording a real AMT
|
||||
|
||||
`python -m napalm_amt.record HOST --password-file FILE --out DIR` makes every read the
|
||||
driver makes and writes each raw answer under the name the mock serves it by, plus
|
||||
`COMMANDS.txt` and `landing_page.txt` (the unauthenticated page with its headers, which
|
||||
is what discovery sees). It never switches power and never writes to AMT. Pages after the
|
||||
first become `<Class>.pull.2.xml`. A class AMT does not know is kept as
|
||||
`<Class>.enumerate.xml` with its fault.
|
||||
|
||||
Name the directory `<vendor>-<model>-<amt version>`, for example
|
||||
`lenovo-m910x-11.8.50.3399`.
|
||||
|
||||
## Running
|
||||
|
||||
```bash
|
||||
.venv/bin/python -m pytest
|
||||
.venv/bin/ruff check . && .venv/bin/mypy napalm_amt
|
||||
```
|
||||
Reference in new issue
Block a user