github.com/jenkins-x/jx/v2@v2.1.155/pkg/kube/roles.go (about) 1 package kube 2 3 import ( 4 "fmt" 5 "sort" 6 7 v1 "github.com/jenkins-x/jx-api/pkg/apis/jenkins.io/v1" 8 "github.com/jenkins-x/jx-api/pkg/client/clientset/versioned" 9 "github.com/jenkins-x/jx-logging/pkg/log" 10 "github.com/jenkins-x/jx/v2/pkg/util" 11 "github.com/pkg/errors" 12 rbacv1 "k8s.io/api/rbac/v1" 13 apierrors "k8s.io/apimachinery/pkg/api/errors" 14 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 15 "k8s.io/client-go/kubernetes" 16 ) 17 18 const ( 19 clusterRoleBindingKind = "ClusterRoleBinding" 20 clusterRoleKind = "ClusterRole" 21 apiGroup = "rbac.authorization.k8s.io" 22 subjectKind = "ServiceAccount" 23 ) 24 25 // GetTeamRoles returns the roles for the given team dev namespace 26 func GetTeamRoles(kubeClient kubernetes.Interface, ns string) (map[string]*rbacv1.Role, []string, error) { 27 m := map[string]*rbacv1.Role{} 28 29 names := []string{} 30 resources, err := kubeClient.RbacV1().Roles(ns).List(metav1.ListOptions{ 31 LabelSelector: LabelKind + "=" + ValueKindEnvironmentRole, 32 }) 33 if err != nil { 34 return m, names, err 35 } 36 for _, env := range resources.Items { 37 n := env.Name 38 copy := env 39 m[n] = © 40 if n != "" { 41 names = append(names, n) 42 } 43 } 44 sort.Strings(names) 45 return m, names, nil 46 } 47 48 // GetEnvironmentRoles returns all the environment role binding names and details 49 func GetEnvironmentRoles(jxClient versioned.Interface, ns string) (map[string]*v1.EnvironmentRoleBinding, []string, error) { 50 names := []string{} 51 m := map[string]*v1.EnvironmentRoleBinding{} 52 envRoleBindingsList, err := jxClient.JenkinsV1().EnvironmentRoleBindings(ns).List(metav1.ListOptions{}) 53 if err != nil { 54 return m, names, fmt.Errorf("Failed to retrieve EnvironmentRoleBinding list for namespace %s: %s", ns, err) 55 } 56 for _, envRoleBinding := range envRoleBindingsList.Items { 57 copy := envRoleBinding 58 name := copy.Name 59 m[name] = © 60 names = append(names, name) 61 } 62 return m, names, err 63 } 64 65 // UpdateUserRoles updates the EnvironmentRoleBinding values based on the given userRoles 66 // userKind is "User" or "ServiceAccount" 67 func GetUserRoles(kubeClient kubernetes.Interface, jxClient versioned.Interface, ns string, userKind string, userName string) ([]string, error) { 68 envRoles, _, err := GetEnvironmentRoles(jxClient, ns) 69 if err != nil { 70 return nil, err 71 } 72 adminNs, err := GetAdminNamespace(kubeClient, ns) 73 if err != nil { 74 return nil, err 75 } 76 currentRoles := userRolesFor(userKind, userName, adminNs, envRoles) 77 return currentRoles, err 78 } 79 80 // UpdateUserRoles updates the EnvironmentRoleBinding values based on the given userRoles. 81 // userKind is "User" or "ServiceAccount" 82 func UpdateUserRoles(kubeClient kubernetes.Interface, jxClient versioned.Interface, ns string, userKind string, userName string, userRoles []string, roles map[string]*rbacv1.Role) error { 83 84 envRoleInterface := jxClient.JenkinsV1().EnvironmentRoleBindings(ns) 85 envRoles, _, err := GetEnvironmentRoles(jxClient, ns) 86 87 adminNs, err := GetAdminNamespace(kubeClient, ns) 88 if err != nil { 89 return errors.Wrapf(err, "Obtaining admin namespace for user lookup") 90 } 91 92 // make sure all of the EnvironmentRoleBinding are created 93 for name := range roles { 94 envRole := envRoles[name] 95 if envRole == nil { 96 envRole = &v1.EnvironmentRoleBinding{ 97 ObjectMeta: metav1.ObjectMeta{ 98 Name: name, 99 Namespace: ns, 100 Labels: map[string]string{ 101 LabelKind: ValueKindEnvironmentRole, 102 }, 103 }, 104 Spec: v1.EnvironmentRoleBindingSpec{ 105 RoleRef: rbacv1.RoleRef{ 106 Kind: "Role", 107 Name: name, 108 APIGroup: "rbac.authorization.k8s.io", 109 }, 110 Subjects: []rbacv1.Subject{}, 111 }, 112 } 113 _, err = envRoleInterface.Create(envRole) 114 if err != nil { 115 return errors.Wrapf(err, "Failed to create EnvironmentRoleBinding %s", name) 116 } 117 envRoles[name] = envRole 118 } 119 } 120 121 oldRoles := userRolesFor(userKind, userName, adminNs, envRoles) 122 123 deleteRoles, createRoles := util.DiffSlices(oldRoles, userRoles) 124 125 // should we use a single patch or create at the end and be atomic for the whole operation? 126 for _, name := range deleteRoles { 127 envRole := envRoles[name] 128 if envRole == nil { 129 log.Logger().Warnf("Could not remove user %s kind %s from EnvironmentRoleBinding %s as it does not exist", userName, userKind, name) 130 } else { 131 found := false 132 for idx, subject := range envRole.Spec.Subjects { 133 if subject.Kind == userKind && subject.Name == userName && subject.Namespace == adminNs { 134 found = true 135 envRole.Spec.Subjects = append(envRole.Spec.Subjects[0:idx], envRole.Spec.Subjects[idx+1:]...) 136 _, err = envRoleInterface.PatchUpdate(envRole) 137 if err != nil { 138 return errors.Wrapf(err, "Failed to remove User %s kind %s as a Subject of EnvironmentRoleBinding %s: %s", userName, userKind, name, err) 139 } 140 break 141 } 142 } 143 if !found { 144 log.Logger().Warnf("User %s kind %s is not a Subject of EnvironmentRoleBinding %s", userName, userKind, name) 145 } 146 } 147 } 148 for _, name := range createRoles { 149 envRole := envRoles[name] 150 if envRole == nil { 151 // TODO lazily create the EnvironmentRoleBinding? 152 log.Logger().Warnf("Could not add user %s to EnvironmentRoleBinding %s as it does not exist!", userName, name) 153 } else { 154 found := false 155 for _, subject := range envRole.Spec.Subjects { 156 if subject.Kind == userKind && subject.Name == userName && subject.Namespace == adminNs { 157 found = true 158 } 159 } 160 if found { 161 log.Logger().Warnf("User %s kind %s is already a Subject of EnvironmentRoleBinding %s", userName, userKind, name) 162 } else { 163 newSubject := rbacv1.Subject{ 164 Name: userName, 165 Kind: userKind, 166 Namespace: adminNs, 167 } 168 newEnvRole, err := envRoleInterface.Get(envRole.Name, metav1.GetOptions{}) 169 create := false 170 if err != nil { 171 create = true 172 newEnvRole = envRole 173 } else { 174 newEnvRole.Spec = envRole.Spec 175 } 176 newEnvRole.Spec.Subjects = append(newEnvRole.Spec.Subjects, newSubject) 177 if create { 178 _, err = envRoleInterface.Create(newEnvRole) 179 if err != nil { 180 return errors.Wrapf(err, "Failed to create EnvironmentRoleBinding %s with Subject User %s kind %s: %s", name, userName, userKind, err) 181 } 182 } else { 183 _, err = envRoleInterface.PatchUpdate(newEnvRole) 184 if err != nil { 185 return errors.Wrapf(err, "Failed to add User %s kind %s as a Subject of EnvironmentRoleBinding %s: %s", userName, userKind, name, err) 186 } 187 } 188 } 189 } 190 } 191 return nil 192 } 193 194 func userRolesFor(userKind string, userName string, userNamespace string, envRoles map[string]*v1.EnvironmentRoleBinding) []string { 195 answer := []string{} 196 for _, envRole := range envRoles { 197 for _, subject := range envRole.Spec.Subjects { 198 if subject.Kind == userKind && subject.Name == userName && subject.Namespace == userNamespace { 199 answer = append(answer, envRole.Name) 200 } 201 } 202 } 203 return answer 204 } 205 206 // IsClusterRoleBinding checks if the cluster role binding exists 207 func IsClusterRoleBinding(kubeClient kubernetes.Interface, name string) bool { 208 _, err := kubeClient.RbacV1().ClusterRoleBindings().Get(name, metav1.GetOptions{}) 209 if apierrors.IsNotFound(err) { 210 return false 211 } 212 return true 213 } 214 215 // CreateClusterRoleBinding creates acluster role binding in a given namespace for a service account 216 func CreateClusterRoleBinding(kubeClient kubernetes.Interface, namespace string, name string, 217 serviceAccountName string, clusterRoleName string) error { 218 rb := &rbacv1.ClusterRoleBinding{ 219 TypeMeta: metav1.TypeMeta{ 220 Kind: clusterRoleBindingKind, 221 APIVersion: "v1", 222 }, 223 ObjectMeta: metav1.ObjectMeta{ 224 Name: name, 225 }, 226 Subjects: []rbacv1.Subject{ 227 { 228 Kind: subjectKind, 229 Name: serviceAccountName, 230 Namespace: namespace, 231 }, 232 }, 233 RoleRef: rbacv1.RoleRef{ 234 APIGroup: apiGroup, 235 Kind: clusterRoleKind, 236 Name: clusterRoleName, 237 }, 238 } 239 240 _, err := kubeClient.RbacV1().ClusterRoleBindings().Create(rb) 241 if err != nil { 242 return errors.Wrap(err, "creating cluster role binding") 243 } 244 return nil 245 } 246 247 // DeleteClusterRoleBinding deltes a cluster role binding 248 func DeleteClusterRoleBinding(kubeClient kubernetes.Interface, name string) error { 249 _, err := kubeClient.RbacV1().ClusterRoleBindings().Get(name, metav1.GetOptions{}) 250 if err == nil { 251 return kubeClient.RbacV1().ClusterRoleBindings().Delete(name, &metav1.DeleteOptions{}) 252 } 253 return nil 254 } 255 256 // IsClusterRole checks if a cluster role exists 257 func IsClusterRole(kubeClient kubernetes.Interface, name string) bool { 258 _, err := kubeClient.RbacV1().ClusterRoles().Get(name, metav1.GetOptions{}) 259 if apierrors.IsNotFound(err) { 260 return false 261 } 262 return true 263 } 264 265 // CreateClusterRole creates a new cluster role 266 func CreateClusterRole(kubeClient kubernetes.Interface, namesapce string, name string, 267 apiGroups []string, resources []string, verbs []string) error { 268 role := &rbacv1.ClusterRole{ 269 TypeMeta: metav1.TypeMeta{ 270 Kind: clusterRoleKind, 271 APIVersion: "v1", 272 }, 273 ObjectMeta: metav1.ObjectMeta{ 274 Name: name, 275 }, 276 Rules: []rbacv1.PolicyRule{ 277 { 278 APIGroups: apiGroups, 279 Resources: resources, 280 Verbs: verbs, 281 }, 282 }, 283 } 284 _, err := kubeClient.RbacV1().ClusterRoles().Create(role) 285 if err != nil { 286 return errors.Wrap(err, "creating custer role") 287 } 288 return nil 289 } 290 291 // DeleteClusterRole deletes a cluster role if exists 292 func DeleteClusterRole(kubeClient kubernetes.Interface, name string) error { 293 if IsClusterRole(kubeClient, name) { 294 return kubeClient.RbacV1().ClusterRoles().Delete(name, &metav1.DeleteOptions{}) 295 } 296 return nil 297 }