From a5b56f59985d05037e605ced289d833733172348 Mon Sep 17 00:00:00 2001 From: ikethecoder Date: Thu, 14 Nov 2024 16:56:32 -0800 Subject: [PATCH] refactor upstream validator --- .../test_validate_upstream.py} | 2 +- microservices/gatewayApi/utils/validators.py | 56 ++++++++++++++++++ microservices/gatewayApi/v1/routes/gateway.py | 59 +------------------ microservices/gatewayApi/v2/routes/gateway.py | 58 +----------------- 4 files changed, 59 insertions(+), 116 deletions(-) rename microservices/gatewayApi/tests/{routes/v1/test_v1_validate_upstream.py => utils/test_validate_upstream.py} (98%) diff --git a/microservices/gatewayApi/tests/routes/v1/test_v1_validate_upstream.py b/microservices/gatewayApi/tests/utils/test_validate_upstream.py similarity index 98% rename from microservices/gatewayApi/tests/routes/v1/test_v1_validate_upstream.py rename to microservices/gatewayApi/tests/utils/test_validate_upstream.py index b71c29a..8aec218 100644 --- a/microservices/gatewayApi/tests/routes/v1/test_v1_validate_upstream.py +++ b/microservices/gatewayApi/tests/utils/test_validate_upstream.py @@ -6,7 +6,7 @@ import yaml import pytest -from v1.routes.gateway import validate_upstream +from utils.validators import validate_upstream def test_upstream_good(app): payload = ''' diff --git a/microservices/gatewayApi/utils/validators.py b/microservices/gatewayApi/utils/validators.py index bfbf752..09c3b01 100644 --- a/microservices/gatewayApi/utils/validators.py +++ b/microservices/gatewayApi/utils/validators.py @@ -1,5 +1,6 @@ import re +from urllib.parse import urlparse namespace_validation_rule='^[a-z][a-z0-9-]{4,14}$' @@ -16,3 +17,58 @@ def host_valid(input_string): # match = regex.match(str(input_string)) # return bool(match is not None) +def validate_upstream(yaml, ns_attributes, protected_kube_namespaces, do_validate_upstreams: bool = False): + errors = [] + + perm_upstreams = ns_attributes.get('perm-upstreams', []) + + allow_protected_ns = ns_attributes.get('perm-protected-ns', ['deny'])[0] == 'allow' + + # A service host must not contain a list of protected + if 'services' in yaml: + for service in yaml['services']: + if 'url' in service: + try: + u = urlparse(service["url"]) + if u.hostname is None: + errors.append("service upstream has invalid url specified (e1)") + else: + validate_upstream_host(u.hostname, errors, allow_protected_ns, protected_kube_namespaces, do_validate_upstreams, perm_upstreams) + except Exception as e: + errors.append("service upstream has invalid url specified (e2)") + + if 'host' in service: + host = service["host"] + validate_upstream_host(host, errors, allow_protected_ns, protected_kube_namespaces, do_validate_upstreams, perm_upstreams) + + if len(errors) != 0: + raise Exception('\n'.join(errors)) + + +def validate_upstream_host(_host, errors, allow_protected_ns, protected_kube_namespaces, do_validate_upstreams, perm_upstreams): + host = _host.lower() + + restricted = ['localhost', '127.0.0.1', '0.0.0.0'] + + if host in restricted: + errors.append("service upstream is invalid (e1)") + elif host.endswith('svc'): + partials = host.split('.') + # get the namespace, and make sure it is not in the protected_kube_namespaces list + if len(partials) != 3: + errors.append("service upstream is invalid (e2)") + elif partials[1] in protected_kube_namespaces and allow_protected_ns is False: + errors.append("service upstream is invalid (e3)") + elif do_validate_upstreams and (partials[1] in perm_upstreams) is False: + errors.append("service upstream is invalid (e6)") + elif host.endswith('svc.cluster.local'): + partials = host.split('.') + # get the namespace, and make sure it is not in the protected_kube_namespaces list + if len(partials) != 5: + errors.append("service upstream is invalid (e4)") + elif partials[1] in protected_kube_namespaces and allow_protected_ns is False: + errors.append("service upstream is invalid (e5)") + elif do_validate_upstreams and (partials[1] in perm_upstreams) is False: + errors.append("service upstream is invalid (e6)") + elif do_validate_upstreams: + errors.append("service upstream is invalid (e6)") diff --git a/microservices/gatewayApi/v1/routes/gateway.py b/microservices/gatewayApi/v1/routes/gateway.py index 10906cb..2a5932a 100644 --- a/microservices/gatewayApi/v1/routes/gateway.py +++ b/microservices/gatewayApi/v1/routes/gateway.py @@ -24,7 +24,7 @@ from clients.ocp_routes import get_host_list, get_route_overrides from clients.ocp_gateway_secret import prep_submitted_config, prep_and_apply_secret, write_submitted_config -from utils.validators import host_valid +from utils.validators import host_valid, validate_upstream from utils.transforms import plugins_transformations from utils.masking import mask @@ -484,63 +484,6 @@ def transform_host(host): else: return host - -def validate_upstream(yaml, ns_attributes, protected_kube_namespaces, do_validate_upstreams: bool = False): - errors = [] - - perm_upstreams = ns_attributes.get('perm-upstreams', []) - - allow_protected_ns = ns_attributes.get('perm-protected-ns', ['deny'])[0] == 'allow' - - # A host must not contain a list of protected - if 'services' in yaml: - for service in yaml['services']: - if 'url' in service: - try: - u = urlparse(service["url"]) - if u.hostname is None: - errors.append("service upstream has invalid url specified (e1)") - else: - validate_upstream_host(u.hostname, errors, allow_protected_ns, protected_kube_namespaces, do_validate_upstreams, perm_upstreams) - except Exception as e: - errors.append("service upstream has invalid url specified (e2)") - - if 'host' in service: - host = service["host"] - validate_upstream_host(host, errors, allow_protected_ns, protected_kube_namespaces, do_validate_upstreams, perm_upstreams) - - if len(errors) != 0: - raise Exception('\n'.join(errors)) - - -def validate_upstream_host(_host, errors, allow_protected_ns, protected_kube_namespaces, do_validate_upstreams, perm_upstreams): - host = _host.lower() - - restricted = ['localhost', '127.0.0.1', '0.0.0.0'] - - if host in restricted: - errors.append("service upstream is invalid (e1)") - elif host.endswith('svc'): - partials = host.split('.') - # get the namespace, and make sure it is not in the protected_kube_namespaces list - if len(partials) != 3: - errors.append("service upstream is invalid (e2)") - elif partials[1] in protected_kube_namespaces and allow_protected_ns is False: - errors.append("service upstream is invalid (e3)") - elif do_validate_upstreams and (partials[1] in perm_upstreams) is False: - errors.append("service upstream is invalid (e6)") - elif host.endswith('svc.cluster.local'): - partials = host.split('.') - # get the namespace, and make sure it is not in the protected_kube_namespaces list - if len(partials) != 5: - errors.append("service upstream is invalid (e4)") - elif partials[1] in protected_kube_namespaces and allow_protected_ns is False: - errors.append("service upstream is invalid (e5)") - elif do_validate_upstreams and (partials[1] in perm_upstreams) is False: - errors.append("service upstream is invalid (e6)") - elif do_validate_upstreams: - errors.append("service upstream is invalid (e6)") - # Handle the two cases: # - pass in an empty config expecting all routes to be deleted ('upstreams' not in yaml) # - pass in a config with services ('services' in yaml) diff --git a/microservices/gatewayApi/v2/routes/gateway.py b/microservices/gatewayApi/v2/routes/gateway.py index b3171fd..2ed0b40 100644 --- a/microservices/gatewayApi/v2/routes/gateway.py +++ b/microservices/gatewayApi/v2/routes/gateway.py @@ -19,7 +19,7 @@ from clients.portal import record_gateway_event from clients.kong import get_routes, register_kong_certs from clients.ocp_gateway_secret import prep_submitted_config -from utils.validators import host_valid +from utils.validators import host_valid, validate_upstream from utils.transforms import plugins_transformations from utils.masking import mask @@ -509,62 +509,6 @@ def transform_host(host): else: return host -def validate_upstream(yaml, ns_attributes, protected_kube_namespaces, do_validate_upstreams: bool = False): - errors = [] - - perm_upstreams = ns_attributes.get('perm-upstreams', []) - - allow_protected_ns = ns_attributes.get('perm-protected-ns', ['deny'])[0] == 'allow' - - # A host must not contain a list of protected - if 'services' in yaml: - for service in yaml['services']: - if 'url' in service: - try: - u = urlparse(service["url"]) - if u.hostname is None: - errors.append("service upstream has invalid url specified (e1)") - else: - validate_upstream_host(u.hostname, errors, allow_protected_ns, protected_kube_namespaces, do_validate_upstreams, perm_upstreams) - except Exception as e: - errors.append("service upstream has invalid url specified (e2)") - - if 'host' in service: - host = service["host"] - validate_upstream_host(host, errors, allow_protected_ns, protected_kube_namespaces, do_validate_upstreams, perm_upstreams) - - if len(errors) != 0: - raise Exception('\n'.join(errors)) - - -def validate_upstream_host(_host, errors, allow_protected_ns, protected_kube_namespaces, do_validate_upstreams, perm_upstreams): - host = _host.lower() - - restricted = ['localhost', '127.0.0.1', '0.0.0.0'] - - if host in restricted: - errors.append("service upstream is invalid (e1)") - elif host.endswith('svc'): - partials = host.split('.') - # get the namespace, and make sure it is not in the protected_kube_namespaces list - if len(partials) != 3: - errors.append("service upstream is invalid (e2)") - elif partials[1] in protected_kube_namespaces and allow_protected_ns is False: - errors.append("service upstream is invalid (e3)") - elif do_validate_upstreams and (partials[1] in perm_upstreams) is False: - errors.append("service upstream is invalid (e6)") - elif host.endswith('svc.cluster.local'): - partials = host.split('.') - # get the namespace, and make sure it is not in the protected_kube_namespaces list - if len(partials) != 5: - errors.append("service upstream is invalid (e4)") - elif partials[1] in protected_kube_namespaces and allow_protected_ns is False: - errors.append("service upstream is invalid (e5)") - elif do_validate_upstreams and (partials[1] in perm_upstreams) is False: - errors.append("service upstream is invalid (e6)") - elif do_validate_upstreams: - errors.append("service upstream is invalid (e6)") - def update_routes_check(yaml): if 'services' in yaml or 'upstreams' not in yaml: return True