Django和弹性Beanstalk URL健康检查 [英] Django and Elastic Beanstalk URL health checks

查看:181
本文介绍了Django和弹性Beanstalk URL健康检查的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Django webapp。它运行在Docker的弹性Beanstalk上。



我想指定一个健康检查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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆