SlideShare a Scribd company logo
Making the most out of kubernetes audit logs
Robert Boll @roboll_
Laurent Bernaille @lbernail
Making the Most Out of
Kubernetes Audit Logs
@lbernail @roboll_
Datadog
Monitoring service
Over 350 integrations
Over 1,200 employees
Over 8,000 customers
Runs on millions of hosts
Trillions of data points per day
10000s hosts in our infra
10s of Kubernetes clusters
Clusters from 50 to 3000 nodes
Multi-cloud
Very fast growth
@lbernail @roboll_
Understanding what happens can be hard
@lbernail @roboll_
Outline
1. Background: The Kubernetes API
2. Audit Logs
3. Configuring Audit Logs
4. 10000 foot view for a large cluster
5. Understanding Kubernetes Internals
6. Troubleshooting examples
@lbernail @roboll_
Outline
1. Background: The Kubernetes API
2. Audit Logs
3. Configuring Audit Logs
4. 10000 foot view for a large cluster
5. Understanding Kubernetes Internals
6. Troubleshooting examples
Background:
The Kubernetes API
@lbernail @roboll_
apiserver
etcd
Calls to the apiservers
@lbernail @roboll_
apiserver
etcd
controllers scheduler
Control plane
@lbernail @roboll_
apiserver
etcd
kubelet controllers scheduler
Kubelet
@lbernail @roboll_
apiserver
etcd
kubelet controllers scheduler
kube-proxy
DaemonSet: kube-proxy
@lbernail @roboll_
apiserver
etcd
kubelet controllers scheduler
kube-proxy
other node
apps
Other DaemonSets (cni, etc.)
@lbernail @roboll_
apiserver
etcd
kubelet controllers scheduler
kube-proxy
coredns
other node
apps
Cluster services: DNS
@lbernail @roboll_
apiserver
etcd
kubelet controllers scheduler
kube-proxy cluster-
autoscaler
ingress
controllers
coredns
other node
apps
Other cluster services
@lbernail @roboll_
apiserver
etcd
kubelet controllers scheduler
kube-proxy cluster-
autoscaler
ingress
controllers
other apps
coredns
other node
apps
Probably several other applications
@lbernail @roboll_
And users, of course
apiserver
etcd
kubelet controllers scheduler
kubectl
kube-proxy cluster-
autoscaler
ingress
controllers
other apps
coredns
other node
apps
@lbernail @roboll_
And, surprise, the apiserver itself
apiserver
etcd
kubelet controllers scheduler
kubectl
kube-proxy cluster-
autoscaler
ingress
controllers
other apps
coredns
other node
apps
@lbernail @roboll_
What happens when you kubectl?
$ kubectl get pod echodeploy-77cf5c6f6-brj76 -v=8
[...]
GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods/echodeploy-77cf5c6f6-brj76
@lbernail @roboll_
Let’s look at details
$ kubectl get pod echodeploy-77cf5c6f6-brj76 -v=8
[...]
GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods/echodeploy-77cf5c6f6-brj76
apiserver api version namespace resource type resource name
@lbernail @roboll_
A few more GET examples
$ kubectl get pod echodeploy-77cf5c6f6-brj76 -v=8
[...]
GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods/echodeploy-77cf5c6f6-brj76
$ kubectl get pods
[...]
GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods?limit=500 List
(paginated)
@lbernail @roboll_
A few more GET examples
$ kubectl get pod echodeploy-77cf5c6f6-brj76 -v=8
[...]
GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods/echodeploy-77cf5c6f6-brj76
$ kubectl get pods
[...]
GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods?limit=500
$ kubectl get pods --watch=true -v=8
[...]
GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods?limit=500
[...]
GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods?resourceVersion=282725545&watch=true
List &
Watch
@lbernail @roboll_
Describe resource
kubectl describe pod echodeploy-77cf5c6f6-5wmw9 -v=8
[...]
GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods/echodeploy-77cf5c6f6-5wmw9
[...]
GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/events?
fieldSelector=involvedObject.name=echodeploy-77cf5c6f6-5wmw9,
involvedObject.namespace=datadog,
involvedObject.uid=770b3a5e-0631-11ea-bc60-12d7306f3c0c
[...]
ResponseBody
{
"kind": "EventList",
"items": [
{
"involvedObject": { "kind": "Pod", "namespace": "datadog", "name": "echodeploy-77cf5c6f6-5wmw9"},
"reason": "Scheduled",
"message": "Successfully assigned echodeploy-77cf5c6f6-5wmw9 to ip-10-128-205-156.ec2.internal",
"source": {
"component": "default-scheduler"
},
}
]
}
@lbernail @roboll_
Describe resource
kubectl describe pod echodeploy-77cf5c6f6-5wmw9 -v=8
[...]
GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods/echodeploy-77cf5c6f6-5wmw9
[...]
GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/events?
fieldSelector=involvedObject.name=echodeploy-77cf5c6f6-5wmw9,
involvedObject.namespace=datadog,
involvedObject.uid=770b3a5e-0631-11ea-bc60-12d7306f3c0c
[...]
ResponseBody
{
"kind": "EventList",
"items": [
{
"involvedObject": { "kind": "Pod", "namespace": "datadog", "name": "echodeploy-77cf5c6f6-5wmw9"},
"reason": "Scheduled",
"message": "Successfully assigned echodeploy-77cf5c6f6-5wmw9 to ip-10-128-205-156.ec2.internal",
"source": {
"component": "default-scheduler"
},
}
]
}
Get resource
@lbernail @roboll_
Describe resource
kubectl describe pod echodeploy-77cf5c6f6-5wmw9 -v=8
[...]
GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods/echodeploy-77cf5c6f6-5wmw9
[...]
GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/events?
fieldSelector=involvedObject.name=echodeploy-77cf5c6f6-5wmw9,
involvedObject.namespace=datadog,
involvedObject.uid=770b3a5e-0631-11ea-bc60-12d7306f3c0c
[...]
ResponseBody
{
"kind": "EventList",
"items": [
{
"involvedObject": { "kind": "Pod", "namespace": "datadog", "name": "echodeploy-77cf5c6f6-5wmw9"},
"reason": "Scheduled",
"message": "Successfully assigned echodeploy-77cf5c6f6-5wmw9 to ip-10-128-205-156.ec2.internal",
"source": {
"component": "default-scheduler"
},
}
]
}
Get resource
Get events associated
with resource
@lbernail @roboll_
A few other examples
$ kubectl delete pod echodeploy-77cf5c6f6-brj76 -v=8
[...]
DELETE https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods/echodeploy-77cf5c6f6-brj76
GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods?fieldSelector=metadata.name%3Dechodeploy-77cf5c6f6-brj76
GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods?fieldSelector=metadata.name%3Dechodeploy-77cf5c6f6-brj76&
resourceVersion=282733788&watch=true
Delete
+
List &
Watch
@lbernail @roboll_
A few other examples
$ kubectl delete pod echodeploy-77cf5c6f6-brj76 -v=8
[...]
DELETE https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods/echodeploy-77cf5c6f6-brj76
GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods?fieldSelector=metadata.name%3Dechodeploy-77cf5c6f6-brj76
GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods?fieldSelector=metadata.name%3Dechodeploy-77cf5c6f6-brj76&
resourceVersion=282733788&watch=true
$ kubectl create deployment test --image=busybox -v=8
Request Body:
{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"creationTimestamp":null,"labels":{"app":"test"},"name":"test"},"spec":{"replicas":1,"s
elector":{"matchLabels":{"app":"test"}},"strategy":{},"template":{"metadata":{"creationTimestamp":null,"labels":{"app":"test"}},"spec":{"container
s":[{"image":"busybox","name":"busybox","resources":{}}]}}},"status":{}}
POST https://kubernetes.fury.us1.staging.dog/apis/apps/v1/namespaces/datadog/deployments
Minimal
deployment
spec
POST call
@lbernail @roboll_
A few other examples
$ kubectl delete pod echodeploy-77cf5c6f6-brj76 -v=8
[...]
DELETE https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods/echodeploy-77cf5c6f6-brj76
GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods?fieldSelector=metadata.name%3Dechodeploy-77cf5c6f6-brj76
GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods?fieldSelector=metadata.name%3Dechodeploy-77cf5c6f6-brj76&
resourceVersion=282733788&watch=true
$ kubectl create deployment test --image=busybox -v=8
Request Body:
{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"creationTimestamp":null,"labels":{"app":"test"},"name":"test"},"spec":{"replicas":1,"s
elector":{"matchLabels":{"app":"test"}},"strategy":{},"template":{"metadata":{"creationTimestamp":null,"labels":{"app":"test"}},"spec":{"container
s":[{"image":"busybox","name":"busybox","resources":{}}]}}},"status":{}}
POST https://kubernetes.fury.us1.staging.dog/apis/apps/v1/namespaces/datadog/deployments
$ kubectl scale deploy test --replicas=2 -v=8
GET https://kubernetes.fury.us1.staging.dog/apis/extensions/v1beta1/namespaces/datadog/deployments/test
Request Body: {"spec":{"replicas":2}}
PATCH https://kubernetes.fury.us1.staging.dog/apis/extensions/v1beta1/namespaces/datadog/deployments/test/scale
GET current
PATCH body
+call
@lbernail @roboll_
Takeaways
â—Ź A lot of components are making calls
â—‹ Control plane: controllers, scheduler
â—‹ Node daemons: kubelet, kube-proxy
â—‹ Other controllers: autoscaler, ingress
● “Simple” user ops translate to many API calls
How can we understand what is going on?
@lbernail @roboll_
Outline
1. Background: The Kubernetes API
2. Audit Logs
3. Configuring Audit Logs
4. 10000 foot view for a large cluster
5. Understanding Kubernetes Internals
6. Troubleshooting examples
Audit Logs
@lbernail @roboll_
What are Audit Logs?
â—Ź Rich Structured json logs output by the apiserver
â—Ź Configurable Verbosity for each resource
â—Ź Logging can happen at different processing stages
apiserverclient
1
3 2: Request processing
1: Apiserver receives request, Stage: RequestReceived
2: Apiserver processes request
3: Apiserver answers, Stage: ResponseComplete/ResponseStarted
@lbernail @roboll_
Content of Audit Logs
â—Ź What happened?
â—Ź Who initiated it?
â—Ź Why was it authorized?
â—Ź When did it happen?
â—Ź From where?
â—Ź Depending on verbosity, Request/Response
@lbernail @roboll_
GET example from earlier
Structured JSON log
A lot of information
$ kubectl get pod echodeploy-77cf5c6f6-5wmw9 -v=8
GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods/echodeploy-77cf5c6f6-5wamw9
@lbernail @roboll_
What happened?
$ kubectl get pod echodeploy-77cf5c6f6-5wmw9 -v=8
GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods/echodeploy-77cf5c6f6-5wmw9
@lbernail @roboll_
Who initiated it?
User was laurent.bernaille@datadoghq.com and mapped to groups
- datadoghq.com
- system:authenticated
$ kubectl get pod echodeploy-77cf5c6f6-5wmw9 -v=8
GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods/echodeploy-77cf5c6f6-5wamw9
@lbernail @roboll_
Why was it authorized?
It was authorized because group datadoghq.com is bound to role
datadoghq:cluster-user by ClusterRoleBinding datadoghq:cluster-admin-binding
(and this role has the required permissions)
$ kubectl get pod echodeploy-77cf5c6f6-5wmw9 -v=8
GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods/echodeploy-77cf5c6f6-5wamw9
@lbernail @roboll_
When, and from where?
Request received at 20:33:26.757
Response completed at 20:33:26:771
Duration: 14ms
From IP: 10.X.Y.74
$ kubectl get pod echodeploy-77cf5c6f6-5wmw9 -v=8
GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods/echodeploy-77cf5c6f6-5wamw9
@lbernail @roboll_
Another GET call
$ kubectl get pods -v=8
GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods?limit=500
GET is mapped to different verbs (get/list)
@lbernail @roboll_
Watches
$ kubectl get pods -v=8 -w
GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods?limit=500
GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods?resourceVersion=288656279&watch=true
Call 1 : list
stage: ResponseComplete
Call 2 : watch
get + watch parameters
136ms later
stage: ResponseStarted
@lbernail @roboll_
Create call
$ kubectl create deployment test --image=busybox -v=8
POST https://kubernetes.fury.us1.staging.dog/apis/apps/v1/namespaces/datadog/deployments
@lbernail @roboll_
Create call
$ kubectl create deployment test --image=busybox -v=8
POST https://kubernetes.fury.us1.staging.dog/apis/apps/v1/namespaces/datadog/deployments
@lbernail @roboll_
Takeaways
Audit logs contain information on all API calls
â—Ź What happened?
â—Ź Who initiated it?
â—Ź Why was it authorized?
â—Ź When did it happen?
â—Ź From where?
â—Ź Depending on verbosity, Request/Response
OK, how do I get them?
@lbernail @roboll_
Outline
1. Background: The Kubernetes API
2. Audit Logs
3. Configuring Audit Logs
4. 10000 foot view for a large cluster
5. Understanding Kubernetes Internals
6. Troubleshooting examples
Configuring Audit Logs
@lbernail @roboll_
Apiserver configuration
kube-apiserver
[...]
--audit-log-path=/var/log/kubernetes/apiserver/audit.log
--audit-policy-file=/etc/kubernetes/audit-policies/policy.yaml
[...]
Where to store them
What to collect
Minimum configuration
Advanced
â—Ź Rotation parameters (max size, backup options)
â—Ź Alternative backend (webhook)
â—Ź Batching mode
@lbernail @roboll_
apiVersion: audit.k8s.io/v1 kind: Policy
rules:
# Log pod changes at RequestResponse level
- level: RequestResponse
omitStages:
- "RequestReceived"
resources:
- group: "" # core API group
resources: ["pods"]
verbs: ["create", "patch"”, "update", "delete"]
# Log "pods/log", "pods/status" at Metadata level
- level: Metadata
omitStages:
- "RequestReceived"
resources:
- group: ""
resources: ["pods/log", "pods/status"]
Set of rules
Audit policy: what to log?
@lbernail @roboll_
apiVersion: audit.k8s.io/v1 kind: Policy
rules:
# Log pod changes at RequestResponse level
- level: RequestResponse
omitStages:
- "RequestReceived"
resources:
- group: "" # core API group
resources: ["pods"]
verbs: ["create", "patch"”, "update", "delete"]
# Log "pods/log", "pods/status" at Metadata level
- level: Metadata
omitStages:
- "RequestReceived"
resources:
- group: ""
resources: ["pods/log", "pods/status"]
Rules match api call
â—Ź api group / version
â—Ź resource
â—Ź verbs
> Similar to RBAC
Audit policy: what to log?
@lbernail @roboll_
apiVersion: audit.k8s.io/v1 kind: Policy
rules:
# Log pod changes at RequestResponse level
- level: RequestResponse
omitStages:
- "RequestReceived"
resources:
- group: "" # core API group
resources: ["pods"]
verbs: ["create", "patch"”, "update", "delete"]
# Log "pods/log", "pods/status" at Metadata level
- level: Metadata
omitStages:
- "RequestReceived"
resources:
- group: ""
resources: ["pods/log", "pods/status"]
For matching API calls
â—Ź Which verbosity?
â—Ź When? (stage)
Audit policy: when to log?
@lbernail @roboll_
apiVersion: audit.k8s.io/v1 kind: Policy
rules:
# Log pod changes at RequestResponse level
- level: RequestResponse
omitStages:
- "RequestReceived"
resources:
- group: "" # core API group
resources: ["pods"]
verbs: ["create", "patch"”, "update", "delete"]
# Log "pods/log", "pods/status" at Metadata level
- level: Metadata
omitStages:
- "RequestReceived"
resources:
- group: ""
resources: ["pods/log", "pods/status"]
Gotchas
Rules are evaluated in order
First matching rule sets level
Request/RequestResponse
> contain payload data
Careful with security implications
ex: tokenreviews calls
group: “” means core API only
Don’t forget to add
â—Ź 3rd party apiservices
â—Ź your apiservices
@lbernail @roboll_
Recommendations
â—Ź Ignore RequestReceived stage
â—Ź Use at least Metadata level for almost everything
â—‹ Possibly ignore healthz, metrics
â—Ź Use Request/Response level for critical resource/verbs
â—‹ Very valuable for retroactive debugging
â—‹ Careful for large/sensitive request/response bodies
â—Ź Very complete example in GKE
https://github.com/kubernetes/kubernetes/blob/master/cluster/gce/gci/configure-helper.sh
â—Ź Documentation
https://kubernetes.io/docs/tasks/debug-application-cluster/audit/#audit-policy
@lbernail @roboll_
Takeaways
● Getting audit logs is “simple”: 2 flags
â—Ź Getting policies right is harder
â—Ź You will get a lot of logs
â—Ź Requires a solution to analyze them
Let’s look at an overview on a real large cluster
@lbernail @roboll_
Outline
1. Background: The Kubernetes API
2. Audit Logs
3. Configuring Audit Logs
4. 10000 foot view for a large cluster
5. Understanding Kubernetes Internals
6. Troubleshooting examples
10000 foot view for a
large cluster
@lbernail @roboll_
Total number of API calls
~900 calls/second on this 2500 nodes cluster
Number of audit logs per hour
@lbernail @roboll_
Top API users?
apiserver: 40 rps kube-proxy: 20 rps
local-volume-provisioner:20 rps
cronjob-controller: 15 rps
spinnaker: 5-10 rps
@lbernail @roboll_
Top list, missing “small” users
total: ~900rps
Top 25: 150 rps
900 calls/second on this 2500 nodes cluster
What is doing ~80% of API calls?
Total number of API calls
@lbernail @roboll_
Grouping by users is not helping
Calls from users in group “system:nodes”: 750 rps (~80% of API calls)
In this 2500-nodes cluster, this means 0.3 rps per node!
Calls by user group
group=system:nodes
@lbernail @roboll_
Why is “system:nodes” so high?
nodes: 500 rps configmaps: 75 rps secrets: 60 rps
Calls from group “system:nodes” by resource targeted
@lbernail @roboll_
Verbs on “node” for a kubelet
10s
Each node update its status every 10s
@lbernail @roboll_
Verbs on “configmaps”
Only GETs
Regularity but not clear pattern
@lbernail @roboll_
Group by resource name
Each configmap is refreshed every ~5mn => GET call
Similar for secrets
~5mn
@lbernail @roboll_
List latency by resource
Latency for list by resource
@lbernail @roboll_
List latency by resource
Latency for list by resource
apiserver restarts
@lbernail @roboll_
Compare cluster performances
Latency for get pod by cluster (ms)
large clusters (1500+ nodes)
smaller clusters (<700 nodes)
@lbernail @roboll_
Takeaways
â—Ź Biggest users are the ones running on each node
â—‹ kubelet, daemonsets (kube-proxy)
â—‹ A lot of effort upstream to reduce their load
â—‹ Be extra careful of damonsets doing API calls
â—Ź Audit logs structure allow to filter and slice & dice
â—Ź Audit logs are verbose (1000 logs/s in our example)
@lbernail @roboll_
Outline
1. Background: The Kubernetes API
2. Audit Logs
3. Configuring Audit Logs
4. 10000 foot view for a large cluster
5. Understanding Kubernetes Internals
6. Troubleshooting examples
Understanding
Kubernetes Internals
@lbernail @roboll_
Creating a simple deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
@lbernail @roboll_
Sequence
User creates
deploy
deployment controller
creates RS
RS controller
creates pods
Scheduler
bind pods
Kubelets
Update
pod status
@lbernail @roboll_
Sequence
Scheduler
bind pods
Scheduler callCreate
Binding
For nginx pod
To node
ip-10-x-y-123
@lbernail @roboll_
Actually a lot more
node 1 node 2 RS controller Deploy ctrl Scheduler apiserver user
Create of Deployment, RS, pods, binding + nodes accept
Nodes create pods and generate events
Pods are running
Deployments/RS update status
Additions
Apiserver verifies Quotas
Components also get/list
Creation of events + Update of status fields
Complete node workflow
~ 3s
@lbernail @roboll_
Node API calls
Initial calls
Get pod
Update pod/status: ContainerCreating
Get service account token
@lbernail @roboll_
Node API calls
Create events to show progression
MountVolume.SetUp succeeded for volume "default-token-dqmzw"
pulling image "nginx"
Successfully pulled image "nginx"
Created container
Started container
@lbernail @roboll_
Node API calls
Finalize pod creation
Get pod
Update container status to “Running”
@lbernail @roboll_
Takeaways
â—Ź A lot of interactions between kube components
â—Ź Audit logs give a great understanding of this!
â—Ź Events are spiky and get generate a lot of logs
â—Ź Events have a 1h default TTL, but stay in audit logs
Let’s identify some problems using audit logs
@lbernail @roboll_
Outline
1. Background: The Kubernetes API
2. Audit Logs
3. Configuring Audit Logs
4. 10000 foot view for a large cluster
5. Understanding Kubernetes Internals
6. Troubleshooting examples
Troubleshooting
examples
@lbernail @roboll_
Troubleshooting
â—Ź Understand what happened
○ “Why was a resource deleted?”
â—Ź Debug performance regressions/improve performances
○ “Which application is responsible for so many calls?”
â—Ź Also, identify issues by looking at HTTP status codes
@lbernail @roboll_
Status codes
Calls by status code
200 201 401
@lbernail @roboll_
4xx only
4xx by status code
401 403 404 422 409
@lbernail @roboll_
4xx only
4xx by status code
401?? (Unauthorized)
@lbernail @roboll_
Analyzing 401s
401s by source IP
4 nodes only, turns out they had expired certificates
@lbernail @roboll_
4xx only
4xx by status code
403?? (Forbidden)
@lbernail @roboll_
Analyzing 403s
403s by user
Most errors from Traefik serviceAccount
Bad RBAC configuration?
@lbernail @roboll_
Analyzing 403s for this user
403s for Traefik serviceAccount by resource
We use Traefik without Kubernetes secrets but it still tries to list them
@lbernail @roboll_
4xx only
4xx by status code
422?? (Invalid)
@lbernail @roboll_
What about 422?
422 by user
kube-system:generic-garbage-collector => ??
@lbernail @roboll_
What is failing?
generic-garbage-collector by verb / resource
patch on pod
@lbernail @roboll_
What is happening?
● Pods are in “Evicted” status and must be kept
â—Ź Controlling RS has been deleted and pods should be orphaned
â—Ź Garbage collector fails to orphan them (remove ownerRef)
â—Ź ReplicaSet has been Terminating for 2 months...
â—Ź Root cause: mutating webhook
â—‹ We modify the pod spec at creation
â—‹ Mutating webhook is registered on pods for CREATE/UPDATE
â—‹ We modify immutable fields
â—‹ Garbage collector patch triggers this...
@lbernail @roboll_
Takeaways
â—Ź Looking at calls triggering HTTP errors help find issues
â—‹ Misconfigured RBAC (403)
○ Applications doing calls they shouldn’t (403)
â—‹ Expired certificates (401)
â—‹ Other weird things
Conclusion
@lbernail @roboll_
Conclusion
â—Ź Audit logs can be incredibly valuable
â—‹ Low-level understanding of Kubernetes
â—‹ Detection of misconfigurations
â—‹ Troubleshooting of issues
â—‹ Identify performance issues
â—Ź Taking advantage of them require some effort
â—‹ Policies are not easy to get right
â—‹ They are verbose and require a tool to analyze them
Thank you
We’re hiring!
Visit our Kubecon booth
or https://www.datadoghq.com/careers/
Or contact us directly:
@lbernail laurent@datadoghq.com
@roboll_ roboll@datadoghq.com

More Related Content

PPTX
Secret Management with Hashicorp Vault and Consul on Kubernetes
PPTX
Observability
PDF
Coffee Break NeuVector
 
PDF
DevSecOps: Key Controls for Modern Security Success
PDF
The Sysdig Secure DevOps Platform
PDF
Rancher 2.0 Technical Deep Dive
PPTX
DEVSECOPS.pptx
PDF
Secret Management with Hashicorp’s Vault
Secret Management with Hashicorp Vault and Consul on Kubernetes
Observability
Coffee Break NeuVector
 
DevSecOps: Key Controls for Modern Security Success
The Sysdig Secure DevOps Platform
Rancher 2.0 Technical Deep Dive
DEVSECOPS.pptx
Secret Management with Hashicorp’s Vault

What's hot (20)

PPTX
DevOps Monitoring and Alerting
PDF
Introduction to DevSecOps
PPTX
Nagios intro
PDF
Kubernetes security
PDF
Improve monitoring and observability for kubernetes with oss tools
PDF
Strengthen and Scale Security Using DevSecOps - OWASP Indonesia
PPSX
Service Mesh - Observability
PDF
Open Policy Agent
PPTX
Kubernetes and container security
PDF
Scaling containers with KEDA
PPTX
Rtf v2 ingress muleSoft meetup self managed kubernetes
PDF
Opa gatekeeper
PDF
Practical DevSecOps Course - Part 1
PPTX
Azure Container Apps
PPTX
Understanding container security
PDF
Power Platform ALM with DevOps
PDF
[DevSecOps Live] DevSecOps: Challenges and Opportunities
PDF
Istio service mesh introduction
PDF
Container Security Essentials
 
PDF
OpenShift 4, the smarter Kubernetes platform
DevOps Monitoring and Alerting
Introduction to DevSecOps
Nagios intro
Kubernetes security
Improve monitoring and observability for kubernetes with oss tools
Strengthen and Scale Security Using DevSecOps - OWASP Indonesia
Service Mesh - Observability
Open Policy Agent
Kubernetes and container security
Scaling containers with KEDA
Rtf v2 ingress muleSoft meetup self managed kubernetes
Opa gatekeeper
Practical DevSecOps Course - Part 1
Azure Container Apps
Understanding container security
Power Platform ALM with DevOps
[DevSecOps Live] DevSecOps: Challenges and Opportunities
Istio service mesh introduction
Container Security Essentials
 
OpenShift 4, the smarter Kubernetes platform
Ad

Similar to Making the most out of kubernetes audit logs (20)

PPTX
Building Your Own IoT Platform using FIWARE GEis
 
PPT
FIWARE IoT Proposal & Community
 
PPTX
[Rakuten TechConf2014] [C-5] Ichiba Architecture on ExaLogic
PPTX
New and smart way to develop microservice for istio with micro profile
PDF
Advanced #2 networking
PDF
apidays Paris 2022 - France Televisions : How we leverage API Platform for ou...
PDF
PuppetDB: A Single Source for Storing Your Puppet Data - PUG NY
 
PDF
Mashing Up The Guardian
PDF
Kubernetes - Sailing a Sea of Containers
PDF
CI Provisioning with OpenStack - Gidi Samuels - OpenStack Day Israel 2016
PDF
FrenchKit 2017: Server(less) Swift
PDF
OpenStack API's and WSGI
PDF
NSA for Enterprises Log Analysis Use Cases
 
PDF
Mashing Up The Guardian
PDF
JDD2015: Kubernetes - Beyond the basics - Paul Bakker
PDF
What's Rio 〜Standalone〜
PPTX
MicroProfile, Docker, Kubernetes, Istio and Open Shift lab @dev nexus
PPTX
What is serveless?
PPTX
OSDN: Serverless technologies with Kubernetes
PDF
Performance Tuning Your Puppet Infrastructure - PuppetConf 2014
 
Building Your Own IoT Platform using FIWARE GEis
 
FIWARE IoT Proposal & Community
 
[Rakuten TechConf2014] [C-5] Ichiba Architecture on ExaLogic
New and smart way to develop microservice for istio with micro profile
Advanced #2 networking
apidays Paris 2022 - France Televisions : How we leverage API Platform for ou...
PuppetDB: A Single Source for Storing Your Puppet Data - PUG NY
 
Mashing Up The Guardian
Kubernetes - Sailing a Sea of Containers
CI Provisioning with OpenStack - Gidi Samuels - OpenStack Day Israel 2016
FrenchKit 2017: Server(less) Swift
OpenStack API's and WSGI
NSA for Enterprises Log Analysis Use Cases
 
Mashing Up The Guardian
JDD2015: Kubernetes - Beyond the basics - Paul Bakker
What's Rio 〜Standalone〜
MicroProfile, Docker, Kubernetes, Istio and Open Shift lab @dev nexus
What is serveless?
OSDN: Serverless technologies with Kubernetes
Performance Tuning Your Puppet Infrastructure - PuppetConf 2014
 
Ad

More from Laurent Bernaille (17)

PDF
How the OOM Killer Deleted My Namespace
PDF
Kubernetes DNS Horror Stories
PDF
Evolution of kube-proxy (Brussels, Fosdem 2020)
PDF
Kubernetes the Very Hard Way. Velocity Berlin 2019
PDF
Kubernetes the Very Hard Way. Lisa Portland 2019
PDF
10 ways to shoot yourself in the foot with kubernetes, #9 will surprise you! ...
PDF
10 ways to shoot yourself in the foot with kubernetes, #9 will surprise you!
PDF
Optimizing kubernetes networking
PDF
Kubernetes at Datadog the very hard way
PPTX
Deep Dive in Docker Overlay Networks
PPTX
Deeper dive in Docker Overlay Networks
PPTX
Discovering OpenBSD on AWS
PPTX
Operational challenges behind Serverless architectures
PPTX
Deep dive in Docker Overlay Networks
PDF
Feedback on AWS re:invent 2016
PDF
Early recognition of encryted applications
PDF
Early application identification. CONEXT 2006
How the OOM Killer Deleted My Namespace
Kubernetes DNS Horror Stories
Evolution of kube-proxy (Brussels, Fosdem 2020)
Kubernetes the Very Hard Way. Velocity Berlin 2019
Kubernetes the Very Hard Way. Lisa Portland 2019
10 ways to shoot yourself in the foot with kubernetes, #9 will surprise you! ...
10 ways to shoot yourself in the foot with kubernetes, #9 will surprise you!
Optimizing kubernetes networking
Kubernetes at Datadog the very hard way
Deep Dive in Docker Overlay Networks
Deeper dive in Docker Overlay Networks
Discovering OpenBSD on AWS
Operational challenges behind Serverless architectures
Deep dive in Docker Overlay Networks
Feedback on AWS re:invent 2016
Early recognition of encryted applications
Early application identification. CONEXT 2006

Recently uploaded (20)

PDF
Encapsulation theory and applications.pdf
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PDF
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
PDF
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
 
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PPTX
Spectroscopy.pptx food analysis technology
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PDF
cuic standard and advanced reporting.pdf
PDF
MIND Revenue Release Quarter 2 2025 Press Release
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
PDF
KodekX | Application Modernization Development
 
PPTX
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PPTX
sap open course for s4hana steps from ECC to s4
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PDF
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
PPT
Teaching material agriculture food technology
PPTX
Programs and apps: productivity, graphics, security and other tools
PDF
Spectral efficient network and resource selection model in 5G networks
Encapsulation theory and applications.pdf
Building Integrated photovoltaic BIPV_UPV.pdf
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
 
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
Spectroscopy.pptx food analysis technology
Per capita expenditure prediction using model stacking based on satellite ima...
20250228 LYD VKU AI Blended-Learning.pptx
cuic standard and advanced reporting.pdf
MIND Revenue Release Quarter 2 2025 Press Release
Dropbox Q2 2025 Financial Results & Investor Presentation
KodekX | Application Modernization Development
 
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
sap open course for s4hana steps from ECC to s4
Digital-Transformation-Roadmap-for-Companies.pptx
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
Teaching material agriculture food technology
Programs and apps: productivity, graphics, security and other tools
Spectral efficient network and resource selection model in 5G networks

Making the most out of kubernetes audit logs

  • 2. Robert Boll @roboll_ Laurent Bernaille @lbernail Making the Most Out of Kubernetes Audit Logs
  • 3. @lbernail @roboll_ Datadog Monitoring service Over 350 integrations Over 1,200 employees Over 8,000 customers Runs on millions of hosts Trillions of data points per day 10000s hosts in our infra 10s of Kubernetes clusters Clusters from 50 to 3000 nodes Multi-cloud Very fast growth
  • 5. @lbernail @roboll_ Outline 1. Background: The Kubernetes API 2. Audit Logs 3. Configuring Audit Logs 4. 10000 foot view for a large cluster 5. Understanding Kubernetes Internals 6. Troubleshooting examples
  • 6. @lbernail @roboll_ Outline 1. Background: The Kubernetes API 2. Audit Logs 3. Configuring Audit Logs 4. 10000 foot view for a large cluster 5. Understanding Kubernetes Internals 6. Troubleshooting examples
  • 11. @lbernail @roboll_ apiserver etcd kubelet controllers scheduler kube-proxy DaemonSet: kube-proxy
  • 12. @lbernail @roboll_ apiserver etcd kubelet controllers scheduler kube-proxy other node apps Other DaemonSets (cni, etc.)
  • 13. @lbernail @roboll_ apiserver etcd kubelet controllers scheduler kube-proxy coredns other node apps Cluster services: DNS
  • 14. @lbernail @roboll_ apiserver etcd kubelet controllers scheduler kube-proxy cluster- autoscaler ingress controllers coredns other node apps Other cluster services
  • 15. @lbernail @roboll_ apiserver etcd kubelet controllers scheduler kube-proxy cluster- autoscaler ingress controllers other apps coredns other node apps Probably several other applications
  • 16. @lbernail @roboll_ And users, of course apiserver etcd kubelet controllers scheduler kubectl kube-proxy cluster- autoscaler ingress controllers other apps coredns other node apps
  • 17. @lbernail @roboll_ And, surprise, the apiserver itself apiserver etcd kubelet controllers scheduler kubectl kube-proxy cluster- autoscaler ingress controllers other apps coredns other node apps
  • 18. @lbernail @roboll_ What happens when you kubectl? $ kubectl get pod echodeploy-77cf5c6f6-brj76 -v=8 [...] GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods/echodeploy-77cf5c6f6-brj76
  • 19. @lbernail @roboll_ Let’s look at details $ kubectl get pod echodeploy-77cf5c6f6-brj76 -v=8 [...] GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods/echodeploy-77cf5c6f6-brj76 apiserver api version namespace resource type resource name
  • 20. @lbernail @roboll_ A few more GET examples $ kubectl get pod echodeploy-77cf5c6f6-brj76 -v=8 [...] GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods/echodeploy-77cf5c6f6-brj76 $ kubectl get pods [...] GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods?limit=500 List (paginated)
  • 21. @lbernail @roboll_ A few more GET examples $ kubectl get pod echodeploy-77cf5c6f6-brj76 -v=8 [...] GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods/echodeploy-77cf5c6f6-brj76 $ kubectl get pods [...] GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods?limit=500 $ kubectl get pods --watch=true -v=8 [...] GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods?limit=500 [...] GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods?resourceVersion=282725545&watch=true List & Watch
  • 22. @lbernail @roboll_ Describe resource kubectl describe pod echodeploy-77cf5c6f6-5wmw9 -v=8 [...] GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods/echodeploy-77cf5c6f6-5wmw9 [...] GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/events? fieldSelector=involvedObject.name=echodeploy-77cf5c6f6-5wmw9, involvedObject.namespace=datadog, involvedObject.uid=770b3a5e-0631-11ea-bc60-12d7306f3c0c [...] ResponseBody { "kind": "EventList", "items": [ { "involvedObject": { "kind": "Pod", "namespace": "datadog", "name": "echodeploy-77cf5c6f6-5wmw9"}, "reason": "Scheduled", "message": "Successfully assigned echodeploy-77cf5c6f6-5wmw9 to ip-10-128-205-156.ec2.internal", "source": { "component": "default-scheduler" }, } ] }
  • 23. @lbernail @roboll_ Describe resource kubectl describe pod echodeploy-77cf5c6f6-5wmw9 -v=8 [...] GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods/echodeploy-77cf5c6f6-5wmw9 [...] GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/events? fieldSelector=involvedObject.name=echodeploy-77cf5c6f6-5wmw9, involvedObject.namespace=datadog, involvedObject.uid=770b3a5e-0631-11ea-bc60-12d7306f3c0c [...] ResponseBody { "kind": "EventList", "items": [ { "involvedObject": { "kind": "Pod", "namespace": "datadog", "name": "echodeploy-77cf5c6f6-5wmw9"}, "reason": "Scheduled", "message": "Successfully assigned echodeploy-77cf5c6f6-5wmw9 to ip-10-128-205-156.ec2.internal", "source": { "component": "default-scheduler" }, } ] } Get resource
  • 24. @lbernail @roboll_ Describe resource kubectl describe pod echodeploy-77cf5c6f6-5wmw9 -v=8 [...] GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods/echodeploy-77cf5c6f6-5wmw9 [...] GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/events? fieldSelector=involvedObject.name=echodeploy-77cf5c6f6-5wmw9, involvedObject.namespace=datadog, involvedObject.uid=770b3a5e-0631-11ea-bc60-12d7306f3c0c [...] ResponseBody { "kind": "EventList", "items": [ { "involvedObject": { "kind": "Pod", "namespace": "datadog", "name": "echodeploy-77cf5c6f6-5wmw9"}, "reason": "Scheduled", "message": "Successfully assigned echodeploy-77cf5c6f6-5wmw9 to ip-10-128-205-156.ec2.internal", "source": { "component": "default-scheduler" }, } ] } Get resource Get events associated with resource
  • 25. @lbernail @roboll_ A few other examples $ kubectl delete pod echodeploy-77cf5c6f6-brj76 -v=8 [...] DELETE https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods/echodeploy-77cf5c6f6-brj76 GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods?fieldSelector=metadata.name%3Dechodeploy-77cf5c6f6-brj76 GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods?fieldSelector=metadata.name%3Dechodeploy-77cf5c6f6-brj76& resourceVersion=282733788&watch=true Delete + List & Watch
  • 26. @lbernail @roboll_ A few other examples $ kubectl delete pod echodeploy-77cf5c6f6-brj76 -v=8 [...] DELETE https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods/echodeploy-77cf5c6f6-brj76 GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods?fieldSelector=metadata.name%3Dechodeploy-77cf5c6f6-brj76 GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods?fieldSelector=metadata.name%3Dechodeploy-77cf5c6f6-brj76& resourceVersion=282733788&watch=true $ kubectl create deployment test --image=busybox -v=8 Request Body: {"apiVersion":"apps/v1","kind":"Deployment","metadata":{"creationTimestamp":null,"labels":{"app":"test"},"name":"test"},"spec":{"replicas":1,"s elector":{"matchLabels":{"app":"test"}},"strategy":{},"template":{"metadata":{"creationTimestamp":null,"labels":{"app":"test"}},"spec":{"container s":[{"image":"busybox","name":"busybox","resources":{}}]}}},"status":{}} POST https://kubernetes.fury.us1.staging.dog/apis/apps/v1/namespaces/datadog/deployments Minimal deployment spec POST call
  • 27. @lbernail @roboll_ A few other examples $ kubectl delete pod echodeploy-77cf5c6f6-brj76 -v=8 [...] DELETE https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods/echodeploy-77cf5c6f6-brj76 GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods?fieldSelector=metadata.name%3Dechodeploy-77cf5c6f6-brj76 GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods?fieldSelector=metadata.name%3Dechodeploy-77cf5c6f6-brj76& resourceVersion=282733788&watch=true $ kubectl create deployment test --image=busybox -v=8 Request Body: {"apiVersion":"apps/v1","kind":"Deployment","metadata":{"creationTimestamp":null,"labels":{"app":"test"},"name":"test"},"spec":{"replicas":1,"s elector":{"matchLabels":{"app":"test"}},"strategy":{},"template":{"metadata":{"creationTimestamp":null,"labels":{"app":"test"}},"spec":{"container s":[{"image":"busybox","name":"busybox","resources":{}}]}}},"status":{}} POST https://kubernetes.fury.us1.staging.dog/apis/apps/v1/namespaces/datadog/deployments $ kubectl scale deploy test --replicas=2 -v=8 GET https://kubernetes.fury.us1.staging.dog/apis/extensions/v1beta1/namespaces/datadog/deployments/test Request Body: {"spec":{"replicas":2}} PATCH https://kubernetes.fury.us1.staging.dog/apis/extensions/v1beta1/namespaces/datadog/deployments/test/scale GET current PATCH body +call
  • 28. @lbernail @roboll_ Takeaways â—Ź A lot of components are making calls â—‹ Control plane: controllers, scheduler â—‹ Node daemons: kubelet, kube-proxy â—‹ Other controllers: autoscaler, ingress â—Ź “Simple” user ops translate to many API calls How can we understand what is going on?
  • 29. @lbernail @roboll_ Outline 1. Background: The Kubernetes API 2. Audit Logs 3. Configuring Audit Logs 4. 10000 foot view for a large cluster 5. Understanding Kubernetes Internals 6. Troubleshooting examples
  • 31. @lbernail @roboll_ What are Audit Logs? â—Ź Rich Structured json logs output by the apiserver â—Ź Configurable Verbosity for each resource â—Ź Logging can happen at different processing stages apiserverclient 1 3 2: Request processing 1: Apiserver receives request, Stage: RequestReceived 2: Apiserver processes request 3: Apiserver answers, Stage: ResponseComplete/ResponseStarted
  • 32. @lbernail @roboll_ Content of Audit Logs â—Ź What happened? â—Ź Who initiated it? â—Ź Why was it authorized? â—Ź When did it happen? â—Ź From where? â—Ź Depending on verbosity, Request/Response
  • 33. @lbernail @roboll_ GET example from earlier Structured JSON log A lot of information $ kubectl get pod echodeploy-77cf5c6f6-5wmw9 -v=8 GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods/echodeploy-77cf5c6f6-5wamw9
  • 34. @lbernail @roboll_ What happened? $ kubectl get pod echodeploy-77cf5c6f6-5wmw9 -v=8 GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods/echodeploy-77cf5c6f6-5wmw9
  • 35. @lbernail @roboll_ Who initiated it? User was laurent.bernaille@datadoghq.com and mapped to groups - datadoghq.com - system:authenticated $ kubectl get pod echodeploy-77cf5c6f6-5wmw9 -v=8 GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods/echodeploy-77cf5c6f6-5wamw9
  • 36. @lbernail @roboll_ Why was it authorized? It was authorized because group datadoghq.com is bound to role datadoghq:cluster-user by ClusterRoleBinding datadoghq:cluster-admin-binding (and this role has the required permissions) $ kubectl get pod echodeploy-77cf5c6f6-5wmw9 -v=8 GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods/echodeploy-77cf5c6f6-5wamw9
  • 37. @lbernail @roboll_ When, and from where? Request received at 20:33:26.757 Response completed at 20:33:26:771 Duration: 14ms From IP: 10.X.Y.74 $ kubectl get pod echodeploy-77cf5c6f6-5wmw9 -v=8 GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods/echodeploy-77cf5c6f6-5wamw9
  • 38. @lbernail @roboll_ Another GET call $ kubectl get pods -v=8 GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods?limit=500 GET is mapped to different verbs (get/list)
  • 39. @lbernail @roboll_ Watches $ kubectl get pods -v=8 -w GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods?limit=500 GET https://kubernetes.fury.us1.staging.dog/api/v1/namespaces/datadog/pods?resourceVersion=288656279&watch=true Call 1 : list stage: ResponseComplete Call 2 : watch get + watch parameters 136ms later stage: ResponseStarted
  • 40. @lbernail @roboll_ Create call $ kubectl create deployment test --image=busybox -v=8 POST https://kubernetes.fury.us1.staging.dog/apis/apps/v1/namespaces/datadog/deployments
  • 41. @lbernail @roboll_ Create call $ kubectl create deployment test --image=busybox -v=8 POST https://kubernetes.fury.us1.staging.dog/apis/apps/v1/namespaces/datadog/deployments
  • 42. @lbernail @roboll_ Takeaways Audit logs contain information on all API calls â—Ź What happened? â—Ź Who initiated it? â—Ź Why was it authorized? â—Ź When did it happen? â—Ź From where? â—Ź Depending on verbosity, Request/Response OK, how do I get them?
  • 43. @lbernail @roboll_ Outline 1. Background: The Kubernetes API 2. Audit Logs 3. Configuring Audit Logs 4. 10000 foot view for a large cluster 5. Understanding Kubernetes Internals 6. Troubleshooting examples
  • 45. @lbernail @roboll_ Apiserver configuration kube-apiserver [...] --audit-log-path=/var/log/kubernetes/apiserver/audit.log --audit-policy-file=/etc/kubernetes/audit-policies/policy.yaml [...] Where to store them What to collect Minimum configuration Advanced â—Ź Rotation parameters (max size, backup options) â—Ź Alternative backend (webhook) â—Ź Batching mode
  • 46. @lbernail @roboll_ apiVersion: audit.k8s.io/v1 kind: Policy rules: # Log pod changes at RequestResponse level - level: RequestResponse omitStages: - "RequestReceived" resources: - group: "" # core API group resources: ["pods"] verbs: ["create", "patch"”, "update", "delete"] # Log "pods/log", "pods/status" at Metadata level - level: Metadata omitStages: - "RequestReceived" resources: - group: "" resources: ["pods/log", "pods/status"] Set of rules Audit policy: what to log?
  • 47. @lbernail @roboll_ apiVersion: audit.k8s.io/v1 kind: Policy rules: # Log pod changes at RequestResponse level - level: RequestResponse omitStages: - "RequestReceived" resources: - group: "" # core API group resources: ["pods"] verbs: ["create", "patch"”, "update", "delete"] # Log "pods/log", "pods/status" at Metadata level - level: Metadata omitStages: - "RequestReceived" resources: - group: "" resources: ["pods/log", "pods/status"] Rules match api call â—Ź api group / version â—Ź resource â—Ź verbs > Similar to RBAC Audit policy: what to log?
  • 48. @lbernail @roboll_ apiVersion: audit.k8s.io/v1 kind: Policy rules: # Log pod changes at RequestResponse level - level: RequestResponse omitStages: - "RequestReceived" resources: - group: "" # core API group resources: ["pods"] verbs: ["create", "patch"”, "update", "delete"] # Log "pods/log", "pods/status" at Metadata level - level: Metadata omitStages: - "RequestReceived" resources: - group: "" resources: ["pods/log", "pods/status"] For matching API calls â—Ź Which verbosity? â—Ź When? (stage) Audit policy: when to log?
  • 49. @lbernail @roboll_ apiVersion: audit.k8s.io/v1 kind: Policy rules: # Log pod changes at RequestResponse level - level: RequestResponse omitStages: - "RequestReceived" resources: - group: "" # core API group resources: ["pods"] verbs: ["create", "patch"”, "update", "delete"] # Log "pods/log", "pods/status" at Metadata level - level: Metadata omitStages: - "RequestReceived" resources: - group: "" resources: ["pods/log", "pods/status"] Gotchas Rules are evaluated in order First matching rule sets level Request/RequestResponse > contain payload data Careful with security implications ex: tokenreviews calls group: “” means core API only Don’t forget to add â—Ź 3rd party apiservices â—Ź your apiservices
  • 50. @lbernail @roboll_ Recommendations â—Ź Ignore RequestReceived stage â—Ź Use at least Metadata level for almost everything â—‹ Possibly ignore healthz, metrics â—Ź Use Request/Response level for critical resource/verbs â—‹ Very valuable for retroactive debugging â—‹ Careful for large/sensitive request/response bodies â—Ź Very complete example in GKE https://github.com/kubernetes/kubernetes/blob/master/cluster/gce/gci/configure-helper.sh â—Ź Documentation https://kubernetes.io/docs/tasks/debug-application-cluster/audit/#audit-policy
  • 51. @lbernail @roboll_ Takeaways â—Ź Getting audit logs is “simple”: 2 flags â—Ź Getting policies right is harder â—Ź You will get a lot of logs â—Ź Requires a solution to analyze them Let’s look at an overview on a real large cluster
  • 52. @lbernail @roboll_ Outline 1. Background: The Kubernetes API 2. Audit Logs 3. Configuring Audit Logs 4. 10000 foot view for a large cluster 5. Understanding Kubernetes Internals 6. Troubleshooting examples
  • 53. 10000 foot view for a large cluster
  • 54. @lbernail @roboll_ Total number of API calls ~900 calls/second on this 2500 nodes cluster Number of audit logs per hour
  • 55. @lbernail @roboll_ Top API users? apiserver: 40 rps kube-proxy: 20 rps local-volume-provisioner:20 rps cronjob-controller: 15 rps spinnaker: 5-10 rps
  • 56. @lbernail @roboll_ Top list, missing “small” users total: ~900rps Top 25: 150 rps 900 calls/second on this 2500 nodes cluster What is doing ~80% of API calls? Total number of API calls
  • 57. @lbernail @roboll_ Grouping by users is not helping Calls from users in group “system:nodes”: 750 rps (~80% of API calls) In this 2500-nodes cluster, this means 0.3 rps per node! Calls by user group group=system:nodes
  • 58. @lbernail @roboll_ Why is “system:nodes” so high? nodes: 500 rps configmaps: 75 rps secrets: 60 rps Calls from group “system:nodes” by resource targeted
  • 59. @lbernail @roboll_ Verbs on “node” for a kubelet 10s Each node update its status every 10s
  • 60. @lbernail @roboll_ Verbs on “configmaps” Only GETs Regularity but not clear pattern
  • 61. @lbernail @roboll_ Group by resource name Each configmap is refreshed every ~5mn => GET call Similar for secrets ~5mn
  • 62. @lbernail @roboll_ List latency by resource Latency for list by resource
  • 63. @lbernail @roboll_ List latency by resource Latency for list by resource apiserver restarts
  • 64. @lbernail @roboll_ Compare cluster performances Latency for get pod by cluster (ms) large clusters (1500+ nodes) smaller clusters (<700 nodes)
  • 65. @lbernail @roboll_ Takeaways â—Ź Biggest users are the ones running on each node â—‹ kubelet, daemonsets (kube-proxy) â—‹ A lot of effort upstream to reduce their load â—‹ Be extra careful of damonsets doing API calls â—Ź Audit logs structure allow to filter and slice & dice â—Ź Audit logs are verbose (1000 logs/s in our example)
  • 66. @lbernail @roboll_ Outline 1. Background: The Kubernetes API 2. Audit Logs 3. Configuring Audit Logs 4. 10000 foot view for a large cluster 5. Understanding Kubernetes Internals 6. Troubleshooting examples
  • 68. @lbernail @roboll_ Creating a simple deployment apiVersion: apps/v1 kind: Deployment metadata: name: nginx labels: app: nginx spec: replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx
  • 69. @lbernail @roboll_ Sequence User creates deploy deployment controller creates RS RS controller creates pods Scheduler bind pods Kubelets Update pod status
  • 70. @lbernail @roboll_ Sequence Scheduler bind pods Scheduler callCreate Binding For nginx pod To node ip-10-x-y-123
  • 71. @lbernail @roboll_ Actually a lot more node 1 node 2 RS controller Deploy ctrl Scheduler apiserver user Create of Deployment, RS, pods, binding + nodes accept Nodes create pods and generate events Pods are running Deployments/RS update status Additions Apiserver verifies Quotas Components also get/list Creation of events + Update of status fields Complete node workflow ~ 3s
  • 72. @lbernail @roboll_ Node API calls Initial calls Get pod Update pod/status: ContainerCreating Get service account token
  • 73. @lbernail @roboll_ Node API calls Create events to show progression MountVolume.SetUp succeeded for volume "default-token-dqmzw" pulling image "nginx" Successfully pulled image "nginx" Created container Started container
  • 74. @lbernail @roboll_ Node API calls Finalize pod creation Get pod Update container status to “Running”
  • 75. @lbernail @roboll_ Takeaways â—Ź A lot of interactions between kube components â—Ź Audit logs give a great understanding of this! â—Ź Events are spiky and get generate a lot of logs â—Ź Events have a 1h default TTL, but stay in audit logs Let’s identify some problems using audit logs
  • 76. @lbernail @roboll_ Outline 1. Background: The Kubernetes API 2. Audit Logs 3. Configuring Audit Logs 4. 10000 foot view for a large cluster 5. Understanding Kubernetes Internals 6. Troubleshooting examples
  • 78. @lbernail @roboll_ Troubleshooting â—Ź Understand what happened â—‹ “Why was a resource deleted?” â—Ź Debug performance regressions/improve performances â—‹ “Which application is responsible for so many calls?” â—Ź Also, identify issues by looking at HTTP status codes
  • 79. @lbernail @roboll_ Status codes Calls by status code 200 201 401
  • 80. @lbernail @roboll_ 4xx only 4xx by status code 401 403 404 422 409
  • 81. @lbernail @roboll_ 4xx only 4xx by status code 401?? (Unauthorized)
  • 82. @lbernail @roboll_ Analyzing 401s 401s by source IP 4 nodes only, turns out they had expired certificates
  • 83. @lbernail @roboll_ 4xx only 4xx by status code 403?? (Forbidden)
  • 84. @lbernail @roboll_ Analyzing 403s 403s by user Most errors from Traefik serviceAccount Bad RBAC configuration?
  • 85. @lbernail @roboll_ Analyzing 403s for this user 403s for Traefik serviceAccount by resource We use Traefik without Kubernetes secrets but it still tries to list them
  • 86. @lbernail @roboll_ 4xx only 4xx by status code 422?? (Invalid)
  • 87. @lbernail @roboll_ What about 422? 422 by user kube-system:generic-garbage-collector => ??
  • 88. @lbernail @roboll_ What is failing? generic-garbage-collector by verb / resource patch on pod
  • 89. @lbernail @roboll_ What is happening? â—Ź Pods are in “Evicted” status and must be kept â—Ź Controlling RS has been deleted and pods should be orphaned â—Ź Garbage collector fails to orphan them (remove ownerRef) â—Ź ReplicaSet has been Terminating for 2 months... â—Ź Root cause: mutating webhook â—‹ We modify the pod spec at creation â—‹ Mutating webhook is registered on pods for CREATE/UPDATE â—‹ We modify immutable fields â—‹ Garbage collector patch triggers this...
  • 90. @lbernail @roboll_ Takeaways â—Ź Looking at calls triggering HTTP errors help find issues â—‹ Misconfigured RBAC (403) â—‹ Applications doing calls they shouldn’t (403) â—‹ Expired certificates (401) â—‹ Other weird things
  • 92. @lbernail @roboll_ Conclusion â—Ź Audit logs can be incredibly valuable â—‹ Low-level understanding of Kubernetes â—‹ Detection of misconfigurations â—‹ Troubleshooting of issues â—‹ Identify performance issues â—Ź Taking advantage of them require some effort â—‹ Policies are not easy to get right â—‹ They are verbose and require a tool to analyze them
  • 93. Thank you We’re hiring! Visit our Kubecon booth or https://www.datadoghq.com/careers/ Or contact us directly: @lbernail laurent@datadoghq.com @roboll_ roboll@datadoghq.com