RC2
Open Standard · RC2

Katar Native Agent

A production-grade, open-protocol security telemetry agent. Captures kernel events via eBPF, evaluates behavioral rules in sandboxed WebAssembly, streams signed telemetry over mTLS gRPC, and enforces network blocks at wire-speed via XDP.

GraphQL API

Query live agent state, stream telemetry, dispatch signed enforcement actions.

🔐

Agent Enrollment

Cert pinning, TPM identity, and Control Plane key provisioning.

🛠

Operations

Startup sequence, env vars, build commands, and troubleshooting.

📡

NOS Protocol

gRPC contract, signing spec, and multi-language codegen guide.

Architecture

KNA follows the industry-standard pattern of kernel-adjacent work in Rust, control/integration layer in Go — the same split used by Falco, Cilium, and Tetragon.

RUST — katar-node
eBPF Sensor
WASM Engine
TPM Identity
XDP Enforcement
↕ mTLS gRPC :50051
GO — katar-control-plane
AgentConnector
AgentRegistry
GraphQL API
Dashboard UI
PROTO — kos/proto (shared contract)
StreamService
ActionService
KOSEvent Schema
Signing Contract

GraphQL API

APIhttp://localhost:8080/query
PLAYGROUNDhttp://localhost:8080/playground

Authentication

All Mutation operations require a Bearer token:

Authorization: Bearer <api_key>

Configured in katar-control-plane/config.yaml under server.api_key. Query operations are unauthenticated.

Types

Agent
FieldTypeDescription
idID!TPM-derived UUID
hostnameString!From config.yaml
addrString!gRPC address
lastSeenString!RFC 3339 timestamp
versionString!Agent version
statusString!ONLINE / OFFLINE / CONNECTING
telemetryCountInt!Events received since CP start
TelemetryEvent
FieldTypeDescription
agentIdString!Source agent UUID
eventIdString!Unique event ID
timestampInt!Unix seconds
eventTypeString!process / network / file / gap
ActionResult
FieldTypeDescription
successBoolean!Agent accepted the action
messageString!Result or error detail

Queries

QUERYagents

List all fleet agents, regardless of current connection status.

query {
  agents {
    id
    hostname
    addr
    status
    lastSeen
    version
    telemetryCount
  }
}
Response
{
  "data": {
    "agents": [{
      "id": "6ba7b811-9dad-11d1-80b4-00c04fd430c8",
      "hostname": "app-server-01",
      "addr": "localhost:50051",
      "status": "ONLINE",
      "lastSeen": "2026-04-27T22:15:03Z",
      "version": "v2.0.0",
      "telemetryCount": 4821
    }]
  }
}
QUERYrecentEvents

Returns up to limit events from an agent's ring buffer. Events persist even while the agent is OFFLINE.

query RecentEvents($agentId: String!, $limit: Int!) {
  recentEvents(agentId: $agentId, limit: $limit) {
    agentId
    eventId
    timestamp
    eventType
  }
}
Variables
{ "agentId": "6ba7b811-...", "limit": 20 }
Event types:
eventTypeSource
processeBPF tracepoint — exec/exit
networkeBPF XDP/TC — connection event
fileeBPF LSM — open/write/unlink
gapOffline queue drain — events dropped
QUERYdestinations
query {
  destinations {
    id
    name
    type
    url
    enabled
  }
}

Mutations

All mutations require Authorization: Bearer <api_key>
MUTATIONexecuteAction

Dispatches a cryptographically signed enforcement action to the target agent. The Control Plane signs with its Ed25519 private key; the agent verifies before applying.

mutation {
  executeAction(
    agentId: "6ba7b811-9dad-11d1-80b4-00c04fd430c8"
    action: "ENFORCE_XDP_BLOCK"
    targetId: "1.2.3.4"
  ) {
    success
    message
  }
}
Action Types
actiontargetId formatExample
ENFORCE_XDP_BLOCKIPv4 address"1.2.3.4"
UNBLOCK_XDP_IPIPv4 address"1.2.3.4"
KILL_PROCESSPID (decimal string)"3821"
QUARANTINE_FILEAbsolute path"/tmp/malware.sh"
PATCH_PACKAGEPackage name"openssl"
curl
curl -X POST http://localhost:8080/query \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer change-me-before-production" \
  -d '{"query":"mutation { executeAction(agentId:\"<UUID>\", action:\"ENFORCE_XDP_BLOCK\", targetId:\"1.2.3.4\") { success message } }"}' | jq
MUTATIONcreateDestination
mutation {
  createDestination(input: {
    name: "Splunk HEC"
    type: "splunk"
    url: "https://splunk.example.com:8088"
  }) { id name enabled }
}
MUTATIONtoggleDestination
mutation {
  toggleDestination(id: "dest-0", enabled: true) {
    id name enabled
  }
}

Error Reference

ErrorCauseFix
unauthorized: Bearer token requiredMissing/wrong Authorization headerSet Authorization: Bearer <api_key>
agent <id> not foundID not in registryCheck agents query — ID must match exactly
agent <id> is OFFLINEAgent disconnectedWait for reconnect or check agent host
unknown action: <name>Invalid action stringUse exact strings from action types table
Action timestamp is invalid or expiredClock skew > 5sSync NTP on both Control Plane and agent hosts
Invalid cryptographic signature. Access Denied.Wrong KATAR_ACTION_PUBKEY on agentSet env var to hex key printed by Control Plane on boot

Full Schema (SDL)

type Agent {
  id:             ID!
  hostname:       String!
  addr:           String!
  lastSeen:       String!
  version:        String!
  status:         String!
  telemetryCount: Int!
}

type TelemetryEvent {
  agentId:   String!
  eventId:   String!
  timestamp: Int!
  eventType: String!
}

type DestinationConfig {
  id:      ID!
  name:    String!
  type:    String!
  url:     String!
  enabled: Boolean!
}

type ActionResult {
  success: Boolean!
  message: String!
}

input NewDestination {
  name:    String!
  type:    String!
  url:     String!
  headers: String
}

type Query {
  agents:       [Agent!]!
  destinations: [DestinationConfig!]!
  recentEvents(agentId: String!, limit: Int!): [TelemetryEvent!]!
}

type Mutation {
  createDestination(input: NewDestination!): DestinationConfig!
  toggleDestination(id: ID!, enabled: Boolean!): DestinationConfig!
  executeAction(agentId: ID!, action: String!, targetId: String!): ActionResult!
}

Agent Enrollment

Connect a katar-node agent to the katar-control-plane.

1

Start the Control Plane

cd katar-control-plane
go run ./cmd/katar-manager/

On first boot, a new Ed25519 keypair is generated and the public key is printed to stdout. Save this hex string.

2

Start the Agent

KATAR_ACTION_PUBKEY=<64-char-hex> cargo run --release

The agent logs its UUID and TLS cert fingerprint:

INFO Agent Identity established. UUID: 6ba7b811-...
INFO Agent TLS cert fingerprint (SHA-256): a3f9c2...
INFO Starting secure gRPC API Server on 0.0.0.0:50051
3

Copy the Agent Certificate

Same host (dev): reference the cert directly in config.yaml.

Remote host:

scp user@agent-host:/path/to/katar-node/certs/agent.crt \
    /etc/KATAR/agents/agent-001.crt

# Verify fingerprint matches Step 2
openssl x509 -in agent-001.crt -fingerprint -sha256 -noout
4

Add Agent to config.yaml

agents:
  - id: "6ba7b811-9dad-11d1-80b4-00c04fd430c8"  # UUID from agent log
    hostname: "app-server-01"
    addr: "app-server-01:50051"
    tls_cert: "/etc/KATAR/agents/agent-001.crt"
    version: "v2.0.0"
5

Verify in Dashboard

Open http://localhost:8080 — the agent should appear with Status: ONLINE and telemetryCount incrementing.

Operations Runbook

Startup Sequence

Always start the Control Plane before agents so its public key is available.
1. Start katar-control-plane  →  save printed Ed25519 public key
2. Start katar-node with KATAR_ACTION_PUBKEY=<hex>
3. Copy certs/agent.crt to Control Plane host (if remote)
4. Add agent to config.yaml, restart Control Plane

Environment Variables

VariableServiceDescription
KATAR_ACTION_PUBKEYkatar-node64-char hex Ed25519 public key from Control Plane. Required for executeAction to work.
PORTkatar-control-planeHTTP port (default: 8080)

Build Commands

# Agent (Rust)
cargo build --release -p katar-node
cargo test -p katar-node

# Control Plane (Go)
go build -o katar-manager ./cmd/katar-manager/
go run github.com/99designs/gqlgen generate  # after schema changes
make proto                                    # after proto changes

# CI drift check
./scripts/check_proto_drift.sh

Troubleshooting

SymptomCauseFix
Agent shows OFFLINE immediatelyTLS cert path wrong or agent not reachableCheck tls_cert in config.yaml; check agent is running on correct port
executeAction returns Access DeniedWrong KATAR_ACTION_PUBKEYUse hex key printed by Control Plane on first boot
Action timestamp expiredClock skew > 5sRun ntpdate pool.ntp.org on both hosts
go build fails — undefined typesSchema updated without regeneratingRun go run github.com/99designs/gqlgen generate
TLS handshake fails — cert expiredOld cert from before RC2 fixDelete certs/agent.crt and agent.key, restart agent

NOS Protocol v2.0

The proto files in kos/proto/ are the single source of truth for all KOS v2 definitions. Neither katar-node nor katar-control-plane owns the contract.

Services

service StreamService {
  // Bidirectional stream — agents push telemetry, plugins push WASM rules
  rpc Subscribe (stream StreamRequest) returns (stream KOSEvent);
}

service ActionService {
  // Signed enforcement actions — see signing contract below
  rpc ExecuteAction (ActionRequest) returns (ActionResponse);
}

Action Signing Contract

Canonical Payload Format
"{action_enum_int32}:{target_id}:{unix_timestamp_seconds}"

Example (ENFORCE_XDP_BLOCK = 4):
"4:192.168.1.50:1714230000"
  • Signed with Ed25519 using the Control Plane's private key
  • Encoded as base64.StdEncoding
  • Replay window: ±5 seconds — ensure NTP sync
  • Go signer: internal/auth/identity.go → SignActionRequest()
  • Rust verifier: src/core/action_engine.rs → verify_action()

Codegen

LanguageCommand
Gocd katar-control-plane && make proto
RustAutomatic — cargo build triggers build.rs