Add production backend configuration with classical JWT authentication, update provisioning tasks, and include production.py in docker-compose and Ansible workflows
This commit is contained in:
parent
e4953042c0
commit
5ef655f1bc
@ -23,11 +23,12 @@
|
|||||||
dest: "{{ deploy_dir }}/nginx/templates/"
|
dest: "{{ deploy_dir }}/nginx/templates/"
|
||||||
mode: "0644"
|
mode: "0644"
|
||||||
|
|
||||||
# backend монтирует ./backend/uwsgi.ini (http-socket + 4 воркера)
|
# backend монтирует ./backend/uwsgi.ini (http-socket + 4 воркера) и
|
||||||
- name: Скопировать конфиг uwsgi для backend
|
# ./backend/production.py (классическая JWT-аутентификация)
|
||||||
|
- name: Скопировать конфиги backend (uwsgi.ini, production.py)
|
||||||
ansible.builtin.copy:
|
ansible.builtin.copy:
|
||||||
src: "{{ deploy_src_root }}/backend/uwsgi.ini"
|
src: "{{ deploy_src_root }}/backend/"
|
||||||
dest: "{{ deploy_dir }}/backend/uwsgi.ini"
|
dest: "{{ deploy_dir }}/backend/"
|
||||||
mode: "0644"
|
mode: "0644"
|
||||||
|
|
||||||
# --- Секреты: генерация с персистом на control-node (идемпотентно) --------
|
# --- Секреты: генерация с персистом на control-node (идемпотентно) --------
|
||||||
|
|||||||
125
backend/production.py
Normal file
125
backend/production.py
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
from .base import *
|
||||||
|
|
||||||
|
from logging.handlers import SysLogHandler
|
||||||
|
|
||||||
|
ALLOWED_HOSTS = env.list('ALLOWED_HOSTS')
|
||||||
|
|
||||||
|
FILE_UPLOAD_PERMISSIONS = 0o644
|
||||||
|
|
||||||
|
DEBUG = False
|
||||||
|
|
||||||
|
CSRF_COOKIE_SECURE = True
|
||||||
|
SESSION_COOKIE_SECURE = True
|
||||||
|
SECURE_SSL_REDIRECT = False
|
||||||
|
|
||||||
|
# STATIC_ROOT = env('STATIC_ROOT')
|
||||||
|
# MEDIA_ROOT = env('MEDIA_ROOT')
|
||||||
|
|
||||||
|
# SECRET_KEY = env('SECRET_KEY')
|
||||||
|
SECRET_KEY = 't2=9+($2f%7ptsdy4!rby$)mcfl1l%o2e@vs^d(g&(wwi&%k1v'
|
||||||
|
|
||||||
|
# DATABASE CONFIGURATION START
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
POSTGRES_DATABASE = env('DJANGO_POSTGRES_DATABASE')
|
||||||
|
POSTGRES_USER = env('DJANGO_POSTGRES_USER')
|
||||||
|
POSTGRES_PASSWORD = env('DJANGO_POSTGRES_PASSWORD')
|
||||||
|
POSTGRES_HOST = env('DJANGO_POSTGRES_HOST')
|
||||||
|
POSTGRES_PORTS = env('DJANGO_POSTGRES_PORTS', default="5432")
|
||||||
|
|
||||||
|
DATABASES = {
|
||||||
|
'default': {
|
||||||
|
'ENGINE': 'django_prometheus.db.backends.postgresql',
|
||||||
|
'NAME': POSTGRES_DATABASE,
|
||||||
|
'USER': POSTGRES_USER,
|
||||||
|
'PASSWORD': POSTGRES_PASSWORD,
|
||||||
|
'HOST': POSTGRES_HOST,
|
||||||
|
'PORT': POSTGRES_PORTS,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# DATABASE CONFIGURATION END
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
LOGGING = {
|
||||||
|
'version': 1,
|
||||||
|
'disable_existing_loggers': False,
|
||||||
|
'filters': {
|
||||||
|
'require_debug_false': {
|
||||||
|
'()': 'django.utils.log.RequireDebugFalse'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'formatters': {
|
||||||
|
'verbose': {
|
||||||
|
'format': '[contactor] %(levelname)s %(asctime)s %(message)s'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'handlers': {
|
||||||
|
# Send all messages to console
|
||||||
|
'console': {
|
||||||
|
'level': 'DEBUG',
|
||||||
|
'class': 'logging.StreamHandler',
|
||||||
|
},
|
||||||
|
# critical errors are logged to sentry
|
||||||
|
'sentry': {
|
||||||
|
'level': 'ERROR',
|
||||||
|
'filters': ['require_debug_false'],
|
||||||
|
'class': 'logging.StreamHandler',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'loggers': {
|
||||||
|
# This is the "catch all" logger
|
||||||
|
'': {
|
||||||
|
'handlers': ['console', 'sentry'],
|
||||||
|
'level': 'DEBUG',
|
||||||
|
'propagate': False,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
COMPARATOR_SECTION = env("COMPARATOR_SECTION", default="sarex-production-storage")
|
||||||
|
|
||||||
|
SIMPLE_JWT = {
|
||||||
|
# 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5),
|
||||||
|
'ACCESS_TOKEN_LIFETIME': timedelta(hours=1),
|
||||||
|
'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
|
||||||
|
'ROTATE_REFRESH_TOKENS': True,
|
||||||
|
'BLACKLIST_AFTER_ROTATION': False,
|
||||||
|
'UPDATE_LAST_LOGIN': False,
|
||||||
|
|
||||||
|
'ALGORITHM': 'RS512',
|
||||||
|
'SIGNING_KEY': env.str("JWT_PRIVATE_KEY").replace("\\n", "\n"),
|
||||||
|
'VERIFYING_KEY': env.str("JWT_PUBLIC_KEY").replace("\\n", "\n"),
|
||||||
|
'AUDIENCE': None,
|
||||||
|
'ISSUER': SIMPLE_JWT_ISSUER,
|
||||||
|
|
||||||
|
'AUTH_HEADER_TYPES': ('Bearer',),
|
||||||
|
'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
|
||||||
|
'USER_ID_FIELD': 'id',
|
||||||
|
'USER_ID_CLAIM': 'user_id',
|
||||||
|
|
||||||
|
'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
|
||||||
|
'TOKEN_TYPE_CLAIM': 'token_type',
|
||||||
|
|
||||||
|
'JTI_CLAIM': 'jti',
|
||||||
|
|
||||||
|
'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',
|
||||||
|
# 'SLIDING_TOKEN_LIFETIME': timedelta(minutes=5),
|
||||||
|
'SLIDING_TOKEN_LIFETIME': timedelta(hours=1),
|
||||||
|
'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1),
|
||||||
|
}
|
||||||
|
|
||||||
|
os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = "true"
|
||||||
|
|
||||||
|
COMPARISON_API_URL = f"{WORKFLOWSSETTINGS.host}/comparisons"
|
||||||
|
DOCUMENTATION_API_URL = f"{WORKFLOWSSETTINGS.host}/documentations"
|
||||||
|
PDM_FILES_API_URL = f"{WORKFLOWSSETTINGS.host}/files"
|
||||||
|
|
||||||
|
# --- Override для self-hosted (auth_type=original) --------------------------
|
||||||
|
# В base.py классическая SimpleJWT-аутентификация закомментирована (образ собран
|
||||||
|
# под Zitadel), поэтому Bearer-токен от /api/token/ отвергается защищёнными
|
||||||
|
# эндпоинтами. Возвращаем её первым классом; Session — для админки.
|
||||||
|
REST_FRAMEWORK["DEFAULT_AUTHENTICATION_CLASSES"] = [
|
||||||
|
"rest_framework_simplejwt.authentication.JWTAuthentication",
|
||||||
|
"rest_framework.authentication.SessionAuthentication",
|
||||||
|
"rest_framework.authentication.BasicAuthentication",
|
||||||
|
]
|
||||||
@ -302,6 +302,8 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
# свой uwsgi.ini поверх образного: http-socket + 4 воркера (:z — SELinux/RedOS)
|
# свой uwsgi.ini поверх образного: http-socket + 4 воркера (:z — SELinux/RedOS)
|
||||||
- ./backend/uwsgi.ini:/opt/sarex/uwsgi.ini:ro,z
|
- ./backend/uwsgi.ini:/opt/sarex/uwsgi.ini:ro,z
|
||||||
|
# production.py с включённой классической JWT-аутентификацией
|
||||||
|
- ./backend/production.py:/opt/sarex/config/settings/production.py:ro,z
|
||||||
depends_on:
|
depends_on:
|
||||||
postgres:
|
postgres:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
@ -321,6 +323,8 @@ services:
|
|||||||
entrypoint: celery -A config worker -l info -E -Q default -n default_worker.%h --concurrency=1 -B
|
entrypoint: celery -A config worker -l info -E -Q default -n default_worker.%h --concurrency=1 -B
|
||||||
environment:
|
environment:
|
||||||
<<: *sarex-backend-env
|
<<: *sarex-backend-env
|
||||||
|
volumes:
|
||||||
|
- ./backend/production.py:/opt/sarex/config/settings/production.py:ro,z
|
||||||
depends_on:
|
depends_on:
|
||||||
postgres:
|
postgres:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user