Skip to main content
availability

Package: Invicti API Security Standalone or Bundle

NTA with eBPF Sniffer

The Invicti Network Traffic Analyzer (NTA) eBPF Sniffer captures encrypted API traffic at the Linux kernel level using eBPF technology. It intercepts plaintext data before encryption and after decryption — enabling automatic API discovery for HTTPS/TLS traffic without requiring TLS termination, certificate manipulation, or application changes.

The eBPF Sniffer works only with TLS-encrypted connections. It does not capture unencrypted HTTP traffic — for that, use the Tap Plugin. Compared to the Tap Plugin, the eBPF Sniffer supports:

  • HTTPS/TLS traffic — no TLS termination or certificate injection required
  • HTTP/2 — full protocol support beyond HTTP/1.1
  • Cross-container capture — one DaemonSet pod per node captures all containers on that node
  • No service mesh dependency — works without Istio or any proxy
  • DNS enrichment — resolves destination IP addresses to hostnames using in-kernel DNS capture
  • Process identification — identifies which service or process made each API call

Prerequisites

  • A Kubernetes cluster (EKS, GKE, AKS, k3s, or self-managed) with Linux worker nodes
  • Helm command-line tool installed (version 3+)
  • Cluster access configured (for example, via kubeconfig)
  • Linux kernel version 5.2 or later on cluster worker nodes (5.8 or later recommended)

Overview

The eBPF Sniffer uses CO-RE (Compile Once, Run Everywhere) technology to load a pre-compiled eBPF program that works across different kernel versions without runtime compilation. It attaches eBPF probes (uprobes) to TLS library functions (for example, OpenSSL's SSL_write and SSL_read), capturing plaintext data before encryption and after decryption. For Go and Rust applications, the sniffer attaches to their built-in TLS implementations directly. This approach requires no changes to your applications, no proxy configuration, and no service mesh.

How it works

eBPF Sniffer data flow: from SSL_write call through eBPF uprobe, user-space parsing, Reconstructor, APIHub, to Platform UIeBPF Sniffer data flow: from SSL_write call through eBPF uprobe, user-space parsing, Reconstructor, APIHub, to Platform UI

Supported SSL/TLS libraries

LibrarySupported runtimesStatus
OpenSSL (libssl)Python, Node.js, Ruby, PHP, curl, nginx, ApacheFully supported
OpenSSL 3.x (SSL_read_ex/SSL_write_ex)Applications linked against OpenSSL 3.xFully supported
GnuTLS (libgnutls)Linux system toolsFully supported
NSS (libnspr4)Firefox, some Linux toolsSupported
Go crypto/tlsAny Go application using crypto/tls (for example, Traefik, Caddy, CoreDNS)Supported (opt-in)
Rust rustlsAny Rust application using rustls (for example, linkerd2-proxy, vector, cloudflared)Supported (opt-in)

Supported protocols

  • HTTP/1.1
  • HTTP/2

Enrichment features

The sniffer enriches each captured API call with additional context:

FeatureDescriptionDefault
DNS enrichmentResolves destination IP addresses to domain names. The resolved hostname is included in the telemetry sent to the Platform.Enabled
Process identificationIdentifies which service made each API call, including the process ancestry chain.Enabled
SNI extractionCaptures the Server Name Indication (SNI) from TLS handshakes to identify the destination hostname.Enabled
Self-healingMonitors sniffer health and takes corrective action automatically (event loss, memory, connectivity).Enabled

Data handling and privacy

The eBPF Sniffer captures HTTP metadata (method, path, headers, status code) and request/response bodies from decrypted TLS traffic. This data is processed locally inside the sniffer pod and sent to the Reconstructor service. The Reconstructor assembles captured HTTP telemetry into OpenAPI specifications and forwards only the relevant API endpoint metadata to the Invicti Platform.

Sensitive data protection:

  • Sensitive headers (Authorization, Cookie, Set-Cookie, X-API-Key, X-Auth-Token, and others) are redacted before data leaves the sniffer pod.
  • Request and response bodies are scanned for sensitive patterns (passwords, API keys, tokens, credit card numbers, Social Security numbers) and redacted automatically.
  • No captured data is written to disk on the node.
  • All operations are recorded in an audit log (start, stop, probe attachment, configuration changes).
caution

The sniffer captures plaintext data from TLS library calls. Ensure that deploying traffic capture tools in your cluster complies with your organization's security and privacy policies.

Namespace filtering

By default, the sniffer captures TLS traffic from all containers on the node. To limit capture to specific Kubernetes namespaces or exclude sensitive namespaces (for example, PCI-scoped environments):

# Enable cgroup-based filtering (required for namespace filtering)
--set trafficSource.ebpfSniffer.filter.cgroupFilterEnabled=true

# Include only specific namespaces
--set "trafficSource.ebpfSniffer.filter.namespaces={production,staging}"

# Exclude specific namespaces (takes priority over include)
--set "trafficSource.ebpfSniffer.filter.excludeNamespaces={kube-system,monitoring,payment-pci}"
note

Namespace filtering requires cgroupFilterEnabled: true. Without it, the filter settings are ignored and all containers on the node are captured.

Installation

Step 1: Generate a registration token

  1. Select Discovery from the left-side menu.
  2. Under API configuration, select API sources.
  3. Click Add source.
  4. Leave the Import type as External platform.
  5. Enter a name for the source configuration. This helps you identify it later in your list of API sources.
  6. Select Invicti Network Traffic Analyzer as the Source type.
  7. Click Generate token.
  8. Click the copy icon next to the newly generated registration token.
  9. Click Save at the bottom of the page. Do not skip this step.

Step 2: Authenticate with the Invicti registry

  1. Launch the Helm command-line tool.
  2. Run the following command:
helm registry login registry.invicti.com
Authentication credentials

Username: your Invicti Platform email Password: your valid Invicti Platform license key

Step 3: Verify kernel compatibility

Verify that your cluster worker nodes are running a supported kernel version. You can check this with:

kubectl get nodes -o wide

The KERNEL-VERSION column shows the kernel version on each node.

Most modern cloud kernels (EKS, GKE, AKS) meet these requirements. No additional packages or kernel headers need to be installed.

Step 4: Deploy the Helm chart

Run the following command to install the NTA with the eBPF Sniffer into your Kubernetes cluster:

helm install invicti-api-discovery \
oci://registry.invicti.com/invicti-api-discovery \
--version 26.4.0 \
-n <your-namespace> \
--set trafficSource.ebpfSniffer.enabled=true \
--set imageRegistryUsername=<email-address> \
--set imageRegistryPassword=<license-key> \
--set reconstructor.JWT_TOKEN="<registration-token>" \
--create-namespace

Replace the following placeholders:

PlaceholderDescription
<your-namespace>The Kubernetes namespace for the deployment
<email-address>Your Invicti Platform email address
<license-key>Your Invicti Platform license key
<registration-token>The token generated in Step 1. Keep it enclosed in double quotes.
Version pinning

Always specify a --version in production environments. Using a pinned version ensures reproducible deployments and controlled upgrades. Check the Invicti release notes for the latest available version.

Namespace creation

The --create-namespace flag creates the namespace automatically. In enterprise environments where namespaces are managed by infrastructure teams, remove this flag and create the namespace beforehand. Ensure your RBAC policies allow the Helm service account to deploy in the target namespace.

Step 5: Verify the installation

Check that the pods are running:

kubectl get pods -n <your-namespace>

You should see one sniffer pod per worker node and one reconstructor pod, all with Running status:

NAME                                                   READY   STATUS    RESTARTS   AGE
invicti-api-discovery-ebpf-sniffer-xxxxx 1/1 Running 0 2m
invicti-api-discovery-reconstructor-xxxxxxxxxx-xxxxx 1/1 Running 0 2m

Verify that the sniffer is capturing traffic by checking the logs. Replace <sniffer-pod> with a pod name from the output above:

kubectl logs -n <your-namespace> <sniffer-pod> --tail=20

You should see output similar to:

{"level":"INFO","msg":"CO-RE mode: using pre-compiled BPF (libbpf, no kernel headers needed)"}
{"level":"INFO","msg":"CO-RE: BPF programs loaded successfully"}
{"level":"INFO","msg":"Discovery: found 3 unique SSL libraries across 45 processes"}
{"level":"INFO","msg":"Attached probes to 4 SSL libraries"}
{"level":"INFO","msg":"DNS capture enabled (cache_ttl=300s, max_size=10000)"}
{"level":"INFO","msg":"Process tracking enabled (max_tree=50000, ancestor_depth=5)"}
{"level":"INFO","msg":"Sniffer is running. Press Ctrl+C to stop."}

If everything looks good, the NTA with the eBPF Sniffer is now capturing and analyzing encrypted traffic in your Kubernetes cluster.

Update or reinstall

Use the same registration token and credentials from your initial installation.

  1. Log in to the Invicti registry as described in Step 2.
  2. Run the upgrade command:
helm upgrade invicti-api-discovery \
oci://registry.invicti.com/invicti-api-discovery \
--version <new-version> \
-n <your-namespace> \
--set trafficSource.ebpfSniffer.enabled=true \
--set imageRegistryUsername=<email-address> \
--set imageRegistryPassword=<license-key> \
--set reconstructor.JWT_TOKEN="<registration-token>"

Replace <new-version> with the target version.

Uninstall

To remove the NTA eBPF Sniffer from your cluster:

helm uninstall invicti-api-discovery -n <your-namespace>

This removes all sniffer and reconstructor pods, services, and ConfigMaps. The sniffer does not persist data on the nodes.

After uninstalling, manually delete the Reconstructor PersistentVolume (it uses a Retain policy and is not removed automatically):

kubectl delete pv invicti-api-discovery-reconstructor-pv
kubectl delete pvc invicti-api-discovery-reconstructor-pvc -n <your-namespace>

Configuration

You can customize the eBPF Sniffer deployment using Helm values. Pass them using --set or a values file. The following example shows an installation command with commonly used parameters:

helm install invicti-api-discovery \
oci://registry.invicti.com/invicti-api-discovery \
--version 26.4.0 \
-n <your-namespace> \
--set trafficSource.ebpfSniffer.enabled=true \
--set trafficSource.ebpfSniffer.logLevel=info \
--set trafficSource.ebpfSniffer.goDiscovery.enabled=true \
--set trafficSource.ebpfSniffer.discovery.rescanInterval=60 \
--set imageRegistryUsername=<email-address> \
--set imageRegistryPassword=<license-key> \
--set reconstructor.JWT_TOKEN="<registration-token>"

Configuration reference

ParameterDescriptionDefault
trafficSource.ebpfSniffer.enabledEnable the eBPF Sniffer DaemonSetfalse
trafficSource.ebpfSniffer.logLevelLog level: debug, info, warning, errorinfo
trafficSource.ebpfSniffer.capture.maxBufferSizeMaximum bytes captured per SSL event8192
trafficSource.ebpfSniffer.capture.perfBufferPagesBuffer size in pages (power of 2). Increase for high-throughput environments.64
trafficSource.ebpfSniffer.goDiscovery.enabledEnable Go crypto/tls binary discoveryfalse
trafficSource.ebpfSniffer.rustDiscovery.enabledEnable Rust rustls binary discoveryfalse
trafficSource.ebpfSniffer.discovery.rescanIntervalInterval in seconds to rescan for new SSL libraries. 0 = scan only at startup.0
trafficSource.ebpfSniffer.namespaceA custom label added to telemetry data to identify the source cluster or environment (for example, production-us or staging). This does not filter which Kubernetes namespace is monitored.""
trafficSource.ebpfSniffer.filter.cgroupFilterEnabledEnable kernel-level cgroup filtering. Required for namespace filtering.false
trafficSource.ebpfSniffer.filter.namespacesInclude only these Kubernetes namespaces. Empty list captures all. Requires cgroupFilterEnabled: true.[]
trafficSource.ebpfSniffer.filter.excludeNamespacesExclude these Kubernetes namespaces. Takes priority over namespaces. Requires cgroupFilterEnabled: true.[]
trafficSource.ebpfSniffer.dns.enabledEnable DNS enrichment (resolve destination IPs to hostnames)true
trafficSource.ebpfSniffer.process.enabledEnable process identification (identify source service per API call)true
trafficSource.ebpfSniffer.watchdog.enabledEnable self-healing watchdog (memory guard, event loss detection, stall detection)true
trafficSource.ebpfSniffer.privilegedRun as fully privileged container. Only required for kernels earlier than 5.8.false
trafficSource.ebpfSniffer.legacyKernelSupportAdd SYS_ADMIN capability for BCC fallback on kernels earlier than 5.8. Not needed on kernel 5.8 or later.false

Security

Container permissions

The eBPF Sniffer runs with the minimum set of Linux capabilities required for eBPF operation. It does not require privileged: true on kernel 5.8 or later.

CapabilityPurpose
CAP_BPFLoad and attach eBPF programs
CAP_PERFMONAccess perf events (uprobe and kretprobe attachment)
CAP_SYS_PTRACERead /proc/*/maps to discover SSL libraries in other containers
CAP_SYS_RESOURCEIncrease RLIMIT_MEMLOCK for BPF maps
CAP_DAC_READ_SEARCHRead container filesystems via /proc/*/root
CAP_NET_ADMINCreate uprobe perf events

For kernels earlier than 5.8, enable legacyKernelSupport: true to add CAP_SYS_ADMIN (required for BPF on older kernels).

Self-healing

The sniffer includes an internal watchdog that monitors its own health and takes corrective action automatically:

  • Event loss detection — alerts when the event loss rate exceeds a configurable threshold (default: 10%)
  • Memory guard — prunes internal caches when memory usage exceeds the limit (default: 400 MB)
  • Output health — detects and reports connectivity issues with the Reconstructor
  • Stall detection — alerts when no events are captured for multiple check intervals

The watchdog runs every 30 seconds by default and requires no configuration.

Audit logging

All sniffer operations are recorded in a structured audit log:

  • Sniffer start and stop events (including the operator user and process ID)
  • Probe attachment and re-attachment events
  • Configuration changes (hot-reload)
  • Namespace filter updates
  • Security alerts
  • Self-healing recovery actions

The audit log is written to /var/log/invicti-sniffer/audit.log inside the pod and rotates automatically at 50 MB.

note

Audit logs are not persisted across pod restarts. To retain logs long-term, configure a log shipping solution (for example, Fluentd or Filebeat) to collect from /var/log/invicti-sniffer/.

Metrics

The sniffer exposes Prometheus metrics on port 9090 at the /metrics path. Metrics include event counts, error rates, probe status, and capture statistics.

Metrics endpoint authentication

The Prometheus metrics endpoint does not require authentication. If your security policy requires authenticated access to metrics, use a Kubernetes NetworkPolicy to restrict access to your monitoring namespace, or place a sidecar proxy in front of the metrics port.

Network requirements

Ensure the following network connectivity is available from the cluster:

EndpointPortDirectionPurpose
registry.invicti.com443 (HTTPS)OutboundPull sniffer and reconstructor container images
platform.invicti.com443 (HTTPS)OutboundReconstructor heartbeat and API specification upload
Cluster DNS53 (UDP)InternalKubernetes service discovery between sniffer and reconstructor

If your cluster uses an egress firewall or proxy, add these endpoints to your allowlist.

Frequently asked questions

Show all questions
What does the eBPF Sniffer do?

The eBPF Sniffer monitors SSL/TLS library function calls at the Linux kernel level using eBPF uprobes. It captures the plaintext data before encryption (on outgoing requests) and after decryption (on incoming responses), extracts HTTP telemetry, enriches it with DNS and process context, and sends it to the Reconstructor service for API discovery.

Does it capture both internal and external API traffic?

The eBPF Sniffer captures SSL/TLS traffic from all processes running on the node. This includes any encrypted HTTP traffic that those processes send or receive, whether to other services within the cluster or to external endpoints.

You can restrict capture to specific namespaces using the namespaces and excludeNamespaces configuration options. In shared or multi-tenant clusters, use namespace filtering to limit the scope to specific workloads.

Does it support HTTPS traffic?

Yes. This is the primary advantage of the eBPF Sniffer over the Tap Plugin. It captures plaintext data directly from SSL library functions, so TLS encryption is transparent to the sniffer. No TLS termination, proxy, or certificate injection is required.

Does it require a service mesh?

No. The eBPF Sniffer operates at the kernel level and does not require Istio, Linkerd, or any other service mesh. It works with any Kubernetes setup.

What kernel version is required?

The minimum kernel version is 5.2 with BTF support. Kernel 5.8 or later is recommended for fine-grained capabilities (no privileged: true or SYS_ADMIN required).

Kernel versionSupport level
Earlier than 5.2Not supported
5.2–5.7Supported (requires legacyKernelSupport: true)
5.8 and laterFull support (fine-grained capabilities, no SYS_ADMIN needed)
Which Kubernetes platforms are supported?
PlatformStatusNotes
Amazon EKS (Amazon Linux 2023 / Ubuntu)SupportedBTF available by default
Google GKE (Ubuntu node pools)SupportedUse Ubuntu image type
Google GKE (Container-Optimized OS)SupportedKernel 5.10+ with BTF (CO-RE mode)
Azure AKS (Ubuntu)SupportedBTF available by default
k3s / RKE2SupportedWorks out of the box
OpenShiftSupportedRequires SecurityContextConstraint for the required capabilities
Are Go and Rust applications supported?

Yes, with opt-in configuration. Go and Rust applications typically use statically-linked TLS libraries that are not shared as .so files. Enable support via:

  • trafficSource.ebpfSniffer.goDiscovery.enabled=true for Go applications using crypto/tls
  • trafficSource.ebpfSniffer.rustDiscovery.enabled=true for Rust applications using rustls
note

Go and Rust support uses uretprobes, which may have a minor performance impact on the target application. Enable only if needed.

Does the eBPF Sniffer capture request and response bodies?

Yes. Request bodies up to 256 KB and response bodies up to 1 MB are captured. Larger bodies are truncated. Sensitive data in both headers and bodies (such as passwords, API keys, tokens, credit card numbers, and Social Security numbers) is redacted automatically before data leaves the sniffer pod.

What is the performance impact?

The eBPF Sniffer operates in kernel space with minimal overhead. The probes execute only during TLS read/write calls and copy a small buffer of plaintext data to user space. The sniffer does not proxy or redirect traffic — it passively observes TLS library calls without affecting the data path.

How many pods does it deploy?

The eBPF Sniffer runs as a Kubernetes DaemonSet — one pod per node. Because eBPF operates at the kernel level, a single pod captures traffic from all containers on that node.

The Reconstructor runs as a single-replica Deployment that receives telemetry from all sniffer pods and forwards API specifications to the Invicti Platform.

Do pods run in privileged mode?

No — on kernel 5.8 and later, the sniffer uses fine-grained Linux capabilities and does not run as a privileged container. The required capabilities are:

  • CAP_BPF — load and attach eBPF programs
  • CAP_PERFMON — access perf events for uprobe attachment
  • CAP_SYS_PTRACE — read /proc/*/maps to discover SSL libraries in other containers
  • CAP_SYS_RESOURCE — increase locked memory for BPF maps
  • CAP_DAC_READ_SEARCH — read container filesystems via /proc/*/root
  • CAP_NET_ADMIN — create uprobe perf events

For kernels earlier than 5.8, set legacyKernelSupport: true to add CAP_SYS_ADMIN, or set privileged: true if required by your cluster's security policy.

What happens if a new application is deployed after the sniffer?

By default, the sniffer discovers SSL libraries at startup only. If you deploy new applications after the sniffer is running, their traffic will not be captured until the sniffer rescans.

To enable automatic discovery of new applications, set trafficSource.ebpfSniffer.discovery.rescanInterval to a non-zero value (in seconds). For example, 60 rescans every minute. This is recommended for clusters where applications are deployed or restarted frequently.

Can I exclude specific namespaces from capture?

Yes. Enable cgroup filtering and set excludeNamespaces to prevent the sniffer from capturing traffic in specific namespaces. This is useful for PCI-scoped environments, monitoring namespaces, or system namespaces:

--set trafficSource.ebpfSniffer.filter.cgroupFilterEnabled=true \
--set "trafficSource.ebpfSniffer.filter.excludeNamespaces={kube-system,monitoring}"

Exclusion takes priority over inclusion — if a namespace appears in both namespaces and excludeNamespaces, it is excluded.

How do I deploy across multiple clusters?

Deploy the Helm chart separately in each cluster using the same registration token. Use the namespace parameter to identify each cluster in the Platform UI:

# Cluster 1: US production
--set trafficSource.ebpfSniffer.namespace="production-us"

# Cluster 2: EU production
--set trafficSource.ebpfSniffer.namespace="production-eu"

# Cluster 3: Staging
--set trafficSource.ebpfSniffer.namespace="staging"

The namespace value appears as a label on discovered API endpoints in the Invicti Platform, allowing you to filter and compare API inventories across environments.

Troubleshooting

Show all troubleshooting topics
Pods are stuck in Init state

The init container is setting up kernel header symlinks. Check the init container logs:

kubectl logs -n <your-namespace> <sniffer-pod> -c fix-kernel-headers

Check the kernel version on the node (see Step 3) and restart the pod.

Sniffer reports "0 probes attached"

No SSL libraries were found on the node. Possible causes:

  • No applications using OpenSSL, GnuTLS, or NSS are running on the node
  • The /proc volume is not mounted correctly
  • The sniffer does not have sufficient permissions to read /proc/*/maps

Check the sniffer logs for detailed discovery output:

kubectl logs -n <your-namespace> <sniffer-pod> | grep -i "discover"
Sniffer logs show "falling back to BCC"

The sniffer could not load its pre-compiled eBPF program, usually because the kernel is older than 5.2 or does not include BTF support. The sniffer will still work using a fallback method, but you may need to set legacyKernelSupport: true for kernels earlier than 5.8.

Readiness probe fails (503)

The readiness probe returns 503 during startup while the sniffer loads eBPF programs and attaches probes. This typically takes 10–30 seconds. If it persists:

  1. Check for errors in the sniffer logs.
  2. Ensure the kernel version is 5.2 or later (see Step 3).
No traffic appears in the Platform UI
  1. Verify the sniffer is running and ready:
kubectl get pods -n <your-namespace> | grep ebpf-sniffer
  1. Check connectivity to the Reconstructor:
kubectl logs -n <your-namespace> <sniffer-pod> | grep -i "reconstructor\|telemetry\|send"
  1. Verify the registration token is valid and the Reconstructor is authenticated with the platform.
  2. Confirm that the target applications use TLS. The eBPF Sniffer does not capture unencrypted HTTP traffic. For plain HTTP, use the Tap Plugin.
High memory usage

If the sniffer pod is consuming more memory than expected:

  • Reduce trafficSource.ebpfSniffer.capture.perfBufferPages (for example, from 64 to 32).
  • The built-in watchdog automatically prunes internal caches when memory usage exceeds 400 MB. This threshold is configurable.
  • Increase the memory limit if your environment has high SSL/TLS throughput.
Permission denied errors in logs

If you see Permission denied errors related to BPF program loading or uprobe attachment:

  1. Verify the pod has the required capabilities (see Container permissions).
  2. For kernels earlier than 5.8, set legacyKernelSupport: true to add CAP_SYS_ADMIN.
  3. If your cluster has restrictive PodSecurityPolicies or PodSecurityStandards, ensure the sniffer's service account is allowed the required capabilities.
Reconstructor crashes with 401 Unauthorized

If the Reconstructor pod is in CrashLoopBackOff and logs show 401 Unauthorized on heartbeat requests, the registration token is invalid or was not passed correctly.

Registration tokens do not expire, so the most common causes are:

  • The token was truncated or modified during copy-paste (ensure it is enclosed in double quotes in the Helm command)
  • The token contains shell-special characters that were interpreted by the shell
  • The API source was deleted from the Platform UI, invalidating the token

To fix:

  1. Verify the token by decoding its base64 content: echo "<token>" | base64 -d
  2. If the token is corrupted, generate a new one following Step 1.
  3. Update the deployment:
helm upgrade invicti-api-discovery \
oci://registry.invicti.com/invicti-api-discovery \
--version 26.4.0 \
-n <your-namespace> \
--set trafficSource.ebpfSniffer.enabled=true \
--set imageRegistryUsername=<email-address> \
--set imageRegistryPassword=<license-key> \
--set reconstructor.JWT_TOKEN="<registration-token>"

For additional issues, refer to NTA troubleshooting.

Need help?

Invicti Support team is ready to provide you with technical help. Go to Help Center

Was this page useful?