2022-11-14 12:00:40 +01:00
package main
2022-11-14 18:30:12 +01:00
import (
2022-12-12 19:39:29 +01:00
"context"
"errors"
2022-12-07 11:30:47 +01:00
"flag"
2022-11-14 18:30:12 +01:00
"os"
2022-11-25 15:29:45 +05:30
"sync"
2022-11-14 18:30:12 +01:00
"time"
2023-08-02 20:17:40 +05:30
"github.com/kyverno/kyverno/api/kyverno"
2023-08-03 06:48:10 +02:00
policyhandlers "github.com/kyverno/kyverno/cmd/cleanup-controller/handlers/admission/policy"
resourcehandlers "github.com/kyverno/kyverno/cmd/cleanup-controller/handlers/admission/resource"
2022-11-18 15:21:15 +01:00
"github.com/kyverno/kyverno/cmd/internal"
2023-08-28 21:48:48 +05:30
"github.com/kyverno/kyverno/pkg/auth/checker"
2022-11-25 15:29:45 +05:30
kyvernoinformer "github.com/kyverno/kyverno/pkg/client/informers/externalversions"
2022-11-14 18:30:12 +01:00
"github.com/kyverno/kyverno/pkg/config"
2022-12-13 16:43:17 +01:00
"github.com/kyverno/kyverno/pkg/controllers/certmanager"
2022-11-25 15:29:45 +05:30
"github.com/kyverno/kyverno/pkg/controllers/cleanup"
2023-03-16 18:17:21 +01:00
genericloggingcontroller "github.com/kyverno/kyverno/pkg/controllers/generic/logging"
2022-12-22 07:13:32 +01:00
genericwebhookcontroller "github.com/kyverno/kyverno/pkg/controllers/generic/webhook"
2024-02-02 12:37:58 +01:00
globalcontextcontroller "github.com/kyverno/kyverno/pkg/controllers/globalcontext"
2023-08-02 18:24:26 +02:00
ttlcontroller "github.com/kyverno/kyverno/pkg/controllers/ttl"
2023-07-18 13:01:09 +03:00
"github.com/kyverno/kyverno/pkg/event"
2024-02-02 15:35:24 +01:00
"github.com/kyverno/kyverno/pkg/globalcontext/store"
2023-06-22 14:14:53 +02:00
"github.com/kyverno/kyverno/pkg/informers"
2022-12-12 19:39:29 +01:00
"github.com/kyverno/kyverno/pkg/leaderelection"
2023-07-18 13:01:09 +03:00
"github.com/kyverno/kyverno/pkg/logging"
2022-12-12 19:39:29 +01:00
"github.com/kyverno/kyverno/pkg/tls"
2024-01-30 09:08:30 +02:00
"github.com/kyverno/kyverno/pkg/toggle"
2024-02-01 15:44:05 +05:30
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
2022-12-09 18:12:37 +01:00
"github.com/kyverno/kyverno/pkg/webhooks"
2022-12-22 07:13:32 +01:00
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
2022-11-14 18:30:12 +01:00
corev1 "k8s.io/api/core/v1"
2024-02-01 15:44:05 +05:30
apiserver "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
2023-08-02 20:17:40 +05:30
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2022-11-14 18:30:12 +01:00
kubeinformers "k8s.io/client-go/informers"
)
const (
2023-08-02 20:17:40 +05:30
resyncPeriod = 15 * time . Minute
webhookWorkers = 2
policyWebhookControllerName = "policy-webhook-controller"
ttlWebhookControllerName = "ttl-webhook-controller"
2022-11-14 18:30:12 +01:00
)
2023-08-28 16:05:49 +02:00
var (
caSecretName string
tlsSecretName string
)
2022-12-09 18:12:37 +01:00
// TODO:
2022-12-12 19:39:29 +01:00
// - helm review labels / selectors
2022-12-09 18:12:37 +01:00
// - implement probes
// - supports certs in cronjob
type probes struct { }
2023-06-21 15:35:43 +02:00
func ( probes ) IsReady ( context . Context ) bool {
2022-12-09 18:12:37 +01:00
return true
}
2023-06-21 15:35:43 +02:00
func ( probes ) IsLive ( context . Context ) bool {
2022-12-09 18:12:37 +01:00
return true
}
2024-02-01 15:44:05 +05:30
func sanityChecks ( apiserverClient apiserver . Interface ) error {
return kubeutils . CRDsInstalled ( apiserverClient , "cleanuppolicies.kyverno.io" , "clustercleanuppolicies.kyverno.io" )
}
2022-11-14 12:00:40 +01:00
func main ( ) {
2022-12-09 18:12:37 +01:00
var (
2024-02-02 16:35:57 +01:00
dumpPayload bool
serverIP string
servicePort int
webhookServerPort int
maxQueuedEvents int
interval time . Duration
renewBefore time . Duration
maxAPICallResponseLength int64
2022-12-09 18:12:37 +01:00
)
2022-12-07 11:30:47 +01:00
flagset := flag . NewFlagSet ( "cleanup-controller" , flag . ExitOnError )
2022-12-09 18:12:37 +01:00
flagset . BoolVar ( & dumpPayload , "dumpPayload" , false , "Set this flag to activate/deactivate debug mode." )
2022-12-22 07:13:32 +01:00
flagset . StringVar ( & serverIP , "serverIP" , "" , "IP address where Kyverno controller runs. Only required if out-of-cluster." )
2023-01-29 00:54:29 +01:00
flagset . IntVar ( & servicePort , "servicePort" , 443 , "Port used by the Kyverno Service resource and for webhook configurations." )
2023-11-17 15:19:53 +01:00
flagset . IntVar ( & webhookServerPort , "webhookServerPort" , 9443 , "Port used by the webhook server." )
2023-07-18 13:01:09 +03:00
flagset . IntVar ( & maxQueuedEvents , "maxQueuedEvents" , 1000 , "Maximum events to be queued." )
2023-08-02 20:17:40 +05:30
flagset . DurationVar ( & interval , "ttlReconciliationInterval" , time . Minute , "Set this flag to set the interval after which the resource controller reconciliation should occur" )
2024-01-30 09:08:30 +02:00
flagset . Func ( toggle . ProtectManagedResourcesFlagName , toggle . ProtectManagedResourcesDescription , toggle . ProtectManagedResources . Parse )
2023-08-28 16:05:49 +02:00
flagset . StringVar ( & caSecretName , "caSecretName" , "" , "Name of the secret containing CA." )
flagset . StringVar ( & tlsSecretName , "tlsSecretName" , "" , "Name of the secret containing TLS pair." )
2023-12-06 15:37:01 +02:00
flagset . DurationVar ( & renewBefore , "renewBefore" , 15 * 24 * time . Hour , "The certificate renewal time before expiration" )
2024-02-02 16:35:57 +01:00
flagset . Int64Var ( & maxAPICallResponseLength , "maxAPICallResponseLength" , 2 * 1000 * 1000 , "Maximum allowed response size from API Calls. A value of 0 bypasses checks (not recommended)." )
2022-11-18 15:21:15 +01:00
// config
2022-11-23 11:36:15 +01:00
appConfig := internal . NewConfiguration (
internal . WithProfiling ( ) ,
2022-11-29 10:16:07 +01:00
internal . WithMetrics ( ) ,
2022-11-23 11:36:15 +01:00
internal . WithTracing ( ) ,
internal . WithKubeconfig ( ) ,
2023-04-11 19:44:49 +02:00
internal . WithLeaderElection ( ) ,
2023-04-14 11:00:52 +02:00
internal . WithKyvernoClient ( ) ,
internal . WithKyvernoDynamicClient ( ) ,
2024-01-03 03:12:05 +02:00
internal . WithEventsClient ( ) ,
2023-06-26 16:57:23 +02:00
internal . WithConfigMapCaching ( ) ,
2023-06-27 07:44:15 +02:00
internal . WithDeferredLoading ( ) ,
2023-08-02 20:17:40 +05:30
internal . WithMetadataClient ( ) ,
2024-02-01 15:44:05 +05:30
internal . WithApiServerClient ( ) ,
2023-08-28 16:05:49 +02:00
internal . WithFlagSets ( flagset ) ,
2022-11-23 11:36:15 +01:00
)
2022-11-14 18:30:12 +01:00
// parse flags
2022-11-24 20:57:01 +01:00
internal . ParseFlags ( appConfig )
2024-01-31 00:08:15 +02:00
var wg sync . WaitGroup
2024-06-10 11:11:07 +02:00
func ( ) {
// setup
ctx , setup , sdown := internal . Setup ( appConfig , "kyverno-cleanup-controller" , false )
defer sdown ( )
if caSecretName == "" {
setup . Logger . Error ( errors . New ( "exiting... caSecretName is a required flag" ) , "exiting... caSecretName is a required flag" )
os . Exit ( 1 )
}
if tlsSecretName == "" {
setup . Logger . Error ( errors . New ( "exiting... tlsSecretName is a required flag" ) , "exiting... tlsSecretName is a required flag" )
os . Exit ( 1 )
}
if err := sanityChecks ( setup . ApiServerClient ) ; err != nil {
setup . Logger . Error ( err , "sanity checks failed" )
os . Exit ( 1 )
}
// certificates informers
caSecret := informers . NewSecretInformer ( setup . KubeClient , config . KyvernoNamespace ( ) , caSecretName , resyncPeriod )
tlsSecret := informers . NewSecretInformer ( setup . KubeClient , config . KyvernoNamespace ( ) , tlsSecretName , resyncPeriod )
if ! informers . StartInformersAndWaitForCacheSync ( ctx , setup . Logger , caSecret , tlsSecret ) {
setup . Logger . Error ( errors . New ( "failed to wait for cache sync" ) , "failed to wait for cache sync" )
os . Exit ( 1 )
}
checker := checker . NewSelfChecker ( setup . KubeClient . AuthorizationV1 ( ) . SelfSubjectAccessReviews ( ) )
// informer factories
kubeInformer := kubeinformers . NewSharedInformerFactoryWithOptions ( setup . KubeClient , resyncPeriod )
kyvernoInformer := kyvernoinformer . NewSharedInformerFactory ( setup . KyvernoClient , resyncPeriod )
// listers
nsLister := kubeInformer . Core ( ) . V1 ( ) . Namespaces ( ) . Lister ( )
// log policy changes
genericloggingcontroller . NewController (
setup . Logger . WithName ( "cleanup-policy" ) ,
"CleanupPolicy" ,
kyvernoInformer . Kyverno ( ) . V2beta1 ( ) . CleanupPolicies ( ) ,
genericloggingcontroller . CheckGeneration ,
)
genericloggingcontroller . NewController (
setup . Logger . WithName ( "cluster-cleanup-policy" ) ,
"ClusterCleanupPolicy" ,
kyvernoInformer . Kyverno ( ) . V2beta1 ( ) . ClusterCleanupPolicies ( ) ,
genericloggingcontroller . CheckGeneration ,
)
eventGenerator := event . NewEventGenerator (
setup . EventsClient ,
logging . WithName ( "EventGenerator" ) ,
maxQueuedEvents ,
)
eventController := internal . NewController (
event . ControllerName ,
2024-02-23 12:34:04 +02:00
eventGenerator ,
2024-06-10 11:11:07 +02:00
event . Workers ,
)
gcstore := store . New ( )
gceController := internal . NewController (
globalcontextcontroller . ControllerName ,
globalcontextcontroller . NewController (
kyvernoInformer . Kyverno ( ) . V2alpha1 ( ) . GlobalContextEntries ( ) ,
setup . KyvernoDynamicClient ,
setup . KyvernoClient ,
gcstore ,
eventGenerator ,
maxAPICallResponseLength ,
false ,
) ,
globalcontextcontroller . Workers ,
)
// start informers and wait for cache sync
if ! internal . StartInformersAndWaitForCacheSync ( ctx , setup . Logger , kubeInformer , kyvernoInformer ) {
os . Exit ( 1 )
}
// setup leader election
le , err := leaderelection . New (
setup . Logger . WithName ( "leader-election" ) ,
"kyverno-cleanup-controller" ,
config . KyvernoNamespace ( ) ,
setup . LeaderElectionClient ,
config . KyvernoPodName ( ) ,
internal . LeaderElectionRetryPeriod ( ) ,
func ( ctx context . Context ) {
logger := setup . Logger . WithName ( "leader" )
// informer factories
kubeInformer := kubeinformers . NewSharedInformerFactoryWithOptions ( setup . KubeClient , resyncPeriod )
kyvernoInformer := kyvernoinformer . NewSharedInformerFactory ( setup . KyvernoClient , resyncPeriod )
2023-09-26 13:02:17 +03:00
2024-06-10 11:11:07 +02:00
cmResolver := internal . NewConfigMapResolver ( ctx , setup . Logger , setup . KubeClient , resyncPeriod )
2023-09-26 13:02:17 +03:00
2024-06-10 11:11:07 +02:00
// controllers
renewer := tls . NewCertRenewer (
setup . KubeClient . CoreV1 ( ) . Secrets ( config . KyvernoNamespace ( ) ) ,
tls . CertRenewalInterval ,
tls . CAValidityDuration ,
tls . TLSValidityDuration ,
renewBefore ,
serverIP ,
config . KyvernoServiceName ( ) ,
config . DnsNames ( config . KyvernoServiceName ( ) , config . KyvernoNamespace ( ) ) ,
config . KyvernoNamespace ( ) ,
2023-08-28 16:05:49 +02:00
caSecretName ,
tlsSecretName ,
2024-06-10 11:11:07 +02:00
)
certController := internal . NewController (
certmanager . ControllerName ,
certmanager . NewController (
caSecret ,
tlsSecret ,
renewer ,
caSecretName ,
tlsSecretName ,
config . KyvernoNamespace ( ) ,
) ,
certmanager . Workers ,
)
policyValidatingWebhookController := internal . NewController (
2023-08-02 20:17:40 +05:30
policyWebhookControllerName ,
2024-06-10 11:11:07 +02:00
genericwebhookcontroller . NewController (
policyWebhookControllerName ,
setup . KubeClient . AdmissionregistrationV1 ( ) . ValidatingWebhookConfigurations ( ) ,
kubeInformer . Admissionregistration ( ) . V1 ( ) . ValidatingWebhookConfigurations ( ) ,
caSecret ,
config . CleanupValidatingWebhookConfigurationName ,
config . CleanupValidatingWebhookServicePath ,
serverIP ,
int32 ( servicePort ) ,
int32 ( webhookServerPort ) ,
nil ,
[ ] admissionregistrationv1 . RuleWithOperations {
{
Rule : admissionregistrationv1 . Rule {
APIGroups : [ ] string { "kyverno.io" } ,
2024-06-14 11:39:36 +02:00
APIVersions : [ ] string { "v2beta1" } ,
2024-06-10 11:11:07 +02:00
Resources : [ ] string {
"cleanuppolicies/*" ,
"clustercleanuppolicies/*" ,
} ,
} ,
Operations : [ ] admissionregistrationv1 . OperationType {
admissionregistrationv1 . Create ,
admissionregistrationv1 . Update ,
2023-08-02 20:17:40 +05:30
} ,
2022-12-22 07:13:32 +01:00
} ,
} ,
2024-06-10 11:11:07 +02:00
genericwebhookcontroller . Fail ,
genericwebhookcontroller . None ,
setup . Configuration ,
caSecretName ,
) ,
webhookWorkers ,
)
ttlWebhookController := internal . NewController (
2023-08-02 20:17:40 +05:30
ttlWebhookControllerName ,
2024-06-10 11:11:07 +02:00
genericwebhookcontroller . NewController (
ttlWebhookControllerName ,
setup . KubeClient . AdmissionregistrationV1 ( ) . ValidatingWebhookConfigurations ( ) ,
kubeInformer . Admissionregistration ( ) . V1 ( ) . ValidatingWebhookConfigurations ( ) ,
caSecret ,
config . TtlValidatingWebhookConfigurationName ,
config . TtlValidatingWebhookServicePath ,
serverIP ,
int32 ( servicePort ) ,
int32 ( webhookServerPort ) ,
& metav1 . LabelSelector {
MatchExpressions : [ ] metav1 . LabelSelectorRequirement {
{
Key : kyverno . LabelCleanupTtl ,
Operator : metav1 . LabelSelectorOpExists ,
} ,
2023-08-02 20:17:40 +05:30
} ,
} ,
2024-06-10 11:11:07 +02:00
[ ] admissionregistrationv1 . RuleWithOperations {
{
Rule : admissionregistrationv1 . Rule {
APIGroups : [ ] string { "*" } ,
APIVersions : [ ] string { "*" } ,
Resources : [ ] string { "*" } ,
} ,
Operations : [ ] admissionregistrationv1 . OperationType {
admissionregistrationv1 . Create ,
admissionregistrationv1 . Update ,
} ,
2023-08-02 20:17:40 +05:30
} ,
} ,
2024-06-10 11:11:07 +02:00
genericwebhookcontroller . Ignore ,
genericwebhookcontroller . None ,
setup . Configuration ,
caSecretName ,
) ,
webhookWorkers ,
)
cleanupController := internal . NewController (
cleanup . ControllerName ,
cleanup . NewController (
setup . KyvernoDynamicClient ,
setup . KyvernoClient ,
kyvernoInformer . Kyverno ( ) . V2beta1 ( ) . ClusterCleanupPolicies ( ) ,
kyvernoInformer . Kyverno ( ) . V2beta1 ( ) . CleanupPolicies ( ) ,
nsLister ,
setup . Configuration ,
cmResolver ,
setup . Jp ,
eventGenerator ,
gcstore ,
) ,
cleanup . Workers ,
)
ttlManagerController := internal . NewController (
ttlcontroller . ControllerName ,
ttlcontroller . NewManager (
setup . MetadataClient ,
setup . KubeClient . Discovery ( ) ,
checker ,
interval ,
) ,
ttlcontroller . Workers ,
)
// start informers and wait for cache sync
if ! internal . StartInformersAndWaitForCacheSync ( ctx , logger , kyvernoInformer , kubeInformer ) {
logger . Error ( errors . New ( "failed to wait for cache sync" ) , "failed to wait for cache sync" )
os . Exit ( 1 )
}
// start leader controllers
var wg sync . WaitGroup
certController . Run ( ctx , logger , & wg )
policyValidatingWebhookController . Run ( ctx , logger , & wg )
ttlWebhookController . Run ( ctx , logger , & wg )
cleanupController . Run ( ctx , logger , & wg )
ttlManagerController . Run ( ctx , logger , & wg )
wg . Wait ( )
} ,
nil ,
)
if err != nil {
setup . Logger . Error ( err , "failed to initialize leader election" )
os . Exit ( 1 )
}
// create handlers
policyHandlers := policyhandlers . New ( setup . KyvernoDynamicClient )
resourceHandlers := resourcehandlers . New ( checker )
// create server
server := NewServer (
func ( ) ( [ ] byte , [ ] byte , error ) {
secret , err := tlsSecret . Lister ( ) . Secrets ( config . KyvernoNamespace ( ) ) . Get ( tlsSecretName )
if err != nil {
return nil , nil , err
}
return secret . Data [ corev1 . TLSCertKey ] , secret . Data [ corev1 . TLSPrivateKeyKey ] , nil
} ,
policyHandlers . Validate ,
resourceHandlers . Validate ,
setup . MetricsManager ,
webhooks . DebugModeOptions {
DumpPayload : dumpPayload ,
} ,
probes { } ,
setup . Configuration ,
)
// start server
server . Run ( )
defer server . Stop ( )
// start non leader controllers
eventController . Run ( ctx , setup . Logger , & wg )
gceController . Run ( ctx , setup . Logger , & wg )
// start leader election
le . Run ( ctx )
} ( )
2024-01-31 00:08:15 +02:00
// wait for everything to shut down and exit
wg . Wait ( )
2022-11-14 12:00:40 +01:00
}