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:
parent
9e8b655f6f
commit
4a4aef54d3
3 changed files with 69 additions and 11 deletions
|
@ -94,7 +94,7 @@ func initMetricsFlags() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func initKubeconfigFlags(qps float64, burst int, eventsQPS float64, eventsBurst int) {
|
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.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.")
|
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() {
|
func lookupKubeconfigFlag() {
|
||||||
if f := flag.CommandLine.Lookup("kubeconfig"); f != nil {
|
if f := flag.Lookup("kubeconfig"); f != nil {
|
||||||
kubeconfig = flag.CommandLine.Lookup("kubeconfig").Value.String()
|
kubeconfig = f.Value.String()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -605,7 +605,6 @@ func main() {
|
||||||
matching.NewMatcher(),
|
matching.NewMatcher(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
voplHandlers := vpol.New(celEngine, contextProvider)
|
|
||||||
ephrs, err := breaker.StartAdmissionReportsCounter(signalCtx, setup.MetadataClient)
|
ephrs, err := breaker.StartAdmissionReportsCounter(signalCtx, setup.MetadataClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
setup.Logger.Error(err, "failed to start admission reports watcher")
|
setup.Logger.Error(err, "failed to start admission reports watcher")
|
||||||
|
@ -640,6 +639,12 @@ func main() {
|
||||||
setup.ReportingConfiguration,
|
setup.ReportingConfiguration,
|
||||||
reportsBreaker,
|
reportsBreaker,
|
||||||
)
|
)
|
||||||
|
voplHandlers := vpol.New(
|
||||||
|
celEngine,
|
||||||
|
contextProvider,
|
||||||
|
setup.KyvernoClient,
|
||||||
|
reportsBreaker,
|
||||||
|
)
|
||||||
exceptionHandlers := webhooksexception.NewHandlers(exception.ValidationOptions{
|
exceptionHandlers := webhooksexception.NewHandlers(exception.ValidationOptions{
|
||||||
Enabled: internal.PolicyExceptionEnabled(),
|
Enabled: internal.PolicyExceptionEnabled(),
|
||||||
Namespace: internal.ExceptionNamespace(),
|
Namespace: internal.ExceptionNamespace(),
|
||||||
|
|
|
@ -6,24 +6,37 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/go-logr/logr"
|
||||||
|
"github.com/kyverno/kyverno/pkg/breaker"
|
||||||
celengine "github.com/kyverno/kyverno/pkg/cel/engine"
|
celengine "github.com/kyverno/kyverno/pkg/cel/engine"
|
||||||
celpolicy "github.com/kyverno/kyverno/pkg/cel/policy"
|
celpolicy "github.com/kyverno/kyverno/pkg/cel/policy"
|
||||||
|
"github.com/kyverno/kyverno/pkg/client/clientset/versioned"
|
||||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||||
admissionutils "github.com/kyverno/kyverno/pkg/utils/admission"
|
admissionutils "github.com/kyverno/kyverno/pkg/utils/admission"
|
||||||
|
reportutils "github.com/kyverno/kyverno/pkg/utils/report"
|
||||||
"github.com/kyverno/kyverno/pkg/webhooks/handlers"
|
"github.com/kyverno/kyverno/pkg/webhooks/handlers"
|
||||||
"go.uber.org/multierr"
|
"go.uber.org/multierr"
|
||||||
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
|
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
)
|
)
|
||||||
|
|
||||||
type handler struct {
|
type handler struct {
|
||||||
context celpolicy.Context
|
context celpolicy.Context
|
||||||
engine celengine.Engine
|
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{
|
return &handler{
|
||||||
context: context,
|
context: context,
|
||||||
engine: engine,
|
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 {
|
if err != nil {
|
||||||
return admissionutils.Response(request.UID, err)
|
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 errs []error
|
||||||
var warnings []string
|
var warnings []string
|
||||||
for _, policy := range response.Policies {
|
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...)
|
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
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue