324 lines
8.4 KiB
Go
324 lines
8.4 KiB
Go
package iam
|
|
|
|
import (
|
|
"github.com/golang/glog"
|
|
"k8s.io/api/rbac/v1"
|
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
|
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
"k8s.io/kubernetes/pkg/util/slice"
|
|
|
|
"kubesphere.io/kubesphere/pkg/client"
|
|
)
|
|
|
|
const ClusterRoleKind = "ClusterRole"
|
|
|
|
func GetUserNamespaces(username string, requiredRule v1.PolicyRule) (allNamespace bool, namespaces []string, err error) {
|
|
|
|
clusterRoles, err := GetClusterRoles(username)
|
|
|
|
if err != nil {
|
|
return false, nil, err
|
|
}
|
|
|
|
clusterRules := make([]v1.PolicyRule, 0)
|
|
for _, role := range clusterRoles {
|
|
clusterRules = append(clusterRules, role.Rules...)
|
|
}
|
|
|
|
if requiredRule.Size() == 0 {
|
|
if ruleValidate(clusterRules, v1.PolicyRule{
|
|
Verbs: []string{"get", "list"},
|
|
APIGroups: []string{""},
|
|
Resources: []string{"namespaces"},
|
|
}) {
|
|
return true, nil, nil
|
|
}
|
|
} else if ruleValidate(clusterRules, requiredRule) {
|
|
return true, nil, nil
|
|
}
|
|
|
|
roles, err := GetRoles(username)
|
|
|
|
if err != nil {
|
|
return false, nil, err
|
|
}
|
|
|
|
rulesMapping := make(map[string][]v1.PolicyRule, 0)
|
|
|
|
for _, role := range roles {
|
|
rules := rulesMapping[role.Namespace]
|
|
if rules == nil {
|
|
rules = make([]v1.PolicyRule, 0)
|
|
}
|
|
rules = append(rules, role.Rules...)
|
|
rulesMapping[role.Namespace] = rules
|
|
}
|
|
|
|
namespaces = make([]string, 0)
|
|
|
|
for namespace, rules := range rulesMapping {
|
|
if requiredRule.Size() == 0 || ruleValidate(rules, requiredRule) {
|
|
namespaces = append(namespaces, namespace)
|
|
}
|
|
}
|
|
|
|
return false, namespaces, nil
|
|
}
|
|
|
|
func DeleteRoleBindings(username string) error {
|
|
k8s := client.NewK8sClient()
|
|
|
|
roleBindings, err := k8s.RbacV1().RoleBindings("").List(meta_v1.ListOptions{})
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, roleBinding := range roleBindings.Items {
|
|
|
|
length1 := len(roleBinding.Subjects)
|
|
|
|
for index, subject := range roleBinding.Subjects {
|
|
if subject.Kind == v1.UserKind && subject.Name == username {
|
|
roleBinding.Subjects = append(roleBinding.Subjects[:index], roleBinding.Subjects[index+1:]...)
|
|
index--
|
|
}
|
|
}
|
|
|
|
length2 := len(roleBinding.Subjects)
|
|
|
|
if length2 == 0 {
|
|
k8s.RbacV1().RoleBindings(roleBinding.Namespace).Delete(roleBinding.Name, &meta_v1.DeleteOptions{})
|
|
} else if length2 < length1 {
|
|
k8s.RbacV1().RoleBindings(roleBinding.Namespace).Update(&roleBinding)
|
|
}
|
|
}
|
|
|
|
clusterRoleBindingList, err := k8s.RbacV1().ClusterRoleBindings().List(meta_v1.ListOptions{})
|
|
|
|
for _, roleBinding := range clusterRoleBindingList.Items {
|
|
length1 := len(roleBinding.Subjects)
|
|
|
|
for index, subject := range roleBinding.Subjects {
|
|
if subject.Kind == v1.UserKind && subject.Name == username {
|
|
roleBinding.Subjects = append(roleBinding.Subjects[:index], roleBinding.Subjects[index+1:]...)
|
|
index--
|
|
}
|
|
}
|
|
|
|
length2 := len(roleBinding.Subjects)
|
|
if length2 == 0 {
|
|
k8s.RbacV1().ClusterRoleBindings().Delete(roleBinding.Name, &meta_v1.DeleteOptions{})
|
|
} else if length2 < length1 {
|
|
k8s.RbacV1().ClusterRoleBindings().Update(&roleBinding)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func GetRole(namespace string, name string) (*v1.Role, error) {
|
|
k8s := client.NewK8sClient()
|
|
role, err := k8s.RbacV1().Roles(namespace).Get(name, meta_v1.GetOptions{})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return role, nil
|
|
}
|
|
|
|
func GetClusterRoleBindings(name string) ([]v1.ClusterRoleBinding, error) {
|
|
k8s := client.NewK8sClient()
|
|
roleBindingList, err := k8s.RbacV1().ClusterRoleBindings().List(meta_v1.ListOptions{})
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
items := make([]v1.ClusterRoleBinding, 0)
|
|
|
|
for _, roleBinding := range roleBindingList.Items {
|
|
if roleBinding.RoleRef.Name == name {
|
|
items = append(items, roleBinding)
|
|
}
|
|
}
|
|
|
|
return items, nil
|
|
}
|
|
|
|
func GetRoleBindings(namespace string, name string) ([]v1.RoleBinding, error) {
|
|
k8s := client.NewK8sClient()
|
|
|
|
roleBindingList, err := k8s.RbacV1().RoleBindings(namespace).List(meta_v1.ListOptions{})
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
items := make([]v1.RoleBinding, 0)
|
|
|
|
for _, roleBinding := range roleBindingList.Items {
|
|
if roleBinding.RoleRef.Name == name {
|
|
items = append(items, roleBinding)
|
|
}
|
|
}
|
|
|
|
return items, nil
|
|
}
|
|
|
|
func GetClusterRole(name string) (*v1.ClusterRole, error) {
|
|
k8s := client.NewK8sClient()
|
|
role, err := k8s.RbacV1().ClusterRoles().Get(name, meta_v1.GetOptions{})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return role, nil
|
|
}
|
|
|
|
func GetRoles(username string) ([]v1.Role, error) {
|
|
k8s := client.NewK8sClient()
|
|
|
|
roleBindings, err := k8s.RbacV1().RoleBindings("").List(meta_v1.ListOptions{})
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
roles := make([]v1.Role, 0)
|
|
|
|
for _, roleBinding := range roleBindings.Items {
|
|
|
|
for _, subject := range roleBinding.Subjects {
|
|
if subject.Kind == v1.UserKind && subject.Name == username {
|
|
if roleBinding.RoleRef.Kind == ClusterRoleKind {
|
|
clusterRole, err := k8s.RbacV1().ClusterRoles().Get(roleBinding.RoleRef.Name, meta_v1.GetOptions{})
|
|
if err == nil {
|
|
var role = v1.Role{TypeMeta: (*clusterRole).TypeMeta, ObjectMeta: (*clusterRole).ObjectMeta, Rules: (*clusterRole).Rules}
|
|
role.Namespace = roleBinding.Namespace
|
|
roles = append(roles, role)
|
|
break
|
|
} else if apierrors.IsNotFound(err) {
|
|
glog.Infoln(err.Error())
|
|
break
|
|
} else {
|
|
return nil, err
|
|
}
|
|
|
|
} else {
|
|
if subject.Kind == v1.UserKind && subject.Name == username {
|
|
rule, err := k8s.RbacV1().Roles(roleBinding.Namespace).Get(roleBinding.RoleRef.Name, meta_v1.GetOptions{})
|
|
if err == nil {
|
|
roles = append(roles, *rule)
|
|
break
|
|
} else if apierrors.IsNotFound(err) {
|
|
glog.Infoln(err.Error())
|
|
break
|
|
} else {
|
|
return nil, err
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return roles, nil
|
|
}
|
|
|
|
func GetClusterRoles(username string) ([]v1.ClusterRole, error) {
|
|
k8s := client.NewK8sClient()
|
|
|
|
clusterRoleBindings, err := k8s.RbacV1().ClusterRoleBindings().List(meta_v1.ListOptions{})
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
roles := make([]v1.ClusterRole, 0)
|
|
|
|
for _, roleBinding := range clusterRoleBindings.Items {
|
|
for _, subject := range roleBinding.Subjects {
|
|
if subject.Kind == v1.UserKind && subject.Name == username {
|
|
if roleBinding.RoleRef.Kind == ClusterRoleKind {
|
|
role, err := k8s.RbacV1().ClusterRoles().Get(roleBinding.RoleRef.Name, meta_v1.GetOptions{})
|
|
if err == nil {
|
|
if role.Annotations == nil {
|
|
role.Annotations = make(map[string]string, 0)
|
|
}
|
|
role.Annotations["rbac.authorization.k8s.io/clusterrolebinding"] = roleBinding.Name
|
|
roles = append(roles, *role)
|
|
break
|
|
} else if apierrors.IsNotFound(err) {
|
|
glog.Infoln(err.Error())
|
|
break
|
|
} else {
|
|
return nil, err
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return roles, nil
|
|
}
|
|
|
|
func ruleValidate(rules []v1.PolicyRule, rule v1.PolicyRule) bool {
|
|
|
|
for _, apiGroup := range rule.APIGroups {
|
|
if len(rule.NonResourceURLs) == 0 {
|
|
for _, resource := range rule.Resources {
|
|
|
|
//if len(Rule.ResourceNames) == 0 {
|
|
|
|
for _, verb := range rule.Verbs {
|
|
if !verbValidate(rules, apiGroup, "", resource, "", verb) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
//} else {
|
|
// for _, resourceName := range Rule.ResourceNames {
|
|
// for _, verb := range Rule.Verbs {
|
|
// if !verbValidate(rules, apiGroup, "", resource, resourceName, verb) {
|
|
// return false
|
|
// }
|
|
// }
|
|
// }
|
|
//}
|
|
}
|
|
} else {
|
|
for _, nonResourceURL := range rule.NonResourceURLs {
|
|
for _, verb := range rule.Verbs {
|
|
if !verbValidate(rules, apiGroup, nonResourceURL, "", "", verb) {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func verbValidate(rules []v1.PolicyRule, apiGroup string, nonResourceURL string, resource string, resourceName string, verb string) bool {
|
|
for _, rule := range rules {
|
|
if slice.ContainsString(rule.APIGroups, apiGroup, nil) || slice.ContainsString(rule.APIGroups, v1.APIGroupAll, nil) {
|
|
if slice.ContainsString(rule.Verbs, verb, nil) || slice.ContainsString(rule.Verbs, v1.VerbAll, nil) {
|
|
if nonResourceURL == "" {
|
|
if slice.ContainsString(rule.Resources, resource, nil) || slice.ContainsString(rule.Resources, v1.ResourceAll, nil) {
|
|
if resourceName == "" {
|
|
return true
|
|
} else if slice.ContainsString(rule.ResourceNames, resourceName, nil) || slice.ContainsString(rule.Resources, v1.ResourceAll, nil) {
|
|
return true
|
|
}
|
|
}
|
|
} else if slice.ContainsString(rule.NonResourceURLs, nonResourceURL, nil) || slice.ContainsString(rule.NonResourceURLs, v1.NonResourceAll, nil) {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|