1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-06 16:06:56 +00:00
kyverno/pkg/userinfo/roleRef.go

192 lines
5.8 KiB
Go
Raw Normal View History

2019-11-11 14:52:09 -08:00
package userinfo
import (
"fmt"
2020-07-10 15:23:07 -07:00
"strings"
"github.com/nirmata/kyverno/pkg/engine"
2020-05-19 13:04:06 -07:00
"github.com/nirmata/kyverno/pkg/utils"
2019-11-11 14:52:09 -08:00
v1beta1 "k8s.io/api/admission/v1beta1"
authenticationv1 "k8s.io/api/authentication/v1"
rbacv1 "k8s.io/api/rbac/v1"
labels "k8s.io/apimachinery/pkg/labels"
rbaclister "k8s.io/client-go/listers/rbac/v1"
2020-03-17 16:25:34 -07:00
"sigs.k8s.io/controller-runtime/pkg/log"
2019-11-11 14:52:09 -08:00
)
2019-11-14 15:49:11 -08:00
const (
clusterrolekind = "ClusterRole"
rolekind = "Role"
2020-02-09 19:15:39 +05:30
SaPrefix = "system:serviceaccount:"
2019-11-14 15:49:11 -08:00
)
2020-07-10 15:23:07 -07:00
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)
2020-05-19 13:04:06 -07:00
if utils.SliceContains(keys, engine.ExcludeUserInfo...) {
return
}
// rolebindings
roleBindings, err := rbLister.List(labels.NewSelector())
2019-11-11 14:52:09 -08:00
if err != nil {
return roles, clusterRoles, fmt.Errorf("failed to list rolebindings: %v", err)
2019-11-11 14:52:09 -08:00
}
rs, crs, err := getRoleRefByRoleBindings(roleBindings, request.UserInfo)
if err != nil {
return roles, clusterRoles, err
2019-11-11 14:52:09 -08:00
}
roles = append(roles, rs...)
clusterRoles = append(clusterRoles, crs...)
2019-11-11 14:52:09 -08:00
// clusterrolebindings
clusterroleBindings, err := crbLister.List(labels.NewSelector())
2019-11-11 14:52:09 -08:00
if err != nil {
return roles, clusterRoles, fmt.Errorf("failed to list clusterrolebindings: %v", err)
}
crs, err = getRoleRefByClusterRoleBindings(clusterroleBindings, request.UserInfo)
2019-11-11 14:52:09 -08:00
if err != nil {
return roles, clusterRoles, err
}
clusterRoles = append(clusterRoles, crs...)
return roles, clusterRoles, nil
}
func getRoleRefByRoleBindings(roleBindings []*rbacv1.RoleBinding, userInfo authenticationv1.UserInfo) (roles []string, clusterRoles []string, err error) {
for _, rolebinding := range roleBindings {
for _, subject := range rolebinding.Subjects {
2019-11-11 14:52:09 -08:00
if !matchSubjectsMap(subject, userInfo) {
continue
}
switch rolebinding.RoleRef.Kind {
2019-11-14 15:49:11 -08:00
case rolekind:
roles = append(roles, rolebinding.Namespace+":"+rolebinding.RoleRef.Name)
2019-11-14 15:49:11 -08:00
case clusterrolekind:
clusterRoles = append(clusterRoles, rolebinding.RoleRef.Name)
2019-11-11 14:52:09 -08:00
}
}
}
return roles, clusterRoles, nil
}
// RoleRef in ClusterRoleBindings can only reference a ClusterRole in the global namespace
func getRoleRefByClusterRoleBindings(clusterroleBindings []*rbacv1.ClusterRoleBinding, userInfo authenticationv1.UserInfo) (clusterRoles []string, err error) {
for _, clusterRoleBinding := range clusterroleBindings {
for _, subject := range clusterRoleBinding.Subjects {
2019-11-11 14:52:09 -08:00
if !matchSubjectsMap(subject, userInfo) {
continue
}
2019-11-14 15:49:11 -08:00
if clusterRoleBinding.RoleRef.Kind == clusterrolekind {
clusterRoles = append(clusterRoles, clusterRoleBinding.RoleRef.Name)
2019-11-11 14:52:09 -08:00
}
}
}
return clusterRoles, nil
}
// matchSubjectsMap checks if userInfo found in subject
// return true directly if found a match
2019-11-14 15:49:11 -08:00
// subject.kind can only be ServiceAccount, User and Group
func matchSubjectsMap(subject rbacv1.Subject, userInfo authenticationv1.UserInfo) bool {
2019-11-11 14:52:09 -08:00
// ServiceAccount
2020-02-09 19:28:51 +05:30
if strings.Contains(userInfo.Username, SaPrefix) {
2019-11-11 14:52:09 -08:00
return matchServiceAccount(subject, userInfo)
2020-02-09 19:56:38 +05:30
} else {
// User or Group
return matchUserOrGroup(subject, userInfo)
2019-11-11 14:52:09 -08:00
}
}
// matchServiceAccount checks if userInfo sa matche the subject sa
// serviceaccount represents as saPrefix:namespace:name in userInfo
func matchServiceAccount(subject rbacv1.Subject, userInfo authenticationv1.UserInfo) bool {
subjectServiceAccount := subject.Namespace + ":" + subject.Name
2020-02-09 19:15:39 +05:30
if userInfo.Username[len(SaPrefix):] != subjectServiceAccount {
2019-11-11 14:52:09 -08:00
return false
}
2020-05-19 13:04:06 -07:00
log.Log.V(3).Info(fmt.Sprintf("found a matched service account not match: %s", subjectServiceAccount))
2019-11-11 14:52:09 -08:00
return true
}
// matchUserOrGroup checks if userInfo contains user or group info in a subject
func matchUserOrGroup(subject rbacv1.Subject, userInfo authenticationv1.UserInfo) bool {
2019-11-11 14:52:09 -08:00
keys := append(userInfo.Groups, userInfo.Username)
for _, key := range keys {
if subject.Name == key {
2020-05-19 13:04:06 -07:00
log.Log.V(3).Info(fmt.Sprintf("found a matched user/group '%v' in request userInfo: %v", subject.Name, keys))
2019-11-11 14:52:09 -08:00
return true
}
}
return false
}
//IsRoleAuthorize is role authorize or not
2020-07-10 15:23:07 -07:00
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) {
2020-07-10 15:23:07 -07:00
roles, clusterRoles, err := GetRoleRef(rbLister, crbLister, request)
if err != nil {
return false, err
}
2020-07-10 12:27:31 -07:00
2020-07-10 15:23:07 -07:00
for _, e := range clusterRoles {
if strings.Contains(e, "kyverno:") {
return true, nil
2020-07-10 16:59:17 -07:00
}
role, err := crLister.Get(e)
if err != nil {
return false, err
}
labels := role.GetLabels()
2020-07-10 15:23:07 -07:00
2020-07-10 16:59:17 -07:00
if labels["kubernetes.io/bootstrapping"] == "rbac-defaults" {
return true, nil
2020-07-10 15:23:07 -07:00
}
}
2020-07-10 15:23:07 -07:00
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 !strings.Contains(e, "kyverno:") {
if labels["kubernetes.io/bootstrapping"] == "rbac-defaults" {
return true, nil
}
2020-07-10 15:23:07 -07:00
}
}
2020-07-14 09:22:08 -07:00
return true, nil
2020-07-10 16:59:17 -07:00
}
// User or Group
excludeDevelopmentRole := []string{"minikube-user", "kubernetes-admin"}
for _, e := range excludeDevelopmentRole {
if strings.Contains(request.UserInfo.Username, e) {
return false, nil
2020-07-10 12:27:31 -07:00
}
2020-07-10 16:59:17 -07:00
}
var matchedRoles []bool
for _, e := range request.UserInfo.Groups {
for _, defaultSuffix := range defaultSuffixs {
if strings.Contains(e, defaultSuffix) {
matchedRoles = append(matchedRoles, true)
break
}
}
2020-07-10 16:59:17 -07:00
}
if len(matchedRoles) == len(request.UserInfo.Groups) {
return true, nil
}
2020-07-10 15:23:07 -07:00
return false, nil
}