Environment variables

The agent loads a .env file from its working directory at startup, before anything else, so these can live there or in a systemd EnvironmentFile.

A flag always wins over its environment variable.

Security

VariableDefaultEffect
KEYSTONE_API_TOKEN—Bearer token for the HTTP API. Required for a non-loopback bind
KEYSTONE_TRUST_BUNDLE—PEM file of CAs used to verify artifact and recipe signatures
KEYSTONE_LEAF_CERT—Provisioned signing leaf certificate
KEYSTONE_INSECURE_SKIP_VERIFYfalseDisables mandatory artifact integrity. Development only
KEYSTONE_ALLOW_NO_EKU_SIGNERSfalseTransition only: accepts signing certificates with no extended key usage. Also honoured by keystonectl verify and by the self-update gate (--verify-update), which reads only the variable, not the flag
KEYSTONE_MAX_REQUEST_BYTES4 MiBHTTP request body cap (413 on overflow)
KEYSTONE_MAX_EXTRACT_BYTES2 GiBCap on decompressed archive size, so a small archive cannot fill the disk

Artifacts

VariableDefaultEffect
KEYSTONE_ARTIFACT_CACHE_LIMIT_BYTES2 GiBCache budget; oldest evicted first
KEYSTONE_DELTA_MAX_BASE_BYTES256 MiBLargest artifact the delta path will attempt. Patching costs memory proportional to the artifact, so past this size downloading it is cheaper than reconstructing it. 0 disables the limit
KEYSTONE_ARTIFACT_DOWNLOAD_TIMEOUT30mPer-artifact download timeout. Accepts 5m, 1h

Lifecycle

VariableDefaultEffect
KEYSTONE_INSTALL_TIMEOUT2mBound on the install phase of a layer
KEYSTONE_DEVICE_IDhostnameDevice identity, used by the messaging adapters

Containers

VariableDefaultEffect
KEYSTONE_CONTAINERD_SOCKET/run/containerd/containerd.sockcontainerd endpoint
KEYSTONE_CONTAINERD_NAMESPACEkeystonecontainerd namespace. On a host where Docker runs on top of containerd, the images live in moby, not here — see Containers
KEYSTONE_CONTAINER_SNAPSHOTTER—Snapshotter override (e.g. native, overlayfs)
KEYSTONE_CONTAINER_REGISTRY—Default registry for unqualified image names
KEYSTONE_IMAGE_VOLUME_DIR—Where image volumes are materialised
KEYSTONE_CNI_CONF_DIR—CNI configuration directory
KEYSTONE_CNI_PLUGIN_DIRS—CNI plugin search path
KEYSTONE_CNI_NETNS_DIR—CNI network namespace directory

Datasets

Datasets are declared per recipe, not by environment variable. What the agent exports to the component is one variable per dataset:

VariableValue
KEYSTONE_DATASET_<NAME>Absolute path to the dataset’s current symlink

The name is upper-cased with anything that is not a letter or digit replaced by an underscore, so cve-bundle becomes KEYSTONE_DATASET_CVE_BUNDLE. The path is absolute because a component runs with its own working directory. See datasets.

Clock

VariableFlagDefault
KEYSTONE_CLOCK_POLICY--clock-policyhigh-water

high-water verifies certificates against the later of the system clock and the agent’s own evidence that time has passed — a mark persisted across restarts and the binary’s build timestamp. It is what lets a gateway with no RTC, whose clock reads 1970 on first boot, accept a valid certificate instead of calling it “not yet valid”.

strict refuses to verify anything while the system clock is behind that evidence. Under it a signature check fails with a retryable error (HTTP 503), because the condition clears by itself once NTP runs.

There is deliberately no setting that ignores certificate expiry. Expiry is what makes a compromised signer stop working on its own; --insecure-skip-verify already exists for development.

Periodic reconcile

Off unless you ask for it. See reconcile and reuse.

VariableFlagDefault
KEYSTONE_RECONCILE_INTERVAL--reconcile-interval0 (disabled)
KEYSTONE_RECONCILE_JITTER--reconcile-jitter10% of the interval

The jitter offset is derived from the device ID (KEYSTONE_DEVICE_ID, or the hostname), not drawn at random, so a device lands in the same slot on every run and a fleet still spreads across the window. Setting the jitter to 0 explicitly is honoured — that is the right value for a single device.

MQTT

Every MQTT flag has an environment equivalent, which is how you normally configure it under systemd:

VariableFlag
KEYSTONE_MQTT_BROKER--mqtt-broker
KEYSTONE_MQTT_DEVICE_ID--mqtt-device-id
KEYSTONE_MQTT_TENANT--mqtt-tenant: required with MQTT, unless an enrolment provides it
KEYSTONE_MQTT_CLIENT_ID--mqtt-client-id
KEYSTONE_MQTT_USER / KEYSTONE_MQTT_PASS--mqtt-user / --mqtt-pass
KEYSTONE_MQTT_TLS_CERT / _KEY / _CAthe matching --mqtt-tls-*
KEYSTONE_ENROL_DIR--enrol-dir: the identity written by keystone enrol, which then provides the TLS files, tenant and device ID above. See Device enrolment
KEYSTONE_MQTT_TLS_VERIFY--mqtt-tls-verify
KEYSTONE_MQTT_QOS--mqtt-qos
KEYSTONE_MQTT_COMMAND_DEDUPE_TTL--mqtt-command-dedupe-ttl
KEYSTONE_SELF_UPDATE_ROOT--self-update-root
KEYSTONE_SELF_UPDATE_CONFIRM_TIMEOUT--self-update-confirm-timeout
KEYSTONE_MQTT_STATE_INTERVAL--mqtt-state-interval
KEYSTONE_MQTT_HEALTH_INTERVAL--mqtt-health-interval

An invalid value (a non-numeric integer, an unparseable duration, a bad boolean) is logged and ignored rather than crashing the agent — but check your logs, because “ignored” means the default is in force.

keystonectl

The client reads three of its own, and they are the ones worth exporting for a device you work on regularly. They are not part of the agent’s .env.

VariableFlagDefault
KEYSTONE_ADDR--addrhttp://127.0.0.1:8080
KEYSTONE_API_TOKEN--token(none)
KEYSTONE_SSH--ssh(direct connection)
export KEYSTONE_SSH=ops@edge-001:52022
export KEYSTONE_ADDR=http://127.0.0.1:9180   # resolved on the SSH host
keystonectl components

KEYSTONE_API_TOKEN is shared with the agent, which reads it as the token to require. See the CLI reference for what --ssh does and what it needs.