2023-01-18 14:38:47 +01:00
package main
import (
"context"
"errors"
"flag"
"os"
2023-05-10 17:18:41 +05:30
"strings"
2023-01-18 14:38:47 +01:00
"sync"
"time"
"github.com/kyverno/kyverno/cmd/internal"
"github.com/kyverno/kyverno/pkg/client/clientset/versioned"
kyvernoinformer "github.com/kyverno/kyverno/pkg/client/informers/externalversions"
"github.com/kyverno/kyverno/pkg/clients/dclient"
"github.com/kyverno/kyverno/pkg/config"
2024-02-02 12:37:58 +01:00
globalcontextcontroller "github.com/kyverno/kyverno/pkg/controllers/globalcontext"
2024-01-31 00:08:47 +01:00
aggregatereportcontroller "github.com/kyverno/kyverno/pkg/controllers/report/aggregate"
2023-01-18 14:38:47 +01:00
backgroundscancontroller "github.com/kyverno/kyverno/pkg/controllers/report/background"
resourcereportcontroller "github.com/kyverno/kyverno/pkg/controllers/report/resource"
2023-01-31 08:46:38 +01:00
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
2023-11-21 15:31:51 +05:30
"github.com/kyverno/kyverno/pkg/engine/apicall"
2023-04-13 13:29:40 +02:00
"github.com/kyverno/kyverno/pkg/engine/jmespath"
2023-01-18 14:38:47 +01:00
"github.com/kyverno/kyverno/pkg/event"
2024-02-02 15:35:24 +01:00
"github.com/kyverno/kyverno/pkg/globalcontext/store"
2023-01-18 14:38:47 +01:00
"github.com/kyverno/kyverno/pkg/leaderelection"
"github.com/kyverno/kyverno/pkg/logging"
2024-02-01 15:44:05 +05:30
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
apiserver "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
2023-09-05 14:42:17 +03:00
"k8s.io/apimachinery/pkg/runtime/schema"
2023-01-18 14:38:47 +01:00
kubeinformers "k8s.io/client-go/informers"
2023-09-05 14:42:17 +03:00
admissionregistrationv1alpha1informers "k8s.io/client-go/informers/admissionregistration/v1alpha1"
2023-01-18 14:38:47 +01:00
metadatainformers "k8s.io/client-go/metadata/metadatainformer"
kyamlopenapi "sigs.k8s.io/kustomize/kyaml/openapi"
)
const (
resyncPeriod = 15 * time . Minute
)
2024-02-01 15:44:05 +05:30
func sanityChecks ( apiserverClient apiserver . Interface ) error {
return kubeutils . CRDsInstalled ( apiserverClient ,
"clusterpolicyreports.wgpolicyk8s.io" ,
"policyreports.wgpolicyk8s.io" ,
"clusterbackgroundscanreports.kyverno.io" ,
"backgroundscanreports.kyverno.io" ,
)
}
2023-01-18 14:38:47 +01:00
func createReportControllers (
2023-02-02 11:58:34 +01:00
eng engineapi . Engine ,
2023-01-18 14:38:47 +01:00
backgroundScan bool ,
admissionReports bool ,
2023-06-16 17:19:22 +02:00
aggregateReports bool ,
2023-07-25 21:22:51 -07:00
policyReports bool ,
2023-09-05 14:42:17 +03:00
validatingAdmissionPolicyReports bool ,
2023-01-18 14:38:47 +01:00
backgroundScanWorkers int ,
client dclient . Interface ,
kyvernoClient versioned . Interface ,
metadataFactory metadatainformers . SharedInformerFactory ,
kubeInformer kubeinformers . SharedInformerFactory ,
kyvernoInformer kyvernoinformer . SharedInformerFactory ,
backgroundScanInterval time . Duration ,
configuration config . Configuration ,
2023-04-13 13:29:40 +02:00
jp jmespath . Interface ,
2023-01-18 14:38:47 +01:00
eventGenerator event . Interface ,
) ( [ ] internal . Controller , func ( context . Context ) error ) {
var ctrls [ ] internal . Controller
var warmups [ ] func ( context . Context ) error
2023-09-05 14:42:17 +03:00
var vapInformer admissionregistrationv1alpha1informers . ValidatingAdmissionPolicyInformer
2024-01-29 13:49:17 +02:00
var vapBindingInformer admissionregistrationv1alpha1informers . ValidatingAdmissionPolicyBindingInformer
2023-09-05 14:42:17 +03:00
// check if validating admission policies are registered in the API server
if validatingAdmissionPolicyReports {
vapInformer = kubeInformer . Admissionregistration ( ) . V1alpha1 ( ) . ValidatingAdmissionPolicies ( )
2024-01-29 13:49:17 +02:00
vapBindingInformer = kubeInformer . Admissionregistration ( ) . V1alpha1 ( ) . ValidatingAdmissionPolicyBindings ( )
2023-09-05 14:42:17 +03:00
}
2023-01-18 14:38:47 +01:00
kyvernoV1 := kyvernoInformer . Kyverno ( ) . V1 ( )
2024-01-17 20:00:15 +02:00
kyvernoV2beta1 := kyvernoInformer . Kyverno ( ) . V2beta1 ( )
2023-01-18 14:38:47 +01:00
if backgroundScan || admissionReports {
resourceReportController := resourcereportcontroller . NewController (
client ,
kyvernoV1 . Policies ( ) ,
kyvernoV1 . ClusterPolicies ( ) ,
2023-09-05 14:42:17 +03:00
vapInformer ,
2023-01-18 14:38:47 +01:00
)
warmups = append ( warmups , func ( ctx context . Context ) error {
return resourceReportController . Warmup ( ctx )
} )
ctrls = append ( ctrls , internal . NewController (
resourcereportcontroller . ControllerName ,
resourceReportController ,
resourcereportcontroller . Workers ,
) )
2023-06-16 17:19:22 +02:00
if aggregateReports {
ctrls = append ( ctrls , internal . NewController (
aggregatereportcontroller . ControllerName ,
aggregatereportcontroller . NewController (
kyvernoClient ,
2024-02-08 11:36:01 +01:00
client ,
2023-06-16 17:19:22 +02:00
metadataFactory ,
kyvernoV1 . Policies ( ) ,
kyvernoV1 . ClusterPolicies ( ) ,
2023-09-20 10:32:38 +02:00
vapInformer ,
2023-06-16 17:19:22 +02:00
) ,
aggregatereportcontroller . Workers ,
) )
}
2023-01-18 14:38:47 +01:00
if backgroundScan {
2023-09-05 14:42:17 +03:00
backgroundScanController := backgroundscancontroller . NewController (
client ,
kyvernoClient ,
eng ,
metadataFactory ,
kyvernoV1 . Policies ( ) ,
kyvernoV1 . ClusterPolicies ( ) ,
2024-01-17 20:00:15 +02:00
kyvernoV2beta1 . PolicyExceptions ( ) ,
2023-09-05 14:42:17 +03:00
vapInformer ,
2024-01-29 13:49:17 +02:00
vapBindingInformer ,
2023-09-05 14:42:17 +03:00
kubeInformer . Core ( ) . V1 ( ) . Namespaces ( ) ,
resourceReportController ,
backgroundScanInterval ,
configuration ,
jp ,
eventGenerator ,
policyReports ,
)
2023-01-18 14:38:47 +01:00
ctrls = append ( ctrls , internal . NewController (
backgroundscancontroller . ControllerName ,
2023-09-05 14:42:17 +03:00
backgroundScanController ,
backgroundScanWorkers ) ,
)
2023-01-18 14:38:47 +01:00
}
}
return ctrls , func ( ctx context . Context ) error {
for _ , warmup := range warmups {
if err := warmup ( ctx ) ; err != nil {
return err
}
}
return nil
}
}
func createrLeaderControllers (
2023-02-02 11:58:34 +01:00
eng engineapi . Engine ,
2023-01-18 14:38:47 +01:00
backgroundScan bool ,
admissionReports bool ,
2023-06-16 17:19:22 +02:00
aggregateReports bool ,
2023-07-25 21:22:51 -07:00
policyReports bool ,
2023-09-05 14:42:17 +03:00
validatingAdmissionPolicyReports bool ,
2023-01-18 14:38:47 +01:00
backgroundScanWorkers int ,
kubeInformer kubeinformers . SharedInformerFactory ,
kyvernoInformer kyvernoinformer . SharedInformerFactory ,
metadataInformer metadatainformers . SharedInformerFactory ,
kyvernoClient versioned . Interface ,
dynamicClient dclient . Interface ,
configuration config . Configuration ,
2023-04-13 13:29:40 +02:00
jp jmespath . Interface ,
2023-01-18 14:38:47 +01:00
eventGenerator event . Interface ,
backgroundScanInterval time . Duration ,
) ( [ ] internal . Controller , func ( context . Context ) error , error ) {
reportControllers , warmup := createReportControllers (
2023-02-02 11:58:34 +01:00
eng ,
2023-01-18 14:38:47 +01:00
backgroundScan ,
admissionReports ,
2023-06-16 17:19:22 +02:00
aggregateReports ,
2023-07-25 21:22:51 -07:00
policyReports ,
2023-09-05 14:42:17 +03:00
validatingAdmissionPolicyReports ,
2023-01-18 14:38:47 +01:00
backgroundScanWorkers ,
dynamicClient ,
kyvernoClient ,
metadataInformer ,
kubeInformer ,
kyvernoInformer ,
backgroundScanInterval ,
configuration ,
2023-04-13 13:29:40 +02:00
jp ,
2023-01-18 14:38:47 +01:00
eventGenerator ,
)
return reportControllers , warmup , nil
}
func main ( ) {
var (
2023-09-05 14:42:17 +03:00
backgroundScan bool
admissionReports bool
aggregateReports bool
policyReports bool
validatingAdmissionPolicyReports bool
reportsChunkSize int
backgroundScanWorkers int
backgroundScanInterval time . Duration
maxQueuedEvents int
omitEvents string
skipResourceFilters bool
2023-11-21 15:31:51 +05:30
maxAPICallResponseLength int64
2023-01-18 14:38:47 +01:00
)
flagset := flag . NewFlagSet ( "reports-controller" , flag . ExitOnError )
2023-06-21 00:53:58 +03:00
flagset . BoolVar ( & backgroundScan , "backgroundScan" , true , "Enable or disable background scan." )
2023-01-18 14:38:47 +01:00
flagset . BoolVar ( & admissionReports , "admissionReports" , true , "Enable or disable admission reports." )
2023-06-16 17:19:22 +02:00
flagset . BoolVar ( & aggregateReports , "aggregateReports" , true , "Enable or disable aggregated policy reports." )
2023-07-25 21:22:51 -07:00
flagset . BoolVar ( & policyReports , "policyReports" , true , "Enable or disable policy reports." )
2023-09-05 14:42:17 +03:00
flagset . BoolVar ( & validatingAdmissionPolicyReports , "validatingAdmissionPolicyReports" , false , "Enable or disable validating admission policy reports." )
2024-02-08 11:36:01 +01:00
flagset . IntVar ( & reportsChunkSize , "reportsChunkSize" , 0 , "Max number of results in generated reports, reports will be split accordingly if there are more results to be stored." )
2023-01-18 14:38:47 +01:00
flagset . IntVar ( & backgroundScanWorkers , "backgroundScanWorkers" , backgroundscancontroller . Workers , "Configure the number of background scan workers." )
flagset . DurationVar ( & backgroundScanInterval , "backgroundScanInterval" , time . Hour , "Configure background scan interval." )
flagset . IntVar ( & maxQueuedEvents , "maxQueuedEvents" , 1000 , "Maximum events to be queued." )
2024-01-31 00:41:13 +01:00
flagset . StringVar ( & omitEvents , "omitEvents" , "" , "Set this flag to a comma separated list of PolicyViolation, PolicyApplied, PolicyError, PolicySkipped to disable events, e.g. --omitEvents=PolicyApplied,PolicyViolation" )
2023-04-04 15:05:29 +02:00
flagset . BoolVar ( & skipResourceFilters , "skipResourceFilters" , true , "If true, resource filters wont be considered." )
2023-11-21 15:31:51 +05:30
flagset . Int64Var ( & maxAPICallResponseLength , "maxAPICallResponseLength" , 2 * 1000 * 1000 , "Maximum allowed response size from API Calls. A value of 0 bypasses checks (not recommended)." )
2023-01-18 14:38:47 +01:00
// config
appConfig := internal . NewConfiguration (
internal . WithProfiling ( ) ,
internal . WithMetrics ( ) ,
internal . WithTracing ( ) ,
internal . WithKubeconfig ( ) ,
2023-04-11 09:12:05 +02:00
internal . WithPolicyExceptions ( ) ,
internal . WithConfigMapCaching ( ) ,
2023-06-27 07:44:15 +02:00
internal . WithDeferredLoading ( ) ,
2023-04-11 16:37:46 +02:00
internal . WithCosign ( ) ,
2023-04-11 15:32:17 +02:00
internal . WithRegistryClient ( ) ,
2023-08-07 01:24:52 +05:30
internal . WithImageVerifyCache ( ) ,
2023-04-11 19:44:49 +02:00
internal . WithLeaderElection ( ) ,
2023-04-14 11:00:52 +02:00
internal . WithKyvernoClient ( ) ,
internal . WithDynamicClient ( ) ,
internal . WithMetadataClient ( ) ,
internal . WithKyvernoDynamicClient ( ) ,
2024-01-03 03:12:05 +02:00
internal . WithEventsClient ( ) ,
2024-02-01 15:44:05 +05:30
internal . WithApiServerClient ( ) ,
2023-01-18 14:38:47 +01:00
internal . WithFlagSets ( flagset ) ,
)
// parse flags
2023-04-13 07:01:11 +02:00
internal . ParseFlags (
appConfig ,
internal . WithDefaultQps ( 300 ) ,
internal . WithDefaultBurst ( 300 ) ,
)
2023-04-11 15:32:17 +02:00
// setup
ctx , setup , sdown := internal . Setup ( appConfig , "kyverno-reports-controller" , skipResourceFilters )
2023-01-18 14:38:47 +01:00
defer sdown ( )
2024-02-08 11:36:01 +01:00
// show warnings
if reportsChunkSize != 0 {
logger := setup . Logger . WithName ( "wanings" )
logger . Info ( "Warning: reportsChunkSize is deprecated and will be removed in 1.13." )
}
2023-01-18 14:38:47 +01:00
// THIS IS AN UGLY FIX
// ELSE KYAML IS NOT THREAD SAFE
kyamlopenapi . Schema ( )
2024-02-01 15:44:05 +05:30
if err := sanityChecks ( setup . ApiServerClient ) ; err != nil {
setup . Logger . Error ( err , "sanity checks failed" )
os . Exit ( 1 )
}
2023-05-02 17:49:45 +02:00
setup . Logger . Info ( "background scan interval" , "duration" , backgroundScanInterval . String ( ) )
2023-09-05 14:42:17 +03:00
// check if validating admission policies are registered in the API server
if validatingAdmissionPolicyReports {
groupVersion := schema . GroupVersion { Group : "admissionregistration.k8s.io" , Version : "v1alpha1" }
if _ , err := setup . KyvernoDynamicClient . GetKubeClient ( ) . Discovery ( ) . ServerResourcesForGroupVersion ( groupVersion . String ( ) ) ; err != nil {
setup . Logger . Error ( err , "validating admission policies aren't supported." )
os . Exit ( 1 )
}
}
2023-01-18 14:38:47 +01:00
// informer factories
2023-04-14 11:00:52 +02:00
kyvernoInformer := kyvernoinformer . NewSharedInformerFactory ( setup . KyvernoClient , resyncPeriod )
2024-01-31 00:08:15 +02:00
var wg sync . WaitGroup
2023-01-18 14:38:47 +01:00
eventGenerator := event . NewEventGenerator (
2024-01-03 03:12:05 +02:00
setup . EventsClient ,
2023-01-18 14:38:47 +01:00
logging . WithName ( "EventGenerator" ) ,
2024-01-31 00:41:13 +01:00
strings . Split ( omitEvents , "," ) ... ,
2023-01-18 14:38:47 +01:00
)
2024-01-31 00:08:15 +02:00
eventController := internal . NewController (
event . ControllerName ,
eventGenerator ,
event . Workers ,
)
2024-02-05 13:24:37 +02:00
gcstore := store . New ( )
2024-02-02 12:37:58 +01:00
gceController := internal . NewController (
globalcontextcontroller . ControllerName ,
globalcontextcontroller . NewController (
kyvernoInformer . Kyverno ( ) . V2alpha1 ( ) . GlobalContextEntries ( ) ,
setup . KyvernoDynamicClient ,
2024-02-23 12:34:04 +02:00
setup . KyvernoClient ,
2024-02-05 13:24:37 +02:00
gcstore ,
2024-02-23 12:34:04 +02:00
eventGenerator ,
2024-02-02 16:35:57 +01:00
maxAPICallResponseLength ,
2024-02-23 12:34:04 +02:00
false ,
2024-02-02 12:37:58 +01:00
) ,
globalcontextcontroller . Workers ,
)
2023-04-11 09:12:05 +02:00
// engine
engine := internal . NewEngine (
ctx ,
2023-04-11 14:05:20 +02:00
setup . Logger ,
setup . Configuration ,
setup . MetricsConfiguration ,
2023-04-13 13:29:40 +02:00
setup . Jp ,
2023-04-14 11:00:52 +02:00
setup . KyvernoDynamicClient ,
2023-04-11 15:32:17 +02:00
setup . RegistryClient ,
2023-08-07 01:24:52 +05:30
setup . ImageVerifyCacheClient ,
2023-04-11 14:05:20 +02:00
setup . KubeClient ,
2023-04-14 11:00:52 +02:00
setup . KyvernoClient ,
2023-06-16 19:07:08 +05:30
setup . RegistrySecretLister ,
2023-11-21 15:31:51 +05:30
apicall . NewAPICallConfiguration ( maxAPICallResponseLength ) ,
2024-02-05 13:24:37 +02:00
gcstore ,
2023-03-23 16:15:20 +01:00
)
2023-01-23 21:25:33 +01:00
// start informers and wait for cache sync
2023-04-11 15:32:17 +02:00
if ! internal . StartInformersAndWaitForCacheSync ( ctx , setup . Logger , kyvernoInformer ) {
2023-04-11 14:05:20 +02:00
setup . Logger . Error ( errors . New ( "failed to wait for cache sync" ) , "failed to wait for cache sync" )
2023-01-23 21:25:33 +01:00
os . Exit ( 1 )
}
2023-01-18 14:38:47 +01:00
// setup leader election
le , err := leaderelection . New (
2023-04-11 14:05:20 +02:00
setup . Logger . WithName ( "leader-election" ) ,
2023-01-18 14:38:47 +01:00
"kyverno-reports-controller" ,
config . KyvernoNamespace ( ) ,
2023-04-11 19:44:49 +02:00
setup . LeaderElectionClient ,
2023-01-18 14:38:47 +01:00
config . KyvernoPodName ( ) ,
2023-04-11 19:44:49 +02:00
internal . LeaderElectionRetryPeriod ( ) ,
2023-01-18 14:38:47 +01:00
func ( ctx context . Context ) {
2023-04-11 14:05:20 +02:00
logger := setup . Logger . WithName ( "leader" )
2023-01-18 14:38:47 +01:00
// create leader factories
2023-04-11 14:05:20 +02:00
kubeInformer := kubeinformers . NewSharedInformerFactory ( setup . KubeClient , resyncPeriod )
kubeKyvernoInformer := kubeinformers . NewSharedInformerFactoryWithOptions ( setup . KubeClient , resyncPeriod , kubeinformers . WithNamespace ( config . KyvernoNamespace ( ) ) )
2023-04-14 11:00:52 +02:00
kyvernoInformer := kyvernoinformer . NewSharedInformerFactory ( setup . KyvernoClient , resyncPeriod )
metadataInformer := metadatainformers . NewSharedInformerFactory ( setup . MetadataClient , 15 * time . Minute )
2023-01-18 14:38:47 +01:00
// create leader controllers
leaderControllers , warmup , err := createrLeaderControllers (
2023-04-11 09:12:05 +02:00
engine ,
2023-01-18 14:38:47 +01:00
backgroundScan ,
admissionReports ,
2023-06-16 17:19:22 +02:00
aggregateReports ,
2023-07-25 21:22:51 -07:00
policyReports ,
2023-09-05 14:42:17 +03:00
validatingAdmissionPolicyReports ,
2023-01-18 14:38:47 +01:00
backgroundScanWorkers ,
kubeInformer ,
kyvernoInformer ,
metadataInformer ,
2023-04-14 11:00:52 +02:00
setup . KyvernoClient ,
setup . KyvernoDynamicClient ,
2023-04-11 14:05:20 +02:00
setup . Configuration ,
2023-04-13 13:29:40 +02:00
setup . Jp ,
2023-01-18 14:38:47 +01:00
eventGenerator ,
backgroundScanInterval ,
)
if err != nil {
logger . Error ( err , "failed to create leader controllers" )
os . Exit ( 1 )
}
// start informers and wait for cache sync
2023-02-09 16:53:27 +01:00
if ! internal . StartInformersAndWaitForCacheSync ( ctx , logger , kyvernoInformer , kubeInformer , kubeKyvernoInformer ) {
2023-01-18 14:38:47 +01:00
logger . Error ( errors . New ( "failed to wait for cache sync" ) , "failed to wait for cache sync" )
os . Exit ( 1 )
}
internal . StartInformers ( ctx , metadataInformer )
2023-02-09 16:53:27 +01:00
if ! internal . CheckCacheSync ( logger , metadataInformer . WaitForCacheSync ( ctx . Done ( ) ) ) {
2023-01-18 14:38:47 +01:00
logger . Error ( errors . New ( "failed to wait for cache sync" ) , "failed to wait for cache sync" )
os . Exit ( 1 )
}
if err := warmup ( ctx ) ; err != nil {
logger . Error ( err , "failed to run warmup" )
os . Exit ( 1 )
}
// start leader controllers
var wg sync . WaitGroup
for _ , controller := range leaderControllers {
controller . Run ( ctx , logger . WithName ( "controllers" ) , & wg )
}
// wait all controllers shut down
wg . Wait ( )
} ,
nil ,
)
if err != nil {
2023-04-11 14:05:20 +02:00
setup . Logger . Error ( err , "failed to initialize leader election" )
2023-01-18 14:38:47 +01:00
os . Exit ( 1 )
}
2024-01-31 00:08:15 +02:00
// start non leader controllers
eventController . Run ( ctx , setup . Logger , & wg )
2024-02-02 12:37:58 +01:00
gceController . Run ( ctx , setup . Logger , & wg )
2024-01-31 00:08:15 +02:00
// start leader election
2023-04-03 17:17:44 +02:00
le . Run ( ctx )
2024-01-31 00:08:15 +02:00
// wait for everything to shut down and exit
2023-04-03 17:17:44 +02:00
wg . Wait ( )
2023-01-18 14:38:47 +01:00
}