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