Check if webhook config references a service before throwing an error
parent
5a246761b2
commit
279004da51
|
@ -194,9 +194,9 @@ Example:
|
||||||
apiVersion: admissionregistration.k8s.io/v1beta1
|
apiVersion: admissionregistration.k8s.io/v1beta1
|
||||||
kind: ValidatingWebhookConfiguration
|
kind: ValidatingWebhookConfiguration
|
||||||
metadata:
|
metadata:
|
||||||
name: sample-webhook.adamwg.com
|
name: sample-webhook.example.com
|
||||||
webhooks:
|
webhooks:
|
||||||
- name: sample-webhook.adamwg.com
|
- name: sample-webhook.example.com
|
||||||
rules:
|
rules:
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- ""
|
- ""
|
||||||
|
@ -226,9 +226,9 @@ How to fix:
|
||||||
apiVersion: admissionregistration.k8s.io/v1beta1
|
apiVersion: admissionregistration.k8s.io/v1beta1
|
||||||
kind: ValidatingWebhookConfiguration
|
kind: ValidatingWebhookConfiguration
|
||||||
metadata:
|
metadata:
|
||||||
name: sample-webhook.adamwg.com
|
name: sample-webhook.example.com
|
||||||
webhooks:
|
webhooks:
|
||||||
- name: sample-webhook.adamwg.com
|
- name: sample-webhook.example.com
|
||||||
rules:
|
rules:
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- ""
|
- ""
|
||||||
|
|
|
@ -67,6 +67,6 @@ const (
|
||||||
PersistentVolume Kind = "persistent volume"
|
PersistentVolume Kind = "persistent volume"
|
||||||
// ValidatingWebhookConfiguration identifies Kubernetes objects of kind `validating webhook configuration`
|
// ValidatingWebhookConfiguration identifies Kubernetes objects of kind `validating webhook configuration`
|
||||||
ValidatingWebhookConfiguration Kind = "validating webhook configuration"
|
ValidatingWebhookConfiguration Kind = "validating webhook configuration"
|
||||||
// MutatingWebhookConfiguration identifies Kubernetes objects of kind `validating webhook configuration`
|
// MutatingWebhookConfiguration identifies Kubernetes objects of kind `mutating webhook configuration`
|
||||||
MutatingWebhookConfiguration Kind = "mutating webhook configuration"
|
MutatingWebhookConfiguration Kind = "mutating webhook configuration"
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
Copyright 2019 DigitalOcean
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package doks
|
package doks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -38,7 +54,9 @@ func (w *webhookCheck) Run(objects *kube.Objects) ([]checks.Diagnostic, error) {
|
||||||
|
|
||||||
for _, config := range objects.ValidatingWebhookConfigurations.Items {
|
for _, config := range objects.ValidatingWebhookConfigurations.Items {
|
||||||
for _, validatingWebhook := range config.Webhooks {
|
for _, validatingWebhook := range config.Webhooks {
|
||||||
if *validatingWebhook.FailurePolicy == ar.Fail && doesSelectorIncludeKubeSystem(validatingWebhook.NamespaceSelector, objects.SystemNamespace) {
|
if *validatingWebhook.FailurePolicy == ar.Fail &&
|
||||||
|
validatingWebhook.ClientConfig.Service != nil &&
|
||||||
|
selectorMatchesNamespace(validatingWebhook.NamespaceSelector, objects.SystemNamespace) {
|
||||||
d := checks.Diagnostic{
|
d := checks.Diagnostic{
|
||||||
Severity: checks.Error,
|
Severity: checks.Error,
|
||||||
Message: "Webhook matches objects in the kube-system namespace. This can cause problems when upgrading the cluster.",
|
Message: "Webhook matches objects in the kube-system namespace. This can cause problems when upgrading the cluster.",
|
||||||
|
@ -53,7 +71,9 @@ func (w *webhookCheck) Run(objects *kube.Objects) ([]checks.Diagnostic, error) {
|
||||||
|
|
||||||
for _, config := range objects.MutatingWebhookConfigurations.Items {
|
for _, config := range objects.MutatingWebhookConfigurations.Items {
|
||||||
for _, mutatingWebhook := range config.Webhooks {
|
for _, mutatingWebhook := range config.Webhooks {
|
||||||
if *mutatingWebhook.FailurePolicy == ar.Fail && doesSelectorIncludeKubeSystem(mutatingWebhook.NamespaceSelector, objects.SystemNamespace) {
|
if *mutatingWebhook.FailurePolicy == ar.Fail &&
|
||||||
|
mutatingWebhook.ClientConfig.Service != nil &&
|
||||||
|
selectorMatchesNamespace(mutatingWebhook.NamespaceSelector, objects.SystemNamespace) {
|
||||||
d := checks.Diagnostic{
|
d := checks.Diagnostic{
|
||||||
Severity: checks.Error,
|
Severity: checks.Error,
|
||||||
Message: "Webhook matches objects in the kube-system namespace. This can cause problems when upgrading the cluster.",
|
Message: "Webhook matches objects in the kube-system namespace. This can cause problems when upgrading the cluster.",
|
||||||
|
@ -68,16 +88,15 @@ func (w *webhookCheck) Run(objects *kube.Objects) ([]checks.Diagnostic, error) {
|
||||||
return diagnostics, nil
|
return diagnostics, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func doesSelectorIncludeKubeSystem(selector *metav1.LabelSelector, namespace *corev1.Namespace) bool {
|
func selectorMatchesNamespace(selector *metav1.LabelSelector, namespace *corev1.Namespace) bool {
|
||||||
if selector.Size() == 0 {
|
if selector.Size() == 0 {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
labels := namespace.GetLabels()
|
labels := namespace.GetLabels()
|
||||||
for key, value := range selector.MatchLabels {
|
for key, value := range selector.MatchLabels {
|
||||||
if v, ok := labels[key]; ok && v == value {
|
if v, ok := labels[key]; !ok || v != value {
|
||||||
continue
|
return false
|
||||||
}
|
}
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
for _, lbr := range selector.MatchExpressions {
|
for _, lbr := range selector.MatchExpressions {
|
||||||
if !match(labels, lbr) {
|
if !match(labels, lbr) {
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
Copyright 2019 DigitalOcean
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package doks
|
package doks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -45,6 +61,11 @@ func TestWebhookError(t *testing.T) {
|
||||||
objs: initObjects(ar.Ignore),
|
objs: initObjects(ar.Ignore),
|
||||||
expected: nil,
|
expected: nil,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "webook does not use service",
|
||||||
|
objs: webhookURL(),
|
||||||
|
expected: nil,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "namespace selector is empty",
|
name: "namespace selector is empty",
|
||||||
objs: initObjects(ar.Fail),
|
objs: initObjects(ar.Fail),
|
||||||
|
@ -133,6 +154,12 @@ func initObjects(failurePolicyType ar.FailurePolicyType) *kube.Objects {
|
||||||
Name: "mw_foo",
|
Name: "mw_foo",
|
||||||
FailurePolicy: &failurePolicyType,
|
FailurePolicy: &failurePolicyType,
|
||||||
NamespaceSelector: &metav1.LabelSelector{},
|
NamespaceSelector: &metav1.LabelSelector{},
|
||||||
|
ClientConfig: ar.WebhookClientConfig{
|
||||||
|
Service: &ar.ServiceReference{
|
||||||
|
Name: "some-svc",
|
||||||
|
Namespace: "k8s",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -150,6 +177,12 @@ func initObjects(failurePolicyType ar.FailurePolicyType) *kube.Objects {
|
||||||
Name: "vw_foo",
|
Name: "vw_foo",
|
||||||
FailurePolicy: &failurePolicyType,
|
FailurePolicy: &failurePolicyType,
|
||||||
NamespaceSelector: &metav1.LabelSelector{},
|
NamespaceSelector: &metav1.LabelSelector{},
|
||||||
|
ClientConfig: ar.WebhookClientConfig{
|
||||||
|
Service: &ar.ServiceReference{
|
||||||
|
Name: "some-svc",
|
||||||
|
Namespace: "k8s",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -159,6 +192,18 @@ func initObjects(failurePolicyType ar.FailurePolicyType) *kube.Objects {
|
||||||
return objs
|
return objs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func webhookURL() *kube.Objects {
|
||||||
|
var url = "https://example.com/webhook/action"
|
||||||
|
objs := initObjects(ar.Fail)
|
||||||
|
objs.ValidatingWebhookConfigurations.Items[0].Webhooks[0].ClientConfig = ar.WebhookClientConfig{
|
||||||
|
URL: &url,
|
||||||
|
}
|
||||||
|
objs.MutatingWebhookConfigurations.Items[0].Webhooks[0].ClientConfig = ar.WebhookClientConfig{
|
||||||
|
URL: &url,
|
||||||
|
}
|
||||||
|
return objs
|
||||||
|
}
|
||||||
|
|
||||||
func label(label map[string]string) *kube.Objects {
|
func label(label map[string]string) *kube.Objects {
|
||||||
objs := initObjects(ar.Fail)
|
objs := initObjects(ar.Fail)
|
||||||
objs.ValidatingWebhookConfigurations.Items[0].Webhooks[0].NamespaceSelector = &metav1.LabelSelector{
|
objs.ValidatingWebhookConfigurations.Items[0].Webhooks[0].NamespaceSelector = &metav1.LabelSelector{
|
||||||
|
|
Loading…
Reference in New Issue