2019-08-07 16:14:33 -07:00
|
|
|
package policy
|
|
|
|
|
|
|
|
import (
|
2020-11-09 11:26:12 -08:00
|
|
|
"context"
|
2021-01-04 19:10:36 +05:30
|
|
|
"crypto/rand"
|
2020-09-04 03:04:23 +05:30
|
|
|
"fmt"
|
2021-01-04 19:10:36 +05:30
|
|
|
"math/big"
|
2020-11-09 11:26:12 -08:00
|
|
|
"reflect"
|
2021-04-08 05:04:45 +05:30
|
|
|
"strings"
|
2019-08-07 16:14:33 -07:00
|
|
|
"time"
|
|
|
|
|
2020-03-17 11:05:20 -07:00
|
|
|
"github.com/go-logr/logr"
|
2021-10-29 18:13:20 +02:00
|
|
|
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
|
2022-04-25 20:20:40 +08:00
|
|
|
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
|
2022-04-14 17:50:18 +05:30
|
|
|
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/common"
|
2022-03-02 00:19:31 +01:00
|
|
|
"github.com/kyverno/kyverno/pkg/autogen"
|
2020-10-07 11:12:31 -07:00
|
|
|
kyvernoclient "github.com/kyverno/kyverno/pkg/client/clientset/versioned"
|
|
|
|
"github.com/kyverno/kyverno/pkg/client/clientset/versioned/scheme"
|
|
|
|
kyvernoinformer "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1"
|
2022-04-25 20:20:40 +08:00
|
|
|
urkyvernoinformer "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1beta1"
|
2020-10-07 11:12:31 -07:00
|
|
|
kyvernolister "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1"
|
2022-04-25 20:20:40 +08:00
|
|
|
urkyvernolister "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1beta1"
|
2020-10-07 11:12:31 -07:00
|
|
|
"github.com/kyverno/kyverno/pkg/config"
|
|
|
|
client "github.com/kyverno/kyverno/pkg/dclient"
|
|
|
|
"github.com/kyverno/kyverno/pkg/event"
|
2021-05-05 00:41:13 +05:30
|
|
|
"github.com/kyverno/kyverno/pkg/metrics"
|
2020-11-09 11:26:12 -08:00
|
|
|
"github.com/kyverno/kyverno/pkg/policyreport"
|
2021-10-29 18:13:20 +02:00
|
|
|
"github.com/kyverno/kyverno/pkg/utils"
|
2022-04-25 20:20:40 +08:00
|
|
|
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
|
2019-08-07 16:14:33 -07:00
|
|
|
v1 "k8s.io/api/core/v1"
|
|
|
|
"k8s.io/apimachinery/pkg/api/errors"
|
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
|
|
|
"k8s.io/apimachinery/pkg/util/wait"
|
2020-11-09 11:26:12 -08:00
|
|
|
informers "k8s.io/client-go/informers/core/v1"
|
2021-06-08 12:37:19 -07:00
|
|
|
"k8s.io/client-go/kubernetes"
|
2019-08-07 16:14:33 -07:00
|
|
|
typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
|
2020-05-26 22:26:07 -07:00
|
|
|
listerv1 "k8s.io/client-go/listers/core/v1"
|
2019-08-07 16:14:33 -07:00
|
|
|
"k8s.io/client-go/tools/cache"
|
|
|
|
"k8s.io/client-go/tools/record"
|
|
|
|
"k8s.io/client-go/util/workqueue"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2019-08-08 13:59:50 -07:00
|
|
|
// maxRetries is the number of times a Policy will be retried before it is dropped out of the queue.
|
2019-08-07 16:14:33 -07:00
|
|
|
// With the current rate-limiter in use (5ms*2^(maxRetries-1)) the following numbers represent the times
|
|
|
|
// a deployment is going to be requeued:
|
|
|
|
//
|
|
|
|
// 5ms, 10ms, 20ms, 40ms, 80ms, 160ms, 320ms, 640ms, 1.3s, 2.6s, 5.1s, 10.2s, 20.4s, 41s, 82s
|
|
|
|
maxRetries = 15
|
|
|
|
)
|
|
|
|
|
|
|
|
// PolicyController is responsible for synchronizing Policy objects stored
|
|
|
|
// in the system with the corresponding policy violations
|
|
|
|
type PolicyController struct {
|
|
|
|
client *client.Client
|
2019-08-08 13:59:50 -07:00
|
|
|
kyvernoClient *kyvernoclient.Clientset
|
2021-06-08 12:37:19 -07:00
|
|
|
pInformer kyvernoinformer.ClusterPolicyInformer
|
|
|
|
npInformer kyvernoinformer.PolicyInformer
|
|
|
|
|
2019-08-13 13:15:04 -07:00
|
|
|
eventGen event.Interface
|
2019-08-07 16:14:33 -07:00
|
|
|
eventRecorder record.EventRecorder
|
|
|
|
|
2020-12-21 11:04:19 -08:00
|
|
|
// Policies that need to be synced
|
2019-08-07 16:14:33 -07:00
|
|
|
queue workqueue.RateLimitingInterface
|
2020-05-26 10:36:56 -07:00
|
|
|
|
2019-08-07 16:14:33 -07:00
|
|
|
// pLister can list/get policy from the shared informer's store
|
2019-09-03 14:51:51 -07:00
|
|
|
pLister kyvernolister.ClusterPolicyLister
|
2020-05-26 10:36:56 -07:00
|
|
|
|
2020-08-19 21:37:23 +05:30
|
|
|
// npLister can list/get namespace policy from the shared informer's store
|
|
|
|
npLister kyvernolister.PolicyLister
|
|
|
|
|
2022-04-25 20:20:40 +08:00
|
|
|
// urLister can list/get update request from the shared informer's store
|
|
|
|
urLister urkyvernolister.UpdateRequestLister
|
|
|
|
|
2020-12-21 11:04:19 -08:00
|
|
|
// nsLister can list/get namespaces from the shared informer's store
|
2020-05-26 22:26:07 -07:00
|
|
|
nsLister listerv1.NamespaceLister
|
|
|
|
|
2019-08-13 09:37:02 -07:00
|
|
|
// Resource manager, manages the mapping for already processed resource
|
|
|
|
rm resourceManager
|
2020-05-26 10:36:56 -07:00
|
|
|
|
2019-10-18 17:38:46 -07:00
|
|
|
// helpers to validate against current loaded configuration
|
|
|
|
configHandler config.Interface
|
2020-05-26 10:36:56 -07:00
|
|
|
|
2020-11-09 11:26:12 -08:00
|
|
|
// policy report generator
|
|
|
|
prGenerator policyreport.GeneratorInterface
|
2020-05-26 10:36:56 -07:00
|
|
|
|
2021-03-25 12:28:03 -07:00
|
|
|
policyReportEraser policyreport.PolicyReportEraser
|
|
|
|
|
|
|
|
reconcilePeriod time.Duration
|
|
|
|
|
2020-11-09 11:26:12 -08:00
|
|
|
log logr.Logger
|
2021-05-05 00:41:13 +05:30
|
|
|
|
|
|
|
promConfig *metrics.PromConfig
|
2019-08-07 16:14:33 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewPolicyController create a new PolicyController
|
2021-06-08 12:37:19 -07:00
|
|
|
func NewPolicyController(
|
|
|
|
kubeClient kubernetes.Interface,
|
|
|
|
kyvernoClient *kyvernoclient.Clientset,
|
2019-11-15 14:01:40 -08:00
|
|
|
client *client.Client,
|
|
|
|
pInformer kyvernoinformer.ClusterPolicyInformer,
|
2020-08-19 21:37:23 +05:30
|
|
|
npInformer kyvernoinformer.PolicyInformer,
|
2022-04-25 20:20:40 +08:00
|
|
|
urInformer urkyvernoinformer.UpdateRequestInformer,
|
2020-11-09 11:26:12 -08:00
|
|
|
configHandler config.Interface,
|
|
|
|
eventGen event.Interface,
|
|
|
|
prGenerator policyreport.GeneratorInterface,
|
2021-03-25 12:28:03 -07:00
|
|
|
policyReportEraser policyreport.PolicyReportEraser,
|
2020-05-26 10:36:56 -07:00
|
|
|
namespaces informers.NamespaceInformer,
|
2020-09-23 02:41:49 +05:30
|
|
|
log logr.Logger,
|
2021-05-05 00:41:13 +05:30
|
|
|
reconcilePeriod time.Duration,
|
2022-03-18 12:30:49 +01:00
|
|
|
promConfig *metrics.PromConfig,
|
|
|
|
) (*PolicyController, error) {
|
2020-05-26 10:36:56 -07:00
|
|
|
|
2019-08-07 16:14:33 -07:00
|
|
|
// Event broad caster
|
|
|
|
eventBroadcaster := record.NewBroadcaster()
|
2020-05-18 21:16:48 -07:00
|
|
|
eventBroadcaster.StartLogging(log.V(5).Info)
|
2019-08-07 16:14:33 -07:00
|
|
|
eventInterface, err := client.GetEventsInterface()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
eventBroadcaster.StartRecordingToSink(&typedcorev1.EventSinkImpl{Interface: eventInterface})
|
|
|
|
|
|
|
|
pc := PolicyController{
|
2021-03-25 12:28:03 -07:00
|
|
|
client: client,
|
|
|
|
kyvernoClient: kyvernoClient,
|
2021-06-08 12:37:19 -07:00
|
|
|
pInformer: pInformer,
|
|
|
|
npInformer: npInformer,
|
2021-03-25 12:28:03 -07:00
|
|
|
eventGen: eventGen,
|
|
|
|
eventRecorder: eventBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "policy_controller"}),
|
|
|
|
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "policy"),
|
|
|
|
configHandler: configHandler,
|
|
|
|
prGenerator: prGenerator,
|
|
|
|
policyReportEraser: policyReportEraser,
|
|
|
|
reconcilePeriod: reconcilePeriod,
|
2021-05-05 00:41:13 +05:30
|
|
|
promConfig: promConfig,
|
2021-06-08 12:37:19 -07:00
|
|
|
log: log,
|
2019-08-07 16:14:33 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
pc.pLister = pInformer.Lister()
|
2020-08-19 21:37:23 +05:30
|
|
|
pc.npLister = npInformer.Lister()
|
2020-11-09 11:26:12 -08:00
|
|
|
|
2020-05-26 22:26:07 -07:00
|
|
|
pc.nsLister = namespaces.Lister()
|
2022-04-25 20:20:40 +08:00
|
|
|
pc.urLister = urInformer.Lister()
|
2021-06-08 12:37:19 -07:00
|
|
|
|
2019-08-13 09:37:02 -07:00
|
|
|
// resource manager
|
|
|
|
// rebuild after 300 seconds/ 5 mins
|
2019-08-14 18:40:33 -07:00
|
|
|
pc.rm = NewResourceManager(30)
|
2019-08-13 09:37:02 -07:00
|
|
|
|
2019-08-07 16:14:33 -07:00
|
|
|
return &pc, nil
|
|
|
|
}
|
|
|
|
|
2022-03-31 08:44:00 +02:00
|
|
|
func (pc *PolicyController) canBackgroundProcess(p kyverno.PolicyInterface) bool {
|
|
|
|
logger := pc.log.WithValues("policy", p.GetName())
|
2020-05-26 10:36:56 -07:00
|
|
|
if !p.BackgroundProcessingEnabled() {
|
|
|
|
logger.V(4).Info("background processed is disabled")
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2021-11-03 11:16:55 -07:00
|
|
|
if err := ValidateVariables(p, true); err != nil {
|
2020-05-26 10:36:56 -07:00
|
|
|
logger.V(4).Info("policy cannot be processed in the background")
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2019-08-07 16:14:33 -07:00
|
|
|
func (pc *PolicyController) addPolicy(obj interface{}) {
|
2020-03-17 11:05:20 -07:00
|
|
|
logger := pc.log
|
2019-09-03 14:51:51 -07:00
|
|
|
p := obj.(*kyverno.ClusterPolicy)
|
2021-01-07 12:34:01 +08:00
|
|
|
|
2021-03-25 12:28:03 -07:00
|
|
|
logger.Info("policy created", "uid", p.UID, "kind", "ClusterPolicy", "name", p.Name)
|
2021-01-07 12:34:01 +08:00
|
|
|
|
2021-05-15 18:10:11 +05:30
|
|
|
// register kyverno_policy_rule_info_total metric concurrently
|
|
|
|
go pc.registerPolicyRuleInfoMetricAddPolicy(logger, p)
|
2021-07-23 21:46:50 +05:30
|
|
|
// register kyverno_policy_changes_total metric concurrently
|
|
|
|
go pc.registerPolicyChangesMetricAddPolicy(logger, p)
|
2021-05-15 18:10:11 +05:30
|
|
|
|
2021-04-29 14:59:37 -07:00
|
|
|
if p.Spec.Background == nil || p.Spec.ValidationFailureAction == "" || missingAutoGenRules(p, logger) {
|
2022-03-28 16:01:27 +02:00
|
|
|
pol, _ := common.MutatePolicy(p, logger)
|
2022-04-24 09:39:11 +02:00
|
|
|
_, err := pc.kyvernoClient.KyvernoV1().ClusterPolicies().Update(context.TODO(), pol.(*kyverno.ClusterPolicy), metav1.UpdateOptions{})
|
2021-04-08 05:04:45 +05:30
|
|
|
if err != nil {
|
|
|
|
logger.Error(err, "failed to add policy ")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-26 10:36:56 -07:00
|
|
|
if !pc.canBackgroundProcess(p) {
|
|
|
|
return
|
2019-12-30 17:08:50 -08:00
|
|
|
}
|
2020-05-26 10:36:56 -07:00
|
|
|
|
|
|
|
logger.V(4).Info("queuing policy for background processing", "name", p.Name)
|
2019-08-07 16:14:33 -07:00
|
|
|
pc.enqueuePolicy(p)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (pc *PolicyController) updatePolicy(old, cur interface{}) {
|
2020-03-17 11:05:20 -07:00
|
|
|
logger := pc.log
|
2019-09-03 14:51:51 -07:00
|
|
|
oldP := old.(*kyverno.ClusterPolicy)
|
|
|
|
curP := cur.(*kyverno.ClusterPolicy)
|
2020-05-26 10:36:56 -07:00
|
|
|
|
2021-05-15 18:10:11 +05:30
|
|
|
// register kyverno_policy_rule_info_total metric concurrently
|
|
|
|
go pc.registerPolicyRuleInfoMetricUpdatePolicy(logger, oldP, curP)
|
2021-07-23 21:46:50 +05:30
|
|
|
// register kyverno_policy_changes_total metric concurrently
|
|
|
|
go pc.registerPolicyChangesMetricUpdatePolicy(logger, oldP, curP)
|
2021-05-15 18:10:11 +05:30
|
|
|
|
2021-04-29 14:59:37 -07:00
|
|
|
if curP.Spec.Background == nil || curP.Spec.ValidationFailureAction == "" || missingAutoGenRules(curP, logger) {
|
2022-03-28 16:01:27 +02:00
|
|
|
pol, _ := common.MutatePolicy(curP, logger)
|
2022-04-24 09:39:11 +02:00
|
|
|
_, err := pc.kyvernoClient.KyvernoV1().ClusterPolicies().Update(context.TODO(), pol.(*kyverno.ClusterPolicy), metav1.UpdateOptions{})
|
2021-04-08 05:04:45 +05:30
|
|
|
if err != nil {
|
|
|
|
logger.Error(err, "failed to update policy ")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-26 10:36:56 -07:00
|
|
|
if !pc.canBackgroundProcess(curP) {
|
|
|
|
return
|
2019-12-30 17:08:50 -08:00
|
|
|
}
|
2020-05-17 09:51:46 -07:00
|
|
|
|
2020-11-09 11:26:12 -08:00
|
|
|
if reflect.DeepEqual(oldP.Spec, curP.Spec) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-03-25 12:28:03 -07:00
|
|
|
logger.V(2).Info("updating policy", "name", oldP.Name)
|
2020-12-08 23:04:16 -08:00
|
|
|
|
2020-12-21 11:04:19 -08:00
|
|
|
pc.enqueueRCRDeletedRule(oldP, curP)
|
2019-08-07 16:14:33 -07:00
|
|
|
pc.enqueuePolicy(curP)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (pc *PolicyController) deletePolicy(obj interface{}) {
|
2020-03-17 11:05:20 -07:00
|
|
|
logger := pc.log
|
2019-09-03 14:51:51 -07:00
|
|
|
p, ok := obj.(*kyverno.ClusterPolicy)
|
2019-08-07 16:14:33 -07:00
|
|
|
if !ok {
|
|
|
|
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
|
|
|
|
if !ok {
|
2020-12-21 11:04:19 -08:00
|
|
|
logger.Info("couldn't get object from tombstone", "obj", obj)
|
2019-08-07 16:14:33 -07:00
|
|
|
return
|
|
|
|
}
|
2019-09-03 14:51:51 -07:00
|
|
|
p, ok = tombstone.Obj.(*kyverno.ClusterPolicy)
|
2019-08-07 16:14:33 -07:00
|
|
|
if !ok {
|
2020-03-17 11:05:20 -07:00
|
|
|
logger.Info("tombstone container object that is not a policy", "obj", obj)
|
2019-08-07 16:14:33 -07:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
2020-05-17 09:51:46 -07:00
|
|
|
|
2021-05-15 18:10:11 +05:30
|
|
|
// register kyverno_policy_rule_info_total metric concurrently
|
|
|
|
go pc.registerPolicyRuleInfoMetricDeletePolicy(logger, p)
|
2021-07-23 21:46:50 +05:30
|
|
|
// register kyverno_policy_changes_total metric concurrently
|
|
|
|
go pc.registerPolicyChangesMetricDeletePolicy(logger, p)
|
2021-05-15 18:10:11 +05:30
|
|
|
|
2021-03-25 12:28:03 -07:00
|
|
|
logger.Info("policy deleted", "uid", p.UID, "kind", "ClusterPolicy", "name", p.Name)
|
2020-05-17 09:51:46 -07:00
|
|
|
|
2022-04-27 03:18:24 +08:00
|
|
|
pc.enqueueRCRDeletedPolicy(p.Name)
|
2021-07-01 00:30:02 +05:30
|
|
|
|
2022-04-27 03:18:24 +08:00
|
|
|
// do not clean up UR on generate clone (sync=true) policy deletion
|
|
|
|
rules := autogen.ComputeRules(p)
|
|
|
|
for _, r := range rules {
|
|
|
|
clone, sync := r.GetCloneSyncForGenerate()
|
|
|
|
if clone && sync {
|
|
|
|
return
|
|
|
|
}
|
2021-07-01 00:30:02 +05:30
|
|
|
}
|
2022-04-27 03:18:24 +08:00
|
|
|
pc.enqueuePolicy(p)
|
2019-08-07 16:14:33 -07:00
|
|
|
}
|
|
|
|
|
2020-08-19 21:37:23 +05:30
|
|
|
func (pc *PolicyController) addNsPolicy(obj interface{}) {
|
|
|
|
logger := pc.log
|
|
|
|
p := obj.(*kyverno.Policy)
|
2021-01-07 12:34:01 +08:00
|
|
|
|
2021-05-15 18:10:11 +05:30
|
|
|
// register kyverno_policy_rule_info_total metric concurrently
|
2022-03-31 14:25:54 +02:00
|
|
|
go pc.registerPolicyRuleInfoMetricAddPolicy(logger, p)
|
2021-07-23 21:46:50 +05:30
|
|
|
// register kyverno_policy_changes_total metric concurrently
|
2022-03-31 14:25:54 +02:00
|
|
|
go pc.registerPolicyChangesMetricAddPolicy(logger, p)
|
2021-05-15 18:10:11 +05:30
|
|
|
|
2021-03-25 12:28:03 -07:00
|
|
|
logger.Info("policy created", "uid", p.UID, "kind", "Policy", "name", p.Name, "namespaces", p.Namespace)
|
2021-01-07 12:34:01 +08:00
|
|
|
|
2022-03-31 08:44:00 +02:00
|
|
|
spec := p.GetSpec()
|
|
|
|
if spec.Background == nil || spec.ValidationFailureAction == "" || missingAutoGenRules(p, logger) {
|
|
|
|
nsPol, _ := common.MutatePolicy(p, logger)
|
2022-04-24 09:39:11 +02:00
|
|
|
_, err := pc.kyvernoClient.KyvernoV1().Policies(p.Namespace).Update(context.TODO(), nsPol.(*kyverno.Policy), metav1.UpdateOptions{})
|
2021-04-08 05:04:45 +05:30
|
|
|
if err != nil {
|
|
|
|
logger.Error(err, "failed to add namespace policy")
|
|
|
|
}
|
|
|
|
}
|
2022-03-31 08:44:00 +02:00
|
|
|
if !pc.canBackgroundProcess(p) {
|
2020-08-19 21:37:23 +05:30
|
|
|
return
|
|
|
|
}
|
2022-03-31 08:44:00 +02:00
|
|
|
logger.V(4).Info("queuing policy for background processing", "namespace", p.GetNamespace(), "name", p.GetName())
|
|
|
|
pc.enqueuePolicy(p)
|
2020-08-19 21:37:23 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
func (pc *PolicyController) updateNsPolicy(old, cur interface{}) {
|
|
|
|
logger := pc.log
|
|
|
|
oldP := old.(*kyverno.Policy)
|
|
|
|
curP := cur.(*kyverno.Policy)
|
2021-05-15 18:10:11 +05:30
|
|
|
|
|
|
|
// register kyverno_policy_rule_info_total metric concurrently
|
2022-03-31 14:25:54 +02:00
|
|
|
go pc.registerPolicyRuleInfoMetricUpdatePolicy(logger, oldP, curP)
|
2021-07-23 21:46:50 +05:30
|
|
|
// register kyverno_policy_changes_total metric concurrently
|
2022-03-31 14:25:54 +02:00
|
|
|
go pc.registerPolicyChangesMetricUpdatePolicy(logger, oldP, curP)
|
2021-05-15 18:10:11 +05:30
|
|
|
|
2022-03-31 08:44:00 +02:00
|
|
|
if curP.Spec.Background == nil || curP.Spec.ValidationFailureAction == "" || missingAutoGenRules(curP, logger) {
|
|
|
|
nsPol, _ := common.MutatePolicy(curP, logger)
|
2022-04-24 09:39:11 +02:00
|
|
|
_, err := pc.kyvernoClient.KyvernoV1().Policies(curP.GetNamespace()).Update(context.TODO(), nsPol.(*kyverno.Policy), metav1.UpdateOptions{})
|
2021-04-08 05:04:45 +05:30
|
|
|
if err != nil {
|
|
|
|
logger.Error(err, "failed to update namespace policy ")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-31 08:44:00 +02:00
|
|
|
if !pc.canBackgroundProcess(curP) {
|
2020-08-19 21:37:23 +05:30
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-11-09 11:26:12 -08:00
|
|
|
if reflect.DeepEqual(oldP.Spec, curP.Spec) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-08-19 21:37:23 +05:30
|
|
|
logger.V(4).Info("updating namespace policy", "namespace", oldP.Namespace, "name", oldP.Name)
|
2020-12-08 23:04:16 -08:00
|
|
|
|
2022-03-31 08:44:00 +02:00
|
|
|
pc.enqueueRCRDeletedRule(oldP, curP)
|
|
|
|
pc.enqueuePolicy(curP)
|
2020-08-19 21:37:23 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
func (pc *PolicyController) deleteNsPolicy(obj interface{}) {
|
|
|
|
logger := pc.log
|
|
|
|
p, ok := obj.(*kyverno.Policy)
|
|
|
|
if !ok {
|
|
|
|
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
|
|
|
|
if !ok {
|
2020-12-21 11:04:19 -08:00
|
|
|
logger.Info("couldn't get object from tombstone", "obj", obj)
|
2020-08-19 21:37:23 +05:30
|
|
|
return
|
|
|
|
}
|
|
|
|
p, ok = tombstone.Obj.(*kyverno.Policy)
|
|
|
|
if !ok {
|
|
|
|
logger.Info("tombstone container object that is not a policy", "obj", obj)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
2021-01-07 12:34:01 +08:00
|
|
|
|
2021-05-15 18:10:11 +05:30
|
|
|
// register kyverno_policy_rule_info_total metric concurrently
|
2022-03-31 14:25:54 +02:00
|
|
|
go pc.registerPolicyRuleInfoMetricDeletePolicy(logger, p)
|
2021-07-23 21:46:50 +05:30
|
|
|
// register kyverno_policy_changes_total metric concurrently
|
2022-03-31 14:25:54 +02:00
|
|
|
go pc.registerPolicyChangesMetricDeletePolicy(logger, p)
|
2021-05-15 18:10:11 +05:30
|
|
|
|
2021-01-07 12:34:01 +08:00
|
|
|
logger.Info("policy deleted event", "uid", p.UID, "kind", "Policy", "policy_name", p.Name, "namespaces", p.Namespace)
|
|
|
|
|
2022-03-31 08:44:00 +02:00
|
|
|
pol := p
|
2020-08-19 21:37:23 +05:30
|
|
|
|
2020-12-21 11:04:19 -08:00
|
|
|
pc.enqueueRCRDeletedPolicy(p.Name)
|
2022-04-27 03:18:24 +08:00
|
|
|
|
|
|
|
// do not clean up UR on generate clone (sync=true) policy deletion
|
|
|
|
rules := autogen.ComputeRules(pol)
|
|
|
|
for _, r := range rules {
|
|
|
|
clone, sync := r.GetCloneSyncForGenerate()
|
|
|
|
if clone && sync {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pc.enqueuePolicy(pol)
|
2020-08-19 21:37:23 +05:30
|
|
|
}
|
|
|
|
|
2022-03-31 08:44:00 +02:00
|
|
|
func (pc *PolicyController) enqueueRCRDeletedRule(old, cur kyverno.PolicyInterface) {
|
2020-11-09 11:26:12 -08:00
|
|
|
curRule := make(map[string]bool)
|
2022-03-28 16:01:27 +02:00
|
|
|
for _, rule := range autogen.ComputeRules(cur) {
|
2020-11-09 11:26:12 -08:00
|
|
|
curRule[rule.Name] = true
|
|
|
|
}
|
|
|
|
|
2022-03-28 16:01:27 +02:00
|
|
|
for _, rule := range autogen.ComputeRules(old) {
|
2020-11-09 11:26:12 -08:00
|
|
|
if !curRule[rule.Name] {
|
|
|
|
pc.prGenerator.Add(policyreport.Info{
|
|
|
|
PolicyName: cur.GetName(),
|
2020-12-21 11:04:19 -08:00
|
|
|
Results: []policyreport.EngineResponseResult{
|
|
|
|
{
|
|
|
|
Rules: []kyverno.ViolatedRule{
|
|
|
|
{Name: rule.Name},
|
|
|
|
},
|
|
|
|
},
|
2020-11-09 11:26:12 -08:00
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-21 11:04:19 -08:00
|
|
|
func (pc *PolicyController) enqueueRCRDeletedPolicy(policyName string) {
|
|
|
|
pc.prGenerator.Add(policyreport.Info{
|
|
|
|
PolicyName: policyName,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-03-31 08:44:00 +02:00
|
|
|
func (pc *PolicyController) enqueuePolicy(policy kyverno.PolicyInterface) {
|
2020-03-17 11:05:20 -07:00
|
|
|
logger := pc.log
|
2019-08-07 16:14:33 -07:00
|
|
|
key, err := cache.MetaNamespaceKeyFunc(policy)
|
|
|
|
if err != nil {
|
2020-06-30 11:53:27 -07:00
|
|
|
logger.Error(err, "failed to enqueue policy")
|
2019-08-07 16:14:33 -07:00
|
|
|
return
|
|
|
|
}
|
|
|
|
pc.queue.Add(key)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Run begins watching and syncing.
|
2021-03-25 12:28:03 -07:00
|
|
|
func (pc *PolicyController) Run(workers int, reconcileCh <-chan bool, stopCh <-chan struct{}) {
|
2020-03-17 11:05:20 -07:00
|
|
|
logger := pc.log
|
2019-08-07 16:14:33 -07:00
|
|
|
|
|
|
|
defer utilruntime.HandleCrash()
|
|
|
|
defer pc.queue.ShutDown()
|
|
|
|
|
2020-03-17 11:05:20 -07:00
|
|
|
logger.Info("starting")
|
|
|
|
defer logger.Info("shutting down")
|
2019-08-07 16:14:33 -07:00
|
|
|
|
2021-06-08 12:37:19 -07:00
|
|
|
pc.pInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
|
|
|
|
AddFunc: pc.addPolicy,
|
|
|
|
UpdateFunc: pc.updatePolicy,
|
|
|
|
DeleteFunc: pc.deletePolicy,
|
|
|
|
})
|
|
|
|
|
|
|
|
pc.npInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
|
|
|
|
AddFunc: pc.addNsPolicy,
|
|
|
|
UpdateFunc: pc.updateNsPolicy,
|
|
|
|
DeleteFunc: pc.deleteNsPolicy,
|
|
|
|
})
|
|
|
|
|
2019-08-07 16:14:33 -07:00
|
|
|
for i := 0; i < workers; i++ {
|
2020-12-23 17:48:00 -08:00
|
|
|
go wait.Until(pc.worker, time.Second, stopCh)
|
2019-08-07 16:14:33 -07:00
|
|
|
}
|
2021-03-25 12:28:03 -07:00
|
|
|
|
|
|
|
go pc.forceReconciliation(reconcileCh, stopCh)
|
|
|
|
|
2019-08-07 16:14:33 -07:00
|
|
|
<-stopCh
|
|
|
|
}
|
|
|
|
|
|
|
|
// worker runs a worker thread that just dequeues items, processes them, and marks them done.
|
|
|
|
// It enforces that the syncHandler is never invoked concurrently with the same key.
|
|
|
|
func (pc *PolicyController) worker() {
|
|
|
|
for pc.processNextWorkItem() {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (pc *PolicyController) processNextWorkItem() bool {
|
|
|
|
key, quit := pc.queue.Get()
|
|
|
|
if quit {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
defer pc.queue.Done(key)
|
2020-06-30 11:53:27 -07:00
|
|
|
err := pc.syncPolicy(key.(string))
|
2019-08-07 16:14:33 -07:00
|
|
|
pc.handleErr(err, key)
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
func (pc *PolicyController) handleErr(err error, key interface{}) {
|
2020-03-17 11:05:20 -07:00
|
|
|
logger := pc.log
|
2019-08-07 16:14:33 -07:00
|
|
|
if err == nil {
|
|
|
|
pc.queue.Forget(key)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if pc.queue.NumRequeues(key) < maxRetries {
|
2020-03-17 11:05:20 -07:00
|
|
|
logger.Error(err, "failed to sync policy", "key", key)
|
2019-08-07 16:14:33 -07:00
|
|
|
pc.queue.AddRateLimited(key)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
utilruntime.HandleError(err)
|
2020-03-17 11:05:20 -07:00
|
|
|
logger.V(2).Info("dropping policy out of queue", "key", key)
|
2019-08-07 16:14:33 -07:00
|
|
|
pc.queue.Forget(key)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (pc *PolicyController) syncPolicy(key string) error {
|
2020-12-21 11:04:19 -08:00
|
|
|
logger := pc.log.WithName("syncPolicy")
|
2019-08-07 16:14:33 -07:00
|
|
|
startTime := time.Now()
|
2020-03-17 11:05:20 -07:00
|
|
|
logger.V(4).Info("started syncing policy", "key", key, "startTime", startTime)
|
2019-08-07 16:14:33 -07:00
|
|
|
defer func() {
|
2020-07-09 11:48:34 -07:00
|
|
|
logger.V(4).Info("finished syncing policy", "key", key, "processingTime", time.Since(startTime).String())
|
2019-08-07 16:14:33 -07:00
|
|
|
}()
|
2020-05-17 09:51:46 -07:00
|
|
|
|
2020-12-21 11:04:19 -08:00
|
|
|
policy, err := pc.getPolicy(key)
|
2020-11-09 11:26:12 -08:00
|
|
|
if err != nil {
|
|
|
|
if errors.IsNotFound(err) {
|
2022-04-29 13:31:02 +08:00
|
|
|
mutateURs := pc.listMutateURs(key, nil)
|
|
|
|
generateURs := pc.listGenerateURs(key, nil)
|
2022-04-28 18:29:48 +08:00
|
|
|
deleteGR(pc.kyvernoClient, key, append(mutateURs, generateURs...), logger)
|
2020-11-09 11:26:12 -08:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return err
|
2022-04-29 13:31:02 +08:00
|
|
|
} else {
|
|
|
|
pc.updateUR(key, policy)
|
2019-08-07 16:14:33 -07:00
|
|
|
}
|
2020-11-09 11:26:12 -08:00
|
|
|
|
2021-07-23 21:46:50 +05:30
|
|
|
pc.processExistingResources(policy)
|
2020-12-21 11:04:19 -08:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-03-31 08:44:00 +02:00
|
|
|
func (pc *PolicyController) getPolicy(key string) (policy kyverno.PolicyInterface, err error) {
|
2021-05-07 00:32:06 +05:30
|
|
|
namespace, key, isNamespacedPolicy := ParseNamespacedPolicy(key)
|
2020-12-21 11:04:19 -08:00
|
|
|
if !isNamespacedPolicy {
|
|
|
|
return pc.pLister.Get(key)
|
|
|
|
}
|
|
|
|
|
|
|
|
nsPolicy, err := pc.npLister.Policies(namespace).Get(key)
|
|
|
|
if err == nil && nsPolicy != nil {
|
2022-03-31 08:44:00 +02:00
|
|
|
policy = nsPolicy
|
2020-12-21 11:04:19 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-04-25 20:20:40 +08:00
|
|
|
func getTriggers(rule kyverno.Rule) []*kyverno.ResourceSpec {
|
|
|
|
var specs []*kyverno.ResourceSpec
|
|
|
|
|
|
|
|
triggers := getTrigger(rule.MatchResources.ResourceDescription)
|
|
|
|
specs = append(specs, triggers...)
|
|
|
|
|
|
|
|
for _, any := range rule.MatchResources.Any {
|
|
|
|
triggers := getTrigger(any.ResourceDescription)
|
|
|
|
specs = append(specs, triggers...)
|
|
|
|
}
|
|
|
|
|
|
|
|
triggers = []*kyverno.ResourceSpec{}
|
|
|
|
for _, all := range rule.MatchResources.All {
|
|
|
|
triggers = getTrigger(all.ResourceDescription)
|
|
|
|
}
|
|
|
|
|
|
|
|
subset := make(map[*kyverno.ResourceSpec]int, len(triggers))
|
|
|
|
for _, trigger := range triggers {
|
|
|
|
c := subset[trigger]
|
|
|
|
subset[trigger] = c + 1
|
|
|
|
}
|
|
|
|
|
|
|
|
for k, v := range subset {
|
|
|
|
if v == len(rule.MatchResources.All) {
|
|
|
|
specs = append(specs, k)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return specs
|
|
|
|
}
|
|
|
|
|
|
|
|
func getTrigger(rd kyverno.ResourceDescription) []*kyverno.ResourceSpec {
|
2022-04-29 13:31:02 +08:00
|
|
|
if len(rd.Names) == 0 && rd.Name == "" {
|
2022-04-25 20:20:40 +08:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var specs []*kyverno.ResourceSpec
|
|
|
|
|
|
|
|
for _, k := range rd.Kinds {
|
|
|
|
apiVersion, kind := kubeutils.GetKindFromGVK(k)
|
|
|
|
if kind == "" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2022-04-29 13:31:02 +08:00
|
|
|
for _, name := range rd.Names {
|
|
|
|
if name == "" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
spec := &kyverno.ResourceSpec{
|
|
|
|
APIVersion: apiVersion,
|
|
|
|
Kind: kind,
|
|
|
|
Name: name,
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, ns := range rd.Namespaces {
|
|
|
|
spec.Namespace = ns
|
2022-04-25 20:20:40 +08:00
|
|
|
specs = append(specs, spec)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return specs
|
|
|
|
}
|
|
|
|
|
|
|
|
func deleteGR(kyvernoClient *kyvernoclient.Clientset, policyKey string, grList []*urkyverno.UpdateRequest, logger logr.Logger) {
|
2020-12-21 11:04:19 -08:00
|
|
|
for _, v := range grList {
|
|
|
|
if policyKey == v.Spec.Policy {
|
2022-04-25 20:20:40 +08:00
|
|
|
err := kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).Delete(context.TODO(), v.GetName(), metav1.DeleteOptions{})
|
2020-12-21 11:04:19 -08:00
|
|
|
if err != nil && !errors.IsNotFound(err) {
|
2022-04-25 20:20:40 +08:00
|
|
|
logger.Error(err, "failed to delete ur", "name", v.GetName())
|
2020-12-21 11:04:19 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-25 20:20:40 +08:00
|
|
|
func updateUR(kyvernoClient *kyvernoclient.Clientset, policyKey string, grList []*urkyverno.UpdateRequest, logger logr.Logger) {
|
2020-12-29 16:36:43 +05:30
|
|
|
for _, gr := range grList {
|
|
|
|
if policyKey == gr.Spec.Policy {
|
|
|
|
grLabels := gr.Labels
|
2021-01-04 15:19:06 +05:30
|
|
|
if len(grLabels) == 0 {
|
2020-12-29 16:36:43 +05:30
|
|
|
grLabels = make(map[string]string)
|
|
|
|
}
|
2021-01-04 19:10:36 +05:30
|
|
|
|
|
|
|
nBig, err := rand.Int(rand.Reader, big.NewInt(100000))
|
|
|
|
if err != nil {
|
|
|
|
logger.Error(err, "failed to generate random interger")
|
|
|
|
}
|
|
|
|
grLabels["policy-update"] = fmt.Sprintf("revision-count-%d", nBig.Int64())
|
2020-12-29 16:36:43 +05:30
|
|
|
gr.SetLabels(grLabels)
|
2021-01-04 19:10:36 +05:30
|
|
|
|
2022-04-27 03:18:24 +08:00
|
|
|
new, err := kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).Update(context.TODO(), gr, metav1.UpdateOptions{})
|
2020-09-04 03:04:23 +05:30
|
|
|
if err != nil {
|
2020-12-29 16:36:43 +05:30
|
|
|
logger.Error(err, "failed to update gr", "name", gr.GetName())
|
2022-04-27 03:18:24 +08:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
new.Status.State = urkyverno.Pending
|
|
|
|
if _, err := kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).UpdateStatus(context.TODO(), new, metav1.UpdateOptions{}); err != nil {
|
|
|
|
logger.Error(err, "failed to set UpdateRequest state to Pending")
|
2020-09-04 03:04:23 +05:30
|
|
|
}
|
|
|
|
}
|
2019-08-07 16:14:33 -07:00
|
|
|
}
|
2019-11-12 23:19:38 -08:00
|
|
|
}
|
2021-04-08 05:04:45 +05:30
|
|
|
|
2022-03-31 08:44:00 +02:00
|
|
|
func missingAutoGenRules(policy kyverno.PolicyInterface, log logr.Logger) bool {
|
2021-04-08 05:04:45 +05:30
|
|
|
var podRuleName []string
|
|
|
|
ruleCount := 1
|
2022-03-31 08:44:00 +02:00
|
|
|
spec := policy.GetSpec()
|
2022-04-29 11:12:21 +02:00
|
|
|
if canApplyAutoGen, _ := autogen.CanAutoGen(spec); canApplyAutoGen {
|
2022-03-28 16:01:27 +02:00
|
|
|
for _, rule := range autogen.ComputeRules(policy) {
|
2021-04-08 05:04:45 +05:30
|
|
|
podRuleName = append(podRuleName, rule.Name)
|
|
|
|
}
|
|
|
|
}
|
2021-04-29 14:59:37 -07:00
|
|
|
|
2021-04-08 05:04:45 +05:30
|
|
|
if len(podRuleName) > 0 {
|
|
|
|
annotations := policy.GetAnnotations()
|
2022-03-09 14:48:04 +01:00
|
|
|
val, ok := annotations[kyverno.PodControllersAnnotation]
|
2021-04-08 05:04:45 +05:30
|
|
|
if !ok {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
if val == "none" {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
res := strings.Split(val, ",")
|
|
|
|
|
|
|
|
if len(res) == 1 {
|
|
|
|
ruleCount = 2
|
|
|
|
}
|
|
|
|
if len(res) > 1 {
|
|
|
|
if utils.ContainsString(res, "CronJob") {
|
|
|
|
ruleCount = 3
|
|
|
|
} else {
|
|
|
|
ruleCount = 2
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-28 16:01:27 +02:00
|
|
|
if len(autogen.ComputeRules(policy)) != (ruleCount * len(podRuleName)) {
|
2021-04-08 05:04:45 +05:30
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|