istio.io/istio@v0.0.0-20240520182934-d79c90f27776/tests/integration/security/util/framework.go (about) 1 //go:build integ 2 // +build integ 3 4 // Copyright Istio Authors 5 // 6 // Licensed under the Apache License, Version 2.0 (the "License"); 7 // you may not use this file except in compliance with the License. 8 // You may obtain a copy of the License at 9 // 10 // http://www.apache.org/licenses/LICENSE-2.0 11 // 12 // Unless required by applicable law or agreed to in writing, software 13 // distributed under the License is distributed on an "AS IS" BASIS, 14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 // See the License for the specific language governing permissions and 16 // limitations under the License. 17 18 package util 19 20 import ( 21 "fmt" 22 "os" 23 "path" 24 25 "istio.io/api/annotation" 26 "istio.io/istio/pkg/config/protocol" 27 "istio.io/istio/pkg/test/echo/common" 28 "istio.io/istio/pkg/test/env" 29 "istio.io/istio/pkg/test/framework/components/echo" 30 "istio.io/istio/pkg/test/framework/components/echo/match" 31 "istio.io/istio/pkg/test/framework/components/namespace" 32 "istio.io/istio/pkg/test/framework/resource" 33 ) 34 35 const ( 36 ASvc = "a" 37 BSvc = "b" 38 CSvc = "c" 39 DSvc = "d" 40 ESvc = "e" 41 MultiversionSvc = "multiversion" 42 VMSvc = "vm" 43 HeadlessSvc = "headless" 44 NakedSvc = "naked" 45 HeadlessNakedSvc = "headless-naked" 46 ExternalSvc = "external" 47 ) 48 49 type EchoDeployments struct { 50 // TODO: Consolidate the echo config and reduce/reuse echo instances (https://github.com/istio/istio/issues/28599) 51 // Namespace1 is used as the default namespace for reachability tests and other tests which can reuse the same config for echo instances 52 Namespace1 namespace.Instance 53 // Namespace2 is used by most authorization test cases within authorization_test.go 54 Namespace2 namespace.Instance 55 // Namespace3 is used by TestAuthorization_Conditions and there is one C echo instance deployed 56 Namespace3 namespace.Instance 57 A, B, C, D, E echo.Instances 58 Multiversion echo.Instances 59 Headless echo.Instances 60 Naked echo.Instances 61 VM echo.Instances 62 HeadlessNaked echo.Instances 63 All echo.Instances 64 External echo.Instances 65 } 66 67 func EchoConfig(name string, headless bool, annos map[string]string) echo.Config { 68 out := echo.Config{ 69 Service: name, 70 ServiceAccount: true, 71 Headless: headless, 72 Subsets: []echo.SubsetConfig{ 73 { 74 Version: "v1", 75 Annotations: annos, 76 }, 77 }, 78 Ports: []echo.Port{ 79 { 80 Name: "http", 81 Protocol: protocol.HTTP, 82 // We use a port > 1024 to not require root 83 WorkloadPort: 8090, 84 ServicePort: 8095, 85 }, 86 { 87 Name: "tcp", 88 Protocol: protocol.TCP, 89 }, 90 { 91 Name: "grpc", 92 Protocol: protocol.GRPC, 93 }, 94 { 95 Name: "https", 96 Protocol: protocol.HTTPS, 97 ServicePort: 443, 98 WorkloadPort: 8443, 99 TLS: true, 100 }, 101 { 102 Name: "http-8091", 103 Protocol: protocol.HTTP, 104 WorkloadPort: 8091, 105 }, 106 { 107 Name: "http-8092", 108 Protocol: protocol.HTTP, 109 WorkloadPort: 8092, 110 }, 111 { 112 Name: "tcp-8093", 113 Protocol: protocol.TCP, 114 WorkloadPort: 8093, 115 }, 116 { 117 Name: "tcp-8094", 118 Protocol: protocol.TCP, 119 WorkloadPort: 8094, 120 }, 121 // Workload Ports needed by TestPassThroughFilterChain 122 // The port 8084-8089 will be defined only in the workload and not in the k8s service. 123 { 124 Name: "tcp-8085", 125 ServicePort: echo.NoServicePort, 126 WorkloadPort: 8085, 127 Protocol: protocol.HTTP, 128 }, 129 { 130 Name: "tcp-8086", 131 ServicePort: echo.NoServicePort, 132 WorkloadPort: 8086, 133 Protocol: protocol.HTTP, 134 }, 135 { 136 Name: "tcp-8087", 137 ServicePort: echo.NoServicePort, 138 WorkloadPort: 8087, 139 Protocol: protocol.TCP, 140 }, 141 { 142 Name: "tcp-8088", 143 ServicePort: echo.NoServicePort, 144 WorkloadPort: 8088, 145 Protocol: protocol.TCP, 146 }, 147 { 148 Name: "tcp-8089", 149 ServicePort: echo.NoServicePort, 150 WorkloadPort: 8089, 151 Protocol: protocol.HTTPS, 152 TLS: true, 153 }, 154 { 155 Name: "tcp-8084", 156 ServicePort: echo.NoServicePort, 157 WorkloadPort: 8084, 158 Protocol: protocol.HTTPS, 159 TLS: true, 160 }, 161 }, 162 } 163 164 // for headless service with selector, the port and target port must be equal 165 // Ref: https://kubernetes.io/docs/concepts/services-networking/service/#headless-services 166 if headless { 167 for i := range out.Ports { 168 out.Ports[i].ServicePort = out.Ports[i].WorkloadPort 169 } 170 } 171 return out 172 } 173 174 func mustReadCert(f string) string { 175 b, err := os.ReadFile(path.Join(env.IstioSrc, "tests/testdata/certs/dns", f)) 176 if err != nil { 177 panic(fmt.Sprintf("failed to read %v: %v", f, err)) 178 } 179 return string(b) 180 } 181 182 func SetupApps(ctx resource.Context, customCfg *[]echo.Config, buildVM bool) error { 183 if ctx.Settings().Skip(echo.VM) { 184 buildVM = false 185 } 186 187 var customConfig []echo.Config 188 a := EchoConfig(ASvc, false, nil) 189 b := EchoConfig(BSvc, false, nil) 190 c := EchoConfig(CSvc, false, nil) 191 d := EchoConfig(DSvc, false, nil) 192 e := EchoConfig(ESvc, false, nil) 193 multiversionCfg := func() echo.Config { 194 // Multi-version specific setup 195 multiVersionCfg := EchoConfig(MultiversionSvc, false, nil) 196 multiVersionCfg.Subsets = []echo.SubsetConfig{ 197 // Istio deployment, with sidecar. 198 { 199 Version: "vistio", 200 }, 201 // Legacy deployment subset, does not have sidecar injected. 202 { 203 Version: "vlegacy", 204 Annotations: map[string]string{annotation.SidecarInject.Name: "false"}, 205 }, 206 } 207 return multiVersionCfg 208 }() 209 210 nakedSvc := EchoConfig(NakedSvc, false, map[string]string{annotation.SidecarInject.Name: "false"}) 211 212 vmCfg := func() echo.Config { 213 // VM specific setup 214 vmCfg := EchoConfig(VMSvc, false, nil) 215 // for test cases that have `buildVM` off, vm will function like a regular pod 216 vmCfg.DeployAsVM = buildVM 217 return vmCfg 218 }() 219 220 externalSvc := echo.Config{ 221 Service: ExternalSvc, 222 // Namespace: appsNamespace, 223 Ports: []echo.Port{ 224 { 225 // Plain HTTP port only used to route request to egress gateway 226 Name: "http", 227 Protocol: protocol.HTTP, 228 ServicePort: 80, 229 WorkloadPort: 8080, 230 }, 231 { 232 // HTTPS port 233 Name: "https", 234 Protocol: protocol.HTTPS, 235 ServicePort: 443, 236 WorkloadPort: 8443, 237 TLS: true, 238 }, 239 }, 240 // Set up TLS certs on the server. This will make the server listen with these credentials. 241 TLSSettings: &common.TLSSettings{ 242 // Echo has these test certs baked into the docker image 243 RootCert: mustReadCert("root-cert.pem"), 244 ClientCert: mustReadCert("cert-chain.pem"), 245 Key: mustReadCert("key.pem"), 246 // Override hostname to match the SAN in the cert we are using 247 Hostname: "server.default.svc", 248 }, 249 Subsets: []echo.SubsetConfig{{ 250 Version: "v1", 251 Annotations: map[string]string{annotation.SidecarInject.Name: "false"}, 252 }}, 253 } 254 255 headlessSvc := EchoConfig(HeadlessSvc, true, nil) 256 headlessNakedSvc := EchoConfig(HeadlessNakedSvc, true, map[string]string{annotation.SidecarInject.Name: "false"}) 257 258 customConfig = append(customConfig, a, b, c, d, e, multiversionCfg, nakedSvc, vmCfg, externalSvc, headlessSvc, headlessNakedSvc) 259 *customCfg = customConfig 260 return nil 261 } 262 263 // IsMultiversion matches instances that have Multi-version specific setup. 264 var IsMultiversion match.Matcher = func(i echo.Instance) bool { 265 if len(i.Config().Subsets) != 2 { 266 return false 267 } 268 var matchIstio, matchLegacy bool 269 for _, s := range i.Config().Subsets { 270 if s.Version == "vistio" { 271 matchIstio = true 272 } else if s.Version == "vlegacy" { 273 if val, ok := s.Annotations[annotation.SidecarInject.Name]; ok && val == "false" { 274 matchLegacy = true 275 } 276 } 277 } 278 return matchIstio && matchLegacy 279 } 280 281 var IsNotMultiversion = match.Not(IsMultiversion) 282 283 // SourceMatcher matches workload pod A with sidecar injected and VM 284 func SourceMatcher(ns namespace.Instance, skipVM bool) match.Matcher { 285 m := match.ServiceName(echo.NamespacedName{ 286 Name: ASvc, 287 Namespace: ns, 288 }) 289 290 if !skipVM { 291 m = match.Or(m, match.ServiceName(echo.NamespacedName{ 292 Name: VMSvc, 293 Namespace: ns, 294 })) 295 } 296 297 return m 298 } 299 300 // DestMatcher matches workload pod B with sidecar injected and VM 301 func DestMatcher(ns namespace.Instance, skipVM bool) match.Matcher { 302 m := match.ServiceName(echo.NamespacedName{ 303 Name: BSvc, 304 Namespace: ns, 305 }) 306 307 if !skipVM { 308 m = match.Or(m, match.ServiceName(echo.NamespacedName{ 309 Name: VMSvc, 310 Namespace: ns, 311 })) 312 } 313 314 return m 315 }