mirror of
https://github.com/ansible/awx.git
synced 2026-01-11 10:00:01 -03:30
add a new configurable, PROXY_IP_WHITELIST
implement a whitelist setting that - if populated - will only allow specific IPs/hostnames to provide custom REMOTE_HOST_HEADERS header values (i.e., `HTTP_X_FORWARDED_FOR`) see: #6538
This commit is contained in:
parent
c821df7fd5
commit
7d12427497
@ -98,6 +98,18 @@ class APIView(views.APIView):
|
||||
self.time_started = time.time()
|
||||
if getattr(settings, 'SQL_DEBUG', False):
|
||||
self.queries_before = len(connection.queries)
|
||||
|
||||
# If there are any custom headers in REMOTE_HOST_HEADERS, make sure
|
||||
# they respect the proxy whitelist
|
||||
if all([
|
||||
settings.PROXY_IP_WHITELIST,
|
||||
request.environ.get('REMOTE_ADDR') not in settings.PROXY_IP_WHITELIST,
|
||||
request.environ.get('REMOTE_HOST') not in settings.PROXY_IP_WHITELIST
|
||||
]):
|
||||
for custom_header in settings.REMOTE_HOST_HEADERS:
|
||||
if custom_header.startswith('HTTP_'):
|
||||
request.environ.pop(custom_header, None)
|
||||
|
||||
drf_request = super(APIView, self).initialize_request(request, *args, **kwargs)
|
||||
request.drf_request = drf_request
|
||||
return drf_request
|
||||
|
||||
@ -82,6 +82,21 @@ register(
|
||||
category_slug='system',
|
||||
)
|
||||
|
||||
register(
|
||||
'PROXY_IP_WHITELIST',
|
||||
field_class=fields.StringListField,
|
||||
label=_('Proxy IP Whitelist'),
|
||||
help_text=_("If Tower is behind a reverse proxy/load balancer, use this setting "
|
||||
"to whitelist the proxy IP addresses from which Tower should trust "
|
||||
"custom REMOTE_HOST_HEADERS header values\n"
|
||||
"REMOTE_HOST_HEADERS = ['HTTP_X_FORWARDED_FOR', ''REMOTE_ADDR', 'REMOTE_HOST']\n"
|
||||
"PROXY_IP_WHITELIST = ['10.0.1.100', '10.0.1.101']\n"
|
||||
"If this setting is an empty list (the default), the headers specified by "
|
||||
"REMOTE_HOST_HEADERS will be trusted unconditionally')"),
|
||||
category=_('System'),
|
||||
category_slug='system',
|
||||
)
|
||||
|
||||
|
||||
def _load_default_license_from_file():
|
||||
try:
|
||||
|
||||
62
awx/main/tests/functional/api/test_generic.py
Normal file
62
awx/main/tests/functional/api/test_generic.py
Normal file
@ -0,0 +1,62 @@
|
||||
import pytest
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_proxy_ip_whitelist(get, patch, admin):
|
||||
url = reverse('api:setting_singleton_detail', args=('system',))
|
||||
patch(url, user=admin, data={
|
||||
'REMOTE_HOST_HEADERS': [
|
||||
'HTTP_X_FROM_THE_LOAD_BALANCER',
|
||||
'REMOTE_ADDR',
|
||||
'REMOTE_HOST'
|
||||
]
|
||||
})
|
||||
|
||||
class HeaderTrackingMiddleware(object):
|
||||
environ = {}
|
||||
|
||||
def process_request(self, request):
|
||||
pass
|
||||
|
||||
def process_response(self, request, response):
|
||||
self.environ = request.environ
|
||||
|
||||
# By default, `PROXY_IP_WHITELIST` is disabled, so custom `REMOTE_HOST_HEADERS`
|
||||
# should just pass through
|
||||
middleware = HeaderTrackingMiddleware()
|
||||
get(url, user=admin, middleware=middleware,
|
||||
HTTP_X_FROM_THE_LOAD_BALANCER='some-actual-ip')
|
||||
assert middleware.environ['HTTP_X_FROM_THE_LOAD_BALANCER'] == 'some-actual-ip'
|
||||
|
||||
# If `PROXY_IP_WHITELIST` is restricted to 10.0.1.100 and we make a request
|
||||
# from 8.9.10.11, the custom `HTTP_X_FROM_THE_LOAD_BALANCER` header should
|
||||
# be stripped
|
||||
patch(url, user=admin, data={
|
||||
'PROXY_IP_WHITELIST': ['10.0.1.100']
|
||||
})
|
||||
middleware = HeaderTrackingMiddleware()
|
||||
get(url, user=admin, middleware=middleware, REMOTE_ADDR='8.9.10.11',
|
||||
HTTP_X_FROM_THE_LOAD_BALANCER='some-actual-ip')
|
||||
assert 'HTTP_X_FROM_THE_LOAD_BALANCER' not in middleware.environ
|
||||
|
||||
# If 8.9.10.11 is added to `PROXY_IP_WHITELIST` the
|
||||
# `HTTP_X_FROM_THE_LOAD_BALANCER` header should be passed through again
|
||||
patch(url, user=admin, data={
|
||||
'PROXY_IP_WHITELIST': ['10.0.1.100', '8.9.10.11']
|
||||
})
|
||||
middleware = HeaderTrackingMiddleware()
|
||||
get(url, user=admin, middleware=middleware, REMOTE_ADDR='8.9.10.11',
|
||||
HTTP_X_FROM_THE_LOAD_BALANCER='some-actual-ip')
|
||||
assert middleware.environ['HTTP_X_FROM_THE_LOAD_BALANCER'] == 'some-actual-ip'
|
||||
|
||||
# Allow whitelisting of proxy hostnames in addition to IP addresses
|
||||
patch(url, user=admin, data={
|
||||
'PROXY_IP_WHITELIST': ['my.proxy.example.org']
|
||||
})
|
||||
middleware = HeaderTrackingMiddleware()
|
||||
get(url, user=admin, middleware=middleware, REMOTE_ADDR='8.9.10.11',
|
||||
REMOTE_HOST='my.proxy.example.org',
|
||||
HTTP_X_FROM_THE_LOAD_BALANCER='some-actual-ip')
|
||||
assert middleware.environ['HTTP_X_FROM_THE_LOAD_BALANCER'] == 'some-actual-ip'
|
||||
@ -152,6 +152,15 @@ ALLOWED_HOSTS = []
|
||||
# reverse proxy.
|
||||
REMOTE_HOST_HEADERS = ['REMOTE_ADDR', 'REMOTE_HOST']
|
||||
|
||||
# If Tower is behind a reverse proxy/load balancer, use this setting to
|
||||
# whitelist the proxy IP addresses from which Tower should trust custom
|
||||
# REMOTE_HOST_HEADERS header values
|
||||
# REMOTE_HOST_HEADERS = ['HTTP_X_FORWARDED_FOR', ''REMOTE_ADDR', 'REMOTE_HOST']
|
||||
# PROXY_IP_WHITELIST = ['10.0.1.100', '10.0.1.101']
|
||||
# If this setting is an empty list (the default), the headers specified by
|
||||
# REMOTE_HOST_HEADERS will be trusted unconditionally')
|
||||
PROXY_IP_WHITELIST = []
|
||||
|
||||
# Note: This setting may be overridden by database settings.
|
||||
STDOUT_MAX_BYTES_DISPLAY = 1048576
|
||||
|
||||
|
||||
@ -130,6 +130,15 @@ SECRET_KEY = 'p7z7g1ql4%6+(6nlebb6hdk7sd^&fnjpal308%n%+p^_e6vo1y'
|
||||
# reverse proxy.
|
||||
REMOTE_HOST_HEADERS = ['REMOTE_ADDR', 'REMOTE_HOST']
|
||||
|
||||
# If Tower is behind a reverse proxy/load balancer, use this setting to
|
||||
# whitelist the proxy IP addresses from which Tower should trust custom
|
||||
# REMOTE_HOST_HEADERS header values
|
||||
# REMOTE_HOST_HEADERS = ['HTTP_X_FORWARDED_FOR', ''REMOTE_ADDR', 'REMOTE_HOST']
|
||||
# PROXY_IP_WHITELIST = ['10.0.1.100', '10.0.1.101']
|
||||
# If this setting is an empty list (the default), the headers specified by
|
||||
# REMOTE_HOST_HEADERS will be trusted unconditionally')
|
||||
PROXY_IP_WHITELIST = []
|
||||
|
||||
# Define additional environment variables to be passed to subprocess started by
|
||||
# the celery task.
|
||||
#AWX_TASK_ENV['FOO'] = 'BAR'
|
||||
|
||||
@ -87,6 +87,15 @@ SECRET_KEY = 'p7z7g1ql4%6+(6nlebb6hdk7sd^&fnjpal308%n%+p^_e6vo1y'
|
||||
# reverse proxy.
|
||||
REMOTE_HOST_HEADERS = ['REMOTE_ADDR', 'REMOTE_HOST']
|
||||
|
||||
# If Tower is behind a reverse proxy/load balancer, use this setting to
|
||||
# whitelist the proxy IP addresses from which Tower should trust custom
|
||||
# REMOTE_HOST_HEADERS header values
|
||||
# REMOTE_HOST_HEADERS = ['HTTP_X_FORWARDED_FOR', ''REMOTE_ADDR', 'REMOTE_HOST']
|
||||
# PROXY_IP_WHITELIST = ['10.0.1.100', '10.0.1.101']
|
||||
# If this setting is an empty list (the default), the headers specified by
|
||||
# REMOTE_HOST_HEADERS will be trusted unconditionally')
|
||||
PROXY_IP_WHITELIST = []
|
||||
|
||||
# Define additional environment variables to be passed to subprocess started by
|
||||
# the celery task.
|
||||
#AWX_TASK_ENV['FOO'] = 'BAR'
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user