Configure audit policies to trace modifications on critical resources and secure the API Server in a Kubernetes cluster.
Prerequisites
Define your cluster name:
$CLUSTER_NAME="my-cluster"
Q1: How to modify the API Server configuration?
Answer
The API Server in Kubernetes runs as a static pod managed by the kubelet. Static pods are defined by YAML manifests in the /etc/kubernetes/manifests/ directory. When you modify a static pod manifest:
The kubelet automatically detects the file changes
It stops the current pod
It starts a new pod with the updated configuration
This means you don’t need to manually restart the API Server - just modify the manifest file and kubelet handles the rest.
Q2: How to backup the API Server manifest locally?
Answer
Since the API Server runs inside a kind container, use docker cp to backup the manifest to your local machine:
# Find your kind cluster namekind get clusters
# Backup the manifest from container to local machinedocker cp ${CLUSTER_NAME}-control-plane:/etc/kubernetes/manifests/kube-apiserver.yaml ./kube-apiserver.yaml.backup
# To restore later (if needed)docker cp ./kube-apiserver.yaml.backup ${CLUSTER_NAME}-control-plane:/etc/kubernetes/manifests/kube-apiserver.yaml
Q3: How to connect to the kind control plane node?
Answer
Use docker exec to access the kind control plane container:
# List running kind containersdocker ps | grep control-plane
# Connect to the control plane containerdocker exec -it ${CLUSTER_NAME}-control-plane bash
# You're now inside the container and can access:# - /etc/kubernetes/manifests/ (static pod manifests)# - /var/log/kubernetes/ (log files)# - /etc/kubernetes/pki/ (certificates)
Setup Commands
# Find your kind cluster name (if you have multiple clusters)kind get clusters
# Access the kind control plane containerdocker exec -it ${CLUSTER_NAME}-control-plane bash
Configure the Audit Policy
Create a file /etc/kubernetes/audit-policy.yaml that logs:
To verify your audit configuration is working correctly:
# Check if audit policy file existsls -la /etc/kubernetes/audit-policy.yaml
# Verify API server manifest has audit flagsgrep -A3 "audit" /etc/kubernetes/manifests/kube-apiserver.yaml
# Check audit log directory existsls -la /var/log/kubernetes/
# Count audit log entrieswc -l /var/log/kubernetes/audit.log 2>/dev/null || echo "No audit log file found"
Test the Audit Configuration
# Create a test secret to generate audit logskubectl create secret generic test-secret --from-literal=key=value
# Create a test pod to generate audit logs (use --restart=Never to avoid issues)kubectl run test-pod --image=nginx --restart=Never
# Wait a moment for logs to be writtensleep 3
Then access audit logs content on the control-plane.
Solution
# Check if audit log file exists and has contentls -la /var/log/kubernetes/audit.log
# Check for secret-related audit entriesgrep "secrets" /var/log/kubernetes/audit.log | head -2
# Check for pod-related audit entriesgrep "pods" /var/log/kubernetes/audit.log | head -2
# View recent audit logs in JSON format (if jq is available)tail -10 /var/log/kubernetes/audit.log | jq . || tail -10 /var/log/kubernetes/audit.log
# Clean up test resourceskubectl delete secret test-secret --ignore-not-found=true
kubectl delete pod test-pod --ignore-not-found=true
Troubleshooting
API Server Won’t Start After Modification
If the API server fails to start after modifying the manifest, here are comprehensive debugging steps:
Check Kubelet Logs
# From inside the kind control plane containerdocker exec -it ${CLUSTER_NAME}-control-plane journalctl -u kubelet | grep -i kube-apiserver
# Look for specific error patternsdocker exec -it ${CLUSTER_NAME}-control-plane journalctl -u kubelet | grep -E "(error|failed|couldn't parse)"# Follow kubelet logs in real-timedocker exec -it ${CLUSTER_NAME}-control-plane journalctl -u kubelet -f
Check Container Runtime Status
# Check API server container status using crictldocker exec -it ${CLUSTER_NAME}-control-plane crictl ps -a | grep kube-apiserver
# Get detailed container infodocker exec -it ${CLUSTER_NAME}-control-plane crictl inspect <container-id>
# Check container logs directlydocker exec -it ${CLUSTER_NAME}-control-plane crictl logs <container-id>
# List all pods in kube-system namespacedocker exec -it ${CLUSTER_NAME}-control-plane crictl pods | grep kube-system
Common Error Patterns and Solutions
YAML Parsing Errors:
# Check for YAML syntax errorspython3 -c "import yaml; yaml.safe_load(open('/etc/kubernetes/manifests/kube-apiserver.yaml'))"# If YAML is invalid, restore from backupdocker cp ./kube-apiserver.yaml.backup ${CLUSTER_NAME}-control-plane:/etc/kubernetes/manifests/kube-apiserver.yaml