Set up comprehensive security scanning and vulnerability management for Istio service mesh using Trivy, Falco, and security policies to protect Kubernetes workloads from threats and compliance violations.
Prerequisites
- Kubernetes cluster with Istio installed
- kubectl configured for cluster access
- Helm 3 installed
- Administrative access to cluster
What this solves
Istio service mesh provides powerful security features for Kubernetes, but requires comprehensive scanning and vulnerability management to protect against threats. This tutorial implements security scanning with Trivy for container vulnerabilities, Falco for runtime security monitoring, and admission controllers for policy enforcement. You'll establish continuous security monitoring and automated alerting for your service mesh workloads.
Prerequisites
- Kubernetes cluster with Istio installed
- kubectl configured for cluster access
- Helm 3 installed
- Administrative access to cluster
Step-by-step configuration
Install Istio security components
First, ensure Istio is configured with security features enabled. Install Istio with security policies and mTLS enabled by default.
istioctl install --set values.pilot.env.EXTERNAL_ISTIOD=false --set values.global.meshConfig.defaultConfig.proxyStatsMatcher.inclusionRegexps=".outlier_detection.,.circuit_breakers.,.upstream_rq_retry.,.upstream_rq_pending.,._cx_." -y
Enable automatic sidecar injection for security scanning:
kubectl label namespace default istio-injection=enabled
kubectl label namespace kube-system istio-injection=enabled
Verify Istio installation with security features:
istioctl verify-install
Deploy Trivy Operator for vulnerability scanning
Install the Trivy Operator to continuously scan container images and Kubernetes configurations for vulnerabilities. This provides comprehensive security assessment of your service mesh workloads.
helm repo add aqua https://aquasecurity.github.io/helm-charts/
helm repo update
helm install trivy-operator aqua/trivy-operator --namespace trivy-system --create-namespace
Configure Trivy for Istio-specific scanning:
apiVersion: v1
kind: ConfigMap
metadata:
name: trivy-operator
namespace: trivy-system
data:
trivy.dbRepository: "ghcr.io/aquasecurity/trivy-db"
trivy.severity: "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL"
trivy.resources.requests.cpu: "100m"
trivy.resources.requests.memory: "100M"
trivy.resources.limits.cpu: "500m"
trivy.resources.limits.memory: "500M"
vulnerabilityReports.scanner: "Trivy"
configAuditReports.scanner: "Trivy"
Apply the configuration:
kubectl apply -f /tmp/trivy-config.yaml
Install Falco for runtime security monitoring
Deploy Falco to monitor runtime security events in your Istio service mesh. This provides real-time threat detection and anomaly detection for running workloads.
helm repo add falcosecurity https://falcosecurity.github.io/charts
helm repo update
Create Falco configuration for Istio monitoring:
falco:
rules_file:
- /etc/falco/falco_rules.yaml
- /etc/falco/falco_rules.local.yaml
- /etc/falco/k8s_audit_rules.yaml
- /etc/falco/rules.d
json_output: true
json_include_output_property: true
log_stderr: true
log_syslog: true
log_level: info
priority: debug
syscall_event_drops:
actions:
- log
- alert
rate: 0.03333
max_burst: 1000
falcoctl:
artifact:
install:
refs: [falco-rules:0]
follow:
refs: [falco-rules:0]
collector:
enabled: false
falcosidekick:
enabled: true
config:
webhook:
address: "http://alertmanager:9093/api/v1/alerts"
tty: true
Install Falco with the configuration:
helm install falco falcosecurity/falco --namespace falco --create-namespace -f /tmp/falco-values.yaml
Configure Istio admission controllers
Set up admission controllers to enforce security policies and prevent vulnerable containers from being deployed. This creates a security gate for all workloads entering your service mesh.
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: istio-system
spec:
mtls:
mode: STRICT
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: deny-all
namespace: istio-system
spec:
rules:
- from:
- source:
principals: ["cluster.local/ns/istio-system/sa/istio-proxy"]
---
apiVersion: v1
kind: ValidatingAdmissionWebhook
metadata:
name: istio-security-validation
webhooks:
- name: security.validation.istio.io
clientConfig:
service:
name: istio-pilot
namespace: istio-system
path: "/validate"
rules:
- operations: ["CREATE", "UPDATE"]
apiGroups: ["", "apps", "extensions"]
apiVersions: ["v1", "v1beta1"]
resources: ["pods", "deployments", "services"]
admissionReviewVersions: ["v1", "v1beta1"]
sideEffects: None
failurePolicy: Fail
Apply the security policies:
kubectl apply -f /tmp/istio-security-policy.yaml
Create a network policy for additional security:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-default
namespace: default
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
name: istio-system
- to: []
ports:
- protocol: TCP
port: 53
- protocol: UDP
port: 53
Apply the network policy:
kubectl apply -f /tmp/network-policy.yaml
Set up Gatekeeper for policy enforcement
Install OPA Gatekeeper to enforce additional security policies and compliance requirements across your Istio service mesh.
kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/release-3.14/deploy/gatekeeper.yaml
Create a constraint template for image scanning requirements:
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
name: k8srequiredimagescan
spec:
crd:
spec:
names:
kind: K8sRequiredImageScan
validation:
openAPIV3Schema:
type: object
properties:
allowedRegistries:
type: array
items:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8srequiredimagescan
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
not starts_with(container.image, input.parameters.allowedRegistries[_])
msg := sprintf("Container image '%v' is not from allowed registry", [container.image])
}
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredImageScan
metadata:
name: must-use-scanned-images
spec:
match:
kinds:
- apiGroups: ["apps"]
kinds: ["Deployment"]
parameters:
allowedRegistries:
- "gcr.io/my-secure-registry"
- "registry.example.com"
Apply the policy:
kubectl apply -f /tmp/image-scan-policy.yaml
Configure continuous monitoring and alerting
Set up Prometheus monitoring for security events and vulnerability metrics. This provides comprehensive observability for your security posture.
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
Create monitoring configuration for security metrics:
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: trivy-operator
namespace: trivy-system
spec:
selector:
matchLabels:
app.kubernetes.io/name: trivy-operator
endpoints:
- port: metrics
interval: 30s
path: /metrics
---
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: falco
namespace: falco
spec:
selector:
matchLabels:
app.kubernetes.io/name: falco
endpoints:
- port: metrics
interval: 30s
path: /metrics
Configure alerting rules for security events:
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: istio-security-alerts
namespace: istio-system
spec:
groups:
- name: istio-security
rules:
- alert: HighSeverityVulnerability
expr: trivy_vulnerability_severity{severity="Critical"} > 0
for: 0m
labels:
severity: critical
annotations:
summary: "Critical vulnerability detected"
description: "Critical severity vulnerability found in {{ $labels.namespace }}/{{ $labels.pod }}"
- alert: FalcoSecurityEvent
expr: increase(falco_events_total[5m]) > 10
for: 1m
labels:
severity: warning
annotations:
summary: "High number of Falco security events"
description: "{{ $value }} security events detected in the last 5 minutes"
- alert: UnauthorizedNetworkTraffic
expr: increase(istio_requests_total{response_code!~"2.."}[5m]) > 50
for: 2m
labels:
severity: warning
annotations:
summary: "High number of failed requests"
description: "Potential security breach - high number of failed requests detected"
Apply the monitoring configuration:
kubectl apply -f /tmp/security-monitoring.yaml
kubectl apply -f /tmp/security-alerts.yaml
Set up automated security scanning workflows
Create automated workflows that trigger security scans when new workloads are deployed to your Istio service mesh.
apiVersion: batch/v1
kind: CronJob
metadata:
name: security-scan
namespace: trivy-system
spec:
schedule: "0 2 *"
jobTemplate:
spec:
template:
spec:
containers:
- name: trivy-scanner
image: aquasec/trivy:latest
command:
- sh
- -c
- |
kubectl get pods --all-namespaces -o jsonpath='{range .items[]}{.metadata.namespace}{" "}{.metadata.name}{" "}{.spec.containers[].image}{"\n"}{end}' | \
while read namespace pod image; do
echo "Scanning $image in $namespace/$pod"
trivy image --severity HIGH,CRITICAL --format json $image > /tmp/scan-$namespace-$pod.json
if [ $(jq '.Results[].Vulnerabilities | length' /tmp/scan-$namespace-$pod.json 2>/dev/null || echo 0) -gt 0 ]; then
echo "Vulnerabilities found in $namespace/$pod"
kubectl annotate pod $pod -n $namespace security.scan/status="vulnerabilities-found" --overwrite
fi
done
restartPolicy: OnFailure
serviceAccountName: trivy-scanner
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: trivy-scanner
namespace: trivy-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: trivy-scanner
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "patch"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: trivy-scanner
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: trivy-scanner
subjects:
- kind: ServiceAccount
name: trivy-scanner
namespace: trivy-system
Apply the automated scanning workflow:
kubectl apply -f /tmp/security-scan-cronjob.yaml
Verify your setup
Check that all security components are running correctly:
kubectl get pods -n trivy-system
kubectl get pods -n falco
kubectl get pods -n gatekeeper-system
Verify Trivy is scanning containers:
kubectl get vulnerabilityreports --all-namespaces
kubectl get configauditreports --all-namespaces
Check Falco is detecting security events:
kubectl logs -n falco -l app.kubernetes.io/name=falco --tail=50
Test admission controller by trying to deploy an insecure workload:
kubectl create deployment test --image=nginx:latest --dry-run=server
Verify security policies are active:
kubectl get peerauthentication -n istio-system
kubectl get authorizationpolicy -n istio-system
kubectl get constraints
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| Trivy scans failing | Insufficient resources or network issues | Increase resource limits in trivy-config.yaml and check network connectivity |
| Falco not detecting events | Missing kernel headers or eBPF support | Install kernel headers: sudo apt install linux-headers-$(uname -r) |
| Admission controller blocking legitimate pods | Overly restrictive policies | Review and update constraint templates to allow necessary images |
| High false positive rates | Default Falco rules too sensitive | Tune Falco rules in ConfigMap to reduce noise for your environment |
| Security scans not updating | CronJob or ServiceAccount permissions | Check RBAC permissions and CronJob status with kubectl get cronjobs -n trivy-system |
Next steps
- Set up Kubernetes container image security scanning with Trivy and admission controllers for additional scanning techniques
- Implement Istio observability with Jaeger tracing and Kiali dashboard for Kubernetes service mesh to complement security monitoring
- Implement Kubernetes network policies for pod-to-pod security and traffic isolation for enhanced network security
- Configure advanced Istio security policies with mTLS and authorization
- Set up automated security compliance scanning with CIS benchmarks
Running this in production?
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'
NC='\033[0m'
# Script configuration
SCRIPT_NAME="$(basename "$0")"
ISTIO_VERSION="1.20.2"
NAMESPACE_DEFAULT="${1:-default}"
# Usage message
usage() {
echo "Usage: $SCRIPT_NAME [namespace]"
echo " namespace: Kubernetes namespace to enable Istio injection (default: default)"
exit 1
}
# Logging functions
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
# Cleanup function for rollback
cleanup() {
if [ $? -ne 0 ]; then
log_error "Installation failed. Cleaning up..."
kubectl delete namespace trivy-system --ignore-not-found=true 2>/dev/null || true
kubectl delete namespace falco --ignore-not-found=true 2>/dev/null || true
helm uninstall trivy-operator -n trivy-system 2>/dev/null || true
helm uninstall falco -n falco 2>/dev/null || true
fi
}
trap cleanup ERR
# Check prerequisites
check_prerequisites() {
log_info "[1/10] Checking prerequisites..."
if [[ $EUID -ne 0 ]] && ! sudo -n true 2>/dev/null; then
log_error "This script requires root privileges or passwordless sudo"
exit 1
fi
command -v kubectl >/dev/null 2>&1 || { log_error "kubectl is required but not installed"; exit 1; }
command -v helm >/dev/null 2>&1 || { log_error "helm is required but not installed"; exit 1; }
kubectl cluster-info >/dev/null 2>&1 || { log_error "kubectl cannot connect to cluster"; exit 1; }
kubectl auth can-i create namespace >/dev/null 2>&1 || { log_error "Insufficient cluster permissions"; exit 1; }
}
# Detect OS and set package manager
detect_os() {
log_info "[2/10] Detecting operating system..."
if [ -f /etc/os-release ]; then
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_INSTALL="apt install -y"
PKG_UPDATE="apt update"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_INSTALL="dnf install -y"
PKG_UPDATE="dnf check-update || true"
;;
amzn)
PKG_MGR="yum"
PKG_INSTALL="yum install -y"
PKG_UPDATE="yum check-update || true"
;;
*)
log_error "Unsupported distribution: $ID"
exit 1
;;
esac
else
log_error "Cannot detect OS distribution"
exit 1
fi
log_info "Detected: $PRETTY_NAME using $PKG_MGR"
}
# Install system dependencies
install_dependencies() {
log_info "[3/10] Installing system dependencies..."
if [[ $EUID -eq 0 ]]; then
$PKG_UPDATE
case "$PKG_MGR" in
apt)
$PKG_INSTALL curl wget jq
;;
dnf|yum)
$PKG_INSTALL curl wget jq
;;
esac
else
sudo $PKG_UPDATE
case "$PKG_MGR" in
apt)
sudo $PKG_INSTALL curl wget jq
;;
dnf|yum)
sudo $PKG_INSTALL curl wget jq
;;
esac
fi
}
# Install istioctl
install_istioctl() {
log_info "[4/10] Installing istioctl..."
if ! command -v istioctl >/dev/null 2>&1; then
curl -L https://istio.io/downloadIstio | ISTIO_VERSION=$ISTIO_VERSION sh -
if [[ $EUID -eq 0 ]]; then
cp istio-$ISTIO_VERSION/bin/istioctl /usr/local/bin/
chmod 755 /usr/local/bin/istioctl
else
sudo cp istio-$ISTIO_VERSION/bin/istioctl /usr/local/bin/
sudo chmod 755 /usr/local/bin/istioctl
fi
rm -rf istio-$ISTIO_VERSION
fi
}
# Install Istio with security features
install_istio() {
log_info "[5/10] Installing Istio with security features..."
istioctl install --set values.pilot.env.EXTERNAL_ISTIOD=false \
--set values.global.meshConfig.defaultConfig.proxyStatsMatcher.inclusionRegexps=".outlier_detection.,.circuit_breakers.,.upstream_rq_retry.,.upstream_rq_pending.,._cx_." \
-y
kubectl label namespace $NAMESPACE_DEFAULT istio-injection=enabled --overwrite
kubectl label namespace kube-system istio-injection=enabled --overwrite
istioctl verify-install
}
# Deploy Trivy Operator
deploy_trivy() {
log_info "[6/10] Deploying Trivy Operator for vulnerability scanning..."
helm repo add aqua https://aquasecurity.github.io/helm-charts/
helm repo update
helm install trivy-operator aqua/trivy-operator \
--namespace trivy-system \
--create-namespace \
--wait
cat > /tmp/trivy-config.yaml << 'EOF'
apiVersion: v1
kind: ConfigMap
metadata:
name: trivy-operator
namespace: trivy-system
data:
trivy.dbRepository: "ghcr.io/aquasecurity/trivy-db"
trivy.severity: "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL"
trivy.resources.requests.cpu: "100m"
trivy.resources.requests.memory: "100M"
trivy.resources.limits.cpu: "500m"
trivy.resources.limits.memory: "500M"
vulnerabilityReports.scanner: "Trivy"
configAuditReports.scanner: "Trivy"
EOF
kubectl apply -f /tmp/trivy-config.yaml
rm -f /tmp/trivy-config.yaml
}
# Deploy Falco for runtime monitoring
deploy_falco() {
log_info "[7/10] Deploying Falco for runtime security monitoring..."
helm repo add falcosecurity https://falcosecurity.github.io/charts
helm repo update
cat > /tmp/falco-values.yaml << 'EOF'
falco:
rules_file:
- /etc/falco/falco_rules.yaml
- /etc/falco/falco_rules.local.yaml
- /etc/falco/k8s_audit_rules.yaml
- /etc/falco/rules.d
json_output: true
json_include_output_property: true
log_stderr: true
log_syslog: true
log_level: info
priority: debug
syscall_event_drops:
actions:
- log
- alert
rate: 0.03333
max_burst: 1000
falcoctl:
artifact:
install:
refs: [falco-rules:0]
follow:
refs: [falco-rules:0]
collector:
enabled: false
falcosidekick:
enabled: true
config:
webhook:
address: "http://alertmanager:9093/api/v1/alerts"
tty: true
EOF
helm install falco falcosecurity/falco \
--namespace falco \
--create-namespace \
--values /tmp/falco-values.yaml \
--wait
rm -f /tmp/falco-values.yaml
}
# Configure Istio security policies
configure_security_policies() {
log_info "[8/10] Configuring Istio security policies..."
cat > /tmp/istio-security-policies.yaml << 'EOF'
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: istio-system
spec:
mtls:
mode: STRICT
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-istio-system
namespace: istio-system
spec:
rules:
- from:
- source:
principals: ["cluster.local/ns/istio-system/sa/istio-proxy"]
EOF
kubectl apply -f /tmp/istio-security-policies.yaml
rm -f /tmp/istio-security-policies.yaml
}
# Wait for deployments
wait_for_deployments() {
log_info "[9/10] Waiting for deployments to be ready..."
kubectl wait --for=condition=available --timeout=300s deployment -l app.kubernetes.io/instance=trivy-operator -n trivy-system
kubectl wait --for=condition=ready --timeout=300s pod -l app.kubernetes.io/name=falco -n falco
kubectl wait --for=condition=available --timeout=300s deployment -n istio-system
}
# Verify installation
verify_installation() {
log_info "[10/10] Verifying installation..."
log_info "Checking Istio status..."
istioctl proxy-status
log_info "Checking Trivy Operator status..."
kubectl get pods -n trivy-system
log_info "Checking Falco status..."
kubectl get pods -n falco
log_info "Checking security policies..."
kubectl get peerauthentication,authorizationpolicy -A
log_info "Installation completed successfully!"
log_warn "Note: Security scanning will begin automatically. Check logs with:"
log_warn " kubectl logs -n trivy-system -l app.kubernetes.io/instance=trivy-operator"
log_warn " kubectl logs -n falco -l app.kubernetes.io/name=falco"
}
# Main execution
main() {
if [[ $# -gt 1 ]]; then
usage
fi
check_prerequisites
detect_os
install_dependencies
install_istioctl
install_istio
deploy_trivy
deploy_falco
configure_security_policies
wait_for_deployments
verify_installation
}
main "$@"
Review the script before running. Execute with: bash install.sh