istio.io/istio@v0.0.0-20240520182934-d79c90f27776/tests/integration/security/sds_ingress/ingress_test.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 sdsingress 19 20 import ( 21 "net/http" 22 "testing" 23 24 "istio.io/istio/pkg/test/framework" 25 "istio.io/istio/pkg/test/framework/components/cluster" 26 "istio.io/istio/pkg/test/framework/components/echo" 27 "istio.io/istio/pkg/test/framework/components/echo/common/deployment" 28 "istio.io/istio/pkg/test/framework/components/echo/echotest" 29 "istio.io/istio/pkg/test/framework/components/istio" 30 "istio.io/istio/pkg/test/framework/components/namespace" 31 "istio.io/istio/pkg/test/framework/resource" 32 ingressutil "istio.io/istio/tests/integration/security/sds_ingress/util" 33 ) 34 35 var ( 36 inst istio.Instance 37 apps deployment.SingleNamespaceView 38 echo1NS namespace.Instance 39 customConfig []echo.Config 40 ) 41 42 func TestMain(m *testing.M) { 43 // Integration test for the ingress SDS Gateway flow. 44 framework. 45 NewSuite(m). 46 Setup(istio.Setup(&inst, nil)). 47 Setup(namespace.Setup(&echo1NS, namespace.Config{Prefix: "echo1", Inject: true})). 48 Setup(func(ctx resource.Context) error { 49 // TODO: due to issue https://github.com/istio/istio/issues/25286, 50 // currently VM does not work in this test 51 err := ingressutil.SetupTest(ctx, &customConfig, namespace.Future(&echo1NS)) 52 if err != nil { 53 return err 54 } 55 return nil 56 }). 57 Setup(deployment.SetupSingleNamespace(&apps, deployment.Config{ 58 Namespaces: []namespace.Getter{ 59 namespace.Future(&echo1NS), 60 }, 61 Configs: echo.ConfigFuture(&customConfig), 62 })). 63 Setup(func(ctx resource.Context) error { 64 return ingressutil.CreateCustomInstances(&apps) 65 }). 66 Run() 67 } 68 69 // TestSingleTlsGateway_SecretRotation tests a single TLS ingress gateway with SDS enabled. 70 // Verifies behavior in these scenarios. 71 // (1) create a kubernetes secret to provision server key/cert, and 72 // verify that TLS connection could establish to deliver HTTPS request. 73 // (2) Rotates key/cert by deleting the secret generated in (1) and 74 // replacing it a new secret with a different server key/cert. 75 // (3) verify that client using older CA cert gets a 404 response 76 // (4) verify that client using the newer CA cert is able to establish TLS connection 77 // to deliver the HTTPS request. 78 func TestSingleTlsGateway_SecretRotation(t *testing.T) { 79 framework. 80 NewTest(t). 81 Run(func(t framework.TestContext) { 82 var ( 83 credName = "testsingletlsgateway-secretrotation" 84 host = "testsingletlsgateway-secretrotation.example.com" 85 ) 86 allInstances := []echo.Instances{ingressutil.A, ingressutil.VM} 87 for _, instances := range allInstances { 88 echotest.New(t, instances). 89 SetupForDestination(func(t framework.TestContext, to echo.Target) error { 90 ingressutil.SetupConfig(t, echo1NS, ingressutil.TestConfig{ 91 Mode: "SIMPLE", 92 CredentialName: credName, 93 Host: host, 94 ServiceName: to.Config().Service, 95 GatewayLabel: inst.Settings().IngressGatewayIstioLabel, 96 }) 97 return nil 98 }). 99 To(echotest.SingleSimplePodServiceAndAllSpecial()). 100 RunFromClusters(func(t framework.TestContext, _ cluster.Cluster, _ echo.Target) { 101 // Add kubernetes secret to provision key/cert for ingress gateway. 102 ingressutil.CreateIngressKubeSecret(t, credName, ingressutil.TLS, 103 ingressutil.IngressCredentialA, false) 104 105 ing := inst.IngressFor(t.Clusters().Default()) 106 if ing == nil { 107 t.Skip() 108 } 109 110 tlsContextA := ingressutil.TLSContext{CaCert: ingressutil.CaCertA} 111 tlsContextB := ingressutil.TLSContext{CaCert: ingressutil.CaCertB} 112 113 // Verify the call works 114 ingressutil.SendRequestOrFail(t, ing, host, credName, ingressutil.TLS, tlsContextA, 115 ingressutil.ExpectedResponse{StatusCode: http.StatusOK}) 116 117 // Now rotate the key/cert 118 ingressutil.RotateSecrets(t, credName, ingressutil.TLS, 119 ingressutil.IngressCredentialB, false) 120 121 t.NewSubTest("old cert should fail").Run(func(t framework.TestContext) { 122 // Client use old server CA cert to set up SSL connection would fail. 123 ingressutil.SendRequestOrFail(t, ing, host, credName, ingressutil.TLS, tlsContextA, 124 ingressutil.ExpectedResponse{ErrorMessage: "certificate signed by unknown authority"}) 125 }) 126 127 t.NewSubTest("new cert should succeed").Run(func(t framework.TestContext) { 128 // Client use new server CA cert to set up SSL connection. 129 ingressutil.SendRequestOrFail(t, ing, host, credName, ingressutil.TLS, tlsContextB, 130 ingressutil.ExpectedResponse{StatusCode: http.StatusOK}) 131 }) 132 }) 133 } 134 }) 135 } 136 137 // TestSingleMTLSGateway_ServerKeyCertRotation tests a single mTLS ingress gateway with SDS enabled. 138 // Verifies behavior in these scenarios. 139 // (1) create two kubernetes secrets to provision server key/cert and client CA cert, and 140 // verify that mTLS connection could establish to deliver HTTPS request. 141 // (2) replace kubernetes secret to rotate server key/cert, and verify that mTLS connection could 142 // not establish. This is because client is still using old server CA cert to validate server cert, 143 // and the new server cert cannot pass validation at client side. 144 // (3) do another key/cert rotation to use the correct server key/cert this time, and verify that 145 // mTLS connection could establish to deliver HTTPS request. 146 func TestSingleMTLSGateway_ServerKeyCertRotation(t *testing.T) { 147 framework. 148 NewTest(t). 149 Run(func(t framework.TestContext) { 150 var ( 151 credName = "testsinglemtlsgateway-serverkeycertrotation" 152 credCaName = "testsinglemtlsgateway-serverkeycertrotation-cacert" 153 host = "testsinglemtlsgateway-serverkeycertrotation.example.com" 154 ) 155 allInstances := []echo.Instances{ingressutil.A, ingressutil.VM} 156 for _, instances := range allInstances { 157 echotest.New(t, instances). 158 SetupForDestination(func(t framework.TestContext, to echo.Target) error { 159 ingressutil.SetupConfig(t, echo1NS, ingressutil.TestConfig{ 160 Mode: "MUTUAL", 161 CredentialName: credName, 162 Host: host, 163 ServiceName: to.Config().Service, 164 GatewayLabel: inst.Settings().IngressGatewayIstioLabel, 165 }) 166 return nil 167 }). 168 To(echotest.SingleSimplePodServiceAndAllSpecial()). 169 RunFromClusters(func(t framework.TestContext, _ cluster.Cluster, _ echo.Target) { 170 // Add two kubernetes secrets to provision server key/cert and client CA cert for ingress gateway. 171 ingressutil.CreateIngressKubeSecret(t, credCaName, ingressutil.Mtls, 172 ingressutil.IngressCredentialCaCertA, false) 173 ingressutil.CreateIngressKubeSecret(t, credName, ingressutil.Mtls, 174 ingressutil.IngressCredentialServerKeyCertA, false) 175 176 ing := inst.IngressFor(t.Clusters().Default()) 177 if ing == nil { 178 t.Skip() 179 } 180 tlsContext := ingressutil.TLSContext{ 181 CaCert: ingressutil.CaCertA, 182 PrivateKey: ingressutil.TLSClientKeyA, 183 Cert: ingressutil.TLSClientCertA, 184 } 185 ingressutil.SendRequestOrFail(t, ing, host, credName, ingressutil.Mtls, tlsContext, 186 ingressutil.ExpectedResponse{StatusCode: http.StatusOK}) 187 188 t.NewSubTest("mismatched key/cert should fail").Run(func(t framework.TestContext) { 189 // key/cert rotation using mis-matched server key/cert. The server cert cannot pass validation 190 // at client side. 191 ingressutil.RotateSecrets(t, credName, ingressutil.Mtls, 192 ingressutil.IngressCredentialServerKeyCertB, false) 193 // Client uses old server CA cert to set up SSL connection would fail. 194 ingressutil.SendRequestOrFail(t, ing, host, credName, ingressutil.Mtls, tlsContext, 195 ingressutil.ExpectedResponse{ErrorMessage: "certificate signed by unknown authority"}) 196 }) 197 198 t.NewSubTest("matched key/cert should succeed").Run(func(t framework.TestContext) { 199 // key/cert rotation using matched server key/cert. This time the server cert is able to pass 200 // validation at client side. 201 ingressutil.RotateSecrets(t, credName, ingressutil.Mtls, 202 ingressutil.IngressCredentialServerKeyCertA, false) 203 // Use old CA cert to set up SSL connection would succeed this time. 204 ingressutil.SendRequestOrFail(t, ing, host, credName, ingressutil.Mtls, tlsContext, 205 ingressutil.ExpectedResponse{StatusCode: http.StatusOK}) 206 }) 207 }) 208 } 209 }) 210 } 211 212 // TestSingleOptionalMTLSGateway tests a single mTLS ingress gateway with SDS enabled. 213 // Verifies behavior when client sends certificate and when client does not send certificate. 214 func TestSingleOptionalMTLSGateway(t *testing.T) { 215 framework. 216 NewTest(t). 217 Run(func(t framework.TestContext) { 218 var ( 219 credName = "testsinglemtlsgateway-serverkeyoptionalmtls" 220 credCaName = "testsinglemtlsgateway-serverkeyoptionalmtls-cacert" 221 host = "testsinglemtlsgateway-serverkeyoptionalmtls.example.com" 222 ) 223 allInstances := []echo.Instances{ingressutil.A, ingressutil.VM} 224 for _, instances := range allInstances { 225 echotest.New(t, instances). 226 SetupForDestination(func(t framework.TestContext, to echo.Target) error { 227 ingressutil.SetupConfig(t, echo1NS, ingressutil.TestConfig{ 228 Mode: "OPTIONAL_MUTUAL", 229 CredentialName: credName, 230 Host: host, 231 ServiceName: to.Config().Service, 232 GatewayLabel: inst.Settings().IngressGatewayIstioLabel, 233 }) 234 return nil 235 }). 236 To(echotest.SingleSimplePodServiceAndAllSpecial()). 237 RunFromClusters(func(t framework.TestContext, _ cluster.Cluster, _ echo.Target) { 238 // Add two kubernetes secrets to provision server key/cert and client CA cert for ingress gateway. 239 ingressutil.CreateIngressKubeSecret(t, credCaName, ingressutil.Mtls, 240 ingressutil.IngressCredentialCaCertA, false) 241 ingressutil.CreateIngressKubeSecret(t, credName, ingressutil.Mtls, 242 ingressutil.IngressCredentialServerKeyCertA, false) 243 244 ing := inst.IngressFor(t.Clusters().Default()) 245 if ing == nil { 246 t.Skip() 247 } 248 tlsContext := ingressutil.TLSContext{ 249 CaCert: ingressutil.CaCertA, 250 PrivateKey: ingressutil.TLSClientKeyA, 251 Cert: ingressutil.TLSClientCertA, 252 } 253 t.NewSubTest("request without client certificates").Run(func(t framework.TestContext) { 254 // Send a SIMPLE TLS request without client certificates. 255 ingressutil.SendRequestOrFail(t, ing, host, credName, ingressutil.TLS, tlsContext, 256 ingressutil.ExpectedResponse{StatusCode: http.StatusOK}) 257 }) 258 t.NewSubTest("request with client certificates").Run(func(t framework.TestContext) { 259 // Send a TLS request with client certificates. 260 ingressutil.SendRequestOrFail(t, ing, host, credName, ingressutil.Mtls, tlsContext, 261 ingressutil.ExpectedResponse{StatusCode: http.StatusOK}) 262 }) 263 }) 264 } 265 }) 266 } 267 268 // TestSingleMTLSGateway_CompoundSecretRotation tests a single mTLS ingress gateway with SDS enabled. 269 // Verifies behavior in these scenarios. 270 // (1) A valid kubernetes secret with key/cert and client CA cert is added, verifies that SSL connection 271 // termination is working properly. This secret is a compound secret. 272 // (2) After key/cert rotation, client needs to pick new CA cert to complete SSL connection. Old CA 273 // cert will cause the SSL connection fail. 274 func TestSingleMTLSGateway_CompoundSecretRotation(t *testing.T) { 275 framework. 276 NewTest(t). 277 Run(func(t framework.TestContext) { 278 var ( 279 credName = "testsinglemtlsgateway-generic-compoundrotation" 280 host = "testsinglemtlsgateway-compoundsecretrotation.example.com" 281 ) 282 allInstances := []echo.Instances{ingressutil.A, ingressutil.VM} 283 for _, instances := range allInstances { 284 echotest.New(t, instances). 285 SetupForDestination(func(t framework.TestContext, to echo.Target) error { 286 ingressutil.SetupConfig(t, echo1NS, ingressutil.TestConfig{ 287 Mode: "MUTUAL", 288 CredentialName: credName, 289 Host: host, 290 ServiceName: to.Config().Service, 291 GatewayLabel: inst.Settings().IngressGatewayIstioLabel, 292 }) 293 return nil 294 }). 295 To(echotest.SingleSimplePodServiceAndAllSpecial()). 296 RunFromClusters(func(t framework.TestContext, _ cluster.Cluster, to echo.Target) { 297 // Add kubernetes secret to provision key/cert for ingress gateway. 298 ingressutil.CreateIngressKubeSecret(t, credName, ingressutil.Mtls, 299 ingressutil.IngressCredentialA, false) 300 301 // Wait for ingress gateway to fetch key/cert from Gateway agent via SDS. 302 ing := inst.IngressFor(t.Clusters().Default()) 303 tlsContext := ingressutil.TLSContext{ 304 CaCert: ingressutil.CaCertA, 305 PrivateKey: ingressutil.TLSClientKeyA, 306 Cert: ingressutil.TLSClientCertA, 307 } 308 ingressutil.SendRequestOrFail(t, ing, host, credName, ingressutil.Mtls, tlsContext, 309 ingressutil.ExpectedResponse{StatusCode: http.StatusOK}) 310 311 t.NewSubTest("old server CA should fail").Run(func(t framework.TestContext) { 312 // key/cert rotation 313 ingressutil.RotateSecrets(t, credName, ingressutil.Mtls, 314 ingressutil.IngressCredentialB, false) 315 // Use old server CA cert to set up SSL connection would fail. 316 ingressutil.SendRequestOrFail(t, ing, host, credName, ingressutil.Mtls, tlsContext, 317 ingressutil.ExpectedResponse{ErrorMessage: "certificate signed by unknown authority"}) 318 }) 319 320 t.NewSubTest("new server CA should succeed").Run(func(t framework.TestContext) { 321 // Use new server CA cert to set up SSL connection. 322 tlsContext = ingressutil.TLSContext{ 323 CaCert: ingressutil.CaCertB, 324 PrivateKey: ingressutil.TLSClientKeyB, 325 Cert: ingressutil.TLSClientCertB, 326 } 327 ingressutil.SendRequestOrFail(t, ing, host, credName, ingressutil.Mtls, tlsContext, 328 ingressutil.ExpectedResponse{StatusCode: http.StatusOK}) 329 }) 330 }) 331 } 332 }) 333 } 334 335 // TestSingleMTLSGatewayAndNotGeneric_CompoundSecretRotation tests a single mTLS ingress gateway with SDS enabled 336 // and use the tls cert instead of generic cert Verifies behavior in these scenarios. 337 // (1) A valid kubernetes secret with key/cert and client CA cert is added, verifies that SSL connection 338 // termination is working properly. This secret is a compound secret. 339 // (2) After key/cert rotation, client needs to pick new CA cert to complete SSL connection. Old CA 340 // cert will cause the SSL connection fail. 341 func TestSingleMTLSGatewayAndNotGeneric_CompoundSecretRotation(t *testing.T) { 342 framework. 343 NewTest(t). 344 Run(func(t framework.TestContext) { 345 var ( 346 credName = "testsinglemtlsgatewayandnotgeneric-compoundsecretrotation" 347 host = "testsinglemtlsgatewayandnotgeneric-compoundsecretrotation.example.com" 348 ) 349 allInstances := []echo.Instances{ingressutil.A, ingressutil.VM} 350 for _, instances := range allInstances { 351 echotest.New(t, instances). 352 SetupForDestination(func(t framework.TestContext, to echo.Target) error { 353 ingressutil.SetupConfig(t, echo1NS, ingressutil.TestConfig{ 354 Mode: "MUTUAL", 355 CredentialName: credName, 356 Host: host, 357 ServiceName: to.Config().Service, 358 GatewayLabel: inst.Settings().IngressGatewayIstioLabel, 359 }) 360 return nil 361 }). 362 To(echotest.SingleSimplePodServiceAndAllSpecial()). 363 RunFromClusters(func(t framework.TestContext, _ cluster.Cluster, _ echo.Target) { 364 // Add kubernetes secret to provision key/cert for ingress gateway. 365 ingressutil.CreateIngressKubeSecret(t, credName, ingressutil.Mtls, 366 ingressutil.IngressCredentialA, true) 367 368 // Wait for ingress gateway to fetch key/cert from Gateway agent via SDS. 369 ing := inst.IngressFor(t.Clusters().Default()) 370 if ing == nil { 371 t.Skip() 372 } 373 tlsContext := ingressutil.TLSContext{ 374 CaCert: ingressutil.CaCertA, 375 PrivateKey: ingressutil.TLSClientKeyA, 376 Cert: ingressutil.TLSClientCertA, 377 } 378 ingressutil.SendRequestOrFail(t, ing, host, credName, ingressutil.Mtls, tlsContext, 379 ingressutil.ExpectedResponse{StatusCode: http.StatusOK}) 380 381 t.NewSubTest("old server CA should fail").Run(func(t framework.TestContext) { 382 // key/cert rotation 383 ingressutil.RotateSecrets(t, credName, ingressutil.Mtls, 384 ingressutil.IngressCredentialB, true) 385 // Use old server CA cert to set up SSL connection would fail. 386 ingressutil.SendRequestOrFail(t, ing, host, credName, ingressutil.Mtls, tlsContext, 387 ingressutil.ExpectedResponse{ErrorMessage: "certificate signed by unknown authority"}) 388 }) 389 390 t.NewSubTest("new server CA should succeed").Run(func(t framework.TestContext) { 391 // Use new server CA cert to set up SSL connection. 392 tlsContext = ingressutil.TLSContext{ 393 CaCert: ingressutil.CaCertB, 394 PrivateKey: ingressutil.TLSClientKeyB, 395 Cert: ingressutil.TLSClientCertB, 396 } 397 ingressutil.SendRequestOrFail(t, ing, host, credName, ingressutil.Mtls, tlsContext, 398 ingressutil.ExpectedResponse{StatusCode: http.StatusOK}) 399 }) 400 }) 401 } 402 }) 403 } 404 405 // TestTlsGateways deploys multiple TLS gateways with SDS enabled, and creates kubernetes that store 406 // private key and server certificate for each TLS gateway. Verifies that all gateways are able to terminate 407 // SSL connections successfully. 408 func TestTlsGateways(t *testing.T) { 409 framework. 410 NewTest(t). 411 Run(func(t framework.TestContext) { 412 ingressutil.RunTestMultiTLSGateways(t, inst, namespace.Future(&echo1NS)) 413 }) 414 } 415 416 // TestMtlsGateways deploys multiple mTLS gateways with SDS enabled, and creates kubernetes that store 417 // private key, server certificate and CA certificate for each mTLS gateway. Verifies that all gateways 418 // are able to terminate mTLS connections successfully. 419 func TestMtlsGateways(t *testing.T) { 420 framework. 421 NewTest(t). 422 Run(func(t framework.TestContext) { 423 ingressutil.RunTestMultiMtlsGateways(t, inst, namespace.Future(&echo1NS)) 424 }) 425 } 426 427 // TestMultiTlsGateway_InvalidSecret tests a single TLS ingress gateway with SDS enabled. Creates kubernetes secret 428 // with invalid key/cert and verify the behavior. 429 func TestMultiTlsGateway_InvalidSecret(t *testing.T) { 430 framework. 431 NewTest(t). 432 Run(func(t framework.TestContext) { 433 testCase := []struct { 434 name string 435 secretName string 436 ingressGatewayCredential ingressutil.IngressCredential 437 hostName string 438 expectedResponse ingressutil.ExpectedResponse 439 callType ingressutil.CallType 440 tlsContext ingressutil.TLSContext 441 }{ 442 { 443 name: "tls ingress gateway invalid private key", 444 secretName: "testmultitlsgateway-invalidsecret-1", 445 ingressGatewayCredential: ingressutil.IngressCredential{ 446 PrivateKey: "invalid", 447 Certificate: ingressutil.TLSServerCertA, 448 }, 449 hostName: "testmultitlsgateway-invalidsecret1.example.com", 450 expectedResponse: ingressutil.ExpectedResponse{ 451 ErrorMessage: "connection reset by peer", 452 }, 453 callType: ingressutil.TLS, 454 tlsContext: ingressutil.TLSContext{ 455 CaCert: ingressutil.CaCertA, 456 }, 457 }, 458 { 459 name: "tls ingress gateway invalid server cert", 460 secretName: "testmultitlsgateway-invalidsecret-2", 461 ingressGatewayCredential: ingressutil.IngressCredential{ 462 PrivateKey: ingressutil.TLSServerKeyA, 463 Certificate: "invalid", 464 }, 465 hostName: "testmultitlsgateway-invalidsecret2.example.com", 466 expectedResponse: ingressutil.ExpectedResponse{ 467 ErrorMessage: "connection reset by peer", 468 }, 469 callType: ingressutil.TLS, 470 tlsContext: ingressutil.TLSContext{ 471 CaCert: ingressutil.CaCertA, 472 }, 473 }, 474 { 475 name: "tls ingress gateway mis-matched key and cert", 476 secretName: "testmultitlsgateway-invalidsecret-3", 477 ingressGatewayCredential: ingressutil.IngressCredential{ 478 PrivateKey: ingressutil.TLSServerKeyA, 479 Certificate: ingressutil.TLSServerCertB, 480 }, 481 hostName: "testmultitlsgateway-invalidsecret3.example.com", 482 expectedResponse: ingressutil.ExpectedResponse{ 483 ErrorMessage: "connection reset by peer", 484 }, 485 callType: ingressutil.TLS, 486 tlsContext: ingressutil.TLSContext{ 487 CaCert: ingressutil.CaCertA, 488 }, 489 }, 490 { 491 name: "tls ingress gateway no private key", 492 secretName: "testmultitlsgateway-invalidsecret-4", 493 ingressGatewayCredential: ingressutil.IngressCredential{ 494 Certificate: ingressutil.TLSServerCertA, 495 }, 496 hostName: "testmultitlsgateway-invalidsecret4.example.com", 497 expectedResponse: ingressutil.ExpectedResponse{ 498 ErrorMessage: "connection reset by peer", 499 }, 500 callType: ingressutil.TLS, 501 tlsContext: ingressutil.TLSContext{ 502 CaCert: ingressutil.CaCertA, 503 }, 504 }, 505 { 506 name: "tls ingress gateway no server cert", 507 secretName: "testmultitlsgateway-invalidsecret-5", 508 ingressGatewayCredential: ingressutil.IngressCredential{ 509 PrivateKey: ingressutil.TLSServerKeyA, 510 }, 511 hostName: "testmultitlsgateway-invalidsecret5.example.com", 512 expectedResponse: ingressutil.ExpectedResponse{ 513 ErrorMessage: "connection reset by peer", 514 }, 515 callType: ingressutil.TLS, 516 tlsContext: ingressutil.TLSContext{ 517 CaCert: ingressutil.CaCertA, 518 }, 519 }, 520 } 521 522 for _, c := range testCase { 523 allInstances := []echo.Instances{ingressutil.A, ingressutil.VM} 524 for _, instances := range allInstances { 525 echotest.New(t, instances). 526 SetupForDestination(func(t framework.TestContext, to echo.Target) error { 527 ingressutil.SetupConfig(t, echo1NS, ingressutil.TestConfig{ 528 Mode: "SIMPLE", 529 CredentialName: c.secretName, 530 Host: c.hostName, 531 ServiceName: to.Config().Service, 532 GatewayLabel: inst.Settings().IngressGatewayIstioLabel, 533 }) 534 return nil 535 }). 536 To(echotest.SingleSimplePodServiceAndAllSpecial()). 537 RunFromClusters(func(t framework.TestContext, _ cluster.Cluster, _ echo.Target) { 538 ing := inst.IngressFor(t.Clusters().Default()) 539 if ing == nil { 540 t.Skip() 541 } 542 t.NewSubTest(c.name).Run(func(t framework.TestContext) { 543 ingressutil.CreateIngressKubeSecret(t, c.secretName, ingressutil.TLS, 544 c.ingressGatewayCredential, false) 545 546 ingressutil.SendRequestOrFail(t, ing, c.hostName, c.secretName, c.callType, c.tlsContext, 547 c.expectedResponse) 548 }) 549 }) 550 } 551 } 552 }) 553 } 554 555 // TestMultiMtlsGateway_InvalidSecret tests a single mTLS ingress gateway with SDS enabled. Creates kubernetes secret 556 // with invalid key/cert and verify the behavior. 557 func TestMultiMtlsGateway_InvalidSecret(t *testing.T) { 558 framework. 559 NewTest(t). 560 Run(func(t framework.TestContext) { 561 testCase := []struct { 562 name string 563 secretName string 564 ingressGatewayCredential ingressutil.IngressCredential 565 hostName string 566 expectedResponse ingressutil.ExpectedResponse 567 callType ingressutil.CallType 568 tlsContext ingressutil.TLSContext 569 }{ 570 { 571 name: "mtls ingress gateway invalid CA cert", 572 secretName: "testmultimtlsgateway-invalidsecret-1", 573 ingressGatewayCredential: ingressutil.IngressCredential{ 574 PrivateKey: ingressutil.TLSServerKeyA, 575 Certificate: ingressutil.TLSServerCertA, 576 CaCert: "invalid", 577 }, 578 hostName: "testmultimtlsgateway-invalidsecret1.example.com", 579 expectedResponse: ingressutil.ExpectedResponse{ 580 ErrorMessage: "connection reset by peer", 581 }, 582 callType: ingressutil.Mtls, 583 tlsContext: ingressutil.TLSContext{ 584 CaCert: ingressutil.CaCertA, 585 PrivateKey: ingressutil.TLSClientKeyA, 586 Cert: ingressutil.TLSClientCertA, 587 }, 588 }, 589 { 590 name: "mtls ingress gateway no CA cert", 591 secretName: "testmultimtlsgateway-invalidsecret-2", 592 ingressGatewayCredential: ingressutil.IngressCredential{ 593 PrivateKey: ingressutil.TLSServerKeyA, 594 Certificate: ingressutil.TLSServerCertA, 595 }, 596 hostName: "testmultimtlsgateway-invalidsecret2.example.com", 597 expectedResponse: ingressutil.ExpectedResponse{ 598 ErrorMessage: "connection reset by peer", 599 }, 600 callType: ingressutil.Mtls, 601 tlsContext: ingressutil.TLSContext{ 602 CaCert: ingressutil.CaCertA, 603 PrivateKey: ingressutil.TLSClientKeyA, 604 Cert: ingressutil.TLSClientCertA, 605 }, 606 }, 607 { 608 name: "mtls ingress gateway mismatched CA cert", 609 secretName: "testmultimtlsgateway-invalidsecret-3", 610 ingressGatewayCredential: ingressutil.IngressCredential{ 611 PrivateKey: ingressutil.TLSServerKeyA, 612 Certificate: ingressutil.TLSServerCertA, 613 CaCert: ingressutil.CaCertB, 614 }, 615 hostName: "testmultimtlsgateway-invalidsecret3.example.com", 616 expectedResponse: ingressutil.ExpectedResponse{ 617 ErrorMessage: "error decrypting message", 618 }, 619 callType: ingressutil.Mtls, 620 tlsContext: ingressutil.TLSContext{ 621 CaCert: ingressutil.CaCertA, 622 PrivateKey: ingressutil.TLSClientKeyA, 623 Cert: ingressutil.TLSClientCertA, 624 }, 625 }, 626 } 627 628 for _, c := range testCase { 629 allInstances := []echo.Instances{ingressutil.A, ingressutil.VM} 630 for _, instances := range allInstances { 631 echotest.New(t, instances). 632 SetupForDestination(func(t framework.TestContext, to echo.Target) error { 633 ingressutil.SetupConfig(t, echo1NS, ingressutil.TestConfig{ 634 Mode: "MUTUAL", 635 CredentialName: c.secretName, 636 Host: c.hostName, 637 ServiceName: to.Config().Service, 638 GatewayLabel: inst.Settings().IngressGatewayIstioLabel, 639 }) 640 return nil 641 }). 642 To(echotest.SingleSimplePodServiceAndAllSpecial()). 643 RunFromClusters(func(t framework.TestContext, src cluster.Cluster, dest echo.Target) { 644 ing := inst.IngressFor(t.Clusters().Default()) 645 if ing == nil { 646 t.Skip() 647 } 648 t.NewSubTest(c.name).Run(func(t framework.TestContext) { 649 ingressutil.CreateIngressKubeSecret(t, c.secretName, ingressutil.Mtls, 650 c.ingressGatewayCredential, false) 651 652 ingressutil.SendRequestOrFail(t, ing, c.hostName, c.secretName, c.callType, c.tlsContext, 653 c.expectedResponse) 654 }) 655 }) 656 } 657 } 658 }) 659 } 660 661 // TestMtlsGateway_CRL tests the behavior of a single mTLS ingress gateway with SDS enabled. Creates kubernetes secret 662 // with CRL enabled and verify the behavior. 663 func TestMtlsGateway_CRL(t *testing.T) { 664 framework. 665 NewTest(t). 666 Run(func(t framework.TestContext) { 667 testCase := []struct { 668 name string 669 secretName string 670 ingressGatewayCredential ingressutil.IngressCredential 671 hostName string 672 expectedResponse ingressutil.ExpectedResponse 673 callType ingressutil.CallType 674 tlsContext ingressutil.TLSContext 675 }{ 676 { 677 // TC1: regular communication without CRL from client A works 678 name: "mtls ingress gateway without CRL-client A", 679 secretName: "testmtlsgateway-secret-without-crl-a", 680 ingressGatewayCredential: ingressutil.IngressCredential{ 681 PrivateKey: ingressutil.TLSServerKeyA, 682 Certificate: ingressutil.TLSServerCertA, 683 CaCert: ingressutil.CaCertA, 684 }, 685 hostName: "testmtlsgateway-crl.example.com", 686 expectedResponse: ingressutil.ExpectedResponse{ 687 StatusCode: http.StatusOK, 688 }, 689 callType: ingressutil.Mtls, 690 tlsContext: ingressutil.TLSContext{ 691 CaCert: ingressutil.CaCertA, 692 PrivateKey: ingressutil.TLSClientKeyA, 693 Cert: ingressutil.TLSClientCertA, 694 }, 695 }, 696 // TC2: regular communication without CRL from client B works 697 { 698 name: "mtls ingress gateway without CRL-client B", 699 secretName: "testmtlsgateway-secret-without-crl-b", 700 ingressGatewayCredential: ingressutil.IngressCredential{ 701 PrivateKey: ingressutil.TLSServerKeyB, 702 Certificate: ingressutil.TLSServerCertB, 703 CaCert: ingressutil.CaCertB, 704 }, 705 hostName: "testmtlsgateway-crl.example.com", 706 expectedResponse: ingressutil.ExpectedResponse{ 707 StatusCode: http.StatusOK, 708 }, 709 callType: ingressutil.Mtls, 710 tlsContext: ingressutil.TLSContext{ 711 CaCert: ingressutil.CaCertB, 712 PrivateKey: ingressutil.TLSClientKeyB, 713 Cert: ingressutil.TLSClientCertB, 714 }, 715 }, 716 // TC3: Add CRL with revoked client Certificate A to the configuration, 717 // and initiate communication from client A. 718 // Server should respond with the "revoked certificate" error message. 719 { 720 name: "mtls ingress gateway with CRL-client A", 721 secretName: "testmtlsgateway-secret-with-crl-a", 722 ingressGatewayCredential: ingressutil.IngressCredential{ 723 PrivateKey: ingressutil.TLSServerKeyA, 724 Certificate: ingressutil.TLSServerCertA, 725 CaCert: ingressutil.CaCertA, 726 Crl: ingressutil.CaCrlA, 727 }, 728 hostName: "testmtlsgateway-crl.example.com", 729 expectedResponse: ingressutil.ExpectedResponse{ 730 StatusCode: http.StatusBadGateway, 731 ErrorMessage: "tls: revoked certificate", 732 }, 733 callType: ingressutil.Mtls, 734 tlsContext: ingressutil.TLSContext{ 735 CaCert: ingressutil.CaCertA, 736 PrivateKey: ingressutil.TLSClientKeyA, 737 Cert: ingressutil.TLSClientCertA, 738 }, 739 }, 740 // TC4: Add CRL with a revoked dummy client certificate to the configuration, 741 // and initiate communication from client A. The communication should go through 742 // as long as the CRL does not have client A certificate as revoked. 743 { 744 name: "mtls ingress gateway with dummy CRL", 745 secretName: "testmtlsgateway-secret-with-dummy-crl", 746 ingressGatewayCredential: ingressutil.IngressCredential{ 747 PrivateKey: ingressutil.TLSServerKeyA, 748 Certificate: ingressutil.TLSServerCertA, 749 CaCert: ingressutil.CaCertA, 750 Crl: ingressutil.DummyCaCrlA, 751 }, 752 hostName: "testmtlsgateway-crl.example.com", 753 expectedResponse: ingressutil.ExpectedResponse{ 754 StatusCode: http.StatusOK, 755 }, 756 callType: ingressutil.Mtls, 757 tlsContext: ingressutil.TLSContext{ 758 CaCert: ingressutil.CaCertA, 759 PrivateKey: ingressutil.TLSClientKeyA, 760 Cert: ingressutil.TLSClientCertA, 761 }, 762 }, 763 // TC5: Add CRL with revoked client Certificate A to the configuration, 764 // and initiate communication from client B. 765 // Server should respond with the "unknown CA" error message. 766 { 767 name: "mtls ingress gateway with CRL-unknown CA", 768 secretName: "testmtlsgateway-secret-with-crl-unknown-ca", 769 ingressGatewayCredential: ingressutil.IngressCredential{ 770 PrivateKey: ingressutil.TLSServerKeyB, 771 Certificate: ingressutil.TLSServerCertB, 772 CaCert: ingressutil.CaCertB, 773 Crl: ingressutil.CaCrlA, 774 }, 775 hostName: "testmtlsgateway-crl.example.com", 776 expectedResponse: ingressutil.ExpectedResponse{ 777 StatusCode: http.StatusBadGateway, 778 ErrorMessage: "tls: unknown certificate authority", 779 }, 780 callType: ingressutil.Mtls, 781 tlsContext: ingressutil.TLSContext{ 782 CaCert: ingressutil.CaCertB, 783 PrivateKey: ingressutil.TLSClientKeyB, 784 Cert: ingressutil.TLSClientCertB, 785 }, 786 }, 787 } 788 789 for _, c := range testCase { 790 allInstances := []echo.Instances{ingressutil.A, ingressutil.VM} 791 for _, instances := range allInstances { 792 echotest.New(t, instances). 793 SetupForDestination(func(t framework.TestContext, to echo.Target) error { 794 ingressutil.SetupConfig(t, echo1NS, ingressutil.TestConfig{ 795 Mode: "MUTUAL", 796 CredentialName: c.secretName, 797 Host: c.hostName, 798 ServiceName: to.Config().Service, 799 GatewayLabel: inst.Settings().IngressGatewayIstioLabel, 800 }) 801 return nil 802 }). 803 To(echotest.SingleSimplePodServiceAndAllSpecial()). 804 RunFromClusters(func(t framework.TestContext, src cluster.Cluster, dest echo.Target) { 805 ing := inst.IngressFor(t.Clusters().Default()) 806 if ing == nil { 807 t.Skip() 808 } 809 t.NewSubTest(c.name).Run(func(t framework.TestContext) { 810 ingressutil.CreateIngressKubeSecret(t, c.secretName, ingressutil.Mtls, 811 c.ingressGatewayCredential, false) 812 813 ingressutil.SendRequestOrFail(t, ing, c.hostName, c.secretName, c.callType, c.tlsContext, 814 c.expectedResponse) 815 }) 816 }) 817 } 818 } 819 }) 820 }