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 dcafcb1
Show file tree
Hide file tree
Showing 4 changed files with 72 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 @@ -21,6 +21,7 @@ import (
"encoding/json"
"errors"
"fmt"
"k8s.io/client-go/tools/record"
"net/http"

"github.com/go-logr/logr"
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 == false {
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 @@ -21,6 +21,7 @@ import (
"encoding/json"
"errors"
"net/http"
"sigs.k8s.io/security-profiles-operator/internal/pkg/webhooks/utils"
"testing"

"github.com/go-logr/logr"
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
41 changes: 41 additions & 0 deletions internal/pkg/webhooks/utils/safe_events.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
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 dcafcb1

Please sign in to comment.