How to Integrate Authorization Webhook with API Server
Kubernetes clusters have built-in authorization mechanisms like RBAC. These work for many cases, but sometimes you need more control. You want to implement your own custom authorization rules.
This is where authorization webhooks come in. You write your own authorization service, and Kubernetes API Server calls it to make decisions. This gives you full control over who can access what in your cluster.
But after you write the webhook, you need to configure API Server to use it. That’s what this post is about.
I’ll show you how to configure Kubernetes API Server to use your authorization webhook.
What is Authorization Webhook?
An authorization webhook is an HTTP service that API Server calls before making authorization decisions. When a user tries to access a resource, API Server sends a request to the webhook asking: “Can this user do this action?” The webhook returns Allow or Deny.
This gives you full control over authorization logic. You can implement custom rules that RBAC alone cannot handle.
Implementation
We mounted webhook configuration files directly to master nodes.
Step 1: Create Directory and Files on Master Nodes
First, we create the directory on each master node:
1
2
3
4
5
6
7
8
# SSH into master node
ssh master-node-01
# Create directory for webhook files
sudo mkdir -p /etc/kubernetes/webhook
# Verify directory exists
ls -la /etc/kubernetes/webhook
Now we create two files in this directory.
Create webhook-config.yaml
Create the configuration file:
1
2
3
sudo vi /etc/kubernetes/webhook/webhook-config.yaml
# or
sudo nano /etc/kubernetes/webhook/webhook-config.yaml
Then write this content:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apiVersion: v1
kind: Config
clusters:
- cluster:
server: https://kube-authz-webhook.auth-system/authorize
certificate-authority: /etc/kubernetes/webhook/webhook-ca.crt
name: kube-authz-webhook
contexts:
- context:
cluster: kube-authz-webhook
user: webhook-client
name: webhook-context
current-context: webhook-context
users:
- name: webhook-client
user: {}
Save the file.
Place webhook-ca.crt
Copy the CA certificate file to the directory:
1
2
3
4
5
# Copy your CA certificate file to this location
sudo cp /path/to/your/webhook-ca.crt /etc/kubernetes/webhook/webhook-ca.crt
# Verify files are in place
ls -la /etc/kubernetes/webhook/
You should see both files:
1
2
-rw-r--r-- 1 root root webhook-ca.crt
-rw-r--r-- 1 root root webhook-config.yaml
Step 2: Edit API Server Manifest
API Server runs as a static pod. We need to edit its manifest file on each master node.
When you edit files in
/etc/kubernetes/manifests/, kubelet automatically restarts the pod. API Server will restart in few seconds. Make sure you test on non-production cluster first!
Find API Server Manifest
On most Kubernetes clusters, API Server manifests are in /etc/kubernetes/manifests/ directory:
1
2
3
# Check manifest file location
ls -la /etc/kubernetes/manifests/
# You should see: kube-apiserver.yaml
Edit the Manifest File
1
2
3
4
# Open the file in editor
sudo vi /etc/kubernetes/manifests/kube-apiserver.yaml
# or
sudo nano /etc/kubernetes/manifests/kube-apiserver.yaml
Add Volume Mount
Find the volumeMounts section in the manifest. Add our webhook volume:
1
2
3
4
5
volumeMounts:
- name: webhook-volume
mountPath: /etc/kubernetes/webhook
readOnly: true
# ... existing volumeMounts
Add Volume Definition
Find the volumes section. Add our webhook volume:
1
2
3
4
5
6
volumes:
- name: webhook-volume
hostPath:
path: /etc/kubernetes/webhook
type: Directory
# ... existing volumes
Add Authorization Flags
Find the spec.containers[0].command section. Add these flags:
1
2
3
4
5
6
7
8
9
10
spec:
containers:
- name: kube-apiserver
command:
- kube-apiserver
# ... existing flags ...
- --authorization-mode=Node,RBAC,Webhook
- --authorization-webhook-config-file=/etc/kubernetes/webhook/webhook-config.yaml
- --authorization-webhook-cache-authorized-ttl=120s
- --authorization-webhook-cache-unauthorized-ttl=30s
Let me explain these flags:
--authorization-mode=Node,RBAC,Webhook- We use three authorization modes. API Server checks in this order: Node, RBAC, then Webhook. If Node or RBAC makes a decision, webhook is not called.--authorization-webhook-config-file- Path to our webhook configuration file--authorization-webhook-cache-authorized-ttl=120s- Cache allowed decisions for 120 seconds--authorization-webhook-cache-unauthorized-ttl=30s- Cache denied decisions for 30 seconds
Cache TTL values help reduce load on the webhook service. Use shorter TTL for production if you need faster policy updates.
Save the file. Kubelet will automatically restart API Server with new config.
Verify Changes
Wait a few seconds for API Server to restart:
1
2
3
4
5
# Check if API Server pod is running
kubectl get pods -n kube-system | grep apiserver
# Check if volume is mounted
kubectl describe pod kube-apiserver-master-0 -n kube-system | grep webhook
Step 3: Repeat on All Master Nodes
Important: You need to do Steps 1-3 on ALL master nodes in your cluster. API Server runs on each master, and all need the same configuration.
1
2
3
4
5
6
7
8
# List all master nodes
kubectl get nodes -l node-role.kubernetes.io/master
# SSH and apply changes to each master
for master in master-01 master-02 master-03; do
ssh $master
# Repeat the steps above
done
How It Works
When a user makes a request to API Server:
- API Server authenticates the user first
- Then it checks authorization in this order:
- Node authorization
- RBAC authorization
- Webhook authorization (only if Node and RBAC don’t make a decision)
- If webhook is called, it returns Allow or Deny
- API Server caches the result for the TTL duration
- API Server makes final decision
This chain allows you to use webhook for custom logic while keeping standard RBAC for common cases.
Webhook Service
Our webhook service runs as a Kubernetes Deployment. API Server calls it via Service URL.
1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: v1
kind: Service
metadata:
name: kube-authz-webhook
namespace: auth-system
spec:
selector:
app: kube-authz-webhook
ports:
- port: 443
targetPort: 8443
protocol: TCP
Request and Response Format
When API Server calls our webhook, it sends this request:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"kind": "SubjectAccessReview",
"apiVersion": "authorization.k8s.io/v1",
"spec": {
"resourceAttributes": {
"namespace": "default",
"verb": "get",
"group": "",
"resource": "pods"
},
"user": "system:serviceaccount:default:myuser",
"group": ["system:authenticated"]
},
"status": {
"allowed": false
}
}
And our webhook returns:
1
2
3
4
5
6
7
8
{
"apiVersion": "authorization.k8s.io/v1",
"kind": "SubjectAccessReview",
"status": {
"allowed": true,
"reason": "User has permission based on fine-grained rules"
}
}
Testing the Webhook
To test if our webhook works:
1
2
3
4
5
6
7
8
# Test if a user can get pods
kubectl auth can-i get pods --as=system:serviceaccount:default:myuser
# Check webhook logs
kubectl logs -n auth-system deployment/kube-authz-webhook
# Check API Server logs to see webhook calls
kubectl logs -n kube-system kube-apiserver-master-0
You should see logs showing webhook requests and responses.
Troubleshooting
If something goes wrong:
1
2
3
4
5
6
7
8
9
10
11
# Check API Server logs for errors
kubectl logs -n kube-system kube-apiserver-master-0 | grep -i webhook
# Verify manifest file is correct
sudo cat /etc/kubernetes/manifests/kube-apiserver.yaml
# Check if files exist on master node
ls -la /etc/kubernetes/webhook/
# Restore backup if needed
sudo cp /etc/kubernetes/manifests/kube-apiserver.yaml.bak /etc/kubernetes/manifests/kube-apiserver.yaml
Common issue ❯ API Server fails to start if webhook config file has wrong path or missing CA certificate. Always verify files exist before adding flags.