OPA Gatekeeper and issue while doing a cluster restore
Posted on December 5, 2022 by Adrian Wyssmann ‐ 6 min read
We recently encountered a huge problem, when using OPA Gatekeeper in a Rancher cluster and performing a restore of this cluster
Issues with cluster restore and Gatekeeper
It has been some weeks since I have installed Gatekeeper. Today we had an issue, which lead me to do a restore of the cluster state to the state from some minutes ago. Usually that is not a problem - well at least before OPA Gatekeeper was installed. While the restore worked, the cluster eventually will not start, some pods stuck in Termination
while others are stuck in Pending
:
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
.........
cattle-gatekeeper-system pod/gatekeeper-controller-manager-87d467bdc-7s76h 1/1 Terminating 0 19d 10.32.13.196 server07 <none> <none>
cattle-gatekeeper-system pod/gatekeeper-controller-manager-87d467bdc-v565l 1/1 Terminating 0 19d 10.32.8.68 server08 <none> <none>
cattle-monitoring-system pod/pushprox-kube-controller-manager-proxy-7c446ddb95-tbwtl 0/1 Terminating 0 5m17s <none> server07 <none> <none>
credit-agreement pod/credit-agreement-frontend-web-86bf44557c-9dwvz 2/2 Terminating 0 103d 10.32.8.154 server08 <none> <none>
ingress-nginx pod/nginx-ingress-controller-79dxf 0/1 Terminating 0 147m <none> server07 <none> <none>
ingress-nginx pod/nginx-ingress-controller-wf8k4 0/1 Terminating 0 148m <none> server08 <none> <none>
......
kube-system pod/canal-g7n6d 0/2 Pending 0 5m4s <none> server08 <none> <none>
kube-system pod/canal-zpxjl -1/2 Pending 0 5m4s <none> server07 <none> <none>
kube-system pod/coredns-b3d8fc84d-c7qrr 0/1 Pending 0 168m <none> server07 <none> <none>
kube-system pod/metrics-server-66b8c99467-tdpk6 0/1 Terminating 0 89d 10.32.8.29 server08 <none> <none>
We can see the events in the namespace cattle-system
:
$ kubectl get event -n kube-system --sort-by='.lastTimestamp'
...
Reason Resource Date FailedMount | Pod istio-cni-node-b8v6tMountVolume.SetUp failed for volume "kube-api-access-dcqs8" : failed to fetch token: pods "istio-cni-node-b8v6t" not found | Tue, Nov 22 2022 6:31:28 pm
FailedMount | Pod canal-6gx6zMountVolume.SetUp failed for volume "kube-api-access-7xdmz" : failed to fetch token: pods "canal-6gx6z" not found | Tue, Nov 22 2022 6:31:24 pm
FailedMount | Pod nginx-ingress-controller-bp47jMountVolume.SetUp failed for volume "kube-api-access-dv9z6" : failed to fetch token: pods "nginx-ingress-controller-bp47j" not found | Tue, Nov 22 2022 6:30:54 pm
FailedMount | Pod istio-cni-node-b82kqMountVolume.SetUp failed for volume "kube-api-access-xz5rm" : failed to fetch token: pods "istio-cni-node-b82kq" not found | Tue, Nov 22 2022 6:30:53 pm
FailedMount | Pod coredns-autoscaler-d958447b4-95zwbMountVolume.SetUp failed for volume "kube-api-access-g88jq" : failed to fetch token: pods "coredns-autoscaler-d958447b4-95zwb" not found | Tue, Nov 22 2022 6:30:47 pm
...
Furthermore, we can also see these errors in the logs:
E1121 18:32:50.705702 1 leaderelection.go:367] Failed to update lock: Put "https://127.0.0.1:6443/apis/coordination.k8s.io/v1/namespaces/kube-system/leases/kube-scheduler?timeout=5s": net/http: request canceled (Client.Timeout exceeded while awaiting headers)
E1122 18:32:58.329994 1 leaderelection.go:367] Failed to update lock: the server was unable to return a response in the time allotted, but may still be processing the request (put leases.coordination.k8s.io kube-scheduler)
We eventually came out of this missery by deleting the Gatekeeper webhooks
$ kubectl delete ValidatingWebhookConfiguration gatekeeper-validating-webhook-configuration
validatingwebhookconfiguration.admissionregistration.k8s.io "gatekeeper-validating-webhook-configuration" deleted
$ kubectl delete MutatingWebhookConfiguration gatekeeper-mutating-webhook-configuration
mutatingwebhookconfiguration.admissionregistration.k8s.io "gatekeeper-mutating-webhook-configuration" deleted
After that we also had to restart some of the nodes, on which the pods were on state Pending
.
Configure Gatekeeper properly
When looking at Exempting Namespaces it’s important to notice this statement:
If you use
--exempt-namespace
flag andadmission.gatekeeper.sh/ignore
label, Gatekeeper’s webhook will not be called by the API server for any resource in that namespace. That means that Gatekeeper being down should have no effect on requests for that namespace.
When looking at the helm chart, more specificall at gatekeeper-controller-manager-deployment.yaml
we can see that one has to provide exemptNamespaces
and exemptNamespacePrefixes
:
...
{{- range .Values.controllerManager.exemptNamespaces}}
- --exempt-namespace={{ . }}
{{- end }}
{{- range .Values.controllerManager.exemptNamespacePrefixes}}
- --exempt-namespace-prefix={{ . }}
{{- end }}
...
Hence the values file has to be extended to your needs, especially under exemptNamespace
you may need to add additional namespaces:
...
controllerManager:
...
exemptNamespace:
- ingress-nginx
- istio-system
- ...
exemptNamespacePrefixes:
- "cattle"
- "kube"
...
Before continue, let’s add back the webhooks we deleted above:
$ kubectl get validatingwebhookconfigurations.admissionregistration.k8s.io -A
NAME WEBHOOKS AGE
gatekeeper-validating-webhook-configuration 2 6s
ingress-nginx-admission 1 453d
istio-validator-istio-system 1 214d
istiod-default-validator 1 106d
rancher-monitoring-admission 1 453d
$ kubectl get mutatingwebhookconfigurations.admissionregistration.k8s.io -A
NAME WEBHOOKS AGE
gatekeeper-mutating-webhook-configuration 1 40s
istio-revision-tag-default 4 4d5h
istio-sidecar-injector 4 214d
rancher-monitoring-admission 1 453d
vpa-webhook-config 1 4m39s
At last, we have to add the missing label to all namespaces. I run this script:
#!/usr/bin/env bash
projectId=$(kubectl get ns cattle-system -o jsonpath='{.metadata.labels.field\.cattle\.io/projectId}')
for ns in $(kubectl get ns --selector field.cattle.io/projectId=$projectId -o name); do
echo "$ns ($CONTEXT):"
if [[ -z "$CONTEXT" ]]; then
kubectl label $ns admission.gatekeeper.sh/ignore="true"
else
kubectl label $ns admission.gatekeeper.sh/ignore="true" --context $CONTEXT
fi
done
Note
Ensure that the namespaces are exempt, before you run the script above, otherwise you get this error
Error from server (Only exempt namespace can have the admission.gatekeeper.sh/ignore label): admission webhook "check-ignore-label.gatekeeper.sh" denied the request: Only exempt namespace can have the admission.gatekeeper.sh/ignore label
After all is in place, we create a new snapshot which we then will restore. Unfortunately, we still have some pods which are in state Pending
and Terminating
:
$ kubectl get pods \
--field-selector="status.phase!=Succeeded,status.phase!=Running" -A
NAMESPACE NAME READY STATUS RESTARTS AGE
cattle-system cattle-cluster-agent-58585d647d-4w2ww 0/1 Pending 0 52s
cattle-system cattle-cluster-agent-58585d647d-xx5rq 0/1 Pending 0 52s
kube-system canal-6qswk 0/2 Pending 0 52s
kube-system canal-gjkcr 0/2 Pending 0 52s
kube-system canal-m9m94 0/2 Pending 0 52s
kube-system coredns-7ddc8976bb-kjxql 0/1 Pending 0 52s
kube-system coredns-autoscaler-9988dc68-72zkw 0/1 Pending 0 52s
kube-system metrics-server-65b8c99467-p45ns 0/1 Pending 0 52s
Still we observe the same events in the namespace kube-system
…
$ kubectl get event -n kube-system --sort-by='.lastTimestamp'
...
2m34s Normal SuccessfulCreate replicaset/coredns-autoscaler-9988dc68 Created pod: coredns-autoscaler-9988dc68-72zkw
2m34s Warning Unhealthy pod/canal-vx4nl Readiness probe failed: Get "http://localhost:9099/readiness": dial tcp 127.0.0.1:9099: connect: connectio
n refused
2m34s Warning FailedKillPod pod/calico-kube-controllers-7586d58b74-l9dzl error killing pod: failed to "KillPodSandbox" for "32f3dd48-96ef-44e8-992a-afd78356164c" with KillPodSandb
oxError: "rpc error: code = Unknown desc = networkPlugin cni failed to teardown pod \"calico-kube-controllers-7586d58b74-l9dzl_kube-system\" network: cni config uninitialized"
2m34s Normal SuccessfulCreate replicaset/calico-kube-controllers-7586d58b74 Created pod: calico-kube-controllers-7586d58b74-6qt4d
2m34s Warning Unhealthy pod/canal-vx4nl Liveness probe errored: rpc error: code = Unknown desc = container not running (dc23c53f0eb7b56567c4116283
0ffbeefa8b3d782e1d00a5503860524319509b)
...
40s Normal Killing pod/metrics-server-65b8c99467-28bxh Stopping container metrics-server
11s Warning FailedKillPod pod/metrics-server-65b8c99467-28bxh error killing pod: failed to "KillPodSandbox" for "a3adecab-f767-4f2d-9100-eff5a2fbc4da" with KillPodSandb
oxError: "rpc error: code = Unknown desc = networkPlugin cni failed to teardown pod \"metrics-server-65b8c99467-28bxh_kube-system\" network: error getting ClusterInformation: connection is unauthorized: Unaut
horized"
...
… and in namespace cattle-system
:
$ kubectl get event -n cattle-system
...
6m46s Warning FailedKillPod pod/helm-operation-cm2kb error killing pod: failed to "KillPodSandbox" for "ee233c56-a656-429b-8fa7-ce0affb19556" with KillPodSandboxError: "rp
c error: code = Unknown desc = networkPlugin cni failed to teardown pod \"helm-operation-cm2kb_cattle-system\" network: cni config uninitialized"
...
Ultimately, it helped to restart the nodes, on which the pods were in Pending
state.
Conclusion
When using Gatekeeper, it is essential to have important namespaces exempt and add label admission.gatekeeper.sh/ignore
to all namespaces in the system project.