2019-11-11 14:52:09 -08:00
|
|
|
package userinfo
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
v1beta1 "k8s.io/api/admission/v1beta1"
|
|
|
|
authenticationv1 "k8s.io/api/authentication/v1"
|
2019-11-11 15:43:13 -08:00
|
|
|
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-01-24 12:05:53 -08:00
|
|
|
//GetRoleRef gets the list of roles and cluster roles for the incoming api-request
|
2019-11-11 15:43:13 -08:00
|
|
|
func GetRoleRef(rbLister rbaclister.RoleBindingLister, crbLister rbaclister.ClusterRoleBindingLister, request *v1beta1.AdmissionRequest) (roles []string, clusterRoles []string, err error) {
|
|
|
|
// rolebindings
|
|
|
|
roleBindings, err := rbLister.List(labels.NewSelector())
|
2019-11-11 14:52:09 -08:00
|
|
|
if err != nil {
|
2019-11-11 15:43:13 -08:00
|
|
|
return roles, clusterRoles, fmt.Errorf("failed to list rolebindings: %v", err)
|
2019-11-11 14:52:09 -08:00
|
|
|
}
|
|
|
|
|
2019-11-11 15:43:13 -08:00
|
|
|
rs, crs, err := getRoleRefByRoleBindings(roleBindings, request.UserInfo)
|
|
|
|
if err != nil {
|
|
|
|
return roles, clusterRoles, err
|
2019-11-11 14:52:09 -08:00
|
|
|
}
|
2019-11-11 15:43:13 -08:00
|
|
|
roles = append(roles, rs...)
|
|
|
|
clusterRoles = append(clusterRoles, crs...)
|
2019-11-11 14:52:09 -08:00
|
|
|
|
|
|
|
// clusterrolebindings
|
2019-11-11 15:43:13 -08:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2019-11-11 15:43:13 -08:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2019-11-11 15:43:13 -08:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2019-11-11 15:43:13 -08:00
|
|
|
switch rolebinding.RoleRef.Kind {
|
2019-11-14 15:49:11 -08:00
|
|
|
case rolekind:
|
2019-11-11 15:43:13 -08:00
|
|
|
roles = append(roles, rolebinding.Namespace+":"+rolebinding.RoleRef.Name)
|
2019-11-14 15:49:11 -08:00
|
|
|
case clusterrolekind:
|
2019-11-11 15:43:13 -08:00
|
|
|
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
|
2019-11-11 15:43:13 -08:00
|
|
|
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 {
|
2019-11-11 15:43:13 -08:00
|
|
|
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
|
2019-11-11 15:43:13 -08:00
|
|
|
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
|
2019-11-11 15:43:13 -08:00
|
|
|
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 {
|
2020-03-17 16:25:34 -07:00
|
|
|
log.Log.V(3).Info(fmt.Sprintf("service account not match, expect %s, got %s", subjectServiceAccount, userInfo.Username[len(SaPrefix):]))
|
2019-11-11 14:52:09 -08:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// matchUserOrGroup checks if userInfo contains user or group info in a subject
|
2019-11-11 15:43:13 -08:00
|
|
|
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 {
|
2019-11-11 15:43:13 -08:00
|
|
|
if subject.Name == key {
|
2019-11-11 14:52:09 -08:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-17 16:25:34 -07:00
|
|
|
log.Log.V(3).Info(fmt.Sprintf("user/group '%v' info not found in request userInfo: %v", subject.Name, keys))
|
2019-11-11 14:52:09 -08:00
|
|
|
return false
|
|
|
|
}
|