github.com/oam-dev/kubevela@v1.9.11/pkg/auth/identity.go (about) 1 /* 2 Copyright 2022 The KubeVela Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package auth 18 19 import ( 20 "fmt" 21 "strings" 22 23 corev1 "k8s.io/api/core/v1" 24 rbacv1 "k8s.io/api/rbac/v1" 25 "k8s.io/apiserver/pkg/authentication/serviceaccount" 26 "k8s.io/utils/strings/slices" 27 ) 28 29 // Identity the kubernetes identity 30 type Identity struct { 31 User string 32 Groups []string 33 ServiceAccount string 34 ServiceAccountNamespace string 35 } 36 37 // String . 38 func (identity *Identity) String() string { 39 var tokens []string 40 if identity.User != "" { 41 tokens = append(tokens, "User="+identity.User) 42 } 43 if len(identity.Groups) > 0 { 44 tokens = append(tokens, "Groups="+strings.Join(identity.Groups, ",")) 45 } 46 if identity.ServiceAccount != "" { 47 tokens = append(tokens, "SA="+serviceaccount.MakeUsername(identity.ServiceAccountNamespace, identity.ServiceAccount)) 48 } 49 return strings.Join(tokens, " ") 50 } 51 52 // Match validate if identity matches rbac subject 53 func (identity *Identity) Match(subject rbacv1.Subject) bool { 54 switch subject.Kind { 55 case rbacv1.UserKind: 56 return subject.Name == identity.User 57 case rbacv1.GroupKind: 58 return slices.Contains(identity.Groups, subject.Name) 59 case rbacv1.ServiceAccountKind: 60 return serviceaccount.MatchesUsername(subject.Namespace, subject.Name, 61 serviceaccount.MakeUsername(identity.ServiceAccountNamespace, identity.ServiceAccount)) 62 default: 63 return false 64 } 65 } 66 67 // MatchAny validate if identity matches any one of the rbac subjects 68 func (identity *Identity) MatchAny(subjects []rbacv1.Subject) bool { 69 for _, subject := range subjects { 70 if identity.Match(subject) { 71 return true 72 } 73 } 74 return false 75 } 76 77 // Regularize clean up input info 78 func (identity *Identity) Regularize() { 79 identity.User = strings.TrimSpace(identity.User) 80 groupMap := map[string]struct{}{} 81 var groups []string 82 for _, group := range identity.Groups { 83 group = strings.TrimSpace(group) 84 if _, found := groupMap[group]; !found { 85 groupMap[group] = struct{}{} 86 groups = append(groups, group) 87 } 88 } 89 identity.Groups = groups 90 identity.ServiceAccount = strings.TrimSpace(identity.ServiceAccount) 91 if identity.ServiceAccount != "" { 92 if identity.ServiceAccountNamespace == "" { 93 identity.ServiceAccountNamespace = corev1.NamespaceDefault 94 } 95 } 96 } 97 98 // Validate check if identity is valid 99 func (identity *Identity) Validate() error { 100 if identity.User == "" && identity.ServiceAccount == "" { 101 return fmt.Errorf("either `user` or `serviceaccount` should be set") 102 } 103 if identity.User != "" && identity.ServiceAccount != "" { 104 return fmt.Errorf("cannot set `user` and `serviceaccount` at the same time") 105 } 106 if len(identity.Groups) > 0 && identity.ServiceAccount != "" { 107 return fmt.Errorf("cannot set `group` and `serviceaccount` at the same time") 108 } 109 if identity.ServiceAccount == "" && identity.ServiceAccountNamespace != "" { 110 return fmt.Errorf("cannot set serviceaccount namespace when serviceaccount is not set") 111 } 112 return nil 113 } 114 115 // Subjects return rbac subjects 116 func (identity *Identity) Subjects() []rbacv1.Subject { 117 var subs []rbacv1.Subject 118 if identity.User != "" { 119 subs = append(subs, rbacv1.Subject{Kind: rbacv1.UserKind, APIGroup: rbacv1.GroupName, Name: identity.User}) 120 } 121 for _, group := range identity.Groups { 122 subs = append(subs, rbacv1.Subject{Kind: rbacv1.GroupKind, APIGroup: rbacv1.GroupName, Name: group}) 123 } 124 if identity.ServiceAccount != "" { 125 subs = append(subs, rbacv1.Subject{Kind: rbacv1.ServiceAccountKind, Name: identity.ServiceAccount, Namespace: identity.ServiceAccountNamespace}) 126 } 127 return subs 128 }