1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-30 19:35:06 +00:00

feat: add kyverno managed resources protection (#4414)

* feat: add kyverno managed resources protection

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

* add toggle

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

Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>
This commit is contained in:
Charles-Edouard Brétéché 2022-09-06 17:43:04 +02:00 committed by GitHub
parent 1947dafed6
commit 317a3ae0bf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 51 additions and 7 deletions

View file

@ -131,6 +131,8 @@ spec:
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: KYVERNO_SERVICEACCOUNT_NAME
value: {{ template "kyverno.serviceAccountName" . }}
- name: KYVERNO_SVC
value: {{ template "kyverno.serviceName" . }}
- name: TUF_ROOT

View file

@ -111,6 +111,7 @@ func main() {
flag.DurationVar(&webhookRegistrationTimeout, "webhookRegistrationTimeout", 120*time.Second, "Timeout for webhook registration, e.g., 30s, 1m, 5m.")
flag.IntVar(&changeRequestLimit, "maxReportChangeRequests", 1000, "Maximum pending report change requests per namespace or for the cluster-wide policy report.")
flag.Func(toggle.SplitPolicyReportFlagName, toggle.SplitPolicyReportDescription, toggle.SplitPolicyReport.Parse)
flag.Func(toggle.ProtectManagedResourcesFlagName, toggle.ProtectManagedResourcesDescription, toggle.ProtectManagedResources.Parse)
if err := flag.Set("v", "2"); err != nil {
setupLog.Error(err, "failed to set log level")
os.Exit(1)

View file

@ -72,6 +72,8 @@ const (
var (
// kyvernoNamespace is the Kyverno namespace
kyvernoNamespace = osutils.GetEnvWithFallback("KYVERNO_NAMESPACE", "kyverno")
// kyvernoServiceAccountName is the Kyverno service account name
kyvernoServiceAccountName = osutils.GetEnvWithFallback("KYVERNO_SERVICEACCOUNT_NAME", "kyverno")
// kyvernoDeploymentName is the Kyverno deployment name
kyvernoDeploymentName = osutils.GetEnvWithFallback("KYVERNO_DEPLOYMENT", "kyverno")
// kyvernoServiceName is the Kyverno service name
@ -88,6 +90,10 @@ func KyvernoNamespace() string {
return kyvernoNamespace
}
func KyvernoServiceAccountName() string {
return kyvernoServiceAccountName
}
func KyvernoDeploymentName() string {
return kyvernoDeploymentName
}

View file

@ -6,19 +6,27 @@ import (
)
const (
AutogenInternalsFlagName = "autogenInternals"
AutogenInternalsDescription = "Enables autogen internal policies. When this is 'true' policy rules should not be mutated."
autogenInternalsEnvVar = "FLAG_AUTOGEN_INTERNALS"
defaultAutogenInternals = true
// autogen
AutogenInternalsFlagName = "autogenInternals"
AutogenInternalsDescription = "Enables autogen internal policies. When this is 'true' policy rules should not be mutated."
autogenInternalsEnvVar = "FLAG_AUTOGEN_INTERNALS"
defaultAutogenInternals = true
// split resource
SplitPolicyReportFlagName = "splitPolicyReport"
SplitPolicyReportDescription = "Set the flag to 'true', to enable the split-up PolicyReports per policy."
splitPolicyReportEnvVar = "FLAG_SPLIT_POLICY_REPORT"
defaultSplitPolicyReport = false
// protect managed resource
ProtectManagedResourcesFlagName = "protectManagedResources"
ProtectManagedResourcesDescription = "Set the flag to 'true', to enable managed resources protection."
protectManagedResourcesEnvVar = "FLAG_PROTECT_MANAGED_RESOURCES"
defaultProtectManagedResources = false
)
var (
AutogenInternals = newToggle(defaultAutogenInternals, autogenInternalsEnvVar)
SplitPolicyReport = newToggle(defaultSplitPolicyReport, splitPolicyReportEnvVar)
AutogenInternals = newToggle(defaultAutogenInternals, autogenInternalsEnvVar)
SplitPolicyReport = newToggle(defaultSplitPolicyReport, splitPolicyReportEnvVar)
ProtectManagedResources = newToggle(defaultProtectManagedResources, protectManagedResourcesEnvVar)
)
type Toggle interface {

View file

@ -3,6 +3,7 @@ package webhooks
import (
"context"
"crypto/tls"
"fmt"
"net/http"
"sync"
"time"
@ -10,9 +11,13 @@ import (
"github.com/go-logr/logr"
"github.com/julienschmidt/httprouter"
"github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/toggle"
"github.com/kyverno/kyverno/pkg/utils"
admissionutils "github.com/kyverno/kyverno/pkg/utils/admission"
"github.com/kyverno/kyverno/pkg/webhookconfig"
"github.com/kyverno/kyverno/pkg/webhooks/handlers"
admissionv1 "k8s.io/api/admission/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
type Server interface {
@ -118,10 +123,32 @@ func (s *server) cleanup(ctx context.Context) {
close(s.cleanUp)
}
func protect(inner handlers.AdmissionHandler) handlers.AdmissionHandler {
return func(logger logr.Logger, request *admissionv1.AdmissionRequest) *admissionv1.AdmissionResponse {
if toggle.ProtectManagedResources.Enabled() {
newResource, oldResource, err := utils.ExtractResources(nil, request)
if err != nil {
logger.Error(err, "Failed to extract resources")
return admissionutils.ResponseFailure(err.Error())
}
for _, resource := range []unstructured.Unstructured{newResource, oldResource} {
resLabels := resource.GetLabels()
if resLabels["app.kubernetes.io/managed-by"] == "kyverno" {
if request.UserInfo.Username != fmt.Sprintf("system:serviceaccount:%s:%s", config.KyvernoNamespace(), config.KyvernoServiceAccountName()) {
logger.Info("Access to the resource not authorized, this is a kyverno managed resource and should be altered only by kyverno")
return admissionutils.ResponseFailure("A kyverno managed resource can only be modified by kyverno")
}
}
}
}
return inner(logger, request)
}
}
func filter(configuration config.Configuration, inner handlers.AdmissionHandler) handlers.AdmissionHandler {
return handlers.Filter(configuration, inner)
}
func admission(logger logr.Logger, monitor *webhookconfig.Monitor, inner handlers.AdmissionHandler) http.HandlerFunc {
return handlers.Monitor(monitor, handlers.Admission(logger, inner))
return handlers.Monitor(monitor, handlers.Admission(logger, protect(inner)))
}