(日本語版 README: README.ja.md)
A2A-protocol-based multi-layer automated containment platform A Hub agent coordinates ZTNA (Go/XDP), Tetragon (eBPF runtime monitoring), and Arista cEOS (NETCONF) using natural-language-driven risk assessment, automating the full path from breach detection through containment, human approval, and rollback.
This repository was built for research and demo purposes (hackathon) and is not intended to be deployed to production as-is. See Disclaimer for details.
- Overview
- Key Features
- Architecture
- Components (Port Table)
- Risk Assessment and Containment Flow
- Test Environment (containerlab)
- Setup
- Environment Variables
- Running the Servers
- Running as systemd Services
- Observability Layer (Elastic Cloud)
- Related Repositories
- License
- Disclaimer
When Tetragon (eBPF) detects anomalous behavior on a Linux host (e.g. unauthorized binary execution, a burst of ticket issuance), the Containment Hub scores the situation and routes the response into one of three tiers:
| Risk | Automatic action | Human approval |
|---|---|---|
| Low | ZTNA (access blocking) only, executed automatically | Not required |
| Medium | ZTNA executed automatically | ACL push to cEOS requires approval |
| High | ZTNA executed automatically + account lock | ACL/config push to cEOS/Junos requires approval; a global lock is also proposed |
All decision-making and enforcement logic is implemented as agents on the A2A protocol; each agent runs as an independent HTTP server (JSON-RPC). Administrators can approve actions, roll back containment, and review audit logs through a NiceGUI-based web UI.
- A2A-standard multi-agent design: Tetragon monitoring, ZTNA enforcement,
and the Containment Hub coordinate over the official
A2A protocol (
message/send), each with a clearly separated responsibility. - Three-tier risk assessment: An LLM evaluates breach severity — Low is contained automatically, Medium/High escalate into a human-approval workflow.
- Human-in-the-Loop UI: The
Containment OSdashboard (app_containment.py) provides one-stop approval, audit-log review, and ZTNA magic-number issuance. - Go × Rust × Python hybrid: The XDP/eBPF kernel program itself is
written in Rust and maintained in a separate repository — see
maf-ebpf-sase/xdp-ebpf.
It's loaded and controlled from userspace by a Go program
(
ztna-tetragon/main.go, built oncilium/ebpf). The AI orchestration layer is Python (LangChain + Groq/Gemini). - Arista cEOS integration: ACLs are generated, pushed, and rolled back via NETCONF (see a2a-ceos-core), extending containment down to the network-device layer.
- EDR-tamper defense: A Tetragon
TracingPolicy(fd_installkprobe) watches for access to the EDR agent's config/binary and issues an immediateSIGKILLin kernel space — before a ransomware precursor can read or disable it (seeztna-tetragon/protect-edr-agent.template.yaml). - Elastic Cloud observability layer: Metrics and raw eBPF events from four sources are aggregated for natural-language investigation via Elastic Agent Builder (see Observability Layer (Elastic Cloud)).
flowchart LR
subgraph Monitor["Monitoring"]
TET["tetragon_a2a_server.py\n:8102\n(eBPF breach detection)"]
end
subgraph Hub["Decision"]
HUB["containment_hub_a2a_server.py\n:8100\nRisk assessment / orchestration"]
end
subgraph Enforce["Containment enforcement"]
ZTNA["ztna_a2a_server.py\n:8101"]
GOZTNA["Go ZTNA/SASE API\n:8080 (inside ceos1 namespace)"]
CEOS["a2a-ceos-core (separate repo)\nPushes ACLs to cEOS\nvia NETCONF/eAPI"]
end
UI["app_containment.py\n:8180\nNiceGUI admin dashboard"]
TET -- "breach notification" --> HUB
HUB -- "automatic containment" --> ZTNA
ZTNA -- "REST" --> GOZTNA
HUB -- "executed after approval" --> CEOS
UI -- "approve / roll back" --> HUB
HUB -- "audit log" --> UI
| Component | File | Default port | Role |
|---|---|---|---|
| Admin UI | app_containment.py |
8180 | NiceGUI dashboard for monitoring containment events, approvals, and audit logs |
| Containment Hub | containment_hub_a2a_server.py |
8100 | Receives breach notifications from Tetragon, performs risk assessment, and orchestrates downstream agents |
| ZTNA Agent | ztna_a2a_server.py |
8101 | Calls the Go ZTNA/SASE API below to enforce access blocking and magic-number authentication |
| Tetragon Agent | tetragon_a2a_server.py |
8102 | Streams tetra getevents, scores breaches, and notifies the Hub |
Go ZTNA/SASE API (ztna-tetragon/main.go) |
— | 8080 (inside the ceos1 container's network namespace, port-forwarded to the host via socat) |
REST API providing eBPF/XDP-based flow blocking and authentication |
The UI is assigned
PORT=8180because8080is already used by the Go ZTNA Server (to avoid a port conflict).
External repository (a2a-ceos-core)
Pushing configuration to cEOS (Arista) is not handled by this repository —
it's handled by the agents in the separate a2a-ceos-core repository.
CEOS_A2A_URL points directly at the NETCONF server rather than going
through the Hub (task_decompose_a2a_server.py), because routing read-type
commands through the Hub at port 8000 caused misrouting.
| Component | Default port | Role |
|---|---|---|
task_decompose_a2a_server.py (Hub) |
8000 | Decomposes natural-language commands and routes them to NETCONF/eAPI |
arista_netconf_rag_a2a_server.py |
8001 | Configuration changes (NETCONF; called directly from this repository) |
arista_eapi_show_a2a_server.py |
8002 | Operational state checks (eAPI, since <state> is not retrievable via NETCONF) |
- Detection —
tetragon_a2a_server.pymonitors Tetragon events and bursts of ticket issuance, and computes a risk score. - Notification — The Hub is notified via
/containment(or an A2A message). - Assessment — The Hub classifies the event as Low / Medium / High:
- Low: ZTNA containment is executed automatically only; no ACL is pushed to cEOS (escalates to Medium on repeat detection).
- Medium: ZTNA is executed immediately and automatically; pushing an
ACL to cEOS requires administrator approval (
POST /deploy/{trace_id}). - High: ZTNA is executed immediately + the account is locked; pushing configuration to cEOS/Junos requires approval. After the cEOS action completes, a system-wide lock is proposed.
- Approval / Rollback — Approvals and rollbacks can be performed from
the UI (
app_containment.py). - Audit — Execution results are recorded in the audit log (
/audit).
Lab topology (sase-lab) defined in containerlab/vpp.clab.yml.
| Node | Role |
|---|---|
linux1 |
Monitored host (runs Tetragon, has FRR) |
linux2 |
Demo attack target |
ceos1 |
Arista cEOS (4.36.0F), eAPI enabled. The ZTNA/SASE XDP agent also runs inside this container's network namespace |
tetragon1 |
Cilium Tetragon (v1.6.0), runs with host networking |
VPP (fdio_vpp) provides the data plane; the management network is
172.20.100.0/24.
- Python 3.11+
- Go 1.24+ (to build the
ztna-tetragonXDP agent) - A Tetragon-capable Linux kernel (BTF support,
/sys/fs/bpfmounted) — see the bind mounts insystemd/tetragon_a2a_server.serviceand thetetragon1node incontainerlab/vpp.clab.ymlfor what's expected - containerlab + Docker, if you want to reproduce the test lab
- Optional: a Groq and/or Google Cloud (Gemini API) account for the LLM layer, and an Elastic Cloud account for the observability layer
# Python 3.11+
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtThe Go-based ZTNA/SASE agent (ztna-tetragon/) needs to be built separately.
cd ztna-tetragon
go build -o sase-agent .config.ini / .env contain secrets and are excluded from Git (see
.gitignore). Provide your own values for your environment.
Key variables are summarized below (full details are also in the docstring at the top of each server file).
LLM configuration (llm_factory.py, shared by all servers)
LLM_PROVIDER:auto(default, Groq → Gemini fallback) /groq/gemini/azureGROQ_API_KEY: Groq (Primary,openai/gpt-oss-120b)- Gemini API (Fallback,
gemini-3.5-flash) - Azure OpenAI (
gpt-4.1-mini) is excluded from automatic fallback and only used whenLLM_PROVIDER=azureis set explicitly
Containment Hub (containment_hub_a2a_server.py)
A2A_PORT(default8100) /A2A_PUBLIC_URLZTNA_A2A_URL(defaulthttp://localhost:8101)TETRAGON_A2A_URL(defaulthttp://localhost:8102)CEOS_A2A_URL(defaulthttp://localhost:8001, direct NETCONF endpoint)JUNOS_A2A_URL(defaulthttp://localhost:8020, separate repository)ELASTIC_KIBANA_URL/ELASTIC_AGENT_ID/ELASTIC_KIBANA_USER/ELASTIC_KIBANA_PASS
ZTNA Agent (ztna_a2a_server.py)
A2A_PORT(default8101) /A2A_PUBLIC_URLSASE_API_URL(defaulthttp://localhost:8080)AGENT_API_KEY(auth key for write operations; development mode if unset)
Tetragon Agent (tetragon_a2a_server.py)
A2A_PORT(default8102) /A2A_PUBLIC_URLCONTAINMENT_HUB_URL(defaulthttp://localhost:8100)ELASTIC_ES_URL/ELASTIC_ES_USER/ELASTIC_ES_PASS/ELASTIC_INDEX_PREFIXTETRAGON_CONTAINER(defaulttetragon1) /DATAPLANE_SUBNET(default10.0.5.) /SIGKILL_THRESHOLD(default2)
UI (app_containment.py)
HUB_URL(defaulthttp://localhost:8100) /ZTNA_URL(defaulthttp://localhost:8101) /TETRAGON_URL(defaulthttp://localhost:8102)PORT(default8180) /BASIC_AUTH_USER/BASIC_AUTH_PASS(defaultadmin/admin— change these before any real-world use)LOCALE(defaultja) /POLL_INTERVAL(default10)
Due to dependencies between them, start the servers in the following order.
python containment_hub_a2a_server.py # :8100
python ztna_a2a_server.py # :8101
python tetragon_a2a_server.py # :8102
python app_containment.py # :8180 (UI)Unit files are included under systemd/ (intended for persistent operation
on a GCP VM). Paths, usernames (e.g. hidemi_k_labs), and secrets are sample
values — replace them with your own environment's values.
| Unit | Purpose |
|---|---|
containment_hub_a2a_server.service |
Runs the Hub persistently |
ztna_a2a_server.service |
Runs the ZTNA Agent persistently |
tetragon_a2a_server.service |
Runs the Tetragon Agent persistently |
app_containment.service |
Runs the UI persistently |
ztna_sase_agent.service |
Runs the Go-based XDP agent (inside the ceos1 namespace) |
ceos1_port_forward_8080.service |
Forwards the ceos1 namespace's :8080 to the host via socat |
This layer is a separate, read-only path — it is completely decoupled from
the containment decision path (/containment, /deploy). If Elastic Cloud
is unreachable or unconfigured, it only disables /investigate; it never
blocks, delays, or otherwise affects automatic or approved containment
actions.
- Four data sources are shipped to Elastic Cloud:
ceos1— gNMI/OpenConfig interface counters (telegraf/ceos1_telegraf.conf)linux1— host metrics (CPU / memory / disk / network) (telegraf/linux1_telegraf.conf)linux2— the same host metrics plussshdauth-log tailing (telegraf/linux2_telegraf.conf)tetragon1— raw Tetragon events, stored under theELASTIC_INDEX_PREFIXindex (defaulttetragon-events)
POST /investigateon the Containment Hub forwards natural-language questions (e.g. "When did the last successful SSH login on linux2 happen?") to Elastic Agent Builder over the standard A2Amessage/sendmethod. Agent Builder generates ES|QL, queries Elasticsearch, and returns a summarized answer.- The
audittab in the UI separately shows the history of containment actions, approvals, and rollbacks — this is unrelated to Elastic Cloud and always works regardless of the observability layer's state.
-
hidemi-k/a2a-ceos-core — Agents for operating Arista cEOS via NETCONF/eAPI/ANTA/XDP (the target of this repository's
CEOS_A2A_URL) -
hidemi-k/maf-ebpf-sase — Rust source for the XDP/eBPF kernel program that
ztna-tetragon/main.goloads and controls
MIT License (see LICENSE) Copyright (c) 2026 hidemi-k
- This repository was built for a hackathon / research demo. It contains
sample credentials (e.g.
BASIC_AUTH_PASS) and sample external-service connection details — do not use these values in any real deployment. - eBPF (Tetragon) and XDP (the Go agent) depend on the host kernel's capabilities, so behavior may vary depending on your kernel version and environment.
- Automatic containment (especially automatic execution at Low risk) can block legitimate access in the case of a false positive. Test thoroughly before any real-world use.
