Skip to content

Commit 30d4b52

Browse files
committed
docs: DPU CA configuration options
Operators can choose how DPUs receive the CA bundle used to authenticate NICo. This collects every supported deployment path and the safe migration steps in one place. Primary callouts are: - Documents the backward-compatible legacy download, site-specific embedded BFB, and operator-mounted bundle modes. - Shows Helm, environment-variable, site configuration, and DPF examples. - Explains staged rollout, root rotation, certificate-chain verification, and the remaining boot-chain trust boundary. This supports #3571 Signed-off-by: Chet Nichols III <chetn@nvidia.com>
1 parent 0cd8acb commit 30d4b52

6 files changed

Lines changed: 491 additions & 3 deletions

File tree

book/src/configuration/configurability.md

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,12 +415,182 @@ overrides. Key fields:
415415

416416
- `default_dpu_agent_version` — DPU agent version installed during provisioning.
417417
- `bfb_image_path` — BFB (Bluefield boot image) location served to DPUs.
418+
- `bootstrap_ca_source`: Trust-anchor source for non-DPF DPU provisioning.
418419
- `dpu_ipmi_tool_impl` (top-level) — `"prod"` for real IPMI; `"fake"` for dev clusters with simulated DPUs.
419420
- `dpu_ipmi_reboot_attempts` (top-level) — retry budget for IPMI reboot ops.
420421

421422
See [`crates/api-core/src/cfg/README.md` → DpuConfig](../../../crates/api-core/src/cfg/README.md#dpuconfig)
422423
for the full field list.
423424

425+
#### DPU Bootstrap CA Trust
426+
427+
For non-DPF provisioning, select the source in site config:
428+
429+
```toml
430+
[dpu_config]
431+
bootstrap_ca_source = "embedded" # legacy_download | embedded | mounted
432+
```
433+
434+
The following table describes the available sources:
435+
436+
| Source | Behavior |
437+
|--------|----------|
438+
| `legacy_download` | Default when the field is omitted. Preserves the historical download and response handling from `nico-pxe` during boot. It does not authenticate or locally validate the response. |
439+
| `embedded` | Uses a site-specific CA bundle staged at `/opt/forge/embedded_forge_root.pem` in the DPU BFB from an explicit `BOOTSTRAP_CA_PATH`. Generic builds do not include this payload. A missing or invalid bundle stops provisioning. There is no download fallback. |
440+
| `mounted` | Uses an operator-managed bundle at `/opt/forge/forge_root.pem`. The provisioning environment must populate the path because the bare-metal flow does not create the mount. A missing or invalid bundle stops provisioning. There is no download fallback. |
441+
442+
##### Operator Configuration Examples
443+
444+
The following examples are independent configurations. Do not combine them.
445+
Omit the field to preserve the current behavior, or declare the legacy
446+
behavior explicitly:
447+
448+
```toml
449+
[dpu_config]
450+
bootstrap_ca_source = "legacy_download"
451+
```
452+
453+
Legacy-download sites can serve a stable operator-owned root bundle without
454+
changing the DPU policy. Reference an existing ConfigMap in the `nico-pxe`
455+
release namespace. In the NICo umbrella chart's values, use:
456+
457+
```yaml
458+
nico-pxe:
459+
bootstrapRootCa:
460+
configMapName: forge-root-ca
461+
key: ca.crt
462+
```
463+
464+
Or reference an existing Secret when that matches the site's distribution
465+
workflow:
466+
467+
```yaml
468+
nico-pxe:
469+
bootstrapRootCa:
470+
secretName: forge-root-ca
471+
key: ca.crt
472+
```
473+
474+
When installing `helm/charts/nico-pxe` directly, omit the `nico-pxe` umbrella
475+
key. The same top-level shape accepts `secretName` instead of
476+
`configMapName`:
477+
478+
```yaml
479+
bootstrapRootCa:
480+
configMapName: forge-root-ca
481+
key: ca.crt
482+
```
483+
484+
For a non-Helm `nico-pxe` deployment, point the binary directly at the served
485+
bundle. The file must already exist in the container, for example through a
486+
read-only mount, and the launcher must export the variable. Omitting it retains
487+
the `FORGE_ROOT_CAFILE_PATH` fallback:
488+
489+
```bash
490+
export FORGE_BOOTSTRAP_ROOT_CAFILE_PATH=/etc/nico/bootstrap/roots.pem
491+
```
492+
493+
For a non-DPF site that publishes its own BFB, supply the bundle during the BFB
494+
build and then select the embedded source in NICo site config:
495+
496+
```bash
497+
BOOTSTRAP_CA_PATH=/secure/site/forge-roots.pem \
498+
cargo make --cwd pxe build-boot-artifacts-bfb
499+
```
500+
501+
```toml
502+
[dpu_config]
503+
bootstrap_ca_source = "embedded"
504+
```
505+
506+
For a non-DPF provisioning environment that installs the bundle itself, place
507+
it at `/opt/forge/forge_root.pem` and select:
508+
509+
```toml
510+
[dpu_config]
511+
bootstrap_ca_source = "mounted"
512+
```
513+
514+
DPF can retain the download while overriding the complete endpoint URL:
515+
516+
```toml
517+
[dpf.dpu_agent_bootstrap_ca]
518+
source = "legacy_download"
519+
url = "http://site-pxe.example.com/api/v0/tls/root_ca"
520+
```
521+
522+
Or DPF can install a projected Secret:
523+
524+
```toml
525+
[dpf.dpu_agent_bootstrap_ca]
526+
source = "mounted"
527+
object_kind = "secret"
528+
name = "nico-bootstrap-ca-v1"
529+
key = "ca.crt"
530+
```
531+
532+
The equivalent ConfigMap form is useful when the object is created directly
533+
in every target DPU cluster:
534+
535+
```toml
536+
[dpf.dpu_agent_bootstrap_ca]
537+
source = "mounted"
538+
object_kind = "config_map"
539+
name = "nico-bootstrap-ca-v1"
540+
key = "ca.crt"
541+
```
542+
543+
This policy is attached only to DPU provisioning instructions. Host Scout
544+
boots do not receive `[dpu_config].bootstrap_ca_source` and retain their
545+
existing trust behavior.
546+
547+
The `nico-pxe` chart can decouple the payload returned by the legacy
548+
`/api/v0/tls/root_ca` endpoint from the CA used by PXE for its own outbound API
549+
connection. Use either chart form from
550+
[Operator Configuration Examples](#operator-configuration-examples).
551+
552+
With neither name set, the chart renders the old deployment and serves the
553+
PXE workload CA as before. This option changes only the bytes served to legacy
554+
clients. It does not authenticate their HTTP download. Set at most one of
555+
`configMapName` and `secretName`. Existing DPUs retain the CA they previously
556+
installed. Changing the served bundle affects only later downloads unless you
557+
reprovision or refresh the DPU through another trusted mechanism.
558+
559+
For non-Helm deployments, set `FORGE_BOOTSTRAP_ROOT_CAFILE_PATH` to the PEM
560+
bundle path in the `nico-pxe` container. If it is unset, `nico-pxe` serves the
561+
file named by `FORGE_ROOT_CAFILE_PATH`, preserving the historical behavior.
562+
563+
Build a site-specific BFB with `BOOTSTRAP_CA_PATH` pointing to the desired PEM
564+
bundle before selecting `embedded`. The build provides no repository or
565+
developer-certificate fallback. Without the explicit input, the artifact has
566+
no dedicated embedded trust anchor. Existing legacy artifact inputs are
567+
unchanged. The embedded source lives at
568+
`/opt/forge/embedded_forge_root.pem`, separately from the final
569+
`/opt/forge/forge_root.pem` path used by `mounted`, so selecting one mode cannot
570+
silently consume material intended for the other. Roll out the compatible code
571+
and site-specific artifacts first. Then change site configuration and
572+
reprovision non-DPF DPUs. During root rotation, use a bundle containing both old
573+
and new roots until the fleet has moved.
574+
575+
For DPF, configure `[dpf.dpu_agent_bootstrap_ca]` instead. Refer to
576+
[DPU Agent Bootstrap CA](../../../docs/manuals/dpf.md#dpu-agent-bootstrap-ca)
577+
for deployment and rotation instructions. DPF configuration changes require a
578+
`nico-api` restart. The shared published DPU agent image does not embed a site
579+
trust anchor. DPF supports the compatible legacy download or an
580+
operator-managed Secret or ConfigMap mounted when the init container starts.
581+
582+
When pinning a root, verify the NICo API presents its intermediate certificate
583+
with each leaf. Clients cannot build a chain from a root-only bundle if the
584+
server omits the intermediate. Pinning a long-lived root lets clients validate
585+
leaf certificates across intermediate rotations without replacing the bundle.
586+
The bundle validates the API server certificate. This validation is required
587+
whether the DPU presents a client certificate for mutual TLS. It does not
588+
authenticate the preceding DHCP, DNS, iPXE, and user-data delivery chain.
589+
Embedded mode also requires an
590+
integrity-protected artifact distribution and boot chain, such as verified
591+
signatures and Secure Boot. Otherwise, an attacker can replace the image and
592+
its CA together.
593+
424594
### BIOS profiles — `bios_profiles`, `selected_profile`
425595

426596
`bios_profiles` is a nested map keyed by vendor then model that defines

crates/api-core/src/cfg/README.md

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,7 @@ Extends `StateControllerConfig` with:
440440

441441
| Field | Type | Default | Description |
442442
|-------|------|---------|-------------|
443+
| `bootstrap_ca_source` | `BootstrapCaSource` | `legacy_download` | How non-DPF DPUs obtain the API trust anchor: `legacy_download`, `embedded`, or `mounted`. Omitting the field preserves the historical PXE download. The field is not sent to host Scout boots. Non-network modes do not fall back to downloading. |
443444
| `dpu_nic_firmware_initial_update_enabled` | `bool` | `false` | Enable DPU NIC firmware updates on initial discovery. |
444445
| `dpu_nic_firmware_reprovision_update_enabled` | `bool` | `true` | Enable DPU NIC firmware updates on reprovisioning. |
445446
| `dpu_models` | `HashMap<String, Firmware>` | *(BF2+BF3 defaults)* | DPU model firmware definitions. |
@@ -448,6 +449,19 @@ Extends `StateControllerConfig` with:
448449
| `num_of_vfs` | `u32` | `16` | Number of VFs configured per DPU PF during BlueField provisioning. Max `126`. |
449450
| `restart_ovs_on_use_admin_network_change` | `bool` | `false` | Restart OVS on DPU-OS agents when host `use_admin_network` changes. Containerized agents skip the local service restart and still ACK the network config. |
450451

452+
To use `embedded`, build a site-specific BFB with an explicit
453+
`BOOTSTRAP_CA_PATH`. The build provides no repository or default CA fallback
454+
for the dedicated embedded payload. Existing legacy artifact inputs remain
455+
unchanged. It stages the source at `/opt/forge/embedded_forge_root.pem`.
456+
457+
This path is separate from `/opt/forge/forge_root.pem`, which the provisioning
458+
environment must populate for `mounted`. NICo does not create that mount. Both
459+
modes fail closed when their own bundle is absent or invalid. Changing this
460+
setting affects the next DPU network boot or reprovisioning. It does not affect
461+
host Scout boots or rewrite installed DPUs in place. The selected CA validates
462+
the NICo API server certificate. This validation remains necessary even when
463+
client-certificate authentication is not used.
464+
451465
### `NetworkSecurityGroupConfig`
452466

453467
| Field | Type | Default | Description |
@@ -539,11 +553,56 @@ events, so consumers handle them identically.
539553
| Field | Type | Default | Description |
540554
|-------|------|---------|-------------|
541555
| `enabled` | `bool` | `false` | Enable DPF Kubernetes deployment. |
542-
| `services` | `Option<Vec<DpfServiceConfig>>` || Additional Helm services. |
556+
| `dpu_agent_bootstrap_ca` | `DpfDpuAgentBootstrapCa` | `legacy_download` | Bootstrap trust for the containerized DPU agent. Supports `legacy_download` and `mounted`, as described in the following examples. |
557+
| `services` | `Box<DpfMandatoryServicesConfig>` | built-in mandatory-service defaults | Helm chart, image, and pull-secret settings for the six mandatory DPF services. |
543558
| `docker_image_pull_secret` | `Option<String>` || Override for the Kubernetes `imagePullSecrets` entry used to pull mandatory-service images (applied to every mandatory service except `dts` and `doca_hbn`). |
544559
| `proxy` | `Option<DpfProxyDetails>` || Proxy configuration for the DPU. When set, containerd on the DPU routes outbound HTTPS traffic through it. |
545560
| `deployments` | `DpfDeploymentsConfig` | *(default)* | Per-generation DPUDeployment configurations. BF3 is always present with defaults; BF4Generic is opt-in via `[dpf.deployments.bf4_generic]`. |
546561

562+
Omitting `[dpf.dpu_agent_bootstrap_ca]` preserves the historical download URL.
563+
Use the following configuration to retain download mode while overriding the
564+
complete endpoint URL:
565+
566+
```toml
567+
[dpf.dpu_agent_bootstrap_ca]
568+
source = "legacy_download"
569+
# Optional full endpoint URL. Omit to use the agent default.
570+
url = "http://carbide-pxe.forge/api/v0/tls/root_ca"
571+
```
572+
573+
Use the following configuration to project an existing Secret into the DPU
574+
agent init container:
575+
576+
```toml
577+
[dpf.dpu_agent_bootstrap_ca]
578+
source = "mounted"
579+
object_kind = "secret"
580+
name = "nico-bootstrap-ca-v1"
581+
key = "ca.crt"
582+
```
583+
584+
Use the following configuration for a ConfigMap that already exists in every
585+
target DPU cluster:
586+
587+
```toml
588+
[dpf.dpu_agent_bootstrap_ca]
589+
source = "mounted"
590+
object_kind = "config_map"
591+
name = "nico-bootstrap-ca-v1"
592+
key = "ca.crt"
593+
```
594+
595+
The URL override changes routing, not the initial trust model. An HTTPS URL is
596+
authenticated only when its server certificate chains to a root already
597+
trusted by the shared dpu-agent image.
598+
599+
Mounted mode never falls back to the legacy download. The shared published
600+
dpu-agent image does not embed a site-specific trust anchor. A mounted
601+
ConfigMap must already exist in the DPU cluster. A suitably labeled Secret can
602+
be propagated there by DPF. Refer to
603+
[DPU Agent Bootstrap CA](../../../../docs/manuals/dpf.md#dpu-agent-bootstrap-ca)
604+
for deployment and rotation instructions.
605+
547606
### `RmsConfig`
548607

549608
| Field | Type | Default | Description |

docs/bootable_artifacts.md

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,57 @@ Install 'mkosi' and 'debootstrap' from the repository -- for Debian it was
88
sudo apt install mkosi debootstrap
99
```
1010

11-
### 2. Build IPXE image
11+
### 2. Select the Bootstrap CA Bundle
12+
13+
Site-specific BlueField bootstream (BFB) builds accept an operator-supplied
14+
certificate authority (CA) bundle in Privacy-Enhanced Mail (PEM) format through
15+
`BOOTSTRAP_CA_PATH`:
16+
17+
```bash
18+
export BOOTSTRAP_CA_PATH=/absolute/path/to/site-bootstrap-roots.pem
19+
```
20+
21+
Build the production BFB from a supported environment with the existing
22+
aarch64 cross-build, BFB tooling, registry, and network prerequisites:
23+
24+
```bash
25+
cargo make --cwd pxe build-boot-artifacts-bfb
26+
```
27+
28+
`embedded` mode is available only when this variable is supplied explicitly.
29+
There is no fallback to `FORGE_CA_PATH`, a repository certificate, or a
30+
developer certificate. When it is absent, the dedicated embedded payload is
31+
removed, while existing legacy artifact inputs remain unchanged. Selecting
32+
`embedded` with such an artifact fails closed instead of downloading a CA.
33+
34+
The artifact stores this build-time input at the dedicated embedded source
35+
`/opt/forge/embedded_forge_root.pem`. At DPU boot, embedded mode copies it into
36+
the final `/opt/forge/forge_root.pem` location. This source is intentionally
37+
distinct from `mounted` mode, which expects the provisioning environment to
38+
populate the final path directly, so one mode cannot silently use material
39+
intended for the other.
40+
41+
The `[dpu_config].bootstrap_ca_source` policy is sent only on DPU provisioning
42+
paths. Host Scout boots do not consume it. Use the same bundle for every BFB
43+
variant deployed at a site.
44+
45+
For a root rotation, first build a bundle containing both the old and new
46+
roots, publish and deploy those artifacts, reprovision the fleet, and only then
47+
build a bundle without the old root. A non-DPF `mounted` deployment instead
48+
expects the provisioning environment to place the operator-managed bundle at
49+
`/opt/forge/forge_root.pem`. NICo does not create that mount.
50+
51+
Upgrade the NICo control plane and publish compatible artifacts before enabling
52+
`embedded` or `mounted`. Older artifacts support only the legacy download.
53+
Verify that the NICo API serves the intermediate certificate with its leaf when
54+
the artifact pins only the root. The bundle performs TLS server certificate
55+
validation whether the agent uses a client certificate for mutual TLS.
56+
57+
Embedding moves trust into the artifact. Protect artifact publication and
58+
distribution with verified signatures. Enforce Secure Boot or an equivalent
59+
chain of trust before treating the embedded CA as a pinned anchor.
60+
61+
### 3. Build iPXE Image
1262

1363
Run
1464

docs/dpu-management/dpu_configuration.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,58 @@ sequenceDiagram
4646
end
4747
```
4848

49+
## Bootstrap CA Trust
50+
51+
Before a DPU agent can use the configuration APIs, it needs a certificate
52+
authority (CA) bundle to authenticate the NICo API. Configure the bundle source
53+
for non-DPF provisioning in the site configuration:
54+
55+
```toml
56+
[dpu_config]
57+
bootstrap_ca_source = "legacy_download" # legacy_download | embedded | mounted
58+
```
59+
60+
If this field is omitted, NICo preserves the historical behavior: the booting
61+
DPU downloads `/api/v0/tls/root_ca` from `nico-pxe`. This supports rolling
62+
upgrades but the download remains dependent on unauthenticated DHCP, DNS, and
63+
HTTP. `embedded` uses a site-specific bundle staged into the DPU BFB only when
64+
its build is given an explicit `BOOTSTRAP_CA_PATH`. There is no repository or
65+
default fallback for the dedicated embedded payload. Existing legacy artifact
66+
inputs remain unchanged. `mounted` instead expects the provisioning environment
67+
to place an operator-managed bundle at `/opt/forge/forge_root.pem`. NICo does
68+
not create that mount. The embedded
69+
source at `/opt/forge/embedded_forge_root.pem` and mounted final path are
70+
distinct. Both non-network modes fail closed when their own bundle is missing
71+
or invalid and never fall back to the download.
72+
73+
NICo includes this setting only in DPU provisioning instructions. It does not
74+
change host Scout boot behavior.
75+
76+
Upgrade NICo and publish compatible boot artifacts before you change the
77+
setting. To switch an installed non-DPF DPU, reprovision it or use another
78+
trusted mechanism to install the bundle. Changing site configuration alone
79+
does not rewrite its filesystem. For root rotation, build or mount an overlap
80+
bundle containing the old and new roots. Migrate the fleet, then remove the old
81+
root.
82+
83+
Containerized DPF agents use the separate
84+
`[dpf.dpu_agent_bootstrap_ca]` policy and apply it when their init container
85+
starts. Refer to
86+
[DPU Agent Bootstrap CA](../manuals/dpf.md#dpu-agent-bootstrap-ca) for the
87+
legacy-download and mounted-object forms. The shared published DPF
88+
dpu-agent image does not embed a site trust anchor.
89+
90+
When pinning a root, verify that the NICo API sends the issuing intermediate
91+
certificate with its leaf certificate. Selecting a stable root establishes the
92+
intended trust anchor. With the complete chain, clients can validate leaf
93+
certificates across intermediate rotations without replacing the bundle. This
94+
is server certificate validation and remains required whether
95+
client-certificate authentication is enabled. It does not authenticate the
96+
earlier DHCP, DNS, iPXE, and user-data boot chain. Embedded mode also depends on
97+
an authenticated artifact and boot chain, such as verified image signatures
98+
plus Secure Boot. Otherwise, an attacker can replace both the artifact and its
99+
CA.
100+
49101
## Configuration Versioning
50102

51103
NICo uses versioned immutable configuration data in order to detect whether any intended changes have not yet been deployed:

0 commit comments

Comments
 (0)