473 lines
15 KiB
Python
473 lines
15 KiB
Python
""" Django settings for console project. """
|
|
import os
|
|
import sys
|
|
|
|
from celery.schedules import crontab
|
|
from django.utils.translation import gettext_lazy
|
|
|
|
from console.services.product import load_product_version
|
|
|
|
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
|
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
|
|
DEBUG = int(os.environ.get('DEBUG', '0')) > 0
|
|
|
|
# Program is started under testing framework
|
|
TEST_MODE = 'test' in sys.argv or 'pytest' in sys.modules or os.environ.get("TEST_MODE")
|
|
|
|
# Program is used by developer (human), i.e. loads additional debug software
|
|
DEV_MODE = DEBUG and not TEST_MODE
|
|
|
|
# False to disable access to admin control panel via web
|
|
ADMIN_PANEL_ENABLED = DEV_MODE
|
|
|
|
##################################
|
|
### SECURITY ###
|
|
##################################
|
|
|
|
CORS_ALLOW_ALL_ORIGINS = True
|
|
CORS_ALLOW_CREDENTIALS = True
|
|
CORS_EXPOSE_HEADERS = ['Content-Disposition']
|
|
|
|
ALLOWED_HOSTS = ['*']
|
|
|
|
######################################
|
|
### APPLICATIONS ###
|
|
######################################
|
|
|
|
INSTALLED_APPS = [
|
|
'django.forms',
|
|
'django.contrib.admin',
|
|
'django.contrib.auth',
|
|
'django.contrib.contenttypes',
|
|
'django.contrib.sessions',
|
|
'django.contrib.messages',
|
|
'django.contrib.staticfiles',
|
|
'rest_framework',
|
|
'rest_framework.authtoken',
|
|
'django_json_widget',
|
|
'solo',
|
|
'django_celery_beat',
|
|
'sequences.apps.SequencesConfig',
|
|
'corsheaders',
|
|
'django_filters',
|
|
'channels',
|
|
]
|
|
|
|
PROJECT_APPS = [
|
|
'assets.apps.AssetsConfig',
|
|
'license_info.apps.LicenseInfoConfig',
|
|
'perms.apps.PermsConfig',
|
|
'console.apps.ConsoleConfig',
|
|
'core.apps.CoreConfig',
|
|
'correlation.apps.CorrelationConfig',
|
|
'dashboard.apps.DashboardConfig',
|
|
'company.apps.CompanyConfig',
|
|
'ncircc.apps.NcirccConfig',
|
|
'logstash.apps.LogstashConfig',
|
|
'networkmap.apps.NetworkmapConfig',
|
|
'users.apps.UsersConfig',
|
|
'incident_export.apps.IncidentExportConfig',
|
|
'storage.apps.StorageConfig',
|
|
'incident.apps.IncidentConfig',
|
|
'events.apps.EventsConfig',
|
|
'rotation.apps.RotationConfig',
|
|
'inputs.apps.InputsConfig',
|
|
'devices.apps.DevicesConfig',
|
|
'notifications.apps.NotificationsConfig',
|
|
]
|
|
|
|
INSTALLED_APPS += PROJECT_APPS
|
|
|
|
MIDDLEWARE = [
|
|
'core.middleware.LicenseMiddleware',
|
|
'django.middleware.security.SecurityMiddleware',
|
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
|
'django.middleware.locale.LocaleMiddleware',
|
|
'corsheaders.middleware.CorsMiddleware',
|
|
'django.middleware.common.CommonMiddleware',
|
|
'django.middleware.csrf.CsrfViewMiddleware',
|
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
|
'django.contrib.messages.middleware.MessageMiddleware',
|
|
'core.middleware.TimezoneMiddleware',
|
|
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
|
]
|
|
|
|
########################################
|
|
### AUTHENTICATION ###
|
|
########################################
|
|
|
|
AUTHENTICATION_BACKENDS = [
|
|
'core.backends.ConsoleAuthBackend.ConsoleAuthSystem',
|
|
'django.contrib.auth.backends.ModelBackend',
|
|
]
|
|
|
|
AUTH_PASSWORD_VALIDATORS = [
|
|
{
|
|
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
|
},
|
|
{
|
|
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
|
'OPTIONS': {
|
|
'min_length': 8,
|
|
}
|
|
},
|
|
{
|
|
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
|
},
|
|
{
|
|
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
|
},
|
|
]
|
|
|
|
##################################
|
|
### DATABASE ###
|
|
##################################
|
|
|
|
if not os.environ['POSTGRES_PORT']:
|
|
os.environ['POSTGRES_PORT'] = '5432'
|
|
DATABASES = {
|
|
'default': {
|
|
'ENGINE': "django.db.backends.postgresql", # Project depends on postgre, so no way to change it from env
|
|
'NAME': os.environ.get('POSTGRES_DB'),
|
|
'USER': os.environ.get('POSTGRES_USER'),
|
|
'PASSWORD': os.environ.get('POSTGRES_PASSWORD'),
|
|
'HOST': os.environ.get('POSTGRES_HOST'),
|
|
'PORT': os.environ.get('POSTGRES_PORT'),
|
|
}
|
|
}
|
|
|
|
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
|
|
|
|
#################################
|
|
### LOGGING ###
|
|
#################################
|
|
|
|
LOG_PATH = os.environ.get('LOG_PATH', os.path.join(BASE_DIR, 'dockerlogs'))
|
|
USER_LOG_FILENAME = os.environ.get('USER_LOG_FILENAME', 'console.log')
|
|
MIN_LOG_LEVEL = os.environ.get('MIN_LOG_LEVEL', 'DEBUG')
|
|
LOG_MAX_BYTES = int(os.environ.get('LOG_MAX_BYTES', 1024 * 1024 * 5))
|
|
LOG_BACKUP_COUNT = int(os.environ.get('LOG_BACKUP_COUNT', 500))
|
|
|
|
os.makedirs(LOG_PATH, exist_ok=True)
|
|
LOGGING = {
|
|
'version': 1,
|
|
'disable_existing_loggers': False,
|
|
'formatters': {
|
|
'info_message': {
|
|
'format': '%(asctime)s %(levelname)s %(message)s',
|
|
},
|
|
'debug_format': {
|
|
'format': '%(asctime)s %(levelname)s %(filename)s %(funcName)s %(message)s'
|
|
}
|
|
},
|
|
'handlers': {
|
|
'console': {
|
|
'class': 'logging.StreamHandler',
|
|
'level': MIN_LOG_LEVEL,
|
|
},
|
|
'file': {
|
|
'level': 'DEBUG',
|
|
'class': 'logging.handlers.RotatingFileHandler',
|
|
'filename': os.path.join(LOG_PATH, USER_LOG_FILENAME),
|
|
'formatter': 'info_message',
|
|
'encoding': 'utf-8',
|
|
'maxBytes': LOG_MAX_BYTES,
|
|
'backupCount': LOG_BACKUP_COUNT,
|
|
},
|
|
},
|
|
'loggers': {
|
|
'': {
|
|
'handlers': ['file', 'console'],
|
|
'level': MIN_LOG_LEVEL,
|
|
},
|
|
},
|
|
}
|
|
|
|
##############################################
|
|
### INTERNATIONALIZATION ###
|
|
##############################################
|
|
|
|
LANGUAGE_CODE = 'en'
|
|
LANGUAGES = [
|
|
('en', gettext_lazy('English')),
|
|
('ru', gettext_lazy('Russian')),
|
|
]
|
|
|
|
INITIAL_DATE_FORMAT = "Y-m-d"
|
|
|
|
# @see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
|
TIME_ZONE = os.environ.get('TIME_ZONE', 'UTC')
|
|
# Timezone used for users by default
|
|
DEFAULT_CURRENT_TIMEZONE = os.environ.get('DEFAULT_CURRENT_TIMEZONE', 'Europe/Moscow')
|
|
|
|
USE_I18N = True
|
|
USE_L10N = True
|
|
USE_TZ = True
|
|
|
|
LOCALE_PATHS = [
|
|
os.path.join(BASE_DIR, 'locale')
|
|
]
|
|
|
|
###############################
|
|
### FILES ###
|
|
###############################
|
|
|
|
# Build paths for generated files like static inside the project like this: os.path.join(PUBLIC_DIR, ...)
|
|
PUBLIC_DIR = os.environ.get('PUBLIC_DIR', os.path.join(BASE_DIR, 'public'))
|
|
|
|
PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
|
|
STATIC_URL = '/static/'
|
|
MEDIA_URL = '/media/'
|
|
STATIC_ROOT = os.path.join(PUBLIC_DIR, 'static')
|
|
MEDIA_ROOT = os.path.join(PUBLIC_DIR, 'media')
|
|
|
|
REDIS_HOST = os.environ.get('REDIS_HOST', 'redis')
|
|
REDIS_PORT = int(os.environ.get('REDIS_PORT', 6379))
|
|
REDIS_CACHE_TIMEOUT = 86400
|
|
|
|
###############################
|
|
### CACHE ###
|
|
###############################
|
|
|
|
SOLO_CACHE = 'local'
|
|
SOLO_CACHE_TIMEOUT = 60 * 5 # 5 mins
|
|
SOLO_CACHE_PREFIX = 'solo'
|
|
|
|
CACHES = {
|
|
'default': {
|
|
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
|
|
},
|
|
'local': {
|
|
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
|
|
},
|
|
'redis': {
|
|
'BACKEND': 'django_redis.cache.RedisCache',
|
|
'LOCATION': f'redis://{REDIS_HOST}:{REDIS_PORT}/1',
|
|
'OPTIONS': {
|
|
'CLIENT_CLASS': 'django_redis.client.DefaultClient'
|
|
}
|
|
}
|
|
}
|
|
|
|
#############################
|
|
### DRF ###
|
|
#############################
|
|
|
|
REST_FRAMEWORK = {
|
|
'DEFAULT_RENDERER_CLASSES': (
|
|
'rest_framework.renderers.JSONRenderer',
|
|
'rest_framework.renderers.BrowsableAPIRenderer',
|
|
),
|
|
'DEFAULT_FILTER_BACKENDS': (
|
|
'django_filters.rest_framework.DjangoFilterBackend',
|
|
'rest_framework.filters.OrderingFilter',
|
|
'core.backends.filters.SearchAllFieldsBackend',
|
|
),
|
|
'DEFAULT_PAGINATION_CLASS': 'core.services.pagination.BasicPagination',
|
|
'DEFAULT_PERMISSION_CLASSES': [
|
|
'rest_framework.permissions.IsAuthenticated',
|
|
],
|
|
'DEFAULT_AUTHENTICATION_CLASSES': [
|
|
'rest_framework.authentication.SessionAuthentication',
|
|
'rest_framework.authentication.TokenAuthentication',
|
|
],
|
|
}
|
|
|
|
################################
|
|
### CELERY ###
|
|
################################
|
|
|
|
CELERY_BROKER_URL = f'redis://{REDIS_HOST}:{REDIS_PORT}'
|
|
CELERY_RESULT_BACKEND = f'redis://{REDIS_HOST}:{REDIS_PORT}'
|
|
CELERY_ACCEPT_CONTENT = ['application/json']
|
|
CELERY_TASK_SERIALIZER = 'json'
|
|
CELERY_RESULT_SERIALIZER = 'json'
|
|
CELERY_TIMEZONE = TIME_ZONE
|
|
CELERY_IMPORTS = ['devices.tasks.firewall', 'devices.tasks.sensor']
|
|
|
|
""" Single place to setup at which time daily tasks should execute, crontab schedule object"""
|
|
DAILY_CRONTAB = crontab(minute='0', hour='1')
|
|
""" Single place to setup at which time weekly tasks should execute, crontab schedule object"""
|
|
WEEKLY_CRONTAB = crontab(minute='0', hour='1', day_of_week='1')
|
|
""" Single place to setup at which time monthly tasks should execute, crontab schedule object"""
|
|
MONTHLY_CRONTAB = crontab(minute='0', hour='1', day_of_month='1')
|
|
""" Execute every 2 minutes."""
|
|
EVERY_2_MINUTE = crontab(minute='*/2')
|
|
|
|
ROTATE_SIZE_CHECK_CRONTAB = crontab(minute='*/5')
|
|
CELERY_BEAT_SCHEDULE = {
|
|
'update_statistics': {
|
|
'task': 'dashboard.tasks.update_statistics_task',
|
|
'schedule': crontab()
|
|
},
|
|
'expire_users': {
|
|
'task': 'console.tasks.expire_users_task',
|
|
'schedule': DAILY_CRONTAB
|
|
},
|
|
'update_auto_network_map_data': {
|
|
'task': 'networkmap.tasks.update_auto_network_map_data',
|
|
'schedule': crontab()
|
|
},
|
|
'update_firewall_info_task': {
|
|
'task': 'devices.tasks.firewall.update_firewall_info_task',
|
|
'schedule': crontab()
|
|
},
|
|
'update_amount_of_elk_events': {
|
|
'task': 'console.tasks.update_amount_of_aggregated_events',
|
|
'schedule': crontab()
|
|
},
|
|
'check_blocked_users': {
|
|
'task': 'core.tasks.check_blocked_users',
|
|
'schedule': crontab()
|
|
},
|
|
'update_status_notification': {
|
|
'task': 'ncircc.tasks.update_status_notification',
|
|
'schedule': crontab(), # todo Уточнить точное время
|
|
},
|
|
'update_comments': {
|
|
'task': 'ncircc.tasks.update_comments',
|
|
'schedule': crontab(), # todo Уточнить точное время
|
|
},
|
|
'ping_sensors': {
|
|
'task': 'devices.tasks.sensor.ping_sensors',
|
|
'schedule': crontab()
|
|
},
|
|
'get_disk_usage_task': {
|
|
'task': 'core.tasks.get_disk_usage_task',
|
|
'schedule': crontab()
|
|
},
|
|
'reboot_correlator_task': {
|
|
'task': 'correlation.tasks.reboot_correlator_task',
|
|
'schedule': EVERY_2_MINUTE,
|
|
},
|
|
|
|
}
|
|
|
|
######################################
|
|
### AMC SERVICES ###
|
|
######################################
|
|
|
|
# LICENSE
|
|
LICENSE_CLIENT_URL = os.environ.get('LICENSE_CLIENT_URL', 'http://license-client:8050')
|
|
LICENSE_CACHE_TIMEOUT = 60 * 60 # 60 minutes
|
|
LICENSE_FEATURE_EVENT_PROCESSING = "event_processing"
|
|
LICENSE_OPTION_EVENT_SOURCE_COUNT = "event_sources"
|
|
|
|
# NGINX
|
|
NGINX_ENABLED_CONFIG_FILENAME = "armaconsole.nginx"
|
|
NGINX_HTTP_CONFIG_FILENAME = "armaconsole_http.nginx"
|
|
NGINX_HTTPS_CONFIG_FILENAME = "armaconsole_https.nginx"
|
|
NGINX_SITES_AVAILABLE = "/usr/local/armaconsole/nginx"
|
|
|
|
# CORRELATOR
|
|
CORRELATOR_SEVERITY_LEVEL = int(os.environ.get('CORRELATOR_SEVERITY_LEVEL', 6))
|
|
CORRELATOR_AUTO_CATEGORY_NAME = os.environ.get('CORRELATOR_AUTO_CATEGORY_NAME', gettext_lazy('Auto'))
|
|
CORRELATOR_URL = os.environ.get('CORRELATOR_URL', 'http://correlator:5566')
|
|
|
|
# VECTOR
|
|
LOGSTASH_CONFIG_DIR = os.environ.get('LOGSTASH_CONFIG_DIR', os.path.join(PUBLIC_DIR, 'vector'))
|
|
|
|
# ELASTICSEARCH
|
|
ELASTIC_URL = os.environ.get('ELASTIC_URL', 'http://elasticsearch:9200')
|
|
elk_split = ELASTIC_URL.replace('http://', '').split(':')
|
|
ELK_HOST = elk_split[0] if len(elk_split) >= 0 else 'elasticsearch'
|
|
ELK_PORT = elk_split[1] if len(elk_split) > 0 else 9200
|
|
ELK_LOGIN = os.environ.get('ELASTIC_USER', 'elastic')
|
|
ELK_PASS = os.environ.get('ELASTIC_PASSWORD', 'changeme')
|
|
ELK_MAX_ENTRIES = 100000
|
|
ELK_AGGREGATED_INDEX = 'aggregated-*'
|
|
ELK_FIREWALL_PRODUCT_NAME = 'Industrial Firerwall' # Yes this is mistake, but it is how now Vector parses IF logs
|
|
ELK_ENDPOINT_PRODUCT_NAME = 'Industrial Endpoint'
|
|
|
|
# RABBITMQ
|
|
RABBIT_URL = os.environ.get('RABBIT_URL', 'http://rabbitmq-management:5672')
|
|
rabbit_split = RABBIT_URL.replace('http://', '').split(':')
|
|
RABBIT_HOST = rabbit_split[0] if len(rabbit_split) >= 0 else 'rabbitmq-management'
|
|
RABBIT_PORT = rabbit_split[1] if len(rabbit_split) > 0 else 5672
|
|
|
|
###############################
|
|
### OTHER ###
|
|
###############################
|
|
|
|
# ROUTING
|
|
ROOT_URLCONF = 'console.urls'
|
|
WSGI_APPLICATION = 'console.wsgi.application'
|
|
ASGI_APPLICATION = 'console.asgi.application'
|
|
LOGIN_REDIRECT_URL = 'index'
|
|
LOGOUT_REDIRECT_URL = 'login'
|
|
LOGIN_URL = 'login'
|
|
|
|
CHANNEL_LAYERS = {
|
|
'default': {
|
|
'BACKEND': 'channels_redis.core.RedisChannelLayer',
|
|
'CONFIG': {
|
|
"hosts": [(REDIS_HOST, REDIS_PORT)],
|
|
},
|
|
},
|
|
}
|
|
|
|
# TEMPLATES
|
|
TEMPLATES = [
|
|
{
|
|
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
|
'DIRS': [],
|
|
'APP_DIRS': True,
|
|
'OPTIONS': {
|
|
'context_processors': [
|
|
'django.template.context_processors.debug',
|
|
'django.template.context_processors.request',
|
|
'django.contrib.auth.context_processors.auth',
|
|
'django.contrib.messages.context_processors.messages',
|
|
],
|
|
},
|
|
},
|
|
]
|
|
|
|
# Site info must not contain dynamic data, only static values
|
|
SITE_INFO = {
|
|
'domain': 'infowatch.ru',
|
|
'name': 'InfoWatch ARMA',
|
|
'package': 'armaconsole', # Must be a valid deb package name
|
|
'version': '1.4.0', # Must be a valid deb package version
|
|
'architecture': 'amd64', # Must be a valid deb package architecture
|
|
# These values are used in CEF format
|
|
'vendor': 'InfoWatch ARMA',
|
|
'product': 'ARMAMC'
|
|
}
|
|
|
|
# How many (in percent) keep in table while rotation occurs
|
|
# So 0.3 - means 30% of table will stay while rotation
|
|
SAVE_DURING_ROTATION = float(os.environ.get('SAVE_DURING_ROTATION', 0.3))
|
|
|
|
EMAIL_HOST_USER = 'console@arma.com'
|
|
EMAIL_HOST = 'localhost'
|
|
|
|
# GENERATE SELFSIGNED CERTIFICATE
|
|
TLS_CERT_DAYS = 365
|
|
TLS_CERT_KEY_SIZE = 2048
|
|
TLS_CERT_COUNTRY = "RU"
|
|
TLS_CERT_STATE = "Moscow"
|
|
TLS_CERT_LOCALITY = "Moscow"
|
|
TLS_CERT_ORIG_NAME = "ARMA"
|
|
TLS_CERT_UNIT_NAME = "Console"
|
|
TLS_CERT_COMMON_NAME = "iwarma.ru"
|
|
TLS_CERT_FILENAME = "/etc/nginx/ssl/armaconsole/nginx-selfsigned.crt"
|
|
TLS_CERT_KEY_FILENAME = "/etc/nginx/ssl/armaconsole/nginx-selfsigned.key"
|
|
# TODO: need use
|
|
TLS_CERT_DHPARAM_FILENAME = "/etc/nginx/ssl/armaconsole/dhparam.pem"
|
|
|
|
WEB_UI_PORT = int(os.environ.get('WEB_UI_PORT', 9090))
|
|
MAX_UPLOADSIZE = 80 * 1024 * 1024
|
|
|
|
# NCIRCC
|
|
NCIRCC_DOMAIN_NAME = os.environ.get('NCIRCC_DOMAIN_NAME', 'https://test-lk.cert.gov.ru')
|
|
NCIRCC_CERT_VERIFY = '/etc/ssl/certs/' if os.path.exists('/etc/ssl/certs/') else False
|
|
|
|
# Compatible ARMAIF versions
|
|
MINIMAL_COMPATIBLE_AIF_VERSION = "3.6"
|
|
|
|
MINIMAL_VERSION_CORRELATION_RULES = '1.3.4'
|
|
|
|
# Product version
|
|
PRODUCT_VERSION = load_product_version()
|