sigs.k8s.io/cluster-api-provider-aws@v1.5.5/pkg/cloud/services/iamauth/configmap.go (about) 1 /* 2 Copyright 2020 The Kubernetes 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 iamauth 18 19 import ( 20 "context" 21 "fmt" 22 23 "github.com/google/go-cmp/cmp" 24 corev1 "k8s.io/api/core/v1" 25 apierrors "k8s.io/apimachinery/pkg/api/errors" 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 "k8s.io/apimachinery/pkg/types" 28 kerrors "k8s.io/apimachinery/pkg/util/errors" 29 crclient "sigs.k8s.io/controller-runtime/pkg/client" 30 "sigs.k8s.io/yaml" 31 32 ekscontrolplanev1 "sigs.k8s.io/cluster-api-provider-aws/controlplane/eks/api/v1beta1" 33 ) 34 35 const ( 36 configMapName = "aws-auth" 37 configMapNS = metav1.NamespaceSystem 38 39 roleKey = "mapRoles" 40 usersKey = "mapUsers" 41 ) 42 43 type configMapBackend struct { 44 client crclient.Client 45 } 46 47 func (b *configMapBackend) MapRole(mapping ekscontrolplanev1.RoleMapping) error { 48 if errs := mapping.Validate(); errs != nil { 49 return kerrors.NewAggregate(errs) 50 } 51 52 authConfig, err := b.getAuthConfig() 53 if err != nil { 54 return fmt.Errorf("getting auth config: %w", err) 55 } 56 57 for _, existingMapping := range authConfig.RoleMappings { 58 if cmp.Equal(existingMapping, mapping) { 59 // A mapping already exists that matches, so ignore 60 return nil 61 } 62 } 63 64 authConfig.RoleMappings = append(authConfig.RoleMappings, mapping) 65 66 return b.saveAuthConfig(authConfig) 67 } 68 69 func (b *configMapBackend) MapUser(mapping ekscontrolplanev1.UserMapping) error { 70 if errs := mapping.Validate(); errs != nil { 71 return kerrors.NewAggregate(errs) 72 } 73 74 authConfig, err := b.getAuthConfig() 75 if err != nil { 76 return fmt.Errorf("getting auth config: %w", err) 77 } 78 79 for _, existingMapping := range authConfig.UserMappings { 80 if cmp.Equal(existingMapping, mapping) { 81 // A mapping already exists that matches, so ignore 82 return nil 83 } 84 } 85 86 authConfig.UserMappings = append(authConfig.UserMappings, mapping) 87 88 return b.saveAuthConfig(authConfig) 89 } 90 91 func (b *configMapBackend) getAuthConfig() (*ekscontrolplanev1.IAMAuthenticatorConfig, error) { 92 ctx := context.Background() 93 94 configMapRef := types.NamespacedName{ 95 Name: configMapName, 96 Namespace: configMapNS, 97 } 98 99 authConfigMap := &corev1.ConfigMap{} 100 101 err := b.client.Get(ctx, configMapRef, authConfigMap) 102 if err != nil && !apierrors.IsNotFound(err) { 103 return nil, fmt.Errorf("getting %s/%s config map: %w", configMapName, configMapNS, err) 104 } 105 106 authConfig := &ekscontrolplanev1.IAMAuthenticatorConfig{ 107 RoleMappings: []ekscontrolplanev1.RoleMapping{}, 108 UserMappings: []ekscontrolplanev1.UserMapping{}, 109 } 110 if authConfigMap.Data == nil { 111 return authConfig, nil 112 } 113 114 mappedRoles, err := b.getMappedRoles(authConfigMap) 115 if err != nil { 116 return nil, fmt.Errorf("getting mapped roles: %w", err) 117 } 118 authConfig.RoleMappings = mappedRoles 119 120 mappedUsers, err := b.getMappedUsers(authConfigMap) 121 if err != nil { 122 return nil, fmt.Errorf("getting mapped users: %w", err) 123 } 124 authConfig.UserMappings = mappedUsers 125 126 return authConfig, nil 127 } 128 129 func (b *configMapBackend) saveAuthConfig(authConfig *ekscontrolplanev1.IAMAuthenticatorConfig) error { 130 ctx := context.Background() 131 132 configMapRef := types.NamespacedName{ 133 Name: configMapName, 134 Namespace: configMapNS, 135 } 136 137 authConfigMap := &corev1.ConfigMap{} 138 139 err := b.client.Get(ctx, configMapRef, authConfigMap) 140 if err != nil && !apierrors.IsNotFound(err) { 141 return fmt.Errorf("getting %s/%s config map: %w", configMapName, configMapNS, err) 142 } 143 144 if authConfigMap.Data == nil { 145 authConfigMap.Data = make(map[string]string) 146 } 147 authConfigMap = authConfigMap.DeepCopy() 148 149 delete(authConfigMap.Data, roleKey) 150 delete(authConfigMap.Data, usersKey) 151 152 if len(authConfig.RoleMappings) > 0 { 153 roleMappings, err := yaml.Marshal(authConfig.RoleMappings) 154 if err != nil { 155 return fmt.Errorf("marshalling auth config roles: %w", err) 156 } 157 authConfigMap.Data[roleKey] = string(roleMappings) 158 } 159 160 if len(authConfig.UserMappings) > 0 { 161 userMappings, err := yaml.Marshal(authConfig.UserMappings) 162 if err != nil { 163 return fmt.Errorf("marshalling auth config users: %w", err) 164 } 165 authConfigMap.Data[usersKey] = string(userMappings) 166 } 167 168 if authConfigMap.UID == "" { 169 authConfigMap.Name = configMapName 170 authConfigMap.Namespace = configMapNS 171 return b.client.Create(ctx, authConfigMap) 172 } 173 174 return b.client.Update(ctx, authConfigMap) 175 } 176 177 func (b *configMapBackend) getMappedRoles(cm *corev1.ConfigMap) ([]ekscontrolplanev1.RoleMapping, error) { 178 mappedRoles := []ekscontrolplanev1.RoleMapping{} 179 180 rolesSection, ok := cm.Data[roleKey] 181 if !ok { 182 return mappedRoles, nil 183 } 184 185 if err := yaml.Unmarshal([]byte(rolesSection), &mappedRoles); err != nil { 186 return nil, fmt.Errorf("unmarshalling mapped roles: %w", err) 187 } 188 189 return mappedRoles, nil 190 } 191 192 func (b *configMapBackend) getMappedUsers(cm *corev1.ConfigMap) ([]ekscontrolplanev1.UserMapping, error) { 193 mappedUsers := []ekscontrolplanev1.UserMapping{} 194 195 usersSection, ok := cm.Data[usersKey] 196 if !ok { 197 return mappedUsers, nil 198 } 199 200 if err := yaml.Unmarshal([]byte(usersSection), &mappedUsers); err != nil { 201 return nil, fmt.Errorf("unmarshalling mapped users: %w", err) 202 } 203 204 return mappedUsers, nil 205 }