github.com/nginxinc/kubernetes-ingress@v1.12.5/tests/suite/test_hsts.py (about)

     1  import pytest
     2  import requests
     3  
     4  from suite.fixtures import PublicEndpoint
     5  from suite.resources_utils import ensure_connection_to_public_endpoint, \
     6      create_example_app, wait_until_all_pods_are_ready, \
     7      delete_common_app, create_items_from_yaml, delete_items_from_yaml, \
     8      wait_before_test, ensure_response_from_backend, \
     9      generate_ingresses_with_annotation, replace_ingress
    10  from suite.yaml_utils import get_first_ingress_host_from_yaml, get_name_from_yaml
    11  from settings import TEST_DATA
    12  
    13  
    14  class HSTSSetup:
    15      """Encapsulate HSTS example details.
    16  
    17      Attributes:
    18          public_endpoint: PublicEndpoint
    19          ingress_name:
    20          ingress_host:
    21          namespace: example namespace
    22      """
    23      def __init__(self, public_endpoint: PublicEndpoint, ingress_src_file, ingress_name, ingress_host, namespace):
    24          self.public_endpoint = public_endpoint
    25          self.ingress_name = ingress_name
    26          self.ingress_host = ingress_host
    27          self.ingress_src_file = ingress_src_file
    28          self.namespace = namespace
    29          self.https_url = f"https://{public_endpoint.public_ip}:{public_endpoint.port_ssl}"
    30          self.http_url = f"http://{public_endpoint.public_ip}:{public_endpoint.port}"
    31  
    32  
    33  @pytest.fixture(scope="class")
    34  def hsts_setup(request,
    35                 kube_apis,
    36                 ingress_controller_prerequisites,
    37                 ingress_controller_endpoint, ingress_controller, test_namespace) -> HSTSSetup:
    38      print("------------------------- Deploy HSTS-Example -----------------------------------")
    39      create_items_from_yaml(kube_apis,
    40                             f"{TEST_DATA}/hsts/{request.param}/hsts-ingress.yaml",
    41                             test_namespace)
    42      ingress_name = get_name_from_yaml(f"{TEST_DATA}/hsts/{request.param}/hsts-ingress.yaml")
    43      ingress_host = get_first_ingress_host_from_yaml(f"{TEST_DATA}/hsts/{request.param}/hsts-ingress.yaml")
    44      create_example_app(kube_apis, "simple", test_namespace)
    45      wait_until_all_pods_are_ready(kube_apis.v1, test_namespace)
    46      ensure_connection_to_public_endpoint(ingress_controller_endpoint.public_ip,
    47                                           ingress_controller_endpoint.port,
    48                                           ingress_controller_endpoint.port_ssl)
    49      req_https_url = f"https://{ingress_controller_endpoint.public_ip}:" \
    50          f"{ingress_controller_endpoint.port_ssl}/backend1"
    51      ensure_response_from_backend(req_https_url, ingress_host)
    52  
    53      def fin():
    54          print("Clean up HSTS Example:")
    55          delete_common_app(kube_apis, "simple", test_namespace)
    56          delete_items_from_yaml(kube_apis,
    57                                 f"{TEST_DATA}/hsts/{request.param}/hsts-ingress.yaml",
    58                                 test_namespace)
    59  
    60      request.addfinalizer(fin)
    61  
    62      return HSTSSetup(ingress_controller_endpoint,
    63                       f"{TEST_DATA}/hsts/{request.param}/hsts-ingress.yaml",
    64                       ingress_name, ingress_host, test_namespace)
    65  
    66  
    67  @pytest.mark.ingresses
    68  @pytest.mark.parametrize('hsts_setup', ["standard-tls", "mergeable-tls"], indirect=True)
    69  class TestTLSHSTSFlows:
    70      def test_headers(self, kube_apis, hsts_setup, ingress_controller_prerequisites):
    71          print("\nCase 1: TLS enabled, secret is in place, hsts is True, hsts-behind-proxy is False")
    72          annotations = {"nginx.org/hsts-behind-proxy": "False"}
    73          new_ing = generate_ingresses_with_annotation(hsts_setup.ingress_src_file, annotations)
    74          for ing in new_ing:
    75              if ing['metadata']['name'] == hsts_setup.ingress_name:
    76                  replace_ingress(kube_apis.extensions_v1_beta1,
    77                                  hsts_setup.ingress_name, hsts_setup.namespace, ing)
    78          wait_before_test(1)
    79  
    80          https_headers = {"host": hsts_setup.ingress_host}
    81          http_headers = {"host": hsts_setup.ingress_host}
    82          https_resp = requests.get(f"{hsts_setup.https_url}/backend1", headers=https_headers, verify=False)
    83          http_resp = requests.get(f"{hsts_setup.http_url}/backend1", headers=http_headers, allow_redirects=False)
    84  
    85          assert "'Strict-Transport-Security': 'max-age=2592000; preload'" in str(https_resp.headers)
    86          assert "'Strict-Transport-Security'" not in str(http_resp.headers)
    87  
    88          print("Case 3: TLS enabled, secret is in place, hsts is True, hsts-behind-proxy is True")
    89          annotations = {"nginx.org/hsts-behind-proxy": "True"}
    90          new_ing = generate_ingresses_with_annotation(hsts_setup.ingress_src_file, annotations)
    91          for ing in new_ing:
    92              if ing['metadata']['name'] == hsts_setup.ingress_name:
    93                  replace_ingress(kube_apis.extensions_v1_beta1,
    94                                  hsts_setup.ingress_name, hsts_setup.namespace, ing)
    95          wait_before_test(1)
    96  
    97          xfp_https_headers = {"host": hsts_setup.ingress_host, "X-Forwarded-Proto": "https"}
    98          xfp_http_headers = {"host": hsts_setup.ingress_host, "X-Forwarded-Proto": "http"}
    99          xfp_https_resp = requests.get(f"{hsts_setup.https_url}/backend1", headers=xfp_https_headers, verify=False)
   100          xfp_http_resp = requests.get(f"{hsts_setup.https_url}/backend1", headers=xfp_http_headers, verify=False)
   101  
   102          assert "'Strict-Transport-Security': 'max-age=2592000; preload'" in str(xfp_https_resp.headers)
   103          assert "'Strict-Transport-Security'" not in str(xfp_http_resp.headers)
   104  
   105  
   106  @pytest.mark.ingresses
   107  @pytest.mark.parametrize('hsts_setup', ["tls-no-secret"], indirect=True)
   108  class TestBrokenTLSHSTSFlows:
   109      def test_headers_without_secret(self, kube_apis, hsts_setup, ingress_controller_prerequisites):
   110          print("\nCase 2: TLS enabled, secret is NOT in place, hsts is True, hsts-behind-proxy is default (False)")
   111          https_headers = {"host": hsts_setup.ingress_host}
   112          http_headers = {"host": hsts_setup.ingress_host}
   113          https_resp = requests.get(f"{hsts_setup.https_url}/backend1", headers=https_headers, verify=False)
   114          http_resp = requests.get(f"{hsts_setup.http_url}/backend1", headers=http_headers, allow_redirects=False)
   115  
   116          assert "'Strict-Transport-Security': 'max-age=2592000; preload'" in str(https_resp.headers)
   117          assert "'Strict-Transport-Security'" not in str(http_resp.headers)
   118  
   119  
   120  @pytest.mark.ingresses
   121  @pytest.mark.parametrize('hsts_setup', ["standard", "mergeable"], indirect=True)
   122  class TestNoTLSHSTS:
   123      def test_headers(self, kube_apis, hsts_setup, ingress_controller_prerequisites):
   124          print("Case 4: no TLS, hsts is True, hsts-behind-proxy is True")
   125          annotations = {"nginx.org/hsts-behind-proxy": "True"}
   126          new_ing = generate_ingresses_with_annotation(hsts_setup.ingress_src_file, annotations)
   127          for ing in new_ing:
   128              if ing['metadata']['name'] == hsts_setup.ingress_name:
   129                  replace_ingress(kube_apis.extensions_v1_beta1,
   130                                  hsts_setup.ingress_name, hsts_setup.namespace, ing)
   131          wait_before_test(1)
   132  
   133          xfp_https_headers = {"host": hsts_setup.ingress_host, "X-Forwarded-Proto": "https"}
   134          xfp_http_headers = {"host": hsts_setup.ingress_host, "X-Forwarded-Proto": "http"}
   135          xfp_https_resp = requests.get(f"{hsts_setup.http_url}/backend1", headers=xfp_https_headers,
   136                                        allow_redirects=False)
   137          xfp_http_resp = requests.get(f"{hsts_setup.http_url}/backend1", headers=xfp_http_headers,
   138                                       allow_redirects=False)
   139  
   140          assert "'Strict-Transport-Security': 'max-age=2592000; preload'" in str(xfp_https_resp.headers)
   141          assert "'Strict-Transport-Security'" not in str(xfp_http_resp.headers)