Deploy Cilium Tetragon for advanced runtime security monitoring in Kubernetes clusters using eBPF technology. Configure security policies, threat detection rules, and real-time monitoring with Grafana dashboards for comprehensive container protection.
Prerequisites
- Running Kubernetes cluster with admin access
- Linux kernel 4.19+ with eBPF support
- Helm 3.x installed
- At least 2GB available memory per node
- Prometheus and Grafana for monitoring (recommended)
What this solves
Cilium Tetragon provides runtime security monitoring for Kubernetes clusters using eBPF technology to observe system calls, network activity, and process execution in real-time. This tutorial helps you implement comprehensive threat detection and security policy enforcement without requiring kernel modifications or application changes. Tetragon integrates seamlessly with existing Kubernetes environments and provides detailed observability into container behavior for detecting security anomalies and policy violations.
Step-by-step installation
Prepare the system and install dependencies
Update your system and install required packages for Kubernetes and eBPF functionality.
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl wget gnupg2 software-properties-common apt-transport-https ca-certificates
Verify Kubernetes cluster readiness
Ensure your Kubernetes cluster is running and you have cluster admin privileges for Tetragon deployment.
kubectl cluster-info
kubectl get nodes
kubectl auth can-i '' '' --all-namespaces
Install Helm for Tetragon deployment
Tetragon uses Helm charts for deployment. Install Helm if not already available in your environment.
curl https://baltocdn.com/helm/signing.asc | gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg > /dev/null
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/helm.gpg] https://baltocdn.com/helm/stable/debian/ all main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list
sudo apt update
sudo apt install -y helm
Add Cilium Helm repository
Add the official Cilium Helm repository to access Tetragon charts and verify the repository.
helm repo add cilium https://helm.cilium.io/
helm repo update
helm search repo cilium/tetragon
Create Tetragon namespace and configuration
Create a dedicated namespace for Tetragon and prepare the configuration values file.
kubectl create namespace kube-system || true
kubectl create namespace tetragon
tetragon:
enabled: true
image:
repository: quay.io/cilium/tetragon
tag: v1.0.2
grpc:
enabled: true
address: "localhost:54321"
gops:
enabled: true
address: "localhost"
port: 8080
prometheus:
enabled: true
port: 2112
serviceMonitor:
enabled: true
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 100m
memory: 128Mi
securityContext:
privileged: false
runAsUser: 0
runAsGroup: 0
capabilities:
add:
- SYS_ADMIN
- SYS_RESOURCE
- BPF
export:
filenames:
- /var/log/tetragon/tetragon.log
stdout: true
mode: json
tetragonOperator:
enabled: true
image:
repository: quay.io/cilium/tetragon-operator
tag: v1.0.2
resources:
limits:
cpu: 500m
memory: 128Mi
requests:
cpu: 100m
memory: 64Mi
serviceAccount:
create: true
name: "tetragon"
Deploy Tetragon using Helm
Install Tetragon in your Kubernetes cluster with the custom configuration and verify the deployment.
helm install tetragon cilium/tetragon -n tetragon -f /tmp/tetragon-values.yaml
kubectl get pods -n tetragon -w
Install Tetragon CLI tool
Install the tetra CLI for interacting with Tetragon and managing security policies.
curl -L https://github.com/cilium/tetragon/releases/latest/download/tetra-linux-amd64.tar.gz | tar -xz
sudo mv tetra /usr/local/bin/
sudo chmod +x /usr/local/bin/tetra
tetra version
Configure runtime security policies
Create basic process monitoring policy
Deploy a TracingPolicy to monitor process execution and system calls across the cluster.
apiVersion: cilium.io/v1alpha1
kind: TracingPolicy
metadata:
name: process-monitoring
namespace: tetragon
spec:
kprobes:
- call: "sys_execve"
syscall: true
args:
- index: 0
type: "string"
- index: 1
type: "char_buf"
sizeArgIndex: 2
- index: 2
type: "char_buf"
sizeArgIndex: 3
selectors:
- matchArgs:
- index: 0
operator: "Equal"
values:
- "/bin/bash"
- "/bin/sh"
- "/usr/bin/curl"
- "/usr/bin/wget"
matchActions:
- action: Post
- call: "sys_openat"
syscall: true
args:
- index: 0
type: "int"
- index: 1
type: "string"
- index: 2
type: "int"
selectors:
- matchArgs:
- index: 1
operator: "Prefix"
values:
- "/etc/passwd"
- "/etc/shadow"
- "/root"
matchActions:
- action: Post
kubectl apply -f /tmp/process-monitoring.yaml
Create network security policy
Configure network monitoring to detect suspicious connections and data exfiltration attempts.
apiVersion: cilium.io/v1alpha1
kind: TracingPolicy
metadata:
name: network-monitoring
namespace: tetragon
spec:
kprobes:
- call: "tcp_connect"
syscall: false
args:
- index: 0
type: "sock"
selectors:
- matchArgs:
- index: 0
operator: "DAddr"
values:
- "0.0.0.0/0"
matchActions:
- action: Post
- call: "sys_socket"
syscall: true
args:
- index: 0
type: "int"
- index: 1
type: "int"
- index: 2
type: "int"
selectors:
- matchArgs:
- index: 0
operator: "Equal"
values:
- "2" # AF_INET
- "10" # AF_INET6
matchActions:
- action: Post
kubectl apply -f /tmp/network-monitoring.yaml
Create file system security policy
Monitor sensitive file access and detect potential privilege escalation attempts.
apiVersion: cilium.io/v1alpha1
kind: TracingPolicy
metadata:
name: filesystem-monitoring
namespace: tetragon
spec:
kprobes:
- call: "security_file_permission"
syscall: false
args:
- index: 0
type: "file"
- index: 1
type: "int"
selectors:
- matchArgs:
- index: 0
operator: "Prefix"
values:
- "/etc/"
- "/var/run/secrets/"
- "/root/"
- "/home/"
matchActions:
- action: Post
- call: "sys_setuid"
syscall: true
args:
- index: 0
type: "int"
selectors:
- matchArgs:
- index: 0
operator: "Equal"
values:
- "0" # root UID
matchActions:
- action: Post
- action: Sigkill # Optional: kill processes attempting to escalate to root
kubectl apply -f /tmp/filesystem-monitoring.yaml
Set up monitoring and alerting
Configure Grafana dashboard for Tetragon
Create a custom Grafana dashboard to visualize Tetragon security events and metrics.
{
"dashboard": {
"id": null,
"title": "Tetragon Runtime Security",
"tags": ["tetragon", "security", "kubernetes"],
"timezone": "browser",
"panels": [
{
"id": 1,
"title": "Process Executions",
"type": "stat",
"targets": [
{
"expr": "rate(tetragon_events_total{event_type=\"PROCESS_EXEC\"}[5m])",
"refId": "A"
}
],
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 0}
},
{
"id": 2,
"title": "Network Connections",
"type": "stat",
"targets": [
{
"expr": "rate(tetragon_events_total{event_type=\"PROCESS_KPROBE\"}[5m])",
"refId": "B"
}
],
"gridPos": {"h": 8, "w": 12, "x": 12, "y": 0}
},
{
"id": 3,
"title": "Security Events Timeline",
"type": "logs",
"targets": [
{
"expr": "{job=\"tetragon\"} | json | line_format \"{{.time}} {{.process.binary}} {{.event_type}}\"",
"refId": "C"
}
],
"gridPos": {"h": 12, "w": 24, "x": 0, "y": 8}
}
],
"time": {
"from": "now-1h",
"to": "now"
},
"refresh": "5s"
}
}
Configure log aggregation with Fluentd
Set up log collection for Tetragon events using Fluentd for centralized analysis.
apiVersion: v1
kind: ConfigMap
metadata:
name: tetragon-fluentd-config
namespace: tetragon
data:
fluent.conf: |
@type tail
path /var/log/tetragon/tetragon.log
pos_file /var/log/fluentd-tetragon.log.pos
tag tetragon.security
@type json
time_key time
time_format %Y-%m-%dT%H:%M:%S.%LZ
@type record_transformer
severity ${record["process"] ? "INFO" : "WARNING"}
cluster_name kubernetes-production
source tetragon
@type forward
name log-server
host elasticsearch.monitoring.svc.cluster.local
port 24224
@type file
path /var/log/fluentd-buffers/tetragon
flush_mode interval
flush_interval 10s
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: tetragon-fluentd
namespace: tetragon
spec:
selector:
matchLabels:
name: tetragon-fluentd
template:
metadata:
labels:
name: tetragon-fluentd
spec:
containers:
- name: fluentd
image: fluent/fluentd:v1.16-debian-1
volumeMounts:
- name: tetragon-logs
mountPath: /var/log/tetragon
readOnly: true
- name: fluentd-config
mountPath: /fluentd/etc
resources:
limits:
memory: 200Mi
cpu: 100m
requests:
memory: 100Mi
cpu: 50m
volumes:
- name: tetragon-logs
hostPath:
path: /var/log/tetragon
- name: fluentd-config
configMap:
name: tetragon-fluentd-config
kubectl apply -f /tmp/tetragon-fluentd.yaml
Create alerting rules for security events
Configure Prometheus alerting rules for critical security events detected by Tetragon.
apiVersion: v1
kind: ConfigMap
metadata:
name: tetragon-alerts
namespace: monitoring
data:
tetragon.rules: |
groups:
- name: tetragon.security
rules:
- alert: TetragonHighProcessExecution
expr: rate(tetragon_events_total{event_type="PROCESS_EXEC"}[5m]) > 10
for: 2m
labels:
severity: warning
annotations:
summary: "High process execution rate detected"
description: "Process execution rate is {{ $value }} events/sec, above threshold"
- alert: TetragonPrivilegeEscalation
expr: increase(tetragon_events_total{event_type="PROCESS_KPROBE",function_name="sys_setuid"}[5m]) > 0
for: 0m
labels:
severity: critical
annotations:
summary: "Potential privilege escalation detected"
description: "Process attempted to change UID, potential privilege escalation"
- alert: TetragonSensitiveFileAccess
expr: increase(tetragon_events_total{event_type="PROCESS_KPROBE",function_name="security_file_permission"}[5m]) > 5
for: 1m
labels:
severity: warning
annotations:
summary: "Suspicious file access pattern"
description: "Multiple sensitive file access attempts detected"
- alert: TetragonAgentDown
expr: up{job="tetragon"} == 0
for: 1m
labels:
severity: critical
annotations:
summary: "Tetragon agent is down"
description: "Tetragon security monitoring agent is not responding"
kubectl apply -f /tmp/tetragon-alerts.yaml
Test threat detection capabilities
Deploy test workload for security monitoring
Create a test pod to validate that Tetragon is detecting and logging security events.
apiVersion: v1
kind: Pod
metadata:
name: security-test-pod
namespace: default
labels:
app: security-test
spec:
containers:
- name: test-container
image: ubuntu:22.04
command: ["/bin/sleep", "3600"]
securityContext:
runAsUser: 1000
runAsGroup: 1000
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: false
restartPolicy: Never
kubectl apply -f /tmp/test-pod.yaml
kubectl wait --for=condition=Ready pod/security-test-pod --timeout=60s
Generate security events for testing
Execute commands inside the test pod to trigger Tetragon monitoring and generate sample events.
kubectl exec -it security-test-pod -- /bin/bash -c "whoami && id"
kubectl exec -it security-test-pod -- /bin/bash -c "ls -la /etc/passwd"
kubectl exec -it security-test-pod -- /bin/bash -c "curl -I https://example.com || true"
Observe Tetragon events
Use the tetra CLI to view real-time security events generated by the test activities.
kubectl port-forward -n tetragon svc/tetragon 54321:54321 &
tetra getevents --server localhost:54321 | head -20
kill %1
Verify your setup
# Check Tetragon pods status
kubectl get pods -n tetragon
Verify tracing policies are active
kubectl get tracingpolicy -n tetragon
Check Tetragon metrics endpoint
kubectl port-forward -n tetragon svc/tetragon 2112:2112 &
curl http://localhost:2112/metrics | grep tetragon_events_total
kill %1
Verify CLI connectivity
kubectl port-forward -n tetragon svc/tetragon 54321:54321 &
tetra status --server localhost:54321
kill %1
Check service account permissions
kubectl auth can-i '' '' --as=system:serviceaccount:tetragon:tetragon
Validate log collection
kubectl logs -n tetragon daemonset/tetragon-fluentd --tail=10
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| Tetragon pods stuck in pending | Node kernel too old or eBPF not enabled | Upgrade to kernel 4.19+ and enable CONFIG_BPF=y |
| Permission denied errors | Insufficient RBAC permissions | Verify cluster-admin access and ServiceAccount permissions |
| No events being generated | TracingPolicy selectors too restrictive | Review matchArgs criteria and test with broader selectors |
| High CPU usage on nodes | Too many tracing points enabled | Reduce policy scope and add resource limits |
| Metrics not appearing in Prometheus | ServiceMonitor not detected | Check Prometheus operator labels and namespace |
| CLI connection timeout | gRPC port not accessible | Verify port-forward or service exposure configuration |
Next steps
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# Default values
TETRAGON_VERSION="v1.0.2"
NAMESPACE="tetragon"
# Usage function
usage() {
echo "Usage: $0 [OPTIONS]"
echo "Options:"
echo " -v, --version VERSION Tetragon version (default: ${TETRAGON_VERSION})"
echo " -n, --namespace NAME Namespace (default: ${NAMESPACE})"
echo " -h, --help Show this help message"
exit 1
}
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
-v|--version)
TETRAGON_VERSION="$2"
shift 2
;;
-n|--namespace)
NAMESPACE="$2"
shift 2
;;
-h|--help)
usage
;;
*)
echo -e "${RED}Unknown option: $1${NC}"
usage
;;
esac
done
# Cleanup function
cleanup() {
echo -e "${RED}Installation failed. Cleaning up...${NC}"
rm -f /tmp/tetragon-values.yaml /tmp/get_helm.sh
kubectl delete namespace "${NAMESPACE}" --ignore-not-found=true
}
trap cleanup ERR
# Check prerequisites
check_prerequisites() {
echo -e "${BLUE}[1/8] Checking prerequisites...${NC}"
if [[ $EUID -eq 0 ]]; then
echo -e "${RED}Do not run as root. Run as a user with sudo privileges.${NC}"
exit 1
fi
if ! command -v sudo &> /dev/null; then
echo -e "${RED}sudo is required but not installed${NC}"
exit 1
fi
if ! command -v kubectl &> /dev/null; then
echo -e "${RED}kubectl is required but not installed${NC}"
exit 1
fi
echo -e "${GREEN}Prerequisites check passed${NC}"
}
# Detect distribution
detect_distro() {
echo -e "${BLUE}[2/8] Detecting distribution...${NC}"
if [ -f /etc/os-release ]; then
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_INSTALL="apt install -y"
UPDATE_CMD="apt update && apt upgrade -y"
HELM_INSTALL_METHOD="apt"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_INSTALL="dnf install -y"
UPDATE_CMD="dnf update -y"
HELM_INSTALL_METHOD="script"
;;
amzn)
PKG_MGR="yum"
PKG_INSTALL="yum install -y"
UPDATE_CMD="yum update -y"
HELM_INSTALL_METHOD="script"
;;
*)
echo -e "${RED}Unsupported distribution: $ID${NC}"
exit 1
;;
esac
else
echo -e "${RED}/etc/os-release not found. Cannot detect distribution.${NC}"
exit 1
fi
echo -e "${GREEN}Detected distribution: $PRETTY_NAME${NC}"
export PKG_MGR PKG_INSTALL UPDATE_CMD HELM_INSTALL_METHOD
}
# Install system dependencies
install_dependencies() {
echo -e "${BLUE}[3/8] Installing system dependencies...${NC}"
sudo bash -c "${UPDATE_CMD}"
if [[ "$PKG_MGR" == "apt" ]]; then
sudo $PKG_INSTALL curl wget gnupg2 software-properties-common apt-transport-https ca-certificates
else
sudo $PKG_INSTALL curl wget gnupg2
fi
echo -e "${GREEN}System dependencies installed${NC}"
}
# Verify Kubernetes cluster
verify_kubernetes() {
echo -e "${BLUE}[4/8] Verifying Kubernetes cluster...${NC}"
if ! kubectl cluster-info &> /dev/null; then
echo -e "${RED}Kubernetes cluster is not accessible${NC}"
exit 1
fi
if ! kubectl get nodes &> /dev/null; then
echo -e "${RED}Cannot access cluster nodes${NC}"
exit 1
fi
if ! kubectl auth can-i '*' '*' --all-namespaces &> /dev/null; then
echo -e "${YELLOW}Warning: You may not have cluster admin privileges${NC}"
fi
echo -e "${GREEN}Kubernetes cluster verification passed${NC}"
}
# Install Helm
install_helm() {
echo -e "${BLUE}[5/8] Installing Helm...${NC}"
if command -v helm &> /dev/null; then
echo -e "${GREEN}Helm already installed${NC}"
return
fi
if [[ "$HELM_INSTALL_METHOD" == "apt" ]]; then
curl -fsSL https://baltocdn.com/helm/signing.asc | gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg > /dev/null
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/helm.gpg] https://baltocdn.com/helm/stable/debian/ all main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list
sudo apt update
sudo $PKG_INSTALL helm
else
curl -fsSL -o /tmp/get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
chmod 700 /tmp/get_helm.sh
/tmp/get_helm.sh
rm -f /tmp/get_helm.sh
fi
echo -e "${GREEN}Helm installed successfully${NC}"
}
# Setup Cilium repository
setup_cilium_repo() {
echo -e "${BLUE}[6/8] Setting up Cilium Helm repository...${NC}"
helm repo add cilium https://helm.cilium.io/
helm repo update
if ! helm search repo cilium/tetragon | grep -q tetragon; then
echo -e "${RED}Tetragon chart not found in repository${NC}"
exit 1
fi
echo -e "${GREEN}Cilium repository configured${NC}"
}
# Deploy Tetragon
deploy_tetragon() {
echo -e "${BLUE}[7/8] Deploying Tetragon...${NC}"
kubectl create namespace "${NAMESPACE}" || echo "Namespace ${NAMESPACE} already exists"
cat > /tmp/tetragon-values.yaml << EOF
tetragon:
enabled: true
image:
repository: quay.io/cilium/tetragon
tag: ${TETRAGON_VERSION}
grpc:
enabled: true
address: "localhost:54321"
gops:
enabled: true
address: "localhost"
port: 8080
prometheus:
enabled: true
port: 2112
serviceMonitor:
enabled: true
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 100m
memory: 128Mi
securityContext:
privileged: false
runAsUser: 0
runAsGroup: 0
capabilities:
add:
- SYS_ADMIN
- SYS_RESOURCE
- BPF
export:
filenames:
- /var/log/tetragon/tetragon.log
stdout: true
mode: json
tetragonOperator:
enabled: true
image:
repository: quay.io/cilium/tetragon-operator
tag: ${TETRAGON_VERSION}
resources:
limits:
cpu: 500m
memory: 128Mi
requests:
cpu: 100m
memory: 64Mi
serviceAccount:
create: true
name: "tetragon"
EOF
chmod 644 /tmp/tetragon-values.yaml
helm install tetragon cilium/tetragon -n "${NAMESPACE}" -f /tmp/tetragon-values.yaml
echo -e "${YELLOW}Waiting for Tetragon pods to be ready...${NC}"
kubectl wait --for=condition=Ready pod -l app.kubernetes.io/name=tetragon -n "${NAMESPACE}" --timeout=300s
# Install Tetragon CLI
curl -L "https://github.com/cilium/tetragon/releases/latest/download/tetra-linux-amd64.tar.gz" | tar -xz
sudo mv tetra /usr/local/bin/
sudo chmod 755 /usr/local/bin/tetra
rm -f /tmp/tetragon-values.yaml
echo -e "${GREEN}Tetragon deployed successfully${NC}"
}
# Verify installation
verify_installation() {
echo -e "${BLUE}[8/8] Verifying installation...${NC}"
if ! kubectl get pods -n "${NAMESPACE}" | grep -q "Running"; then
echo -e "${RED}Tetragon pods are not running${NC}"
exit 1
fi
if ! tetra version &> /dev/null; then
echo -e "${RED}Tetragon CLI is not working${NC}"
exit 1
fi
echo -e "${GREEN}Installation verification completed successfully${NC}"
echo -e "${BLUE}Tetragon is now running in namespace: ${NAMESPACE}${NC}"
echo -e "${BLUE}Use 'kubectl get pods -n ${NAMESPACE}' to check status${NC}"
echo -e "${BLUE}Use 'tetra' command to interact with Tetragon${NC}"
}
# Main execution
main() {
echo -e "${GREEN}Starting Cilium Tetragon installation...${NC}"
check_prerequisites
detect_distro
install_dependencies
verify_kubernetes
install_helm
setup_cilium_repo
deploy_tetragon
verify_installation
echo -e "${GREEN}Cilium Tetragon installation completed successfully!${NC}"
}
main "$@"
Review the script before running. Execute with: bash install.sh