github.com/nginxinc/kubernetes-ingress@v1.12.5/tests/suite/test_jwt_policies.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 create_virtual_server_from_yaml, 14 delete_and_create_vs_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/standard/virtual-server.yaml" 22 jwk_sec_valid_src = f"{TEST_DATA}/jwt-policy/secret/jwk-secret-valid.yaml" 23 jwk_sec_invalid_src = f"{TEST_DATA}/jwt-policy/secret/jwk-secret-invalid.yaml" 24 jwt_pol_valid_src = f"{TEST_DATA}/jwt-policy/policies/jwt-policy-valid.yaml" 25 jwt_pol_multi_src = f"{TEST_DATA}/jwt-policy/policies/jwt-policy-valid-multi.yaml" 26 jwt_vs_single_src = f"{TEST_DATA}/jwt-policy/spec/virtual-server-policy-single.yaml" 27 jwt_vs_single_invalid_pol_src = ( 28 f"{TEST_DATA}/jwt-policy/spec/virtual-server-policy-single-invalid-pol.yaml" 29 ) 30 jwt_vs_multi_1_src = f"{TEST_DATA}/jwt-policy/spec/virtual-server-policy-multi-1.yaml" 31 jwt_vs_multi_2_src = f"{TEST_DATA}/jwt-policy/spec/virtual-server-policy-multi-2.yaml" 32 jwt_pol_invalid_src = f"{TEST_DATA}/jwt-policy/policies/jwt-policy-invalid.yaml" 33 jwt_pol_invalid_sec_src = f"{TEST_DATA}/jwt-policy/policies/jwt-policy-invalid-secret.yaml" 34 jwt_vs_single_invalid_sec_src = ( 35 f"{TEST_DATA}/jwt-policy/spec/virtual-server-policy-single-invalid-secret.yaml" 36 ) 37 jwt_vs_override_route = f"{TEST_DATA}/jwt-policy/route-subroute/virtual-server-override-route.yaml" 38 jwt_vs_override_spec_route_1 = ( 39 f"{TEST_DATA}/jwt-policy/route-subroute/virtual-server-override-spec-route-1.yaml" 40 ) 41 jwt_vs_override_spec_route_2 = ( 42 f"{TEST_DATA}/jwt-policy/route-subroute/virtual-server-override-spec-route-2.yaml" 43 ) 44 valid_token = f"{TEST_DATA}/jwt-policy/token.jwt" 45 invalid_token = f"{TEST_DATA}/jwt-policy/invalid-token.jwt" 46 47 48 @pytest.mark.skip_for_nginx_oss 49 @pytest.mark.policies 50 @pytest.mark.parametrize( 51 "crd_ingress_controller, virtual_server_setup", 52 [ 53 ( 54 { 55 "type": "complete", 56 "extra_args": [ 57 f"-enable-custom-resources", 58 f"-enable-preview-policies", 59 f"-enable-leader-election=false", 60 ], 61 }, 62 {"example": "virtual-server", "app_type": "simple",}, 63 ) 64 ], 65 indirect=True, 66 ) 67 class TestJWTPolicies: 68 def setup_single_policy(self, kube_apis, test_namespace, token, secret, policy, vs_host): 69 print(f"Create jwk secret") 70 secret_name = create_secret_from_yaml(kube_apis.v1, test_namespace, secret) 71 72 print(f"Create jwt policy") 73 pol_name = create_policy_from_yaml(kube_apis.custom_objects, policy, test_namespace) 74 wait_before_test() 75 76 with open(token, "r") as file: 77 data = file.readline() 78 headers = {"host": vs_host, "token": data} 79 80 return secret_name, pol_name, headers 81 82 def setup_multiple_policies( 83 self, kube_apis, test_namespace, token, secret, policy_1, policy_2, vs_host 84 ): 85 print(f"Create jwk secret") 86 secret_name = create_secret_from_yaml(kube_apis.v1, test_namespace, secret) 87 88 print(f"Create jwt policy #1") 89 pol_name_1 = create_policy_from_yaml(kube_apis.custom_objects, policy_1, test_namespace) 90 print(f"Create jwt policy #2") 91 pol_name_2 = create_policy_from_yaml(kube_apis.custom_objects, policy_2, test_namespace) 92 93 wait_before_test() 94 with open(token, "r") as file: 95 data = file.readline() 96 headers = {"host": vs_host, "token": data} 97 98 return secret_name, pol_name_1, pol_name_2, headers 99 100 @pytest.mark.parametrize("token", [valid_token, invalid_token]) 101 def test_jwt_policy_token( 102 self, kube_apis, crd_ingress_controller, virtual_server_setup, test_namespace, token, 103 ): 104 """ 105 Test jwt-policy with no token, valid token and invalid token 106 """ 107 secret, pol_name, headers = self.setup_single_policy( 108 kube_apis, 109 test_namespace, 110 token, 111 jwk_sec_valid_src, 112 jwt_pol_valid_src, 113 virtual_server_setup.vs_host, 114 ) 115 116 print(f"Patch vs with policy: {jwt_vs_single_src}") 117 delete_and_create_vs_from_yaml( 118 kube_apis.custom_objects, 119 virtual_server_setup.vs_name, 120 jwt_vs_single_src, 121 virtual_server_setup.namespace, 122 ) 123 wait_before_test() 124 125 resp1 = requests.get( 126 virtual_server_setup.backend_1_url, headers={"host": virtual_server_setup.vs_host}, 127 ) 128 print(resp1.status_code) 129 130 resp2 = requests.get(virtual_server_setup.backend_1_url, headers=headers) 131 print(resp2.status_code) 132 133 delete_policy(kube_apis.custom_objects, pol_name, test_namespace) 134 delete_secret(kube_apis.v1, secret, test_namespace) 135 136 delete_and_create_vs_from_yaml( 137 kube_apis.custom_objects, 138 virtual_server_setup.vs_name, 139 std_vs_src, 140 virtual_server_setup.namespace, 141 ) 142 143 assert resp1.status_code == 401 144 assert f"401 Authorization Required" in resp1.text 145 146 if token == valid_token: 147 assert resp2.status_code == 200 148 assert f"Request ID:" in resp2.text 149 else: 150 assert resp2.status_code == 401 151 assert f"Authorization Required" in resp2.text 152 153 @pytest.mark.parametrize("jwk_secret", [jwk_sec_valid_src, jwk_sec_invalid_src]) 154 def test_jwt_policy_secret( 155 self, kube_apis, crd_ingress_controller, virtual_server_setup, test_namespace, jwk_secret, 156 ): 157 """ 158 Test jwt-policy with a valid and an invalid secret 159 """ 160 if jwk_secret == jwk_sec_valid_src: 161 pol = jwt_pol_valid_src 162 vs = jwt_vs_single_src 163 elif jwk_secret == jwk_sec_invalid_src: 164 pol = jwt_pol_invalid_sec_src 165 vs = jwt_vs_single_invalid_sec_src 166 else: 167 pytest.fail("Invalid configuration") 168 secret, pol_name, headers = self.setup_single_policy( 169 kube_apis, test_namespace, valid_token, jwk_secret, pol, virtual_server_setup.vs_host, 170 ) 171 172 print(f"Patch vs with policy: {jwt_vs_single_src}") 173 delete_and_create_vs_from_yaml( 174 kube_apis.custom_objects, 175 virtual_server_setup.vs_name, 176 vs, 177 virtual_server_setup.namespace, 178 ) 179 wait_before_test() 180 181 resp = requests.get(virtual_server_setup.backend_1_url, headers=headers) 182 print(resp.status_code) 183 184 crd_info = read_custom_resource( 185 kube_apis.custom_objects, 186 virtual_server_setup.namespace, 187 "virtualservers", 188 virtual_server_setup.vs_name, 189 ) 190 delete_policy(kube_apis.custom_objects, pol_name, test_namespace) 191 delete_secret(kube_apis.v1, secret, test_namespace) 192 193 delete_and_create_vs_from_yaml( 194 kube_apis.custom_objects, 195 virtual_server_setup.vs_name, 196 std_vs_src, 197 virtual_server_setup.namespace, 198 ) 199 200 if jwk_secret == jwk_sec_valid_src: 201 assert resp.status_code == 200 202 assert f"Request ID:" in resp.text 203 assert crd_info["status"]["state"] == "Valid" 204 elif jwk_secret == jwk_sec_invalid_src: 205 assert resp.status_code == 500 206 assert f"Internal Server Error" in resp.text 207 assert crd_info["status"]["state"] == "Warning" 208 else: 209 pytest.fail(f"Not a valid case or parameter") 210 211 @pytest.mark.smoke 212 @pytest.mark.parametrize("policy", [jwt_pol_valid_src, jwt_pol_invalid_src]) 213 def test_jwt_policy( 214 self, kube_apis, crd_ingress_controller, virtual_server_setup, test_namespace, policy, 215 ): 216 """ 217 Test jwt-policy with a valid and an invalid policy 218 """ 219 secret, pol_name, headers = self.setup_single_policy( 220 kube_apis, 221 test_namespace, 222 valid_token, 223 jwk_sec_valid_src, 224 policy, 225 virtual_server_setup.vs_host, 226 ) 227 228 print(f"Patch vs with policy: {policy}") 229 policy_info = read_custom_resource(kube_apis.custom_objects, test_namespace, "policies", pol_name) 230 if policy == jwt_pol_valid_src: 231 vs_src = jwt_vs_single_src 232 assert ( 233 policy_info["status"] 234 and policy_info["status"]["reason"] == "AddedOrUpdated" 235 and policy_info["status"]["state"] == "Valid" 236 ) 237 elif policy == jwt_pol_invalid_src: 238 vs_src = jwt_vs_single_invalid_pol_src 239 assert ( 240 policy_info["status"] 241 and policy_info["status"]["reason"] == "Rejected" 242 and policy_info["status"]["state"] == "Invalid" 243 ) 244 else: 245 pytest.fail("Invalid configuration") 246 247 delete_and_create_vs_from_yaml( 248 kube_apis.custom_objects, 249 virtual_server_setup.vs_name, 250 vs_src, 251 virtual_server_setup.namespace, 252 ) 253 wait_before_test() 254 resp = requests.get(virtual_server_setup.backend_1_url, headers=headers) 255 print(resp.status_code) 256 crd_info = read_custom_resource( 257 kube_apis.custom_objects, 258 virtual_server_setup.namespace, 259 "virtualservers", 260 virtual_server_setup.vs_name, 261 ) 262 delete_policy(kube_apis.custom_objects, pol_name, test_namespace) 263 delete_secret(kube_apis.v1, secret, test_namespace) 264 265 delete_and_create_vs_from_yaml( 266 kube_apis.custom_objects, 267 virtual_server_setup.vs_name, 268 std_vs_src, 269 virtual_server_setup.namespace, 270 ) 271 272 if policy == jwt_pol_valid_src: 273 assert resp.status_code == 200 274 assert f"Request ID:" in resp.text 275 assert crd_info["status"]["state"] == "Valid" 276 elif policy == jwt_pol_invalid_src: 277 assert resp.status_code == 500 278 assert f"Internal Server Error" in resp.text 279 assert crd_info["status"]["state"] == "Warning" 280 else: 281 pytest.fail(f"Not a valid case or parameter") 282 283 def test_jwt_policy_delete_secret( 284 self, kube_apis, crd_ingress_controller, virtual_server_setup, test_namespace, 285 ): 286 """ 287 Test if requests result in 500 when secret is deleted 288 """ 289 secret, pol_name, headers = self.setup_single_policy( 290 kube_apis, 291 test_namespace, 292 valid_token, 293 jwk_sec_valid_src, 294 jwt_pol_valid_src, 295 virtual_server_setup.vs_host, 296 ) 297 298 print(f"Patch vs with policy: {jwt_pol_valid_src}") 299 delete_and_create_vs_from_yaml( 300 kube_apis.custom_objects, 301 virtual_server_setup.vs_name, 302 jwt_vs_single_src, 303 virtual_server_setup.namespace, 304 ) 305 wait_before_test() 306 307 resp1 = requests.get(virtual_server_setup.backend_1_url, headers=headers) 308 print(resp1.status_code) 309 310 delete_secret(kube_apis.v1, secret, test_namespace) 311 resp2 = requests.get(virtual_server_setup.backend_1_url, headers=headers) 312 print(resp2.status_code) 313 314 delete_policy(kube_apis.custom_objects, pol_name, test_namespace) 315 316 delete_and_create_vs_from_yaml( 317 kube_apis.custom_objects, 318 virtual_server_setup.vs_name, 319 std_vs_src, 320 virtual_server_setup.namespace, 321 ) 322 323 assert resp1.status_code == 200 324 assert resp2.status_code == 500 325 326 def test_jwt_policy_delete_policy( 327 self, kube_apis, crd_ingress_controller, virtual_server_setup, test_namespace, 328 ): 329 """ 330 Test if requests result in 500 when policy is deleted 331 """ 332 secret, pol_name, headers = self.setup_single_policy( 333 kube_apis, 334 test_namespace, 335 valid_token, 336 jwk_sec_valid_src, 337 jwt_pol_valid_src, 338 virtual_server_setup.vs_host, 339 ) 340 341 print(f"Patch vs with policy: {jwt_pol_valid_src}") 342 delete_and_create_vs_from_yaml( 343 kube_apis.custom_objects, 344 virtual_server_setup.vs_name, 345 jwt_vs_single_src, 346 virtual_server_setup.namespace, 347 ) 348 wait_before_test() 349 350 resp1 = requests.get(virtual_server_setup.backend_1_url, headers=headers) 351 print(resp1.status_code) 352 353 delete_policy(kube_apis.custom_objects, pol_name, test_namespace) 354 355 resp2 = requests.get(virtual_server_setup.backend_1_url, headers=headers) 356 print(resp2.status_code) 357 358 delete_secret(kube_apis.v1, secret, test_namespace) 359 360 delete_and_create_vs_from_yaml( 361 kube_apis.custom_objects, 362 virtual_server_setup.vs_name, 363 std_vs_src, 364 virtual_server_setup.namespace, 365 ) 366 367 assert resp1.status_code == 200 368 assert resp2.status_code == 500 369 370 def test_jwt_policy_override( 371 self, kube_apis, crd_ingress_controller, virtual_server_setup, test_namespace, 372 ): 373 """ 374 Test if first reference to a policy in the same context takes precedence 375 """ 376 secret, pol_name_1, pol_name_2, headers = self.setup_multiple_policies( 377 kube_apis, 378 test_namespace, 379 valid_token, 380 jwk_sec_valid_src, 381 jwt_pol_valid_src, 382 jwt_pol_multi_src, 383 virtual_server_setup.vs_host, 384 ) 385 386 print(f"Patch vs with multiple policy in spec context") 387 print(f"Patch vs with policy in order: {jwt_pol_multi_src} and {jwt_pol_valid_src}") 388 delete_and_create_vs_from_yaml( 389 kube_apis.custom_objects, 390 virtual_server_setup.vs_name, 391 jwt_vs_multi_1_src, 392 virtual_server_setup.namespace, 393 ) 394 wait_before_test() 395 396 resp1 = requests.get(virtual_server_setup.backend_1_url, headers=headers) 397 print(resp1.status_code) 398 399 print(f"Patch vs with policy in order: {jwt_pol_valid_src} and {jwt_pol_multi_src}") 400 delete_and_create_vs_from_yaml( 401 kube_apis.custom_objects, 402 virtual_server_setup.vs_name, 403 jwt_vs_multi_2_src, 404 virtual_server_setup.namespace, 405 ) 406 wait_before_test() 407 resp2 = requests.get(virtual_server_setup.backend_1_url, headers=headers) 408 print(resp2.status_code) 409 410 print(f"Patch vs with multiple policy in route context") 411 delete_and_create_vs_from_yaml( 412 kube_apis.custom_objects, 413 virtual_server_setup.vs_name, 414 jwt_vs_override_route, 415 virtual_server_setup.namespace, 416 ) 417 wait_before_test() 418 resp3 = requests.get(virtual_server_setup.backend_1_url, headers=headers) 419 print(resp3.status_code) 420 421 delete_policy(kube_apis.custom_objects, pol_name_1, test_namespace) 422 delete_policy(kube_apis.custom_objects, pol_name_2, test_namespace) 423 delete_secret(kube_apis.v1, secret, test_namespace) 424 425 delete_and_create_vs_from_yaml( 426 kube_apis.custom_objects, 427 virtual_server_setup.vs_name, 428 std_vs_src, 429 virtual_server_setup.namespace, 430 ) 431 432 assert ( 433 resp1.status_code == 401 434 ) # 401 unauthorized, since no token is attached to policy in spec context 435 assert resp2.status_code == 200 436 assert ( 437 resp3.status_code == 401 438 ) # 401 unauthorized, since no token is attached to policy in route context 439 440 def test_jwt_policy_override_spec( 441 self, kube_apis, crd_ingress_controller, virtual_server_setup, test_namespace, 442 ): 443 """ 444 Test if policy reference in route takes precedence over policy in spec 445 """ 446 secret, pol_name_1, pol_name_2, headers = self.setup_multiple_policies( 447 kube_apis, 448 test_namespace, 449 valid_token, 450 jwk_sec_valid_src, 451 jwt_pol_valid_src, 452 jwt_pol_multi_src, 453 virtual_server_setup.vs_host, 454 ) 455 456 print(f"Patch vs with invalid policy in route and valid policy in spec") 457 delete_and_create_vs_from_yaml( 458 kube_apis.custom_objects, 459 virtual_server_setup.vs_name, 460 jwt_vs_override_spec_route_1, 461 virtual_server_setup.namespace, 462 ) 463 wait_before_test() 464 465 resp1 = requests.get(virtual_server_setup.backend_1_url, headers=headers) 466 print(resp1.status_code) 467 468 print(f"Patch vs with valid policy in route and invalid policy in spec") 469 delete_and_create_vs_from_yaml( 470 kube_apis.custom_objects, 471 virtual_server_setup.vs_name, 472 jwt_vs_override_spec_route_2, 473 virtual_server_setup.namespace, 474 ) 475 wait_before_test() 476 resp2 = requests.get(virtual_server_setup.backend_1_url, headers=headers) 477 print(resp2.status_code) 478 479 delete_policy(kube_apis.custom_objects, pol_name_1, test_namespace) 480 delete_policy(kube_apis.custom_objects, pol_name_2, test_namespace) 481 delete_secret(kube_apis.v1, secret, test_namespace) 482 483 delete_and_create_vs_from_yaml( 484 kube_apis.custom_objects, 485 virtual_server_setup.vs_name, 486 std_vs_src, 487 virtual_server_setup.namespace, 488 ) 489 490 assert resp1.status_code == 401 # 401 unauthorized, since no token is attached to policy 491 assert resp2.status_code == 200