Kntrl
kntrl is an eBPF based runtime agent that monitors and prevents anomalous behaviour defined by you on your pipeline. kntrl achieves this by monitoring kernel calls, and denying access as soon as your defined behaviour is detected. For more: https://kntrl.dev
Install / Use
/learn @kondukto-io/KntrlREADME
<!-- markdownlint-disable-line first-line-heading -->
kntrl is an eBPF-based runtime security agent that monitors and controls network, process, DNS, TLS, and file activity on CI/CD runners and build pipelines. It hooks into kernel-level syscalls to enforce policies in real time — blocking supply-chain attacks, unauthorized network access, and anomalous process behaviour before they cause damage.
Refer to this presentation for a deeper look at the architecture.
Features
- Network monitoring & enforcement — Intercepts IPv4/IPv6 TCP and UDP connections via eBPF kprobes. Allows or blocks based on destination IP, domain, CIDR range, and process identity.
- DNS monitoring — Captures DNS queries and responses at the kernel level. Tracks which domains each process resolves and restricts DNS server usage.
- TLS SNI inspection — Extracts Server Name Indication from TLS ClientHello packets via eBPF TC hooks for accurate domain-based blocking even before the connection completes.
- Process ancestry tracking — Monitors fork/exec events to build an in-memory process tree. Blocks connections when specific process chains are detected (e.g., block
curlspawned bynpm). - File access monitoring — Tracks file open events on sensitive paths (e.g.,
/etc/shadow,/root/.ssh/). - Per-process network profiles — Assign different allowed hosts per process (e.g.,
npmcan only reachregistry.npmjs.org). - OPA policy engine — All policy decisions use Open Policy Agent with embedded Rego rules. Extend or override with custom
.regofiles. - Two operating modes —
monitor(log only) andtrace(enforce and block). - Webhook alerting — Send block/pass events to external endpoints in real time.
- Established connection preloading — Reads
/proc/net/tcp{,6}at startup so existing SSH and database connections survive agent start. - SIGHUP live reload — Reload YAML rules and flush policy caches without restarting.
- Daemon mode — Run in the background with PID file management.
Security hardening
- Process identity validation — Overrides the BPF
commfield (spoofable viaprctl) with the real executable name from/proc/[pid]/exe. - Dot-boundary host matching —
"github.com"matchessub.github.combut NOTevil-github.com. - Raw socket monitoring — Detects creation of
AF_PACKET,IPPROTO_RAW, andIPPROTO_ICMPsockets. - No DNS auto-whitelisting — DNS-resolved IPs require explicit policy approval before they enter the BPF allowlist.
- LRU BPF maps — Auto-evicting hash maps prevent map overflow under high load.
Performance
- Policy result caching — Per-IP+task+ancestry TTL cache avoids redundant OPA evaluations (30s TTL).
- Async DNS resolution — Non-blocking worker goroutine for forward DNS cache population.
- Buffered report I/O — 64KB buffered writer reduces syscall overhead for report file writes.
Installation
Linux
kntrl is available as a downloadable binary from the releases page. Download the pre-compiled binary and copy it to the desired location.
Container Images
docker pull kondukto/kntrl:latest
To pull a specific version:
docker pull kondukto/kntrl:0.1.4
Building from source
make generate # compile eBPF programs (requires clang, llvm, libelf-dev)
make build # build the Go binary to build/kntrl
Quick start
Start the agent in monitor mode during your CI/CD job:
- name: start kntrl agent
run: sudo ./kntrl start --mode=monitor --allowed-hosts=download.kondukto.io,${{ env.GITHUB_ACTIONS_URL }} --allowed-ips=10.0.2.3 --daemonize
Stop and print the report:
- name: stop kntrl agent
run: sudo ./kntrl stop
Or with Docker:
- name: kntrl agent
run: sudo docker run --privileged \
--pid=host \
--network=host \
--cgroupns=host \
--volume=/sys/kernel/debug:/sys/kernel/debug:ro \
--volume /tmp:/tmp \
--rm docker.io/kondukto/kntrl:0.1.4 \
start --mode=trace --allowed-hosts=kondukto.io,download.kondukto.io
CLI reference
kntrl [command]
Commands:
start Start kntrl agent
stop Stop kntrl daemon and print reports
status Print kntrl daemon status
completion Generate shell autocompletion script
help Help about any command
Global flags:
-v, --verbose Enable verbose logging
--version Show version
kntrl start flags
| Flag | Default | Description |
| ------------------------ | ---------------- | ------------------------------------------------------------------- |
| --mode | monitor | Operating mode: monitor (log only) or trace (enforce) |
| --allowed-hosts | | Comma-separated allowed hostnames (e.g., example.com,.github.com) |
| --allowed-ips | | Comma-separated allowed IP addresses |
| --allow-local-ranges | true | Allow local IP ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) |
| --allow-github-meta | false | Allow GitHub Actions IP ranges from api.github.com/meta |
| --allow-metadata | false | Allow cloud metadata endpoints (169.254.169.254, 168.63.129.16) |
| --monitor-processes | true | Enable process fork/exec monitoring |
| --rules-file | | Path to a YAML policy file |
| --rules-dir | | Path to a directory containing .yaml and/or .rego rule files |
| -o, --output-file-name | /tmp/kntrl.out | Report output file |
| --pretty | false | Pretty-print process events as a tree |
| --daemonize | false | Run in the background |
YAML policy configuration
Use --rules-file to load a comprehensive YAML policy. This gives fine-grained control over network access, process monitoring, DNS servers, file access, process ancestry chains, per-process profiles, and webhook alerting.
version: "1"
mode: trace
rules:
network:
allowed_hosts:
- "github.com"
- ".npmjs.org"
- ".amazonaws.com"
allowed_ips:
- "10.0.0.0/8"
- "172.16.0.0/12"
allow_local_ranges: true
allow_github_meta: true
allow_metadata: false
allowed_processes:
- "curl"
- "git"
- "wget"
- "docker"
profiles:
- process: "npm"
allowed_hosts:
- "registry.npmjs.org"
- process: "pip"
allowed_hosts:
- "pypi.org"
- "files.pythonhosted.org"
process:
enabled: true
blocked_chains:
- process: "curl"
ancestors: ["npm"]
- process: "wget"
ancestors: ["pip"]
dns:
allowed_servers:
- "8.8.8.8"
- "8.8.4.4"
file:
enabled: false
monitored_paths:
- "/etc/shadow"
- "/root/.ssh/"
- "/proc/self/environ"
webhooks:
- url: "https://your-siem.example.com/events"
headers:
Authorization: "Bearer <token>"
filter: "block"
See examples/policy-v2.yaml for a full example.
Live reload
Send SIGHUP to the running agent to reload the YAML rules file and flush policy caches without restarting:
kill -HUP $(cat /tmp/kntrl.pid)
Process ancestry chain blocking
kntrl tracks process fork/exec events to build an in-memory process tree. When a network connection is made, kntrl walks the tree to determine the full ancestry chain of the connecting process. This ancestry is then evaluated against blocked_chains rules.
Each blocked_chains entry specifies a process name and a list of ancestors. If the process making the network connection matches process and every name in ancestors appears somewhere in its ancestry chain, the connection is denied.
This lets you write rules like "block curl if it was spawned (directly or indirectly) by npm":
rules:
process:
enabled: true
blocked_chains:
- process: "curl"
ancestors: ["npm"]
With this rule:
npm installspawningsh -> curlto exfiltrate data is blocked- A user running
curl github.comdirectly from a shell is allowed
You can require multiple ancestors to be present:
blocked_chains:
- process: "sh"
ancestors: ["npm", "node"]
The ancestry chain is also passed into OPA policy evaluation as input.ancestors, so you can write custom Rego rules against it.
Per-process network profiles
Restrict which hosts a specific process can reach. For example, allow npm to reach only its registry:
rules:
network:
profiles:
- process: "npm"
allowed_hosts:
- "registry.npmjs.org"
- process: "pip"
allowed_hosts:
- "pypi.org"
- "files.pythonhosted.org"
If the connecting process matches a profile, only the hosts listed in that profile are allowed — the global allowed list does not apply.
DNS monitoring
kntrl captures DNS queries and responses at the kernel level via eBPF kprobes. This provides:
- Correlation between resolved domains and destination IPs for accurate policy evaluation
- DNS server restriction — only allow queries to approved DNS servers
- Visibility into which processes resolve which domains
rules:
dns:
allowed_servers:
- "8.8.8.8"
- "8.8.4.4"
DNS events are displayed in the repor
Related Skills
tmux
341.8kRemote-control tmux sessions for interactive CLIs by sending keystrokes and scraping pane output.
blogwatcher
341.8kMonitor blogs and RSS/Atom feeds for updates using the blogwatcher CLI.
product
Cloud-agnostic Kubernetes infrastructure with Terraform & Helm for homelabs, edge, and production clusters.
Unla
2.1k🧩 MCP Gateway - A lightweight gateway service that instantly transforms existing MCP Servers and APIs into MCP servers with zero code changes. Features Docker deployment and management UI, requiring no infrastructure modifications.
