fix: validate pods on update

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>
This commit is contained in:
Oliver Bähler
2022-12-29 17:49:45 +01:00
committed by Dario Tranchitella
parent 79391f863a
commit 628efbb30f
2 changed files with 71 additions and 50 deletions
+70 -49
View File
@@ -25,53 +25,7 @@ func ContainerRegistry() capsulewebhook.Handler {
func (h *containerRegistryHandler) OnCreate(c client.Client, decoder *admission.Decoder, recorder record.EventRecorder) capsulewebhook.Func {
return func(ctx context.Context, req admission.Request) *admission.Response {
pod := &corev1.Pod{}
if err := decoder.Decode(req, pod); err != nil {
return utils.ErroredResponse(err)
}
tntList := &capsulev1beta2.TenantList{}
if err := c.List(ctx, tntList, client.MatchingFieldsSelector{
Selector: fields.OneTermEqualSelector(".status.namespaces", pod.Namespace),
}); err != nil {
return utils.ErroredResponse(err)
}
if len(tntList.Items) == 0 {
return nil
}
tnt := tntList.Items[0]
if tnt.Spec.ContainerRegistries != nil {
var valid, matched bool
for _, container := range pod.Spec.Containers {
reg := NewRegistry(container.Image)
if len(reg.Registry()) == 0 {
recorder.Eventf(&tnt, corev1.EventTypeWarning, "MissingFQCI", "Pod %s/%s is not using using a fully qualified container image, cannot enforce registry the current Tenant", req.Namespace, req.Name, reg.Registry())
response := admission.Denied(NewContainerRegistryForbidden(container.Image, *tnt.Spec.ContainerRegistries).Error())
return &response
}
valid = tnt.Spec.ContainerRegistries.ExactMatch(reg.Registry())
matched = tnt.Spec.ContainerRegistries.RegexMatch(reg.Registry())
if !valid && !matched {
recorder.Eventf(&tnt, corev1.EventTypeWarning, "ForbiddenContainerRegistry", "Pod %s/%s is using a container hosted on registry %s that is forbidden for the current Tenant", req.Namespace, req.Name, reg.Registry())
response := admission.Denied(NewContainerRegistryForbidden(container.Image, *tnt.Spec.ContainerRegistries).Error())
return &response
}
}
}
return nil
return h.validate(ctx, c, decoder, recorder, req)
}
}
@@ -81,8 +35,75 @@ func (h *containerRegistryHandler) OnDelete(client.Client, *admission.Decoder, r
}
}
func (h *containerRegistryHandler) OnUpdate(client.Client, *admission.Decoder, record.EventRecorder) capsulewebhook.Func {
// ust be validate on update events since updates to pods on spec.containers[*].image and spec.initContainers[*].image are allowed.
func (h *containerRegistryHandler) OnUpdate(c client.Client, decoder *admission.Decoder, recorder record.EventRecorder) capsulewebhook.Func {
return func(ctx context.Context, req admission.Request) *admission.Response {
return nil
return h.validate(ctx, c, decoder, recorder, req)
}
}
func (h *containerRegistryHandler) validate(ctx context.Context, c client.Client, decoder *admission.Decoder, recorder record.EventRecorder, req admission.Request) *admission.Response {
pod := &corev1.Pod{}
if err := decoder.Decode(req, pod); err != nil {
return utils.ErroredResponse(err)
}
tntList := &capsulev1beta2.TenantList{}
if err := c.List(ctx, tntList, client.MatchingFieldsSelector{
Selector: fields.OneTermEqualSelector(".status.namespaces", pod.Namespace),
}); err != nil {
return utils.ErroredResponse(err)
}
if len(tntList.Items) == 0 {
return nil
}
tnt := tntList.Items[0]
if tnt.Spec.ContainerRegistries != nil {
// Evaluate init containers
for _, container := range pod.Spec.InitContainers {
if response := h.VerifyContainerRegistry(recorder, req, container, tnt); response != nil {
return response
}
}
// Evaluate containers
for _, container := range pod.Spec.Containers {
if response := h.VerifyContainerRegistry(recorder, req, container, tnt); response != nil {
return response
}
}
}
return nil
}
func (h *containerRegistryHandler) VerifyContainerRegistry(recorder record.EventRecorder, req admission.Request, container corev1.Container, tnt capsulev1beta2.Tenant) *admission.Response {
var valid, matched bool
reg := NewRegistry(container.Image)
if len(reg.Registry()) == 0 {
recorder.Eventf(&tnt, corev1.EventTypeWarning, "MissingFQCI", "Pod %s/%s is not using using a fully qualified container image, cannot enforce registry the current Tenant", req.Namespace, req.Name, reg.Registry())
response := admission.Denied(NewContainerRegistryForbidden(container.Image, *tnt.Spec.ContainerRegistries).Error())
return &response
}
valid = tnt.Spec.ContainerRegistries.ExactMatch(reg.Registry())
matched = tnt.Spec.ContainerRegistries.RegexMatch(reg.Registry())
if !valid && !matched {
recorder.Eventf(&tnt, corev1.EventTypeWarning, "ForbiddenContainerRegistry", "Pod %s/%s is using a container hosted on registry %s that is forbidden for the current Tenant", req.Namespace, req.Name, reg.Registry())
response := admission.Denied(NewContainerRegistryForbidden(container.Image, *tnt.Spec.ContainerRegistries).Error())
return &response
}
return nil
}
+1 -1
View File
@@ -7,7 +7,7 @@ import (
capsulewebhook "github.com/clastix/capsule/pkg/webhook"
)
// +kubebuilder:webhook:path=/pods,mutating=false,sideEffects=None,admissionReviewVersions=v1,failurePolicy=fail,groups="",resources=pods,verbs=create,versions=v1,name=pods.capsule.clastix.io
// +kubebuilder:webhook:path=/pods,mutating=false,sideEffects=None,admissionReviewVersions=v1,failurePolicy=fail,groups="",resources=pods,verbs=create;update,versions=v1,name=pods.capsule.clastix.io
type pod struct {
handlers []capsulewebhook.Handler