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.
| Interface | Carries | Policy input | Runtime check |
|---|---|---|---|
| IP | Application IP traffic | Named bridges | The requested bridges must be allowed by the admitted policy. |
| Frame bus | Fixed-size telemetry and command frames | APID range and send_to list | space-net checks the source APID and the destination service. |
| Supervision page | Heartbeat, health, mission time, and host commands | supervision_page declaration | The 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.projectversion: "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:
$ space build -t <your-registry>/payload:devSee 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:
apidsis one inclusive range written as[low, high].send_tois 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.