01The key is declared, not inferred
Every path pattern declares exactly what enters its key. Nothing is cacheable until declared, and an origin Vary outside the declared key stops the object being stored and alerts the owner.
ADR-0129 views, in reading order. Every view ships three ways: an HTML page, an SVG that re-opens in diagrams.net fully editable, and draw.io source.
A content delivery platform built from open-source software on hardware the organisation owns: 18 points of presence announcing anycast prefixes, Envoy terminating TLS and HTTP/3, Apache Traffic Server caching in memory and on NVMe, four shield pools in front of the origins, and a control plane in two core data centres that is never on the request path. Read the set in order. Acts 1 and 2 fix the boundary and the people who depend on it. Act 3 shows the parts and the path of one request. Act 4 separates the four kinds of data and shows the cache key being built. Act 5 walks a flash crowd, a two-million-object purge, a returning PoP and a bad configuration. Acts 6 and 7 cover how it is run, what it costs and why it is safe to leave eighteen sites unattended. One decision governs every page: the cache key is a security boundary, declared by the property owner and never inferred from the origin.
A cache hit is a claim that a stored response is the correct answer for this request. The cache key is the whole content of that claim. This architecture is built around getting the key right, and around everything that becomes cheap once it is.
Delivery platforms are sold on latency, but what they are worth is the origin traffic they prevent. Both come from the same mechanism: a request answered from a nearby cache instead of a distant origin. The failure that matters most does not show up on a latency graph. It is a hit on the wrong key: one user's signed-in page served to thousands of strangers, from cache, at line rate, with every metric green. The estate here is 18 points of presence on four continents, 40 properties belonging to business units of one organisation, 250,000 requests per second at peak and 900 million cacheable objects, all on open-source software and hardware the organisation operates itself. The job is not only to serve bytes quickly. It is to serve only correct bytes, make the origin see a small and predictable fraction of the traffic, make a content change visible everywhere within seconds with proof, and keep working when anything outside the PoP is down.
Each PoP announces four anycast prefix classes through BIRD. Katran spreads connections across cache nodes using consistent hashing that understands QUIC. On each node, Envoy terminates TLS 1.3, HTTP/2 and HTTP/3, verifies signed URLs and enforces per-property ceilings, then passes the request over loopback to Apache Traffic Server. Traffic Server builds the key with keyspec, a small Rust library that follows the property's declared rules and nothing else. It checks the tag table for invalidations, then serves from memory or NVMe. A miss goes to the node that owns the key in the PoP's ring, then to one of four shield pools placed next to the origins, where concurrent fetches collapse into one and per-origin ceilings are enforced. Property configuration lives in Git, is validated with CUE, invariant checks and a two-user identity probe, compiled into signed bundles and rolled out one ring at a time by a Temporal workflow that halts itself on a regression. Purges are records in a NATS JetStream log mirrored into every PoP. A purge is applied by timestamp comparison, so it costs the same for one object or two million, and each PoP's acknowledgement is recorded. Access records go through Vector and Kafka into ClickHouse, where hit ratio, offload and cost per terabyte are computed per property and per path pattern. None of the control or telemetry systems is on the request path.
Every path pattern declares exactly what enters its key. Nothing is cacheable until declared, and an origin Vary outside the declared key stops the object being stored and alerts the owner.
ADR-01The same Rust library computes the key in the cache plugin, the validator and the explain API. The tool an owner uses to check a key cannot disagree with production.
ADR-02Validation fetches declared test URLs as two users. A path whose response changes with the user cannot become cacheable under a key that leaves the user out.
ADR-04A purge is one row: tag, time, mode. A lookup compares the object's store time with it. Two million objects cost the same as one, and serving never waits for a purge.
ADR-13Invalidations are an ordered, replicated log mirrored into every PoP. Each PoP records how far it has applied, and a returning PoP catches up before it announces.
ADR-14Misses hash to a shield node next to the origin, and requests collapse at the node, the PoP and the shield. Origin load follows how often content changes, not how many users arrive.
ADR-10PoPs apply only signed bundles, keep the last five on disk and serve on the last good one indefinitely. Control plane, logs and analytics may all be down while delivery continues.
ADR-21Each PoP holds its own 14-day certificates, sealed to its TPM. A stolen server is revoked alone, and its keys are useless within days whatever happens to revocation.
ADR-24Delivery platforms usually age badly in one of four ways. The cache engine is replaced and every property's behaviour quietly changes with it. The organisation decides to buy the edge instead of running it, and the configuration and purge semantics turn out to be tied to one product. The object count grows past what the purge or index design assumed. Or a vendor changes its licence and a core component has to be replaced under pressure. The design defends against each of these on purpose.
A declared key, not-cacheable by default, and refusing private responses are expressed in HTTP caching semantics (RFC 9111), Cache-Status (RFC 9211) and surrogate keys. They were right for proxy caches twenty years ago and will be right for whatever replaces Traffic Server. The property owner's declaration is the lasting asset, not the engine that reads it.
Owners write engine-neutral YAML. A compiler turns it into Envoy and Traffic Server configuration today. Moving to another engine, or to a commercial CDN's configuration API, means writing a new compiler back end and replaying the ring rollout, not rewriting 40 properties by hand.
Because one library computes the key everywhere, its behaviour is fixed by a corpus of real requests and expected keys. A new engine or a new team inherits the exact key semantics by linking the library or passing the corpus.
Cached content is derived and disposable, so hardware generations, storage technologies and even the cache engine can be changed one PoP at a time with a cold start as the only cost. There is no data to move and no recovery objective to protect during a migration.
Invalidation by timestamp comparison, per-node LMDB tables bounded by the TTL ceiling and hashed ownership inside a PoP mean that going from 900 million to 2 billion objects lowers the hit ratio at the margin but does not change a single design element.
BGP, HTTP/3 and QUIC, ACME, SPIFFE, OIDC, the S3 API, the Kafka protocol and Prometheus exposition sit between the components. Any single product can be replaced without its neighbours noticing, which is what keeps a ten-year platform from becoming a ten-year dependency.
Components are chosen for open governance where it exists: Apache, CNCF, Linux Foundation. OpenBao was chosen over Vault after Vault's licence change showed what a single-vendor project can do. Where one company leads, such as Katran, NATS, Temporal, ClickHouse and Vector, the record names the fallback: IPVS with Maglev, Kafka, plain workers with PostgreSQL, Parquet on Ceph, Fluent Bit.
Per-node capacity, hit ratio per path, cost per terabyte, cost per miss and the cost of n−1 headroom are published every month. Whoever re-decides these choices in five years starts from measurements, not from this document.
Targets from the requirement, and the mechanism that meets each one. Every latency, throughput and cost figure is replaced by a measured value in the proof phase and republished monthly.
| Quality | Target | How it is met | View |
|---|---|---|---|
| Delivery availability | ≥ 99.99% monthly, measured from outside | Anycast across 18 PoPs with n−1 regional capacity; guarded automatic withdrawal; success rate measured by probes in 12 external networks | 24 |
| Purge API · control plane | ≥ 99.95% · ≥ 99.9% | Purge API on Kubernetes in two core DCs behind a JetStream quorum across three sites; configuration pipeline allowed to be slower to recover because PoPs keep serving | 20 |
| Cache-hit TTFB | p50 ≤ 15 ms · p95 ≤ 45 ms · p99 ≤ 120 ms | Hot set in 384 GB of RAM per node, NVMe long tail, loopback hop between Envoy and Traffic Server, PoPs within the latency radius of most users | 09 |
| Shield hit | ≤ 60 ms p95 added, same continent | Shield pools at IAD, DFW, FRA and LHR next to the origins; Asia and South America over budget by construction and reported separately | 02 |
| TLS handshake | p95 ≤ 25 ms resumed · ≤ 80 ms full | TLS 1.3 and QUIC terminated at the PoP with local keys; hourly session-ticket key rotation per PoP; no keyless round trip on the handshake path | 28 |
| Cache effectiveness | ≥ 96% requests · ≥ 92% bytes · offload ≥ 98.5% bytes | Declared allow-lists, intra-PoP ownership ring, shield convergence, conditional revalidation end to end, hit ratio published per path pattern | 13 |
| Throughput | 250k req/s · 400 Gbps peak · 2× without redesign | 72 edge nodes at a 20 Gbps planning ceiling (about 1.4 Tbps nominal), added a node or a PoP at a time; per-node ceiling measured before capacity plans use it | 20 |
| Flash crowd | 8× one property for 90 s, no origin impact | Read-while-writer collapsing at node, PoP ring and shield; TTL jitter; per-origin connection ceilings at the shield | 15 |
| Invalidation | 99% of PoPs ≤ 5 s p95 · ≤ 30 s p99, including 2 M objects | One JetStream record per purge, mirrored to leaf nodes, applied as a timestamp in LMDB, acknowledged per PoP | 16 |
| Configuration | All PoPs ≤ 60 s p95 per ring · halt ≤ 30 s · revert ≤ 60 s | Signed bundles pulled on notification; Temporal ring controller watching per-path hit ratio; revert switches to a bundle already on disk | 19 |
| Control-plane loss | No delivery effect for ≥ 7 days | Last-known-good bundles on disk; 14-day certificates renewed at day 5; purges queue in JetStream and drain on recovery | 29 |
| Cold start | ≥ 90% of steady byte hit ratio within 4 h | Persistent NVMe cache survives restarts; cold mode caps shield fetch concurrency at 25% until 80% byte hit ratio | 22 |
| Recovery objectives | Content: none · config RPO 5 min, RTO 30 min · invalidation RPO 0 | Content is derived; configuration in Git plus Patroni with a streaming standby; invalidations acknowledged only after quorum on two of three sites | 11 |
| Correctness | Zero responses under a key that omits a varying dimension | Declared keys, refusal of private responses, Vary mismatch blocks storage, identity probe before release, key defect handled as a security incident | 13 |
| Cost | ≤ $4.00 per delivered TB · origin bytes ≤ 1.5% | Cost model per property and PoP; offload breaches named by path pattern; hardware beyond six PoPs gated on measured volume, since the target only holds near 45 PB a month | 25 |
The proof does not try out every feature. It tests the properties everything else depends on: a key that cannot leak, a purge whose outcome is known, a PoP that keeps serving when everything else is gone, and a monthly traffic volume that justifies running the edge at all.
| Risk | If it lands | Response |
|---|---|---|
| The traffic figures in the requirement are inconsistent | At 6 PB a month the estate costs about $30 per TB, not $4, and a commercial CDN is cheaper | Measure real volume in the proof phase; order hardware beyond six PoPs only after that; treat buying the edge as a valid outcome (ADR-28, ADR-29) |
| Asia and South America shield hits exceed 60 ms | Slower misses for those edges; p95 TTFB unaffected while their miss share stays low | Reported separately; a regional shield pool at SIN is prepared and triggered by measured miss share (ADR-10) |
| Five product behaviours are unconfirmed | Peering ring, lookup status override, QUIC-LB IDs, 14-day leaf replay or ACME volume may not work as assumed | Each is a named proof-phase test with a fallback: full replication per node, native purge with longer budget, ECMP without QUIC stickiness, full flush on return, commercial CA contract |
| Identity probe coverage depends on owners' test URLs | A property with poor test URLs gets weaker pre-release protection | Minimum test URL count per rule enforced by CUE; Vary-mismatch and Set-Cookie refusal alerts in production as the second line (ADR-04) |
| Running BGP at 18 sites needs network engineering on call | A misconfigured announcement can withdraw or hijack traffic at internet scale | Steering intent compiled and ringed like property config; pop-guard's never-the-last-PoP rule; RPKI ROAs for every prefix; network on-call staffed before go-live (ADR-18, ADR-19) |
| Several components have single-company governance | A licence change could force a replacement under time pressure | Fallback named per component in the glossary; seams kept to standard protocols so a swap is local (longevity section) |
Twenty-nine decisions make up this architecture. Everything else on the twenty-nine views is convention, and convention needs no defence. Each record starts with the question that forced a decision, says what was chosen and how it is built on hardware the organisation owns, lists the options that lost and why, and states what the choice costs. It then gives the conditions under which a different organisation should choose differently, and explains why the choice should still be right after the products, the hardware and the team have all changed. Read the one-pager first. Read a record when you want to argue with it.
Status of this document. This is a design, not a report on a running system. Latency, throughput, hit-ratio and cost figures are targets and stated assumptions taken from the requirement or from planning prices, and each is replaced by a measured value in the proof phase. Five product behaviours are relied on and must be confirmed before production depends on them: Traffic Server next-hop strategies in peering-ring mode for intra-PoP ownership; a Traffic Server plugin overriding the cache lookup status after the lookup completes, which the tag table needs; Envoy's QUIC-LB connection ID generator working with Katran's QUIC server-ID routing; NATS JetStream mirrors on leaf nodes replaying correctly after a 14-day disconnection; and the public ACME CA's issuance limits accommodating per-PoP certificates renewed every five days.
What a cache hit is allowed to mean, who decides it, and how the platform stops a wrong decision from reaching users.
ADR-01The cache key is declared per path pattern, and nothing is cacheable until declared ADR-02One Rust library computes the key in the cache, the validator and the explain API ADR-03Private responses are refused whatever the rule says, and an unexpected Vary is a configuration error ADR-04Validation proves identity is in the key with invariants and a two-user probeThe software on a PoP node, how a PoP behaves as one cache, how tenants share it, and what gets served when things go wrong.
ADR-05Apache Traffic Server is the cache engine ADR-06Envoy terminates TLS and HTTP/3 in a separate process from the cache ADR-07Inside a PoP, every node keeps its own hot set and the long tail has one owner on a peering ring ADR-08Memory and NVMe tiers, with per-property cache volumes that set a floor and a ceiling ADR-09Freshness is declared per path as strict, standard or resilient, and overload sheds in a fixed orderWhere misses go, how an origin is protected from the edge, and how an origin tells the platform apart from everyone else.
ADR-10Shield pools sit next to the origins, in continental pairs, with each key converging on one shield node ADR-11Origin protection is enforced at the shield, slow is distinguished from down, and the direct path is capped ADR-12Origins authenticate the platform with mTLS from workload identitiesHow content changes everywhere within seconds, how the platform knows it did, and when not to purge at all.
ADR-13Invalidation compares timestamps at lookup instead of deleting objects ADR-14NATS JetStream is the invalidation log, mirrored into every PoP, with acknowledgement per PoP ADR-15A returning PoP reconciles before serving, and this ships in the MVP ADR-16Versioned URLs first, purge second, short TTLs last, with the strategy declared per pathHow users reach a PoP, how traffic is moved, when a PoP removes itself, and how much spare capacity is carried.
ADR-17Anycast from every PoP, with Katran on dedicated hosts for QUIC-aware L4 balancing ADR-18Four anycast prefix classes for fine steering, and DNS as a manual per-property override from one intent ADR-19Automatic withdrawal needs sustained evidence, drains first, and never removes the last PoP ADR-20Capacity is planned to n−1 per region from measured per-node ceilings, and cold PoPs refill under a capWhere configuration is authoritative, how it reaches 18 sites safely, and where the control plane runs.
ADR-21Git is the configuration authority, and PoPs apply only signed bundles and keep the last known good ADR-22Rollout is a Temporal workflow through canary, region and global rings, halting on regressions without a person ADR-23PoPs run a signed image on bare metal; the control plane runs on Kubernetes in two core data centres and a witnessPrivate keys in buildings the organisation does not own, separated privileges, and a record nobody can quietly edit.
ADR-24Each PoP has its own short-lived certificates, with keys sealed to its TPM; keyless termination only later and only for a few properties ADR-25Three separated privileges, encrypted caches that can be destroyed by key, and an audit trail its writer cannot deleteWhat is measured, from where, what it costs, and whether running the edge is the right call at all.
ADR-26Access records are droppable: Vector at the node, Kafka in the core, ClickHouse for analysis ADR-27Availability is measured from outside, and silence at a PoP is an alert ADR-28Offload and the cost of a miss are financial metrics, and the traffic assumptions are checked before scaling out ADR-29One self-operated delivery path for now, with configuration and purge semantics kept portableEvery capability on the views, the package that provides it, a credible alternative, and the record that justifies the choice. Everything runs on hardware the organisation owns, with no managed service and no external dependency on the request path.
| Capability | Choice | Origin | Credible alternative | Why this one | Record |
|---|---|---|---|---|---|
| Cache key and refusal rules | keyspec (Rust, C ABI) with a request corpus | This design | Traffic Server cachekey plugin; Varnish VCL | One implementation shared by cache, validator and explain tool | ADR-02 |
| Configuration schema and validation | CUE plus Go invariant checks and a two-user identity probe | Open source | JSON Schema; OPA with Rego | Types, defaults and constraints in one language; the probe tests actual origin behaviour | ADR-04 |
| Cache engine, edge and shield | Apache Traffic Server 10 | Open source | Varnish Cache; NGINX | Persistent NVMe cache, parent strategies, read-while-writer, lookup-level plugin API | ADR-05 |
| TLS, HTTP/3 and edge policy | Envoy | Open source | HAProxy; NGINX | SDS certificate delivery, QUIC-LB connection IDs, local limits, precise draining | ADR-06 |
| Intra-PoP ownership | Traffic Server next-hop strategies, peering ring | Open source | Full replication per node | Near N-times effective cache and PoP-wide collapsing | ADR-07 |
| Tenant isolation | Traffic Server cache volumes plus Envoy per-property limits | Open source | Shared LRU | One property cannot evict another | ADR-08 |
| Stale serving | Traffic Server stale_response plugin, declared classes | Open source | Origin headers only | Owner-declared, platform-capped behaviour during failures | ADR-09 |
| Shield tier | Traffic Server shield pools at IAD, DFW, FRA, LHR | Open source | Regional shields; hashed mid-tier | Highest offload for origins in two data centres | ADR-10 |
| Origin authentication | mTLS with SPIFFE SVIDs from SPIRE | Open source | HTTP message signatures; IP allow-lists | Proven caller identity, automatic rotation | ADR-12 |
| Invalidation at the node | tagguard plugin with LMDB tag tables | This design | Tag index with deletion; regex revalidation | Purge cost independent of object count | ADR-13 |
| Invalidation log | NATS JetStream, R3 core with leaf-node mirrors | Open source | Apache Kafka; HTTP fan-out | Durable, ordered, replayable and light enough for every PoP | ADR-14 |
| L4 load balancing | Katran (XDP, Maglev) | Open source | IPVS with Maglev; switch ECMP | Consistent hashing with QUIC connection-ID routing | ADR-17 |
| Anycast announcement | BIRD 2 on L4 hosts; SONiC with FRRouting on border switches | Open source | GoBGP; ExaBGP; vendor routers | Proven BGP daemons controllable by pop-guard | ADR-17 |
| Per-property DNS steering | PowerDNS Authoritative with dnsdist | Open source | Knot DNS; NSD | Scriptable answers generated from steering intent | ADR-18 |
| Withdrawal control | pop-guard (Go) | This design | BIRD health scripts | Sustained evidence, drain and the never-last-PoP rule in one place | ADR-19 |
| Configuration authority | Forgejo with signed commits | Open source | Gitea; GitLab CE | Reviewed changes and history as the audit record, community governance | ADR-21 |
| Bundle signing and storage | cosign with key in OpenBao; Ceph RGW | Open source | GPG signatures; MinIO | PoPs verify origin of every bundle | ADR-21 |
| Ring rollout | Temporal workflows | Open source | Plain workers on PostgreSQL; CI stages | Durable timers and state across restarts | ADR-22 |
| Control-plane runtime | RKE2 Kubernetes with Argo CD; PostgreSQL with Patroni | Open source | Nomad; plain VMs | Standard operations in the core only | ADR-23 |
| Node provisioning and image | Tinkerbell; mkosi images; NetBox inventory | Open source | MAAS; PXE with Ansible | Remote, image-based, drift-free PoP nodes | ADR-23 |
| Keys, PKI and certificates | OpenBao; public ACME CA via DNS-01 | Open source | HashiCorp Vault; HSMs | Per-PoP keys, 14-day certificates, community governance after Vault's licence change | ADR-24 |
| Node identity | SPIRE with TPM attestation | Open source | Static client certificates | A tampered or reimaged node cannot fetch keys or bundles | ADR-24 |
| Operator identity and roles | Keycloak with WebAuthn | Open source | Authentik; Dex | Three separated privileges with strong authentication | ADR-25 |
| Encryption at rest and audit | LUKS2 with TPM-sealed keys; Ceph RGW Object Lock | Open source | Self-encrypting drives; immudb | Destroy a cache by destroying a key; audit its writer cannot delete | ADR-25 |
| Access record pipeline | Vector, Apache Kafka, ClickHouse, Parquet on Ceph | Open source | Fluent Bit; OpenSearch | Droppable at the node, replayable in the core, fast analytics | ADR-26 |
| Metrics, probes and alerting | Prometheus, Thanos, blackbox_exporter, Alertmanager, Grafana | Open source | VictoriaMetrics; commercial synthetic monitoring | Local collection that survives WAN loss, global view, outside-in SLI | ADR-27 |
| Cost model | ClickHouse cost tables with NetBox asset data | This design | Spreadsheet model | Cost per TB and per miss computed from the same records as hit ratio | ADR-28 |
Who decides what makes two requests the same request?
How does an owner check a key and trust that production computes the same one?
What happens when the origin's response contradicts the owner's declaration?
How does the platform reject a change that would make a user-specific path cacheable without the user in the key?
Which open-source cache engine can meet the key, storage and shielding requirements on hardware we run?
Where do TLS termination, token checks and per-property limits run?
Does every node in a PoP hold everything, or does the PoP shard its cache?
How does one property's traffic avoid evicting another property's cache?
When the origin fails or the PoP is overloaded, what does a user get?
What shape should the shield tier be?
How is an origin protected from the edge, including when the shield itself fails?
How can an origin refuse traffic that did not come through the platform?
How can a purge of two million objects reach 18 PoPs in seconds without affecting serving?
What carries invalidations so that none acknowledged is lost and every PoP's outcome is known?
What stops a PoP that missed purges while away from serving stale content when it returns?
Should content change be handled by purge, by versioned URLs or by short TTLs with revalidation?
How do users reach a PoP, and how are connections spread across its nodes?
Anycast alone, DNS steering, or both?
When should a PoP remove itself from the internet, and what stops a health check from taking everything down?
How much capacity does the edge carry, and how is a cold PoP kept from hurting the shield?
Where is configuration authoritative, and how does a PoP keep serving without the control plane?
How does a validated change reach 18 PoPs without a bad one reaching all of them?
Where does each part of the platform run, and what does it depend on?
Where does a TLS private key live in a facility the organisation does not own?
Who can change what, how is a PoP's cache destroyed, and how is every change recorded beyond tampering?
How are one structured record per request delivered centrally without ever slowing delivery?
How does the platform know it is failing users it cannot see?
How is the platform's value measured, and is the stated cost target achievable?
Is this the only delivery path, or one of several?
Every open-source package named on the views, what it is, the job it does here, and what was considered instead.
| Package | What it is | What it does here | Considered instead |
|---|---|---|---|
| Apache Traffic Server | HTTP caching proxy, Apache Software Foundation | Edge and shield cache with persistent NVMe storage and parent routing | Varnish Cache, NGINX |
| Envoy | L7 proxy, CNCF graduated | TLS, HTTP/2 and HTTP/3 termination, signed URL checks, limits, draining | HAProxy, NGINX |
| Katran | XDP-based L4 load balancer, open-sourced by Meta | Consistent-hash connection balancing with QUIC connection-ID routing | IPVS with Maglev |
| BIRD | BGP routing daemon | Announces anycast prefixes from L4 hosts while the PoP is healthy | GoBGP, ExaBGP |
| SONiC and FRRouting | Open network operating system (Linux Foundation) and routing suite | Border switches, transit and exchange BGP sessions | Vendor router OS |
| PowerDNS Authoritative and dnsdist | Authoritative DNS server and DNS load balancer | Property hostnames, per-property steering overrides, ACME DNS-01 | Knot DNS, NSD |
| NATS JetStream | Messaging system with persistent streams, CNCF | Invalidation log with quorum replication and leaf-node mirrors at PoPs | Apache Kafka |
| LMDB | Embedded memory-mapped key-value store | Per-node tag tables read by the cache plugin | RocksDB |
| Rust | Memory-safe systems language | keyspec, the shared cache key library | C++ |
| CUE | Configuration language with types and constraints | Property configuration schema and defaults | JSON Schema, OPA with Rego |
| Forgejo | Self-hosted Git forge, community governed | Configuration authority, reviews, CI runners | Gitea, GitLab CE |
| cosign | Artefact signing tool, Sigstore project | Signs configuration bundles and node images | GPG |
| Temporal | Durable workflow engine | Ring rollout controller with halts and reverts | Plain workers on PostgreSQL |
| PostgreSQL and Patroni | Relational database and high-availability manager | Control DB: rollouts, acknowledgements, Temporal persistence | CockroachDB |
| Kubernetes (RKE2) and Argo CD | Container orchestration and GitOps delivery | Control-plane services in the core data centres | Nomad |
| Tinkerbell | Bare-metal provisioning, CNCF | Remote provisioning of PoP nodes over out-of-band networks | MAAS |
| mkosi | Image builder from the systemd project | Signed, read-only A/B node images | Packer |
| NetBox | Infrastructure inventory and IPAM | PoPs, nodes, prefixes, rings and hardware cost records | Nautobot |
| OpenBao | Secrets and key management, Linux Foundation fork of Vault | Per-PoP TLS keys, PKI for SPIRE, bundle signing key, test identities | HashiCorp Vault |
| SPIRE | SPIFFE workload identity implementation, CNCF | Node and shield identities after TPM attestation | Static certificates |
| Keycloak | Identity and access management, CNCF | Operator sign-in and the three separated roles | Authentik, Dex |
| LUKS2 (cryptsetup) | Linux disk encryption | Encrypted NVMe caches with TPM-sealed keys | Self-encrypting drives |
| Ceph RGW | S3-compatible object gateway of Ceph | Bundle store, cold logs, Object Lock audit trail | MinIO |
| Vector | Observability data pipeline | Ships access records from nodes with a bounded disk buffer | Fluent Bit |
| Apache Kafka | Distributed event log | Three-day central buffer for access records | Redpanda |
| ClickHouse | Column-oriented analytical database | Hot access records, hit ratio, offload and cost models | Apache Druid |
| Prometheus and Thanos | Metrics collection and long-term global query layer, CNCF | PoP-local metrics, 13-month retention, ring gates | VictoriaMetrics |
| blackbox_exporter | Prometheus probe exporter | External probes from 12 outside networks | Commercial synthetic monitoring |
| Alertmanager and Grafana | Alert routing and dashboards | Paging, SLO burn and owner dashboards | Kibana |
svg/<view>.svg or drawio/<view>.drawio in draw.io Desktop or at app.diagrams.net to edit. The SVG carries the diagram inside it, so it is both the picture and the source. This folder is self-contained — copy it whole and every link still resolves.