mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-29 02:45:06 +00:00
Customize namespaceSelector of Webhookconfigurations (#2003)
* customize namespaceSelector of webhook configurations from configMap Signed-off-by: Shuting Zhao <shutting06@gmail.com> * update webhook configurations base on UPDATEs of Kyverno ConfigMap Signed-off-by: Shuting Zhao <shutting06@gmail.com> * register webhook configurations with the namespaceSelector from ConfigMap Signed-off-by: Shuting Zhao <shutting06@gmail.com> * address golint comment Signed-off-by: Shuting Zhao <shutting06@gmail.com> * validate webhooks config format Signed-off-by: Shuting Zhao <shutting06@gmail.com> * fix NotDefined scenario Signed-off-by: Shuting Zhao <shutting06@gmail.com>
This commit is contained in:
parent
b486493f87
commit
6f07ea407f
5 changed files with 248 additions and 61 deletions
|
@ -165,21 +165,6 @@ func main() {
|
|||
if err != nil {
|
||||
setupLog.Error(err, "ConfigMap lookup disabled: failed to create resource cache")
|
||||
}
|
||||
debug := serverIP != ""
|
||||
webhookCfg := webhookconfig.NewRegister(
|
||||
clientConfig,
|
||||
client,
|
||||
rCache,
|
||||
serverIP,
|
||||
int32(webhookTimeout),
|
||||
debug,
|
||||
log.Log)
|
||||
|
||||
webhookMonitor, err := webhookconfig.NewMonitor(kubeClient, log.Log.WithName("WebhookMonitor"))
|
||||
if err != nil {
|
||||
setupLog.Error(err, "failed to initialize webhookMonitor")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// KYVERNO CRD INFORMER
|
||||
// watches CRD resources:
|
||||
|
@ -231,6 +216,22 @@ func main() {
|
|||
os.Exit(1)
|
||||
}
|
||||
|
||||
debug := serverIP != ""
|
||||
webhookCfg := webhookconfig.NewRegister(
|
||||
clientConfig,
|
||||
client,
|
||||
rCache,
|
||||
serverIP,
|
||||
int32(webhookTimeout),
|
||||
debug,
|
||||
log.Log)
|
||||
|
||||
webhookMonitor, err := webhookconfig.NewMonitor(kubeClient, log.Log.WithName("WebhookMonitor"))
|
||||
if err != nil {
|
||||
setupLog.Error(err, "failed to initialize webhookMonitor")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Configuration Data
|
||||
// dynamically load the configuration from configMap
|
||||
// - resource filters
|
||||
|
@ -242,6 +243,7 @@ func main() {
|
|||
excludeGroupRole,
|
||||
excludeUsername,
|
||||
prgen.ReconcileCh,
|
||||
webhookCfg.UpdateWebhookChan,
|
||||
log.Log.WithName("ConfigData"),
|
||||
)
|
||||
|
||||
|
@ -350,10 +352,18 @@ func main() {
|
|||
registerWebhookConfigurations := func() {
|
||||
certManager.InitTLSPemPair()
|
||||
|
||||
// validate the ConfigMap format
|
||||
if err := webhookCfg.ValidateWebhookConfigurations(config.KyvernoNamespace, configData.GetInitConfigMapName()); err != nil {
|
||||
setupLog.Error(err, "invalid format of the Kyverno init ConfigMap, please correct the format of 'data.webhooks'")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
go webhookCfg.UpdateWebhookConfigurations(configData)
|
||||
if registrationErr := registerWrapperRetry(); registrationErr != nil {
|
||||
setupLog.Error(err, "Timeout registering admission control webhooks")
|
||||
os.Exit(1)
|
||||
}
|
||||
webhookCfg.UpdateWebhookChan <- true
|
||||
}
|
||||
|
||||
// leader election context
|
||||
|
@ -366,7 +376,7 @@ func main() {
|
|||
cancel()
|
||||
}()
|
||||
|
||||
// register webhooks by the leader, it's a one-time job
|
||||
// webhookconfigurations are registered by the leader only
|
||||
webhookRegisterLeader, err := leaderelection.New("webhook-register", config.KyvernoNamespace, kubeClient, registerWebhookConfigurations, nil, log.Log.WithName("webhookRegister/LeaderElection"))
|
||||
if err != nil {
|
||||
setupLog.Error(err, "failed to elector leader")
|
||||
|
|
15
go.sum
15
go.sum
|
@ -741,11 +741,7 @@ github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOms
|
|||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
<<<<<<< HEAD
|
||||
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
|
||||
=======
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
>>>>>>> 2c944c03 (updated verison to latest)
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.8.0 h1:nfhvjKcUMhBMVqbKHJlk5RPrrfYr/NMo3692g0dwfWU=
|
||||
github.com/sirupsen/logrus v1.8.0/go.mod h1:4GuYW9TZmE769R5STWrRakJc4UqQ3+QQ95fyz7ENv1A=
|
||||
|
@ -762,7 +758,6 @@ github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU
|
|||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
||||
github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4=
|
||||
github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
|
@ -779,7 +774,6 @@ github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3
|
|||
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
|
@ -808,7 +802,6 @@ github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk
|
|||
github.com/valyala/quicktemplate v1.2.0/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4=
|
||||
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
|
||||
github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=
|
||||
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
|
||||
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
|
||||
github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
|
@ -878,7 +871,6 @@ golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPh
|
|||
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201217014255-9d1352758620/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
|
@ -1115,7 +1107,6 @@ golang.org/x/tools v0.0.0-20210114065538-d78b04bdf963/go.mod h1:emZCQorbCU4vsT4f
|
|||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gomodules.xyz/jsonpatch/v2 v2.1.0/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU=
|
||||
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||
|
@ -1135,7 +1126,6 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
|
|||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
|
@ -1193,7 +1183,6 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
|
|||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
|
||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
|
@ -1207,9 +1196,7 @@ gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
|||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
@ -1227,7 +1214,6 @@ gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71/go.mod h1:K4uyk7z7BCEPqu6E+C
|
|||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
@ -1260,7 +1246,6 @@ k8s.io/apiserver v0.0.0-20190918160949-bfa5e2e684ad/go.mod h1:XPCXEwhjaFN29a8Nld
|
|||
k8s.io/apiserver v0.16.4/go.mod h1:kbLJOak655g6W7C+muqu1F76u9wnEycfKMqbVaXIdAc=
|
||||
k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU=
|
||||
k8s.io/apiserver v0.21.0/go.mod h1:w2YSn4/WIwYuxG5zJmcqtRdtqgW/J2JRgFAqps3bBpg=
|
||||
k8s.io/cli-runtime v0.20.2 h1:W0/FHdbApnl9oB7xdG643c/Zaf7TZT+43I+zKxwqvhU=
|
||||
k8s.io/cli-runtime v0.20.2/go.mod h1:FjH6uIZZZP3XmwrXWeeYCbgxcrD6YXxoAykBaWH0VdM=
|
||||
k8s.io/client-go v0.0.0-20190918160344-1fbdaa4c8d90/go.mod h1:J69/JveO6XESwVgG53q3Uz5OSfgsv4uxpScmmyYOOlk=
|
||||
k8s.io/client-go v0.16.4/go.mod h1:ZgxhFDxSnoKY0J0U2/Y1C8obKDdlhGPZwA7oHH863Ok=
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"reflect"
|
||||
"regexp"
|
||||
|
@ -10,6 +11,7 @@ import (
|
|||
"github.com/go-logr/logr"
|
||||
"github.com/minio/pkg/wildcard"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
informers "k8s.io/client-go/informers/core/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
|
@ -21,6 +23,10 @@ const cmNameEnv string = "INIT_CONFIG"
|
|||
|
||||
var defaultExcludeGroupRole []string = []string{"system:serviceaccounts:kube-system", "system:nodes", "system:kube-scheduler"}
|
||||
|
||||
type WebhookConfig struct {
|
||||
NamespaceSelector *metav1.LabelSelector `json:"namespaceSelector,omitempty" protobuf:"bytes,5,opt,name=namespaceSelector"`
|
||||
}
|
||||
|
||||
// ConfigData stores the configuration
|
||||
type ConfigData struct {
|
||||
client kubernetes.Interface
|
||||
|
@ -30,8 +36,10 @@ type ConfigData struct {
|
|||
excludeGroupRole []string
|
||||
excludeUsername []string
|
||||
restrictDevelopmentUsername []string
|
||||
webhooks []WebhookConfig
|
||||
cmSycned cache.InformerSynced
|
||||
reconcilePolicyReport chan<- bool
|
||||
updateWebhookConfigurations chan<- bool
|
||||
log logr.Logger
|
||||
}
|
||||
|
||||
|
@ -87,6 +95,16 @@ func (cd *ConfigData) FilterNamespaces(namespaces []string) []string {
|
|||
return results
|
||||
}
|
||||
|
||||
func (cd *ConfigData) GetWebhooks() []WebhookConfig {
|
||||
cd.mux.RLock()
|
||||
defer cd.mux.RUnlock()
|
||||
return cd.webhooks
|
||||
}
|
||||
|
||||
func (cd *ConfigData) GetInitConfigMapName() string {
|
||||
return cd.cmName
|
||||
}
|
||||
|
||||
// Interface to be used by consumer to check filters
|
||||
type Interface interface {
|
||||
ToFilter(kind, namespace, name string) bool
|
||||
|
@ -94,21 +112,24 @@ type Interface interface {
|
|||
GetExcludeUsername() []string
|
||||
RestrictDevelopmentUsername() []string
|
||||
FilterNamespaces(namespaces []string) []string
|
||||
GetWebhooks() []WebhookConfig
|
||||
GetInitConfigMapName() string
|
||||
}
|
||||
|
||||
// NewConfigData ...
|
||||
func NewConfigData(rclient kubernetes.Interface, cmInformer informers.ConfigMapInformer, filterK8sResources, excludeGroupRole, excludeUsername string, reconcilePolicyReport chan<- bool, log logr.Logger) *ConfigData {
|
||||
func NewConfigData(rclient kubernetes.Interface, cmInformer informers.ConfigMapInformer, filterK8sResources, excludeGroupRole, excludeUsername string, reconcilePolicyReport, updateWebhookConfigurations chan<- bool, log logr.Logger) *ConfigData {
|
||||
// environment var is read at start only
|
||||
if cmNameEnv == "" {
|
||||
log.Info("ConfigMap name not defined in env:INIT_CONFIG: loading no default configuration")
|
||||
}
|
||||
|
||||
cd := ConfigData{
|
||||
client: rclient,
|
||||
cmName: os.Getenv(cmNameEnv),
|
||||
cmSycned: cmInformer.Informer().HasSynced,
|
||||
reconcilePolicyReport: reconcilePolicyReport,
|
||||
log: log,
|
||||
client: rclient,
|
||||
cmName: os.Getenv(cmNameEnv),
|
||||
cmSycned: cmInformer.Informer().HasSynced,
|
||||
reconcilePolicyReport: reconcilePolicyReport,
|
||||
updateWebhookConfigurations: updateWebhookConfigurations,
|
||||
log: log,
|
||||
}
|
||||
|
||||
cd.restrictDevelopmentUsername = []string{"minikube-user", "kubernetes-admin"}
|
||||
|
@ -156,7 +177,6 @@ func (cd *ConfigData) addCM(obj interface{}) {
|
|||
return
|
||||
}
|
||||
cd.load(*cm)
|
||||
// else load the configuration
|
||||
}
|
||||
|
||||
func (cd *ConfigData) updateCM(old, cur interface{}) {
|
||||
|
@ -165,11 +185,16 @@ func (cd *ConfigData) updateCM(old, cur interface{}) {
|
|||
return
|
||||
}
|
||||
// if data has not changed then dont load configmap
|
||||
changed := cd.load(*cm)
|
||||
if changed {
|
||||
reconcilePolicyReport, updateWebook := cd.load(*cm)
|
||||
if reconcilePolicyReport {
|
||||
cd.log.Info("resource filters changed, sending reconcile signal to the policy controller")
|
||||
cd.reconcilePolicyReport <- true
|
||||
}
|
||||
|
||||
if updateWebook {
|
||||
cd.log.Info("webhook configurations changed, updating webhook configurations")
|
||||
cd.updateWebhookConfigurations <- true
|
||||
}
|
||||
}
|
||||
|
||||
func (cd *ConfigData) deleteCM(obj interface{}) {
|
||||
|
@ -195,7 +220,7 @@ func (cd *ConfigData) deleteCM(obj interface{}) {
|
|||
cd.unload(*cm)
|
||||
}
|
||||
|
||||
func (cd *ConfigData) load(cm v1.ConfigMap) (changed bool) {
|
||||
func (cd *ConfigData) load(cm v1.ConfigMap) (reconcilePolicyReport, updateWebhook bool) {
|
||||
logger := cd.log.WithValues("name", cm.Name, "namespace", cm.Namespace)
|
||||
if cm.Data == nil {
|
||||
logger.V(4).Info("configuration: No data defined in ConfigMap")
|
||||
|
@ -215,7 +240,7 @@ func (cd *ConfigData) load(cm v1.ConfigMap) (changed bool) {
|
|||
} else {
|
||||
logger.V(2).Info("Updated resource filters", "oldFilters", cd.filters, "newFilters", newFilters)
|
||||
cd.filters = newFilters
|
||||
changed = true
|
||||
reconcilePolicyReport = true
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -230,7 +255,7 @@ func (cd *ConfigData) load(cm v1.ConfigMap) (changed bool) {
|
|||
} else {
|
||||
logger.V(2).Info("Updated resource excludeGroupRoles", "oldExcludeGroupRole", cd.excludeGroupRole, "newExcludeGroupRole", newExcludeGroupRoles)
|
||||
cd.excludeGroupRole = newExcludeGroupRoles
|
||||
changed = true
|
||||
reconcilePolicyReport = true
|
||||
}
|
||||
|
||||
excludeUsername, ok := cm.Data["excludeUsername"]
|
||||
|
@ -243,11 +268,29 @@ func (cd *ConfigData) load(cm v1.ConfigMap) (changed bool) {
|
|||
} else {
|
||||
logger.V(2).Info("Updated resource excludeUsernames", "oldExcludeUsername", cd.excludeUsername, "newExcludeUsername", excludeUsernames)
|
||||
cd.excludeUsername = excludeUsernames
|
||||
changed = true
|
||||
reconcilePolicyReport = true
|
||||
}
|
||||
}
|
||||
|
||||
return changed
|
||||
webhooks, ok := cm.Data["webhooks"]
|
||||
if !ok {
|
||||
logger.V(4).Info("configuration: No webhook configurations defined in ConfigMap")
|
||||
} else {
|
||||
cfgs, err := parseWebhooks(webhooks)
|
||||
if err != nil {
|
||||
logger.Error(err, "unable to parse webhooks configurations")
|
||||
return
|
||||
}
|
||||
|
||||
if reflect.DeepEqual(cfgs, cd.webhooks) {
|
||||
logger.V(4).Info("webhooks did not change")
|
||||
} else {
|
||||
logger.Info("Updated webhooks configurations", "oldWebhooks", cd.webhooks, "newWebhookd", cfgs)
|
||||
cd.webhooks = cfgs
|
||||
updateWebhook = true
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//TODO: this has been added to backward support command line arguments
|
||||
|
@ -330,3 +373,12 @@ func parseKinds(list string) []k8Resource {
|
|||
func parseRbac(list string) []string {
|
||||
return strings.Split(list, ",")
|
||||
}
|
||||
|
||||
func parseWebhooks(webhooks string) ([]WebhookConfig, error) {
|
||||
webhookCfgs := make([]WebhookConfig, 0, 10)
|
||||
if err := json.Unmarshal([]byte(webhooks), &webhookCfgs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return webhookCfgs, nil
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package webhookconfig
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
@ -12,6 +12,7 @@ import (
|
|||
client "github.com/kyverno/kyverno/pkg/dclient"
|
||||
"github.com/kyverno/kyverno/pkg/resourcecache"
|
||||
"github.com/kyverno/kyverno/pkg/tls"
|
||||
"github.com/pkg/errors"
|
||||
admregapi "k8s.io/api/admissionregistration/v1beta1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
errorsapi "k8s.io/apimachinery/pkg/api/errors"
|
||||
|
@ -40,6 +41,8 @@ type Register struct {
|
|||
timeoutSeconds int32
|
||||
log logr.Logger
|
||||
debug bool
|
||||
|
||||
UpdateWebhookChan chan bool
|
||||
}
|
||||
|
||||
// NewRegister creates new Register instance
|
||||
|
@ -52,13 +55,14 @@ func NewRegister(
|
|||
debug bool,
|
||||
log logr.Logger) *Register {
|
||||
return &Register{
|
||||
clientConfig: clientConfig,
|
||||
client: client,
|
||||
resCache: resCache,
|
||||
serverIP: serverIP,
|
||||
timeoutSeconds: webhookTimeout,
|
||||
log: log.WithName("Register"),
|
||||
debug: debug,
|
||||
clientConfig: clientConfig,
|
||||
client: client,
|
||||
resCache: resCache,
|
||||
serverIP: serverIP,
|
||||
timeoutSeconds: webhookTimeout,
|
||||
log: log.WithName("Register"),
|
||||
debug: debug,
|
||||
UpdateWebhookChan: make(chan bool),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -147,6 +151,70 @@ func (wrc *Register) Remove(cleanUp chan<- struct{}) {
|
|||
wrc.removeSecrets()
|
||||
}
|
||||
|
||||
// UpdateWebhookConfigurations updates resource webhook configurations dynamically
|
||||
// base on the UPDATEs of Kyverno init-config ConfigMap
|
||||
//
|
||||
// it currently updates namespaceSelector only, can be extend to update other fieids
|
||||
func (wrc *Register) UpdateWebhookConfigurations(configHandler config.Interface) {
|
||||
logger := wrc.log.WithName("UpdateWebhookConfigurations")
|
||||
for {
|
||||
<-wrc.UpdateWebhookChan
|
||||
logger.Info("received the signal to update webhook configurations")
|
||||
|
||||
var nsSelector map[string]interface{}
|
||||
webhookCfgs := configHandler.GetWebhooks()
|
||||
if webhookCfgs != nil {
|
||||
selector := webhookCfgs[0].NamespaceSelector
|
||||
selectorBytes, err := json.Marshal(*selector)
|
||||
if err != nil {
|
||||
logger.Error(err, "failed to serialize namespaceSelector")
|
||||
continue
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(selectorBytes, &nsSelector); err != nil {
|
||||
logger.Error(err, "failed to convert namespaceSelector to the map")
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if err := wrc.updateResourceMutatingWebhookConfiguration(nsSelector); err != nil {
|
||||
logger.Error(err, "unable to update mutatingWebhookConfigurations", "name", wrc.getResourceMutatingWebhookConfigName())
|
||||
} else {
|
||||
logger.Info("successfully updated mutatingWebhookConfigurations", "name", wrc.getResourceMutatingWebhookConfigName())
|
||||
}
|
||||
|
||||
if err := wrc.updateResourceValidatingWebhookConfiguration(nsSelector); err != nil {
|
||||
logger.Error(err, "unable to update validatingWebhookConfigurations", "name", wrc.getResourceValidatingWebhookConfigName())
|
||||
} else {
|
||||
logger.Info("successfully updated validatingWebhookConfigurations", "name", wrc.getResourceValidatingWebhookConfigName())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (wrc *Register) ValidateWebhookConfigurations(namespace, name string) error {
|
||||
logger := wrc.log.WithName("ValidateWebhookConfigurations")
|
||||
|
||||
cm, err := wrc.client.GetResource("", "ConfigMap", namespace, name)
|
||||
if err != nil {
|
||||
logger.Error(err, "unable to fetch ConfigMap", "namespace", namespace, "name", name)
|
||||
return nil
|
||||
}
|
||||
|
||||
webhooks, ok, err := unstructured.NestedString(cm.UnstructuredContent(), "data", "webhooks")
|
||||
if err != nil {
|
||||
logger.Error(err, "failed to fetch tag 'webhooks' from the ConfigMap")
|
||||
return nil
|
||||
}
|
||||
|
||||
if !ok {
|
||||
logger.V(4).Info("webhook configurations not defined")
|
||||
return nil
|
||||
}
|
||||
|
||||
webhookCfgs := make([]config.WebhookConfig, 0, 10)
|
||||
return json.Unmarshal([]byte(webhooks), &webhookCfgs)
|
||||
}
|
||||
|
||||
// cleanupKyvernoResource returns true if Kyverno deployment is terminating
|
||||
func (wrc *Register) cleanupKyvernoResource() bool {
|
||||
logger := wrc.log.WithName("cleanupKyvernoResource")
|
||||
|
@ -179,9 +247,9 @@ func (wrc *Register) createResourceMutatingWebhookConfiguration(caData []byte) e
|
|||
var config *admregapi.MutatingWebhookConfiguration
|
||||
|
||||
if wrc.serverIP != "" {
|
||||
config = wrc.constructDebugMutatingWebhookConfig(caData)
|
||||
config = wrc.constructDefaultDebugMutatingWebhookConfig(caData)
|
||||
} else {
|
||||
config = wrc.constructMutatingWebhookConfig(caData)
|
||||
config = wrc.constructDefaultMutatingWebhookConfig(caData)
|
||||
}
|
||||
|
||||
logger := wrc.log.WithValues("kind", kindMutating, "name", config.Name)
|
||||
|
@ -205,9 +273,9 @@ func (wrc *Register) createResourceValidatingWebhookConfiguration(caData []byte)
|
|||
var config *admregapi.ValidatingWebhookConfiguration
|
||||
|
||||
if wrc.serverIP != "" {
|
||||
config = wrc.constructDebugValidatingWebhookConfig(caData)
|
||||
config = wrc.constructDefaultDebugValidatingWebhookConfig(caData)
|
||||
} else {
|
||||
config = wrc.constructValidatingWebhookConfig(caData)
|
||||
config = wrc.constructDefaultValidatingWebhookConfig(caData)
|
||||
}
|
||||
|
||||
logger := wrc.log.WithValues("kind", kindValidating, "name", config.Name)
|
||||
|
@ -550,3 +618,75 @@ func (wrc *Register) checkEndpoint() error {
|
|||
wrc.log.V(3).Info(err.Error(), "ns", config.KyvernoNamespace, "name", config.KyvernoServiceName)
|
||||
return err
|
||||
}
|
||||
|
||||
func (wrc *Register) updateResourceValidatingWebhookConfiguration(nsSelector map[string]interface{}) error {
|
||||
validatingCache, _ := wrc.resCache.GetGVRCache(kindValidating)
|
||||
|
||||
resourceValidating, err := validatingCache.Lister().Get(wrc.getResourceValidatingWebhookConfigName())
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to get validatingWebhookConfigurations")
|
||||
}
|
||||
|
||||
webhooksUntyped, _, err := unstructured.NestedSlice(resourceValidating.UnstructuredContent(), "webhooks")
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to load validatingWebhookConfigurations.webhooks")
|
||||
}
|
||||
|
||||
var webhooks map[string]interface{}
|
||||
var ok bool
|
||||
if webhooksUntyped != nil {
|
||||
webhooks, ok = webhooksUntyped[0].(map[string]interface{})
|
||||
if !ok {
|
||||
return errors.Wrapf(err, "type mismatched, expected map[string]interface{}, got %T", webhooksUntyped[0])
|
||||
}
|
||||
}
|
||||
if err = unstructured.SetNestedMap(webhooks, nsSelector, "namespaceSelector"); err != nil {
|
||||
return errors.Wrapf(err, "unable to set validatingWebhookConfigurations.webhooks[0].namespaceSelector")
|
||||
}
|
||||
|
||||
if err = unstructured.SetNestedSlice(resourceValidating.UnstructuredContent(), []interface{}{webhooks}, "webhooks"); err != nil {
|
||||
return errors.Wrapf(err, "unable to set validatingWebhookConfigurations.webhooks")
|
||||
}
|
||||
|
||||
if _, err := wrc.client.UpdateResource(resourceValidating.GetAPIVersion(), resourceValidating.GetKind(), "", resourceValidating, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (wrc *Register) updateResourceMutatingWebhookConfiguration(nsSelector map[string]interface{}) error {
|
||||
mutatingCache, _ := wrc.resCache.GetGVRCache(kindMutating)
|
||||
|
||||
resourceMutating, err := mutatingCache.Lister().Get(wrc.getResourceMutatingWebhookConfigName())
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to get mutatingWebhookConfigurations")
|
||||
}
|
||||
|
||||
webhooksUntyped, _, err := unstructured.NestedSlice(resourceMutating.UnstructuredContent(), "webhooks")
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to load mutatingWebhookConfigurations.webhooks")
|
||||
}
|
||||
|
||||
var webhooks map[string]interface{}
|
||||
var ok bool
|
||||
if webhooksUntyped != nil {
|
||||
webhooks, ok = webhooksUntyped[0].(map[string]interface{})
|
||||
if !ok {
|
||||
return errors.Wrapf(err, "type mismatched, expected map[string]interface{}, got %T", webhooksUntyped[0])
|
||||
}
|
||||
}
|
||||
if err = unstructured.SetNestedMap(webhooks, nsSelector, "namespaceSelector"); err != nil {
|
||||
return errors.Wrapf(err, "unable to set mutatingWebhookConfigurations.webhooks[0].namespaceSelector")
|
||||
}
|
||||
|
||||
if err = unstructured.SetNestedSlice(resourceMutating.UnstructuredContent(), []interface{}{webhooks}, "webhooks"); err != nil {
|
||||
return errors.Wrapf(err, "unable to set mutatingWebhookConfigurations.webhooks")
|
||||
}
|
||||
|
||||
if _, err := wrc.client.UpdateResource(resourceMutating.GetAPIVersion(), resourceMutating.GetKind(), "", resourceMutating, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func (wrc *Register) constructDebugMutatingWebhookConfig(caData []byte) *admregapi.MutatingWebhookConfiguration {
|
||||
func (wrc *Register) constructDefaultDebugMutatingWebhookConfig(caData []byte) *admregapi.MutatingWebhookConfiguration {
|
||||
logger := wrc.log
|
||||
url := fmt.Sprintf("https://%s%s", wrc.serverIP, config.MutatingWebhookServicePath)
|
||||
logger.V(4).Info("Debug MutatingWebhookConfig registered", "url", url)
|
||||
|
@ -35,7 +35,7 @@ func (wrc *Register) constructDebugMutatingWebhookConfig(caData []byte) *admrega
|
|||
}
|
||||
}
|
||||
|
||||
func (wrc *Register) constructMutatingWebhookConfig(caData []byte) *admregapi.MutatingWebhookConfiguration {
|
||||
func (wrc *Register) constructDefaultMutatingWebhookConfig(caData []byte) *admregapi.MutatingWebhookConfiguration {
|
||||
|
||||
webhookCfg := generateMutatingWebhook(
|
||||
config.MutatingWebhookName,
|
||||
|
@ -94,7 +94,7 @@ func (wrc *Register) removeResourceMutatingWebhookConfiguration(wg *sync.WaitGro
|
|||
logger.Info("webhook configuration deleted")
|
||||
}
|
||||
|
||||
func (wrc *Register) constructDebugValidatingWebhookConfig(caData []byte) *admregapi.ValidatingWebhookConfiguration {
|
||||
func (wrc *Register) constructDefaultDebugValidatingWebhookConfig(caData []byte) *admregapi.ValidatingWebhookConfiguration {
|
||||
url := fmt.Sprintf("https://%s%s", wrc.serverIP, config.ValidatingWebhookServicePath)
|
||||
|
||||
return &admregapi.ValidatingWebhookConfiguration{
|
||||
|
@ -117,7 +117,7 @@ func (wrc *Register) constructDebugValidatingWebhookConfig(caData []byte) *admre
|
|||
}
|
||||
}
|
||||
|
||||
func (wrc *Register) constructValidatingWebhookConfig(caData []byte) *admregapi.ValidatingWebhookConfiguration {
|
||||
func (wrc *Register) constructDefaultValidatingWebhookConfig(caData []byte) *admregapi.ValidatingWebhookConfiguration {
|
||||
return &admregapi.ValidatingWebhookConfiguration{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: config.ValidatingWebhookConfigurationName,
|
||||
|
|
Loading…
Add table
Reference in a new issue