Modern infrastructure requires strong, scalable, and transparent identity mechanisms — especially for non-human actors like services, workloads, jobs, or AI agents. At Riptides, we deliver exactly that by anchoring non-human identity at the kernel level. Using technologies like SPIFFE, kTLS, and in-kernel mTLS handshakes, our platform offers zero trust security: authenticated, encrypted communication for user-space applications, without requiring developers to modify their code.
But to make this work, our system needs deep integration with the Linux kernel. We deploy custom eBPF-based telemetry and kernel modules that issue identity, track posture, and enforce policy at runtime. That means supporting a growing matrix of kernel versions, distributions, and CPU architectures — and being able to build and deliver the right driver to the right workload, at the right time.
This post walks through how we built a cloud-native, incremental kernel module build system using Docker, GitHub Actions, and EKS — one that produces hundreds of kernel-specific drivers daily, with minimal friction and full automation.
Building and maintaining kernel drivers for half a dozen Linux distributions and two CPU architectures is a deceptively complex task. Dependency hell, constantly changing kernel Application Binary Interfaces (ABIs), and the need for rapid vulnerability fixes turn a “simple” make && make install into a true at-scale engineering challenge. This article walks through the architecture, and inner workings of our build pipeline which is a Docker-based, GitHub Actions powered system that compiles and ships drivers to an S3 bucket across Ubuntu, Amazon Linux 2, Amazon Linux 2023, Fedora, AlmaLinux, and Debian on both x86_64 and arm64.
Maintaining a modern kernel driver farm means satisfying three moving targets simultaneously: supported distributions, supported kernel releases within each distribution, and supported CPU architectures. Each axis amplifies matrix complexity exponentially.
A quick calculation of driver build matrix size:
| Axis | Current coverage |
|---|---|
| Distributions | Ubuntu, Amazon Linux 2, Amazon Linux 2023, Fedora, AlmaLinux, Debian |
| Kernel releases per distro (AVG) | 40 |
| Architectures | x86_64, aarch64 |
| Theoretical build variants | 540 (6 distros × 40 kernels × 2 arches) |
Even a modest 480 variant grid exceeds what can be built manually, so the automation is non-negotiable.
The Falco security project faced a nearly identical challenge compiling its kernel module and eBPF probes. Their answer combines three open-source components:
We decided against using Prow primarily due to its configuration complexity and steep learning curve. Additionally, Prow’s terminology, such as ProwJob, Deck, Tide, and Hook is tightly coupled to its internal architecture and not immediately intuitive. This makes onboarding and day-to-day maintenance more difficult compared to alternatives that prioritize simplicity.
We distilled the Falco pattern into a leaner stack that leverages tools our engineers already use daily.
| Layer | Our Implementation | Rationale |
|---|---|---|
| CI Orchestrator | GitHub Actions | Native to repos, rich marketplace, familiar YAML workflow syntax |
| Runner Fleet | Self-hosted runners on Amazon EKS via Actions Runner Controller | Autoscaling, spot-instance friendly, GitHub-supported |
| Containerized Builder | Distro-specific Dockerfiles | Reproducible toolchains, no host pollution |
| Matrix Definition | Custom Go tool parsing Falco’s kernel-crawler output | Reuses community data, but fine-tuned for our needs |
| Artifact Store | Amazon S3 | Cheap, durable, global distribution |
High Level Architecture:

At the heart of the pipeline is our matrix-gen CLI tool that consumes Falco’s kernel-crawler JSON dataset and emits a filtered JSON tailored to our needs.
matrix-gen generate\
--distro=ubuntu,amazonlinux2,amazonlinux2023,fedora,almalinux,debian \
--arch=x86_64,aarch64 \
--driver-version=0.1.1 \
--kernel-release='.*6\.[0-9]+\..*'
Sample Output Element:
[
{
"kversion": "6.1.12-17.42.amzn2023.x86_64",
"distribution": "amazonlinux2023",
"architecture": "x86_64",
"kernelurls": [
"https://amazonlinux-2023-repos.s3.us-west-2.amazonaws.com/2023.0.20231016.0/kernel/6.1.12-17.42.amzn2023.x86_64/kernel-6.1.12-17.42.amzn2023.x86_64.rpm"
],
"output": "0.1.0/amazonlinux2023/x86_64/6.1.12-17.42.amzn2023.x86_64",
"driverversion": "0.1.1"
},
...
]
Key fields:
Each nightly GitHub Actions workflow takes three steps:
This approach shrinks CI time drastically. If just two new Fedora kernels land overnight, the workflow launches only two jobs instead of rebuilding hundreds. When we release a driver patch, the diff naturally marks every entry as changed, ensuring all variants are rebuilt with fixes.
After the build matrix is generated, we rely on three key pillars to make our driver builds fast, simple, and reproducible.
1. Docker-Based Build Jobs:
We maintain a directory of slim, distro-specific Dockerfiles that have common characteristics:
2. Architecture-Aware Scheduling:
Each matrix element carries an ‘architecture’ field. GitHub Actions assigns a runs-on: [self-hosted, build, x86_64] or [self-hosted, build, aarch64] label dynamically, ensuring ARC schedules the pod on a node with the matching CPU.
3. Runner & Node Autoscaling:
Actions Runner Controller (ARC)’s RunnerDeployment objects declare how many idle runners should persist. HorizontalRunnerAutoscaler (HRA) adjusts replicas using Live Job Queue metrics. Meanwhile, the Kubernetes Cluster Autoscaler on EKS grows or shrinks EC2 nodes based on pending pods, giving us a two-tier elasticity model:
Sequence Diagram of Driver Build:

A Runner Scale Set is a managed group of self-hosted GitHub Actions runners that can automatically scale up or down based on job demand.
Key Advantages of RunnerScaleSet Over HorizontalRunnerAutoscaler:
RunnerScaleSets are more secure, efficient, and easier to manage compared to HorizontalRunnerAutoscaler.
By integrating open-source tools like kernel-crawler, leveraging containerized builds, and deploying a cloud-native CI/CD pipeline with elastic scaling, we turned a notoriously brittle part of kernel engineering into a reliable, automated system. The result is a scalable driver build infrastructure that keeps pace with upstream kernel releases, supports a diverse range of environments, and requires minimal human intervention. This investment is foundational. The telemetry and enforcement capabilities that set Riptides apart begin with kernel-level visibility. And that visibility depends on having the right module, built for the right kernel, shipped to the right place — every time. With this system in place and upcoming migration to GitHub Runner Scale Sets, we’re ready to scale even further, simplify operations, and continue delivering on our mission to secure workloads from the kernel up.
Key takeaways:
This setup meets today’s scale comfortably, and with upcoming RunnerScaleSets we expect even smoother scaling and simpler secrets management.