1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-28 10:28:36 +00:00

validation added for deny request for generated resource

This commit is contained in:
evalsocket 2020-07-10 11:48:27 -07:00
parent 85d2ac9f84
commit 014db64ed2
3 changed files with 104 additions and 31 deletions

View file

@ -272,6 +272,8 @@ func main() {
pInformer.Kyverno().V1().ClusterPolicies(),
kubeInformer.Rbac().V1().RoleBindings(),
kubeInformer.Rbac().V1().ClusterRoleBindings(),
kubeInformer.Rbac().V1().Roles(),
kubeInformer.Rbac().V1().ClusterRoles(),
eventGenerator,
pCacheController.Cache,
webhookRegistrationClient,

View file

@ -20,6 +20,8 @@ const (
SaPrefix = "system:serviceaccount:"
)
var defaultSuffixs = []string{"system:","kyverno:"}
//GetRoleRef gets the list of roles and cluster roles for the incoming api-request
func GetRoleRef(rbLister rbaclister.RoleBindingLister, crbLister rbaclister.ClusterRoleBindingLister, request *v1beta1.AdmissionRequest) (roles []string, clusterRoles []string, err error) {
keys := append(request.UserInfo.Groups, request.UserInfo.Username)
@ -127,3 +129,51 @@ func matchUserOrGroup(subject rbacv1.Subject, userInfo authenticationv1.UserInfo
return false
}
//IsRoleAuthorize is role authorize or not
func IsRoleAuthorize(rbLister rbaclister.RoleBindingLister, crbLister rbaclister.ClusterRoleBindingLister,rLister rbaclister.RoleLister, crLister rbaclister.ClusterRoleLister, request *v1beta1.AdmissionRequest) (bool,error) {
if strings.Contains(request.UserInfo.Username, SaPrefix) {
roles,clusterRoles,err := GetRoleRef(rbLister,crbLister,request)
if err != nil {
return false, err
}
for _,e := range clusterRoles {
role,err := crLister.Get(e);
if err != nil {
return false, err
}
labels := role.GetLabels()
if labels["kubernetes.io/bootstrapping"] == "rbac-defaults" {
return true,nil
}
}
for _,e := range roles {
roleData := strings.Split(e, ":")
role, err := rLister.Roles(roleData[0]).Get(roleData[1]);
if err != nil {
return false, err
}
labels := role.GetLabels()
if labels["kubernetes.io/bootstrapping"] == "rbac-defaults" {
return true, nil
}
}
} else {
// User or Group
var matchedRoles []bool
for _,e := range request.UserInfo.Groups {
for _,defaultSuffix := range defaultSuffixs {
if strings.Contains(e,defaultSuffix) {
matchedRoles = append(matchedRoles, true)
}
}
}
if len(matchedRoles) == len(request.UserInfo.Groups) {
return true,nil
}
}
return false,nil
}

View file

@ -8,6 +8,7 @@ import (
"fmt"
"io/ioutil"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"net/http"
"time"
@ -54,6 +55,12 @@ type WebhookServer struct {
// 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
@ -106,6 +113,8 @@ func NewWebhookServer(
pInformer kyvernoinformer.ClusterPolicyInformer,
rbInformer rbacinformer.RoleBindingInformer,
crbInformer rbacinformer.ClusterRoleBindingInformer,
rInformer rbacinformer.RoleInformer,
crInformer rbacinformer.ClusterRoleInformer,
eventGen event.Interface,
pCache policycache.Interface,
webhookRegistrationClient *webhookconfig.WebhookRegistrationClient,
@ -137,8 +146,10 @@ func NewWebhookServer(
pLister: pInformer.Lister(),
pSynced: pInformer.Informer().HasSynced,
rbLister: rbInformer.Lister(),
rLister: rInformer.Lister(),
rbSynced: rbInformer.Informer().HasSynced,
crbLister: crbInformer.Lister(),
crLister: crInformer.Lister(),
crbSynced: crbInformer.Informer().HasSynced,
eventGen: eventGen,
pCache: pCache,
@ -366,27 +377,25 @@ func (ws *WebhookServer) resourceMutation(request *v1beta1.AdmissionRequest) *v1
func (ws *WebhookServer) resourceValidation(request *v1beta1.AdmissionRequest) *v1beta1.AdmissionResponse {
logger := ws.log.WithName("resourceValidation").WithValues("uid", request.UID, "kind", request.Kind.Kind, "namespace", request.Namespace, "name", request.Name, "operation", request.Operation)
logger.V(4).Info("DEBUG","request",request)
checked, err := userinfo.IsRoleAuthorize(ws.rbLister, ws.crbLister,ws.rLister, ws.crLister, request)
if err != nil {
logger.Error(err, "failed to get RBAC infromation for request")
}
if request.Operation == v1beta1.Delete || request.Operation == v1beta1.Update {
// convert RAW to unstructured
resource, err := enginutils.ConvertToUnstructured(request.Object.Raw)
if err != nil {
//TODO: skip applying the admission control ?
logger.Error(err, "failed to convert RAR resource to unstructured format")
return &v1beta1.AdmissionResponse{
Allowed: false,
Result: &metav1.Status{
Status: "Failure",
Message: err.Error(),
},
if !checked {
if request.Operation == v1beta1.Delete || request.Operation == v1beta1.Update {
// convert RAW to unstructured
var resource *unstructured.Unstructured
if request.Operation == v1beta1.Delete {
resource, err = enginutils.ConvertToUnstructured(request.OldObject.Raw)
}else{
resource, err = enginutils.ConvertToUnstructured(request.Object.Raw)
}
}
if err != nil {
//TODO: skip applying the admission control ?
logger.Error(err, "failed to convert RAR resource to unstructured format")
oldResource, err := ws.client.GetResource(resource.GetKind(),resource.GetNamespace(),resource.GetName());
if err != nil {
if !apierrors.IsNotFound(err) {
logger.Error(err, "failed to get resource")
return &v1beta1.AdmissionResponse{
Allowed: false,
Result: &metav1.Status{
@ -395,22 +404,35 @@ func (ws *WebhookServer) resourceValidation(request *v1beta1.AdmissionRequest) *
},
}
}
}
labels := oldResource.GetLabels()
if labels != nil {
if labels["app.kubernetes.io/managed-by"] == "kyverno" && labels["app.kubernetes.io/synchronize"] == "enable" {
return &v1beta1.AdmissionResponse{
Allowed: false,
Result: &metav1.Status{
Status: "Failure",
Message: "You don't have permission to update resourses that is generated by kyverno",
},
oldResource, err := ws.client.GetResource(resource.GetKind(),resource.GetNamespace(),resource.GetName());
if err != nil {
if !apierrors.IsNotFound(err) {
logger.Error(err, "failed to get resource")
return &v1beta1.AdmissionResponse{
Allowed: false,
Result: &metav1.Status{
Status: "Failure",
Message: err.Error(),
},
}
}
}
labels := oldResource.GetLabels()
if labels != nil {
if labels["app.kubernetes.io/managed-by"] == "kyverno" && labels["app.kubernetes.io/synchronize"] == "enable" {
return &v1beta1.AdmissionResponse{
Allowed: false,
Result: &metav1.Status{
Status: "Failure",
Message: "You don't have permission to update resourses that is generated by kyverno",
},
}
}
}
}
}
if !ws.supportMudateValidate {
logger.Info("mutate and validate rules are not supported prior to Kubernetes 1.14.0")
return &v1beta1.AdmissionResponse{
@ -437,7 +459,6 @@ func (ws *WebhookServer) resourceValidation(request *v1beta1.AdmissionRequest) *
}
var roles, clusterRoles []string
var err error
// getRoleRef only if policy has roles/clusterroles defined
if containRBACinfo(policies) {
roles, clusterRoles, err = userinfo.GetRoleRef(ws.rbLister, ws.crbLister, request)