我希望使用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自己的文档,但不幸的是,他们没有提到如何保护Flower的api或web ui。它所说的一切:[Need more text here]
谢谢!
更新:我的问题部分是这里的副本:如何将身份验证和端点添加到 Django 芹菜花监控?
但是,我在这里澄清了他的问题,询问如何使用在同一台远程计算机上包含nginx,gunicorn和芹菜的环境来运行它。我也想知道如何设置 Flower 的外部可访问网址,但如果可能的话,我也更喜欢像 https 而不是 http 这样的东西(或者某种保护 webui 和远程访问它的方法)。我还需要知道,对于任何可能访问 Flower 内部 API 的人来说,让 Flower 运行是否是一个相当大的安全风险,以及保护它的最佳方式是什么,或者是否应该完全禁用它并根据需要使用。
您可以使用 --auth 标志运行花朵,该标志将使用特定的 google 电子邮件进行身份验证:
celery flower --auth=your.email@gmail.com
编辑 1:
新版本的Flower需要更多的标志和一个在Google开发者控制台上注册的OAuth2客户端:
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
必须是实际的花卉登录网址,并且还必须添加到Google开发控制台中的授权重定向网址中。
不幸的是,此功能在当前的稳定版本0.7.2
中无法正常工作,但现在在开发版本中已修复,0.8.0-dev
通过此提交。
编辑 2:
您可以使用基本身份验证配置 Flower:
celery flower --basic_auth=user1:password1,user2:password2
然后阻止除本地主机之外的所有端口的 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,否则没有意义:)
我已经在 Django 端 https://pypi.org/project/django-revproxy/使用代理弄清楚了它。所以 Flower 隐藏在 Django 身份验证后面,它比基本身份验证更灵活。而且你不需要在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
我想在我的网络服务器的子目录上开花,所以我的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 获得花朵(受密码保护)
其中大部分来自有关配置 nginx 反向代理的 Flower 文档页面:
http://flower.readthedocs.org/en/latest/reverse-proxy.html
我遵循了@petr-přikryl使用代理视图的方法。但是我无法让它验证身份验证(我认为从来没有调用过test_func
)。相反,我选择将其嵌入 Django Admin 视图中,并使用 AdminSite.admin_view()
(如此处所述)使用 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
为了卸载 django 应用程序,我建议你使用 X-Accel-Redirect
标头来使用 nginx 来代理 Flower 服务器。具体如下:
- 用户请求花朵路径(例如
/task
) - nginx 像往常一样
proxy_pass
对应用
的请求 - 你的 Django 应用程序选择接受或拒绝请求(例如,基于身份验证)
- 如果您的应用接受请求,它将返回一个带有 HTTP 标头
X-Accel-Redirect
以及内部位置字符串的响应,即用户无法直接访问的路径 - nginx拦截响应而不是将其转发给用户,并将其用作新路径,这次可以访问内部位置,在我们的例子中是Flower服务器
如果请求被拒绝,请不要使用X-Accel-Redirect
,并像实现任何其他被拒绝的请求一样处理这种情况。
nginx.conf:
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;
}
}
views.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}')
urls.py:
from django.urls import re_path
from app import views
urlpatterns = [
re_path('task/(?P<path>.*)', views.task_app, name='task'),
]
花
改变花的url-prefix
很重要:
celery flower --unix-socket="/var/run/celery/flower.sock" --url-prefix="task"
这是对Petr Přikryl帖子的回复。 django-revproxy 无法在我的 Django 4.1.x 项目上运行。我遇到错误AttributeError: 'HttpResponse' object has no attribute '_headers'
。许多其他人也面临同样的问题。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 --app myproject flower --loglevel INFO --url_prefix=flower
然后,您可以在浏览器中查看它,通过 Django 提供,http://localhost:8000/flower/。
附加说明:
--url_prefix= 很重要,因为这将允许代理提供 flower 请求的静态文件。
如果您使用的是 docker 撰写,则可能需要更改 flower
函数中 remoteurl
字符串中的主机名以反映服务的相同内容。例如,我的服务在我的docker-compose.yaml
文件中被适当地称为flower
。因此,我会将字符串从 f"http://localhost:5555/flower/"
更改为f"http://flower:5555/flower/"
是的,花朵上没有身份验证,因为它只是与代理交谈,但是如果您通过 SSL 运行它,那么基本身份验证应该足够好。
HTTP 和 HTTPS 将如何影响 Celery 的安全性?您指的是哪些用户登录?
花监视器通过附加到工人来监视芹菜队列。设置 Flower 时,需要提供连接字符串 [broker]://[user_name]:[password]@[database_address]:[端口]/[实例]。用户名和密码是登录到所选数据库的凭据。
如果您指的是此登录名,那么简单地禁用/删除其登录名就足够了吗?