Amazon ELB 的 Django ALLOWED_HOSTS

问题描述 投票:0回答:3

我正在使用 Django,并且我有

ALLOWED_HOSTS
设置来包含我的
EC2
的私有 IP,如下所示:

import requests
EC2_PRIVATE_IP = None
try:
    EC2_PRIVATE_IP = requests.get('http://169.254.169.254/latest/meta-data/local-ipv4', timeout=0.01).text
except requests.exceptions.RequestException:
    pass
if EC2_PRIVATE_IP and not DEBUG:
    ALLOWED_HOSTS.append(EC2_PRIVATE_IP)

问题是上述内容没有考虑将请求转发到我的

ELB
实例的
EC2
。有没有办法让它以编程方式工作?我可以请求公共 IP 地址或设置检查 DNS 吗?

我发现 ELB 的公共 IP 地址存在此问题。

django amazon-web-services
3个回答
15
投票

另一个简单的解决方案是编写一个自定义的

MIDDLEWARE
,它将在检查
ALLOWED_HOSTS
之前向 ELB 提供响应。所以现在您不必动态加载
ALLOWED_HOSTS

中间件可以很简单:

project/app/middleware.py

from django.http import HttpResponse
from django.utils.deprecation import MiddlewareMixin

class HealthCheckMiddleware(MiddlewareMixin):
    def process_request(self, request):
        if request.META["PATH_INFO"] == "/ping/":
            return HttpResponse("pong")

settings.py

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    'app.middleware.HealthCheckMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    ...
]

Django 中间件参考 https://docs.djangoproject.com/en/dev/topics/http/middleware/


3
投票

获取AWS内部IP并添加到ALLOWED_HOST并不是最好的解决方案。由于此获取仅在应用程序重新加载时发生。 ELB IP 可以随时更改。

取而代之的是,我们可以在 nginx 中设置实际的主机标头,如果请求来自 IP。

功劳归于: https://www.xormedia.com/django-allowed-hosts-and-amazon-elastic-load-balancer/


0
投票

获取私有IP

我最近也遇到这个问题了。目前的答案大致是OP所描述的,但它还涉及预先获取访问令牌并在请求中使用它。我的设置位于负载均衡器后面的 Elastic Beanstalk 上,运行状况检查器请求 EC2 实例的私有 IP,如果私有 IP 不在 ALLOWED_HOSTS 中,则会失败。当获取并添加私有IP后,它就可以工作了。 EB 运行状况检查器似乎需要实例的私有 IP,而不是负载均衡器的私有 IP。

我从这个问题的答案中得到了答案。我对其进行了一些修改,将生成的 ip 缓存在临时文件中一段时间,这样站点就不需要每次有人加载页面时都发出请求。

private_ip = None
private_ip_filepath = "{dir}/private-ip.txt".format(dir=tempfile.gettempdir().rstrip('/'))
if os.path.exists(private_ip_filepath):
    if datetime.datetime.now() - datetime.datetime.fromtimestamp(os.path.getmtime(private_ip_filepath)) < datetime.timedelta(seconds=3600):
        with open(private_ip_filepath, "r") as f:
            private_ip = f.read().strip()
    else:
        os.remove(private_ip_filepath)
if not private_ip:
    if STAGE == 'local':
        private_ip = "127.0.0.1"
    else:
        # https://stackoverflow.com/questions/47277541/how-to-dynamically-add-ec2-ip-addresses-to-django-allowed-hosts
        try:
            IMDSv2_token = requests.put('http://169.254.169.254/latest/api/token', headers={
                'X-aws-ec2-metadata-token-ttl-seconds': '3600',
            }).text
            private_ip = requests.get('http://169.254.169.254/latest/meta-data/local-ipv4', timeout=0.01, headers={
                'X-aws-ec2-metadata-token': IMDSv2_token
            }).text
        except requests.exceptions.RequestException:
            pass
    with open(private_ip_filepath, "w") as f:
        f.write(private_ip)
if private_ip:
    ALLOWED_HOSTS.append(private_ip)

目前接受的答案是编写中间件以始终返回健康响应,这违背了健康检查器的目的。另一种答案是忽略来自客户端的 Host 标头并将其替换为有效的标头,这违背了 ALLOWED_HOSTS 的目的。

© www.soinside.com 2019 - 2024. All rights reserved.