Skip to content

Commit

Permalink
recording: Issue an event if a privileged pod is recorded with a log-…
Browse files Browse the repository at this point in the history
…based recorder

In addition to documenting that privileged pods can't be recorded with a
log-based recorder, let's also issue an event.
  • Loading branch information
jhrozek committed Sep 8, 2022
1 parent 6585ab2 commit d7a34f8
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 6 deletions.
2 changes: 1 addition & 1 deletion cmd/security-profiles-operator/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,7 @@ func runWebhook(ctx *cli.Context, info *version.Info) error {
setupLog.Info("registering webhooks")
hookserver := mgr.GetWebhookServer()
binding.RegisterWebhook(hookserver, mgr.GetClient())
recording.RegisterWebhook(hookserver, mgr.GetClient())
recording.RegisterWebhook(hookserver, mgr.GetEventRecorderFor("recording-webhook"), mgr.GetClient())

sigHandler := ctrl.SetupSignalHandler()
setupLog.Info("starting webhook")
Expand Down
32 changes: 28 additions & 4 deletions internal/pkg/webhooks/recording/recording.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
corev1 "k8s.io/api/core/v1"
kerrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/tools/record"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
logf "sigs.k8s.io/controller-runtime/pkg/log"
Expand All @@ -44,16 +45,18 @@ const finalizer = "active-seccomp-profile-recording-lock"

type podSeccompRecorder struct {
impl
log logr.Logger
log logr.Logger
record *utils.SafeRecorder
}

func RegisterWebhook(server *webhook.Server, c client.Client) {
func RegisterWebhook(server *webhook.Server, rec record.EventRecorder, c client.Client) {
server.Register(
"/mutate-v1-pod-recording",
&webhook.Admission{
Handler: &podSeccompRecorder{
impl: &defaultImpl{client: c},
log: logf.Log.WithName("recording"),
impl: &defaultImpl{client: c},
log: logf.Log.WithName("recording"),
record: utils.NewSafeRecorder(rec),
},
},
)
Expand Down Expand Up @@ -194,6 +197,8 @@ func (p *podSeccompRecorder) updatePod(
return false, err
}

p.warnEventIfContainerPrivileged(profileRecording, ctr, pod)

p.updateSecurityContext(ctr, profileRecording)
existingValue, ok := pod.GetAnnotations()[key]
if !ok {
Expand Down Expand Up @@ -391,3 +396,22 @@ func (p *podSeccompRecorder) InjectDecoder(decoder *admission.Decoder) error {
p.impl.SetDecoder(decoder)
return nil
}

func (p *podSeccompRecorder) warnEventIfContainerPrivileged(
profileRecording *profilerecordingv1alpha1.ProfileRecording,
ctr *corev1.Container,
pod *corev1.Pod,
) {
if profileRecording.Spec.Recorder != profilerecordingv1alpha1.ProfileRecorderLogs {
return
}

if ctr.SecurityContext == nil || ctr.SecurityContext.Privileged == nil || !*ctr.SecurityContext.Privileged {
return
}

p.record.Eventf(profileRecording,
corev1.EventTypeWarning,
"PrivilegedContainer",
"Container %s in pod %s is privileged, cannot use log-based profile recording", ctr.Name, pod.Name)
}
3 changes: 2 additions & 1 deletion internal/pkg/webhooks/recording/recording_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import (

"sigs.k8s.io/security-profiles-operator/api/profilerecording/v1alpha1"
"sigs.k8s.io/security-profiles-operator/internal/pkg/webhooks/recording/recordingfakes"
"sigs.k8s.io/security-profiles-operator/internal/pkg/webhooks/utils"
)

var (
Expand Down Expand Up @@ -499,7 +500,7 @@ func TestHandle(t *testing.T) {
mock := &recordingfakes.FakeImpl{}
tc.prepare(mock)

recorder := podSeccompRecorder{impl: mock, log: logr.Discard()}
recorder := podSeccompRecorder{impl: mock, log: logr.Discard(), record: utils.NewSafeRecorder(nil)}
resp := recorder.Handle(context.Background(), tc.request)
tc.assert(resp)
}
Expand Down
61 changes: 61 additions & 0 deletions internal/pkg/webhooks/utils/safe_events.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
Copyright 2022 The Kubernetes Authors.
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 utils

import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/tools/record"
)

type SafeRecorder struct {
recorder record.EventRecorder
}

func NewSafeRecorder(recorder record.EventRecorder) *SafeRecorder {
return &SafeRecorder{recorder: recorder}
}

func (sr *SafeRecorder) Event(object runtime.Object, eventtype, reason, message string) {
if sr.recorder == nil {
return
}

sr.recorder.Event(object, eventtype, reason, message)
}

// Eventf is just like Event, but with Sprintf for the message field.
func (sr *SafeRecorder) Eventf(object runtime.Object, eventtype, reason, messageFmt string, args ...interface{}) {
if sr.recorder == nil {
return
}

sr.recorder.Eventf(object, eventtype, reason, messageFmt, args...)
}

// AnnotatedEventf is just like eventf, but with annotations attached.
func (sr *SafeRecorder) AnnotatedEventf(
object runtime.Object,
annotations map[string]string,
eventtype, reason, messageFmt string,
args ...interface{},
) {
if sr.recorder == nil {
return
}

sr.recorder.AnnotatedEventf(object, annotations, eventtype, reason, messageFmt, args...)
}

0 comments on commit d7a34f8

Please sign in to comment.