@@ -20,41 +20,125 @@ package filter
2020import (
2121 "context"
2222 "fmt"
23- k8serrors "k8s.io/apimachinery/pkg/api/errors"
2423 "net/http"
24+ "strings"
25+ "time"
2526
2627 platformv1 "tkestack.io/tke/api/client/clientset/versioned/typed/platform/v1"
2728 "tkestack.io/tke/pkg/apiserver/authentication"
29+ "tkestack.io/tke/pkg/apiserver/util"
2830 "tkestack.io/tke/pkg/util/log"
2931
32+ rbacv1 "k8s.io/api/rbac/v1"
33+ k8serrors "k8s.io/apimachinery/pkg/api/errors"
3034 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
35+ "k8s.io/apimachinery/pkg/labels"
3136 genericfilters "k8s.io/apiserver/pkg/endpoints/filters"
3237 "k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
3338 "k8s.io/apiserver/pkg/endpoints/request"
3439 genericapiserver "k8s.io/apiserver/pkg/server"
40+ "k8s.io/client-go/informers"
41+ "k8s.io/client-go/kubernetes"
42+ rbaclisters "k8s.io/client-go/listers/rbac/v1"
43+ "k8s.io/client-go/tools/cache"
3544)
3645
3746type Inspector interface {
3847 Inspect (handler http.Handler , c * genericapiserver.Config ) http.Handler
3948}
4049
4150type clusterInspector struct {
51+ k8sClient kubernetes.Interface
52+ crbLister rbaclisters.ClusterRoleBindingLister
53+ crLister rbaclisters.ClusterRoleLister
4254 platformClient platformv1.PlatformV1Interface
4355 privilegedUsername string
4456}
4557
46- func NewClusterInspector (platformClient platformv1.PlatformV1Interface , privilegedUsername string ) Inspector {
58+ func NewClusterInspector (platformClient platformv1.PlatformV1Interface , privilegedUsername string ) (Inspector , error ) {
59+ k8sClient , err := util .BuildKubeClient ()
60+ if err != nil {
61+ return nil , err
62+ }
63+ informerFactory := informers .NewSharedInformerFactory (k8sClient , time .Minute )
64+ clusterRoleBindingInformer := informerFactory .Rbac ().V1 ().ClusterRoleBindings ()
65+ clusterRoleBindingLister := clusterRoleBindingInformer .Lister ()
66+ clusterRoleInformer := informerFactory .Rbac ().V1 ().ClusterRoles ()
67+ clusterRoleLister := clusterRoleInformer .Lister ()
68+ stopCh := util .SetupSignalHandler ()
69+ informerFactory .Start (stopCh )
70+ if ok := cache .WaitForCacheSync (stopCh , clusterRoleBindingInformer .Informer ().HasSynced ,
71+ clusterRoleInformer .Informer ().HasSynced )
72+ ! ok {
73+ return nil , fmt .Errorf ("failed to wait for namespaces caches to sync" )
74+ }
4775 return & clusterInspector {
76+ k8sClient : k8sClient ,
77+ crbLister : clusterRoleBindingLister ,
78+ crLister : clusterRoleLister ,
4879 platformClient : platformClient ,
4980 privilegedUsername : privilegedUsername ,
81+ }, nil
82+ }
83+
84+ func isClusterAdmin (rules []rbacv1.PolicyRule ) bool {
85+ if len (rules ) != 2 {
86+ return false
5087 }
88+ isAdmin := true
89+ for _ , rul := range rules {
90+ if len (rul .APIGroups ) == 1 && rul .APIGroups [0 ] == "*" &&
91+ len (rul .Resources ) == 1 && rul .Resources [0 ] == "*" &&
92+ len (rul .Verbs ) == 1 && rul .Verbs [0 ] == "*" {
93+ continue
94+ }
95+ if len (rul .NonResourceURLs ) == 1 && rul .NonResourceURLs [0 ] == "*" &&
96+ len (rul .Verbs ) == 1 && rul .Verbs [0 ] == "*" {
97+ continue
98+ }
99+ isAdmin = false
100+ break
101+ }
102+ return isAdmin
103+ }
104+
105+ func (i * clusterInspector ) needInspect (ctx context.Context , privilegedUsername string ) bool {
106+ username , tenantID := authentication .UsernameAndTenantID (ctx )
107+ if (username == privilegedUsername || username == "system:apiserver" ) && tenantID == "" {
108+ return false
109+ }
110+
111+ clusterRoleBindings , err := i .crbLister .List (labels .Everything ())
112+ if err != nil {
113+ log .Errorf ("query clusterRoleBindings failed: %+v" , err )
114+ return true
115+ }
116+ username = strings .TrimPrefix (username , "system:serviceaccount:kube-system:" )
117+ for _ , crb := range clusterRoleBindings {
118+ for _ , sub := range crb .Subjects {
119+ if sub .Name == username && sub .Namespace == "kube-system" {
120+ cr , err := i .crLister .Get (crb .RoleRef .Name )
121+ if err != nil {
122+ log .Errorf ("query clusterRole: %+v failed: %+v" , crb .RoleRef .Name , err )
123+ continue
124+ }
125+ if len (cr .Rules ) != 2 {
126+ continue
127+ }
128+ log .Debugf ("needInspect: username: %+v clusterRole: %+v->%v" , username , cr .Name , cr .Rules )
129+ if isClusterAdmin (cr .Rules ) {
130+ return false
131+ }
132+ }
133+ }
134+ }
135+ return true
51136}
52137
53138func (i * clusterInspector ) Inspect (handler http.Handler , c * genericapiserver.Config ) http.Handler {
54139 return http .HandlerFunc (func (w http.ResponseWriter , req * http.Request ) {
55140 ctx := req .Context ()
56- username , tenantID := authentication .UsernameAndTenantID (ctx )
57- if (username == i .privilegedUsername || username == "system:apiserver" ) && tenantID == "" {
141+ if ! i .needInspect (ctx , i .privilegedUsername ) {
58142 handler .ServeHTTP (w , req )
59143 return
60144 }
@@ -77,7 +161,8 @@ func (i *clusterInspector) Inspect(handler http.Handler, c *genericapiserver.Con
77161 "invalid request: too many clusterName in request" )
78162 return
79163 }
80- log .Infof ("WithTKEAuthorization clusterNames: %+v, username: %+v, tenant: %+v, " +
164+ username , tenantID := authentication .UsernameAndTenantID (ctx )
165+ log .Infof (" clusterNames: %+v, username: %+v, tenant: %+v, " +
81166 "action: %+v, resource: %+v, name: %+v" ,
82167 clusterNames , username , tenantID , tkeAttributes .GetVerb (),
83168 tkeAttributes .GetResource (), tkeAttributes .GetName ())
0 commit comments