Skip to content
The shipped runtime reads and enforces every interface declaration below, but the ground-link commands need a target and a registry, so they are shown rather than run by the documentation gate. Declaring interfaces in space.yaml and building the project work today.

Networking and data planes

A compromised or buggy service that can reach every socket on a payload computer can flood the link to the ground or spoof another service's telemetry. SpaceOS gives each service only the interfaces declared for it in space.yaml. When it resolves a deployment, the space CLI turns those declarations into each partition's signed capability: the list of what the partition may use (APIDs, routes, bridges, ports, data links, and secrets), signed, with its digest carried in the release. The runner checks that signature before it starts a service and refuses any request that is not a subset of the capability; it then uses the declarations to configure the service. The capability envelope glossary entry names its fields.

InterfaceCarriesPolicy inputRuntime check
IPApplication IP trafficNamed bridgesThe requested bridges must be allowed by the admitted policy.
Frame busFixed-size telemetry and command framesAPID range and send_to listspace-net checks the source APID and the destination service.
Supervision pageHeartbeat, health, mission time, and host commandssupervision_page declarationThe host treats guest-written fields as untrusted and reads them through bounded accessors.

The frame bus and supervision page are separate. A stalled frame bus does not prevent the host from reading the service heartbeat.

Declare service interfaces

Declare interfaces on each service in space.yaml:

schema: space.project
version: "1"
build:
output: _build/spaceos
run:
partitions:
payload:
services:
- name: classifier
image: ghcr.io/<your-org>/classifier:1
runtime: oci
isolation: runc
interfaces:
- type: ip
bridges: [payload-net]
- type: frame_bus
apids: [0x120, 0x12F]
send_to: [sdls-downlink]
- type: supervision_page
- name: sdls-downlink
image: ghcr.io/parsimoni-labs/sdls-downlink:1
runtime: oci
isolation: runc
interfaces:
- type: frame_bus
apids: [0x130, 0x13F]

Build the project after changing an interface declaration:

Terminal window
$ space build -t <your-registry>/payload:dev

See the space.yaml reference for the complete interface syntax.

IP interfaces

An ip interface lists the bridges the service may join. A bridge is a named virtual network segment, a software switch that the services joining it share. Bridge names are policy labels, not credentials. The capability's network_policy field lists the bridges the partition may use, and the runner rejects a bridge outside that list.

A service with no ip interface has no declared IP bridge. The host_network interface is a separate capability for a runc service. It lists the TCP ports the service may bind in the node network namespace, the node's own network stack, so those ports are reachable on the node's addresses. A service cannot combine host_network with an ip bridge.

Do not use an IP address as service identity. Network policy is derived from the admitted service and interface declarations.

Frame bus

A frame_bus interface contains two fields:

  • apids is one inclusive range written as [low, high].
  • send_to is the default-deny list of local services this service may reach.

Each service on the frame bus gets its own Unix socket. The service does not choose the identity attached to that socket. space-net uses that identity to check the source APID and the destination allow-list.

An APID (application process identifier) is the 11-bit number CCSDS gives each stream of packets. Every frame is 256 bytes: an 8-byte header (version, message type, source APID, payload length, destination APID) and a 248-byte payload; the frame bus format gives the byte layout. APIDs identify streams and route frames. They are not authentication credentials: space-net knows the sender by the socket a frame arrived on, and uses the APID only to check it lies in that sender's range.

Ground relay

The relay sends frames between one source partition, other partitions, and the reserved ground destination. It also applies a token-bucket rate limit and a bounded egress queue. A token bucket refills at r tokens per second up to a capacity of b tokens, and each frame spends one token. A source can therefore send b frames at once and r frames per second after that. Each egress queue holds q frames, and when it is full the relay drops by the configured policy. The defaults in space.yaml are r = 1000, b = 64, q = 256, and drop-oldest. A frame carries 248 bytes of payload, so one source sustains 248 × 1000 = 248,000 payload bytes per second (about 2 Mbit/s), and a full queue holds 256 × 248 = 63,488 payload bytes.

The SDLS relay authenticates frames and checks the anti-replay sequence number. A relay frame is 276 bytes: a 6-byte CCSDS Space Packet header, a 6-byte security header (a 2-byte security parameter index naming the association and a 4-byte sequence number, set by sn_len), the 248-byte data field, and a 16-byte MAC. The MAC covers the headers and the data under the association's key. The receiver drops a frame whose MAC fails. It accepts a sequence number above the highest it has seen, or one at most 128 below it (arsnw) that its window has not seen yet, and refuses every other number, so a recorded frame sent again is refused. Framing and authentication take 28 of the 276 bytes, about 10 percent of the link. The association names its authentication suite, one of aes-256-cmac, hmac-sha-256, hmac-sha-384, or hmac-sha-512, and the relay opens it with authentication enabled and encryption disabled. It does not encrypt frame payloads.

Supervision page

The supervision page is a 4096-byte shared-memory page between a service and the host runner.

The guest writes:

  • a heartbeat counter;
  • a status word;
  • a bounded health string;
  • acknowledgements for host commands.

The host writes:

  • the heartbeat acknowledgement;
  • mission time under a seqlock (a version counter beside the value: the host makes it odd, writes the time, then makes it even, and a reader retries until it reads the same even version before and after copying, so it never sees a half-written time);
  • the host command word.

The split is a protocol convention. A compromised guest can write any byte in the page. The runner therefore treats all guest fields as untrusted. It bounds the health string, reads status words as unsigned values, and compares heartbeat progress only with the host clock.

The runner reads the heartbeat counter once a second and reports a service as wedged when the counter has not advanced for the stall timeout, 5 seconds by default. The same grace applies before the first beat. A fresh heartbeat returns it to the alive state.

Ground transport security

The ground path uses separate transport and security layers:

  • CFDP Class 2 handles acknowledged object transfer.
  • BPv7 carries bundles over intermittent links.
  • BPSec authenticates bundle payloads with a Block Integrity Block (BIB).
  • SDLS authenticates frames on the relay association.

The BPSec receiver refuses an unprotected payload, a wrong key, insufficient integrity scope, a replayed bundle, and a bundle outside its acceptance window. The integrity scope (RFC 9173) is a set of flags saying which parts of the bundle the BIB's MAC covers besides the payload: the primary block, the target block's header, and the security block's header. The receiver requires the primary block and the target header, so a valid payload MAC cannot be moved onto another bundle. The acceptance window is the age beyond which a bundle is refused as stale: 7 days by default, with 5 minutes of clock skew allowed. The receiver keeps the identifier of each bundle it admitted inside that window, up to a fixed number of entries, and refuses a bundle it has already admitted. The outgoing producer currently adds a BIB. It does not add a Block Confidentiality Block (BCB).

Each of these layers gives some security properties and not others, and a protocol name alone establishes none of them:

  • Authentication identifies the key or peer that produced a message. BPSec's Block Integrity Block and the SDLS relay both give it.
  • Integrity detects a change to protected bytes. The same two layers give it.
  • Replay protection rejects a message that was valid in an earlier window. The SDLS sequence window and the BPSec receiver's replay state give it.
  • Confidentiality keeps protected data from an observer without the key. No layer gives it, as the caution above says.
  • Authorization decides what an authenticated peer may do. The signed capability gives it. The link does not.

Network access does not authorize a workload or a command. Software admission is a separate verification path, described in Signing and verification.