sigs.k8s.io/cluster-api-provider-aws@v1.5.5/pkg/cloud/services/iamauth/configmap_test.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  	"testing"
    22  
    23  	"github.com/google/go-cmp/cmp"
    24  	. "github.com/onsi/gomega"
    25  	corev1 "k8s.io/api/core/v1"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	"k8s.io/apimachinery/pkg/types"
    28  	crclient "sigs.k8s.io/controller-runtime/pkg/client"
    29  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    30  	"sigs.k8s.io/yaml"
    31  
    32  	ekscontrolplanev1 "sigs.k8s.io/cluster-api-provider-aws/controlplane/eks/api/v1beta1"
    33  )
    34  
    35  var (
    36  	existingNodeRoleMap = `
    37      - groups:
    38        - system:bootstrappers
    39        - system:nodes
    40        rolearn: arn:aws:iam::000000000000:role/KubernetesNode
    41        username: system:node:{{EC2PrivateDNSName}}
    42  `
    43  
    44  	existingUserMap = `
    45      - userarn: arn:aws:iam::000000000000:user/Alice
    46        username: alice
    47        groups:
    48        - system:masters
    49  `
    50  )
    51  
    52  func TestAddRoleMappingCM(t *testing.T) {
    53  	testCases := []struct {
    54  		name                  string
    55  		existingAuthConfigMap *corev1.ConfigMap
    56  		roleToMap             ekscontrolplanev1.RoleMapping
    57  		expectedRoleMaps      []ekscontrolplanev1.RoleMapping
    58  		expectError           bool
    59  	}{
    60  		{
    61  			name: "no existing mappings, add role mapping",
    62  			roleToMap: ekscontrolplanev1.RoleMapping{
    63  				RoleARN: "arn:aws:iam::000000000000:role/KubernetesNode",
    64  				KubernetesMapping: ekscontrolplanev1.KubernetesMapping{
    65  					UserName: "system:node:{{EC2PrivateDNSName}}",
    66  					Groups:   []string{"system:bootstrappers", "system:nodes"},
    67  				},
    68  			},
    69  			expectedRoleMaps: []ekscontrolplanev1.RoleMapping{
    70  				{
    71  					RoleARN: "arn:aws:iam::000000000000:role/KubernetesNode",
    72  					KubernetesMapping: ekscontrolplanev1.KubernetesMapping{
    73  						UserName: "system:node:{{EC2PrivateDNSName}}",
    74  						Groups:   []string{"system:bootstrappers", "system:nodes"},
    75  					},
    76  				},
    77  			},
    78  			expectError: false,
    79  		},
    80  		{
    81  			name: "existing mapping, add different mapping",
    82  			roleToMap: ekscontrolplanev1.RoleMapping{
    83  				RoleARN: "arn:aws:iam::000000000000:role/KubernetesAdmin",
    84  				KubernetesMapping: ekscontrolplanev1.KubernetesMapping{
    85  					UserName: "admin:{{SessionName}}",
    86  					Groups:   []string{"system:masters"},
    87  				},
    88  			},
    89  			expectedRoleMaps: []ekscontrolplanev1.RoleMapping{
    90  				{
    91  					RoleARN: "arn:aws:iam::000000000000:role/KubernetesNode",
    92  					KubernetesMapping: ekscontrolplanev1.KubernetesMapping{
    93  						UserName: "system:node:{{EC2PrivateDNSName}}",
    94  						Groups:   []string{"system:bootstrappers", "system:nodes"},
    95  					},
    96  				},
    97  				{
    98  					RoleARN: "arn:aws:iam::000000000000:role/KubernetesAdmin",
    99  					KubernetesMapping: ekscontrolplanev1.KubernetesMapping{
   100  						UserName: "admin:{{SessionName}}",
   101  						Groups:   []string{"system:masters"},
   102  					},
   103  				},
   104  			},
   105  			expectError:           false,
   106  			existingAuthConfigMap: createFakeConfigMap(existingNodeRoleMap, ""),
   107  		},
   108  		{
   109  			name: "existing mapping, add same mapping",
   110  			roleToMap: ekscontrolplanev1.RoleMapping{
   111  				RoleARN: "arn:aws:iam::000000000000:role/KubernetesNode",
   112  				KubernetesMapping: ekscontrolplanev1.KubernetesMapping{
   113  					UserName: "system:node:{{EC2PrivateDNSName}}",
   114  					Groups:   []string{"system:bootstrappers", "system:nodes"},
   115  				},
   116  			},
   117  			expectedRoleMaps: []ekscontrolplanev1.RoleMapping{
   118  				{
   119  					RoleARN: "arn:aws:iam::000000000000:role/KubernetesNode",
   120  					KubernetesMapping: ekscontrolplanev1.KubernetesMapping{
   121  						UserName: "system:node:{{EC2PrivateDNSName}}",
   122  						Groups:   []string{"system:bootstrappers", "system:nodes"},
   123  					},
   124  				},
   125  			},
   126  			expectError:           false,
   127  			existingAuthConfigMap: createFakeConfigMap(existingNodeRoleMap, ""),
   128  		},
   129  	}
   130  
   131  	for _, tc := range testCases {
   132  		t.Run(tc.name, func(t *testing.T) {
   133  			g := NewGomegaWithT(t)
   134  
   135  			var client crclient.Client
   136  			if tc.existingAuthConfigMap == nil {
   137  				client = fake.NewClientBuilder().Build()
   138  			} else {
   139  				client = fake.NewClientBuilder().WithObjects(tc.existingAuthConfigMap).Build()
   140  			}
   141  			backend, err := NewBackend(BackendTypeConfigMap, client)
   142  			g.Expect(err).To(BeNil())
   143  
   144  			err = backend.MapRole(tc.roleToMap)
   145  			if tc.expectError {
   146  				g.Expect(err).ToNot(BeNil())
   147  				return
   148  			}
   149  
   150  			g.Expect(err).To(BeNil())
   151  
   152  			key := types.NamespacedName{
   153  				Name:      "aws-auth",
   154  				Namespace: "kube-system",
   155  			}
   156  
   157  			cm := &corev1.ConfigMap{}
   158  
   159  			err = client.Get(context.TODO(), key, cm)
   160  			g.Expect(err).To(BeNil())
   161  
   162  			g.Expect(cm.Name).To(Equal("aws-auth"))
   163  			g.Expect(cm.Namespace).To(Equal("kube-system"))
   164  			g.Expect(cm.Data).ToNot(BeNil())
   165  
   166  			actualRoleMappings, roleMappingsFound := cm.Data["mapRoles"]
   167  			if len(tc.expectedRoleMaps) == 0 {
   168  				g.Expect(roleMappingsFound).To(BeFalse())
   169  			} else {
   170  				roles := []ekscontrolplanev1.RoleMapping{}
   171  				err := yaml.Unmarshal([]byte(actualRoleMappings), &roles)
   172  				g.Expect(err).To(BeNil())
   173  				g.Expect(len(roles)).To(Equal(len(tc.expectedRoleMaps)))
   174  				//TODO: we may need to do a better match
   175  				bothMatch := cmp.Equal(roles, tc.expectedRoleMaps)
   176  				g.Expect(bothMatch).To(BeTrue())
   177  			}
   178  
   179  			_, userMappingsFound := cm.Data["mapUsers"]
   180  			g.Expect(userMappingsFound).To(BeFalse())
   181  		})
   182  	}
   183  }
   184  
   185  func TestAddUserMappingCM(t *testing.T) {
   186  	testCases := []struct {
   187  		name                  string
   188  		existingAuthConfigMap *corev1.ConfigMap
   189  		userToMap             ekscontrolplanev1.UserMapping
   190  		expectedUsersMap      []ekscontrolplanev1.UserMapping
   191  		expectError           bool
   192  	}{
   193  		{
   194  			name: "no existing user mappings, add user mapping",
   195  			userToMap: ekscontrolplanev1.UserMapping{
   196  				UserARN: "arn:aws:iam::000000000000:user/Alice",
   197  				KubernetesMapping: ekscontrolplanev1.KubernetesMapping{
   198  					UserName: "alice",
   199  					Groups:   []string{"system:masters"},
   200  				},
   201  			},
   202  			expectedUsersMap: []ekscontrolplanev1.UserMapping{
   203  				{
   204  					UserARN: "arn:aws:iam::000000000000:user/Alice",
   205  					KubernetesMapping: ekscontrolplanev1.KubernetesMapping{
   206  						UserName: "alice",
   207  						Groups:   []string{"system:masters"},
   208  					},
   209  				},
   210  			},
   211  			expectError: false,
   212  		},
   213  		{
   214  			name: "existing user mapping, add different user mapping",
   215  			userToMap: ekscontrolplanev1.UserMapping{
   216  				UserARN: "arn:aws:iam::000000000000:user/Bob",
   217  				KubernetesMapping: ekscontrolplanev1.KubernetesMapping{
   218  					UserName: "bob",
   219  					Groups:   []string{"system:masters"},
   220  				},
   221  			},
   222  			expectedUsersMap: []ekscontrolplanev1.UserMapping{
   223  				{
   224  					UserARN: "arn:aws:iam::000000000000:user/Alice",
   225  					KubernetesMapping: ekscontrolplanev1.KubernetesMapping{
   226  						UserName: "alice",
   227  						Groups:   []string{"system:masters"},
   228  					},
   229  				},
   230  				{
   231  					UserARN: "arn:aws:iam::000000000000:user/Bob",
   232  					KubernetesMapping: ekscontrolplanev1.KubernetesMapping{
   233  						UserName: "bob",
   234  						Groups:   []string{"system:masters"},
   235  					},
   236  				},
   237  			},
   238  			expectError:           false,
   239  			existingAuthConfigMap: createFakeConfigMap("", existingUserMap),
   240  		},
   241  		{
   242  			name: "existing user mapping, add same user mapping",
   243  			userToMap: ekscontrolplanev1.UserMapping{
   244  				UserARN: "arn:aws:iam::000000000000:user/Alice",
   245  				KubernetesMapping: ekscontrolplanev1.KubernetesMapping{
   246  					UserName: "alice",
   247  					Groups:   []string{"system:masters"},
   248  				},
   249  			},
   250  			expectedUsersMap: []ekscontrolplanev1.UserMapping{
   251  				{
   252  					UserARN: "arn:aws:iam::000000000000:user/Alice",
   253  					KubernetesMapping: ekscontrolplanev1.KubernetesMapping{
   254  						UserName: "alice",
   255  						Groups:   []string{"system:masters"},
   256  					},
   257  				},
   258  			},
   259  			expectError:           false,
   260  			existingAuthConfigMap: createFakeConfigMap("", existingUserMap),
   261  		},
   262  	}
   263  
   264  	for _, tc := range testCases {
   265  		t.Run(tc.name, func(t *testing.T) {
   266  			g := NewGomegaWithT(t)
   267  
   268  			var client crclient.Client
   269  			if tc.existingAuthConfigMap == nil {
   270  				client = fake.NewClientBuilder().Build()
   271  			} else {
   272  				client = fake.NewClientBuilder().WithObjects(tc.existingAuthConfigMap).Build()
   273  			}
   274  			backend, err := NewBackend(BackendTypeConfigMap, client)
   275  			g.Expect(err).To(BeNil())
   276  
   277  			err = backend.MapUser(tc.userToMap)
   278  			if tc.expectError {
   279  				g.Expect(err).ToNot(BeNil())
   280  				return
   281  			}
   282  
   283  			g.Expect(err).To(BeNil())
   284  
   285  			key := types.NamespacedName{
   286  				Name:      "aws-auth",
   287  				Namespace: "kube-system",
   288  			}
   289  
   290  			cm := &corev1.ConfigMap{}
   291  
   292  			err = client.Get(context.TODO(), key, cm)
   293  			g.Expect(err).To(BeNil())
   294  
   295  			g.Expect(cm.Name).To(Equal("aws-auth"))
   296  			g.Expect(cm.Namespace).To(Equal("kube-system"))
   297  			g.Expect(cm.Data).ToNot(BeNil())
   298  
   299  			actualUserMappings, userMappingsFound := cm.Data["mapUsers"]
   300  			if len(tc.expectedUsersMap) == 0 {
   301  				g.Expect(userMappingsFound).To(BeFalse())
   302  			} else {
   303  				users := []ekscontrolplanev1.UserMapping{}
   304  				err := yaml.Unmarshal([]byte(actualUserMappings), &users)
   305  				g.Expect(err).To(BeNil())
   306  				g.Expect(len(users)).To(Equal(len(tc.expectedUsersMap)))
   307  				//TODO: we may need to do a better match
   308  				bothMatch := cmp.Equal(users, tc.expectedUsersMap)
   309  				g.Expect(bothMatch).To(BeTrue())
   310  			}
   311  
   312  			_, roleMappingsFound := cm.Data["mapRoles"]
   313  			g.Expect(roleMappingsFound).To(BeFalse())
   314  		})
   315  	}
   316  }
   317  
   318  func createFakeConfigMap(roleMappings string, userMappings string) *corev1.ConfigMap {
   319  	cm := &corev1.ConfigMap{
   320  		ObjectMeta: metav1.ObjectMeta{
   321  			Name:      "aws-auth",
   322  			Namespace: "kube-system",
   323  			UID:       "1234567",
   324  		},
   325  		Data: make(map[string]string),
   326  	}
   327  
   328  	if roleMappings != "" {
   329  		cm.Data["mapRoles"] = roleMappings
   330  	}
   331  
   332  	if userMappings != "" {
   333  		cm.Data["mapUsers"] = userMappings
   334  	}
   335  
   336  	return cm
   337  }