istio

Форк
0
1815 строк · 63.3 Кб
1
// Copyright Istio Authors
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15
package ambient
16

17
import (
18
	"fmt"
19
	"net/netip"
20
	"path/filepath"
21
	"strings"
22
	"testing"
23
	"time"
24

25
	corev1 "k8s.io/api/core/v1"
26
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27
	"k8s.io/apimachinery/pkg/runtime/schema"
28
	k8sv1 "sigs.k8s.io/gateway-api/apis/v1"
29
	k8sbeta "sigs.k8s.io/gateway-api/apis/v1beta1"
30

31
	"istio.io/api/meta/v1alpha1"
32
	"istio.io/api/networking/v1alpha3"
33
	auth "istio.io/api/security/v1beta1"
34
	"istio.io/api/type/v1beta1"
35
	apiv1alpha3 "istio.io/client-go/pkg/apis/networking/v1alpha3"
36
	clientsecurityv1beta1 "istio.io/client-go/pkg/apis/security/v1beta1"
37
	"istio.io/istio/pilot/pkg/config/kube/crd"
38
	"istio.io/istio/pilot/pkg/features"
39
	"istio.io/istio/pilot/pkg/model"
40
	"istio.io/istio/pilot/pkg/serviceregistry/util/xdsfake"
41
	"istio.io/istio/pilot/test/util"
42
	"istio.io/istio/pkg/cluster"
43
	"istio.io/istio/pkg/config"
44
	"istio.io/istio/pkg/config/constants"
45
	"istio.io/istio/pkg/config/labels"
46
	"istio.io/istio/pkg/config/schema/gvk"
47
	"istio.io/istio/pkg/config/schema/gvr"
48
	"istio.io/istio/pkg/config/schema/kind"
49
	kubeclient "istio.io/istio/pkg/kube"
50
	"istio.io/istio/pkg/kube/controllers"
51
	"istio.io/istio/pkg/kube/kclient/clienttest"
52
	"istio.io/istio/pkg/kube/krt"
53
	"istio.io/istio/pkg/network"
54
	"istio.io/istio/pkg/slices"
55
	"istio.io/istio/pkg/test"
56
	"istio.io/istio/pkg/test/util/assert"
57
	"istio.io/istio/pkg/test/util/file"
58
	"istio.io/istio/pkg/test/util/retry"
59
	"istio.io/istio/pkg/util/protomarshal"
60
	"istio.io/istio/pkg/util/sets"
61
	"istio.io/istio/pkg/workloadapi"
62
	"istio.io/istio/pkg/workloadapi/security"
63
)
64

65
const (
66
	testNS   = "ns1"
67
	systemNS = "istio-system"
68
	testNW   = "testnetwork"
69
	testC    = "cluster0"
70
)
71

72
func init() {
73
	features.EnableAmbientWaypoints = true
74
	features.EnableAmbientControllers = true
75
}
76

77
func TestAmbientIndex_NetworkAndClusterIDs(t *testing.T) {
78
	cases := []struct {
79
		name    string
80
		cluster cluster.ID
81
		network network.ID
82
	}{
83
		{
84
			name:    "values unset",
85
			cluster: "",
86
			network: "",
87
		},
88
		{
89
			name:    "values set",
90
			cluster: testC,
91
			network: testNW,
92
		},
93
	}
94

95
	for _, c := range cases {
96
		t.Run(c.name, func(t *testing.T) {
97
			s := newAmbientTestServer(t, c.cluster, c.network)
98
			s.addPods(t, "127.0.0.1", "pod1", "sa1", map[string]string{"app": "a"}, nil, true, corev1.PodRunning)
99
			s.assertEvent(t, s.podXdsName("pod1"))
100
			s.assertAddresses(t, s.addrXdsName("127.0.0.1"), "pod1")
101
		})
102
	}
103
}
104

105
func TestAmbientIndex_WorkloadNotFound(t *testing.T) {
106
	s := newAmbientTestServer(t, testC, testNW)
107

108
	// Add a pod.
109
	s.addPods(t, "127.0.0.1", "pod1", "sa1", map[string]string{"app": "a"}, nil, true, corev1.PodRunning)
110

111
	// Lookup a different address and verify nothing is returned.
112
	s.assertAddresses(t, s.addrXdsName("10.0.0.1"))
113
}
114

115
func TestAmbientIndex_LookupWorkloads(t *testing.T) {
116
	s := newAmbientTestServer(t, testC, testNW)
117

118
	s.addPods(t, "127.0.0.1", "pod1", "sa1", map[string]string{"app": "a"}, nil, true, corev1.PodRunning)
119
	s.assertAddresses(t, "", "pod1")
120
	s.assertEvent(t, s.podXdsName("pod1"))
121

122
	s.addPods(t, "127.0.0.2", "pod2", "sa1", map[string]string{"app": "a", "other": "label"}, nil, true, corev1.PodRunning)
123
	s.addPods(t, "127.0.0.3", "pod3", "sa1", map[string]string{"app": "other"}, nil, true, corev1.PodRunning)
124
	s.assertAddresses(t, "", "pod1", "pod2", "pod3")
125
	s.assertAddresses(t, s.addrXdsName("127.0.0.1"), "pod1")
126
	s.assertAddresses(t, s.addrXdsName("127.0.0.2"), "pod2")
127
	for _, key := range []string{s.podXdsName("pod3"), s.addrXdsName("127.0.0.3")} {
128
		assert.Equal(t, s.lookup(key), []model.AddressInfo{
129
			{
130
				Address: &workloadapi.Address{
131
					Type: &workloadapi.Address_Workload{
132
						Workload: &workloadapi.Workload{
133
							Name:              "pod3",
134
							Namespace:         testNS,
135
							Addresses:         [][]byte{netip.MustParseAddr("127.0.0.3").AsSlice()},
136
							Network:           testNW,
137
							ServiceAccount:    "sa1",
138
							Uid:               s.podXdsName("pod3"),
139
							Node:              "node1",
140
							CanonicalName:     "other",
141
							CanonicalRevision: "latest",
142
							WorkloadType:      workloadapi.WorkloadType_POD,
143
							WorkloadName:      "pod3",
144
							ClusterId:         testC,
145
							Status:            workloadapi.WorkloadStatus_HEALTHY,
146
						},
147
					},
148
				},
149
			},
150
		})
151
	}
152
	s.assertEvent(t, s.podXdsName("pod2"))
153
	s.assertEvent(t, s.podXdsName("pod3"))
154
}
155

156
func TestAmbientIndex_ServiceAttachedWaypoints(t *testing.T) {
157
	test.SetForTest(t, &features.EnableAmbientControllers, true)
158
	s := newAmbientTestServer(t, testC, testNW)
159

160
	s.addWaypoint(t, "10.0.0.10", "test-wp", "default", true)
161

162
	s.addPods(t, "127.0.0.1", "pod1", "sa1", map[string]string{"app": "a"}, nil, true, corev1.PodRunning)
163
	s.assertEvent(t, s.podXdsName("pod1"))
164

165
	// Now add a service that will select pods with label "a".
166
	s.addService(t, "svc1",
167
		map[string]string{},
168
		map[string]string{},
169
		[]int32{80}, map[string]string{"app": "a"}, "10.0.0.1")
170
	s.assertEvent(t, s.podXdsName("pod1"), s.svcXdsName("svc1"))
171

172
	s.addService(t, "svc1",
173
		map[string]string{},
174
		map[string]string{constants.AmbientUseWaypoint: "test-wp"},
175
		[]int32{80}, map[string]string{"app": "a"}, "10.0.0.1")
176
	s.assertEvent(t, s.svcXdsName("svc1"))
177
	s.assertNoEvent(t)
178

179
	// We should now see the waypoint service IP when we look up the annotated svc
180
	assert.Equal(t,
181
		s.lookup(s.addrXdsName("10.0.0.1"))[0].Address.GetService().Waypoint.GetAddress().Address,
182
		netip.MustParseAddr("10.0.0.10").AsSlice())
183
}
184

185
func TestAmbientIndex_ServiceSelectsCorrectWorkloads(t *testing.T) {
186
	s := newAmbientTestServer(t, testC, testNW)
187

188
	// Add 2 pods with the "a" label, and one without.
189
	// We should get an event for the new Service and the two *Pod* IPs impacted
190
	s.addPods(t, "127.0.0.1", "pod1", "sa1", map[string]string{"app": "a"}, nil, true, corev1.PodRunning)
191
	s.assertEvent(t, s.podXdsName("pod1"))
192
	s.addPods(t, "127.0.0.2", "pod2", "sa1", map[string]string{"app": "a", "other": "label"}, nil, true, corev1.PodRunning)
193
	s.assertEvent(t, s.podXdsName("pod2"))
194
	s.addPods(t, "127.0.0.3", "pod3", "sa1", map[string]string{"app": "other"}, nil, true, corev1.PodRunning)
195
	s.assertEvent(t, s.podXdsName("pod3"))
196
	s.clearEvents()
197

198
	// Now add a service that will select pods with label "a".
199
	s.addService(t, "svc1",
200
		map[string]string{},
201
		map[string]string{},
202
		[]int32{80}, map[string]string{"app": "a"}, "10.0.0.1")
203
	s.assertEvent(t, s.podXdsName("pod1"), s.podXdsName("pod2"), s.svcXdsName("svc1"))
204

205
	// Services should appear with workloads when we get all resources.
206
	s.assertAddresses(t, "", "pod1", "pod2", "pod3", "svc1")
207

208
	// Look up the resources by VIP.
209
	s.assertAddresses(t, s.addrXdsName("10.0.0.1"), "pod1", "pod2", "svc1")
210

211
	s.clearEvents()
212

213
	// Add a new pod to the service, we should see it
214
	s.addPods(t, "127.0.0.4", "pod4", "sa1", map[string]string{"app": "a"}, nil, true, corev1.PodRunning)
215
	s.assertAddresses(t, "", "pod1", "pod2", "pod3", "pod4", "svc1")
216
	s.assertAddresses(t, s.addrXdsName("10.0.0.1"), "pod1", "pod2", "pod4", "svc1")
217
	s.assertEvent(t, s.podXdsName("pod4"))
218
	s.clearEvents()
219

220
	// Delete it, should remove from the Service as well
221
	s.deletePod(t, "pod4")
222
	s.assertAddresses(t, "", "pod1", "pod2", "pod3", "svc1")
223
	s.assertAddresses(t, s.addrXdsName("10.0.0.1"), "pod1", "pod2", "svc1")
224
	s.assertAddresses(t, s.addrXdsName("127.0.0.4")) // Should not be accessible anymore
225
	s.assertAddresses(t, s.podXdsName("pod4"))
226
	s.assertEvent(t, s.podXdsName("pod4"))
227
	s.clearEvents()
228

229
	// Update Service to have a more restrictive label selector
230
	s.addService(t, "svc1",
231
		map[string]string{},
232
		map[string]string{},
233
		[]int32{80}, map[string]string{"app": "a", "other": "label"}, "10.0.0.1")
234
	s.assertAddresses(t, "", "pod1", "pod2", "pod3", "svc1")
235
	s.assertAddresses(t, s.addrXdsName("10.0.0.1"), "pod2", "svc1")
236
	s.assertEvent(t, s.podXdsName("pod1"))
237
	s.clearEvents()
238

239
	// Update a pod to add it to the service
240
	s.addPods(t, "127.0.0.3", "pod3", "sa1", map[string]string{"app": "a", "other": "label"}, nil, true, corev1.PodRunning)
241
	s.assertAddresses(t, "", "pod1", "pod2", "pod3", "svc1")
242
	s.assertAddresses(t, s.addrXdsName("10.0.0.1"), "pod2", "pod3", "svc1")
243
	s.assertEvent(t, s.podXdsName("pod3"))
244
	s.clearEvents()
245

246
	// And remove it again
247
	s.addPods(t, "127.0.0.3", "pod3", "sa1", map[string]string{"app": "a"}, nil, true, corev1.PodRunning)
248
	s.assertAddresses(t, "", "pod1", "pod2", "pod3", "svc1")
249
	s.assertAddresses(t, s.addrXdsName("10.0.0.1"), "pod2", "svc1")
250
	s.assertEvent(t, s.podXdsName("pod3"))
251
	s.clearEvents()
252

253
	// Delete the service entirely
254
	s.deleteService(t, "svc1")
255
	s.assertAddresses(t, "", "pod1", "pod2", "pod3")
256
	s.assertAddresses(t, s.addrXdsName("10.0.0.1"))
257
	s.assertEvent(t, s.podXdsName("pod2"), s.svcXdsName("svc1"))
258
}
259

260
func TestAmbientIndex_WaypointConfiguredOnlyWhenReady(t *testing.T) {
261
	s := newAmbientTestServer(t, testC, testNW)
262

263
	s.addPods(t,
264
		"127.0.0.1",
265
		"pod1",
266
		"sa1",
267
		map[string]string{"app": "a"},
268
		map[string]string{constants.AmbientUseWaypoint: "waypoint-sa1"},
269
		true,
270
		corev1.PodRunning)
271
	s.assertEvent(t, s.podXdsName("pod1"))
272
	s.addPods(t,
273
		"127.0.0.2",
274
		"pod2",
275
		"sa2",
276
		map[string]string{"app": "b"},
277
		map[string]string{constants.AmbientUseWaypoint: "waypoint-sa2"},
278
		true,
279
		corev1.PodRunning)
280
	s.assertEvent(t, s.podXdsName("pod2"))
281

282
	s.addWaypoint(t, "10.0.0.1", "waypoint-sa1", "sa1", false)
283
	s.addWaypoint(t, "10.0.0.2", "waypoint-sa2", "sa2", true)
284
	s.assertEvent(t, s.podXdsName("pod2"))
285

286
	// make waypoint-sa1 ready
287
	s.addWaypoint(t, "10.0.0.1", "waypoint-sa1", "sa1", true)
288
	// if waypoint-sa1 was configured when not ready "pod2" assertions should skip the "pod1" xds event and this should fail
289
	s.assertEvent(t, s.podXdsName("pod1"))
290
}
291

292
func TestAmbientIndex_WaypointAddressAddedToWorkloads(t *testing.T) {
293
	s := newAmbientTestServer(t, testC, testNW)
294

295
	s.ns.Update(&corev1.Namespace{
296
		ObjectMeta: metav1.ObjectMeta{
297
			Name: testNS,
298
			Annotations: map[string]string{
299
				constants.AmbientUseWaypoint: "waypoint-ns",
300
			},
301
		},
302
	})
303

304
	// Add pods for app "a".
305
	s.addPods(t, "127.0.0.1", "pod1", "sa1", map[string]string{"app": "a"}, nil, true, corev1.PodRunning)
306
	s.assertEvent(t, s.podXdsName("pod1"))
307
	s.addPods(t, "127.0.0.2", "pod2", "sa1", map[string]string{"app": "a", "other": "label"}, nil, true, corev1.PodRunning)
308
	s.assertEvent(t, s.podXdsName("pod2"))
309
	s.addPods(t, "127.0.0.3", "pod3", "sa1", map[string]string{"app": "a"}, nil, true, corev1.PodRunning)
310
	s.assertEvent(t, s.podXdsName("pod3"))
311
	// Add pods for app "b".
312
	s.addPods(t,
313
		"127.0.0.4",
314
		"pod4",
315
		"sa2",
316
		map[string]string{"app": "b"},
317
		map[string]string{constants.AmbientUseWaypoint: "waypoint-sa2"},
318
		true,
319
		corev1.PodRunning)
320
	s.assertEvent(t, s.podXdsName("pod4"))
321

322
	s.addWaypoint(t, "10.0.0.2", "waypoint-ns", "", true)
323
	// All these workloads updated, so push them
324
	s.assertEvent(t, s.podXdsName("pod1"),
325
		s.podXdsName("pod2"),
326
		s.podXdsName("pod3"),
327
	)
328

329
	// Add a waypoint proxy pod for namespace
330
	s.addPods(t, "127.0.0.200", "waypoint-ns-pod", "namespace-wide",
331
		map[string]string{
332
			constants.ManagedGatewayLabel: constants.ManagedGatewayMeshControllerLabel,
333
			constants.GatewayNameLabel:    "namespace-wide",
334
		}, nil, true, corev1.PodRunning)
335
	s.assertEvent(t, s.podXdsName("waypoint-ns-pod"))
336
	// create the waypoint service
337
	s.addService(t, "waypoint-ns",
338
		map[string]string{constants.ManagedGatewayLabel: constants.ManagedGatewayMeshControllerLabel},
339
		map[string]string{},
340
		[]int32{80}, map[string]string{constants.GatewayNameLabel: "namespace-wide"}, "10.0.0.2")
341
	s.assertEvent(t,
342
		s.podXdsName("waypoint-ns-pod"),
343
		s.svcXdsName("waypoint-ns"),
344
	)
345
	s.assertAddresses(t, "", "pod1", "pod2", "pod3", "pod4", "waypoint-ns", "waypoint-ns-pod")
346

347
	s.addWaypoint(t, "10.0.0.3", "waypoint-sa2", "sa2", true)
348
	s.assertEvent(t, s.podXdsName("pod4"))
349
	// Add a waypoint proxy pod for sa2
350
	s.addPods(t, "127.0.0.250", "waypoint-sa2-pod", "service-account",
351
		map[string]string{
352
			constants.ManagedGatewayLabel: constants.ManagedGatewayMeshControllerLabel,
353
			constants.GatewayNameLabel:    "service-account",
354
		}, nil, true, corev1.PodRunning)
355
	s.assertEvent(t, s.podXdsName("waypoint-sa2-pod"))
356
	// create the waypoint service
357
	s.addService(t, "waypoint-sa2",
358
		map[string]string{constants.ManagedGatewayLabel: constants.ManagedGatewayMeshControllerLabel},
359
		map[string]string{},
360
		[]int32{80}, map[string]string{constants.GatewayNameLabel: "service-account"}, "10.0.0.3")
361
	s.assertEvent(t,
362
		s.podXdsName("waypoint-sa2-pod"),
363
		s.svcXdsName("waypoint-sa2"),
364
	)
365
	s.assertAddresses(t, "", "pod1", "pod2", "pod3", "pod4", "waypoint-ns", "waypoint-ns-pod", "waypoint-sa2-pod", "waypoint-sa2")
366

367
	// We should now see the waypoint service IP
368
	assert.Equal(t,
369
		s.lookup(s.addrXdsName("127.0.0.3"))[0].Address.GetWorkload().Waypoint.GetAddress().Address,
370
		netip.MustParseAddr("10.0.0.2").AsSlice())
371

372
	assert.Equal(t,
373
		s.lookup(s.addrXdsName("127.0.0.4"))[0].Address.GetWorkload().Waypoint.GetAddress().Address,
374
		netip.MustParseAddr("10.0.0.3").AsSlice())
375

376
	// Lookup for service VIP should return Workload and Service AddressInfo objects
377
	assert.Equal(t,
378
		len(s.lookup(s.addrXdsName("10.0.0.2"))),
379
		2)
380
	for _, k := range s.lookup(s.addrXdsName("10.0.0.2")) {
381
		switch k.Type.(type) {
382
		case *workloadapi.Address_Workload:
383
			assert.Equal(t, k.Address.GetWorkload().Name, "waypoint-ns-pod")
384
			assert.Equal(t, k.Address.GetWorkload().Waypoint, nil)
385
		case *workloadapi.Address_Service:
386
			assert.Equal(t, k.Address.GetService().Name, "waypoint-ns")
387
		}
388
	}
389

390
	// Lookup for service via namespace/hostname returns Service and Workload AddressInfo
391
	assert.Equal(t,
392
		len(s.lookup(s.svcXdsName("waypoint-ns"))), 2)
393
	for _, k := range s.lookup(s.svcXdsName("waypoint-ns")) {
394
		switch k.Type.(type) {
395
		case *workloadapi.Address_Workload:
396
			assert.Equal(t, k.Address.GetWorkload().Name, "waypoint-ns-pod")
397
			assert.Equal(t, k.Address.GetWorkload().Waypoint, nil)
398
		case *workloadapi.Address_Service:
399
			assert.Equal(t, k.Address.GetService().Hostname, s.hostnameForService("waypoint-ns"))
400
		}
401
	}
402

403
	// Add another waypoint pod, expect no updates for other pods since waypoint address refers to service VIP
404
	s.addPods(t, "127.0.0.201", "waypoint2-ns-pod", "namespace-wide",
405
		map[string]string{
406
			constants.ManagedGatewayLabel: constants.ManagedGatewayMeshControllerLabel,
407
			constants.GatewayNameLabel:    "namespace-wide",
408
		}, nil, true, corev1.PodRunning)
409
	s.assertEvent(t, s.podXdsName("waypoint2-ns-pod"))
410
	assert.Equal(t,
411
		s.lookup(s.addrXdsName("127.0.0.3"))[0].Address.GetWorkload().Waypoint.GetAddress().Address,
412
		netip.MustParseAddr("10.0.0.2").AsSlice())
413
	// Waypoints do not have waypoints
414
	assert.Equal(t,
415
		s.lookup(s.addrXdsName("127.0.0.200"))[0].Address.GetWorkload().Waypoint,
416
		nil)
417

418
	// make sure looking up the waypoint for a wl by network and address functions correctly
419
	assert.Equal(t, len(s.Waypoint(testNW, "127.0.0.1")), 1)
420
	for _, k := range s.Waypoint(testNW, "127.0.0.1") {
421
		assert.Equal(t, k.AsSlice(), netip.MustParseAddr("10.0.0.2").AsSlice())
422
	}
423

424
	s.addService(t, "svc1",
425
		map[string]string{},
426
		map[string]string{},
427
		[]int32{80}, map[string]string{"app": "a"}, "10.0.0.1")
428
	s.assertAddresses(t, s.addrXdsName("10.0.0.1"), "pod1", "pod2", "pod3", "svc1")
429
	// Send update for the workloads as well...
430
	s.assertEvent(t, s.podXdsName("pod1"),
431
		s.podXdsName("pod2"),
432
		s.podXdsName("pod3"),
433
		s.svcXdsName("svc1"),
434
	)
435
	// Make sure Service sees waypoints as well
436
	assert.Equal(t,
437
		s.lookup(s.addrXdsName("10.0.0.1"))[1].Address.GetWorkload().Waypoint.GetAddress().Address,
438
		netip.MustParseAddr("10.0.0.2").AsSlice())
439

440
	// Delete a waypoint
441
	s.deletePod(t, "waypoint2-ns-pod")
442
	s.assertEvent(t, s.podXdsName("waypoint2-ns-pod"))
443

444
	// Workload should not be updated since service has not changed
445
	assert.Equal(t,
446
		s.lookup(s.addrXdsName("127.0.0.3"))[0].Address.GetWorkload().Waypoint.GetAddress().Address,
447
		netip.MustParseAddr("10.0.0.2").AsSlice())
448

449
	// As should workload via Service
450
	assert.Equal(t,
451
		s.lookup(s.addrXdsName("10.0.0.1"))[1].Address.GetWorkload().Waypoint.GetAddress().Address,
452
		netip.MustParseAddr("10.0.0.2").AsSlice())
453

454
	s.addPods(t, "127.0.0.201", "waypoint2-sa", "waypoint-sa",
455
		map[string]string{constants.ManagedGatewayLabel: constants.ManagedGatewayMeshControllerLabel},
456
		map[string]string{constants.WaypointServiceAccount: "sa2"}, true, corev1.PodRunning)
457
	s.assertEvent(t, s.podXdsName("waypoint2-sa"))
458
	// Unrelated SA should not change anything
459
	assert.Equal(t,
460
		s.lookup(s.addrXdsName("127.0.0.3"))[0].Address.GetWorkload().Waypoint.GetAddress().Address,
461
		netip.MustParseAddr("10.0.0.2").AsSlice())
462

463
	// Adding a new pod should also see the waypoint
464
	s.addPods(t, "127.0.0.6", "pod6", "sa1", map[string]string{"app": "a"}, nil, true, corev1.PodRunning)
465
	s.assertEvent(t, s.podXdsName("pod6"))
466
	assert.Equal(t,
467
		s.lookup(s.addrXdsName("127.0.0.6"))[0].Address.GetWorkload().Waypoint.GetAddress().Address,
468
		netip.MustParseAddr("10.0.0.2").AsSlice())
469

470
	s.deletePod(t, "pod6")
471
	s.assertEvent(t, s.podXdsName("pod6"))
472

473
	s.deletePod(t, "pod3")
474
	s.assertEvent(t, s.podXdsName("pod3"))
475
	s.deletePod(t, "pod2")
476
	s.assertEvent(t, s.podXdsName("pod2"))
477

478
	s.deleteWaypoint(t, "waypoint-ns")
479
	s.assertEvent(t, s.podXdsName("pod1"))
480
	s.deleteService(t, "waypoint-ns")
481
	s.assertEvent(t,
482
		s.podXdsName("waypoint-ns-pod"),
483
		s.svcXdsName("waypoint-ns"))
484

485
	s.deleteWaypoint(t, "waypoint-sa2")
486
	s.assertEvent(t, s.podXdsName("pod4"))
487
	s.deleteService(t, "waypoint-sa2")
488
	s.assertEvent(t,
489
		s.podXdsName("waypoint-sa2-pod"),
490
		s.svcXdsName("waypoint-sa2"))
491
	assert.Equal(t,
492
		s.lookup(s.addrXdsName("10.0.0.1"))[1].Address.GetWorkload().Waypoint,
493
		nil)
494
}
495

496
// TODO(nmittler): Consider splitting this into multiple, smaller tests.
497
func TestAmbientIndex_Policy(t *testing.T) {
498
	s := newAmbientTestServer(t, testC, testNW)
499

500
	s.addPods(t, "127.0.0.1", "pod1", "sa1", map[string]string{"app": "a"}, nil, true, corev1.PodRunning)
501
	s.assertEvent(t, s.podXdsName("pod1"))
502
	s.addPods(t, "127.0.0.200", "waypoint-ns-pod", "namespace-wide",
503
		map[string]string{
504
			constants.ManagedGatewayLabel: constants.ManagedGatewayMeshControllerLabel,
505
			constants.GatewayNameLabel:    "namespace-wide",
506
		}, nil, true, corev1.PodRunning)
507
	s.assertEvent(t, s.podXdsName("waypoint-ns-pod"))
508
	s.addPods(t, "127.0.0.201", "waypoint2-sa", "waypoint-sa",
509
		map[string]string{constants.ManagedGatewayLabel: constants.ManagedGatewayMeshControllerLabel},
510
		map[string]string{constants.WaypointServiceAccount: "sa2"}, true, corev1.PodRunning)
511
	s.assertEvent(t, s.podXdsName("waypoint2-sa"))
512
	s.addWaypoint(t, "10.0.0.2", "waypoint-ns", "", true)
513
	s.ns.Update(&corev1.Namespace{
514
		ObjectMeta: metav1.ObjectMeta{
515
			Name: testNS,
516
			Annotations: map[string]string{
517
				constants.AmbientUseWaypoint: "waypoint-ns",
518
			},
519
		},
520
	})
521
	s.assertEvent(t, s.podXdsName("pod1"))
522
	s.addService(t, "waypoint-ns",
523
		map[string]string{constants.ManagedGatewayLabel: constants.ManagedGatewayMeshControllerLabel},
524
		map[string]string{},
525
		[]int32{80}, map[string]string{constants.GatewayNameLabel: "namespace-wide"}, "10.0.0.2")
526
	s.assertUnorderedEvent(t, s.podXdsName("waypoint-ns-pod"), s.svcXdsName("waypoint-ns"))
527
	s.clearEvents()
528
	selectorPolicyName := "selector"
529

530
	// Test that PeerAuthentications are added to the ambient index
531
	s.addPolicy(t, "global", systemNS, nil, gvk.PeerAuthentication, func(c controllers.Object) {
532
		pol := c.(*clientsecurityv1beta1.PeerAuthentication)
533
		pol.Spec.Mtls = &auth.PeerAuthentication_MutualTLS{
534
			Mode: auth.PeerAuthentication_MutualTLS_PERMISSIVE,
535
		}
536
	})
537
	s.clearEvents()
538

539
	s.addPolicy(t, "namespace", testNS, nil, gvk.PeerAuthentication, func(c controllers.Object) {
540
		pol := c.(*clientsecurityv1beta1.PeerAuthentication)
541
		pol.Spec.Mtls = &auth.PeerAuthentication_MutualTLS{
542
			Mode: auth.PeerAuthentication_MutualTLS_STRICT,
543
		}
544
	})
545
	// Should add the static policy to all pods in the ns1 namespace since the effective mode is STRICT
546
	s.assertEvent(t, s.podXdsName("pod1"), s.podXdsName("waypoint-ns-pod"), s.podXdsName("waypoint2-sa"))
547
	assert.Equal(t,
548
		s.lookup(s.addrXdsName("127.0.0.1"))[0].Address.GetWorkload().AuthorizationPolicies,
549
		[]string{fmt.Sprintf("istio-system/%s", staticStrictPolicyName)})
550
	s.clearEvents()
551

552
	s.addPolicy(t, selectorPolicyName, testNS, map[string]string{"app": "a"}, gvk.PeerAuthentication, func(c controllers.Object) {
553
		pol := c.(*clientsecurityv1beta1.PeerAuthentication)
554
		pol.Spec.Mtls = &auth.PeerAuthentication_MutualTLS{
555
			Mode: auth.PeerAuthentication_MutualTLS_STRICT,
556
		}
557
	})
558
	// Expect no event since the effective policy doesn't change
559
	assert.Equal(t,
560
		s.lookup(s.addrXdsName("127.0.0.1"))[0].Address.GetWorkload().AuthorizationPolicies,
561
		[]string{fmt.Sprintf("istio-system/%s", staticStrictPolicyName)})
562

563
	// Change the workload policy to be permissive
564
	s.addPolicy(t, selectorPolicyName, testNS, map[string]string{"app": "a"}, gvk.PeerAuthentication, func(c controllers.Object) {
565
		pol := c.(*clientsecurityv1beta1.PeerAuthentication)
566
		pol.Spec.Mtls = &auth.PeerAuthentication_MutualTLS{
567
			Mode: auth.PeerAuthentication_MutualTLS_PERMISSIVE,
568
		}
569
	})
570
	s.assertEvent(t, s.podXdsName("pod1")) // Static policy should be removed since it isn't STRICT
571
	assert.Equal(t,
572
		s.lookup(s.addrXdsName("127.0.0.1"))[0].Address.GetWorkload().AuthorizationPolicies,
573
		nil)
574

575
	// Add a port-level STRICT exception to the workload policy
576
	s.addPolicy(t, selectorPolicyName, testNS, map[string]string{"app": "a"}, gvk.PeerAuthentication, func(c controllers.Object) {
577
		pol := c.(*clientsecurityv1beta1.PeerAuthentication)
578
		pol.Spec.Mtls = &auth.PeerAuthentication_MutualTLS{
579
			Mode: auth.PeerAuthentication_MutualTLS_PERMISSIVE,
580
		}
581
		pol.Spec.PortLevelMtls = map[uint32]*auth.PeerAuthentication_MutualTLS{
582
			9090: {
583
				Mode: auth.PeerAuthentication_MutualTLS_STRICT,
584
			},
585
		}
586
	})
587
	s.assertEvent(t, s.podXdsName("pod1")) // Selector policy should be added back since there is now a STRICT exception
588
	time.Sleep(time.Second)
589
	assert.Equal(t,
590
		s.lookup(s.addrXdsName("127.0.0.1"))[0].Address.GetWorkload().AuthorizationPolicies,
591
		[]string{fmt.Sprintf("ns1/%s", model.GetAmbientPolicyConfigName(model.ConfigKey{
592
			Kind:      kind.PeerAuthentication,
593
			Name:      selectorPolicyName,
594
			Namespace: "ns1",
595
		}))})
596

597
	// Pod not in selector policy, but namespace policy should take effect (hence static policy)
598
	s.addPods(t, "127.0.0.2", "pod2", "sa1", map[string]string{"app": "not-a"}, nil, true, corev1.PodRunning)
599
	s.assertEvent(t, s.podXdsName("pod2"))
600
	assert.Equal(t,
601
		s.lookup(s.addrXdsName("127.0.0.2"))[0].Address.GetWorkload().AuthorizationPolicies,
602
		[]string{fmt.Sprintf("istio-system/%s", staticStrictPolicyName)})
603

604
	// Add it to the policy by updating its selector
605
	s.addPods(t, "127.0.0.2", "pod2", "sa1", map[string]string{"app": "a"}, nil, true, corev1.PodRunning)
606
	s.assertEvent(t, s.podXdsName("pod2"))
607
	assert.Equal(t,
608
		s.lookup(s.addrXdsName("127.0.0.2"))[0].Address.GetWorkload().AuthorizationPolicies,
609
		[]string{fmt.Sprintf("ns1/%s", model.GetAmbientPolicyConfigName(model.ConfigKey{
610
			Kind:      kind.PeerAuthentication,
611
			Name:      selectorPolicyName,
612
			Namespace: "ns1",
613
		}))})
614

615
	// Add global selector policy; nothing should happen since PeerAuthentication doesn't support global mesh wide selectors
616
	s.addPolicy(t, "global-selector", systemNS, map[string]string{"app": "a"}, gvk.PeerAuthentication, func(c controllers.Object) {
617
		pol := c.(*clientsecurityv1beta1.PeerAuthentication)
618
		pol.Spec.Mtls = &auth.PeerAuthentication_MutualTLS{
619
			Mode: auth.PeerAuthentication_MutualTLS_STRICT,
620
		}
621
	})
622
	assert.Equal(t,
623
		s.lookup(s.addrXdsName("127.0.0.1"))[0].Address.GetWorkload().AuthorizationPolicies,
624
		[]string{fmt.Sprintf("ns1/%s", model.GetAmbientPolicyConfigName(model.ConfigKey{
625
			Kind:      kind.PeerAuthentication,
626
			Name:      selectorPolicyName,
627
			Namespace: "ns1",
628
		}))})
629

630
	// Delete global selector policy
631
	s.pa.Delete("global-selector", systemNS)
632

633
	// Update workload policy to be PERMISSIVE
634
	s.addPolicy(t, selectorPolicyName, testNS, map[string]string{"app": "a"}, gvk.PeerAuthentication, func(c controllers.Object) {
635
		pol := c.(*clientsecurityv1beta1.PeerAuthentication)
636
		pol.Spec.Mtls = &auth.PeerAuthentication_MutualTLS{
637
			Mode: auth.PeerAuthentication_MutualTLS_PERMISSIVE,
638
		}
639
		pol.Spec.PortLevelMtls = map[uint32]*auth.PeerAuthentication_MutualTLS{
640
			9090: {
641
				Mode: auth.PeerAuthentication_MutualTLS_PERMISSIVE,
642
			},
643
		}
644
	})
645
	// There should be an event since effective policy moves to PERMISSIVE
646
	s.assertEvent(t, s.podXdsName("pod1"), s.podXdsName("pod2"))
647
	assert.Equal(t,
648
		s.lookup(s.addrXdsName("127.0.0.1"))[0].Address.GetWorkload().AuthorizationPolicies,
649
		nil)
650

651
	// Change namespace policy to be PERMISSIVE
652
	s.addPolicy(t, "namespace", testNS, nil, gvk.PeerAuthentication, func(c controllers.Object) {
653
		pol := c.(*clientsecurityv1beta1.PeerAuthentication)
654
		pol.Spec.Mtls = &auth.PeerAuthentication_MutualTLS{
655
			Mode: auth.PeerAuthentication_MutualTLS_PERMISSIVE,
656
		}
657
	})
658

659
	// All pods have an event (since we're only testing one namespace) but still no policies attached
660
	s.assertEvent(t, s.podXdsName("waypoint-ns-pod"), s.podXdsName("waypoint2-sa"))
661
	assert.Equal(t,
662
		s.lookup(s.addrXdsName("127.0.0.1"))[0].Address.GetWorkload().AuthorizationPolicies,
663
		nil)
664

665
	// Change workload policy to be STRICT and remove port-level overrides
666
	s.addPolicy(t, selectorPolicyName, testNS, map[string]string{"app": "a"}, gvk.PeerAuthentication, func(c controllers.Object) {
667
		pol := c.(*clientsecurityv1beta1.PeerAuthentication)
668
		pol.Spec.Mtls = &auth.PeerAuthentication_MutualTLS{
669
			Mode: auth.PeerAuthentication_MutualTLS_STRICT,
670
		}
671
		pol.Spec.PortLevelMtls = nil
672
	})
673

674
	// Selected pods receive an event
675
	s.assertEvent(t, s.podXdsName("pod1"), s.podXdsName("pod2"))
676
	assert.Equal(t,
677
		s.lookup(s.addrXdsName("127.0.0.1"))[0].Address.GetWorkload().AuthorizationPolicies,
678
		[]string{fmt.Sprintf("istio-system/%s", staticStrictPolicyName)}) // Effective mode is STRICT so set policy
679

680
	// Add a permissive port-level override
681
	s.addPolicy(t, selectorPolicyName, testNS, map[string]string{"app": "a"}, gvk.PeerAuthentication, func(c controllers.Object) {
682
		pol := c.(*clientsecurityv1beta1.PeerAuthentication)
683
		pol.Spec.Mtls = &auth.PeerAuthentication_MutualTLS{
684
			Mode: auth.PeerAuthentication_MutualTLS_STRICT,
685
		}
686
		pol.Spec.PortLevelMtls = map[uint32]*auth.PeerAuthentication_MutualTLS{
687
			9090: {
688
				Mode: auth.PeerAuthentication_MutualTLS_PERMISSIVE,
689
			},
690
		}
691
	})
692
	s.assertEvent(t, s.podXdsName("pod1"), s.podXdsName("pod2")) // Matching pods receive an event
693
	assert.Equal(t,
694
		s.lookup(s.addrXdsName("127.0.0.1"))[0].Address.GetWorkload().AuthorizationPolicies,
695
		[]string{fmt.Sprintf("ns1/%s", model.GetAmbientPolicyConfigName(model.ConfigKey{
696
			Kind:      kind.PeerAuthentication,
697
			Name:      selectorPolicyName,
698
			Namespace: "ns1",
699
		}))})
700

701
	// Set workload policy to be UNSET with a STRICT port-level override
702
	s.addPolicy(t, selectorPolicyName, testNS, map[string]string{"app": "a"}, gvk.PeerAuthentication, func(c controllers.Object) {
703
		pol := c.(*clientsecurityv1beta1.PeerAuthentication)
704
		pol.Spec.Mtls = nil // equivalent to UNSET
705
		pol.Spec.PortLevelMtls = map[uint32]*auth.PeerAuthentication_MutualTLS{
706
			9090: {
707
				Mode: auth.PeerAuthentication_MutualTLS_STRICT,
708
			},
709
		}
710
	})
711
	// The policy should still be added since the effective policy is PERMISSIVE
712
	assert.Equal(t,
713
		s.lookup(s.addrXdsName("127.0.0.1"))[0].Address.GetWorkload().AuthorizationPolicies,
714
		[]string{fmt.Sprintf("ns1/%s", model.GetAmbientPolicyConfigName(model.ConfigKey{
715
			Kind:      kind.PeerAuthentication,
716
			Name:      selectorPolicyName,
717
			Namespace: "ns1",
718
		}))})
719

720
	// Change namespace policy back to STRICT
721
	s.addPolicy(t, "namespace", testNS, nil, gvk.PeerAuthentication, func(c controllers.Object) {
722
		pol := c.(*clientsecurityv1beta1.PeerAuthentication)
723
		pol.Spec.Mtls = &auth.PeerAuthentication_MutualTLS{
724
			Mode: auth.PeerAuthentication_MutualTLS_STRICT,
725
		}
726
	})
727
	// All pods have an event (since we're only testing one namespace)
728
	s.assertEvent(t, s.podXdsName("pod1"), s.podXdsName("pod2"), s.podXdsName("waypoint-ns-pod"), s.podXdsName("waypoint2-sa"))
729
	assert.Equal(t,
730
		s.lookup(s.addrXdsName("127.0.0.1"))[0].Address.GetWorkload().AuthorizationPolicies,
731
		[]string{fmt.Sprintf("istio-system/%s", staticStrictPolicyName)}) // Effective mode is STRICT so set static policy
732

733
	// Set workload policy to be UNSET with a PERMISSIVE port-level override
734
	s.addPolicy(t, selectorPolicyName, testNS, map[string]string{"app": "a"}, gvk.PeerAuthentication, func(c controllers.Object) {
735
		pol := c.(*clientsecurityv1beta1.PeerAuthentication)
736
		pol.Spec.Mtls = nil // equivalent to UNSET
737
		pol.Spec.PortLevelMtls = map[uint32]*auth.PeerAuthentication_MutualTLS{
738
			9090: {
739
				Mode: auth.PeerAuthentication_MutualTLS_PERMISSIVE,
740
			},
741
		}
742
	})
743
	s.assertEvent(t, s.podXdsName("pod1"), s.podXdsName("pod2")) // Matching pods receive an event
744
	// The policy should still be added since the effective policy is STRICT
745
	assert.Equal(t,
746
		s.lookup(s.addrXdsName("127.0.0.1"))[0].Address.GetWorkload().AuthorizationPolicies,
747
		[]string{fmt.Sprintf("istio-system/%s", staticStrictPolicyName), fmt.Sprintf("ns1/%s", model.GetAmbientPolicyConfigName(model.ConfigKey{
748
			Kind:      kind.PeerAuthentication,
749
			Name:      selectorPolicyName,
750
			Namespace: "ns1",
751
		}))})
752

753
	// Clear PeerAuthentication from workload
754
	s.pa.Delete("selector", testNS)
755
	s.assertEvent(t, s.podXdsName("pod1"), s.podXdsName("pod2"))
756
	// Effective policy is still STRICT so the static policy should still be set
757
	assert.Equal(t,
758
		s.lookup(s.addrXdsName("127.0.0.1"))[0].Address.GetWorkload().AuthorizationPolicies,
759
		[]string{fmt.Sprintf("istio-system/%s", staticStrictPolicyName)})
760

761
	// Now remove the namespace and global policies along with the pods
762
	s.pa.Delete("namespace", testNS)
763
	s.pa.Delete("global", systemNS)
764
	s.deletePod(t, "pod2")
765
	s.assertEvent(t, s.podXdsName("pod2"), s.podXdsName("pod1"))
766
	s.clearEvents()
767

768
	// Test AuthorizationPolicies
769
	s.addPolicy(t, "global", systemNS, nil, gvk.AuthorizationPolicy, nil)
770
	s.addPolicy(t, "namespace", testNS, nil, gvk.AuthorizationPolicy, nil)
771
	assert.Equal(t,
772
		s.lookup(s.addrXdsName("127.0.0.1"))[0].Address.GetWorkload().AuthorizationPolicies,
773
		nil)
774

775
	s.addPolicy(t, selectorPolicyName, testNS, map[string]string{"app": "a"}, gvk.AuthorizationPolicy, nil)
776
	s.assertEvent(t, s.podXdsName("pod1"))
777
	assert.Equal(t,
778
		s.lookup(s.addrXdsName("127.0.0.1"))[0].Address.GetWorkload().AuthorizationPolicies,
779
		[]string{"ns1/selector"})
780

781
	// Pod not in policy
782
	s.addPods(t, "127.0.0.2", "pod3", "sa1", map[string]string{"app": "not-a"}, nil, true, corev1.PodRunning)
783
	s.assertEvent(t, s.podXdsName("pod3"))
784
	assert.Equal(t,
785
		s.lookup(s.addrXdsName("127.0.0.2"))[0].Address.GetWorkload().AuthorizationPolicies,
786
		nil)
787

788
	// Add it to the policy by updating its selector
789
	s.addPods(t, "127.0.0.2", "pod3", "sa1", map[string]string{"app": "a"}, nil, true, corev1.PodRunning)
790
	s.assertEvent(t, s.podXdsName("pod3"))
791
	assert.Equal(t,
792
		s.lookup(s.addrXdsName("127.0.0.2"))[0].Address.GetWorkload().AuthorizationPolicies,
793
		[]string{"ns1/selector"})
794

795
	s.addPolicy(t, "global-selector", systemNS, map[string]string{"app": "a"}, gvk.AuthorizationPolicy, nil)
796
	s.assertEvent(t, s.podXdsName("pod1"), s.podXdsName("pod3"))
797

798
	assert.Equal(t,
799
		s.lookup(s.addrXdsName("127.0.0.1"))[0].Address.GetWorkload().AuthorizationPolicies,
800
		[]string{"istio-system/global-selector", "ns1/selector"})
801

802
	// Update selector to not select
803
	s.addPolicy(t, "global-selector", systemNS, map[string]string{"app": "not-a"}, gvk.AuthorizationPolicy, nil)
804
	s.assertEvent(t, s.podXdsName("pod1"), s.podXdsName("pod3"))
805

806
	assert.Equal(t,
807
		s.lookup(s.addrXdsName("127.0.0.1"))[0].Address.GetWorkload().AuthorizationPolicies,
808
		[]string{"ns1/selector"})
809

810
	// Add STRICT global PeerAuthentication
811
	s.addPolicy(t, "strict", systemNS, nil, gvk.PeerAuthentication, func(c controllers.Object) {
812
		pol := c.(*clientsecurityv1beta1.PeerAuthentication)
813
		pol.Spec.Mtls = &auth.PeerAuthentication_MutualTLS{
814
			Mode: auth.PeerAuthentication_MutualTLS_STRICT,
815
		}
816
	})
817
	// Every workload should receive an event
818
	s.assertEvent(t, s.podXdsName("pod1"), s.podXdsName("pod3"), s.podXdsName("waypoint-ns-pod"), s.podXdsName("waypoint2-sa"))
819
	// Static STRICT policy should be sent
820
	assert.Equal(t,
821
		s.lookup(s.addrXdsName("127.0.0.1"))[0].Address.GetWorkload().AuthorizationPolicies,
822
		[]string{"ns1/selector", fmt.Sprintf("istio-system/%s", staticStrictPolicyName)})
823

824
	// Now add a STRICT workload PeerAuthentication
825
	s.addPolicy(t, "selector-strict", testNS, map[string]string{"app": "a"}, gvk.PeerAuthentication, func(c controllers.Object) {
826
		pol := c.(*clientsecurityv1beta1.PeerAuthentication)
827
		pol.Spec.Mtls = &auth.PeerAuthentication_MutualTLS{
828
			Mode: auth.PeerAuthentication_MutualTLS_STRICT,
829
		}
830
	})
831
	// Effective policy is still STRICT so only static policy should be referenced
832
	assert.Equal(t,
833
		s.lookup(s.addrXdsName("127.0.0.1"))[0].Address.GetWorkload().AuthorizationPolicies,
834
		[]string{"ns1/selector", fmt.Sprintf("istio-system/%s", staticStrictPolicyName)})
835

836
	// Change the workload policy to PERMISSIVE
837
	s.addPolicy(t, "selector-strict", testNS, map[string]string{"app": "a"}, gvk.PeerAuthentication, func(c controllers.Object) {
838
		pol := c.(*clientsecurityv1beta1.PeerAuthentication)
839
		pol.Spec.Mtls = &auth.PeerAuthentication_MutualTLS{
840
			Mode: auth.PeerAuthentication_MutualTLS_PERMISSIVE,
841
		}
842
	})
843
	s.assertEvent(t, s.podXdsName("pod1"), s.podXdsName("pod3")) // Matching workloads should receive an event
844
	// Static STRICT policy should disappear
845
	assert.Equal(t,
846
		s.lookup(s.addrXdsName("127.0.0.1"))[0].Address.GetWorkload().AuthorizationPolicies,
847
		[]string{"ns1/selector"})
848

849
	// Change the workload policy to DISABLE
850
	s.addPolicy(t, "selector-strict", testNS, map[string]string{"app": "a"}, gvk.PeerAuthentication, func(c controllers.Object) {
851
		pol := c.(*clientsecurityv1beta1.PeerAuthentication)
852
		pol.Spec.Mtls = &auth.PeerAuthentication_MutualTLS{
853
			Mode: auth.PeerAuthentication_MutualTLS_DISABLE,
854
		}
855
	})
856

857
	// No event because there's effectively no change
858

859
	// Static STRICT policy should disappear
860
	assert.Equal(t,
861
		s.lookup(s.addrXdsName("127.0.0.1"))[0].Address.GetWorkload().AuthorizationPolicies,
862
		[]string{"ns1/selector"})
863

864
	// Now make the workload policy STRICT but have a PERMISSIVE port-level override
865
	s.addPolicy(t, "selector-strict", testNS, map[string]string{"app": "a"}, gvk.PeerAuthentication, func(c controllers.Object) {
866
		pol := c.(*clientsecurityv1beta1.PeerAuthentication)
867
		pol.Spec.Mtls = &auth.PeerAuthentication_MutualTLS{
868
			Mode: auth.PeerAuthentication_MutualTLS_STRICT,
869
		}
870
		pol.Spec.PortLevelMtls = map[uint32]*auth.PeerAuthentication_MutualTLS{
871
			9090: {
872
				Mode: auth.PeerAuthentication_MutualTLS_PERMISSIVE,
873
			},
874
		}
875
	})
876
	s.assertEvent(t, s.podXdsName("pod1"), s.podXdsName("pod3")) // Matching workloads should receive an event
877
	// Workload policy should be added since there's a port level exclusion
878
	assert.Equal(t,
879
		s.lookup(s.addrXdsName("127.0.0.1"))[0].Address.GetWorkload().AuthorizationPolicies,
880
		[]string{"ns1/selector", fmt.Sprintf("ns1/%s", model.GetAmbientPolicyConfigName(model.ConfigKey{
881
			Kind:      kind.PeerAuthentication,
882
			Name:      "selector-strict",
883
			Namespace: "ns1",
884
		}))})
885

886
	// Now add a rule allowing a specific source principal to the workload AuthorizationPolicy
887
	s.addPolicy(t, selectorPolicyName, testNS, map[string]string{"app": "a"}, gvk.AuthorizationPolicy, func(c controllers.Object) {
888
		pol := c.(*clientsecurityv1beta1.AuthorizationPolicy)
889
		pol.Spec.Rules = []*auth.Rule{
890
			{
891
				From: []*auth.Rule_From{{Source: &auth.Source{Principals: []string{"cluster.local/ns/ns1/sa/sa1"}}}},
892
			},
893
		}
894
	})
895
	// No event since workload policy should still be there (both workloads' policy references remain the same).
896
	// Since PeerAuthentications are translated into DENY policies we can safely apply them
897
	// alongside ALLOW authorization policies
898
	assert.Equal(t,
899
		s.lookup(s.addrXdsName("127.0.0.1"))[0].Address.GetWorkload().AuthorizationPolicies,
900
		[]string{"ns1/selector", fmt.Sprintf("ns1/%s", model.GetAmbientPolicyConfigName(model.ConfigKey{
901
			Kind:      kind.PeerAuthentication,
902
			Name:      "selector-strict",
903
			Namespace: "ns1",
904
		}))})
905

906
	s.authz.Delete("selector", testNS)
907
	s.assertEvent(t, s.podXdsName("pod1"), s.podXdsName("pod3"))
908
	assert.Equal(t,
909
		s.lookup(s.addrXdsName("127.0.0.1"))[0].Address.GetWorkload().AuthorizationPolicies,
910
		[]string{fmt.Sprintf("ns1/%s", model.GetAmbientPolicyConfigName(model.ConfigKey{
911
			Kind:      kind.PeerAuthentication,
912
			Name:      "selector-strict",
913
			Namespace: "ns1",
914
		}))})
915

916
	// Delete selector policy
917
	s.pa.Delete("selector-strict", testNS)
918
	s.assertEvent(t, s.podXdsName("pod1"), s.podXdsName("pod3")) // Matching workloads should receive an event
919
	// Static STRICT policy should now be sent because of the global policy
920
	assert.Equal(t,
921
		s.lookup(s.addrXdsName("127.0.0.1"))[0].Address.GetWorkload().AuthorizationPolicies,
922
		[]string{fmt.Sprintf("istio-system/%s", staticStrictPolicyName)})
923

924
	// Delete global policy
925
	s.pa.Delete("strict", systemNS)
926
	// Every workload should receive an event
927
	s.assertEvent(t, s.podXdsName("pod1"), s.podXdsName("pod3"), s.podXdsName("waypoint-ns-pod"), s.podXdsName("waypoint2-sa"))
928
	// Now no policies are in effect
929
	assert.Equal(t,
930
		s.lookup(s.addrXdsName("127.0.0.1"))[0].Address.GetWorkload().AuthorizationPolicies,
931
		nil)
932

933
	s.clearEvents()
934
	s.addPolicy(t, "gateway-targeted", testNS, nil, gvk.AuthorizationPolicy, func(o controllers.Object) {
935
		p := o.(*clientsecurityv1beta1.AuthorizationPolicy)
936
		p.Spec.TargetRef = &v1beta1.PolicyTargetReference{
937
			Group: gvk.KubernetesGateway.Group,
938
			Kind:  gvk.KubernetesGateway.Kind,
939
			Name:  "dummy-waypoint",
940
		}
941
	})
942
	// there should be no event for creation of a gateway-targeted policy because we should not configure WDS with a policy
943
	// when expressed user intent is specifically to have that policy enforced by a gateway
944
	s.assertNoEvent(t)
945
}
946

947
func TestPodLifecycleWorkloadGates(t *testing.T) {
948
	s := newAmbientTestServer(t, "", "")
949

950
	s.addPods(t, "127.0.0.1", "pod1", "sa1", map[string]string{"app": "a"}, nil, true, corev1.PodRunning)
951
	s.assertEvent(t, "//Pod/ns1/pod1")
952
	s.assertWorkloads(t, "", workloadapi.WorkloadStatus_HEALTHY, "pod1")
953

954
	s.addPods(t, "127.0.0.2", "pod2", "sa1", map[string]string{"app": "a", "other": "label"}, nil, false, corev1.PodRunning)
955
	s.addPods(t, "127.0.0.3", "pod3", "sa1", map[string]string{"app": "other"}, nil, false, corev1.PodPending)
956
	s.addPods(t, "", "pod4", "sa1", map[string]string{"app": "another"}, nil, false, corev1.PodPending)
957
	s.assertEvent(t, "//Pod/ns1/pod2")
958
	// Still healthy
959
	s.assertWorkloads(t, "", workloadapi.WorkloadStatus_HEALTHY, "pod1")
960
	// Unhealthy
961
	s.assertWorkloads(t, "", workloadapi.WorkloadStatus_UNHEALTHY, "pod2", "pod3")
962
	// pod3 is pending but have be assigned IP
963
	// pod4 is pending and not have IP
964
}
965

966
func TestAddressInformation(t *testing.T) {
967
	s := newAmbientTestServer(t, testC, testNW)
968

969
	// Add 2 pods with the "a" label, and one without.
970
	// We should get an event for the new Service and the two *Pod* IPs impacted
971
	s.addPods(t, "127.0.0.1", "pod1", "sa1", map[string]string{"app": "a"}, nil, true, corev1.PodRunning)
972
	s.assertEvent(t, s.podXdsName("pod1"))
973
	s.addPods(t, "127.0.0.2", "pod2", "sa1", map[string]string{"app": "a", "other": "label"}, nil, true, corev1.PodRunning)
974
	s.assertEvent(t, s.podXdsName("pod2"))
975
	s.addPods(t, "127.0.0.3", "pod3", "sa1", map[string]string{"app": "other"}, nil, true, corev1.PodRunning)
976
	s.assertEvent(t, s.podXdsName("pod3"))
977
	s.clearEvents()
978

979
	// Now add a service that will select pods with label "a".
980
	s.addService(t, "svc1",
981
		map[string]string{},
982
		map[string]string{},
983
		[]int32{80}, map[string]string{"app": "a"}, "10.0.0.1")
984
	s.assertEvent(t, s.podXdsName("pod1"), s.podXdsName("pod2"), s.svcXdsName("svc1"))
985

986
	addrs, _ := s.AddressInformation(sets.New[string](s.svcXdsName("svc1"), s.podXdsName("pod2")))
987
	got := sets.New[string]()
988
	for _, addr := range addrs {
989
		if got.Contains(addr.ResourceName()) {
990
			t.Fatalf("got duplicate address %v", addr.ResourceName())
991
		}
992
		got.Insert(addr.ResourceName())
993
	}
994
}
995

996
func TestRBACConvert(t *testing.T) {
997
	files := file.ReadDirOrFail(t, "testdata")
998
	if len(files) == 0 {
999
		// Just in case
1000
		t.Fatal("expected test cases")
1001
	}
1002
	for _, f := range files {
1003
		name := filepath.Base(f)
1004
		if !strings.Contains(name, "-in.yaml") {
1005
			continue
1006
		}
1007
		t.Run(name, func(t *testing.T) {
1008
			pol, _, err := crd.ParseInputs(file.AsStringOrFail(t, f))
1009
			assert.NoError(t, err)
1010
			var o *security.Authorization
1011
			switch pol[0].GroupVersionKind {
1012
			case gvk.AuthorizationPolicy:
1013
				o = convertAuthorizationPolicy(systemNS, &clientsecurityv1beta1.AuthorizationPolicy{
1014
					TypeMeta: metav1.TypeMeta{},
1015
					ObjectMeta: metav1.ObjectMeta{
1016
						Name:      pol[0].Name,
1017
						Namespace: pol[0].Namespace,
1018
					},
1019
					Spec: *((pol[0].Spec).(*auth.AuthorizationPolicy)), //nolint: govet
1020
				})
1021
			case gvk.PeerAuthentication:
1022
				o = convertPeerAuthentication(systemNS, &clientsecurityv1beta1.PeerAuthentication{
1023
					TypeMeta: metav1.TypeMeta{},
1024
					ObjectMeta: metav1.ObjectMeta{
1025
						Name:      pol[0].Name,
1026
						Namespace: pol[0].Namespace,
1027
					},
1028
					Spec: *((pol[0].Spec).(*auth.PeerAuthentication)), //nolint: govet
1029
				})
1030
			default:
1031
				t.Fatalf("unknown kind %v", pol[0].GroupVersionKind)
1032
			}
1033
			msg := ""
1034
			if o != nil {
1035
				msg, err = protomarshal.ToYAML(o)
1036
				assert.NoError(t, err)
1037
			}
1038
			golden := filepath.Join("testdata", strings.ReplaceAll(name, "-in", ""))
1039
			util.CompareContent(t, []byte(msg), golden)
1040
		})
1041
	}
1042
}
1043

1044
func TestEmptyVIPsExcluded(t *testing.T) {
1045
	testSVC := corev1.Service{
1046
		Spec: corev1.ServiceSpec{
1047
			ClusterIP: "",
1048
		},
1049
		Status: corev1.ServiceStatus{
1050
			LoadBalancer: corev1.LoadBalancerStatus{
1051
				Ingress: []corev1.LoadBalancerIngress{
1052
					{
1053
						IP: "",
1054
					},
1055
				},
1056
			},
1057
		},
1058
	}
1059
	vips := getVIPs(&testSVC)
1060
	assert.Equal(t, 0, len(vips), "optional IP fields should be ignored if empty")
1061
}
1062

1063
// assertWaypointAddressForPod takes a pod name for key and the expected waypoint IP Address
1064
// if the IP is empty we assume you're asserting that the pod's waypoint address is nil
1065
// will assert that the GW address for the pod's waypoint is the expected address
1066
// nolint: unparam
1067
func (s *ambientTestServer) assertWaypointAddressForPod(t *testing.T, key, expectedIP string) {
1068
	t.Helper()
1069
	var expectedAddress *workloadapi.GatewayAddress
1070
	if expectedIP != "" { // "" is assumed to mean a nil address
1071
		expectedAddress = &workloadapi.GatewayAddress{
1072
			Destination: &workloadapi.GatewayAddress_Address{
1073
				Address: &workloadapi.NetworkAddress{
1074
					Address: netip.MustParseAddr(expectedIP).AsSlice(),
1075
				},
1076
			},
1077
			HboneMtlsPort: 15008,
1078
		}
1079
	}
1080
	workloads := s.lookup(s.podXdsName(key))
1081
	if len(workloads) < 1 {
1082
		t.Log("no workloads provided, assertion must fail")
1083
		t.Fail()
1084
	}
1085
	for _, workload := range workloads {
1086
		assert.Equal(t, expectedAddress.String(), workload.GetWorkload().GetWaypoint().String())
1087
	}
1088
}
1089

1090
func TestUpdateWaypointForWorkload(t *testing.T) {
1091
	s := newAmbientTestServer(t, "", "")
1092

1093
	// add our waypoints but they won't be used until annotations are added
1094
	// add a new waypoint
1095
	s.addWaypoint(t, "10.0.0.2", "waypoint-sa1", "sa1", true)
1096
	// Add a namespace waypoint to the pod
1097
	s.addWaypoint(t, "10.0.0.1", "waypoint-ns", "", true)
1098

1099
	s.addPods(t, "127.0.0.1", "pod1", "sa1", map[string]string{"app": "a"}, nil, true, corev1.PodRunning)
1100
	s.assertAddresses(t, "", "pod1")
1101
	s.assertEvent(t, s.podXdsName("pod1"))
1102
	// assert that no waypoint is being used
1103
	s.assertWaypointAddressForPod(t, "pod1", "")
1104

1105
	// let use a waypoint by namespace annotation
1106
	s.ns.Update(&corev1.Namespace{
1107
		ObjectMeta: metav1.ObjectMeta{
1108
			Name: testNS,
1109
			Annotations: map[string]string{
1110
				constants.AmbientUseWaypoint: "waypoint-ns",
1111
			},
1112
		},
1113
	})
1114
	s.assertEvent(t, s.podXdsName("pod1"))
1115
	s.assertWaypointAddressForPod(t, "pod1", "10.0.0.1")
1116

1117
	// annotate pod1 to use a different waypoint than the namespace specifies
1118
	s.annotatePod(t, "pod1", testNS, map[string]string{constants.AmbientUseWaypoint: "waypoint-sa1"})
1119
	s.assertEvent(t, s.podXdsName("pod1"))
1120
	// assert that we're using the correct waypoint for pod1
1121
	s.assertWaypointAddressForPod(t, "pod1", "10.0.0.2")
1122

1123
	// remove the use-waypoint annotation from pod1
1124
	s.annotatePod(t, "pod1", testNS, map[string]string{})
1125
	s.assertEvent(t, s.podXdsName("pod1"))
1126
	// assert that pod1 is using the waypoint specified on the namespace
1127
	s.assertWaypointAddressForPod(t, "pod1", "10.0.0.1")
1128

1129
	// unannotate the namespace too
1130
	s.ns.Update(&corev1.Namespace{
1131
		ObjectMeta: metav1.ObjectMeta{
1132
			Name:        testNS,
1133
			Annotations: map[string]string{},
1134
		},
1135
	})
1136
	s.assertEvent(t, s.podXdsName("pod1"))
1137
	// assert that we're once again using no waypoint
1138
	s.assertWaypointAddressForPod(t, "pod1", "")
1139

1140
	// annotate pod2 to use a waypoint
1141
	s.annotatePod(t, "pod1", testNS, map[string]string{constants.AmbientUseWaypoint: "waypoint-sa1"})
1142
	s.assertEvent(t, s.podXdsName("pod1"))
1143
	// assert that the correct waypoint was configured
1144
	s.assertWaypointAddressForPod(t, "pod1", "10.0.0.2")
1145

1146
	// add a namespace annotation to use the namespace-scope waypoint
1147
	s.ns.Update(&corev1.Namespace{
1148
		ObjectMeta: metav1.ObjectMeta{
1149
			Name: testNS,
1150
			Annotations: map[string]string{
1151
				constants.AmbientUseWaypoint: "waypoint-ns",
1152
			},
1153
		},
1154
	})
1155
	// pod2 should not experience any xds event
1156
	s.assertNoEvent(t)
1157
	// assert that pod2 is still using the waypoint specified in it's annotation
1158
	s.assertWaypointAddressForPod(t, "pod1", "10.0.0.2")
1159

1160
	// assert local waypoint opt-out works as expected
1161
	s.annotatePod(t, "pod1", testNS, map[string]string{constants.AmbientUseWaypoint: "#none"})
1162
	s.assertEvent(t, s.podXdsName("pod1"))
1163
	// assert that we're using no waypoint
1164
	s.assertWaypointAddressForPod(t, "pod1", "")
1165
	// check that the other opt out also works
1166
	s.annotatePod(t, "pod1", testNS, map[string]string{constants.AmbientUseWaypoint: "~"})
1167
	s.assertNoEvent(t)
1168
	s.assertWaypointAddressForPod(t, "pod1", "")
1169
}
1170

1171
func TestWorkloadsForWaypoint(t *testing.T) {
1172
	s := newAmbientTestServer(t, "", testNW)
1173

1174
	assertWaypoint := func(t *testing.T, waypointNetwork string, waypointAddress string, expected ...string) {
1175
		t.Helper()
1176
		wl := sets.New(slices.Map(s.WorkloadsForWaypoint(model.WaypointKey{
1177
			Network:   waypointNetwork,
1178
			Addresses: []string{waypointAddress},
1179
		}), func(e model.WorkloadInfo) string {
1180
			return e.ResourceName()
1181
		})...)
1182
		assert.Equal(t, wl, sets.New(expected...))
1183
	}
1184
	// Add a namespace waypoint to the pod
1185
	s.addWaypoint(t, "10.0.0.1", "waypoint-ns", "", true)
1186
	s.addWaypoint(t, "10.0.0.2", "waypoint-sa1", "sa1", true)
1187

1188
	s.addPods(t, "127.0.0.1", "pod1", "sa1", map[string]string{"app": "a"}, nil, true, corev1.PodRunning)
1189
	s.assertEvent(t, s.podXdsName("pod1"))
1190
	s.addPods(t, "127.0.0.2", "pod2", "sa2", map[string]string{"app": "a"}, nil, true, corev1.PodRunning)
1191
	s.assertEvent(t, s.podXdsName("pod2"))
1192

1193
	s.ns.Update(&corev1.Namespace{
1194
		ObjectMeta: metav1.ObjectMeta{
1195
			Name: testNS,
1196
			Annotations: map[string]string{
1197
				constants.AmbientUseWaypoint: "waypoint-ns",
1198
			},
1199
		},
1200
	})
1201

1202
	s.assertEvent(t, s.podXdsName("pod1"), s.podXdsName("pod2"))
1203
	assertWaypoint(t, testNW, "10.0.0.1", s.podXdsName("pod1"), s.podXdsName("pod2"))
1204
	// TODO: should this be returned? Or should it be filtered because such a waypoint does not exist
1205

1206
	// Add a service account waypoint to the pod
1207
	s.annotatePod(t, "pod1", testNS, map[string]string{constants.AmbientUseWaypoint: "waypoint-sa1"})
1208
	s.assertEvent(t, s.podXdsName("pod1"))
1209

1210
	assertWaypoint(t, testNW, "10.0.0.2", s.podXdsName("pod1"))
1211
	assertWaypoint(t, testNW, "10.0.0.1", s.podXdsName("pod2"))
1212

1213
	// Revert back
1214
	s.annotatePod(t, "pod1", testNS, map[string]string{})
1215
	s.assertEvent(t, s.podXdsName("pod1"))
1216

1217
	assertWaypoint(t, testNW, "10.0.0.1", s.podXdsName("pod1"), s.podXdsName("pod2"))
1218
}
1219

1220
func TestWorkloadsForWaypointOrder(t *testing.T) {
1221
	test.SetForTest(t, &features.EnableAmbientControllers, true)
1222
	s := newAmbientTestServer(t, "", testNW)
1223

1224
	assertOrderedWaypoint := func(t *testing.T, network, address string, expected ...string) {
1225
		t.Helper()
1226
		wls := s.WorkloadsForWaypoint(model.WaypointKey{
1227
			Network:   network,
1228
			Addresses: []string{address},
1229
		})
1230
		wl := make([]string, len(wls))
1231
		for i, e := range wls {
1232
			wl[i] = e.ResourceName()
1233
		}
1234
		assert.Equal(t, wl, expected)
1235
	}
1236
	s.addWaypoint(t, "10.0.0.1", "waypoint", "", true)
1237

1238
	// expected order is pod3, pod1, pod2, which is the order of creation
1239
	s.addPods(t,
1240
		"127.0.0.3",
1241
		"pod3",
1242
		"sa3",
1243
		map[string]string{"app": "a"},
1244
		map[string]string{constants.AmbientUseWaypoint: "waypoint"},
1245
		true,
1246
		corev1.PodRunning)
1247
	s.assertEvent(t, s.podXdsName("pod3"))
1248
	s.addPods(t,
1249
		"127.0.0.1",
1250
		"pod1",
1251
		"sa1",
1252
		map[string]string{"app": "a"},
1253
		map[string]string{constants.AmbientUseWaypoint: "waypoint"},
1254
		true,
1255
		corev1.PodRunning)
1256
	s.assertEvent(t, s.podXdsName("pod1"))
1257
	s.addPods(t,
1258
		"127.0.0.2",
1259
		"pod2",
1260
		"sa2",
1261
		map[string]string{"app": "a"},
1262
		map[string]string{constants.AmbientUseWaypoint: "waypoint"},
1263
		true,
1264
		corev1.PodRunning)
1265
	s.assertEvent(t, s.podXdsName("pod2"))
1266
	assertOrderedWaypoint(t, testNW, "10.0.0.1",
1267
		s.podXdsName("pod3"), s.podXdsName("pod1"), s.podXdsName("pod2"))
1268
}
1269

1270
// This is a regression test for a case where policies added after pods were not applied when
1271
// querying by service
1272
func TestPolicyAfterPod(t *testing.T) {
1273
	s := newAmbientTestServer(t, testC, testNW)
1274

1275
	s.addService(t, "svc1",
1276
		map[string]string{},
1277
		map[string]string{},
1278
		[]int32{80}, map[string]string{"app": "a"}, "10.0.0.1")
1279
	s.assertEvent(t, s.svcXdsName("svc1"))
1280
	s.addPods(t, "127.0.0.1", "pod1", "sa1", map[string]string{"app": "a"}, nil, true, corev1.PodRunning)
1281
	s.assertEvent(t, s.podXdsName("pod1"))
1282
	s.addPolicy(t, "selector", testNS, map[string]string{"app": "a"}, gvk.AuthorizationPolicy, nil)
1283
	s.assertEvent(t, s.podXdsName("pod1"))
1284
	assert.Equal(t, s.lookup(s.svcXdsName("svc1"))[1].GetWorkload().GetAuthorizationPolicies(), []string{"ns1/selector"})
1285
}
1286

1287
type ambientTestServer struct {
1288
	*index
1289
	clusterID cluster.ID
1290
	network   network.ID
1291
	fx        *xdsfake.Updater
1292
	pc        clienttest.TestClient[*corev1.Pod]
1293
	sc        clienttest.TestWriter[*corev1.Service]
1294
	ns        clienttest.TestWriter[*corev1.Namespace]
1295
	grc       clienttest.TestWriter[*k8sbeta.Gateway]
1296
	se        clienttest.TestWriter[*apiv1alpha3.ServiceEntry]
1297
	we        clienttest.TestWriter[*apiv1alpha3.WorkloadEntry]
1298
	pa        clienttest.TestWriter[*clientsecurityv1beta1.PeerAuthentication]
1299
	authz     clienttest.TestWriter[*clientsecurityv1beta1.AuthorizationPolicy]
1300
	t         *testing.T
1301
}
1302

1303
func newAmbientTestServer(t *testing.T, clusterID cluster.ID, networkID network.ID) *ambientTestServer {
1304
	up := xdsfake.NewFakeXDS()
1305
	up.SplitEvents = true
1306
	cl := kubeclient.NewFakeClient()
1307
	for _, crd := range []schema.GroupVersionResource{
1308
		gvr.AuthorizationPolicy,
1309
		gvr.PeerAuthentication,
1310
		gvr.KubernetesGateway,
1311
		gvr.WorkloadEntry,
1312
		gvr.ServiceEntry,
1313
	} {
1314
		clienttest.MakeCRD(t, cl, crd)
1315
	}
1316
	idx := New(Options{
1317
		Client:          cl,
1318
		SystemNamespace: systemNS,
1319
		DomainSuffix:    "company.com",
1320
		ClusterID:       clusterID,
1321
		XDSUpdater:      up,
1322
		LookupNetwork: func(endpointIP string, labels labels.Instance) network.ID {
1323
			return networkID
1324
		},
1325
	})
1326
	cl.RunAndWait(test.NewStop(t))
1327

1328
	t.Cleanup(func() {
1329
		if t.Failed() {
1330
			idx := idx.(*index)
1331
			krt.Dump(idx.authorizationPolicies)
1332
			krt.Dump(idx.workloads.Collection)
1333
			krt.Dump(idx.services.Collection)
1334
			krt.Dump(idx.waypoints.Collection)
1335
		}
1336
	})
1337
	a := &ambientTestServer{
1338
		t:         t,
1339
		clusterID: clusterID,
1340
		network:   networkID,
1341
		index:     idx.(*index),
1342
		fx:        up,
1343
		pc:        clienttest.NewDirectClient[*corev1.Pod, corev1.Pod, *corev1.PodList](t, cl),
1344
		sc:        clienttest.NewWriter[*corev1.Service](t, cl),
1345
		ns:        clienttest.NewWriter[*corev1.Namespace](t, cl),
1346
		grc:       clienttest.NewWriter[*k8sbeta.Gateway](t, cl),
1347
		se:        clienttest.NewWriter[*apiv1alpha3.ServiceEntry](t, cl),
1348
		we:        clienttest.NewWriter[*apiv1alpha3.WorkloadEntry](t, cl),
1349
		pa:        clienttest.NewWriter[*clientsecurityv1beta1.PeerAuthentication](t, cl),
1350
		authz:     clienttest.NewWriter[*clientsecurityv1beta1.AuthorizationPolicy](t, cl),
1351
	}
1352

1353
	// ns is more important now that we want to be able to annotate ns for svc, wl waypoint selection
1354
	// always create the testNS enabled for ambient
1355
	a.ns.Create(&corev1.Namespace{
1356
		ObjectMeta: metav1.ObjectMeta{
1357
			Name:   testNS,
1358
			Labels: map[string]string{"istio.io/dataplane-mode": "ambient"},
1359
		},
1360
	})
1361

1362
	return a
1363
}
1364

1365
func (s *ambientTestServer) addWaypoint(t *testing.T, ip, name, sa string, ready bool) {
1366
	t.Helper()
1367

1368
	fromSame := k8sv1.NamespacesFromSame
1369
	gatewaySpec := k8sbeta.GatewaySpec{
1370
		GatewayClassName: constants.WaypointGatewayClassName,
1371
		Listeners: []k8sbeta.Listener{
1372
			{
1373
				Name:     "mesh",
1374
				Port:     15008,
1375
				Protocol: "HBONE",
1376
				AllowedRoutes: &k8sbeta.AllowedRoutes{
1377
					Namespaces: &k8sbeta.RouteNamespaces{
1378
						From: &fromSame,
1379
					},
1380
				},
1381
			},
1382
		},
1383
	}
1384

1385
	gateway := k8sbeta.Gateway{
1386
		TypeMeta: metav1.TypeMeta{
1387
			Kind:       gvk.KubernetesGateway.Kind,
1388
			APIVersion: gvk.KubernetesGateway.GroupVersion(),
1389
		},
1390
		ObjectMeta: metav1.ObjectMeta{
1391
			Name:      name,
1392
			Namespace: testNS,
1393
		},
1394
		Spec:   gatewaySpec,
1395
		Status: k8sbeta.GatewayStatus{},
1396
	}
1397
	if sa != "" {
1398
		annotations := make(map[string]string, 1)
1399
		annotations[constants.WaypointServiceAccount] = sa
1400
		gateway.Annotations = annotations
1401
	}
1402
	if ready {
1403
		addrType := k8sbeta.IPAddressType
1404
		gateway.Status = k8sbeta.GatewayStatus{
1405
			// addresses:
1406
			// - type: IPAddress
1407
			//   value: 10.96.59.188
1408
			Addresses: []k8sv1.GatewayStatusAddress{
1409
				{
1410
					Type:  &addrType,
1411
					Value: ip,
1412
				},
1413
			},
1414
		}
1415
	}
1416
	s.grc.CreateOrUpdate(&gateway)
1417
}
1418

1419
func (s *ambientTestServer) deleteWaypoint(t *testing.T, name string) {
1420
	t.Helper()
1421
	s.grc.Delete(name, testNS)
1422
}
1423

1424
func (s *ambientTestServer) addPods(t *testing.T, ip string, name, sa string, labels map[string]string,
1425
	annotations map[string]string, markReady bool, phase corev1.PodPhase,
1426
) {
1427
	t.Helper()
1428
	pod := generatePod(ip, name, testNS, sa, "node1", labels, annotations)
1429

1430
	p := s.pc.Get(name, pod.Namespace)
1431
	if p == nil {
1432
		// Apiserver doesn't allow Create to modify the pod status; in real world it's a 2 part process
1433
		pod.Status = corev1.PodStatus{}
1434
		newPod := s.pc.Create(pod)
1435
		if markReady {
1436
			setPodReady(newPod)
1437
		}
1438
		newPod.Status.PodIP = ip
1439
		newPod.Status.Phase = phase
1440
		newPod.Status.PodIPs = []corev1.PodIP{
1441
			{
1442
				IP: ip,
1443
			},
1444
		}
1445
		s.pc.UpdateStatus(newPod)
1446
	} else {
1447
		s.pc.Update(pod)
1448
	}
1449
}
1450

1451
// just overwrites the annotations
1452
// nolint: unparam
1453
func (s *ambientTestServer) annotatePod(t *testing.T, name, ns string, annotations map[string]string) {
1454
	t.Helper()
1455

1456
	p := s.pc.Get(name, ns)
1457
	if p == nil {
1458
		return
1459
	}
1460
	p.ObjectMeta.Annotations = annotations
1461
	s.pc.Update(p)
1462
}
1463

1464
func (s *ambientTestServer) addWorkloadEntries(t *testing.T, ip string, name, sa string, labels map[string]string) {
1465
	t.Helper()
1466
	s.we.CreateOrUpdate(generateWorkloadEntry(ip, name, "ns1", sa, labels, nil))
1467
}
1468

1469
func generateWorkloadEntry(ip, name, namespace, saName string, labels map[string]string, annotations map[string]string) *apiv1alpha3.WorkloadEntry {
1470
	return &apiv1alpha3.WorkloadEntry{
1471
		ObjectMeta: metav1.ObjectMeta{
1472
			Name:        name,
1473
			Labels:      labels,
1474
			Annotations: annotations,
1475
			Namespace:   namespace,
1476
		},
1477
		Spec: v1alpha3.WorkloadEntry{
1478
			Address:        ip,
1479
			ServiceAccount: saName,
1480
			Labels:         labels,
1481
		},
1482
	}
1483
}
1484

1485
func (s *ambientTestServer) deleteWorkloadEntry(t *testing.T, name string) {
1486
	t.Helper()
1487
	s.we.Delete(name, "ns1")
1488
}
1489

1490
func (s *ambientTestServer) addServiceEntry(t *testing.T,
1491
	hostStr string,
1492
	addresses []string,
1493
	name,
1494
	ns string,
1495
	labels map[string]string,
1496
	epAddresses []string,
1497
) {
1498
	t.Helper()
1499

1500
	se := &apiv1alpha3.ServiceEntry{
1501
		ObjectMeta: metav1.ObjectMeta{
1502
			Name:      name,
1503
			Namespace: ns,
1504
			Labels:    labels,
1505
		},
1506
		Spec:   *generateServiceEntry(hostStr, addresses, labels, epAddresses),
1507
		Status: v1alpha1.IstioStatus{},
1508
	}
1509
	s.se.CreateOrUpdate(se)
1510
}
1511

1512
func generateServiceEntry(host string, addresses []string, labels map[string]string, epAddresses []string) *v1alpha3.ServiceEntry {
1513
	var endpoints []*v1alpha3.WorkloadEntry
1514
	var workloadSelector *v1alpha3.WorkloadSelector
1515

1516
	if epAddresses == nil {
1517
		workloadSelector = &v1alpha3.WorkloadSelector{
1518
			Labels: labels,
1519
		}
1520
	} else {
1521
		endpoints = []*v1alpha3.WorkloadEntry{}
1522
		for _, addr := range epAddresses {
1523
			endpoints = append(endpoints, &v1alpha3.WorkloadEntry{
1524
				Address: addr,
1525
				Labels:  labels,
1526
				Ports: map[string]uint32{
1527
					"http": 8081, // we will override the SE http port
1528
				},
1529
			})
1530
		}
1531
	}
1532

1533
	return &v1alpha3.ServiceEntry{
1534
		Hosts:     []string{host},
1535
		Addresses: addresses,
1536
		Ports: []*v1alpha3.ServicePort{
1537
			{
1538
				Name:       "http",
1539
				Number:     80,
1540
				TargetPort: 8080,
1541
			},
1542
		},
1543
		WorkloadSelector: workloadSelector,
1544
		Endpoints:        endpoints,
1545
	}
1546
}
1547

1548
func (s *ambientTestServer) deleteServiceEntry(t *testing.T, name, ns string) {
1549
	t.Helper()
1550
	s.se.Delete(name, ns)
1551
}
1552

1553
func (s *ambientTestServer) assertAddresses(t *testing.T, lookup string, names ...string) {
1554
	t.Helper()
1555
	want := sets.New(names...)
1556
	assert.EventuallyEqual(t, func() sets.String {
1557
		addresses := s.lookup(lookup)
1558
		have := sets.New[string]()
1559
		for _, address := range addresses {
1560
			switch addr := address.Address.Type.(type) {
1561
			case *workloadapi.Address_Workload:
1562
				have.Insert(addr.Workload.Name)
1563
			case *workloadapi.Address_Service:
1564
				have.Insert(addr.Service.Name)
1565
			}
1566
		}
1567
		return have
1568
	}, want, retry.Timeout(time.Second*3))
1569
}
1570

1571
func (s *ambientTestServer) assertWorkloads(t *testing.T, lookup string, state workloadapi.WorkloadStatus, names ...string) {
1572
	t.Helper()
1573
	want := sets.New(names...)
1574
	assert.EventuallyEqual(t, func() sets.String {
1575
		workloads := s.lookup(lookup)
1576
		have := sets.New[string]()
1577
		for _, wl := range workloads {
1578
			switch addr := wl.Address.Type.(type) {
1579
			case *workloadapi.Address_Workload:
1580
				if addr.Workload.Status == state {
1581
					have.Insert(addr.Workload.Name)
1582
				}
1583
			}
1584
		}
1585
		return have
1586
	}, want, retry.Timeout(time.Second*3))
1587
}
1588

1589
// Make sure there are no two workloads in the index with similar UIDs
1590
func (s *ambientTestServer) assertUniqueWorkloads(t *testing.T) {
1591
	t.Helper()
1592
	uids := sets.New[string]()
1593
	workloads := s.lookup("")
1594
	for _, wl := range workloads {
1595
		if wl.GetWorkload() != nil && uids.InsertContains(wl.GetWorkload().GetUid()) {
1596
			t.Fatal("Index has workloads with the same UID")
1597
		}
1598
	}
1599
}
1600

1601
func (s *ambientTestServer) deletePolicy(name, ns string, kind config.GroupVersionKind,
1602
) {
1603
	switch kind {
1604
	case gvk.AuthorizationPolicy:
1605
		s.authz.Delete(name, ns)
1606
	case gvk.PeerAuthentication:
1607
		s.pa.Delete(name, ns)
1608
	}
1609
}
1610

1611
func (s *ambientTestServer) addPolicy(t *testing.T, name, ns string, selector map[string]string,
1612
	kind config.GroupVersionKind, modify func(controllers.Object),
1613
) {
1614
	t.Helper()
1615
	var sel *v1beta1.WorkloadSelector
1616
	if selector != nil {
1617
		sel = &v1beta1.WorkloadSelector{
1618
			MatchLabels: selector,
1619
		}
1620
	}
1621
	switch kind {
1622
	case gvk.AuthorizationPolicy:
1623
		pol := &clientsecurityv1beta1.AuthorizationPolicy{
1624
			ObjectMeta: metav1.ObjectMeta{
1625
				Name:      name,
1626
				Namespace: ns,
1627
			},
1628
			Spec: auth.AuthorizationPolicy{
1629
				Selector: sel,
1630
			},
1631
		}
1632
		if modify != nil {
1633
			modify(pol)
1634
		}
1635
		s.authz.CreateOrUpdate(pol)
1636
	case gvk.PeerAuthentication:
1637
		pol := &clientsecurityv1beta1.PeerAuthentication{
1638
			ObjectMeta: metav1.ObjectMeta{
1639
				Name:      name,
1640
				Namespace: ns,
1641
			},
1642
			Spec: auth.PeerAuthentication{
1643
				Selector: sel,
1644
			},
1645
		}
1646
		if modify != nil {
1647
			modify(pol)
1648
		}
1649
		s.pa.CreateOrUpdate(pol)
1650
	}
1651
}
1652

1653
func (s *ambientTestServer) deletePod(t *testing.T, name string) {
1654
	t.Helper()
1655
	s.pc.Delete(name, testNS)
1656
}
1657

1658
func (s *ambientTestServer) assertEvent(t *testing.T, ip ...string) {
1659
	t.Helper()
1660
	s.assertUnorderedEvent(t, ip...)
1661
}
1662

1663
func (s *ambientTestServer) assertUnorderedEvent(t *testing.T, ip ...string) {
1664
	t.Helper()
1665
	ev := []xdsfake.Event{}
1666
	for _, i := range ip {
1667
		ev = append(ev, xdsfake.Event{Type: "xds", ID: i})
1668
	}
1669
	s.fx.MatchOrFail(t, ev...)
1670
}
1671

1672
func (s *ambientTestServer) assertNoEvent(t *testing.T) {
1673
	t.Helper()
1674
	s.fx.AssertEmpty(t, time.Millisecond*10)
1675
}
1676

1677
func (s *ambientTestServer) deleteService(t *testing.T, name string) {
1678
	t.Helper()
1679
	s.sc.Delete(name, testNS)
1680
}
1681

1682
func (s *ambientTestServer) addService(t *testing.T, name string, labels, annotations map[string]string,
1683
	ports []int32, selector map[string]string, ip string,
1684
) {
1685
	t.Helper()
1686
	service := generateService(name, testNS, labels, annotations, ports, selector, ip)
1687
	s.sc.CreateOrUpdate(service)
1688
}
1689

1690
func (s *ambientTestServer) lookup(key string) []model.AddressInfo {
1691
	if key == "" {
1692
		return s.All()
1693
	}
1694
	return s.Lookup(key)
1695
}
1696

1697
func (s *ambientTestServer) clearEvents() {
1698
	s.fx.Clear()
1699
}
1700

1701
// Returns the XDS resource name for the given pod.
1702
func (s *ambientTestServer) podXdsName(name string) string {
1703
	return fmt.Sprintf("%s//Pod/%s/%s",
1704
		s.clusterID, testNS, name)
1705
}
1706

1707
// Returns the XDS resource name for the given address.
1708
func (s *ambientTestServer) addrXdsName(addr string) string {
1709
	return string(s.network) + "/" + addr
1710
}
1711

1712
// Returns the XDS resource name for the given service.
1713
func (s *ambientTestServer) svcXdsName(serviceName string) string {
1714
	return fmt.Sprintf("%s/%s", testNS, s.hostnameForService(serviceName))
1715
}
1716

1717
// Returns the hostname for the given service.
1718
func (s *ambientTestServer) hostnameForService(serviceName string) string {
1719
	return fmt.Sprintf("%s.%s.svc.company.com", serviceName, testNS)
1720
}
1721

1722
// Returns the XDS resource name for the given WorkloadEntry.
1723
func (s *ambientTestServer) wleXdsName(wleName string) string {
1724
	return fmt.Sprintf("%s/networking.istio.io/WorkloadEntry/%s/%s",
1725
		s.clusterID, testNS, wleName)
1726
}
1727

1728
// Returns the XDS resource name for the given ServiceEntry IP address.
1729
func (s *ambientTestServer) seIPXdsName(name string, ip string) string {
1730
	return fmt.Sprintf("%s/networking.istio.io/ServiceEntry/%s/%s/%s",
1731
		s.clusterID, testNS, name, ip)
1732
}
1733

1734
func generatePod(ip, name, namespace, saName, node string, labels map[string]string, annotations map[string]string) *corev1.Pod {
1735
	automount := false
1736
	return &corev1.Pod{
1737
		ObjectMeta: metav1.ObjectMeta{
1738
			Name:        name,
1739
			Labels:      labels,
1740
			Annotations: annotations,
1741
			Namespace:   namespace,
1742
			CreationTimestamp: metav1.Time{
1743
				Time: time.Now(),
1744
			},
1745
		},
1746
		Spec: corev1.PodSpec{
1747
			ServiceAccountName:           saName,
1748
			NodeName:                     node,
1749
			AutomountServiceAccountToken: &automount,
1750
			// Validation requires this
1751
			Containers: []corev1.Container{
1752
				{
1753
					Name:  "test",
1754
					Image: "ununtu",
1755
				},
1756
			},
1757
		},
1758
		// The cache controller uses this as key, required by our impl.
1759
		Status: corev1.PodStatus{
1760
			Conditions: []corev1.PodCondition{
1761
				{
1762
					Type:               corev1.PodReady,
1763
					Status:             corev1.ConditionTrue,
1764
					LastTransitionTime: metav1.Now(),
1765
				},
1766
			},
1767
			PodIP:  ip,
1768
			HostIP: ip,
1769
			PodIPs: []corev1.PodIP{
1770
				{
1771
					IP: ip,
1772
				},
1773
			},
1774
			Phase: corev1.PodRunning,
1775
		},
1776
	}
1777
}
1778

1779
func setPodReady(pod *corev1.Pod) {
1780
	pod.Status.Conditions = []corev1.PodCondition{
1781
		{
1782
			Type:               corev1.PodReady,
1783
			Status:             corev1.ConditionTrue,
1784
			LastTransitionTime: metav1.Now(),
1785
		},
1786
	}
1787
}
1788

1789
func generateService(name, namespace string, labels, annotations map[string]string,
1790
	ports []int32, selector map[string]string, ip string,
1791
) *corev1.Service {
1792
	svcPorts := make([]corev1.ServicePort, 0)
1793
	for _, p := range ports {
1794
		svcPorts = append(svcPorts, corev1.ServicePort{
1795
			Name:     "tcp-port",
1796
			Port:     p,
1797
			Protocol: "http",
1798
		})
1799
	}
1800

1801
	return &corev1.Service{
1802
		ObjectMeta: metav1.ObjectMeta{
1803
			Name:        name,
1804
			Namespace:   namespace,
1805
			Annotations: annotations,
1806
			Labels:      labels,
1807
		},
1808
		Spec: corev1.ServiceSpec{
1809
			ClusterIP: ip,
1810
			Ports:     svcPorts,
1811
			Selector:  selector,
1812
			Type:      corev1.ServiceTypeClusterIP,
1813
		},
1814
	}
1815
}
1816

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.