mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-29 10:55:05 +00:00
Feature - Add checks for k8s version when Kyverno starts (#831)
* Added k8s version check for mutating and validating' * version check adde * middelware added * formate * Added timeout flag value to webhook server timeout middelware and refactore kubernetes version check * Fixed test cases * Removed log * Update kubernetes version check * Added check for mutate and validate * Skip Validation in handleValidateAdmissionRequest if kubernetes version is below 1.14 * Update return object AdmissionResponse * fixed condition for skiping mutation * Handle condition for skip feature in case of kubernetes version 1.14.2
This commit is contained in:
parent
5595c23eeb
commit
277402ba4c
5 changed files with 113 additions and 74 deletions
|
@ -7,14 +7,13 @@ import (
|
|||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/nirmata/kyverno/pkg/config"
|
||||
client "github.com/nirmata/kyverno/pkg/dclient"
|
||||
"github.com/nirmata/kyverno/pkg/signal"
|
||||
"github.com/nirmata/kyverno/pkg/utils"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
rest "k8s.io/client-go/rest"
|
||||
clientcmd "k8s.io/client-go/tools/clientcmd"
|
||||
|
@ -63,7 +62,9 @@ func main() {
|
|||
// Exit for unsupported version of kubernetes cluster
|
||||
// https://github.com/nirmata/kyverno/issues/700
|
||||
// - supported from v1.12.7+
|
||||
isVersionSupported(client)
|
||||
if !utils.CompareKubernetesVersion(client, log.Log, 1, 12, 7) {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
requests := []request{
|
||||
// Resource
|
||||
|
@ -222,39 +223,3 @@ func merge(done <-chan struct{}, stopCh <-chan struct{}, processes ...<-chan err
|
|||
}()
|
||||
return out
|
||||
}
|
||||
|
||||
func isVersionSupported(client *client.Client) {
|
||||
logger := log.Log
|
||||
serverVersion, err := client.DiscoveryClient.GetServerVersion()
|
||||
if err != nil {
|
||||
logger.Error(err, "Failed to get kubernetes server version")
|
||||
os.Exit(1)
|
||||
}
|
||||
exp := regexp.MustCompile(`v(\d*).(\d*).(\d*)`)
|
||||
groups := exp.FindAllStringSubmatch(serverVersion.String(), -1)
|
||||
if len(groups) != 1 || len(groups[0]) != 4 {
|
||||
logger.Error(err, "Failed to extract kubernetes server version", "serverVersion", serverVersion)
|
||||
os.Exit(1)
|
||||
}
|
||||
// convert string to int
|
||||
// assuming the version are always intergers
|
||||
major, err := strconv.Atoi(groups[0][1])
|
||||
if err != nil {
|
||||
logger.Error(err, "Failed to extract kubernetes major server version", "serverVersion", serverVersion)
|
||||
os.Exit(1)
|
||||
}
|
||||
minor, err := strconv.Atoi(groups[0][2])
|
||||
if err != nil {
|
||||
logger.Error(err, "Failed to extract kubernetes minor server version", "serverVersion", serverVersion)
|
||||
os.Exit(1)
|
||||
}
|
||||
sub, err := strconv.Atoi(groups[0][3])
|
||||
if err != nil {
|
||||
logger.Error(err, "Failed to extract kubernetes sub minor server version", "serverVersion", serverVersion)
|
||||
os.Exit(1)
|
||||
}
|
||||
if major <= 1 && minor <= 12 && sub < 7 {
|
||||
logger.Info("Unsupported kubernetes server version %s. Kyverno is supported from version v1.12.7+", "serverVersion", serverVersion)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@ package utils
|
|||
|
||||
import (
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/minio/minio/pkg/wildcard"
|
||||
|
@ -86,3 +88,40 @@ func CleanupOldCrd(client *dclient.Client, log logr.Logger) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CompareKubernetesVersion compare kuberneates client version to user given version
|
||||
func CompareKubernetesVersion(client *client.Client, log logr.Logger, k8smajor, k8sminor, k8ssub int) bool {
|
||||
logger := log.WithName("CompareKubernetesVersion")
|
||||
serverVersion, err := client.DiscoveryClient.GetServerVersion()
|
||||
if err != nil {
|
||||
logger.Error(err, "Failed to get kubernetes server version")
|
||||
return false
|
||||
}
|
||||
exp := regexp.MustCompile(`v(\d*).(\d*).(\d*)`)
|
||||
groups := exp.FindAllStringSubmatch(serverVersion.String(), -1)
|
||||
if len(groups) != 1 || len(groups[0]) != 4 {
|
||||
logger.Error(err, "Failed to extract kubernetes server version", "serverVersion", serverVersion)
|
||||
return false
|
||||
}
|
||||
// convert string to int
|
||||
// assuming the version are always intergers
|
||||
major, err := strconv.Atoi(groups[0][1])
|
||||
if err != nil {
|
||||
logger.Error(err, "Failed to extract kubernetes major server version", "serverVersion", serverVersion)
|
||||
return false
|
||||
}
|
||||
minor, err := strconv.Atoi(groups[0][2])
|
||||
if err != nil {
|
||||
logger.Error(err, "Failed to extract kubernetes minor server version", "serverVersion", serverVersion)
|
||||
return false
|
||||
}
|
||||
sub, err := strconv.Atoi(groups[0][3])
|
||||
if err != nil {
|
||||
logger.Error(err, "Failed to extract kubernetes sub minor server version", "serverVersion", serverVersion)
|
||||
return false
|
||||
}
|
||||
if major <= k8smajor && minor <= k8sminor && sub < k8ssub {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -338,3 +338,8 @@ func (wrc *WebhookRegistrationClient) removePolicyValidatingWebhookConfiguration
|
|||
|
||||
logger.V(4).Info("successfully deleted policy validating webhook configutation")
|
||||
}
|
||||
|
||||
// GetWebhookTimeOut returns the value of webhook timeout
|
||||
func (wrc *WebhookRegistrationClient) GetWebhookTimeOut() time.Duration {
|
||||
return time.Duration(wrc.timeoutSeconds)
|
||||
}
|
||||
|
|
15
pkg/webhooks/middleware.go
Normal file
15
pkg/webhooks/middleware.go
Normal file
|
@ -0,0 +1,15 @@
|
|||
package webhooks
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
func timeoutHandler(h http.Handler, timeout time.Duration) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var timeoutHandler http.Handler
|
||||
msg := "ok"
|
||||
timeoutHandler = http.TimeoutHandler(h, timeout*time.Second, msg)
|
||||
timeoutHandler.ServeHTTP(w, r)
|
||||
}
|
||||
}
|
|
@ -11,8 +11,8 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/julienschmidt/httprouter"
|
||||
|
||||
"github.com/nirmata/kyverno/pkg/openapi"
|
||||
"github.com/nirmata/kyverno/pkg/utils"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/nirmata/kyverno/pkg/checker"
|
||||
|
@ -131,12 +131,14 @@ func NewWebhookServer(
|
|||
log: log,
|
||||
openAPIController: openAPIController,
|
||||
}
|
||||
|
||||
mux := httprouter.New()
|
||||
mux.HandlerFunc("POST", config.MutatingWebhookServicePath, ws.handlerFunc(ws.handleMutateAdmissionRequest, true))
|
||||
mux.HandlerFunc("POST", config.ValidatingWebhookServicePath, ws.handlerFunc(ws.handleValidateAdmissionRequest, true))
|
||||
mux.HandlerFunc("POST", config.PolicyMutatingWebhookServicePath, ws.handlerFunc(ws.handlePolicyMutation, true))
|
||||
mux.HandlerFunc("POST", config.PolicyValidatingWebhookServicePath, ws.handlerFunc(ws.handlePolicyValidation, true))
|
||||
mux.HandlerFunc("POST", config.VerifyMutatingWebhookServicePath, ws.handlerFunc(ws.handleVerifyRequest, false))
|
||||
|
||||
mux.HandlerFunc("POST", config.ValidatingWebhookServicePath, timeoutHandler(ws.handlerFunc(ws.handleValidateAdmissionRequest, true), ws.webhookRegistrationClient.GetWebhookTimeOut()))
|
||||
mux.HandlerFunc("POST", config.MutatingWebhookServicePath, timeoutHandler(ws.handlerFunc(ws.handleMutateAdmissionRequest, true), ws.webhookRegistrationClient.GetWebhookTimeOut()))
|
||||
mux.HandlerFunc("POST", config.PolicyValidatingWebhookServicePath, timeoutHandler(ws.handlerFunc(ws.handlePolicyValidation, true), ws.webhookRegistrationClient.GetWebhookTimeOut()))
|
||||
mux.HandlerFunc("POST", config.PolicyMutatingWebhookServicePath, timeoutHandler(ws.handlerFunc(ws.handlePolicyMutation, true), ws.webhookRegistrationClient.GetWebhookTimeOut()))
|
||||
mux.HandlerFunc("POST", config.VerifyMutatingWebhookServicePath, timeoutHandler(ws.handlerFunc(ws.handleVerifyRequest, false), ws.webhookRegistrationClient.GetWebhookTimeOut()))
|
||||
ws.server = http.Server{
|
||||
Addr: ":443", // Listen on port for HTTPS requests
|
||||
TLSConfig: &tlsConfig,
|
||||
|
@ -238,29 +240,37 @@ func (ws *WebhookServer) handleMutateAdmissionRequest(request *v1beta1.Admission
|
|||
}
|
||||
}
|
||||
|
||||
// MUTATION
|
||||
// mutation failure should not block the resource creation
|
||||
// any mutation failure is reported as the violation
|
||||
patches := ws.HandleMutation(request, resource, policies, roles, clusterRoles)
|
||||
var patches, patchedResource []byte
|
||||
|
||||
// patch the resource with patches before handling validation rules
|
||||
patchedResource := processResourceWithPatches(patches, request.Object.Raw, logger)
|
||||
versionCheck := utils.CompareKubernetesVersion(ws.client, ws.log, 1, 14, 0)
|
||||
|
||||
if ws.resourceWebhookWatcher != nil && ws.resourceWebhookWatcher.RunValidationInMutatingWebhook == "true" {
|
||||
// VALIDATION
|
||||
ok, msg := ws.HandleValidation(request, policies, patchedResource, roles, clusterRoles)
|
||||
if !ok {
|
||||
logger.Info("admission request denied")
|
||||
return &v1beta1.AdmissionResponse{
|
||||
Allowed: false,
|
||||
Result: &metav1.Status{
|
||||
Status: "Failure",
|
||||
Message: msg,
|
||||
},
|
||||
if versionCheck {
|
||||
// MUTATION
|
||||
// mutation failure should not block the resource creation
|
||||
// any mutation failure is reported as the violation
|
||||
patches = ws.HandleMutation(request, resource, policies, roles, clusterRoles)
|
||||
|
||||
// patch the resource with patches before handling validation rules
|
||||
patchedResource := processResourceWithPatches(patches, request.Object.Raw, logger)
|
||||
|
||||
if ws.resourceWebhookWatcher != nil && ws.resourceWebhookWatcher.RunValidationInMutatingWebhook == "true" {
|
||||
// VALIDATION
|
||||
ok, msg := ws.HandleValidation(request, policies, patchedResource, roles, clusterRoles)
|
||||
if !ok {
|
||||
logger.Info("admission request denied")
|
||||
return &v1beta1.AdmissionResponse{
|
||||
Allowed: false,
|
||||
Result: &metav1.Status{
|
||||
Status: "Failure",
|
||||
Message: msg,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// patch the resource with patches before handling validation rules
|
||||
patchedResource = processResourceWithPatches(patches, request.Object.Raw, logger)
|
||||
}
|
||||
|
||||
// GENERATE
|
||||
// Only applied during resource creation
|
||||
// Success -> Generate Request CR created successsfully
|
||||
|
@ -278,6 +288,7 @@ func (ws *WebhookServer) handleMutateAdmissionRequest(request *v1beta1.Admission
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Succesfful processing of mutation & validation rules in policy
|
||||
patchType := v1beta1.PatchTypeJSONPatch
|
||||
return &v1beta1.AdmissionResponse{
|
||||
|
@ -288,6 +299,7 @@ func (ws *WebhookServer) handleMutateAdmissionRequest(request *v1beta1.Admission
|
|||
Patch: patches,
|
||||
PatchType: &patchType,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (ws *WebhookServer) handleValidateAdmissionRequest(request *v1beta1.AdmissionRequest) *v1beta1.AdmissionResponse {
|
||||
|
@ -332,19 +344,22 @@ func (ws *WebhookServer) handleValidateAdmissionRequest(request *v1beta1.Admissi
|
|||
}
|
||||
}
|
||||
|
||||
// VALIDATION
|
||||
ok, msg := ws.HandleValidation(request, policies, nil, roles, clusterRoles)
|
||||
if !ok {
|
||||
logger.Info("admission request denied")
|
||||
return &v1beta1.AdmissionResponse{
|
||||
Allowed: false,
|
||||
Result: &metav1.Status{
|
||||
Status: "Failure",
|
||||
Message: msg,
|
||||
},
|
||||
versionCheck := utils.CompareKubernetesVersion(ws.client, ws.log, 1, 14, 0)
|
||||
|
||||
if !versionCheck {
|
||||
// VALIDATION
|
||||
ok, msg := ws.HandleValidation(request, policies, nil, roles, clusterRoles)
|
||||
if !ok {
|
||||
logger.Info("admission request denied")
|
||||
return &v1beta1.AdmissionResponse{
|
||||
Allowed: false,
|
||||
Result: &metav1.Status{
|
||||
Status: "Failure",
|
||||
Message: msg,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &v1beta1.AdmissionResponse{
|
||||
Allowed: true,
|
||||
Result: &metav1.Status{
|
||||
|
|
Loading…
Add table
Reference in a new issue