1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package partialpolicy_test
19
20 import (
21 "context"
22 "fmt"
23 "log"
24 "math/rand"
25 "reflect"
26 "strings"
27 "testing"
28 "time"
29
30 iamv1beta1 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/apis/iam/v1beta1"
31 kcciamclient "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/iam/iamclient"
32 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/iam/partialpolicy"
33 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/dcl/clientconfig"
34 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/dcl/conversion"
35 dclmetadata "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/dcl/metadata"
36 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/dcl/schema/dclschemaloader"
37 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/k8s"
38 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/test"
39 testcontroller "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/test/controller"
40 testreconciler "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/test/controller/reconciler"
41 testgcp "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/test/gcp"
42 testiam "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/test/iam"
43 testk8s "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/test/k8s"
44 testmain "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/test/main"
45 testservicemappingloader "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/test/servicemappingloader"
46 tfprovider "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/tf/provider"
47
48 "github.com/google/go-cmp/cmp"
49 "k8s.io/apimachinery/pkg/api/errors"
50 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
51 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
52 "sigs.k8s.io/controller-runtime/pkg/client"
53 "sigs.k8s.io/controller-runtime/pkg/manager"
54 "sigs.k8s.io/controller-runtime/pkg/reconcile"
55 )
56
57 type updateTestCase struct {
58 name string
59 newBindings []iamv1beta1.IAMPartialPolicyBinding
60 }
61
62 var (
63 mgr manager.Manager
64 expectedReconcileResult = reconcile.Result{RequeueAfter: k8s.MeanReconcileReenqueuePeriod}
65 )
66
67 var resourceLevelIAMPartialPolicyTestFunc = func(t *testing.T, _ string, mgr manager.Manager, rc testiam.IAMResourceContext, refResource *unstructured.Unstructured, resourceRef iamv1beta1.ResourceReference) {
68 provider := tfprovider.NewOrLogFatal(tfprovider.DefaultConfig)
69 kubeClient := mgr.GetClient()
70 smLoader := testservicemappingloader.New(t)
71 dclSchemaLoader, err := dclschemaloader.New()
72 dclConfig := clientconfig.NewForIntegrationTest()
73 if err != nil {
74 t.Fatalf("error creating a new DCL schema loader: %v", err)
75 }
76 serviceMetaLoader := dclmetadata.New()
77 converter := conversion.New(dclSchemaLoader, serviceMetaLoader)
78 iamClient := kcciamclient.New(provider, smLoader, kubeClient, converter, dclConfig)
79 reconciler := testreconciler.NewForDCLAndTFTestReconciler(t, mgr, provider, dclConfig)
80
81
82 serviceAccountName1 := fmt.Sprintf("%v-%v", "sa1", rand.Intn(1000000))
83 createIAMServiceAccount(t, serviceAccountName1, refResource.GetNamespace(), kubeClient, reconciler)
84 defer deleteIAMServiceAccount(t, serviceAccountName1, refResource.GetNamespace(), kubeClient, reconciler)
85
86 serviceAccountName2 := fmt.Sprintf("%v-%v", "sa2", rand.Intn(1000000))
87 createIAMServiceAccount(t, serviceAccountName2, refResource.GetNamespace(), kubeClient, reconciler)
88 defer deleteIAMServiceAccount(t, serviceAccountName2, refResource.GetNamespace(), kubeClient, reconciler)
89
90 testMembers := []iamv1beta1.IAMPartialPolicyMember{
91 {
92 Member: iamv1beta1.Member("group:configconnector-test@google.com"),
93 },
94 {
95 MemberFrom: &iamv1beta1.MemberSource{
96 ServiceAccountRef: &iamv1beta1.MemberReference{
97 Name: serviceAccountName1,
98 },
99 },
100 },
101 }
102 bindings := make([]iamv1beta1.IAMPartialPolicyBinding, 0)
103
104 if rc.Kind != "PubSubTopic" {
105 bindings = append(bindings, iamv1beta1.IAMPartialPolicyBinding{
106 Role: rc.CreateBindingRole,
107 Members: testMembers,
108 })
109 }
110
111 updateTestCases := []updateTestCase{
112 {
113 name: "new bindings with one more role",
114 newBindings: []iamv1beta1.IAMPartialPolicyBinding{
115 {
116 Role: rc.CreateBindingRole,
117 Members: testMembers,
118 },
119 {
120 Role: rc.UpdateBindingRole,
121 Members: testMembers,
122 },
123 },
124 },
125 {
126 name: "new bindings with updated member",
127 newBindings: []iamv1beta1.IAMPartialPolicyBinding{
128 {
129 Role: rc.CreateBindingRole,
130 Members: testMembers,
131 },
132 {
133 Role: rc.UpdateBindingRole,
134 Members: []iamv1beta1.IAMPartialPolicyMember{
135 {
136 Member: iamv1beta1.Member("group:kcc-team@google.com"),
137 },
138 {
139 MemberFrom: &iamv1beta1.MemberSource{
140 ServiceAccountRef: &iamv1beta1.MemberReference{
141 Name: serviceAccountName1,
142 },
143 },
144 },
145 },
146 },
147 },
148 },
149 {
150 name: "new bindings with added member",
151 newBindings: []iamv1beta1.IAMPartialPolicyBinding{
152 {
153 Role: rc.CreateBindingRole,
154 Members: testMembers,
155 },
156 {
157 Role: rc.UpdateBindingRole,
158 Members: []iamv1beta1.IAMPartialPolicyMember{
159 {
160 Member: iamv1beta1.Member("group:configconnector-test@google.com"),
161 },
162 {
163 Member: iamv1beta1.Member("group:kcc-team@google.com"),
164 },
165 {
166 MemberFrom: &iamv1beta1.MemberSource{
167 ServiceAccountRef: &iamv1beta1.MemberReference{
168 Name: serviceAccountName1,
169 },
170 },
171 },
172 },
173 },
174 },
175 },
176 {
177 name: "new bindings with updated memberFrom",
178 newBindings: []iamv1beta1.IAMPartialPolicyBinding{
179 {
180 Role: rc.CreateBindingRole,
181 Members: testMembers,
182 },
183 {
184 Role: rc.UpdateBindingRole,
185 Members: []iamv1beta1.IAMPartialPolicyMember{
186 {
187 Member: iamv1beta1.Member("group:configconnector-test@google.com"),
188 },
189 {
190 MemberFrom: &iamv1beta1.MemberSource{
191 ServiceAccountRef: &iamv1beta1.MemberReference{
192 Name: serviceAccountName2,
193 },
194 },
195 },
196 },
197 },
198 },
199 },
200 {
201 name: "new bindings with added memberFrom",
202 newBindings: []iamv1beta1.IAMPartialPolicyBinding{
203 {
204 Role: rc.CreateBindingRole,
205 Members: testMembers,
206 },
207 {
208 Role: rc.UpdateBindingRole,
209 Members: []iamv1beta1.IAMPartialPolicyMember{
210 {
211 Member: iamv1beta1.Member("group:configconnector-test@google.com"),
212 },
213 {
214 MemberFrom: &iamv1beta1.MemberSource{
215 ServiceAccountRef: &iamv1beta1.MemberReference{
216 Name: serviceAccountName1,
217 },
218 },
219 },
220 {
221 MemberFrom: &iamv1beta1.MemberSource{
222 ServiceAccountRef: &iamv1beta1.MemberReference{
223 Name: serviceAccountName2,
224 },
225 },
226 },
227 },
228 },
229 },
230 },
231 {
232 name: "new bindings with removed role",
233 newBindings: []iamv1beta1.IAMPartialPolicyBinding{
234 {
235 Role: rc.CreateBindingRole,
236 Members: testMembers,
237 },
238 },
239 },
240 }
241
242 k8sPartialPolicy := newIAMPartialPolicyFixture(t, refResource, resourceRef, bindings)
243
244 existingPolicy := presetPolicy(t, iamClient, rc, k8sPartialPolicy)
245 testReconcileResourceLevelCreateNoChangesUpdateDelete(t, kubeClient, k8sPartialPolicy, updateTestCases, existingPolicy, iamClient, reconciler)
246 }
247
248 func TestReconcileIAMPartialPolicyResourceLevelCreateNoChangesUpdateDelete(t *testing.T) {
249 testiam.RunResourceLevelTest(t, mgr, resourceLevelIAMPartialPolicyTestFunc, testiam.ShouldRunWithNoProjectKind)
250 }
251
252 func TestReconcileIAMPartialPolicyResourceLevelCreateNoChangesUpdateDeleteWithExternalRef(t *testing.T) {
253 testiam.RunResourceLevelTestWithExternalRef(t, mgr, resourceLevelIAMPartialPolicyTestFunc, testiam.ShouldRunAcquire)
254 }
255
256
257
258 func presetPolicy(t *testing.T, iamClient *kcciamclient.IAMClient, rc testiam.IAMResourceContext, k8sPartialPolicy *iamv1beta1.IAMPartialPolicy) *iamv1beta1.IAMPolicy {
259 existingBinding := []iamv1beta1.IAMPolicyBinding{
260 {
261 Role: rc.CreateBindingRole,
262 Members: []iamv1beta1.Member{iamv1beta1.Member(testgcp.GetIAMPolicyBindingMember(t))},
263 },
264 }
265 k8sPolicy := partialpolicy.ToIAMPolicySkeleton(k8sPartialPolicy)
266 k8sPolicy.Spec.Bindings = existingBinding
267 if rc.Kind == "Project" || rc.Kind == "Folder" {
268 k8sPolicy.Spec.AuditConfigs = []iamv1beta1.IAMPolicyAuditConfig{
269 {
270 Service: "allServices",
271 AuditLogConfigs: []iamv1beta1.AuditLogConfig{
272 {
273 LogType: "DATA_WRITE",
274 },
275 {
276 LogType: "DATA_READ",
277 ExemptedMembers: []iamv1beta1.Member{iamv1beta1.Member(testgcp.GetIAMPolicyBindingMember(t))},
278 },
279 },
280 },
281 }
282 }
283 existingPolicy, err := iamClient.SetPolicy(context.TODO(), k8sPolicy)
284 if err != nil {
285 t.Fatalf("error setting policy: %v", err)
286 }
287 return existingPolicy
288 }
289
290 func testReconcileResourceLevelCreateNoChangesUpdateDelete(t *testing.T, kubeClient client.Client, k8sPartialPolicy *iamv1beta1.IAMPartialPolicy, updateTestCases []updateTestCase, existingPolicy *iamv1beta1.IAMPolicy, iamClient *kcciamclient.IAMClient, reconciler *testreconciler.TestReconciler) {
291 testReconcileResourceLevelCreate(t, kubeClient, k8sPartialPolicy, existingPolicy, iamClient, reconciler)
292 testReconcileResourceLevelNoChanges(t, kubeClient, k8sPartialPolicy, iamClient, reconciler)
293 currentPartialPolicy := k8sPartialPolicy
294 for _, tc := range updateTestCases {
295 newK8sPartialPolicy := currentPartialPolicy.DeepCopy()
296 newK8sPartialPolicy.Spec.Bindings = tc.newBindings
297 t.Run(fmt.Sprintf("TestUpdate-%v", tc.name), func(t *testing.T) {
298 testReconcileResourceLevelUpdate(t, kubeClient, currentPartialPolicy, newK8sPartialPolicy, existingPolicy, iamClient, reconciler)
299 })
300 currentPartialPolicy = newK8sPartialPolicy
301 }
302 testReconcileResourceLevelDelete(t, kubeClient, currentPartialPolicy, existingPolicy, iamClient, reconciler)
303 }
304
305 func testReconcileResourceLevelCreate(t *testing.T, kubeClient client.Client, k8sPartialPolicy *iamv1beta1.IAMPartialPolicy, existingPolicy *iamv1beta1.IAMPolicy, iamClient *kcciamclient.IAMClient, reconciler *testreconciler.TestReconciler) {
306 if err := kubeClient.Create(context.TODO(), k8sPartialPolicy); err != nil {
307 t.Fatalf("error creating k8sPartialPolicy: %v", err)
308 }
309 preReconcileGeneration := k8sPartialPolicy.GetGeneration()
310 reconciler.ReconcileObjectMeta(k8sPartialPolicy.ObjectMeta, iamv1beta1.IAMPartialPolicyGVK.Kind, expectedReconcileResult, nil)
311 k8sPolicy := partialpolicy.ToIAMPolicySkeleton(k8sPartialPolicy)
312 gcpPolicy, err := iamClient.GetPolicy(context.TODO(), k8sPolicy)
313 if err != nil {
314 t.Fatalf("error retrieving GCP policy: %v", err)
315 }
316 if err := kubeClient.Get(context.TODO(), k8s.GetNamespacedName(k8sPartialPolicy), k8sPartialPolicy); err != nil {
317 t.Fatalf("unexpected error getting k8s resource: %v", err)
318 }
319 assertPolicy(t, k8sPartialPolicy, existingPolicy, gcpPolicy, iamClient)
320 testcontroller.AssertReadyCondition(t, k8sPartialPolicy.Status.Conditions)
321 testcontroller.AssertEventRecordedForObjectMetaAndKind(t, kubeClient, iamv1beta1.IAMPartialPolicyGVK.Kind, &k8sPartialPolicy.ObjectMeta, k8s.UpToDate)
322 assertObservedGenerationEquals(t, k8sPartialPolicy, preReconcileGeneration)
323 }
324
325 func testReconcileResourceLevelUpdate(t *testing.T, kubeClient client.Client, k8sPartialPolicy, newK8sPartialPolicy *iamv1beta1.IAMPartialPolicy, existingPolicy *iamv1beta1.IAMPolicy, iamClient *kcciamclient.IAMClient, reconciler *testreconciler.TestReconciler) {
326 if err := kubeClient.Get(context.TODO(), k8s.GetNamespacedName(k8sPartialPolicy), k8sPartialPolicy); err != nil {
327 t.Fatalf("unexpected error getting k8s resource: %v", err)
328 }
329 newK8sPartialPolicy.SetResourceVersion(k8sPartialPolicy.GetResourceVersion())
330 if err := kubeClient.Update(context.TODO(), newK8sPartialPolicy); err != nil {
331 t.Fatalf("error updating k8sPartialPolicy: %v", err)
332 }
333 preReconcileGeneration := newK8sPartialPolicy.GetGeneration()
334 reconciler.ReconcileObjectMeta(newK8sPartialPolicy.ObjectMeta, iamv1beta1.IAMPartialPolicyGVK.Kind, expectedReconcileResult, nil)
335 if err := kubeClient.Get(context.TODO(), k8s.GetNamespacedName(newK8sPartialPolicy), newK8sPartialPolicy); err != nil {
336 t.Fatalf("unexpected error getting k8s resource: %v", err)
337 }
338 k8sPolicy := partialpolicy.ToIAMPolicySkeleton(newK8sPartialPolicy)
339 gcpPolicy, err := iamClient.GetPolicy(context.TODO(), k8sPolicy)
340 if err != nil {
341 t.Fatalf("error retrieving GCP policy: %v", err)
342 }
343 assertPolicy(t, newK8sPartialPolicy, existingPolicy, gcpPolicy, iamClient)
344 testcontroller.AssertReadyCondition(t, newK8sPartialPolicy.Status.Conditions)
345 testcontroller.AssertEventRecordedForObjectMetaAndKind(t, kubeClient, iamv1beta1.IAMPartialPolicyGVK.Kind, &newK8sPartialPolicy.ObjectMeta, k8s.UpToDate)
346 assertObservedGenerationEquals(t, newK8sPartialPolicy, preReconcileGeneration)
347 }
348
349 func testReconcileResourceLevelNoChanges(t *testing.T, kubeClient client.Client, k8sPartialPolicy *iamv1beta1.IAMPartialPolicy, iamClient *kcciamclient.IAMClient, reconciler *testreconciler.TestReconciler) {
350 if err := kubeClient.Get(context.TODO(), k8s.GetNamespacedName(k8sPartialPolicy), k8sPartialPolicy); err != nil {
351 t.Fatalf("unexpected error getting k8s resource: %v", err)
352 }
353 preReconcileGeneration := k8sPartialPolicy.GetGeneration()
354 reconciler.ReconcileObjectMeta(k8sPartialPolicy.ObjectMeta, iamv1beta1.IAMPartialPolicyGVK.Kind, expectedReconcileResult, nil)
355 newK8sPartialPolicy := &iamv1beta1.IAMPartialPolicy{}
356 if err := kubeClient.Get(context.TODO(), k8s.GetNamespacedName(k8sPartialPolicy), newK8sPartialPolicy); err != nil {
357 t.Fatalf("unexpected error getting k8s resource: %v", err)
358 }
359 if k8sPartialPolicy.GetResourceVersion() != newK8sPartialPolicy.GetResourceVersion() {
360 t.Errorf("reconcile that was expected to be a no-op resulted in a write to the API server")
361 }
362 assertObservedGenerationEquals(t, newK8sPartialPolicy, preReconcileGeneration)
363 }
364
365 func TestReconcileIAMPartialPolicyResourceLevelDeleteParentFirst(t *testing.T) {
366 testFunc := func(t *testing.T, _ string, mgr manager.Manager, rc testiam.IAMResourceContext, refResource *unstructured.Unstructured, resourceRef iamv1beta1.ResourceReference) {
367 bindings := []iamv1beta1.IAMPartialPolicyBinding{
368 {
369 Role: rc.CreateBindingRole,
370 Members: []iamv1beta1.IAMPartialPolicyMember{
371 {
372 Member: iamv1beta1.Member(testgcp.GetIAMPolicyBindingMember(t)),
373 },
374 },
375 },
376 }
377 k8sPartialPolicy := newIAMPartialPolicyFixture(t, refResource, resourceRef, bindings)
378 testReconcileResourceLevelDeleteParentFirst(t, mgr, k8sPartialPolicy, refResource)
379 }
380 testiam.RunResourceLevelTest(t, mgr, testFunc, testiam.ShouldRunDeleteParentFirst)
381 }
382
383 func TestReconcileIAMPartialPolicyResourceLevelDeleteParentFirstWithExternalRef(t *testing.T) {
384 testFunc := func(t *testing.T, _ string, mgr manager.Manager, rc testiam.IAMResourceContext, refResource *unstructured.Unstructured, resourceRef iamv1beta1.ResourceReference) {
385 bindings := []iamv1beta1.IAMPartialPolicyBinding{
386 {
387 Role: rc.CreateBindingRole,
388 Members: []iamv1beta1.IAMPartialPolicyMember{
389 {
390 Member: iamv1beta1.Member(testgcp.GetIAMPolicyBindingMember(t)),
391 },
392 },
393 },
394 }
395 k8sPartialPolicy := newIAMPartialPolicyFixture(t, refResource, resourceRef, bindings)
396 testReconcileResourceLevelDeleteParentFirst(t, mgr, k8sPartialPolicy, refResource)
397 }
398 testiam.RunResourceLevelTestWithExternalRef(t, mgr, testFunc, testiam.ShouldRunDeleteParentFirst)
399 }
400
401 func testReconcileResourceLevelDelete(t *testing.T, kubeClient client.Client, k8sPartialPolicy *iamv1beta1.IAMPartialPolicy, existingPolicy *iamv1beta1.IAMPolicy, iamClient *kcciamclient.IAMClient, reconciler *testreconciler.TestReconciler) {
402 if k8sPartialPolicy.Spec.ResourceReference.Kind == "StorageBucket" {
403
404
405 return
406 }
407 if err := kubeClient.Delete(context.TODO(), k8sPartialPolicy); err != nil {
408 t.Fatalf("error deleting k8sPartialPolicy: %v", err)
409 }
410 reconciler.ReconcileObjectMeta(k8sPartialPolicy.ObjectMeta, iamv1beta1.IAMPartialPolicyGVK.Kind, testreconciler.ExpectedRequeueReconcileStruct, nil)
411 k8sPolicy := partialpolicy.ToIAMPolicySkeleton(k8sPartialPolicy)
412 gcpPolicy, err := iamClient.GetPolicy(context.TODO(), k8sPolicy)
413 if err != nil {
414 t.Fatalf("error retrieving GCP policy: %v", err)
415 }
416 assertPolicy(t, k8sPartialPolicy, existingPolicy, gcpPolicy, iamClient)
417 testk8s.RemoveDeletionDefenderFinalizer(t, k8sPartialPolicy, iamv1beta1.IAMPartialPolicyGVK, kubeClient)
418 reconciler.ReconcileObjectMeta(k8sPartialPolicy.ObjectMeta, iamv1beta1.IAMPartialPolicyGVK.Kind, expectedReconcileResult, nil)
419 gcpPolicy, err = iamClient.GetPolicy(context.TODO(), k8sPolicy)
420 if err != nil {
421 t.Fatalf("error retrieving GCP policy: %v", err)
422 }
423 testiam.AssertSamePolicy(t, existingPolicy, gcpPolicy)
424 if err := kubeClient.Get(context.TODO(), k8s.GetNamespacedName(k8sPartialPolicy), k8sPartialPolicy); err == nil || !errors.IsNotFound(err) {
425 t.Fatalf("unexpected error value: %v", err)
426 }
427 testcontroller.AssertEventRecordedForObjectMetaAndKind(t, kubeClient, iamv1beta1.IAMPartialPolicyGVK.Kind, &k8sPartialPolicy.ObjectMeta, k8s.Deleted)
428 }
429
430 func testReconcileResourceLevelDeleteParentFirst(t *testing.T, mgr manager.Manager, k8sPartialPolicy *iamv1beta1.IAMPartialPolicy, refResource *unstructured.Unstructured) {
431 kubeClient := mgr.GetClient()
432 if err := kubeClient.Create(context.TODO(), k8sPartialPolicy); err != nil {
433 t.Fatalf("error creating k8sPartialPolicy: %v", err)
434 }
435 reconciler := testreconciler.New(t, mgr, tfprovider.NewOrLogFatal(tfprovider.DefaultConfig))
436 reconciler.ReconcileObjectMeta(k8sPartialPolicy.ObjectMeta, iamv1beta1.IAMPartialPolicyGVK.Kind, expectedReconcileResult, nil)
437
438
439 log.Printf("Deleting the parent of the IAM Policy first %v: %v/%v\n", refResource.GetKind(), refResource.GetNamespace(), refResource.GetName())
440 testk8s.RemoveDeletionDefenderFinalizerForUnstructured(t, refResource, kubeClient)
441 err := kubeClient.Delete(context.TODO(), refResource)
442 if err != nil {
443 t.Errorf("error deleting %v: %v", refResource, err)
444 }
445 reconciler.Reconcile(refResource, expectedReconcileResult, nil)
446
447
448 testk8s.RemoveDeletionDefenderFinalizer(t, k8sPartialPolicy, iamv1beta1.IAMPartialPolicyGVK, kubeClient)
449 if err := kubeClient.Delete(context.TODO(), k8sPartialPolicy); err != nil {
450 t.Fatalf("error deleting k8sPartialPolicy: %v", err)
451 }
452 reconciler.ReconcileObjectMeta(k8sPartialPolicy.ObjectMeta, iamv1beta1.IAMPartialPolicyGVK.Kind, expectedReconcileResult, nil)
453 if err := kubeClient.Get(context.TODO(), k8s.GetNamespacedName(k8sPartialPolicy), k8sPartialPolicy); err == nil || !errors.IsNotFound(err) {
454 t.Fatalf("unexpected error value: %v", err)
455 }
456
457 testcontroller.CollectEvents(t, mgr.GetConfig(), k8sPartialPolicy.Namespace, 6, 5*time.Second)
458 testcontroller.AssertEventRecordedForObjectMetaAndKind(t, kubeClient, iamv1beta1.IAMPartialPolicyGVK.Kind, &k8sPartialPolicy.ObjectMeta, k8s.Deleted)
459 }
460
461 func TestReconcileIAMPartialPolicyResourceLevelAcquire(t *testing.T) {
462 testFunc := func(t *testing.T, _ string, mgr manager.Manager, rc testiam.IAMResourceContext, refResource *unstructured.Unstructured, resourceRef iamv1beta1.ResourceReference) {
463 bindings := []iamv1beta1.IAMPartialPolicyBinding{
464 {
465 Role: rc.CreateBindingRole,
466 Members: []iamv1beta1.IAMPartialPolicyMember{
467 {
468 Member: iamv1beta1.Member(testgcp.GetIAMPolicyBindingMember(t)),
469 },
470 },
471 },
472 }
473 existingBindings := []iamv1beta1.IAMPolicyBinding{
474 {
475 Role: rc.CreateBindingRole,
476 Members: []iamv1beta1.Member{
477 iamv1beta1.Member(testgcp.GetIAMPolicyBindingMember(t)),
478 },
479 },
480 }
481 k8sPartialPolicy := newIAMPartialPolicyFixture(t, refResource, resourceRef, bindings)
482 testReconcileResourceLevelAcquire(t, mgr, k8sPartialPolicy, existingBindings)
483 }
484 testiam.RunResourceLevelTest(t, mgr, testFunc, testiam.ShouldRunAcquire)
485 }
486
487 func TestReconcileIAMPartialPolicyResourceLevelAcquireWithExternalRef(t *testing.T) {
488 testFunc := func(t *testing.T, _ string, mgr manager.Manager, rc testiam.IAMResourceContext, refResource *unstructured.Unstructured, resourceRef iamv1beta1.ResourceReference) {
489 bindings := []iamv1beta1.IAMPartialPolicyBinding{
490 {
491 Role: rc.CreateBindingRole,
492 Members: []iamv1beta1.IAMPartialPolicyMember{
493 {
494 Member: iamv1beta1.Member(testgcp.GetIAMPolicyBindingMember(t)),
495 },
496 },
497 },
498 }
499 existingBindings := []iamv1beta1.IAMPolicyBinding{
500 {
501 Role: rc.CreateBindingRole,
502 Members: []iamv1beta1.Member{
503 iamv1beta1.Member(testgcp.GetIAMPolicyBindingMember(t)),
504 },
505 },
506 }
507 k8sPartialPolicy := newIAMPartialPolicyFixture(t, refResource, resourceRef, bindings)
508 testReconcileResourceLevelAcquire(t, mgr, k8sPartialPolicy, existingBindings)
509 }
510 testiam.RunResourceLevelTestWithExternalRef(t, mgr, testFunc, testiam.ShouldRunAcquire)
511 }
512
513 func testReconcileResourceLevelAcquire(t *testing.T, mgr manager.Manager, k8sPartialPolicy *iamv1beta1.IAMPartialPolicy, existingBindings []iamv1beta1.IAMPolicyBinding) {
514 kubeClient := mgr.GetClient()
515 provider := tfprovider.NewOrLogFatal(tfprovider.DefaultConfig)
516 smLoader := testservicemappingloader.New(t)
517 dclConfig := clientconfig.NewForIntegrationTest()
518 dclSchemaLoader, err := dclschemaloader.New()
519 if err != nil {
520 t.Fatalf("error creating a new DCL schema loader: %v", err)
521 }
522 serviceMetaLoader := dclmetadata.New()
523 converter := conversion.New(dclSchemaLoader, serviceMetaLoader)
524 iamClient := kcciamclient.New(provider, smLoader, kubeClient, converter, dclConfig)
525 reconciler := testreconciler.New(t, mgr, provider)
526
527
528 k8sPolicy := partialpolicy.ToIAMPolicySkeleton(k8sPartialPolicy)
529 k8sPolicy.Spec.Bindings = existingBindings
530 if _, err := iamClient.SetPolicy(context.TODO(), k8sPolicy); err != nil {
531 t.Fatalf("error creating GCP policy: %v", err)
532 }
533
534
535 if err := kubeClient.Create(context.TODO(), k8sPartialPolicy); err != nil {
536 t.Fatalf("error creating k8sPartialPolicy: %v", err)
537 }
538 preReconcileGeneration := k8sPartialPolicy.GetGeneration()
539 reconciler.ReconcileObjectMeta(k8sPartialPolicy.ObjectMeta, iamv1beta1.IAMPartialPolicyGVK.Kind, expectedReconcileResult, nil)
540 gcpPolicy, err := iamClient.GetPolicy(context.TODO(), k8sPolicy)
541 if err != nil {
542 t.Fatalf("error retrieving GCP policy: %v", err)
543 }
544 testiam.AssertSamePolicy(t, k8sPolicy, gcpPolicy)
545 if err := kubeClient.Get(context.TODO(), k8s.GetNamespacedName(k8sPartialPolicy), k8sPartialPolicy); err != nil {
546 t.Fatalf("unexpected error getting k8s resource: %v", err)
547 }
548 testcontroller.AssertReadyCondition(t, k8sPartialPolicy.Status.Conditions)
549 testcontroller.AssertEventRecordedForObjectMetaAndKind(t, kubeClient, iamv1beta1.IAMPartialPolicyGVK.Kind, &k8sPartialPolicy.ObjectMeta, k8s.UpToDate)
550 assertObservedGenerationEquals(t, k8sPartialPolicy, preReconcileGeneration)
551 }
552
553 func newIAMPartialPolicyFixture(t *testing.T, refResource *unstructured.Unstructured, resourceRef iamv1beta1.ResourceReference, bindings []iamv1beta1.IAMPartialPolicyBinding) *iamv1beta1.IAMPartialPolicy {
554 t.Helper()
555 if !strings.HasPrefix(t.Name(), "TestReconcile") {
556 t.Fatalf("Unexpected test name prefix, all tests are expected to start with TestReconcile")
557 }
558 return &iamv1beta1.IAMPartialPolicy{
559 TypeMeta: metav1.TypeMeta{
560 APIVersion: iamv1beta1.IAMPartialPolicyGVK.GroupVersion().String(),
561 Kind: iamv1beta1.IAMPartialPolicyGVK.Kind,
562 },
563 ObjectMeta: metav1.ObjectMeta{
564 Name: testcontroller.UniqueName(t, name(t)),
565 Namespace: refResource.GetNamespace(),
566 },
567 Spec: iamv1beta1.IAMPartialPolicySpec{
568 ResourceReference: resourceRef,
569 Bindings: bindings,
570 },
571 }
572 }
573
574 func createIAMServiceAccount(t *testing.T, name, namespace string, kubeClient client.Client, reconciler *testreconciler.TestReconciler) {
575 refServiceAccount := test.NewIAMServiceAccountUnstructured(name, namespace)
576 if err := kubeClient.Create(context.TODO(), refServiceAccount); err != nil {
577 t.Fatalf("error creating IAMServiceAccount: %v", err)
578 }
579 objectMeta := metav1.ObjectMeta{
580 Name: name,
581 Namespace: namespace,
582 }
583 reconciler.ReconcileObjectMeta(objectMeta, kcciamclient.IAMServiceAccountGVK.Kind, expectedReconcileResult, nil)
584 }
585
586 func deleteIAMServiceAccount(t *testing.T, name, namespace string, kubeClient client.Client, reconciler *testreconciler.TestReconciler) {
587 refServiceAccount := test.NewIAMServiceAccountUnstructured(name, namespace)
588
589 testk8s.RemoveDeletionDefenderFinalizerForUnstructured(t, refServiceAccount, kubeClient)
590 if err := kubeClient.Delete(context.TODO(), refServiceAccount); err != nil {
591 t.Fatalf("error deleting IAMServiceAccount %v: %v", refServiceAccount.GetName(), err)
592 }
593 reconciler.Reconcile(refServiceAccount, expectedReconcileResult, nil)
594 }
595
596 func assertPolicy(t *testing.T, k8sPartialPolicy *iamv1beta1.IAMPartialPolicy, existingPolicy *iamv1beta1.IAMPolicy, gcpPolicy *iamv1beta1.IAMPolicy, iamClient *kcciamclient.IAMClient) {
597 if !reflect.DeepEqual(k8sPartialPolicy.Spec.ResourceReference, gcpPolicy.Spec.ResourceReference) {
598 diff := cmp.Diff(k8sPartialPolicy.Spec.ResourceReference, gcpPolicy.Spec.ResourceReference)
599 t.Fatalf("GCP policy has incorrect resource reference. Diff (-want, +got):\n%v", diff)
600 }
601 if !testiam.ContainsBindings(gcpPolicy.Spec.Bindings, existingPolicy.Spec.Bindings) {
602 t.Fatalf("GCP policy doesn't have all existing bindings as expected; current bindings: %v, existing bindings: %v", gcpPolicy.Spec.Bindings, existingPolicy.Spec.Bindings)
603 }
604 resolver := partialpolicy.IAMMemberIdentityResolver{Iamclient: iamClient, Ctx: context.TODO()}
605 configuredBinding, err := partialpolicy.ConvertIAMPartialBindingsToIAMPolicyBindings(k8sPartialPolicy, &resolver)
606 if err != nil {
607 t.Fatalf("ConvertIAMPartialBindingsToIAMPolicyBindings returned error: %v", err)
608 }
609 if !testiam.ContainsBindings(gcpPolicy.Spec.Bindings, configuredBinding) {
610 t.Fatalf("GCP policy doesn't have all bindings that are configured in IAM partial policy; current bindings: %v, configured bindings: %v", gcpPolicy.Spec.Bindings, configuredBinding)
611 }
612 if !testiam.SameBindings(k8sPartialPolicy.Status.AllBindings, gcpPolicy.Spec.Bindings) {
613 t.Fatalf("GCP policy has incorrect bindings; got: %v, want: %v", gcpPolicy.Spec.Bindings, k8sPartialPolicy.Spec.Bindings)
614 }
615 if !testiam.SameAuditConfigs(existingPolicy.Spec.AuditConfigs, gcpPolicy.Spec.AuditConfigs) {
616 t.Fatalf("GCP policy has incorrect audit configs; got: %v, want: %v", gcpPolicy.Spec.AuditConfigs, existingPolicy.Spec.AuditConfigs)
617 }
618 }
619
620 func assertObservedGenerationEquals(t *testing.T, gcpPolicy *iamv1beta1.IAMPartialPolicy, preReconcileGeneration int64) {
621 if gcpPolicy.Status.ObservedGeneration != preReconcileGeneration {
622 t.Errorf("observedGeneration %v doesn't match with the pre-reconcile generation %v", gcpPolicy.Status.ObservedGeneration, preReconcileGeneration)
623 }
624 }
625
626 func name(t *testing.T) string {
627
628 name := strings.ToLower(testcontroller.Name(t))
629 return strings.Split(name, "/")[0]
630 }
631
632 func TestMain(m *testing.M) {
633 testmain.TestMainForIntegrationTests(m, &mgr)
634 }
635
View as plain text