SkillAgentSearch skills...

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/Kntrl
About this skill

Quality Score

0/100

Category

Operations

Supported Platforms

Universal

README

kntrl logo <!-- 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 curl spawned by npm).
  • 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., npm can only reach registry.npmjs.org).
  • OPA policy engine — All policy decisions use Open Policy Agent with embedded Rego rules. Extend or override with custom .rego files.
  • Two operating modesmonitor (log only) and trace (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 comm field (spoofable via prctl) with the real executable name from /proc/[pid]/exe.
  • Dot-boundary host matching"github.com" matches sub.github.com but NOT evil-github.com.
  • Raw socket monitoring — Detects creation of AF_PACKET, IPPROTO_RAW, and IPPROTO_ICMP sockets.
  • 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 install spawning sh -> curl to exfiltrate data is blocked
  • A user running curl github.com directly 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

View on GitHub
GitHub Stars125
CategoryOperations
Updated5d ago
Forks7

Languages

C

Security Score

95/100

Audited on Mar 25, 2026

No findings