1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-06 07:57:07 +00:00

feat: add reporting to validating admission handler (#12090)

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
Charles-Edouard Brétéché 2025-02-04 21:32:18 +01:00 committed by GitHub
parent 9e8b655f6f
commit 4a4aef54d3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 69 additions and 11 deletions

View file

@ -94,7 +94,7 @@ func initMetricsFlags() {
}
func initKubeconfigFlags(qps float64, burst int, eventsQPS float64, eventsBurst int) {
if f := flag.CommandLine.Lookup("kubeconfig"); f == nil {
if f := flag.Lookup("kubeconfig"); f == nil {
flag.StringVar(&kubeconfig, "kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.")
}
flag.Float64Var(&clientRateLimitQPS, "clientRateLimitQPS", qps, "Configure the maximum QPS to the Kubernetes API server from Kyverno. Uses the client default if zero.")
@ -149,8 +149,8 @@ func initReportingFlags() {
}
func lookupKubeconfigFlag() {
if f := flag.CommandLine.Lookup("kubeconfig"); f != nil {
kubeconfig = flag.CommandLine.Lookup("kubeconfig").Value.String()
if f := flag.Lookup("kubeconfig"); f != nil {
kubeconfig = f.Value.String()
}
}

View file

@ -605,7 +605,6 @@ func main() {
matching.NewMatcher(),
)
}
voplHandlers := vpol.New(celEngine, contextProvider)
ephrs, err := breaker.StartAdmissionReportsCounter(signalCtx, setup.MetadataClient)
if err != nil {
setup.Logger.Error(err, "failed to start admission reports watcher")
@ -640,6 +639,12 @@ func main() {
setup.ReportingConfiguration,
reportsBreaker,
)
voplHandlers := vpol.New(
celEngine,
contextProvider,
setup.KyvernoClient,
reportsBreaker,
)
exceptionHandlers := webhooksexception.NewHandlers(exception.ValidationOptions{
Enabled: internal.PolicyExceptionEnabled(),
Namespace: internal.ExceptionNamespace(),

View file

@ -6,24 +6,37 @@ import (
"time"
"github.com/go-logr/logr"
"github.com/kyverno/kyverno/pkg/breaker"
celengine "github.com/kyverno/kyverno/pkg/cel/engine"
celpolicy "github.com/kyverno/kyverno/pkg/cel/policy"
"github.com/kyverno/kyverno/pkg/client/clientset/versioned"
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
admissionutils "github.com/kyverno/kyverno/pkg/utils/admission"
reportutils "github.com/kyverno/kyverno/pkg/utils/report"
"github.com/kyverno/kyverno/pkg/webhooks/handlers"
"go.uber.org/multierr"
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
"k8s.io/apimachinery/pkg/util/wait"
)
type handler struct {
context celpolicy.Context
engine celengine.Engine
kyvernoClient versioned.Interface
reportsBreaker breaker.Breaker
}
func New(engine celengine.Engine, context celpolicy.Context) *handler {
func New(
engine celengine.Engine,
context celpolicy.Context,
kyvernoClient versioned.Interface,
reportsBreaker breaker.Breaker,
) *handler {
return &handler{
context: context,
engine: engine,
kyvernoClient: kyvernoClient,
reportsBreaker: reportsBreaker,
}
}
@ -35,10 +48,18 @@ func (h *handler) Validate(ctx context.Context, logger logr.Logger, request hand
if err != nil {
return admissionutils.Response(request.UID, err)
}
return admissionResponse(response, request)
var group wait.Group
defer group.Wait()
group.Start(func() {
err := h.admissionReport(ctx, response, request)
if err != nil {
logger.Error(err, "failed to create report")
}
})
return h.admissionResponse(response, request)
}
func admissionResponse(response celengine.EngineResponse, request handlers.AdmissionRequest) handlers.AdmissionResponse {
func (h *handler) admissionResponse(response celengine.EngineResponse, request handlers.AdmissionRequest) handlers.AdmissionResponse {
var errs []error
var warnings []string
for _, policy := range response.Policies {
@ -65,3 +86,35 @@ func admissionResponse(response celengine.EngineResponse, request handlers.Admis
}
return admissionutils.Response(request.UID, multierr.Combine(errs...), warnings...)
}
func (h *handler) admissionReport(ctx context.Context, response celengine.EngineResponse, request handlers.AdmissionRequest) error {
object, oldObject, err := admissionutils.ExtractResources(nil, request.AdmissionRequest)
if err != nil {
return err
}
if object.Object == nil {
object = oldObject
}
responses := make([]engineapi.EngineResponse, 0, len(response.Policies))
for _, r := range response.Policies {
engineResponse := engineapi.EngineResponse{
Resource: object,
PolicyResponse: engineapi.PolicyResponse{
Rules: r.Rules,
},
}
engineResponse = engineResponse.WithPolicy(engineapi.NewValidatingPolicy(&r.Policy))
responses = append(responses, engineResponse)
}
report := reportutils.BuildAdmissionReport(object, request.AdmissionRequest, responses...)
if len(report.GetResults()) > 0 {
err := h.reportsBreaker.Do(ctx, func(ctx context.Context) error {
_, err := reportutils.CreateReport(ctx, report, h.kyvernoClient)
return err
})
if err != nil {
return err
}
}
return nil
}