2019-02-06 14:52:09 +02:00
package main
import (
2019-03-04 20:40:02 +02:00
"flag"
2019-08-14 18:40:33 -07:00
"time"
2019-02-21 20:31:18 +02:00
2019-05-31 17:59:36 -07:00
"github.com/golang/glog"
2019-08-19 10:00:39 -07:00
kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned"
kyvernoinformer "github.com/nirmata/kyverno/pkg/client/informers/externalversions"
2019-05-31 17:59:36 -07:00
"github.com/nirmata/kyverno/pkg/config"
2019-05-29 14:12:09 -07:00
client "github.com/nirmata/kyverno/pkg/dclient"
2019-05-21 11:00:09 -07:00
event "github.com/nirmata/kyverno/pkg/event"
2019-08-14 14:56:53 -07:00
"github.com/nirmata/kyverno/pkg/namespace"
2019-08-07 16:14:33 -07:00
"github.com/nirmata/kyverno/pkg/policy"
2019-08-08 15:36:19 -07:00
"github.com/nirmata/kyverno/pkg/policyviolation"
2019-08-14 14:56:53 -07:00
"github.com/nirmata/kyverno/pkg/utils"
2019-08-21 01:07:32 -07:00
"github.com/nirmata/kyverno/pkg/webhookconfig"
2019-05-21 11:00:09 -07:00
"github.com/nirmata/kyverno/pkg/webhooks"
2019-08-21 01:07:32 -07:00
kubeinformers "k8s.io/client-go/informers"
2019-05-10 00:05:21 -07:00
"k8s.io/sample-controller/pkg/signals"
2019-02-11 19:49:27 +02:00
)
var (
2019-10-28 15:23:52 -05:00
kubeconfig string
serverIP string
2019-10-18 17:38:46 -07:00
cpu bool
memory bool
webhookTimeout int
2019-10-29 10:56:28 -07:00
//TODO: this has been added to backward support command line arguments
// will be removed in future and the configuration will be set only via configmaps
filterK8Resources string
2019-02-06 14:52:09 +02:00
)
2019-08-20 17:01:47 -07:00
// TODO: tune resync time differently for each informer
2019-08-19 19:26:51 -07:00
const defaultReSyncTime = 10 * time . Second
2019-03-15 19:03:55 +02:00
func main ( ) {
2019-05-31 17:59:36 -07:00
defer glog . Flush ( )
printVersionInfo ( )
2019-08-20 23:51:34 -07:00
// profile cpu and memory consuption
2019-08-02 11:18:02 -07:00
prof = enableProfiling ( cpu , memory )
2019-10-28 18:37:41 -07:00
// cleanUp Channel
2019-08-27 16:44:10 -07:00
cleanUp := make ( chan struct { } )
2019-10-18 17:38:46 -07:00
// SIGINT & SIGTERM channel
stopCh := signals . SetupSignalHandler ( )
2019-08-09 16:55:43 -07:00
// CLIENT CONFIG
2019-03-15 19:03:55 +02:00
clientConfig , err := createClientConfig ( kubeconfig )
2019-03-04 20:40:02 +02:00
if err != nil {
2019-05-31 17:59:36 -07:00
glog . Fatalf ( "Error building kubeconfig: %v\n" , err )
2019-03-04 20:40:02 +02:00
}
2019-08-09 16:55:43 -07:00
// KYVENO CRD CLIENT
// access CRD resources
// - Policy
// - PolicyViolation
2019-08-19 10:00:39 -07:00
pclient , err := kyvernoclient . NewForConfig ( clientConfig )
2019-03-04 20:40:02 +02:00
if err != nil {
2019-05-31 17:59:36 -07:00
glog . Fatalf ( "Error creating client: %v\n" , err )
2019-03-04 20:40:02 +02:00
}
2019-08-20 23:51:34 -07:00
2019-08-09 19:12:50 -07:00
// DYNAMIC CLIENT
// - client for all registered resources
client , err := client . NewClient ( clientConfig )
2019-03-04 20:40:02 +02:00
if err != nil {
2019-08-09 19:12:50 -07:00
glog . Fatalf ( "Error creating client: %v\n" , err )
2019-03-04 20:40:02 +02:00
}
2019-08-07 18:01:28 -07:00
2019-08-22 11:18:13 -07:00
// CRD CHECK
// - verify if the CRD for Policy & PolicyViolation are avialalbe
if ! utils . CRDInstalled ( client . DiscoveryClient ) {
glog . Fatalf ( "Required CRDs unavailable" )
}
2019-08-20 23:56:47 -07:00
// KUBERNETES CLIENT
kubeClient , err := utils . NewKubeClient ( clientConfig )
if err != nil {
glog . Fatalf ( "Error creating kubernetes client: %v\n" , err )
}
2019-08-21 01:07:32 -07:00
// WERBHOOK REGISTRATION CLIENT
webhookRegistrationClient , err := webhookconfig . NewWebhookRegistrationClient ( clientConfig , client , serverIP , int32 ( webhookTimeout ) )
if err != nil {
glog . Fatalf ( "Unable to register admission webhooks on cluster: %v\n" , err )
}
2019-08-09 16:55:43 -07:00
// KYVERNO CRD INFORMER
// watches CRD resources:
// - Policy
// - PolicyVolation
2019-08-14 18:40:33 -07:00
// - cache resync time: 10 seconds
pInformer := kyvernoinformer . NewSharedInformerFactoryWithOptions ( pclient , 10 * time . Second )
2019-08-20 23:51:34 -07:00
2019-08-21 01:07:32 -07:00
// KUBERNETES RESOURCES INFORMER
2019-08-21 00:23:14 -07:00
// watches namespace resource
// - cache resync time: 10 seconds
kubeInformer := kubeinformers . NewSharedInformerFactoryWithOptions ( kubeClient , 10 * time . Second )
2019-08-19 19:26:51 -07:00
2019-10-18 17:38:46 -07:00
// Configuration Data
// dyamically load the configuration from configMap
// - resource filters
// if the configMap is update, the configuration will be updated :D
2019-10-29 10:56:28 -07:00
configData := config . NewConfigData ( kubeClient , kubeInformer . Core ( ) . V1 ( ) . ConfigMaps ( ) , filterK8Resources )
2019-10-25 18:49:26 -05:00
2019-08-13 13:15:04 -07:00
// EVENT GENERATOR
2019-08-20 23:51:34 -07:00
// - generate event with retry mechanism
2019-09-03 14:51:51 -07:00
egen := event . NewEventGenerator ( client , pInformer . Kyverno ( ) . V1alpha1 ( ) . ClusterPolicies ( ) )
2019-08-09 16:55:43 -07:00
// POLICY CONTROLLER
// - reconciliation policy and policy violation
2019-08-14 10:01:47 -07:00
// - process policy on existing resources
2019-08-20 17:35:55 -07:00
// - status aggregator: recieves stats when a policy is applied
2019-08-20 23:51:34 -07:00
// & updates the policy status
2019-10-18 17:38:46 -07:00
pc , err := policy . NewPolicyController ( pclient , client , pInformer . Kyverno ( ) . V1alpha1 ( ) . ClusterPolicies ( ) , pInformer . Kyverno ( ) . V1alpha1 ( ) . ClusterPolicyViolations ( ) , egen , kubeInformer . Admissionregistration ( ) . V1beta1 ( ) . MutatingWebhookConfigurations ( ) , webhookRegistrationClient , configData )
2019-08-07 18:01:28 -07:00
if err != nil {
2019-08-07 16:14:33 -07:00
glog . Fatalf ( "error creating policy controller: %v\n" , err )
2019-08-07 18:01:28 -07:00
}
2019-08-09 16:55:43 -07:00
// POLICY VIOLATION CONTROLLER
2019-08-20 23:51:34 -07:00
// policy violation cleanup if the corresponding resource is deleted
2019-08-09 16:55:43 -07:00
// status: lastUpdatTime
2019-09-03 14:51:51 -07:00
pvc , err := policyviolation . NewPolicyViolationController ( client , pclient , pInformer . Kyverno ( ) . V1alpha1 ( ) . ClusterPolicies ( ) , pInformer . Kyverno ( ) . V1alpha1 ( ) . ClusterPolicyViolations ( ) )
2019-08-08 15:36:19 -07:00
if err != nil {
glog . Fatalf ( "error creating policy violation controller: %v\n" , err )
2019-08-07 18:01:28 -07:00
}
2019-08-14 14:56:53 -07:00
// GENERATE CONTROLLER
// - watches for Namespace resource and generates resource based on the policy generate rule
2019-10-18 17:38:46 -07:00
nsc := namespace . NewNamespaceController ( pclient , client , kubeInformer . Core ( ) . V1 ( ) . Namespaces ( ) , pInformer . Kyverno ( ) . V1alpha1 ( ) . ClusterPolicies ( ) , pInformer . Kyverno ( ) . V1alpha1 ( ) . ClusterPolicyViolations ( ) , pc . GetPolicyStatusAggregator ( ) , egen , configData )
2019-08-14 14:56:53 -07:00
2019-08-20 23:56:47 -07:00
// CONFIGURE CERTIFICATES
2019-06-05 17:43:59 -07:00
tlsPair , err := initTLSPemPair ( clientConfig , client )
2019-03-22 22:11:55 +02:00
if err != nil {
2019-05-31 17:59:36 -07:00
glog . Fatalf ( "Failed to initialize TLS key/certificate pair: %v\n" , err )
2019-03-04 20:40:02 +02:00
}
2019-05-14 18:10:25 +03:00
2019-08-20 23:51:34 -07:00
// WEBHOOK REGISTRATION
// - validationwebhookconfiguration (Policy)
// - mutatingwebhookconfiguration (All resources)
// webhook confgiuration is also generated dynamically in the policy controller
// based on the policy resources created
2019-08-14 19:00:37 -07:00
if err = webhookRegistrationClient . Register ( ) ; err != nil {
glog . Fatalf ( "Failed registering Admission Webhooks: %v\n" , err )
}
2019-08-20 23:51:34 -07:00
// WEBHOOOK
// - https server to provide endpoints called based on rules defined in Mutating & Validation webhook configuration
// - reports the results based on the response from the policy engine:
// -- annotations on resources with update details on mutation JSON patches
// -- generate policy violation resource
// -- generate events on policy and resource
2019-10-18 17:38:46 -07:00
server , err := webhooks . NewWebhookServer ( pclient , client , tlsPair , pInformer . Kyverno ( ) . V1alpha1 ( ) . ClusterPolicies ( ) , pInformer . Kyverno ( ) . V1alpha1 ( ) . ClusterPolicyViolations ( ) , egen , webhookRegistrationClient , pc . GetPolicyStatusAggregator ( ) , configData , cleanUp )
2019-05-14 18:10:25 +03:00
if err != nil {
2019-08-07 18:01:28 -07:00
glog . Fatalf ( "Unable to create webhook server: %v\n" , err )
2019-05-14 18:10:25 +03:00
}
2019-08-20 23:51:34 -07:00
// Start the components
2019-08-07 16:14:33 -07:00
pInformer . Start ( stopCh )
2019-08-14 14:56:53 -07:00
kubeInformer . Start ( stopCh )
2019-10-25 18:49:26 -05:00
if err := configData . Run ( kubeInformer . Core ( ) . V1 ( ) . ConfigMaps ( ) , stopCh ) ; err != nil {
glog . Fatalf ( "Unable loading dynamic configuration: %v\n" , err )
}
2019-08-07 16:14:33 -07:00
go pc . Run ( 1 , stopCh )
2019-08-08 15:36:19 -07:00
go pvc . Run ( 1 , stopCh )
2019-08-09 13:41:56 -07:00
go egen . Run ( 1 , stopCh )
2019-08-14 14:56:53 -07:00
go nsc . Run ( 1 , stopCh )
2019-08-09 16:55:43 -07:00
//TODO add WG for the go routines?
2019-05-14 18:10:25 +03:00
server . RunAsync ( )
2019-08-02 11:18:02 -07:00
2019-03-04 20:40:02 +02:00
<- stopCh
2019-08-02 11:18:02 -07:00
disableProfiling ( prof )
server . Stop ( )
2019-08-27 16:44:10 -07:00
// resource cleanup
// remove webhook configurations
<- cleanUp
2019-02-11 19:49:27 +02:00
}
func init ( ) {
2019-08-02 11:18:02 -07:00
// profiling feature gate
// cpu and memory profiling cannot be enabled at same time
// if both cpu and memory are enabled
// by default is to profile cpu
flag . BoolVar ( & cpu , "cpu" , false , "cpu profilling feature gate, default to false || cpu and memory profiling cannot be enabled at the same time" )
flag . BoolVar ( & memory , "memory" , false , "memory profilling feature gate, default to false || cpu and memory profiling cannot be enabled at the same time" )
2019-10-29 10:56:28 -07:00
//TODO: this has been added to backward support command line arguments
// will be removed in future and the configuration will be set only via configmaps
flag . StringVar ( & filterK8Resources , "filterK8Resources" , "" , "k8 resource in format [kind,namespace,name] where policy is not evaluated by the admission webhook. example --filterKind \"[Deployment, kyverno, kyverno]\" --filterKind \"[Deployment, kyverno, kyverno],[Events, *, *]\"" )
2019-10-29 11:31:45 -07:00
flag . IntVar ( & webhookTimeout , "webhooktimeout" , 3 , "timeout for webhook configurations" )
2019-03-04 20:40:02 +02:00
flag . StringVar ( & kubeconfig , "kubeconfig" , "" , "Path to a kubeconfig. Only required if out-of-cluster." )
2019-06-10 18:10:51 -07:00
flag . StringVar ( & serverIP , "serverIP" , "" , "IP address where Kyverno controller runs. Only required if out-of-cluster." )
2019-05-31 17:59:36 -07:00
config . LogDefaultFlags ( )
2019-03-15 19:03:55 +02:00
flag . Parse ( )
2019-06-05 17:43:59 -07:00
}