2019-11-08 18:58:09 -08:00
|
|
|
package engine
|
|
|
|
|
|
|
|
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 (
|
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 RequestInfo) bool {
|
|
|
|
// when processing existing resource, it does not contain requestInfo
|
|
|
|
// skip permission checking
|
|
|
|
if reflect.DeepEqual(requestInfo, RequestInfo{}) {
|
|
|
|
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 RequestInfo) bool {
|
|
|
|
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 RequestInfo) bool {
|
|
|
|
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
|
|
|
|
}
|