github.com/nginxinc/kubernetes-ingress@v1.12.5/tests/suite/test_jwt_policies_vsr.py (about) 1 import pytest, requests, time 2 from kubernetes.client.rest import ApiException 3 from suite.resources_utils import ( 4 wait_before_test, 5 replace_configmap_from_yaml, 6 create_secret_from_yaml, 7 delete_secret, 8 replace_secret, 9 ) 10 from suite.custom_resources_utils import ( 11 read_custom_resource, 12 delete_virtual_server, 13 patch_virtual_server_from_yaml, 14 patch_v_s_route_from_yaml, 15 create_policy_from_yaml, 16 delete_policy, 17 read_policy, 18 ) 19 from settings import TEST_DATA, DEPLOYMENTS 20 21 std_vs_src = f"{TEST_DATA}/virtual-server-route/standard/virtual-server.yaml" 22 std_vsr_src = f"{TEST_DATA}/virtual-server-route/route-multiple.yaml" 23 jwk_sec_valid_src = f"{TEST_DATA}/jwt-policy/secret/jwk-secret-valid.yaml" 24 jwk_sec_invalid_src = f"{TEST_DATA}/jwt-policy/secret/jwk-secret-invalid.yaml" 25 jwt_pol_valid_src = f"{TEST_DATA}/jwt-policy/policies/jwt-policy-valid.yaml" 26 jwt_pol_multi_src = f"{TEST_DATA}/jwt-policy/policies/jwt-policy-valid-multi.yaml" 27 jwt_pol_invalid_src = f"{TEST_DATA}/jwt-policy/policies/jwt-policy-invalid.yaml" 28 jwt_pol_invalid_sec_src = f"{TEST_DATA}/jwt-policy/policies/jwt-policy-invalid-secret.yaml" 29 jwt_vsr_invalid_src = ( 30 f"{TEST_DATA}/jwt-policy/route-subroute/virtual-server-route-invalid-subroute.yaml" 31 ) 32 jwt_vsr_invalid_sec_src = ( 33 f"{TEST_DATA}/jwt-policy/route-subroute/virtual-server-route-invalid-subroute-secret.yaml" 34 ) 35 jwt_vsr_override_src = ( 36 f"{TEST_DATA}/jwt-policy/route-subroute/virtual-server-route-override-subroute.yaml" 37 ) 38 jwt_vsr_valid_src = ( 39 f"{TEST_DATA}/jwt-policy/route-subroute/virtual-server-route-valid-subroute.yaml" 40 ) 41 jwt_vsr_valid_multi_src = ( 42 f"{TEST_DATA}/jwt-policy/route-subroute/virtual-server-route-valid-subroute-multi.yaml" 43 ) 44 jwt_vs_override_spec_src = ( 45 f"{TEST_DATA}/jwt-policy/route-subroute/virtual-server-vsr-spec-override.yaml" 46 ) 47 jwt_vs_override_route_src = ( 48 f"{TEST_DATA}/jwt-policy/route-subroute/virtual-server-vsr-route-override.yaml" 49 ) 50 valid_token = f"{TEST_DATA}/jwt-policy/token.jwt" 51 invalid_token = f"{TEST_DATA}/jwt-policy/invalid-token.jwt" 52 53 54 @pytest.mark.skip_for_nginx_oss 55 @pytest.mark.policies 56 @pytest.mark.parametrize( 57 "crd_ingress_controller, v_s_route_setup", 58 [ 59 ( 60 { 61 "type": "complete", 62 "extra_args": [ 63 f"-enable-custom-resources", 64 f"-enable-preview-policies", 65 f"-enable-leader-election=false", 66 ], 67 }, 68 {"example": "virtual-server-route"}, 69 ) 70 ], 71 indirect=True, 72 ) 73 class TestJWTPoliciesVsr: 74 def setup_single_policy(self, kube_apis, namespace, token, secret, policy, vs_host): 75 print(f"Create jwk secret") 76 secret_name = create_secret_from_yaml(kube_apis.v1, namespace, secret) 77 78 print(f"Create jwt policy") 79 pol_name = create_policy_from_yaml(kube_apis.custom_objects, policy, namespace) 80 81 wait_before_test() 82 with open(token, "r") as file: 83 data = file.readline() 84 headers = {"host": vs_host, "token": data} 85 86 return secret_name, pol_name, headers 87 88 def setup_multiple_policies( 89 self, kube_apis, namespace, token, secret, policy_1, policy_2, vs_host 90 ): 91 print(f"Create jwk secret") 92 secret_name = create_secret_from_yaml(kube_apis.v1, namespace, secret) 93 94 print(f"Create jwt policy #1") 95 pol_name_1 = create_policy_from_yaml(kube_apis.custom_objects, policy_1, namespace) 96 print(f"Create jwt policy #2") 97 pol_name_2 = create_policy_from_yaml(kube_apis.custom_objects, policy_2, namespace) 98 99 wait_before_test() 100 with open(token, "r") as file: 101 data = file.readline() 102 headers = {"host": vs_host, "token": data} 103 104 return secret_name, pol_name_1, pol_name_2, headers 105 106 @pytest.mark.parametrize("token", [valid_token, invalid_token]) 107 def test_jwt_policy_token( 108 self, 109 kube_apis, 110 crd_ingress_controller, 111 v_s_route_app_setup, 112 v_s_route_setup, 113 test_namespace, 114 token, 115 ): 116 """ 117 Test jwt-policy with no token, valid token and invalid token 118 """ 119 req_url = f"http://{v_s_route_setup.public_endpoint.public_ip}:{v_s_route_setup.public_endpoint.port}" 120 secret, pol_name, headers = self.setup_single_policy( 121 kube_apis, 122 v_s_route_setup.route_m.namespace, 123 token, 124 jwk_sec_valid_src, 125 jwt_pol_valid_src, 126 v_s_route_setup.vs_host, 127 ) 128 129 print(f"Patch vsr with policy: {jwt_vsr_valid_src}") 130 patch_v_s_route_from_yaml( 131 kube_apis.custom_objects, 132 v_s_route_setup.route_m.name, 133 jwt_vsr_valid_src, 134 v_s_route_setup.route_m.namespace, 135 ) 136 wait_before_test() 137 138 resp1 = requests.get( 139 f"{req_url}{v_s_route_setup.route_m.paths[0]}", 140 headers={"host": v_s_route_setup.vs_host}, 141 ) 142 print(resp1.status_code) 143 144 resp2 = requests.get(f"{req_url}{v_s_route_setup.route_m.paths[0]}", headers=headers) 145 print(resp2.status_code) 146 147 delete_policy(kube_apis.custom_objects, pol_name, v_s_route_setup.route_m.namespace) 148 delete_secret(kube_apis.v1, secret, v_s_route_setup.route_m.namespace) 149 150 patch_v_s_route_from_yaml( 151 kube_apis.custom_objects, 152 v_s_route_setup.route_m.name, 153 std_vsr_src, 154 v_s_route_setup.route_m.namespace, 155 ) 156 157 assert resp1.status_code == 401 158 assert f"401 Authorization Required" in resp1.text 159 160 if token == valid_token: 161 assert resp2.status_code == 200 162 assert f"Request ID:" in resp2.text 163 else: 164 assert resp2.status_code == 401 165 assert f"Authorization Required" in resp2.text 166 167 @pytest.mark.parametrize("jwk_secret", [jwk_sec_valid_src, jwk_sec_invalid_src]) 168 def test_jwt_policy_secret( 169 self, 170 kube_apis, 171 crd_ingress_controller, 172 v_s_route_app_setup, 173 v_s_route_setup, 174 test_namespace, 175 jwk_secret, 176 ): 177 """ 178 Test jwt-policy with a valid and an invalid secret 179 """ 180 req_url = f"http://{v_s_route_setup.public_endpoint.public_ip}:{v_s_route_setup.public_endpoint.port}" 181 if jwk_secret == jwk_sec_valid_src: 182 pol = jwt_pol_valid_src 183 vsr = jwt_vsr_valid_src 184 elif jwk_secret == jwk_sec_invalid_src: 185 pol = jwt_pol_invalid_sec_src 186 vsr = jwt_vsr_invalid_sec_src 187 else: 188 pytest.fail(f"Not a valid case or parameter") 189 190 secret, pol_name, headers = self.setup_single_policy( 191 kube_apis, 192 v_s_route_setup.route_m.namespace, 193 valid_token, 194 jwk_secret, 195 pol, 196 v_s_route_setup.vs_host, 197 ) 198 199 print(f"Patch vsr with policy: {pol}") 200 patch_v_s_route_from_yaml( 201 kube_apis.custom_objects, 202 v_s_route_setup.route_m.name, 203 vsr, 204 v_s_route_setup.route_m.namespace, 205 ) 206 wait_before_test() 207 208 resp = requests.get(f"{req_url}{v_s_route_setup.route_m.paths[0]}", headers=headers,) 209 print(resp.status_code) 210 211 crd_info = read_custom_resource( 212 kube_apis.custom_objects, 213 v_s_route_setup.route_m.namespace, 214 "virtualserverroutes", 215 v_s_route_setup.route_m.name, 216 ) 217 delete_policy(kube_apis.custom_objects, pol_name, v_s_route_setup.route_m.namespace) 218 delete_secret(kube_apis.v1, secret, v_s_route_setup.route_m.namespace) 219 220 patch_v_s_route_from_yaml( 221 kube_apis.custom_objects, 222 v_s_route_setup.route_m.name, 223 std_vsr_src, 224 v_s_route_setup.route_m.namespace, 225 ) 226 227 if jwk_secret == jwk_sec_valid_src: 228 assert resp.status_code == 200 229 assert f"Request ID:" in resp.text 230 assert crd_info["status"]["state"] == "Valid" 231 elif jwk_secret == jwk_sec_invalid_src: 232 assert resp.status_code == 500 233 assert f"Internal Server Error" in resp.text 234 assert crd_info["status"]["state"] == "Warning" 235 else: 236 pytest.fail(f"Not a valid case or parameter") 237 238 @pytest.mark.smoke 239 @pytest.mark.parametrize("policy", [jwt_pol_valid_src, jwt_pol_invalid_src]) 240 def test_jwt_policy( 241 self, 242 kube_apis, 243 crd_ingress_controller, 244 v_s_route_app_setup, 245 v_s_route_setup, 246 test_namespace, 247 policy, 248 ): 249 """ 250 Test jwt-policy with a valid and an invalid policy 251 """ 252 req_url = f"http://{v_s_route_setup.public_endpoint.public_ip}:{v_s_route_setup.public_endpoint.port}" 253 if policy == jwt_pol_valid_src: 254 vsr = jwt_vsr_valid_src 255 elif policy == jwt_pol_invalid_src: 256 vsr = jwt_vsr_invalid_src 257 else: 258 pytest.fail(f"Not a valid case or parameter") 259 260 secret, pol_name, headers = self.setup_single_policy( 261 kube_apis, 262 v_s_route_setup.route_m.namespace, 263 valid_token, 264 jwk_sec_valid_src, 265 policy, 266 v_s_route_setup.vs_host, 267 ) 268 269 print(f"Patch vsr with policy: {policy}") 270 patch_v_s_route_from_yaml( 271 kube_apis.custom_objects, 272 v_s_route_setup.route_m.name, 273 vsr, 274 v_s_route_setup.route_m.namespace, 275 ) 276 wait_before_test() 277 278 resp = requests.get(f"{req_url}{v_s_route_setup.route_m.paths[0]}", headers=headers,) 279 print(resp.status_code) 280 policy_info = read_custom_resource( 281 kube_apis.custom_objects, v_s_route_setup.route_m.namespace, "policies", pol_name 282 ) 283 crd_info = read_custom_resource( 284 kube_apis.custom_objects, 285 v_s_route_setup.route_m.namespace, 286 "virtualserverroutes", 287 v_s_route_setup.route_m.name, 288 ) 289 delete_policy(kube_apis.custom_objects, pol_name, v_s_route_setup.route_m.namespace) 290 delete_secret(kube_apis.v1, secret, v_s_route_setup.route_m.namespace) 291 292 patch_v_s_route_from_yaml( 293 kube_apis.custom_objects, 294 v_s_route_setup.route_m.name, 295 std_vsr_src, 296 v_s_route_setup.route_m.namespace, 297 ) 298 299 if policy == jwt_pol_valid_src: 300 assert resp.status_code == 200 301 assert f"Request ID:" in resp.text 302 assert crd_info["status"]["state"] == "Valid" 303 assert ( 304 policy_info["status"] 305 and policy_info["status"]["reason"] == "AddedOrUpdated" 306 and policy_info["status"]["state"] == "Valid" 307 ) 308 elif policy == jwt_pol_invalid_src: 309 assert resp.status_code == 500 310 assert f"Internal Server Error" in resp.text 311 assert crd_info["status"]["state"] == "Warning" 312 assert ( 313 policy_info["status"] 314 and policy_info["status"]["reason"] == "Rejected" 315 and policy_info["status"]["state"] == "Invalid" 316 ) 317 else: 318 pytest.fail(f"Not a valid case or parameter") 319 320 def test_jwt_policy_delete_secret( 321 self, 322 kube_apis, 323 crd_ingress_controller, 324 v_s_route_app_setup, 325 v_s_route_setup, 326 test_namespace, 327 ): 328 """ 329 Test if requests result in 500 when secret is deleted 330 """ 331 req_url = f"http://{v_s_route_setup.public_endpoint.public_ip}:{v_s_route_setup.public_endpoint.port}" 332 secret, pol_name, headers = self.setup_single_policy( 333 kube_apis, 334 v_s_route_setup.route_m.namespace, 335 valid_token, 336 jwk_sec_valid_src, 337 jwt_pol_valid_src, 338 v_s_route_setup.vs_host, 339 ) 340 341 print(f"Patch vsr with policy: {jwt_pol_valid_src}") 342 patch_v_s_route_from_yaml( 343 kube_apis.custom_objects, 344 v_s_route_setup.route_m.name, 345 jwt_vsr_valid_src, 346 v_s_route_setup.route_m.namespace, 347 ) 348 wait_before_test() 349 350 resp1 = requests.get(f"{req_url}{v_s_route_setup.route_m.paths[0]}", headers=headers,) 351 print(resp1.status_code) 352 353 delete_secret(kube_apis.v1, secret, v_s_route_setup.route_m.namespace) 354 resp2 = requests.get(f"{req_url}{v_s_route_setup.route_m.paths[0]}", headers=headers,) 355 print(resp2.status_code) 356 crd_info = read_custom_resource( 357 kube_apis.custom_objects, 358 v_s_route_setup.route_m.namespace, 359 "virtualserverroutes", 360 v_s_route_setup.route_m.name, 361 ) 362 delete_policy(kube_apis.custom_objects, pol_name, v_s_route_setup.route_m.namespace) 363 364 patch_v_s_route_from_yaml( 365 kube_apis.custom_objects, 366 v_s_route_setup.route_m.name, 367 std_vsr_src, 368 v_s_route_setup.route_m.namespace, 369 ) 370 assert resp1.status_code == 200 371 assert f"Request ID:" in resp1.text 372 assert crd_info["status"]["state"] == "Warning" 373 assert ( 374 f"references an invalid secret {v_s_route_setup.route_m.namespace}/{secret}: secret doesn't exist or of an unsupported type" 375 in crd_info["status"]["message"] 376 ) 377 assert resp2.status_code == 500 378 assert f"Internal Server Error" in resp2.text 379 380 def test_jwt_policy_delete_policy( 381 self, 382 kube_apis, 383 crd_ingress_controller, 384 v_s_route_app_setup, 385 v_s_route_setup, 386 test_namespace, 387 ): 388 """ 389 Test if requests result in 500 when policy is deleted 390 """ 391 req_url = f"http://{v_s_route_setup.public_endpoint.public_ip}:{v_s_route_setup.public_endpoint.port}" 392 secret, pol_name, headers = self.setup_single_policy( 393 kube_apis, 394 v_s_route_setup.route_m.namespace, 395 valid_token, 396 jwk_sec_valid_src, 397 jwt_pol_valid_src, 398 v_s_route_setup.vs_host, 399 ) 400 401 print(f"Patch vsr with policy: {jwt_pol_valid_src}") 402 patch_v_s_route_from_yaml( 403 kube_apis.custom_objects, 404 v_s_route_setup.route_m.name, 405 jwt_vsr_valid_src, 406 v_s_route_setup.route_m.namespace, 407 ) 408 wait_before_test() 409 410 resp1 = requests.get(f"{req_url}{v_s_route_setup.route_m.paths[0]}", headers=headers,) 411 print(resp1.status_code) 412 delete_policy(kube_apis.custom_objects, pol_name, v_s_route_setup.route_m.namespace) 413 414 resp2 = requests.get(f"{req_url}{v_s_route_setup.route_m.paths[0]}", headers=headers,) 415 print(resp2.status_code) 416 crd_info = read_custom_resource( 417 kube_apis.custom_objects, 418 v_s_route_setup.route_m.namespace, 419 "virtualserverroutes", 420 v_s_route_setup.route_m.name, 421 ) 422 delete_secret(kube_apis.v1, secret, v_s_route_setup.route_m.namespace) 423 424 patch_v_s_route_from_yaml( 425 kube_apis.custom_objects, 426 v_s_route_setup.route_m.name, 427 std_vsr_src, 428 v_s_route_setup.route_m.namespace, 429 ) 430 assert resp1.status_code == 200 431 assert f"Request ID:" in resp1.text 432 assert crd_info["status"]["state"] == "Warning" 433 assert ( 434 f"{v_s_route_setup.route_m.namespace}/{pol_name} is missing" 435 in crd_info["status"]["message"] 436 ) 437 assert resp2.status_code == 500 438 assert f"Internal Server Error" in resp2.text 439 440 def test_jwt_policy_override( 441 self, 442 kube_apis, 443 crd_ingress_controller, 444 v_s_route_app_setup, 445 v_s_route_setup, 446 test_namespace, 447 ): 448 """ 449 Test if first reference to a policy in the same context(subroute) takes precedence, 450 i.e. in this case, policy without $httptoken over policy with $httptoken. 451 """ 452 req_url = f"http://{v_s_route_setup.public_endpoint.public_ip}:{v_s_route_setup.public_endpoint.port}" 453 secret, pol_name_1, pol_name_2, headers = self.setup_multiple_policies( 454 kube_apis, 455 v_s_route_setup.route_m.namespace, 456 valid_token, 457 jwk_sec_valid_src, 458 jwt_pol_valid_src, 459 jwt_pol_multi_src, 460 v_s_route_setup.vs_host, 461 ) 462 463 print(f"Patch vsr with policies: {jwt_pol_valid_src}") 464 patch_v_s_route_from_yaml( 465 kube_apis.custom_objects, 466 v_s_route_setup.route_m.name, 467 jwt_vsr_override_src, 468 v_s_route_setup.route_m.namespace, 469 ) 470 wait_before_test() 471 472 resp = requests.get(f"{req_url}{v_s_route_setup.route_m.paths[0]}", headers=headers,) 473 print(resp.status_code) 474 475 crd_info = read_custom_resource( 476 kube_apis.custom_objects, 477 v_s_route_setup.route_m.namespace, 478 "virtualserverroutes", 479 v_s_route_setup.route_m.name, 480 ) 481 delete_policy(kube_apis.custom_objects, pol_name_1, v_s_route_setup.route_m.namespace) 482 delete_policy(kube_apis.custom_objects, pol_name_2, v_s_route_setup.route_m.namespace) 483 delete_secret(kube_apis.v1, secret, v_s_route_setup.route_m.namespace) 484 485 patch_v_s_route_from_yaml( 486 kube_apis.custom_objects, 487 v_s_route_setup.route_m.name, 488 std_vsr_src, 489 v_s_route_setup.route_m.namespace, 490 ) 491 assert resp.status_code == 401 492 assert f"Authorization Required" in resp.text 493 assert ( 494 f"Multiple jwt policies in the same context is not valid." 495 in crd_info["status"]["message"] 496 ) 497 498 @pytest.mark.parametrize("vs_src", [jwt_vs_override_route_src, jwt_vs_override_spec_src]) 499 def test_jwt_policy_override_vs_vsr( 500 self, 501 kube_apis, 502 crd_ingress_controller, 503 v_s_route_app_setup, 504 v_s_route_setup, 505 test_namespace, 506 vs_src, 507 ): 508 """ 509 Test if policy specified in vsr:subroute (policy without $httptoken) takes preference over policy specified in: 510 1. vs:spec (policy with $httptoken) 511 2. vs:route (policy with $httptoken) 512 """ 513 req_url = f"http://{v_s_route_setup.public_endpoint.public_ip}:{v_s_route_setup.public_endpoint.port}" 514 secret, pol_name_1, pol_name_2, headers = self.setup_multiple_policies( 515 kube_apis, 516 v_s_route_setup.route_m.namespace, 517 valid_token, 518 jwk_sec_valid_src, 519 jwt_pol_valid_src, 520 jwt_pol_multi_src, 521 v_s_route_setup.vs_host, 522 ) 523 524 print(f"Patch vsr with policies: {jwt_pol_valid_src}") 525 patch_v_s_route_from_yaml( 526 kube_apis.custom_objects, 527 v_s_route_setup.route_m.name, 528 jwt_vsr_valid_multi_src, 529 v_s_route_setup.route_m.namespace, 530 ) 531 patch_virtual_server_from_yaml( 532 kube_apis.custom_objects, v_s_route_setup.vs_name, vs_src, v_s_route_setup.namespace, 533 ) 534 wait_before_test() 535 536 resp = requests.get(f"{req_url}{v_s_route_setup.route_m.paths[0]}", headers=headers,) 537 print(resp.status_code) 538 539 delete_policy(kube_apis.custom_objects, pol_name_1, v_s_route_setup.route_m.namespace) 540 delete_policy(kube_apis.custom_objects, pol_name_2, v_s_route_setup.route_m.namespace) 541 delete_secret(kube_apis.v1, secret, v_s_route_setup.route_m.namespace) 542 543 patch_v_s_route_from_yaml( 544 kube_apis.custom_objects, 545 v_s_route_setup.route_m.name, 546 std_vsr_src, 547 v_s_route_setup.route_m.namespace, 548 ) 549 patch_virtual_server_from_yaml( 550 kube_apis.custom_objects, v_s_route_setup.vs_name, std_vs_src, v_s_route_setup.namespace 551 ) 552 assert resp.status_code == 401 553 assert f"Authorization Required" in resp.text