mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-30 04:33:00 +02:00
doc: expand on static vs dynamic factory-config
Infix now supports static /etc/factory-config.cfg from a rootfs overlay or /usr/share/product/<VPD.PRODUCT>/etc/factory-config.cfg in addition to the autogenerated /run/confd/*-config.gen files. Update the Branding & Releases document with a bit more information on this rather complex topic. [skip ci] Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
+192
-6
@@ -41,13 +41,92 @@ Verify the result after a build by inspecting:
|
||||
printed on a label on the device.
|
||||
|
||||
|
||||
Factory Defaults
|
||||
----------------
|
||||
Factory & Failure Config
|
||||
------------------------
|
||||
|
||||
The Infix default configuration, factory-config, is part static files
|
||||
and part per-device generated files, e.g., SSH hostkey and hostname.
|
||||
The latter is constructed from the file `/etc/hostname`, appended with
|
||||
the last three octets of the system's base MAC address. To override the
|
||||
To support booting the same image (CPU architecture) on multiple boards,
|
||||
Infix by default generates the device's initial configuration every time
|
||||
at boot. This also ensures the device can always be restored to a known
|
||||
state after a factory reset, since the `factory-config` is guaranteed to
|
||||
be compatible with the YANG models for the given software version. (For
|
||||
more information on how the system boots, please see the section [Key
|
||||
Concepts](introduction.md#key-concepts) in the Introduction document.)
|
||||
|
||||
However, for custom builds of Infix it is possible to override this with
|
||||
a single static `/etc/factory-config.cfg` (and failure-config) in your
|
||||
rootfs overlay -- with a [VPD](vpd.md) you can even support several!
|
||||
|
||||
|
||||
### Variables & Format Specifiers
|
||||
|
||||
Parts of the configuration you likely always want to generated, like the
|
||||
SSH hostkey used by NETCONF, a unique hostname, or the `admin` user's
|
||||
unique (per-device with a VPD) password hash. This section lists the
|
||||
available keywords, see the next section for examples of how to use
|
||||
them:
|
||||
|
||||
- **Default password hash:** `$factory$` (from VPD, .dtb, or built-in)
|
||||
XPath: `/ietf-system:system/authentication/user/password`
|
||||
- **Default NETCONF hostkey:** `genkey` (regenerated at factory reset)
|
||||
XPath: `/ietf-keystore:keystore/asymmetric-keys/asymmetric-key[name='genkey']`
|
||||
- **Hostname format specifiers:**
|
||||
XPath: `/ietf-system:system/hostname`
|
||||
- `%i`: OS ID, from `/etc/os-release`, from Menuconfig branding
|
||||
- `%h`: Default hostname, from `/etc/os-release`, from branding
|
||||
- `%m`: NIC specific part of base MAC, e.g., to `c0-ff-ee`
|
||||
- `%%`: Literal %
|
||||
|
||||
|
||||
### Static Files
|
||||
|
||||
> **Caveat:** maintaining static a factory-config and failure-config may
|
||||
> seem like an obvious choice, but as YANG models evolve (even the IETF
|
||||
> models get upgraded), you may need to upgrade your static files.
|
||||
|
||||
First, for one-off builds (one image per product), the simplest way is
|
||||
to override the location where the system looks for the files, `/etc`
|
||||
already at build time. This can be done using a Buildroot rootfs
|
||||
overlay providing, e.g., `/etc/factory-config.cfg`. Example: [NanoPi
|
||||
R2S][] in `${INFIX}/board/aarch64/r2s/rootfs/etc/factory-config.cfg`.
|
||||
|
||||
Second, to support multiple products in a single image, we can employ
|
||||
another method to install a `/etc/factory-config.cfg` override -- at
|
||||
runtime. This relies on the very early system `probe` that detects the
|
||||
specific product from VPD data.
|
||||
|
||||
The `probe` consists of several sequential steps that currently run from
|
||||
`${INFIX}/board/common/rootfs/usr/libexec/infix/init.d/`. One of them
|
||||
check if `/usr/share/product/<PRODUCT>` exists, and if so attempts to
|
||||
copy the entire contents to `/`. Here, `<PRODUCT>` is determined from
|
||||
the VPD, which is available in `/run/system.json` as `"product-name"`,
|
||||
after `00-probe` has run. The lower case version of the string is used.
|
||||
|
||||
I.e., create a rootfs overlay that provides any combination of:
|
||||
|
||||
- `/usr/share/product/<PRODUCT>/etc/factory-config.cfg`
|
||||
- `/usr/share/product/<PRODUCT>/etc/failure-config.cfg`
|
||||
|
||||
|
||||
### Dynamically Generated
|
||||
|
||||
The generated `factory-config` and `failure-config` files consist of
|
||||
both static JSON files and part generated files at runtime for each
|
||||
device. The resulting files are written to the RAM disk in `/run`:
|
||||
|
||||
- `/run/confd/factory-config.gen`
|
||||
- `/run/confd/failure-config.gen`
|
||||
|
||||
Provided no custom overrides (see above) have been installed already,
|
||||
these files are then copied to:
|
||||
|
||||
- `/etc/factory-config.cfg`
|
||||
- `/etc/failure-config.cfg`
|
||||
|
||||
... where the bootstrap process expects them to be in the next step.
|
||||
|
||||
Examples of generated contents are the SSH hostkey and hostname. The
|
||||
latter is constructed from the file `/etc/hostname`, appended with the
|
||||
last three octets of the system's base MAC address. To override the
|
||||
base hostname, set `BR2_TARGET_GENERIC_HOSTNAME` in your defconfig.
|
||||
|
||||
The static files are installed by Infix `confd` in `/usr/share/confd/`
|
||||
@@ -97,6 +176,112 @@ bootstrap script for more help, and up-to-date information.
|
||||
> you may want to look into `GEN_IFACE_OPTS`.
|
||||
|
||||
|
||||
### Example Snippets
|
||||
|
||||
**IETF System:**
|
||||
|
||||
```hsib
|
||||
"ietf-system:system": {
|
||||
"hostname": "example-%m",
|
||||
"ntp": {
|
||||
"enabled": true,
|
||||
"server": [
|
||||
{
|
||||
"name": "ntp.org",
|
||||
"udp": {
|
||||
"address": "pool.ntp.org"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"authentication": {
|
||||
"user": [
|
||||
{
|
||||
"name": "admin",
|
||||
"password": "$factory$",
|
||||
"infix-system:shell": "bash"
|
||||
}
|
||||
]
|
||||
},
|
||||
"infix-system:motd-banner": "Li0tLS0tLS0uCnwgIC4gLiAgfCBJbmZpeCAtLSBhIE5ldHdvcmsgT3BlcmF0aW5nIFN5c3RlbQp8LS4gdiAuLXwgaHR0cHM6Ly9rZXJuZWxraXQuZ2l0aHViLmlvCictJy0tLSctJwo="
|
||||
}, # <---- REMEMBER COMMA SEPARATORS IN SNIPPETS!
|
||||
# <---- ... and no comments.
|
||||
```
|
||||
|
||||
The `motd-banner` is a binary type, which is basically a Base64 encoded
|
||||
text file without line breaks (`-w0`):
|
||||
|
||||
```bash
|
||||
$ echo "Li0tLS0tLS0uCnwgIC4gLiAgfCBJbmZpeCAtLSBhIE5ldHdvcmsgT3BlcmF0aW5nIFN5c3RlbQp8LS4gdiAuLXwgaHR0cHM6Ly9rZXJuZWxraXQuZ2l0aHViLmlvCictJy0tLSctJwo=" |base64 -d
|
||||
.-------.
|
||||
| . . | Infix -- a Network Operating System
|
||||
|-. v .-| https://kernelkit.github.io
|
||||
'-'---'-'
|
||||
```
|
||||
|
||||
**IETF Keystore**
|
||||
|
||||
Notice how both the public and private keys are left empty here. The
|
||||
`genkey` is always automatically regenerated after each factory reset.
|
||||
Keeping the `factory-config` snippet like this means we can use the same
|
||||
file on multiple devices, without risking them sharing the same host
|
||||
keys. Sometimes you may want the same host keys, but that is the easy
|
||||
use-case and not documented here.
|
||||
|
||||
```json
|
||||
"ietf-keystore:keystore": {
|
||||
"asymmetric-keys": {
|
||||
"asymmetric-key": [
|
||||
{
|
||||
"name": "genkey",
|
||||
"public-key-format": "ietf-crypto-types:ssh-public-key-format",
|
||||
"public-key": "",
|
||||
"private-key-format": "ietf-crypto-types:rsa-private-key-format",
|
||||
"cleartext-private-key": "",
|
||||
"certificates": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
The `genkey` is currently only used by the NETCONF SSH backend.
|
||||
|
||||
**IETF NETCONF Server**
|
||||
|
||||
```json
|
||||
"ietf-netconf-server:netconf-server": {
|
||||
"listen": {
|
||||
"endpoints": {
|
||||
"endpoint": [
|
||||
{
|
||||
"name": "default-ssh",
|
||||
"ssh": {
|
||||
"tcp-server-parameters": {
|
||||
"local-address": "::"
|
||||
},
|
||||
"ssh-server-parameters": {
|
||||
"server-identity": {
|
||||
"host-key": [
|
||||
{
|
||||
"name": "default-key",
|
||||
"public-key": {
|
||||
"central-keystore-reference": "genkey"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
|
||||
|
||||
Integration
|
||||
-----------
|
||||
|
||||
@@ -203,3 +388,4 @@ variable `INFIX_OEM_PATH` to that of the br2-external. It is also
|
||||
possible to set the `GIT_VERSION` variable in your `post-build.sh`
|
||||
script to change how the VCS version is extracted.
|
||||
|
||||
[NanoPi R2S]: https://github.com/kernelkit/infix/blob/main/board/aarch64/r2s/rootfs/etc/factory-config.cfg
|
||||
|
||||
+17
-10
@@ -62,9 +62,11 @@ The system has several datastores (or files):
|
||||
configure context. Any changes made here can be discarded (`abort`,
|
||||
`rollback`) or committed (`commit`, `leave`) to `running-config`.
|
||||
|
||||
> See the [Branding & Releases](branding.md) for information on how
|
||||
> `factory-config` and `failure-config` can be adapted to different
|
||||
> customer requirements.
|
||||
> Please see the [Branding & Releases](branding.md) document for more
|
||||
> in-depth information on how `factory-config` and `failure-config` can
|
||||
> be adapted to different customer requirements. Including how you can
|
||||
> override the generated versions of these files with plain per-product
|
||||
> ones -- this may even protect against some of the failure modes below.
|
||||
|
||||
|
||||
## System Boot
|
||||
@@ -90,7 +92,8 @@ password in VPD, are detailed later in this section.
|
||||
there is a working fail safe, or rather *fail secure*, mode
|
||||
4. On first power-on, and after a factory reset, the system does not
|
||||
have a `startup-config`, in which case `factory-config` is copied
|
||||
to `startup-config`
|
||||
to `startup-config` -- if a per-product specific version exists it
|
||||
is preferred over the generated one
|
||||
5. Provided the integrity of the `startup-config` is OK, a system
|
||||
service loads and activates the configuration
|
||||
|
||||
@@ -123,13 +126,17 @@ syntax, failed validation against the system's YANG model, or a bug in
|
||||
the system's `confd` service, the *Fail Secure Mode* is triggered and
|
||||
`failure-config` is loaded (unless VPD Failure, see above).
|
||||
|
||||
> Again, please see the [Branding & Releases](branding.md) document for
|
||||
> how to provide a per-product hard-coded `failure-config` to suit your
|
||||
> products preferences.
|
||||
|
||||
*Fail Secure Mode* is a fail-safe mode provided for debugging the
|
||||
system. The default[^3] is isolated interfaces with communication only to
|
||||
the management CPU, SSH and console login using the device's factory
|
||||
reset password, IP connectivity only using IPv6 link-local, and device
|
||||
discovery protocols: LLDP, mDNS-SD. The login and shell prompt are set
|
||||
to `failure-c0-ff-ee`, the last three octets of the device's base MAC
|
||||
address.
|
||||
system. The default[^3] creates a setup of isolated interfaces with
|
||||
communication only to the management CPU, SSH and console login using
|
||||
the device's factory reset password, IP connectivity only using IPv6
|
||||
link-local, and device discovery protocols: LLDP, mDNS-SD. The login
|
||||
and shell prompt are set to `failure-c0-ff-ee`, the last three octets of
|
||||
the device's base MAC address.
|
||||
|
||||
[^1]: YANG is a modeling language from IETF, replacing that used for
|
||||
SNMP (MIB), used to describe the subsystems and properties of
|
||||
|
||||
Reference in New Issue
Block a user