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

118 lines
3.1 KiB
Go
Raw Normal View History

package rbac
2019-11-08 18:58:09 -08:00
import (
"reflect"
2019-11-13 13:41:08 -08:00
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
2019-11-08 18:58:09 -08:00
utils "github.com/nirmata/kyverno/pkg/utils"
authenticationv1 "k8s.io/api/authentication/v1"
rbacv1 "k8s.io/api/rbac/v1"
)
const (
//SaPrefix defines the prefix for service accounts
2019-11-11 09:56:53 -08:00
SaPrefix = "system:serviceaccount:"
2019-11-08 18:58:09 -08:00
)
// MatchAdmissionInfo return true if the rule can be applied to the request
func MatchAdmissionInfo(rule kyverno.Rule, requestInfo kyverno.RequestInfo) bool {
2019-11-08 18:58:09 -08:00
// when processing existing resource, it does not contain requestInfo
// skip permission checking
if reflect.DeepEqual(requestInfo, kyverno.RequestInfo{}) {
2019-11-08 18:58:09 -08:00
return true
}
if !validateMatch(rule.MatchResources, requestInfo) {
return false
}
return validateExclude(rule.ExcludeResources, requestInfo)
}
// match:
// roles: role1, role2
// clusterRoles: clusterRole1,clusterRole2
// subjects: subject1, subject2
// validateMatch return true if (role1 || role2) and (clusterRole1 || clusterRole2)
// and (subject1 || subject2) are found in requestInfo, OR operation for each list
func validateMatch(match kyverno.MatchResources, requestInfo kyverno.RequestInfo) bool {
2019-11-08 18:58:09 -08:00
if len(match.Roles) > 0 {
if !matchRoleRefs(match.Roles, requestInfo.Roles) {
return false
}
}
if len(match.ClusterRoles) > 0 {
if !matchRoleRefs(match.ClusterRoles, requestInfo.ClusterRoles) {
return false
}
}
if len(match.Subjects) > 0 {
if !matchSubjects(match.Subjects, requestInfo.AdmissionUserInfo) {
return false
}
}
return true
}
// exclude:
// roles: role1, role2
// clusterRoles: clusterRole1,clusterRole2
// subjects: subject1, subject2
// validateExclude return true if none of the above found in requestInfo
// otherwise return false immediately means rule should not be applied
func validateExclude(exclude kyverno.ExcludeResources, requestInfo kyverno.RequestInfo) bool {
2019-11-08 18:58:09 -08:00
if len(exclude.Roles) > 0 {
if matchRoleRefs(exclude.Roles, requestInfo.Roles) {
return false
}
}
if len(exclude.ClusterRoles) > 0 {
if matchRoleRefs(exclude.ClusterRoles, requestInfo.ClusterRoles) {
return false
}
}
if len(exclude.Subjects) > 0 {
if matchSubjects(exclude.Subjects, requestInfo.AdmissionUserInfo) {
return false
}
}
return true
}
// matchRoleRefs return true if one of ruleRoleRefs exist in resourceRoleRefs
func matchRoleRefs(ruleRoleRefs, resourceRoleRefs []string) bool {
for _, ruleRoleRef := range ruleRoleRefs {
if utils.ContainsString(resourceRoleRefs, ruleRoleRef) {
return true
}
}
return false
}
// matchSubjects return true if one of ruleSubjects exist in userInfo
func matchSubjects(ruleSubjects []rbacv1.Subject, userInfo authenticationv1.UserInfo) bool {
userGroups := append(userInfo.Groups, userInfo.Username)
for _, subject := range ruleSubjects {
switch subject.Kind {
case "ServiceAccount":
2019-11-11 14:29:36 -08:00
if len(userInfo.Username) <= len(SaPrefix) {
continue
}
2019-11-08 18:58:09 -08:00
subjectServiceAccount := subject.Namespace + ":" + subject.Name
if userInfo.Username[len(SaPrefix):] == subjectServiceAccount {
return true
}
case "User", "Group":
if utils.ContainsString(userGroups, subject.Name) {
return true
}
}
}
2019-11-11 14:29:36 -08:00
2019-11-08 18:58:09 -08:00
return false
}