Skip to content

Commit

Permalink
refactor upstream validator
Browse files Browse the repository at this point in the history
  • Loading branch information
ikethecoder committed Nov 15, 2024
1 parent 53f5af4 commit a5b56f5
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 116 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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 = '''
Expand Down
56 changes: 56 additions & 0 deletions microservices/gatewayApi/utils/validators.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

import re
from urllib.parse import urlparse

namespace_validation_rule='^[a-z][a-z0-9-]{4,14}$'

Expand All @@ -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)")
59 changes: 1 addition & 58 deletions microservices/gatewayApi/v1/routes/gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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)
Expand Down
58 changes: 1 addition & 57 deletions microservices/gatewayApi/v2/routes/gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down

0 comments on commit a5b56f5

Please sign in to comment.