1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-06 16:06:56 +00:00
kyverno/pkg/webhooks/server.go
shuting 2a656f6de0
feat: mutate existing resources (#3669)
* feat: mutate existing, replace GR by UR in webhook server (#3601)

* add attributes for post mutation

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* add UR informer to webhook server

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* - replace gr with ur in the webhook server; - create ur for mutateExsiting policies

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* replace gr by ur across entire packages

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* add YAMLs

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* update api docs & fix unit tests

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* add UR deletion handler

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* add api docs for v1beta1

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* fix clientset method

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* fix v1beta1 client registration

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* feat: mutate existing - generates UR for admission requests (#3623)

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* replace with UR in policy controller generate rules (#3635)

Signed-off-by: prateekpandey14 <prateek.pandey@nirmata.com>

* - enable mutate engine to process mutateExisting rules; - add unit tests

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* implemented ur background reconciliation for mutateExisting policies

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* fix webhook update error

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* temporary comment out new unit tests

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* feat: mutate existing, replace GR by UR in webhook server (#3601)

* add attributes for post mutation

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* add UR informer to webhook server

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* - replace gr with ur in the webhook server; - create ur for mutateExsiting policies

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* replace gr by ur across entire packages

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* fix missing policy.kyverno.io/policy-name label (#3599)

Signed-off-by: prateekpandey14 <prateek.pandey@nirmata.com>

* refactor cli code from pkg to cmd (#3591)

* refactor cli code from pkg to cmd

Signed-off-by: Mritunjay Sharma <mritunjaysharma394@gmail.com>

* fixes in imports

Signed-off-by: Mritunjay Sharma <mritunjaysharma394@gmail.com>

* fixes tests

Signed-off-by: Mritunjay Sharma <mritunjaysharma394@gmail.com>

* fixed conflicts

Signed-off-by: Mritunjay Sharma <mritunjaysharma394@gmail.com>

* moved non-commands to utils

Signed-off-by: Mritunjay Sharma <mritunjaysharma394@gmail.com>

Co-authored-by: Vyankatesh Kudtarkar <vyankateshkd@gmail.com>

* add YAMLs

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* update api docs & fix unit tests

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* add UR deletion handler

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* add api docs for v1beta1

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* fix clientset method

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* add-kms-libraries for cosign (#3603)

* add-kms-libraries

Signed-off-by: anushkamittal20 <anumittal4641@gmail.com>

* Shifted providers to cosign package

Signed-off-by: anushkamittal20 <anumittal4641@gmail.com>
Signed-off-by: ShutingZhao <shuting@nirmata.com>

* Add support for custom image extractors (#3596)

Signed-off-by: Sambhav Kothari <skothari44@bloomberg.net>

* Update vulnerable dependencies (#3577)

Signed-off-by: Shubham Gupta <shubham.gupta2956@gmail.com>

Co-authored-by: Jim Bugwadia <jim@nirmata.com>
Signed-off-by: ShutingZhao <shuting@nirmata.com>

* fix v1beta1 client registration

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* feat: mutate existing - generates UR for admission requests (#3623)

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* updating version in Chart.yaml (#3618)

* updatimg version in Chart.yaml

Signed-off-by: Prateeknandle <prateeknandle@gmail.com>

* changes from, make gen-helm

Signed-off-by: Prateeknandle <prateeknandle@gmail.com>

Co-authored-by: Vyankatesh Kudtarkar <vyankateshkd@gmail.com>
Signed-off-by: ShutingZhao <shuting@nirmata.com>

* Allow kyverno-policies to have preconditions defined (#3606)

* Allow kyverno-policies to have preconditions defined

Signed-off-by: Trey Dockendorf <tdockendorf@osc.edu>

* Fix docs

Signed-off-by: Trey Dockendorf <tdockendorf@osc.edu>
Signed-off-by: ShutingZhao <shuting@nirmata.com>

* replace with UR in policy controller generate rules (#3635)

Signed-off-by: prateekpandey14 <prateek.pandey@nirmata.com>
Signed-off-by: ShutingZhao <shuting@nirmata.com>

* - enable mutate engine to process mutateExisting rules; - add unit tests

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* implemented ur background reconciliation for mutateExisting policies

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* fix webhook update error

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* temporary comment out new unit tests

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* Image verify attestors (#3614)

* fix logs

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* fix logs

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* support multiple attestors

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* rm CLI tests (not currently supported)

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* apply attestor repo

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* fix linter issues

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* fix entryError assignment

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* fix tests

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* format

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* add intermediary certs

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* Allow defining imagePullSecrets (#3633)

* Allow defining imagePullSecrets

Signed-off-by: Trey Dockendorf <tdockendorf@osc.edu>

* Use dict for imagePullSecrets

Signed-off-by: Trey Dockendorf <tdockendorf@osc.edu>

* Simplify how imagePullSecrets is defined

Signed-off-by: Trey Dockendorf <tdockendorf@osc.edu>
Signed-off-by: ShutingZhao <shuting@nirmata.com>

* Fix race condition in pCache (#3632)

* fix race condition in pCache

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* refact: remove unused Run function from generate (#3638)

Signed-off-by: prateekpandey14 <prateek.pandey@nirmata.com>

* Remove helm mode setting (#3628)

Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>
Signed-off-by: ShutingZhao <shuting@nirmata.com>

* refactor: image utils (#3630)

Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>
Signed-off-by: ShutingZhao <shuting@nirmata.com>

* -resolve lift comments; -fix informer sync issue

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* refact the update request cleanup controller

Signed-off-by: prateekpandey14 <prateek.pandey@nirmata.com>

* - fix delete request for mutateExisting; - fix context variable substitution; - improve logging

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* - enable events; - add last applied annotation

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* enable mutate existing on policy creation

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* update autogen code

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* merge main

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* add unit tests

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* address list comments

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* update api docs

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* fix "Implicit memory aliasing in for loop"

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* remove unused definitions

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* update api docs

Signed-off-by: ShutingZhao <shuting@nirmata.com>

Co-authored-by: Prateek Pandey <prateek.pandey@nirmata.com>
Co-authored-by: Mritunjay Kumar Sharma <mritunjaysharma394@gmail.com>
Co-authored-by: Vyankatesh Kudtarkar <vyankateshkd@gmail.com>
Co-authored-by: Anushka Mittal <55237170+anushkamittal20@users.noreply.github.com>
Co-authored-by: Sambhav Kothari <sambhavs.email@gmail.com>
Co-authored-by: Shubham Gupta <shubham.gupta2956@gmail.com>
Co-authored-by: Jim Bugwadia <jim@nirmata.com>
Co-authored-by: Prateek Nandle <56027872+Prateeknandle@users.noreply.github.com>
Co-authored-by: treydock <tdockendorf@osc.edu>
Co-authored-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>
2022-04-25 12:20:40 +00:00

298 lines
10 KiB
Go

package webhooks
import (
"context"
"crypto/tls"
"net/http"
"sync"
"time"
"github.com/go-logr/logr"
"github.com/julienschmidt/httprouter"
"github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/background"
kyvernoclient "github.com/kyverno/kyverno/pkg/client/clientset/versioned"
kyvernoinformer "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1"
urinformer "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1beta1"
kyvernolister "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1"
urlister "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/config"
client "github.com/kyverno/kyverno/pkg/dclient"
"github.com/kyverno/kyverno/pkg/engine"
"github.com/kyverno/kyverno/pkg/event"
"github.com/kyverno/kyverno/pkg/metrics"
"github.com/kyverno/kyverno/pkg/openapi"
"github.com/kyverno/kyverno/pkg/policycache"
"github.com/kyverno/kyverno/pkg/policyreport"
tlsutils "github.com/kyverno/kyverno/pkg/tls"
"github.com/kyverno/kyverno/pkg/userinfo"
"github.com/kyverno/kyverno/pkg/utils"
"github.com/kyverno/kyverno/pkg/webhookconfig"
"github.com/kyverno/kyverno/pkg/webhooks/handlers"
webhookgenerate "github.com/kyverno/kyverno/pkg/webhooks/updaterequest"
"github.com/pkg/errors"
admissionv1 "k8s.io/api/admission/v1"
informers "k8s.io/client-go/informers/core/v1"
rbacinformer "k8s.io/client-go/informers/rbac/v1"
listerv1 "k8s.io/client-go/listers/core/v1"
rbaclister "k8s.io/client-go/listers/rbac/v1"
"k8s.io/client-go/tools/cache"
)
// WebhookServer contains configured TLS server with MutationWebhook.
type WebhookServer struct {
server *http.Server
client *client.Client
kyvernoClient *kyvernoclient.Clientset
// grLister can list/get generate request from the shared informer's store
grLister kyvernolister.GenerateRequestNamespaceLister
// grSynced returns true if the Generate Request store has been synced at least once
grSynced cache.InformerSynced
// urLister can list/get update requests from the shared informer's store
urLister urlister.UpdateRequestNamespaceLister
// urSynced returns true if the Update Request store has been synced at least once
urSynced cache.InformerSynced
// list/get cluster policy resource
pLister kyvernolister.ClusterPolicyLister
// returns true if the cluster policy store has synced atleast
pSynced cache.InformerSynced
// list/get role binding resource
rbLister rbaclister.RoleBindingLister
// list/get role binding resource
rLister rbaclister.RoleLister
// list/get role binding resource
crLister rbaclister.ClusterRoleLister
// return true if role bining store has synced atleast once
rbSynced cache.InformerSynced
// return true if role store has synced atleast once
rSynced cache.InformerSynced
// list/get cluster role binding resource
crbLister rbaclister.ClusterRoleBindingLister
// return true if cluster role binding store has synced atleast once
crbSynced cache.InformerSynced
// return true if cluster role store has synced atleast once
crSynced cache.InformerSynced
// generate events
eventGen event.Interface
// policy cache
pCache policycache.Interface
// webhook registration client
webhookRegister *webhookconfig.Register
// helpers to validate against current loaded configuration
configHandler config.Interface
// channel for cleanup notification
cleanUp chan<- struct{}
// last request time
webhookMonitor *webhookconfig.Monitor
// policy report generator
prGenerator policyreport.GeneratorInterface
// generate request generator
grGenerator webhookgenerate.Interface
nsLister listerv1.NamespaceLister
// nsListerSynced returns true if the namespace store has been synced at least once
nsListerSynced cache.InformerSynced
auditHandler AuditHandler
log logr.Logger
openAPIController *openapi.Controller
grController *background.Controller
promConfig *metrics.PromConfig
mu sync.RWMutex
}
// NewWebhookServer creates new instance of WebhookServer accordingly to given configuration
// Policy Controller and Kubernetes Client should be initialized in configuration
func NewWebhookServer(
kyvernoClient *kyvernoclient.Clientset,
client *client.Client,
tlsPair *tlsutils.PemPair,
grInformer kyvernoinformer.GenerateRequestInformer,
urInformer urinformer.UpdateRequestInformer,
pInformer kyvernoinformer.ClusterPolicyInformer,
rbInformer rbacinformer.RoleBindingInformer,
crbInformer rbacinformer.ClusterRoleBindingInformer,
rInformer rbacinformer.RoleInformer,
crInformer rbacinformer.ClusterRoleInformer,
namespace informers.NamespaceInformer,
eventGen event.Interface,
pCache policycache.Interface,
webhookRegistrationClient *webhookconfig.Register,
webhookMonitor *webhookconfig.Monitor,
configHandler config.Interface,
prGenerator policyreport.GeneratorInterface,
grGenerator webhookgenerate.Interface,
auditHandler AuditHandler,
cleanUp chan<- struct{},
log logr.Logger,
openAPIController *openapi.Controller,
grc *background.Controller,
promConfig *metrics.PromConfig,
) (*WebhookServer, error) {
if tlsPair == nil {
return nil, errors.New("NewWebhookServer is not initialized properly")
}
pair, err := tls.X509KeyPair(tlsPair.Certificate, tlsPair.PrivateKey)
if err != nil {
return nil, err
}
ws := &WebhookServer{
client: client,
kyvernoClient: kyvernoClient,
grLister: grInformer.Lister().GenerateRequests(config.KyvernoNamespace),
grSynced: grInformer.Informer().HasSynced,
urLister: urInformer.Lister().UpdateRequests(config.KyvernoNamespace),
urSynced: urInformer.Informer().HasSynced,
pLister: pInformer.Lister(),
pSynced: pInformer.Informer().HasSynced,
rbLister: rbInformer.Lister(),
rbSynced: rbInformer.Informer().HasSynced,
rLister: rInformer.Lister(),
rSynced: rInformer.Informer().HasSynced,
nsLister: namespace.Lister(),
nsListerSynced: namespace.Informer().HasSynced,
crbLister: crbInformer.Lister(),
crLister: crInformer.Lister(),
crbSynced: crbInformer.Informer().HasSynced,
crSynced: crInformer.Informer().HasSynced,
eventGen: eventGen,
pCache: pCache,
webhookRegister: webhookRegistrationClient,
configHandler: configHandler,
cleanUp: cleanUp,
webhookMonitor: webhookMonitor,
prGenerator: prGenerator,
grGenerator: grGenerator,
grController: grc,
auditHandler: auditHandler,
log: log,
openAPIController: openAPIController,
promConfig: promConfig,
}
mux := httprouter.New()
mux.HandlerFunc("POST", config.MutatingWebhookServicePath, ws.admissionHandler(true, ws.resourceMutation))
mux.HandlerFunc("POST", config.ValidatingWebhookServicePath, ws.admissionHandler(true, ws.resourceValidation))
mux.HandlerFunc("POST", config.PolicyMutatingWebhookServicePath, ws.admissionHandler(true, ws.policyMutation))
mux.HandlerFunc("POST", config.PolicyValidatingWebhookServicePath, ws.admissionHandler(true, ws.policyValidation))
mux.HandlerFunc("POST", config.VerifyMutatingWebhookServicePath, ws.admissionHandler(false, handlers.Verify(ws.webhookMonitor, ws.log.WithName("verifyHandler"))))
mux.HandlerFunc("GET", config.LivenessServicePath, handlers.Probe(ws.webhookRegister.Check))
mux.HandlerFunc("GET", config.ReadinessServicePath, handlers.Probe(nil))
ws.server = &http.Server{
Addr: ":9443", // Listen on port for HTTPS requests
TLSConfig: &tls.Config{Certificates: []tls.Certificate{pair}, MinVersion: tls.VersionTLS12},
Handler: mux,
ReadTimeout: 15 * time.Second,
WriteTimeout: 15 * time.Second,
}
return ws, nil
}
func (ws *WebhookServer) buildPolicyContext(request *admissionv1.AdmissionRequest, addRoles bool) (*engine.PolicyContext, error) {
userRequestInfo := v1beta1.RequestInfo{
AdmissionUserInfo: *request.UserInfo.DeepCopy(),
}
if addRoles {
var err error
userRequestInfo.Roles, userRequestInfo.ClusterRoles, err = userinfo.GetRoleRef(ws.rbLister, ws.crbLister, request, ws.configHandler)
if err != nil {
return nil, errors.Wrap(err, "failed to fetch RBAC information for request")
}
}
ctx, err := newVariablesContext(request, &userRequestInfo)
if err != nil {
return nil, errors.Wrap(err, "failed to create policy rule context")
}
// convert RAW to unstructured
resource, err := utils.ConvertResource(request.Object.Raw, request.Kind.Group, request.Kind.Version, request.Kind.Kind, request.Namespace)
if err != nil {
return nil, errors.Wrap(err, "failed to convert raw resource to unstructured format")
}
if err := ctx.AddImageInfos(&resource); err != nil {
return nil, errors.Wrap(err, "failed to add image information to the policy rule context")
}
if request.Kind.Kind == "Secret" && request.Operation == admissionv1.Update {
resource, err = utils.NormalizeSecret(&resource)
if err != nil {
return nil, errors.Wrap(err, "failed to convert secret to unstructured format")
}
}
policyContext := &engine.PolicyContext{
NewResource: resource,
AdmissionInfo: userRequestInfo,
ExcludeGroupRole: ws.configHandler.GetExcludeGroupRole(),
ExcludeResourceFunc: ws.configHandler.ToFilter,
JSONContext: ctx,
Client: ws.client,
AdmissionOperation: true,
}
if request.Operation == admissionv1.Update {
policyContext.OldResource = resource
}
return policyContext, nil
}
// RunAsync TLS server in separate thread and returns control immediately
func (ws *WebhookServer) RunAsync(stopCh <-chan struct{}) {
if !cache.WaitForCacheSync(stopCh, ws.grSynced, ws.urSynced, ws.pSynced, ws.rbSynced, ws.crbSynced, ws.rSynced, ws.crSynced) {
ws.log.Info("failed to sync informer cache")
}
go func() {
ws.log.V(3).Info("started serving requests", "addr", ws.server.Addr)
if err := ws.server.ListenAndServeTLS("", ""); err != http.ErrServerClosed {
ws.log.Error(err, "failed to listen to requests")
}
}()
ws.log.Info("starting service")
}
// Stop TLS server and returns control after the server is shut down
func (ws *WebhookServer) Stop(ctx context.Context) {
// remove the static webhook configurations
go ws.webhookRegister.Remove(ws.cleanUp)
// shutdown http.Server with context timeout
err := ws.server.Shutdown(ctx)
if err != nil {
// Error from closing listeners, or context timeout:
ws.log.Error(err, "shutting down server")
err = ws.server.Close()
if err != nil {
ws.log.Error(err, "server shut down failed")
}
}
}