Proxy servers act as an intermediary for requests from clients seeking resources from other servers. A client connects to the proxy server, requesting some service or available resource from a different server, and the proxy server evaluates the request as a way to simplify and control its complexity.
Using SSL offloading or using a proxy that handles SSL for Tower is supported. The proxy/load balancer needs to be configured to pass the remote host information.
When offloading SSL to the load balancer or proxy, set
nginx_disable_https=true as an extra variable passed to the setup playbook. Refer to The Setup Playbook for information on applying extra variables to the setup playbook.
Sessions in Tower associate an IP address upon creation. Tower policy requires that any use of the session match the original associated IP address.
To provide proxy server support, Tower handles proxied requests (such as ELB in front of Tower, HAProxy, Squid, and tinyproxy) via the
REMOTE_HOST_HEADERS list variable in the System settings of the Configure Tower user interface. Prior to Ansible Tower 3.2, this setting was configured in the
remote_host_headers.py file, which is no longer supplied with Tower installations.
REMOTE_HOST_HEADERS is set to
REMOTE_ADDR, REMOTE_HOST. To enable proxy server support, the
REMOTE_HOST_HEADERS parameter should be defined with a simple comma-separated string, like the following:
REMOTE_HOST_HEADERS = HTTP_X_FORWARDED_FOR, REMOTE_ADDR, REMOTE_HOST.
Tower determines the remote host’s IP address by searching through the list of headers in
REMOTE_HOST_HEADERS until the FIRST IP address is located.
Header names are constructed using the following logic:
With the exception of
CONTENT_TYPE, any HTTP headers in the request are converted to META keys by converting all characters to uppercase, replacing any hyphens with underscores, and adding an
HTTP_ prefix to the name. For example, a header called
X-Barkley would be mapped to the META key
For more information on HTTP request and response objects, refer to: https://docs.djangoproject.com/en/1.8/ref/request-response/#django.http.HttpRequest.META
If using SSL termination at the load balancer and forwarding traffic to a different port on the tower node (443 -> 80), set the following values in the
/etc/tower/settings.py file accordingly:
USE_X_FORWARDED_PORT = True USE_X_FORWARDED_HOST = True
When Tower is configured with
REMOTE_HOST_HEADERS = HTTP_X_FORWARDED_FOR, REMOTE_ADDR, REMOTE_HOST, it assumes that the value of
X-Forwarded-For has originated from the proxy/load balancer sitting in front of Tower. In a scenario where Tower is still reachable without use of the proxy/load balancer or when the proxy does not validate the header,
X-Forwarded-For can be spoofed fairly easily to fake the originating IP addresses. Using
HTTP_X_FORWARDED_FOR in the
REMOTE_HOST_HEADERS setting poses a vulnerability that essentially gives users access to certain resources that they should not have.
To avoid this, you can configure a list of “known proxies” that are allowed, which is the
PROXY_IP_WHITELIST setting via the settings API. Load balancers and hosts that are not on the list will result in a rejected request.
PROXY_IP_WHITELIST only works if the proxies in the list are properly sanitizing header input and correctly setting an
X-Forwarded-For value equal to the real source IP of the client; the crux of this setting is that Tower can rely on the IPs/hostnames in
PROXY_IP_WHITELIST to provide non-spoofed values for the
HTTP_X_FORWARDED_FOR should never be configured as an item in
REMOTE_HOST_HEADERS unless all of the following are satisfied:
- You are using a proxied environment w/ ssl termination
- The proxy provides sanitization/validation of the
X-Forwarded-Forheader to prevent client spoofing
PROXY_IP_WHITELISTthat contains only the originating IP of trusted proxies/load balancers
If you do not need all of the traffic to be put through the proxy, then you can specify the IP scheme(s) that you want to exclude in the
no_proxy field. The list can be IP ranges or individual IPs, separated by a comma. This example shows a specified range of IPs in JSON format:
"https_proxy": "example.proxy.com:8080", "http_proxy": "example.proxy.com:8080", "no_proxy": "10.0.0.0/8"
Also, an SCM update with a
no_proxy configuration and a CIDR notation may not work for a particular SCM. The support for
no_proxy depends on the the implementation in the application (git|hg|svn). For example, git does not support CIDR notation for
no_proxy because git is limited by its C library: https://curl.haxx.se/libcurl/c/CURLOPT_NOPROXY.html.
If you are behind a reverse proxy, you may want to setup a header field for
X-Forwarded-For (XFF) HTTP header field identifies the originating IP address of a client connecting to a web server through an HTTP proxy or load balancer.
REMOTE_HOST_HEADERS = HTTP_X_FORWARDED_FOR, REMOTE_ADDR, REMOTE_HOST
If you find that your notifications are not working behind a proxy, refer to the knowledge base article, How do I Use Ansible Tower Notifications from Behind a Proxy?.