Skip to content

About

Replicated RADIUS server in Java on Aeron Cluster: accounting acknowledged only after a majority commit, PAP/CHAP/MS-CHAP/EAP (TLS, PEAP, TTLS, TEAP, SIM/AKA), RadSec, DTLS, proxying, CoA. Helm chart, Docker, ECS.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

152 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

radiusward

CI CodeQL Quality Gate Coverage Maintainability Integration tests End-to-end tests Fault injection Kubernetes Benchmark License: Apache-2.0

A replicated RADIUS server for Java — accounting and authentication — built on Aeron Cluster.

radiusward answers an Accounting-Request only after the record is durably committed on a majority of a three-node cluster (fsync on), so an acknowledged accounting record survives the loss of any single node. Duplicate and retransmitted requests — including retries that arrive through another gateway after a failover — are recognised and answered without being counted twice.

Access-Requests are decided by the gateways from identity stores (users file, SQL, LDAP/Active Directory, Netlogon); what must be shared between gateways — simultaneous-use counts, SIM sequence numbers — lives in the same replicated state.

Status: Phase 5 complete — authentication with PAP, CHAP, MS-CHAP and the EAP methods below, RadSec, DTLS and TCP, proxying, CoA/Disconnect, policies and pools; EAP-SIM, EAP-AKA and EAP-AKA′ with local SIM keys. Phases 0–3: replicated accounting, container image, durability proven on Linux with simulated power loss of all members, partitions, full disks and overload (2M sessions in 1 GiB per member), a crashed leader replaced in ~2.2 s without NAS retransmissions, export to PostgreSQL. Phase 4: a Helm chart and systemd units, members that reseed themselves after a lost disk, a continuous backup that restores a lost quorum, and 500k sessions under leader kills, partitions and node drains on Kubernetes without a lost request (report); deployment guides for Kubernetes, Amazon ECS on Graviton and bare metal; published test reports and weekly benchmarks. Next: more sinks (Phase 3b) — see the roadmap.

What it does

  • Accounting: acknowledged only after the commit; deduplication of retransmissions across gateways; Accounting-On/Off; idle sessions closed; export to PostgreSQL, JSON-lines files, or forwarded to other RADIUS servers (docs/accounting-contract.md).
  • Authentication methods: PAP, CHAP, MS-CHAPv1/v2, EAP-MD5, EAP-TLS, PEAP (MS-CHAPv2, GTC, TLS inside, crypto binding), TTLS (PAP, CHAP, MS-CHAP, EAP inside), TEAP, EAP-pwd, EAP-SIM, EAP-AKA, EAP-AKA′ (pseudonyms and fast re-authentication); TOTP as a second factor; stored passwords from cleartext to bcrypt, SHA-crypt, yescrypt and NT hashes.
  • Identity stores: users file, SQL (radcheck layout), LDAP/Active Directory, Active Directory over Netlogon (pure Java); plug-in API for more.
  • Transports: UDP over IPv4 and IPv6, RadSec (RADIUS over TLS), RADIUS over DTLS and over TCP; NAS entries by address, network or client certificate, or looked up in SQL on demand.
  • Policy: check and reply items, groups, Simultaneous-Use across all gateways, login times, expiry, usage counters, IPv4 and IPv6 address pools, Chargeable-User-Identity, a small rule layer.
  • Proxying: realms to pools of home servers over UDP, TLS, TCP or DTLS with failover and load balancing, RFC 7585 discovery, per-realm rewriting, inner-tunnel proxying, CoA relay.
  • CoA and Disconnect: by user or session through an HTTP API, disconnect-oldest for Simultaneous-Use.
  • Operations: Prometheus metrics with five Grafana dashboards and alert rules (monitoring), per-request traces, an authentication log, delayed rejects, configuration reload on SIGHUP; public multi-arch container images, a Helm chart and systemd units.
  • Recovery: a member that lost its disk reseeds itself from the others (ADR 0063); cluster-backup keeps a continuous backup outside the cluster, and cluster-restore or cluster.restore.from brings back a cluster that lost its quorum (backup).

Architecture in short

 NAS ──UDP/TLS/DTLS/TCP──▶ gateway A ─┐                       ┌──▶ sink: PostgreSQL
                           gateway B ─┼─▶ Aeron Cluster ──────┼──▶ sink: JSON files
                              │       │   (3 nodes, Raft,     └──▶ sink: RADIUS forwarding
                              │       │    fsync, dedup,
                              │       │    shared auth state)
 Accounting-Response ◀────────┼───────┘   only after commit
 Access-Accept/Reject ◀── identity stores (file, SQL, LDAP/AD, Netlogon) · home servers (proxying)
  • Gateways (stateless, NIO): own the sockets, validate and authenticate packets, extract the hot attributes without allocating, forward accounting to the cluster and reply after commit; decide Access-Requests on worker threads from the identity stores.
  • Cluster (Aeron Cluster, 3 nodes): replicated, fsynced log; per-session deduplication; snapshots; the shared state of authentication (reservations, sequence numbers).
  • Exporter (inside every member): tails the committed log into pluggable sinks — PostgreSQL, JSON files and RADIUS forwarding built in, more on the roadmap.

Test reports of the integration, end-to-end, fault-injection and Kubernetes suites, and the benchmarks: radiusward.github.io/radiusward-server.

Benchmarks

scripts/bench.py raises the request rate step by step until p99 latency passes 500 ms or a request is lost, for accounting, authentication and a mix, kills the leader under load and runs the JMH suite (docs/testing/benchmarks.md, ADR 0066). It runs weekly on a GitHub runner and the results are published. On a shared 4-vCPU runner, where three members, two gateways and the load generators share the CPUs — a lower bound — it carried 3,731 accounting requests/s (each replicated to three members with fsync), at least 15,053 Access-Requests/s (every step up to 16,000/s passed) and 6,821/s mixed, and a leader killed under load lost nothing. The hot path alone handles about 1.3 million packets/s on one core (JMH). The ceilings per profile on AWS, with the generators on their own machines, are measured with scripts/bench-aws.sh.

Details: docs/architecture.md · what an ACK guarantees: docs/accounting-contract.md · decisions: docs/adr · every setting: docs/configuration.md.

Quickstart with Docker

./mvnw -q install -DskipTests && docker build -f deploy/docker/Dockerfile -t radiusward:dev .
docker compose -f deploy/compose/compose.yaml up -d --wait   # 3 members + 2 gateways, fsync on
docker compose -f deploy/compose/compose.yaml run --rm tools acct --server gateway-a:1813 \
     --secret testing123 --status start --session-id abc123
deploy/compose/demo-failover.sh                              # kill -9 the leader under load, nothing lost

Released images (public, amd64 and arm64): ghcr.io/radiusward/radiusward-server (docs/operations/docker.md); a backup profile in compose runs the continuous backup.

Kubernetes

helm install radiusward deploy/helm/radiusward -n radius --create-namespace -f my-values.yaml

Three members and two gateways, each gateway with its own address for the NAS's primary and secondary server — docs/operations/kubernetes.md. The chart also runs the continuous backup and ships the dashboards and alert rules; it is tested nightly on kind under load (leader killed, members and gateways rolled, a volume replaced, a lost quorum restored). On Amazon ECS: docs/operations/aws-ecs.md with example CloudFormation and Terraform templates for Graviton in deploy/aws. On plain hosts with systemd: docs/operations/bare-metal.md. Restoring after a lost quorum: docs/operations/backup.md.

Quickstart without Docker

Requirements: JDK 25+.

./mvnw verify                          # build + unit/integration tests (~1 min)
scripts/run-local.sh start             # 3 cluster members + 2 gateways as separate JVMs
scripts/run-local.sh wait-ready && scripts/run-local.sh status

java -jar tools/radclient/target/radclient.jar acct --server 127.0.0.1:1813 --secret testing123 \
     --status start --session-id abc123 --user alice --vendor cisco

scripts/run-local.sh demo-failover     # load through both gateways, kill -9 the leader, nothing lost
./mvnw -Pe2e verify                    # end-to-end tests against real processes
scripts/linux-tests.sh                 # fault injection in containers (needs Docker; nightly in CI)

More in docs/operations/local-cluster.md and docs/configuration.md.

Authentication in a few lines

gateway.auth.enabled = true
auth.stores = local
auth.store.local.type = file
auth.store.local.path = /etc/radiusward/users       # alice  Cleartext-Password := "secret"
auth.store.local.mschap = true                      # MS-CHAPv2 (PEAP) from Cleartext-Password
auth.eap.methods = peap, ttls, tls
auth.eap.tls.certificate = /etc/radiusward/server.pem
auth.eap.tls.key = /etc/radiusward/server.key
auth.eap.tls.ca = /etc/radiusward/ca.pem

Stores, methods, RadSec, proxying and policies: docs/configuration.md.

Modules

Module What it is
protocol SBE messages between gateways, cluster and tools
common configuration, profiles, management HTTP server, non-blocking logging
cluster-service deterministic accounting state machine (dedup, sessions, snapshots)
cluster-node launches a cluster member; seeding, continuous backup and restore
gateway RADIUS gateway: accounting, authentication, EAP, RadSec/DTLS/TCP, proxying, CoA
export-api sink plug-in API, canonical attribute encoding, migration runner
exporter exports the committed log to sinks (lease, state-machine reducer)
sinks/postgres PostgreSQL sink
sinks/file JSON-lines sink
sinks/radius forwards accounting of proxied realms to their home servers
auth-api identity store plug-in API
stores/file users-file identity store
stores/sql SQL identity store (radcheck schema)
stores/ldap LDAP/Active Directory identity store and bind verifier
verifiers/netlogon Active Directory over Netlogon, pure Java (MS-CHAPv1/v2, PAP)
distribution the runnable radiusward.jar
radius-dictionary FreeRADIUS-format dictionary parser and attribute tree
radius-dictionary-freeradius Bundled FreeRADIUS dictionaries (CC BY 4.0)
radius-codegen Generates constants and the hot-attribute extractor
radius-codec Zero-allocation RADIUS packet codec
tools/radclient Command-line test client: accounting and Access-Requests (PAP, CHAP, MS-CHAPv2), replays, decoding, load
tools/admin-cli replicated state, sinks and export checks, resync, CoA/Disconnect, state versions
testing/test-harness in-JVM local cluster, dev mode
testing/e2e-tests end-to-end tests against real processes (-Pe2e)
testing/linux-tests fault injection in containers: power loss, partitions, full disk, overload (-Plinux)
testing/benchmarks JMH benchmarks
testing/coverage Aggregate coverage over unit + integration tests, module floors (-Pcoverage)
testing/test-images the prebuilt public test images (ghcr.io/radiusward/radiusward-test-images), built locally when not published
testing/interop-debs the interop tests' server packages as .deb files for CI
testing/eapol-test wpa_supplicant's eapol_test with its SIM/USIM simulator, for the EAP interop tests
testing/radsec-client radsecproxy and clients for the RadSec and DTLS interop tests
testing/samba-ad Samba AD domain controller for the LDAP and Netlogon tests

Supported vendors

All 190+ vendors in the bundled FreeRADIUS dictionaries are decoded. Cisco, Juniper (Junos 2636 and ERX/Unisphere 4874 for MX subscriber management), MikroTik, Huawei, Meraki and Ruckus additionally have generated accessors, deduplication profiles (Phase 1) and test fixtures; Aruba, Ubiquiti UniFi, Open-Mesh and MikroTik hotspots have test fixtures too. Operators can add or override dictionaries in /etc/radiusward/dictionary.d/ (docs/dictionaries.md).

License

Apache License 2.0 — see LICENSE and NOTICE.

Third-party resources

The RADIUS dictionary files in radius-dictionary-freeradius come from the FreeRADIUS project and are licensed under the Creative Commons Attribution 4.0 International License (CC BY 4.0). Copyright The FreeRADIUS Server project and contributors. Source commit and the one change made are recorded in NOTICE and THIRD-PARTY-LICENSES.md.

About

Replicated RADIUS server in Java on Aeron Cluster: accounting acknowledged only after a majority commit, PAP/CHAP/MS-CHAP/EAP (TLS, PEAP, TTLS, TEAP, SIM/AKA), RadSec, DTLS, proxying, CoA. Helm chart, Docker, ECS.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages