sigs.k8s.io/cluster-api-provider-aws@v1.5.5/pkg/cloud/services/iamauth/crd_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  	"strings"
    22  	"testing"
    23  
    24  	"github.com/google/go-cmp/cmp"
    25  	. "github.com/onsi/gomega"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	"k8s.io/apimachinery/pkg/runtime"
    28  	iamauthv1 "sigs.k8s.io/aws-iam-authenticator/pkg/mapper/crd/apis/iamauthenticator/v1alpha1"
    29  	crclient "sigs.k8s.io/controller-runtime/pkg/client"
    30  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    31  
    32  	ekscontrolplanev1 "sigs.k8s.io/cluster-api-provider-aws/controlplane/eks/api/v1beta1"
    33  )
    34  
    35  func TestAddRoleMappingCRD(t *testing.T) {
    36  	testCases := []struct {
    37  		name                 string
    38  		existingRoleMapping  *iamauthv1.IAMIdentityMapping
    39  		roleToMap            ekscontrolplanev1.RoleMapping
    40  		expectedRoleMapSpecs []iamauthv1.IAMIdentityMappingSpec
    41  		expectError          bool
    42  	}{
    43  		{
    44  			name: "no existing mappings, add role mapping",
    45  			roleToMap: ekscontrolplanev1.RoleMapping{
    46  				RoleARN: "arn:aws:iam::000000000000:role/KubernetesNode",
    47  				KubernetesMapping: ekscontrolplanev1.KubernetesMapping{
    48  					UserName: "system:node:{{EC2PrivateDNSName}}",
    49  					Groups:   []string{"system:bootstrappers", "system:nodes"},
    50  				},
    51  			},
    52  			expectedRoleMapSpecs: []iamauthv1.IAMIdentityMappingSpec{
    53  				{
    54  					ARN:      "arn:aws:iam::000000000000:role/KubernetesNode",
    55  					Username: "system:node:{{EC2PrivateDNSName}}",
    56  					Groups:   []string{"system:bootstrappers", "system:nodes"},
    57  				},
    58  			},
    59  			expectError: false,
    60  		},
    61  		{
    62  			name: "existing mapping, add different role mapping",
    63  			roleToMap: ekscontrolplanev1.RoleMapping{
    64  				RoleARN: "arn:aws:iam::000000000000:role/KubernetesNode",
    65  				KubernetesMapping: ekscontrolplanev1.KubernetesMapping{
    66  					UserName: "system:node:{{EC2PrivateDNSName}}",
    67  					Groups:   []string{"system:bootstrappers", "system:nodes"},
    68  				},
    69  			},
    70  			existingRoleMapping: createIAMAuthMapping("arn:aws:iam::000000000000:role/KubernetesAdmin", "admin:{{SessionName}}", []string{"system:masters"}),
    71  			expectedRoleMapSpecs: []iamauthv1.IAMIdentityMappingSpec{
    72  				{
    73  					ARN:      "arn:aws:iam::000000000000:role/KubernetesAdmin",
    74  					Username: "admin:{{SessionName}}",
    75  					Groups:   []string{"system:masters"},
    76  				},
    77  				{
    78  					ARN:      "arn:aws:iam::000000000000:role/KubernetesNode",
    79  					Username: "system:node:{{EC2PrivateDNSName}}",
    80  					Groups:   []string{"system:bootstrappers", "system:nodes"},
    81  				},
    82  			},
    83  			expectError: false,
    84  		},
    85  		{
    86  			name: "existing mapping, add same role mapping",
    87  			roleToMap: ekscontrolplanev1.RoleMapping{
    88  				RoleARN: "arn:aws:iam::000000000000:role/KubernetesNode",
    89  				KubernetesMapping: ekscontrolplanev1.KubernetesMapping{
    90  					UserName: "system:node:{{EC2PrivateDNSName}}",
    91  					Groups:   []string{"system:bootstrappers", "system:nodes"},
    92  				},
    93  			},
    94  			existingRoleMapping: createIAMAuthMapping("arn:aws:iam::000000000000:role/KubernetesNode", "system:node:{{EC2PrivateDNSName}}", []string{"system:bootstrappers", "system:nodes"}),
    95  			expectedRoleMapSpecs: []iamauthv1.IAMIdentityMappingSpec{
    96  				{
    97  					ARN:      "arn:aws:iam::000000000000:role/KubernetesNode",
    98  					Username: "system:node:{{EC2PrivateDNSName}}",
    99  					Groups:   []string{"system:bootstrappers", "system:nodes"},
   100  				},
   101  			},
   102  			expectError: false,
   103  		},
   104  		{
   105  			name: "no existing mapping, add role with not role ARN",
   106  			roleToMap: ekscontrolplanev1.RoleMapping{
   107  				RoleARN: "arn:aws:iam::000000000000:user/Alice",
   108  				KubernetesMapping: ekscontrolplanev1.KubernetesMapping{
   109  					UserName: "system:node:{{EC2PrivateDNSName}}",
   110  					Groups:   []string{"system:bootstrappers", "system:nodes"},
   111  				},
   112  			},
   113  			expectedRoleMapSpecs: []iamauthv1.IAMIdentityMappingSpec{},
   114  			expectError:          true,
   115  		},
   116  	}
   117  
   118  	for _, tc := range testCases {
   119  		t.Run(tc.name, func(t *testing.T) {
   120  			g := NewGomegaWithT(t)
   121  
   122  			scheme := runtime.NewScheme()
   123  			iamauthv1.AddToScheme(scheme)
   124  
   125  			var client crclient.Client
   126  			if tc.existingRoleMapping == nil {
   127  				client = fake.NewClientBuilder().WithScheme(scheme).Build()
   128  			} else {
   129  				client = fake.NewClientBuilder().WithScheme(scheme).WithObjects(tc.existingRoleMapping).Build()
   130  			}
   131  			backend, err := NewBackend(BackendTypeCRD, client)
   132  			g.Expect(err).To(BeNil())
   133  
   134  			err = backend.MapRole(tc.roleToMap)
   135  			if tc.expectError {
   136  				g.Expect(err).ToNot(BeNil())
   137  				return
   138  			}
   139  
   140  			g.Expect(err).To(BeNil())
   141  
   142  			mappings := &iamauthv1.IAMIdentityMappingList{}
   143  			err = client.List(context.TODO(), mappings)
   144  			g.Expect(err).To(BeNil())
   145  
   146  			g.Expect(len(mappings.Items)).To(Equal(len(tc.expectedRoleMapSpecs)))
   147  
   148  			for _, actualMapping := range mappings.Items {
   149  				found := false
   150  				for _, expectedMappingSpec := range tc.expectedRoleMapSpecs {
   151  					if cmp.Equal(actualMapping.Spec, expectedMappingSpec) {
   152  						found = true
   153  					}
   154  				}
   155  				g.Expect(found).To(BeTrue())
   156  				g.Expect(actualMapping.Namespace).To(Equal("kube-system"))
   157  				g.Expect(strings.HasPrefix(actualMapping.Name, "capa-iamauth-")).To(BeTrue())
   158  			}
   159  		})
   160  	}
   161  }
   162  func TestAddUserMappingCRD(t *testing.T) {
   163  	testCases := []struct {
   164  		name                 string
   165  		existingUserMapping  *iamauthv1.IAMIdentityMapping
   166  		userToMap            ekscontrolplanev1.UserMapping
   167  		expectedUserMapSpecs []iamauthv1.IAMIdentityMappingSpec
   168  		expectError          bool
   169  	}{
   170  		{
   171  			name: "no existing mappings, add user mapping",
   172  			userToMap: ekscontrolplanev1.UserMapping{
   173  				UserARN: "arn:aws:iam::000000000000:user/Alice",
   174  				KubernetesMapping: ekscontrolplanev1.KubernetesMapping{
   175  					UserName: "alice",
   176  					Groups:   []string{"system:masters"},
   177  				},
   178  			},
   179  			expectedUserMapSpecs: []iamauthv1.IAMIdentityMappingSpec{
   180  				{
   181  					ARN:      "arn:aws:iam::000000000000:user/Alice",
   182  					Username: "alice",
   183  					Groups:   []string{"system:masters"},
   184  				},
   185  			},
   186  			expectError: false,
   187  		},
   188  		{
   189  			name: "existing mapping, add different user mapping",
   190  			userToMap: ekscontrolplanev1.UserMapping{
   191  				UserARN: "arn:aws:iam::000000000000:user/Alice",
   192  				KubernetesMapping: ekscontrolplanev1.KubernetesMapping{
   193  					UserName: "alice",
   194  					Groups:   []string{"system:masters"},
   195  				},
   196  			},
   197  			existingUserMapping: createIAMAuthMapping("arn:aws:iam::000000000000:user/Bob", "bob", []string{"system:masters"}),
   198  			expectedUserMapSpecs: []iamauthv1.IAMIdentityMappingSpec{
   199  				{
   200  					ARN:      "arn:aws:iam::000000000000:user/Bob",
   201  					Username: "bob",
   202  					Groups:   []string{"system:masters"},
   203  				},
   204  				{
   205  					ARN:      "arn:aws:iam::000000000000:user/Alice",
   206  					Username: "alice",
   207  					Groups:   []string{"system:masters"},
   208  				},
   209  			},
   210  			expectError: false,
   211  		},
   212  		{
   213  			name: "existing mapping, add same user mapping",
   214  			userToMap: ekscontrolplanev1.UserMapping{
   215  				UserARN: "arn:aws:iam::000000000000:user/Alice",
   216  				KubernetesMapping: ekscontrolplanev1.KubernetesMapping{
   217  					UserName: "alice",
   218  					Groups:   []string{"system:masters"},
   219  				},
   220  			},
   221  			existingUserMapping: createIAMAuthMapping("arn:aws:iam::000000000000:user/Alice", "alice", []string{"system:masters"}),
   222  			expectedUserMapSpecs: []iamauthv1.IAMIdentityMappingSpec{
   223  				{
   224  					ARN:      "arn:aws:iam::000000000000:user/Alice",
   225  					Username: "alice",
   226  					Groups:   []string{"system:masters"},
   227  				},
   228  			},
   229  			expectError: false,
   230  		},
   231  		{
   232  			name: "no existing mapping, add role with not role ARN",
   233  			userToMap: ekscontrolplanev1.UserMapping{
   234  				UserARN: "arn:aws:iam::000000000000:role/KubernetesNode",
   235  				KubernetesMapping: ekscontrolplanev1.KubernetesMapping{
   236  					UserName: "system:node:{{EC2PrivateDNSName}}",
   237  					Groups:   []string{"system:masters"},
   238  				},
   239  			},
   240  			expectedUserMapSpecs: []iamauthv1.IAMIdentityMappingSpec{},
   241  			expectError:          true,
   242  		},
   243  	}
   244  
   245  	for _, tc := range testCases {
   246  		t.Run(tc.name, func(t *testing.T) {
   247  			g := NewGomegaWithT(t)
   248  
   249  			scheme := runtime.NewScheme()
   250  			iamauthv1.AddToScheme(scheme)
   251  
   252  			var client crclient.Client
   253  			if tc.existingUserMapping == nil {
   254  				client = fake.NewClientBuilder().WithScheme(scheme).Build()
   255  			} else {
   256  				client = fake.NewClientBuilder().WithScheme(scheme).WithObjects(tc.existingUserMapping).Build()
   257  			}
   258  			backend, err := NewBackend(BackendTypeCRD, client)
   259  			g.Expect(err).To(BeNil())
   260  
   261  			err = backend.MapUser(tc.userToMap)
   262  			if tc.expectError {
   263  				g.Expect(err).ToNot(BeNil())
   264  				return
   265  			}
   266  
   267  			g.Expect(err).To(BeNil())
   268  
   269  			mappings := &iamauthv1.IAMIdentityMappingList{}
   270  			err = client.List(context.TODO(), mappings)
   271  			g.Expect(err).To(BeNil())
   272  
   273  			g.Expect(len(mappings.Items)).To(Equal(len(tc.expectedUserMapSpecs)))
   274  
   275  			for _, actualMapping := range mappings.Items {
   276  				found := false
   277  				for _, expectedMappingSpec := range tc.expectedUserMapSpecs {
   278  					if cmp.Equal(actualMapping.Spec, expectedMappingSpec) {
   279  						found = true
   280  					}
   281  				}
   282  				g.Expect(found).To(BeTrue())
   283  				g.Expect(actualMapping.Namespace).To(Equal("kube-system"))
   284  				g.Expect(strings.HasPrefix(actualMapping.Name, "capa-iamauth-")).To(BeTrue())
   285  			}
   286  		})
   287  	}
   288  }
   289  
   290  func createIAMAuthMapping(arn string, username string, groups []string) *iamauthv1.IAMIdentityMapping {
   291  	return &iamauthv1.IAMIdentityMapping{
   292  		ObjectMeta: metav1.ObjectMeta{
   293  			Name:      "capa-iamauth-abcd1234",
   294  			Namespace: "kube-system",
   295  			UID:       "1234567890",
   296  		},
   297  		Spec: iamauthv1.IAMIdentityMappingSpec{
   298  			ARN:      arn,
   299  			Username: username,
   300  			Groups:   groups,
   301  		},
   302  	}
   303  }