36 Star 395 Fork 71

GVPrancher / rancher

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
manager.go 24.36 KB
一键复制 编辑 原始数据 按行查看 历史
Dan Ramich 提交于 2018-08-03 16:35 . Properly cleanup clusterRoleBindings
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796
package auth
import (
"reflect"
"fmt"
"github.com/pkg/errors"
"github.com/rancher/norman/objectclient"
"github.com/rancher/norman/types/slice"
v13 "github.com/rancher/types/apis/core/v1"
"github.com/rancher/types/apis/management.cattle.io/v3"
typesrbacv1 "github.com/rancher/types/apis/rbac.authorization.k8s.io/v1"
"github.com/rancher/types/config"
"github.com/rancher/types/user"
"github.com/sirupsen/logrus"
"k8s.io/api/rbac/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/tools/cache"
)
func newRTBLifecycles(management *config.ManagementContext) (*prtbLifecycle, *crtbLifecycle) {
crbInformer := management.RBAC.ClusterRoleBindings("").Controller().Informer()
crbIndexers := map[string]cache.IndexFunc{
rbByRoleAndSubjectIndex: rbByRoleAndSubject,
}
crbInformer.AddIndexers(crbIndexers)
rbInformer := management.RBAC.RoleBindings("").Controller().Informer()
rbIndexers := map[string]cache.IndexFunc{
rbByOwnerIndex: rbByOwner,
rbByRoleAndSubjectIndex: rbByRoleAndSubject,
}
rbInformer.AddIndexers(rbIndexers)
prtb := &prtbLifecycle{
mgr: &manager{
mgmt: management,
projectLister: management.Management.Projects("").Controller().Lister(),
crbLister: management.RBAC.ClusterRoleBindings("").Controller().Lister(),
crLister: management.RBAC.ClusterRoles("").Controller().Lister(),
rLister: management.RBAC.Roles("").Controller().Lister(),
rbLister: management.RBAC.RoleBindings("").Controller().Lister(),
rtLister: management.Management.RoleTemplates("").Controller().Lister(),
nsLister: management.Core.Namespaces("").Controller().Lister(),
rbIndexer: rbInformer.GetIndexer(),
crbIndexer: crbInformer.GetIndexer(),
userMGR: management.UserManager,
controller: ptrbMGMTController,
},
projectLister: management.Management.Projects("").Controller().Lister(),
clusterLister: management.Management.Clusters("").Controller().Lister(),
}
crtb := &crtbLifecycle{
mgr: &manager{
mgmt: management,
projectLister: management.Management.Projects("").Controller().Lister(),
crbLister: management.RBAC.ClusterRoleBindings("").Controller().Lister(),
crLister: management.RBAC.ClusterRoles("").Controller().Lister(),
rLister: management.RBAC.Roles("").Controller().Lister(),
rbLister: management.RBAC.RoleBindings("").Controller().Lister(),
rtLister: management.Management.RoleTemplates("").Controller().Lister(),
nsLister: management.Core.Namespaces("").Controller().Lister(),
rbIndexer: rbInformer.GetIndexer(),
crbIndexer: crbInformer.GetIndexer(),
userMGR: management.UserManager,
controller: ctrbMGMTController,
},
clusterLister: management.Management.Clusters("").Controller().Lister(),
}
return prtb, crtb
}
type manager struct {
projectLister v3.ProjectLister
crLister typesrbacv1.ClusterRoleLister
rLister typesrbacv1.RoleLister
rbLister typesrbacv1.RoleBindingLister
crbLister typesrbacv1.ClusterRoleBindingLister
rtLister v3.RoleTemplateLister
nsLister v13.NamespaceLister
rbIndexer cache.Indexer
crbIndexer cache.Indexer
mgmt *config.ManagementContext
userMGR user.Manager
controller string
}
// When a CRTB is created that gives a subject some permissions in a project or cluster, we need to create a "membership" binding
// that gives the subject access to the the cluster custom resource itself
// This is painfully similar to ensureProjectMemberBinding, but making one function that handles both is overly complex
func (m *manager) ensureClusterMembershipBinding(roleName, rtbUID string, cluster *v3.Cluster, makeOwner bool, subject v1.Subject) error {
if err := m.createClusterMembershipRole(roleName, cluster, makeOwner); err != nil {
return err
}
key := rbRoleSubjectKey(roleName, subject)
set := labels.Set(map[string]string{rtbUID: membershipBindingOwner})
crbs, err := m.crbLister.List("", set.AsSelector())
if err != nil {
return err
}
var crb *v1.ClusterRoleBinding
for _, iCRB := range crbs {
if len(iCRB.Subjects) != 1 {
iKey := rbRoleSubjectKey(iCRB.RoleRef.Name, iCRB.Subjects[0])
if iKey == key {
crb = iCRB
continue
}
}
if err := m.reconcileClusterMembershipBindingForDelete(roleName, rtbUID); err != nil {
return err
}
}
if crb != nil {
return nil
}
objs, err := m.crbIndexer.ByIndex(rbByRoleAndSubjectIndex, key)
if err != nil {
return err
}
if len(objs) == 0 {
logrus.Infof("[%v] Creating clusterRoleBinding for membership in cluster %v for subject %v", m.controller, cluster.Name, subject.Name)
_, err := m.mgmt.RBAC.ClusterRoleBindings("").Create(&v1.ClusterRoleBinding{
ObjectMeta: metav1.ObjectMeta{
GenerateName: "clusterrolebinding-",
Labels: map[string]string{
rtbUID: membershipBindingOwner,
},
},
Subjects: []v1.Subject{subject},
RoleRef: v1.RoleRef{
Kind: "ClusterRole",
Name: roleName,
},
})
return err
}
crb, _ = objs[0].(*v1.ClusterRoleBinding)
for owner := range crb.Labels {
if rtbUID == owner {
return nil
}
}
crb = crb.DeepCopy()
if crb.Labels == nil {
crb.Labels = map[string]string{}
}
crb.Labels[rtbUID] = membershipBindingOwner
logrus.Infof("[%v] Updating clusterRoleBinding %v for cluster membership in cluster %v for subject %v", m.controller, crb.Name, cluster.Name, subject.Name)
_, err = m.mgmt.RBAC.ClusterRoleBindings("").Update(crb)
return err
}
// When a PRTB is created that gives a subject some permissions in a project or cluster, we need to create a "membership" binding
// that gives the subject access to the the project/cluster custom resource itself
func (m *manager) ensureProjectMembershipBinding(roleName, rtbUID, namespace string, project *v3.Project, makeOwner bool, subject v1.Subject) error {
if err := m.createProjectMembershipRole(roleName, namespace, project, makeOwner); err != nil {
return err
}
key := rbRoleSubjectKey(roleName, subject)
set := labels.Set(map[string]string{rtbUID: membershipBindingOwner})
rbs, err := m.rbLister.List("", set.AsSelector())
if err != nil {
return err
}
var rb *v1.RoleBinding
for _, iRB := range rbs {
if len(iRB.Subjects) != 1 {
iKey := rbRoleSubjectKey(iRB.RoleRef.Name, iRB.Subjects[0])
if iKey == key {
rb = iRB
continue
}
}
if err := m.reconcileProjectMembershipBindingForDelete(namespace, roleName, rtbUID); err != nil {
return err
}
}
if rb != nil {
return nil
}
objs, err := m.rbIndexer.ByIndex(rbByRoleAndSubjectIndex, key)
if err != nil {
return err
}
if len(objs) == 0 {
logrus.Infof("[%v] Creating roleBinding for membership in project %v for subject %v", m.controller, project.Name, subject.Name)
_, err := m.mgmt.RBAC.RoleBindings(namespace).Create(&v1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{
GenerateName: "rolebinding-",
Labels: map[string]string{
rtbUID: membershipBindingOwner,
},
},
Subjects: []v1.Subject{subject},
RoleRef: v1.RoleRef{
Kind: "Role",
Name: roleName,
},
})
return err
}
rb, _ = objs[0].(*v1.RoleBinding)
for owner := range rb.Labels {
if rtbUID == owner {
return nil
}
}
rb = rb.DeepCopy()
if rb.Labels == nil {
rb.Labels = map[string]string{}
}
rb.Labels[rtbUID] = membershipBindingOwner
logrus.Infof("[%v] Updating roleBinding %v for project membership in project %v for subject %v", m.controller, rb.Name, project.Name, subject.Name)
_, err = m.mgmt.RBAC.RoleBindings(namespace).Update(rb)
return err
}
// Creates a role that lets the bound subject see (if they are an ordinary member) the project or cluster in the mgmt api
// (or CRUD the project/cluster if they are an owner)
func (m *manager) createClusterMembershipRole(roleName string, cluster *v3.Cluster, makeOwner bool) error {
if cr, _ := m.crLister.Get("", roleName); cr == nil {
return m.createMembershipRole(clusterResource, roleName, makeOwner, cluster, m.mgmt.RBAC.ClusterRoles("").ObjectClient())
}
return nil
}
// Creates a role that lets the bound subject see (if they are an ordinary member) the project in the mgmt api
// (or CRUD the project if they are an owner)
func (m *manager) createProjectMembershipRole(roleName, namespace string, project *v3.Project, makeOwner bool) error {
if cr, _ := m.rLister.Get(namespace, roleName); cr == nil {
return m.createMembershipRole(projectResource, roleName, makeOwner, project, m.mgmt.RBAC.Roles(namespace).ObjectClient())
}
return nil
}
func (m *manager) createMembershipRole(resourceType, roleName string, makeOwner bool, ownerObject interface{}, client *objectclient.ObjectClient) error {
metaObj, err := meta.Accessor(ownerObject)
if err != nil {
return err
}
typeMeta, err := meta.TypeAccessor(ownerObject)
if err != nil {
return err
}
rules := []v1.PolicyRule{
{
APIGroups: []string{"management.cattle.io"},
Resources: []string{resourceType},
ResourceNames: []string{metaObj.GetName()},
Verbs: []string{"get"},
},
}
if makeOwner {
rules[0].Verbs = []string{"*"}
} else {
rules[0].Verbs = []string{"get"}
}
logrus.Infof("[%v] Creating clusterRole %v", m.controller, roleName)
_, err = client.Create(&v1.ClusterRole{
ObjectMeta: metav1.ObjectMeta{
Name: roleName,
OwnerReferences: []metav1.OwnerReference{
{
APIVersion: typeMeta.GetAPIVersion(),
Kind: typeMeta.GetKind(),
Name: metaObj.GetName(),
UID: metaObj.GetUID(),
},
},
},
Rules: rules,
})
return err
}
// The CRTB has been deleted or modified, either delete or update the membership binding so that the subject
// is removed from the cluster if they should be
func (m *manager) reconcileClusterMembershipBindingForDelete(roleToKeep, rtbUID string) error {
list := func(ns string, selector labels.Selector) ([]runtime.Object, error) {
rbs, err := m.crbLister.List(ns, selector)
if err != nil {
return nil, err
}
var items []runtime.Object
for _, rb := range rbs {
items = append(items, rb.DeepCopy())
}
return items, nil
}
convert := func(i interface{}) string {
rb, _ := i.(*v1.ClusterRoleBinding)
return rb.RoleRef.Name
}
return m.reconcileMembershipBindingForDelete("", roleToKeep, rtbUID, list, convert, m.mgmt.RBAC.ClusterRoleBindings("").ObjectClient())
}
// The PRTB has been deleted, either delete or update the project membership binding so that the subject
// is removed from the project if they should be
func (m *manager) reconcileProjectMembershipBindingForDelete(namespace, roleToKeep, rtbUID string) error {
list := func(ns string, selector labels.Selector) ([]runtime.Object, error) {
rbs, err := m.rbLister.List(ns, selector)
if err != nil {
return nil, err
}
var items []runtime.Object
for _, rb := range rbs {
items = append(items, rb.DeepCopy())
}
return items, nil
}
convert := func(i interface{}) string {
rb, _ := i.(*v1.RoleBinding)
return rb.RoleRef.Name
}
return m.reconcileMembershipBindingForDelete(namespace, roleToKeep, rtbUID, list, convert, m.mgmt.RBAC.RoleBindings(namespace).ObjectClient())
}
type listFn func(ns string, selector labels.Selector) ([]runtime.Object, error)
type convertFn func(i interface{}) string
func (m *manager) reconcileMembershipBindingForDelete(namespace, roleToKeep, rtbUID string, list listFn, convert convertFn, client *objectclient.ObjectClient) error {
set := labels.Set(map[string]string{rtbUID: membershipBindingOwner})
roleBindings, err := list(namespace, set.AsSelector())
if err != nil {
return err
}
for _, rb := range roleBindings {
objMeta, err := meta.Accessor(rb)
if err != nil {
return err
}
roleName := convert(rb)
if roleName == roleToKeep {
continue
}
var otherOwners bool
for k, v := range objMeta.GetLabels() {
if k == rtbUID && v == membershipBindingOwner {
delete(objMeta.GetLabels(), k)
} else if v == membershipBindingOwner {
// Another crtb is also linked to this roleBinding so don't delete
otherOwners = true
}
}
if !otherOwners {
logrus.Infof("[%v] Deleting roleBinding %v", m.controller, objMeta.GetName())
if err := client.Delete(objMeta.GetName(), &metav1.DeleteOptions{}); err != nil {
if apierrors.IsNotFound(err) {
continue
}
return err
}
} else {
logrus.Infof("[%v] Updating owner label for roleBinding %v", m.controller, objMeta.GetName())
if _, err := client.Update(objMeta.GetName(), rb); err != nil {
return err
}
}
}
return nil
}
// Certain resources (projects, machines, prtbs, crtbs, clusterevents, etc) exist in the mangement plane but are scoped to clusters or
// projects. They need special RBAC handling because the need to be authorized just inside of the namespace that backs the project
// or cluster they belong to.
func (m *manager) grantManagementPlanePrivileges(roleTemplateName string, resources []string, subject v1.Subject, binding interface{}) error {
bindingMeta, err := meta.Accessor(binding)
if err != nil {
return err
}
bindingTypeMeta, err := meta.TypeAccessor(binding)
if err != nil {
return err
}
namespace := bindingMeta.GetNamespace()
roles, err := m.gatherAndDedupeRoles(roleTemplateName)
if err != nil {
return err
}
desiredRBs := map[string]*v1.RoleBinding{}
roleBindings := m.mgmt.RBAC.RoleBindings(namespace)
for _, role := range roles {
resourceToVerbs := map[string]map[string]bool{}
for _, resource := range resources {
verbs, err := m.checkForManagementPlaneRules(role, resource)
if err != nil {
return err
}
if len(verbs) > 0 {
resourceToVerbs[resource] = verbs
bindingName := bindingMeta.GetName() + "-" + role.Name
if _, ok := desiredRBs[bindingName]; !ok {
desiredRBs[bindingName] = &v1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: bindingName,
OwnerReferences: []metav1.OwnerReference{
{
APIVersion: bindingTypeMeta.GetAPIVersion(),
Kind: bindingTypeMeta.GetKind(),
Name: bindingMeta.GetName(),
UID: bindingMeta.GetUID(),
},
},
},
Subjects: []v1.Subject{subject},
RoleRef: v1.RoleRef{
Kind: "Role",
Name: role.Name,
},
}
}
}
}
if len(resourceToVerbs) > 0 {
if err := m.reconcileManagementPlaneRole(namespace, resourceToVerbs, role); err != nil {
return err
}
}
}
currentRBs := map[string]*v1.RoleBinding{}
current, err := m.rbIndexer.ByIndex(rbByOwnerIndex, string(bindingMeta.GetUID()))
if err != nil {
return err
}
for _, c := range current {
rb := c.(*v1.RoleBinding)
currentRBs[rb.Name] = rb
}
return m.reconcileDesiredMGMTPlaneRoleBindings(currentRBs, desiredRBs, roleBindings)
}
// grantManagementClusterScopedPrivilegesInProjectNamespace ensures that rolebindings for roles like cluster-owner (that should be able to fully
// manage all projects in a cluster) grant proper permissions to project-scoped resources. Specifically, this satisfies the use case that
// a cluster owner should be able to manage the members of all projects in their cluster
func (m *manager) grantManagementClusterScopedPrivilegesInProjectNamespace(roleTemplateName, projectNamespace string, resources []string,
subject v1.Subject, binding *v3.ClusterRoleTemplateBinding) error {
roles, err := m.gatherAndDedupeRoles(roleTemplateName)
if err != nil {
return err
}
desiredRBs := map[string]*v1.RoleBinding{}
roleBindings := m.mgmt.RBAC.RoleBindings(projectNamespace)
for _, role := range roles {
resourceToVerbs := map[string]map[string]bool{}
for _, resource := range resources {
verbs, err := m.checkForManagementPlaneRules(role, resource)
if err != nil {
return err
}
if len(verbs) > 0 {
resourceToVerbs[resource] = verbs
bindingName := binding.Name + "-" + role.Name
if _, ok := desiredRBs[bindingName]; !ok {
desiredRBs[bindingName] = &v1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: bindingName,
Labels: map[string]string{
string(binding.UID): crtbInProjectBindingOwner,
},
},
Subjects: []v1.Subject{subject},
RoleRef: v1.RoleRef{
Kind: "Role",
Name: role.Name,
},
}
}
}
}
if len(resourceToVerbs) > 0 {
if err := m.reconcileManagementPlaneRole(projectNamespace, resourceToVerbs, role); err != nil {
return err
}
}
}
currentRBs := map[string]*v1.RoleBinding{}
set := labels.Set(map[string]string{string(binding.UID): crtbInProjectBindingOwner})
current, err := m.rbLister.List(projectNamespace, set.AsSelector())
if err != nil {
return err
}
for _, rb := range current {
currentRBs[rb.Name] = rb
}
return m.reconcileDesiredMGMTPlaneRoleBindings(currentRBs, desiredRBs, roleBindings)
}
// grantManagementProjectScopedPrivilegesInClusterNamespace ensures that project roles grant permissions to certain cluster-scoped
// resources(notifier, clusterpipelines). These resources exists in cluster namespace but need to be shared between projects.
func (m *manager) grantManagementProjectScopedPrivilegesInClusterNamespace(roleTemplateName, clusterNamespace string, resources []string,
subject v1.Subject, binding *v3.ProjectRoleTemplateBinding) error {
roles, err := m.gatherAndDedupeRoles(roleTemplateName)
if err != nil {
return err
}
desiredRBs := map[string]*v1.RoleBinding{}
roleBindings := m.mgmt.RBAC.RoleBindings(clusterNamespace)
for _, role := range roles {
resourceToVerbs := map[string]map[string]bool{}
for _, resource := range resources {
verbs, err := m.checkForManagementPlaneRules(role, resource)
if err != nil {
return err
}
if len(verbs) > 0 {
resourceToVerbs[resource] = verbs
bindingName := fmt.Sprintf("%s-%s-%s", binding.Namespace, binding.Name, role.Name)
if _, ok := desiredRBs[bindingName]; !ok {
desiredRBs[bindingName] = &v1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: bindingName,
Labels: map[string]string{
string(binding.UID): prtbInClusterBindingOwner,
},
},
Subjects: []v1.Subject{subject},
RoleRef: v1.RoleRef{
Kind: "Role",
Name: role.Name,
},
}
}
}
}
if len(resourceToVerbs) > 0 {
if err := m.reconcileManagementPlaneRole(clusterNamespace, resourceToVerbs, role); err != nil {
return err
}
}
}
currentRBs := map[string]*v1.RoleBinding{}
set := labels.Set(map[string]string{string(binding.UID): prtbInClusterBindingOwner})
current, err := m.rbLister.List(clusterNamespace, set.AsSelector())
if err != nil {
return err
}
for _, rb := range current {
currentRBs[rb.Name] = rb
}
return m.reconcileDesiredMGMTPlaneRoleBindings(currentRBs, desiredRBs, roleBindings)
}
func (m *manager) gatherAndDedupeRoles(roleTemplateName string) (map[string]*v3.RoleTemplate, error) {
rt, err := m.rtLister.Get("", roleTemplateName)
if err != nil {
return nil, err
}
allRoles := map[string]*v3.RoleTemplate{}
if err := m.gatherRoleTemplates(rt, allRoles); err != nil {
return nil, err
}
//de-dupe
roles := map[string]*v3.RoleTemplate{}
for _, role := range allRoles {
roles[role.Name] = role
}
return roles, nil
}
func (m *manager) reconcileDesiredMGMTPlaneRoleBindings(currentRBs, desiredRBs map[string]*v1.RoleBinding, roleBindings typesrbacv1.RoleBindingInterface) error {
rbsToDelete := map[string]bool{}
processed := map[string]bool{}
for _, rb := range currentRBs {
// protect against an rb being in the list more than once (shouldn't happen, but just to be safe)
if ok := processed[rb.Name]; ok {
continue
}
processed[rb.Name] = true
if _, ok := desiredRBs[rb.Name]; ok {
delete(desiredRBs, rb.Name)
} else {
rbsToDelete[rb.Name] = true
}
}
for _, rb := range desiredRBs {
logrus.Infof("[%v] Creating roleBinding for subject %v with role %v in namespace %v", m.controller, rb.Subjects[0].Name, rb.RoleRef.Name, rb.Namespace)
_, err := roleBindings.Create(rb)
if err != nil {
return err
}
}
for name := range rbsToDelete {
logrus.Infof("[%v] Deleting roleBinding %v", m.controller, name)
if err := roleBindings.Delete(name, &metav1.DeleteOptions{}); err != nil {
return err
}
}
return nil
}
// If the roleTemplate has rules granting access to a management plane resource, return the verbs for those rules
func (m *manager) checkForManagementPlaneRules(role *v3.RoleTemplate, managementPlaneResource string) (map[string]bool, error) {
var rules []v1.PolicyRule
if role.External {
externalRole, err := m.crLister.Get("", role.Name)
if err != nil && !apierrors.IsNotFound(err) {
// dont error if it doesnt exist
return nil, err
}
if externalRole != nil {
rules = externalRole.Rules
}
} else {
rules = role.Rules
}
verbs := map[string]bool{}
for _, rule := range rules {
if (slice.ContainsString(rule.Resources, managementPlaneResource) || slice.ContainsString(rule.Resources, "*")) && len(rule.ResourceNames) == 0 {
for _, v := range rule.Verbs {
verbs[v] = true
}
}
}
return verbs, nil
}
func (m *manager) reconcileManagementPlaneRole(namespace string, resourceToVerbs map[string]map[string]bool, rt *v3.RoleTemplate) error {
roleCli := m.mgmt.RBAC.Roles(namespace)
update := false
if role, err := m.rLister.Get(namespace, rt.Name); err == nil && role != nil {
newRole := role.DeepCopy()
for resource, newVerbs := range resourceToVerbs {
currentVerbs := map[string]bool{}
for _, rule := range role.Rules {
if slice.ContainsString(rule.Resources, resource) {
for _, v := range rule.Verbs {
currentVerbs[v] = true
}
}
}
if !reflect.DeepEqual(currentVerbs, newVerbs) {
update = true
role = role.DeepCopy()
added := false
for i, rule := range newRole.Rules {
if slice.ContainsString(rule.Resources, resource) {
newRole.Rules[i] = buildRule(resource, newVerbs)
added = true
}
}
if !added {
newRole.Rules = append(newRole.Rules, buildRule(resource, newVerbs))
}
}
}
if update {
logrus.Infof("[%v] Updating role %v in namespace %v", m.controller, newRole.Name, namespace)
_, err := roleCli.Update(newRole)
return err
}
return nil
}
var rules []v1.PolicyRule
for resource, newVerbs := range resourceToVerbs {
rules = append(rules, buildRule(resource, newVerbs))
}
logrus.Infof("[%v] Creating role %v in namespace %v", m.controller, rt.Name, namespace)
_, err := roleCli.Create(&v1.Role{
ObjectMeta: metav1.ObjectMeta{
Name: rt.Name,
},
Rules: rules,
})
if err != nil {
return errors.Wrapf(err, "couldn't create role %v", rt.Name)
}
return nil
}
func (m *manager) gatherRoleTemplates(rt *v3.RoleTemplate, roleTemplates map[string]*v3.RoleTemplate) error {
roleTemplates[rt.Name] = rt
for _, rtName := range rt.RoleTemplateNames {
subRT, err := m.rtLister.Get("", rtName)
if err != nil {
return errors.Wrapf(err, "couldn't get RoleTemplate %s", rtName)
}
if err := m.gatherRoleTemplates(subRT, roleTemplates); err != nil {
return errors.Wrapf(err, "couldn't gather RoleTemplate %s", rtName)
}
}
return nil
}
func buildRule(resource string, verbs map[string]bool) v1.PolicyRule {
var vs []string
for v := range verbs {
vs = append(vs, v)
}
return v1.PolicyRule{
Resources: []string{resource},
Verbs: vs,
APIGroups: []string{"*"},
}
}
func buildSubjectFromRTB(binding interface{}) (v1.Subject, error) {
var userName, groupPrincipalName, groupName, name, kind string
if rtb, ok := binding.(*v3.ProjectRoleTemplateBinding); ok {
userName = rtb.UserName
groupPrincipalName = rtb.GroupPrincipalName
groupName = rtb.GroupName
} else if rtb, ok := binding.(*v3.ClusterRoleTemplateBinding); ok {
userName = rtb.UserName
groupPrincipalName = rtb.GroupPrincipalName
groupName = rtb.GroupName
} else {
return v1.Subject{}, errors.Errorf("unrecognized roleTemplateBinding type: %v", binding)
}
if userName != "" {
name = userName
kind = "User"
}
if groupPrincipalName != "" {
if name != "" {
return v1.Subject{}, errors.Errorf("roletemplatebinding has more than one subject fields set: %v", binding)
}
name = groupPrincipalName
kind = "Group"
}
if groupName != "" {
if name != "" {
return v1.Subject{}, errors.Errorf("roletemplatebinding has more than one subject fields set: %v", binding)
}
name = groupName
kind = "Group"
}
if name == "" {
return v1.Subject{}, errors.Errorf("roletemplatebinding doesn't have any subject fields set: %v", binding)
}
return v1.Subject{
Kind: kind,
Name: name,
}, nil
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/rancher/rancher.git
git@gitee.com:rancher/rancher.git
rancher
rancher
rancher
v2.0.7-rc1

搜索帮助

344bd9b3 5694891 D2dac590 5694891