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)