Django和弹性Beanstalk URL健康检查 [英] Django and Elastic Beanstalk URL health checks
问题描述
我想指定一个健康检查URL 进行稍微更高级的运行状况检查,ELB可以建立TCP连接。
ELB通过使用实例的主机名连接到实例,完全合理地执行此操作(例如 ec2-127-0 -0-1.compute-1.amazonaws.com
)作为主机
标题。
Django已 ALLOWED_HOSTS
,验证传入请求的主机
头。我通过环境变量将其设置到我的应用程序的外部域。
不出所料,完全合理地,Django由于缺少匹配的而拒绝ELB URL健康检查主持人
。
我们不想禁用 ALLOWED_HOSTS
,因为我们想能够相信 get_host()
。
迄今为止的解决方案似乎是:
- 以某种方式说服Django不关心某些特定路径的
ALLOWED_HOSTS
- 做一些简单的事情,例如在启动时调用EC2 info API以获取主机的FQDN并将其附加到
ALLOWED_HOSTS
这两个都不是特别愉快。任何人都可以推荐更好/现有的解决方案?
(为了避免疑问,我认为这个问题与Disabled ALLOWED_HOSTS
,前端HTTPD过滤主机 - 我想要健康检查来点击Django ,而不是前端的HTTPD)
如果ELB健康检查使用包含弹性beanstalk域(* .elasticbeanstalk.com或EC2域* .amazonaws.com)的主机头发送其请求,则标准 ALLOWED_HOSTS
仍然可以使用通配符条目'。amazonaws.com'
或 '.elasticbeanstalk.com'
。
在我的情况下,我收到了健康检查主机的标准ipv4地址,因此需要一个不同的解决方案。如果您根本无法预测主机,假设您不能安全,则需要采取以下路线之一。
您可以使用Apache来处理已批准的主机,而不是向Django传播不明确的请求。由于主机头是打算接收请求的服务器的主机名,因此该解决方案会更改有效请求的头部以使用预期的站点主机名。使用弹性beanstalk,您将需要使用 .ebextensions
配置Apache,如这里。在项目根目录下的 .ebextensions
目录下,将以下内容添加到.config文件中。
/etc/httpd/conf.d/eb_healthcheck.conf:
mode:000644
owner:root
group:root
内容:|
< Ifreq('User-Agent')=='ELB-HealthChecker / 1.0'&%{REQUEST_URI} =='/ status /'>
RequestHeader设置主机example.com
< / If>
使用健康检查替换 / status /
URL和 example.com
与您网站的适当域名。这告诉Apache检查所有传入的请求,并使用正确请求健康检查URL的健康检查用户代理,在请求上更改主机头。
如果你真的不想配置Apache,您可以编写一个自定义中间件来验证运行状况检查。中间件必须覆盖Django的 CommonMiddleware
调用 HttpRequest
的 get_host()
方法来验证请求的主机。你可以这样做一些这样的东西
从django.middleware.common import CommonMiddleware
类CommonOverrideMiddleware(CommonMiddleware):
def process_request(self,request):
如果没有('HTTP_USER_AGENT'在request.META和request.META ['HTTP_USER_AGENT'] =='ELB-HealthChecker / 1.0'和request.get_full_path()=='/ status /'):
return super()。process_request(request)
哪些只允许任何健康检查请求跳过主机验证。然后,您将在中替换
。 django.middleware.common.CommonMiddleware
与 path.CommonOverrideMiddleware
settings.py
我建议使用Apache配置方法来避免中间件的任何细节,并将Django完全隔离主机问题。
I have a Django webapp. It runs inside Docker on Elastic Beanstalk.
I'd like to specify a health check URL for slightly more advanced health checking than "can the ELB establish a TCP connection".
Entirely reasonably, the ELB does this by connecting to the instance over HTTP, using the instance's hostname (e.g. ec2-127-0-0-1.compute-1.amazonaws.com
) as the Host
header.
Django has ALLOWED_HOSTS
which validates the Host
header of incoming requests. I set this to my application's external domain via environment variable.
Unsurprisingly and entirely reasonably, Django thus rejects ELB URL health checks due to lack of matching Host
.
We don't want to disable ALLOWED_HOSTS
because we'd like to be able to trust get_host()
.
The solutions so far seem to be:
- Somehow persuade Django to not care about
ALLOWED_HOSTS
for certain specific paths (i.e. the health check URL) - Do something funky like calling the EC2 info API on startup to get the host's FQDN and append it to
ALLOWED_HOSTS
Neither of these seem particularly pleasant. Can anyone recommend a better / existing solution?
(For the avoidance of doubt, I believe this problem to be identical to the scenario of "Disabled ALLOWED_HOSTS
, fronting HTTPD that filters on host" - I want the health check to hit Django, not a fronting HTTPD)
If the ELB health check is sending its request with a host header containing the elastic beanstalk domain (*.elasticbeanstalk.com, or an EC2 domain *.amazonaws.com) then the standard ALLOWED_HOSTS
can still be used with a wildcard entry of '.amazonaws.com'
or '.elasticbeanstalk.com'
.
In my case I received standard ipv4 addresses as the health check hosts, so a different solution was needed. If you can't predict the host at all, and it might be safer to assume you can't, you would need to take a route such as one of the following.
You can use Apache to handle approved hosts instead of propagating ambiguous requests to Django. Since the host header is intended to be the hostname of the server receiving the request, this solution changes the header of valid requests to use the expected site hostname. With elastic beanstalk you'll need to configure Apache using .ebextensions
as described here. Under the .ebextensions
directory in your project root, add the following to a .config file.
files:
"/etc/httpd/conf.d/eb_healthcheck.conf":
mode: "000644"
owner: root
group: root
content: |
<If "req('User-Agent') == 'ELB-HealthChecker/1.0' && %{REQUEST_URI} == '/status/'">
RequestHeader set Host "example.com"
</If>
Replacing /status/
with your health check URL and example.com
with your site's appropriate domain. This tells Apache to check all incoming requests and change the host headers on requests with the appropriate health check user agent that are requesting the appropriate health check URL.
If you would really prefer not to configure Apache, you could write a custom middleware to authenticate health checks. The middleware would have to override Django's CommonMiddleware
which calls HttpRequest
's get_host()
method that validates the request's host. You could do something like this
from django.middleware.common import CommonMiddleware
class CommonOverrideMiddleware(CommonMiddleware):
def process_request(self, request):
if not('HTTP_USER_AGENT' in request.META and request.META['HTTP_USER_AGENT'] == 'ELB-HealthChecker/1.0' and request.get_full_path() == '/status/'):
return super().process_request(request)
Which just allows any health check requests to skip the host validation. You'd then replace django.middleware.common.CommonMiddleware
with path.CommonOverrideMiddleware
in your settings.py
.
I would recommend using the Apache configuration approach to avoid any details in the middleware, and to completely isolate Django from host issues.
这篇关于Django和弹性Beanstalk URL健康检查的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!