nginx 西芹花安全生产

mi7gmzs6  于 2023-02-03  发布在  Nginx
关注(0)|答案(8)|浏览(228)

我希望使用Flower(https://github.com/mher/flower)来监控我的Celery任务,代替django-admin,就像他们的文档中建议的那样(http://docs. celeryproject. org/en/latest/userguide/monitoring. html #flower-real-time-celery-web-monitor)。然而,因为我是新手,所以我对Flower的页面只基于HTTP而不是HTTPS的方式有点困惑。我如何才能为我的Celery任务启用安全性,使任何老用户都不能访问不需要登录的网站http://flowerserver.com:5555并更改一些东西呢?
我曾经考虑过Celery的own documentation,但不幸的是,他们没有提到如何保护Flower的api或web ui。[Need more text here]
谢谢!

    • 更新:**我的问题部分重复于此:如何在Django Celery Flower Monitoring中添加身份验证和端点?

但是,我在这里澄清了他的问题,询问如何在同一台远程计算机上使用包含nginx、gunicorn和celery的环境来运行它。我也想知道如何设置Flower的外部可访问URL。但是如果可能的话也会喜欢HTTPS而不是HTTP(或者某种保护webui并远程访问它的方法)。我还需要知道让flower运行是否对任何可能获得flower访问权限的人来说都是一个相当大的安全风险的内部API,以及保护它的最佳方法是什么,或者是否应该完全禁用它并仅在需要时使用它。

gcxthw6b

gcxthw6b1#

我希望flower位于Web服务器的子目录中,所以我的nginx反向代理配置如下所示:

location /flower/ {
    proxy_pass http://localhost:5555/;
    proxy_redirect off;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Protocol $scheme;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_http_version 1.1;

    auth_basic  "Restricted";
    auth_basic_user_file  /etc/nginx/.htpasswd;
}

现在我可以通过www.example.com访问flower(受密码保护www.example.com/flower
大部分内容来自Flower文档页面中关于配置nginx反向代理的内容:
http://flower.readthedocs.org/en/latest/reverse-proxy.html

ejk8hzay

ejk8hzay2#

我遵循@petr-přikryl的方法使用代理视图,但是我不能让它验证身份(我不认为test_func被调用过),相反我选择将其嵌入Django Admin视图并使用AdminSite.admin_view()(如这里所述)来 Package Django Admin身份验证视图。
具体来说,我做了以下更改:

# Pipfile
[packages]
...
django-revproxy="*"
# admin.py
class MyAdminSite(admin.AdminSite):
    # ...
    def get_urls(self):
        from django.urls import re_path

        # Because this is hosted in the root `urls.py` under `/admin` this 
        # makes the total prefix /admin/flower
        urls = super().get_urls()
        urls += [
            re_path(
                r"^(?P<path>flower.*)$",
                self.admin_view(FlowerProxyView.as_view()),
            )
        ]
        return urls
# views.py
from __future__ import annotations

from django.urls import re_path

from revproxy.views import ProxyView

class FlowerProxyView(ProxyView):
    # Need `/admin/` here because the embedded view in the admin app drops the
    # `/admin` prefix before sending the URL to the ProxyView
    upstream = "http://{}:{}/admin/".format("localhost", 5555)

最后,我们需要确保在运行flower时设置了--url_prefix,因此我将其设置为在生产和开发环境中如下运行:

celery flower --app=my_app.celery:app --url_prefix=admin/flower
wlsrxk51

wlsrxk513#

要卸载django应用,我建议您使用X-Accel-Redirect头文件,以便使用nginx来代理Flower服务器。
1.用户请求花道(例如/task

  1. nginx proxy_pass发送到应用的请求,像往常一样
    1.你的django应用选择接受或拒绝请求(例如基于认证)
    1.如果您的应用接受请求,它将返回一个响应,其中包含X-Accel-Redirect HTTP头以及一个 * 内部位置 * 字符串,即用户无法直接访问的路径
  2. nginx拦截响应,而不是将其转发给用户,并将其用作新路径,这一次可以访问内部位置,在我们的示例中是Flower服务器
    如果请求被拒绝,就不要使用X-Accel-Redirect,并像处理您要实现的任何其他被拒绝的请求一样处理该情况。
    • nginx配置文件:**
upstream celery_server {
    server /var/run/celery/flower.sock;
}

upstream app_server {
    server /var/run/gunicorn/asgi.sock;
}

server {
    listen 80;

    location /protected/task {
        internal;  # returns 404 if accessed directly
        proxy_http_version 1.1;
        proxy_redirect off;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header Upgrade $http_upgrade;

        proxy_pass http://celery_server/task;
    }

    location / {
        proxy_http_version 1.1;
        proxy_redirect off;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Host $server_name;

        proxy_pass http://app_server;
    }
}
    • 浏览次数. py:**
from django.contrib.admin.views.decorators import staff_member_required
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse

class XAccelRedirectResponse(HttpResponse):
    def __init__(self, path, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self['X-Accel-Redirect'] = '/protected' + path
        del self['Content-Type']  # necessary

# I chose to only allow staff members, i.e. whose who can access the admin panel
@staff_member_required
@csrf_exempt
def task_app(request, path):
    query_str = request.META['QUERY_STRING']  # you must keep the query string
    return XAccelRedirectResponse(f'/task/{path}?{query_str}')
    • 网址. py:**
from django.urls import re_path
from app import views

urlpatterns = [
    re_path('task/(?P<path>.*)', views.task_app, name='task'),
]
    • 花**

更改Flower的url-prefix非常重要:

celery flower --unix-socket="/var/run/celery/flower.sock" --url-prefix="task"
lh80um4z

lh80um4z4#

是的,在flower上没有auth,因为它只是与代理对话,但是如果您通过SSL运行它,那么基本的auth应该足够好了。

u91tlkcl

u91tlkcl5#

HTTP和HTTPS会如何影响Celery的安全性?你指的是什么用户登录?
Flower通过连接到工作线程来监视Celery队列。设置Flower时,您需要提供连接字符串[broker]://[user_name]:[password]@[database_address]:[port]/[instance]。用户名和密码是登录到所选数据库的凭据。
如果你指的是这个登录,简单地禁用/删除他们的登录还不够吗?

abithluo

abithluo6#

这是对Petr Přikryl的帖子的回复。django-revproxy在我的Django 4.1.x项目上无法工作。我遇到了错误AttributeError: 'HttpResponse' object has no attribute '_headers'Many others也面临着同样的问题。brianmay在问题线程中声称,"我认为这个项目基本上已经死了,对不起。"
我选择了另一个库作为变通方案。
安装django-proxy
这是我的代码。

# urls.py

from django.urls import re_path
from myapp.views import flower

urlpatterns = [
    re_path("flower/(?P<path>.*)", flower),
]
# views.py

from django.views.decorators.csrf import csrf_exempt
from proxy.views import proxy_view

@csrf_exempt
def flower(request, path):
    extra_requests_args = {}
    remoteurl = f"http://localhost:5555/flower/" + path
    return proxy_view(request, remoteurl, extra_requests_args)

然后把celery

$ celery --app myproject flower --loglevel INFO --url_prefix=flower

然后你可以在浏览器中查看它,通过Django提供,网址是http://localhost:8000/flower/。
补充说明:

  • -url_prefix =很重要,因为这将允许代理服务器为flower请求的静态文件提供服务。
    如果您使用的是docker compose,那么您可能需要更改flower函数中remoteurl字符串中的主机名,以反映相同的服务。例如,我的服务在docker-compose.yaml文件中被正确地称为flower。因此,我将字符串从f"http://localhost:5555/flower/"更改为f"http://flower:5555/flower/"
fnatzsnv

fnatzsnv7#

你可以使用--auth flag来运行flower,它将使用一个特定的google email来验证身份:

celery flower --auth=your.email@gmail.com

编辑1

新版本的Flower需要更多的标志和注册的OAuth2客户端(Google Developer Console

celery flower \
    --auth=your.email@gmail.com \
    --oauth2_key="client_id" \
    --oauth2_secret="client_secret" \
    --oauth2_redirect_uri="http://example.com:5555/login"

oauth2_redirect_uri必须是实际的花登录url,并且还必须将其添加到Google开发控制台中的授权重定向url。
不幸的是,这个特性在当前的稳定版本0.7.2中不能正常工作,但是现在它在开发版本0.8.0-dev中通过这个提交得到了修复。

编辑2

您可以使用基本身份验证配置Flower:

celery flower --basic_auth=user1:password1,user2:password2

然后阻塞除localhost之外的所有端口的5555端口,并为nginx或apache配置反向代理:

ProxyRequests off
ProxyPreserveHost On
ProxyPass / http://localhost:5555

然后确保代理模式已打开:

sudo a2enmod proxy
sudo a2enmod proxy_http

如果您无法将其设置在单独的子域上,例如:flower.example.com(上面的配置),您可以将其设置为example.com/flower
使用url_prefix运行花:

celery flower --url_prefix=flower --basic_auth=user1:password1,user2:password2

在apache配置中:

ProxyPass /flower http://localhost:5555

当然,要确保配置了SSL,否则就没有意义了:)

bpsygsoo

bpsygsoo8#

我已经在Django端https://pypi.org/project/django-revproxy/使用代理解决了这个问题。所以Flower隐藏在Django auth后面,比基本auth更灵活。而且你不需要在NGINX中重写规则。

花0.9.5及更高版本

必须将URL前缀移动到代理路径中:https://github.com/mher/flower/pull/766
urls.py

urlpatterns = [
    FlowerProxyView.as_url(),
    ...
]

views.py

class FlowerProxyView(UserPassesTestMixin, ProxyView):
    # `flower` is Docker container, you can use `localhost` instead
    upstream = 'http://{}:{}'.format('flower', 5555)
    url_prefix = 'flower'
    rewrite = (
        (r'^/{}$'.format(url_prefix), r'/{}/'.format(url_prefix)),
     )

    def test_func(self):
        return self.request.user.is_superuser

    @classmethod
    def as_url(cls):
        return re_path(r'^(?P<path>{}.*)$'.format(cls.url_prefix), cls.as_view())

花0.9.4及更低版本

urls.py

urlpatterns = [
    re_path(r'^flower/?(?P<path>.*)$', FlowerProxyView.as_view()),
    ...
]

views.py

from django.contrib.auth.mixins import UserPassesTestMixin
from revproxy.views import ProxyView

class FlowerProxyView(UserPassesTestMixin, ProxyView):
    # `flower` is Docker container, you can use `localhost` instead
    upstream = 'http://flower:5555'

    def test_func(self):
        return self.request.user.is_superuser

相关问题