Kubernetes-native management framework for Non-Terrestrial Networks (NTN). Declaratively manage satellite constellations, ground stations, NTN cell configurations, and terrestrial-satellite failover — all through standard Kubernetes CRDs.
Latest release: v0.4.0-rc.1 — Prometheus metrics integration, OLM bundle, signal hysteresis, cosign/SBOM supply chain. See CHANGELOG.md for the v0.2 → v0.3 → v0.4 additions.
| CRD | Short Name | Description |
|---|---|---|
| SatelliteEphemeris | sateph |
Auto-fetches GP data (OMM JSON) from CelesTrak or SpaceTrack, runs SGP4 pass prediction |
| GroundStationLifecycle | gs |
Manages edge ground station nodes — health checks, firmware OTA with timeout, K8s integration |
| NTNCellConfig | ntncc |
Configures NTN gNB cells via OCUDU provider (generates ConfigMap with OwnerReference) |
| NTNSlice | nts |
Manages terrestrial-satellite slice failover, QoS mapping, security policy, billing |
graph TB
subgraph "Kubernetes Cluster"
subgraph "NTN Operators"
SE[SatelliteEphemeris<br/>Controller]
GS[GroundStationLifecycle<br/>Controller]
NC[NTNCellConfig<br/>Controller]
NS[NTNSlice<br/>Controller]
end
subgraph "Provider Layer"
OP[OCUDU Provider]
CM[ConfigMap<br/>geo_ntn.yml]
end
subgraph "Failover Engine"
FE[Failover State Machine]
end
subgraph "Observability"
PM[Prometheus Metrics]
end
NC --> OP
OP --> CM
NS --> FE
SE & GS & NC & NS --> PM
end
CL[CelesTrak API] -.-> SE
ST[SpaceTrack API] -.-> SE
ND[K8s Node] -.-> GS
CM -.-> GNB[OCUDU gNB]
Data sources: SatelliteEphemeris supports CelesTrak (public, no auth) and SpaceTrack (requires credentials via K8s Secret). Both use the same OMM JSON format parsed by SGP4.
Provider pattern: NTNCellConfig uses a pluggable provider interface (currently OCUDU). Additional providers may be added in future releases.
Failover engine: NTNSlice evaluates trigger conditions (RSRP, latency, packet loss) and manages terrestrial-satellite path switching with configurable switchback delay. QoS, security, and billing parameters are tracked per active path.
Validation: CEL XValidation rules cover most constraints at admission (lat/lon range, path priority consistency, MetricsSource shape, ECEF non-zero, credentials when SpaceTrack). When the optional validating webhook is enabled (webhooks.enable=true in the Helm chart; off by default), it additionally enforces cross-field rules CEL cannot express — notably FailoverPolicy.triggers syntax. With the webhook disabled, invalid trigger syntax is caught at runtime by the failover engine instead.
- Go 1.26+
- Kubernetes 1.29+ (for CEL validation)
- kubectl
- Helm v3.16+ (optional, for Helm-based install)
# Install CRDs
make install
# Deploy via Helm
helm install ntn-operators dist/chart \
--namespace ntn-operators-system \
--create-namespace \
--set crd.enable=falsehack/kind-setup.sh
# Tear down when done:
hack/kind-setup.sh teardownmake install # Install CRDs
make run # Run controller locally (connects to current kubeconfig)# Satellite constellation tracking (CelesTrak)
kubectl apply -f config/samples/ntn_v1alpha1_satelliteephemeris.yaml
# Ground stations (Taipei + Hsinchu)
kubectl apply -f config/samples/ntn_v1alpha1_groundstationlifecycle.yaml
kubectl apply -f config/samples/ntn_v1alpha1_groundstationlifecycle_hsinchu.yaml
# NTN cell configuration (OCUDU)
kubectl apply -f config/samples/ntn_v1alpha1_ntncellconfig.yaml
# Terrestrial-satellite slice failover
kubectl apply -f config/samples/ntn_v1alpha1_ntnslice.yaml# Check satellite ephemeris data
kubectl get sateph
# NAME SATELLITES LAST UPDATED AGE
# oneweb-constellation 651 2m 5m
# Check ground station status
kubectl get gs
# NAME PHASE VENDOR K8S AGE
# gs-taipei-01 Provisioning ennoconn v1.35.1 5m
# Check NTN cell configuration
kubectl get ntncellconfigs
# NAME PROVIDER KOFFSET PAYLOAD AGE
# ntn-cell-geo-demo ocudu 150 transparent 5m
# Check NTN slice failover
kubectl get ntnslices
# NAME TENANT ACTIVE PATH FAILOVERS AGE
# enterprise-resilient-slice acme-corp terrestrial 0 5mapiVersion: ntn.operators.dev/v1alpha1
kind: SatelliteEphemeris
metadata:
name: oneweb-constellation
spec:
source:
type: CelesTrak
url: https://celestrak.org/NORAD/elements/gp.php?GROUP=oneweb&FORMAT=JSON
refreshInterval: 4h
satellites:
constellation: oneweb
passPrediction:
groundStations:
- gs-taipei-01
- gs-hsinchu-01
minElevation: "10"
horizon: 24hapiVersion: ntn.operators.dev/v1alpha1
kind: NTNCellConfig
metadata:
name: ntn-cell-geo-demo
spec:
provider:
type: ocudu
ntn:
cellSpecificKoffset: 150
ephemerisECEF:
posX: 20922195
posY: 1967783
posZ: 19770302
velX: 0
velY: 0
velZ: 0
payloadType: transparentapiVersion: ntn.operators.dev/v1alpha1
kind: NTNSlice
metadata:
name: enterprise-resilient-slice
spec:
tenant: acme-corp
terrestrialPath:
provider: chunghwa-telecom
priority: primary
satellitePath:
provider: oneweb
ephemerisRef: oneweb-constellation
priority: failover
failoverPolicy:
triggers:
- "rsrp < -120"
- "latency > 200"
switchbackDelay: 60s
sessionContinuity: true
qosMapping:
terrestrial5QI: 9
satelliteQCI: best-effort
security:
encryptionLevel: AES-256
authOnHandover: re-authenticateThe operator exports custom metrics at :8443/metrics:
| Metric | Type | Description |
|---|---|---|
ntn_operators_failover_total |
Counter | Failover events by slice, source/target path |
ntn_operators_satellite_pass_available |
Gauge | Satellite pass window active (1/0) |
ntn_operators_ground_station_health |
Gauge | Station condition status (1/0/-1) |
ntn_operators_config_apply_errors_total |
Counter | Cell config apply failures |
ntn_operators_gp_fetch_duration_seconds |
Histogram | GP data fetch duration |
ntn_operators_gp_satellite_count |
Gauge | Satellites from latest fetch |
ntn_operators_reader_query_duration_seconds |
Histogram | Per-query metrics reader latency, by source + outcome |
ntn_operators_reader_errors_total |
Counter | Metrics-reader failures, by source + reason |
ntn_operators_reader_stale_value_used_total |
Counter | Reconciles served from the stale cache, per slice |
To use SpaceTrack as a data source, create a Secret with your credentials:
apiVersion: v1
kind: Secret
metadata:
name: spacetrack-creds
type: Opaque
stringData:
username: your-spacetrack-username
password: your-spacetrack-passwordThen reference it in the SatelliteEphemeris:
apiVersion: ntn.operators.dev/v1alpha1
kind: SatelliteEphemeris
metadata:
name: oneweb-spacetrack
spec:
source:
type: SpaceTrack
url: https://www.space-track.org/basicspacedata/query/class/gp/GROUP/oneweb/format/json
refreshInterval: 4h
credentials:
name: spacetrack-creds
key: passwordmake generate # Generate DeepCopy methods
make manifests # Generate CRD and RBAC YAML
make test # Run unit + envtest tests
make lint # Run golangci-lint
make build # Build manager binary
make docs # Generate API reference from CRDs
make ko-build # Build container image with ko (local)
make ko-push # Build and push multi-arch image
make test-e2e # Run E2E tests on Kind clusterapi/v1alpha1/ # CRD type definitions (with CEL validation rules)
internal/controller/ # Reconciler implementations
pkg/ephemeris/ # CelesTrak + SpaceTrack GP fetchers, SGP4 pass prediction
pkg/provider/ocudu/ # OCUDU provider (config generation)
pkg/slice/ # Failover state machine + trigger parser
pkg/netutil/ # SSRF-safe HTTP client
pkg/metrics/ # Custom Prometheus metrics
config/crd/ # Generated CRD YAML
config/samples/ # Sample CR manifests
dist/chart/ # Helm chart
hack/ # Demo and setup scripts
docs/ # API reference (auto-generated)
- Antenna health:
AntennaReadyis still simulated as True when the node exists; real hardware agents are tracked for v1.0 (#68). - Session continuity: The
sessionContinuityspec field is tracked but not yet enforced at the data plane — paused (#69). - Providers: Only OCUDU is implemented; OAI gNB support is tracked for v1.0 (#65).
- Firmware updates: The controller monitors node annotations for firmware versions but does not directly trigger OTA. An external agent on the node manages the actual update.
- Metrics source:
spec.metricsSource.type=annotations(or omitting themetricsSourceblock entirely) is the default for backward compatibility. Production deployments should setspec.metricsSource.type=prometheus— seeconfig/samples/ntn_v1alpha1_ntnslice_prometheus.yamlfor a copy-pasteable example and the CHANGELOG for the pluggable reader layer shipped in #67.
Import config/grafana/ntn-operators-dashboard.json into your Grafana instance to visualize all 6 custom metrics (failover events, satellite pass availability, ground station health, fetch duration, satellite count, config errors).
See docs/api-reference.md for the complete CRD field reference.
See CONTRIBUTING.md for development guidelines.