Running EURECOM's open-exposure NEF against a simulated 5G core on Kubernetes, with ETSI OpenCAPIF in front of it doing real API authorisation — plus what broke along the way.
A NEF (Network Exposure Function) is the 3GPP front door: it lets an application outside the operator ask the network things it otherwise could not — where a device is, when it comes online, what QoS it can have. CAPIF is the framework that decides whether that application is allowed to ask. Getting the two to talk is where the interesting failures live.
This repository does not contain the NEF. That software is EURECOM's and stays theirs — see Upstream. What is here is the Kubernetes deployment, the CAPIF integration, the fixes, and the write-up.
k8s/ |
A kustomize deployment of the full NEF + core-simulator + observability stack. Upstream ships docker-compose and a Helm chart; this is the Kubernetes-native version |
k8s-capif/ |
The CAPIF integration — a ccf-bridge and the connector that registers the NEF as a CAPIF provider |
upstream/ |
Four fixes to upstream's Helm chart, as a patch, plus a free5gc values overlay |
docs/ |
The testbed write-up, the OpenCAPIF integration, and the investigation notes |
| Doc | Covers |
|---|---|
| Testbed | The four-layer model, what is deployed, every test and its result, the fixes, and the configuration hazard below |
| OpenCAPIF integration | Identifying the CCF implementation, provider onboarding, the mTLS hostname constraint and the bridge that satisfies it |
| Investigation notes | How the stack was mapped, including the branch survey across all 19 repositories |
A half-configured CAPIF looks like a working one. CAPIF enforcement is a feature toggle — an
empty capifSvc deliberately runs the NEF open. The hazard is that configured but unreachable
lands in the same branch: point the NEF at a CCF that never comes up and you get no 403s, an API
answering normally, and one line in the startup log. A broken CAPIF deployment is indistinguishable
from a working open one unless you read that log. Details.
The CCF's TLS certificate is also its JWT verification key. capif-service does
tls.Dial(<fqdn>:443), keeps the peer certificate, and uses that certificate's public key to
verify invoker JWTs. So the CCF cannot sit behind an ordinary HTTP reverse proxy — re-terminating
TLS hands it the wrong key and every token check fails. The bridge in
k8s-capif/10-ccf-bridge.yaml is therefore an nginx stream
(L4) proxy, with a hostAliases entry because the mTLS client also checks the hostname against the
certificate CN.
upstream/upstream-fixes.patch — four defects in upstream's Helm
chart, each of which failed silently:
redisSvcread the wrong value block. It pointed at the redis-stack subchart's values (aliasedredisinChart.yaml), which has nourikey, so it rendered empty and monitoring-event could not reach Redis. Visible only asimmediateRep: truereturning a report with nolocationInfo.fqdnwas never templated.values.yamlsets it to a template string; Helm does not recursively template values, so{{ .Values.global.fqdn.coreSimulator }}rendered literally into the config file. Fixed by running it throughtpl.- Missing positioning fields. Without a geographic anchor the simulator falls back to
CELLID, discarding the LMF's UL-TDoA fixes — nogeographicArea, no uncertainty ellipse, which is the simulator's most valuable output. - A race at startup.
core-network-servicesubscribes to AMF/SMF exactly once during init and logs success without checking the response, so subscribing before the core registers its NFs fails quietly and no event ever reaches Redis. Fixed with an init-container gate that waits for the AMF to actually answer.
The patch applies to feat/helm of nef/deployment at commit 50356f9.
kubectl apply -k k8s/ # NEF, core simulator, observability
kubectl apply -f k8s-capif/ # CAPIF bridge and provider registrationAddresses in the manifests and docs are RFC 5737 documentation ranges (198.51.100.x,
203.0.113.x) — substitute your own. Credentials are placeholders; set real ones before running
anything you care about.
Requires a Kubernetes cluster with an ingress controller, and a reachable 5G core (this was validated against both free5GC and Open5GS). The NEF images come from upstream.
The NEF, core simulator and CAPIF client library are EURECOM's open-exposure project, primarily by Giulio Carota and Thomas Du — https://gitlab.eurecom.fr/open-exposure. Apache-2.0 across most repositories; a few carry no licence, so check before reusing.
ETSI OpenCAPIF provides the CCF. The 3GPP OpenAPI definitions the NEF implements are © 3GPP and referenced by TS number rather than reproduced here.
See NOTICE for exactly which files are reproduced, which are derived, and which are original.
- Single-cluster lab. Validated on one Kubernetes cluster with a simulated core, not a multi-site or production deployment.
- A snapshot. Pinned to the upstream state of mid-2026; the project moves.
- Not a NEF distribution. For the software itself, go upstream.
- Positioning comes from the simulator, not a real LMF — the UL-TDoA fixes are synthetic.
Apache License 2.0, matching upstream. See NOTICE for attribution.