monsterops 1.12.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- monsterops-1.12.0/.env.example +38 -0
- monsterops-1.12.0/.gitignore +21 -0
- monsterops-1.12.0/CHANGELOG.md +110 -0
- monsterops-1.12.0/Dockerfile +18 -0
- monsterops-1.12.0/LICENSE +21 -0
- monsterops-1.12.0/PKG-INFO +138 -0
- monsterops-1.12.0/README.md +73 -0
- monsterops-1.12.0/SECURITY.md +25 -0
- monsterops-1.12.0/alembic/README +1 -0
- monsterops-1.12.0/alembic/env.py +85 -0
- monsterops-1.12.0/alembic/script.py.mako +28 -0
- monsterops-1.12.0/alembic/versions/a2f9c4b1e837_phase13_notifications.py +122 -0
- monsterops-1.12.0/alembic/versions/a4d1c7e6b520_firewall_autoblock.py +37 -0
- monsterops-1.12.0/alembic/versions/a9d4e7f2c1b5_realms_proxy.py +115 -0
- monsterops-1.12.0/alembic/versions/a9f3e2b1c0d8_retrograde_stop_trigger.py +39 -0
- monsterops-1.12.0/alembic/versions/b3e9a1f72c04_radpostauth_extra_columns.py +22 -0
- monsterops-1.12.0/alembic/versions/b6f2d8a3e91c_vpn_tunnels.py +54 -0
- monsterops-1.12.0/alembic/versions/b7d3f1e92a05_radpostauth_station_class_columns.py +21 -0
- monsterops-1.12.0/alembic/versions/b7f2c9a4e1d3_nas_reachability.py +35 -0
- monsterops-1.12.0/alembic/versions/b8e3f1a2d9c4_firewall_set_managed_source.py +22 -0
- monsterops-1.12.0/alembic/versions/c1f7b4a9d2e6_keyset_pagination_indexes.py +40 -0
- monsterops-1.12.0/alembic/versions/c2a8f4e71b93_radacct_unique_index_and_nasreload.py +27 -0
- monsterops-1.12.0/alembic/versions/c3f1a8e20d74_nas_manager.py +59 -0
- monsterops-1.12.0/alembic/versions/c7a1e3f92b84_nas_groups.py +48 -0
- monsterops-1.12.0/alembic/versions/c9e4b1f2a8d5_phase14_integrations.py +50 -0
- monsterops-1.12.0/alembic/versions/d1e5f8a2c3b7_phase15_apikeys_scheduler.py +75 -0
- monsterops-1.12.0/alembic/versions/d2e8b3f1a9c7_mr_bulk_jobs.py +32 -0
- monsterops-1.12.0/alembic/versions/d3b7f0a15c92_firewall_block_event.py +38 -0
- monsterops-1.12.0/alembic/versions/d4b2f6c81e93_nas_config_history.py +57 -0
- monsterops-1.12.0/alembic/versions/e1f4a9c2b6d8_mr_webhook_subs.py +36 -0
- monsterops-1.12.0/alembic/versions/e3a7f1c90d52_group_access_types.py +28 -0
- monsterops-1.12.0/alembic/versions/e5c9a1f3d827_auth_framework.py +134 -0
- monsterops-1.12.0/alembic/versions/e7c3a9d15f84_firewall.py +93 -0
- monsterops-1.12.0/alembic/versions/e85388a04f39_initial_schema.py +162 -0
- monsterops-1.12.0/alembic/versions/f2a8c4d97b16_log_table_indexes.py +19 -0
- monsterops-1.12.0/alembic/versions/f3a7c1e2d9b4_mr_automation_rules.py +39 -0
- monsterops-1.12.0/alembic/versions/f4c8d2a91b37_phase9_auth_enrichment.py +23 -0
- monsterops-1.12.0/alembic/versions/fd99a6deb43d_add_audit_log.py +35 -0
- monsterops-1.12.0/alembic.ini +150 -0
- monsterops-1.12.0/assets/MonsterOpsDO.png +0 -0
- monsterops-1.12.0/assets/monsterops-logo.jpg +0 -0
- monsterops-1.12.0/deploy/freeradius/mods-available/sql +406 -0
- monsterops-1.12.0/deploy/freeradius/mods-config/sql/main/postgresql/queries.conf +753 -0
- monsterops-1.12.0/deploy/install.sh +408 -0
- monsterops-1.12.0/deploy/provision-ad.sh +276 -0
- monsterops-1.12.0/deploy/provision-sudoers.sh +85 -0
- monsterops-1.12.0/deploy/provision-vpn.sh +114 -0
- monsterops-1.12.0/deploy/upgrade.sh +222 -0
- monsterops-1.12.0/docker-compose.yml +35 -0
- monsterops-1.12.0/docs/active-directory-auth.md +255 -0
- monsterops-1.12.0/docs/reference.md +251 -0
- monsterops-1.12.0/docs/user-guide.md +464 -0
- monsterops-1.12.0/monsterops/__init__.py +7 -0
- monsterops-1.12.0/monsterops/app.py +246 -0
- monsterops-1.12.0/monsterops/cli.py +568 -0
- monsterops-1.12.0/monsterops/config.py +106 -0
- monsterops-1.12.0/monsterops/database.py +29 -0
- monsterops-1.12.0/monsterops/events.py +51 -0
- monsterops-1.12.0/monsterops/geo.py +108 -0
- monsterops-1.12.0/monsterops/keyrotate.py +71 -0
- monsterops-1.12.0/monsterops/limiter.py +6 -0
- monsterops-1.12.0/monsterops/modules/__init__.py +0 -0
- monsterops-1.12.0/monsterops/modules/accounting/__init__.py +0 -0
- monsterops-1.12.0/monsterops/modules/accounting/coa.py +172 -0
- monsterops-1.12.0/monsterops/modules/accounting/models.py +63 -0
- monsterops-1.12.0/monsterops/modules/accounting/radius.dict +17 -0
- monsterops-1.12.0/monsterops/modules/accounting/router.py +299 -0
- monsterops-1.12.0/monsterops/modules/accounting/schemas.py +60 -0
- monsterops-1.12.0/monsterops/modules/accounting/static/accounting.js +685 -0
- monsterops-1.12.0/monsterops/modules/accounting/static/manifest.json +12 -0
- monsterops-1.12.0/monsterops/modules/apikeys/__init__.py +0 -0
- monsterops-1.12.0/monsterops/modules/apikeys/models.py +27 -0
- monsterops-1.12.0/monsterops/modules/apikeys/router.py +210 -0
- monsterops-1.12.0/monsterops/modules/apikeys/schemas.py +30 -0
- monsterops-1.12.0/monsterops/modules/apikeys/static/apikeys.js +338 -0
- monsterops-1.12.0/monsterops/modules/apikeys/static/manifest.json +5 -0
- monsterops-1.12.0/monsterops/modules/apikeys/v1.py +754 -0
- monsterops-1.12.0/monsterops/modules/auth/__init__.py +0 -0
- monsterops-1.12.0/monsterops/modules/auth/models.py +40 -0
- monsterops-1.12.0/monsterops/modules/auth/router.py +333 -0
- monsterops-1.12.0/monsterops/modules/auth/schemas.py +71 -0
- monsterops-1.12.0/monsterops/modules/auth/utils.py +201 -0
- monsterops-1.12.0/monsterops/modules/auth_logs/__init__.py +0 -0
- monsterops-1.12.0/monsterops/modules/auth_logs/models.py +29 -0
- monsterops-1.12.0/monsterops/modules/auth_logs/router.py +383 -0
- monsterops-1.12.0/monsterops/modules/auth_logs/schemas.py +50 -0
- monsterops-1.12.0/monsterops/modules/auth_logs/static/auth_logs.js +821 -0
- monsterops-1.12.0/monsterops/modules/auth_logs/static/manifest.json +12 -0
- monsterops-1.12.0/monsterops/modules/automation/__init__.py +0 -0
- monsterops-1.12.0/monsterops/modules/automation/engine.py +335 -0
- monsterops-1.12.0/monsterops/modules/automation/models.py +23 -0
- monsterops-1.12.0/monsterops/modules/automation/router.py +169 -0
- monsterops-1.12.0/monsterops/modules/automation/static/automation.js +639 -0
- monsterops-1.12.0/monsterops/modules/automation/static/manifest.json +12 -0
- monsterops-1.12.0/monsterops/modules/dashboard/__init__.py +0 -0
- monsterops-1.12.0/monsterops/modules/dashboard/router.py +240 -0
- monsterops-1.12.0/monsterops/modules/dashboard/schemas.py +62 -0
- monsterops-1.12.0/monsterops/modules/dashboard/static/dashboard.js +1074 -0
- monsterops-1.12.0/monsterops/modules/dashboard/static/manifest.json +7 -0
- monsterops-1.12.0/monsterops/modules/firewall/__init__.py +0 -0
- monsterops-1.12.0/monsterops/modules/firewall/generator.py +203 -0
- monsterops-1.12.0/monsterops/modules/firewall/geoblock.py +149 -0
- monsterops-1.12.0/monsterops/modules/firewall/models.py +114 -0
- monsterops-1.12.0/monsterops/modules/firewall/nft.py +96 -0
- monsterops-1.12.0/monsterops/modules/firewall/presets.py +81 -0
- monsterops-1.12.0/monsterops/modules/firewall/router.py +665 -0
- monsterops-1.12.0/monsterops/modules/firewall/schemas.py +193 -0
- monsterops-1.12.0/monsterops/modules/firewall/service.py +543 -0
- monsterops-1.12.0/monsterops/modules/firewall/static/firewall.js +1048 -0
- monsterops-1.12.0/monsterops/modules/firewall/static/manifest.json +12 -0
- monsterops-1.12.0/monsterops/modules/firewall/validators.py +79 -0
- monsterops-1.12.0/monsterops/modules/firewall/worker.py +168 -0
- monsterops-1.12.0/monsterops/modules/groups/__init__.py +0 -0
- monsterops-1.12.0/monsterops/modules/groups/models.py +40 -0
- monsterops-1.12.0/monsterops/modules/groups/router.py +601 -0
- monsterops-1.12.0/monsterops/modules/groups/schemas.py +85 -0
- monsterops-1.12.0/monsterops/modules/groups/static/groups.js +1100 -0
- monsterops-1.12.0/monsterops/modules/groups/static/manifest.json +12 -0
- monsterops-1.12.0/monsterops/modules/health/__init__.py +0 -0
- monsterops-1.12.0/monsterops/modules/health/router.py +574 -0
- monsterops-1.12.0/monsterops/modules/health/schemas.py +36 -0
- monsterops-1.12.0/monsterops/modules/health/static/health.js +519 -0
- monsterops-1.12.0/monsterops/modules/health/static/manifest.json +12 -0
- monsterops-1.12.0/monsterops/modules/integrations/__init__.py +0 -0
- monsterops-1.12.0/monsterops/modules/integrations/graylog_client.py +108 -0
- monsterops-1.12.0/monsterops/modules/integrations/models.py +21 -0
- monsterops-1.12.0/monsterops/modules/integrations/router.py +257 -0
- monsterops-1.12.0/monsterops/modules/integrations/schemas.py +38 -0
- monsterops-1.12.0/monsterops/modules/integrations/static/img/graylog.svg +1 -0
- monsterops-1.12.0/monsterops/modules/integrations/static/img/zabbix.svg +1 -0
- monsterops-1.12.0/monsterops/modules/integrations/static/integrations.js +1166 -0
- monsterops-1.12.0/monsterops/modules/integrations/static/manifest.json +5 -0
- monsterops-1.12.0/monsterops/modules/integrations/zabbix_client.py +178 -0
- monsterops-1.12.0/monsterops/modules/ip_pools/__init__.py +0 -0
- monsterops-1.12.0/monsterops/modules/ip_pools/models.py +20 -0
- monsterops-1.12.0/monsterops/modules/ip_pools/router.py +253 -0
- monsterops-1.12.0/monsterops/modules/ip_pools/schemas.py +54 -0
- monsterops-1.12.0/monsterops/modules/ip_pools/static/ip_pools.js +942 -0
- monsterops-1.12.0/monsterops/modules/ip_pools/static/manifest.json +12 -0
- monsterops-1.12.0/monsterops/modules/nas/__init__.py +0 -0
- monsterops-1.12.0/monsterops/modules/nas/models.py +64 -0
- monsterops-1.12.0/monsterops/modules/nas/probe.py +142 -0
- monsterops-1.12.0/monsterops/modules/nas/radius_attr_hints.py +167 -0
- monsterops-1.12.0/monsterops/modules/nas/router.py +630 -0
- monsterops-1.12.0/monsterops/modules/nas/schemas.py +152 -0
- monsterops-1.12.0/monsterops/modules/nas/static/manifest.json +12 -0
- monsterops-1.12.0/monsterops/modules/nas/static/nas.js +1782 -0
- monsterops-1.12.0/monsterops/modules/nas_manager/__init__.py +0 -0
- monsterops-1.12.0/monsterops/modules/nas_manager/crypto.py +30 -0
- monsterops-1.12.0/monsterops/modules/nas_manager/history.py +126 -0
- monsterops-1.12.0/monsterops/modules/nas_manager/models.py +80 -0
- monsterops-1.12.0/monsterops/modules/nas_manager/radius_deploy.py +264 -0
- monsterops-1.12.0/monsterops/modules/nas_manager/router.py +873 -0
- monsterops-1.12.0/monsterops/modules/nas_manager/schemas.py +258 -0
- monsterops-1.12.0/monsterops/modules/nas_manager/service.py +125 -0
- monsterops-1.12.0/monsterops/modules/nas_manager/static/manifest.json +5 -0
- monsterops-1.12.0/monsterops/modules/nas_manager/static/nas_manager.js +1353 -0
- monsterops-1.12.0/monsterops/modules/nas_manager/vendor_map.py +71 -0
- monsterops-1.12.0/monsterops/modules/nas_manager/worker.py +89 -0
- monsterops-1.12.0/monsterops/modules/notifications/__init__.py +0 -0
- monsterops-1.12.0/monsterops/modules/notifications/channels.py +97 -0
- monsterops-1.12.0/monsterops/modules/notifications/models.py +61 -0
- monsterops-1.12.0/monsterops/modules/notifications/router.py +178 -0
- monsterops-1.12.0/monsterops/modules/notifications/schemas.py +81 -0
- monsterops-1.12.0/monsterops/modules/notifications/static/manifest.json +12 -0
- monsterops-1.12.0/monsterops/modules/notifications/static/notifications.js +881 -0
- monsterops-1.12.0/monsterops/modules/notifications/worker.py +208 -0
- monsterops-1.12.0/monsterops/modules/radius_logs/__init__.py +0 -0
- monsterops-1.12.0/monsterops/modules/radius_logs/static/manifest.json +5 -0
- monsterops-1.12.0/monsterops/modules/radius_logs/static/radius_logs.js +407 -0
- monsterops-1.12.0/monsterops/modules/realms/__init__.py +0 -0
- monsterops-1.12.0/monsterops/modules/realms/enforcement/__init__.py +16 -0
- monsterops-1.12.0/monsterops/modules/realms/enforcement/base.py +47 -0
- monsterops-1.12.0/monsterops/modules/realms/enforcement/freeradius.py +207 -0
- monsterops-1.12.0/monsterops/modules/realms/ldap_probe.py +132 -0
- monsterops-1.12.0/monsterops/modules/realms/ldap_sync.py +544 -0
- monsterops-1.12.0/monsterops/modules/realms/models.py +199 -0
- monsterops-1.12.0/monsterops/modules/realms/probe.py +111 -0
- monsterops-1.12.0/monsterops/modules/realms/proxyconf.py +135 -0
- monsterops-1.12.0/monsterops/modules/realms/radius.dict +4 -0
- monsterops-1.12.0/monsterops/modules/realms/router.py +1181 -0
- monsterops-1.12.0/monsterops/modules/realms/schemas.py +402 -0
- monsterops-1.12.0/monsterops/modules/realms/static/manifest.json +12 -0
- monsterops-1.12.0/monsterops/modules/realms/static/realms.js +1604 -0
- monsterops-1.12.0/monsterops/modules/reports/__init__.py +0 -0
- monsterops-1.12.0/monsterops/modules/reports/router.py +302 -0
- monsterops-1.12.0/monsterops/modules/reports/schemas.py +39 -0
- monsterops-1.12.0/monsterops/modules/reports/static/manifest.json +12 -0
- monsterops-1.12.0/monsterops/modules/reports/static/reports.js +552 -0
- monsterops-1.12.0/monsterops/modules/scheduler/__init__.py +0 -0
- monsterops-1.12.0/monsterops/modules/scheduler/jobs.py +455 -0
- monsterops-1.12.0/monsterops/modules/scheduler/models.py +45 -0
- monsterops-1.12.0/monsterops/modules/scheduler/router.py +160 -0
- monsterops-1.12.0/monsterops/modules/scheduler/schemas.py +56 -0
- monsterops-1.12.0/monsterops/modules/scheduler/service.py +172 -0
- monsterops-1.12.0/monsterops/modules/scheduler/static/manifest.json +5 -0
- monsterops-1.12.0/monsterops/modules/scheduler/static/scheduler.js +465 -0
- monsterops-1.12.0/monsterops/modules/system/__init__.py +0 -0
- monsterops-1.12.0/monsterops/modules/system/router.py +304 -0
- monsterops-1.12.0/monsterops/modules/system/static/manifest.json +12 -0
- monsterops-1.12.0/monsterops/modules/system/static/system.js +1006 -0
- monsterops-1.12.0/monsterops/modules/users/__init__.py +0 -0
- monsterops-1.12.0/monsterops/modules/users/models.py +58 -0
- monsterops-1.12.0/monsterops/modules/users/router.py +1205 -0
- monsterops-1.12.0/monsterops/modules/users/schemas.py +235 -0
- monsterops-1.12.0/monsterops/modules/users/static/manifest.json +12 -0
- monsterops-1.12.0/monsterops/modules/users/static/users.js +1817 -0
- monsterops-1.12.0/monsterops/modules/vpn/__init__.py +0 -0
- monsterops-1.12.0/monsterops/modules/vpn/backends/__init__.py +0 -0
- monsterops-1.12.0/monsterops/modules/vpn/backends/base.py +145 -0
- monsterops-1.12.0/monsterops/modules/vpn/backends/l2tp_ipsec.py +242 -0
- monsterops-1.12.0/monsterops/modules/vpn/backends/wireguard.py +128 -0
- monsterops-1.12.0/monsterops/modules/vpn/models.py +44 -0
- monsterops-1.12.0/monsterops/modules/vpn/router.py +268 -0
- monsterops-1.12.0/monsterops/modules/vpn/schemas.py +271 -0
- monsterops-1.12.0/monsterops/modules/vpn/service.py +32 -0
- monsterops-1.12.0/monsterops/modules/vpn/static/manifest.json +12 -0
- monsterops-1.12.0/monsterops/modules/vpn/static/vpn.js +618 -0
- monsterops-1.12.0/monsterops/modules/vpn/wgkeys.py +69 -0
- monsterops-1.12.0/monsterops/modules/vpn/worker.py +41 -0
- monsterops-1.12.0/monsterops/modules/webhooks/__init__.py +0 -0
- monsterops-1.12.0/monsterops/modules/webhooks/handler.py +122 -0
- monsterops-1.12.0/monsterops/modules/webhooks/models.py +21 -0
- monsterops-1.12.0/monsterops/modules/webhooks/router.py +225 -0
- monsterops-1.12.0/monsterops/modules/webhooks/static/manifest.json +5 -0
- monsterops-1.12.0/monsterops/modules/webhooks/static/webhooks.js +506 -0
- monsterops-1.12.0/monsterops/pagination.py +20 -0
- monsterops-1.12.0/monsterops/plugins/__init__.py +0 -0
- monsterops-1.12.0/monsterops/plugins/loader.py +49 -0
- monsterops-1.12.0/monsterops/radius_reload.py +115 -0
- monsterops-1.12.0/monsterops/static/css/theme.css +401 -0
- monsterops-1.12.0/monsterops/static/img/monsterops-mascot.png +0 -0
- monsterops-1.12.0/monsterops/static/index.html +25 -0
- monsterops-1.12.0/monsterops/static/js/api.js +131 -0
- monsterops-1.12.0/monsterops/static/js/app.js +199 -0
- monsterops-1.12.0/monsterops/static/js/components/app-confirm.js +145 -0
- monsterops-1.12.0/monsterops/static/js/components/app-sidebar.js +653 -0
- monsterops-1.12.0/monsterops/static/js/components/app-statusbar.js +187 -0
- monsterops-1.12.0/monsterops/static/js/components/app-toast.js +105 -0
- monsterops-1.12.0/monsterops/static/js/components/base-component.js +51 -0
- monsterops-1.12.0/monsterops/static/js/components/mr-card.js +93 -0
- monsterops-1.12.0/monsterops/static/js/components/mr-modal.js +179 -0
- monsterops-1.12.0/monsterops/static/js/components/server-console.js +519 -0
- monsterops-1.12.0/monsterops/static/js/components/signal-pulse.js +103 -0
- monsterops-1.12.0/monsterops/static/js/loader.js +22 -0
- monsterops-1.12.0/monsterops/static/js/router.js +49 -0
- monsterops-1.12.0/monsterops/static/js/utils/countries.js +263 -0
- monsterops-1.12.0/monsterops/static/js/utils/empty.js +151 -0
- monsterops-1.12.0/monsterops/static/js/utils/form.js +88 -0
- monsterops-1.12.0/monsterops/static/js/utils/geo.js +45 -0
- monsterops-1.12.0/monsterops/static/js/utils/poll.js +41 -0
- monsterops-1.12.0/monsterops/static/js/utils/sparkline.js +96 -0
- monsterops-1.12.0/monsterops/static/js/utils/table.js +186 -0
- monsterops-1.12.0/monsterops/static/js/views/login.js +167 -0
- monsterops-1.12.0/monsterops/static/js/views/setup.js +146 -0
- monsterops-1.12.0/monsterops/static/js/views/style_guide.js +289 -0
- monsterops-1.12.0/pyproject.toml +69 -0
- monsterops-1.12.0/scripts/mr-firewall-panic.sh +47 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# MonsterOps environment variables
|
|
2
|
+
# Copy this file to .env and fill in real values before starting.
|
|
3
|
+
|
|
4
|
+
# PostgreSQL connection string (asyncpg dialect)
|
|
5
|
+
MONSTEROPS_DATABASE_URL=postgresql+asyncpg://radius:CHANGE_ME@localhost/radius
|
|
6
|
+
|
|
7
|
+
# JWT signing secret — generate with: openssl rand -hex 32
|
|
8
|
+
MONSTEROPS_SECRET_KEY=CHANGE_ME_USE_32_RANDOM_BYTES
|
|
9
|
+
|
|
10
|
+
# Set to true only in development — exposes /docs and /redoc
|
|
11
|
+
MONSTEROPS_DEBUG=false
|
|
12
|
+
|
|
13
|
+
# Log level: debug | info | warning | error
|
|
14
|
+
MONSTEROPS_LOG_LEVEL=info
|
|
15
|
+
|
|
16
|
+
# Comma-separated allowed CORS origins (leave empty to disable CORS)
|
|
17
|
+
# MONSTEROPS_ALLOWED_ORIGINS=https://your-domain.com
|
|
18
|
+
|
|
19
|
+
# Directory where the VPN module writes WireGuard tunnel configs (mode 0600).
|
|
20
|
+
# Must be writable by the service user; the private key is stored here.
|
|
21
|
+
# MONSTEROPS_VPN_CONFIG_DIR=/etc/monsterops/vpn
|
|
22
|
+
|
|
23
|
+
# ── Database connection pool ──────────────────────────────────────────────────
|
|
24
|
+
# Steady pool + burst overflow. Raise pool size on busy instances with many
|
|
25
|
+
# concurrent admins/log streams; keep pool_size + max_overflow below the
|
|
26
|
+
# PostgreSQL max_connections budget for this app.
|
|
27
|
+
# MONSTEROPS_DB_POOL_SIZE=10
|
|
28
|
+
# MONSTEROPS_DB_MAX_OVERFLOW=20
|
|
29
|
+
# MONSTEROPS_DB_POOL_TIMEOUT=30
|
|
30
|
+
# MONSTEROPS_DB_POOL_RECYCLE=1800
|
|
31
|
+
|
|
32
|
+
# ── Log retention (days) ──────────────────────────────────────────────────────
|
|
33
|
+
# Used by the "Log Retention" scheduler job (create it under Scheduler → New
|
|
34
|
+
# Job). 0 = keep forever.
|
|
35
|
+
# MONSTEROPS_RETENTION_AUTH_LOG_DAYS=90 # radpostauth (RADIUS auth attempts)
|
|
36
|
+
# MONSTEROPS_RETENTION_AUDIT_LOG_DAYS=365 # audit_log (admin actions)
|
|
37
|
+
# MONSTEROPS_RETENTION_NOTIFICATION_DAYS=90 # notification history
|
|
38
|
+
# MONSTEROPS_RETENTION_DISPATCH_LOG_DAYS=180 # NAS command dispatch log
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*.egg-info/
|
|
4
|
+
dist/
|
|
5
|
+
build/
|
|
6
|
+
.venv/
|
|
7
|
+
venv/
|
|
8
|
+
.env
|
|
9
|
+
.env.local
|
|
10
|
+
*.sqlite3
|
|
11
|
+
.mypy_cache/
|
|
12
|
+
.ruff_cache/
|
|
13
|
+
.pytest_cache/
|
|
14
|
+
node_modules/
|
|
15
|
+
logs/
|
|
16
|
+
data/
|
|
17
|
+
|
|
18
|
+
# Editor / OS
|
|
19
|
+
.DS_Store
|
|
20
|
+
.idea/
|
|
21
|
+
.vscode/
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **`pip install monsterops` now works end to end.** The database migrations ship
|
|
8
|
+
inside the package, and a new `monsterops migrate` command creates or upgrades the
|
|
9
|
+
schema — so you can install from PyPI, run `monsterops migrate`, then
|
|
10
|
+
`monsterops serve` without a source checkout. From a checkout, `alembic upgrade head`
|
|
11
|
+
still works too.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- `monsterops.__version__` now reports the installed package version instead of a
|
|
16
|
+
stale hardcoded value.
|
|
17
|
+
|
|
18
|
+
## v1.12.0 — 2026-07-20
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- **Point a NAS at this RADIUS server in one click.** A new **RADIUS Setup** tab
|
|
23
|
+
in NAS Manager generates the vendor-specific RADIUS-client config for a managed
|
|
24
|
+
device — you tick which services should authenticate (PPP/PPPoE, hotspot, admin
|
|
25
|
+
login, 802.1X), preview the exact commands, then push them over SSH. The running
|
|
26
|
+
config is snapshotted first for rollback. MikroTik (RouterOS v6 and v7) and
|
|
27
|
+
Huawei produce real, pushable config; other vendors get a preview-only reference
|
|
28
|
+
block. The generated MikroTik config also enables CoA/Disconnect so you can drop
|
|
29
|
+
a live session from the UI.
|
|
30
|
+
- **Automation can run a command on a NAS.** A new **Run NAS command** rule action
|
|
31
|
+
runs a single CLI command on a managed NAS over SSH when a matching event fires,
|
|
32
|
+
using the credentials NAS Manager already stores. Commands can reference the
|
|
33
|
+
triggering event (`{entity_id}`, `{actor}`, `{type}`, `{data.<key>}`) — for
|
|
34
|
+
example, kicking a user's live session the moment they're disabled.
|
|
35
|
+
- **Secret-key rotation.** A new `monsterops rotate-secret-key` command re-encrypts
|
|
36
|
+
every stored credential (NAS Manager SSH secrets and directory bind passwords)
|
|
37
|
+
when you change `MONSTEROPS_SECRET_KEY`, so rotating the key no longer orphans
|
|
38
|
+
them. It is abort-safe and supports a `--dry-run`.
|
|
39
|
+
- **Server Console command history.** The console's command palette now keeps a
|
|
40
|
+
"Recent runs" list — each command with its result and a timestamp — that persists
|
|
41
|
+
across page reloads.
|
|
42
|
+
|
|
43
|
+
### Changed
|
|
44
|
+
|
|
45
|
+
- **The Server Console is now off by default.** Because its palette restarts
|
|
46
|
+
FreeRADIUS and runs migrations from the browser, it is opt-in: set
|
|
47
|
+
`MONSTEROPS_CONSOLE_ENABLED=true` to enable it. Installs that relied on the
|
|
48
|
+
console will need to set this.
|
|
49
|
+
|
|
50
|
+
## v1.11.1 — 2026-07-16
|
|
51
|
+
|
|
52
|
+
### Added
|
|
53
|
+
|
|
54
|
+
- **NAS reachability monitoring.** A background ICMP probe reports a true
|
|
55
|
+
reachable/unreachable state per NAS on the dashboard, distinct from the existing
|
|
56
|
+
activity-based "idle" — so a quiet device is shown *idle but up*, while one that
|
|
57
|
+
has genuinely dropped off the network is shown *down*. Subnet/wildcard clients
|
|
58
|
+
are marked *skipped*. Configurable via `MONSTEROPS_NAS_PROBE_ENABLED`.
|
|
59
|
+
|
|
60
|
+
### Fixed
|
|
61
|
+
|
|
62
|
+
- **Delegated Active Directory logins after wiring the host.** The AD provisioning
|
|
63
|
+
script now restarts FreeRADIUS instead of reloading it, so the newly added
|
|
64
|
+
authentication module is loaded and delegated (live-AD-password) logins succeed.
|
|
65
|
+
|
|
66
|
+
## v1.11.0 — 2026-07-16
|
|
67
|
+
|
|
68
|
+
### Added
|
|
69
|
+
|
|
70
|
+
- **Per-realm authentication with Active Directory.** Authentication is now
|
|
71
|
+
configured per realm as an identity source plus a method: **Local password**
|
|
72
|
+
(MonsterOps owns each subscriber's password; works offline, any protocol) or
|
|
73
|
+
**Directory-delegated** (subscribers sign in with their real Active Directory
|
|
74
|
+
password, verified live against a Domain Controller via winbind/`ntlm_auth`).
|
|
75
|
+
Import all or selected users from AD, map AD groups to MonsterOps groups and
|
|
76
|
+
plans, and see each account's source (its AD realm, or Local) in the Users
|
|
77
|
+
view. Delegated realms show a **host: ready / needs join** indicator with the
|
|
78
|
+
exact one-time setup command. Full walkthrough in the
|
|
79
|
+
[Active Directory guide](docs/active-directory-auth.md).
|
|
80
|
+
- **Adaptive firewall access control.** The nftables firewall manager gained
|
|
81
|
+
brute-force auto-blocking with a structured audit trail and a dashboard
|
|
82
|
+
widget; **"allow only this country"** inverse blocking with layered
|
|
83
|
+
anti-lockout guards that keep management (SSH/web) and RADIUS reachable; and
|
|
84
|
+
self-lockout / NAS-impact warnings before a block takes effect, so a
|
|
85
|
+
fat-fingered blocklist entry can't cut off admin access or silently break a
|
|
86
|
+
NAS. A last-resort `scripts/mr-firewall-panic.sh` restores connectivity from
|
|
87
|
+
the shell.
|
|
88
|
+
|
|
89
|
+
### Changed
|
|
90
|
+
|
|
91
|
+
- **Faster large-table browsing.** Live sessions, accounting, and auth logs use
|
|
92
|
+
keyset pagination for consistent performance on large datasets.
|
|
93
|
+
|
|
94
|
+
### Fixed
|
|
95
|
+
|
|
96
|
+
- **Dashboard:** the header icons (drill-through chevron, refresh, settings
|
|
97
|
+
gear) no longer briefly flash oversized and blue when returning to the
|
|
98
|
+
Dashboard from another page.
|
|
99
|
+
- **Sidebar:** collapsing the sidebar to its icon rail now hides labels cleanly
|
|
100
|
+
and keeps the icons centred.
|
|
101
|
+
|
|
102
|
+
## v1.10.0 — Initial public release
|
|
103
|
+
|
|
104
|
+
The first public release of MonsterOps — a self-hosted network operations
|
|
105
|
+
platform for FreeRADIUS environments. Includes user & group management, NAS
|
|
106
|
+
device and NAS SSH/Telnet management, IP pool management, live session
|
|
107
|
+
monitoring with CoA, auth logs & analytics, reports, RADIUS proxy & realms,
|
|
108
|
+
WireGuard and L2TP/IPsec VPN tunnels, an nftables firewall manager, automation
|
|
109
|
+
& scheduling, webhooks & event bus, a scoped REST API, and integrations
|
|
110
|
+
(Zabbix, Graylog, MaxMind GeoIP2).
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
FROM python:3.11-slim
|
|
2
|
+
|
|
3
|
+
WORKDIR /app
|
|
4
|
+
|
|
5
|
+
RUN apt-get update \
|
|
6
|
+
&& apt-get install -y --no-install-recommends postgresql-client \
|
|
7
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
8
|
+
|
|
9
|
+
COPY pyproject.toml LICENSE README.md ./
|
|
10
|
+
COPY monsterops/ monsterops/
|
|
11
|
+
COPY alembic/ alembic/
|
|
12
|
+
COPY alembic.ini .
|
|
13
|
+
|
|
14
|
+
RUN pip install --no-cache-dir -e .
|
|
15
|
+
|
|
16
|
+
EXPOSE 8000
|
|
17
|
+
|
|
18
|
+
CMD ["monsterops", "serve", "--host", "0.0.0.0", "--port", "8000"]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 NLRI65000
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: monsterops
|
|
3
|
+
Version: 1.12.0
|
|
4
|
+
Summary: A self-hosted network operations platform built around FreeRADIUS
|
|
5
|
+
Project-URL: Homepage, https://github.com/NLRI65000/MonsterOps
|
|
6
|
+
Project-URL: Repository, https://github.com/NLRI65000/MonsterOps
|
|
7
|
+
Project-URL: Issues, https://github.com/NLRI65000/MonsterOps/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/NLRI65000/MonsterOps/blob/main/CHANGELOG.md
|
|
9
|
+
Author-email: NLRI65000 <nlrigithub@hotmail.com>
|
|
10
|
+
License: MIT License
|
|
11
|
+
|
|
12
|
+
Copyright (c) 2026 NLRI65000
|
|
13
|
+
|
|
14
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
15
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
16
|
+
in the Software without restriction, including without limitation the rights
|
|
17
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
18
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
19
|
+
furnished to do so, subject to the following conditions:
|
|
20
|
+
|
|
21
|
+
The above copyright notice and this permission notice shall be included in all
|
|
22
|
+
copies or substantial portions of the Software.
|
|
23
|
+
|
|
24
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
25
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
26
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
27
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
28
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
29
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
30
|
+
SOFTWARE.
|
|
31
|
+
License-File: LICENSE
|
|
32
|
+
Keywords: aaa,authentication,daloradius,fastapi,freeradius,network,radius
|
|
33
|
+
Classifier: Development Status :: 4 - Beta
|
|
34
|
+
Classifier: Environment :: Web Environment
|
|
35
|
+
Classifier: Framework :: FastAPI
|
|
36
|
+
Classifier: Intended Audience :: System Administrators
|
|
37
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
38
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
39
|
+
Classifier: Programming Language :: Python :: 3
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
41
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
42
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
43
|
+
Classifier: Topic :: Internet
|
|
44
|
+
Classifier: Topic :: System :: Systems Administration :: Authentication/Directory
|
|
45
|
+
Requires-Python: >=3.11
|
|
46
|
+
Requires-Dist: alembic>=1.13.0
|
|
47
|
+
Requires-Dist: apscheduler<4,>=3.10
|
|
48
|
+
Requires-Dist: argon2-cffi>=23.1.0
|
|
49
|
+
Requires-Dist: asyncpg>=0.29.0
|
|
50
|
+
Requires-Dist: bcrypt>=4.0.0
|
|
51
|
+
Requires-Dist: cryptography>=42.0.0
|
|
52
|
+
Requires-Dist: fastapi>=0.111.0
|
|
53
|
+
Requires-Dist: geoip2>=4.8.0
|
|
54
|
+
Requires-Dist: httpx>=0.27.0
|
|
55
|
+
Requires-Dist: ldap3>=2.9.1
|
|
56
|
+
Requires-Dist: netmiko>=4.0.0
|
|
57
|
+
Requires-Dist: pydantic-settings>=2.3.0
|
|
58
|
+
Requires-Dist: pyjwt>=2.8.0
|
|
59
|
+
Requires-Dist: pyrad>=2.4
|
|
60
|
+
Requires-Dist: python-multipart>=0.0.9
|
|
61
|
+
Requires-Dist: slowapi>=0.1.9
|
|
62
|
+
Requires-Dist: sqlalchemy[asyncio]>=2.0.0
|
|
63
|
+
Requires-Dist: uvicorn[standard]>=0.30.0
|
|
64
|
+
Description-Content-Type: text/markdown
|
|
65
|
+
|
|
66
|
+
<p align="center">
|
|
67
|
+
<img src="assets/MonsterOpsDO.png" alt="MonsterOps — Monitor. Manage. Automate." width="460" />
|
|
68
|
+
</p>
|
|
69
|
+
|
|
70
|
+
# MonsterOps
|
|
71
|
+
|
|
72
|
+
**MonsterOps** is a self-hosted network operations platform for ISPs, enterprise networks, and anyone running a FreeRADIUS environment — RADIUS users & groups, NAS devices, IP pools, sessions & accounting, auth analytics, RADIUS proxy/realms, VPN tunnels, a safe nftables firewall manager, automation, and a REST API, all in one dashboard.
|
|
73
|
+
|
|
74
|
+
Built with **FastAPI + PostgreSQL** and a **vanilla-JS Web Components** frontend — a single Python package, no Node.js, no build step.
|
|
75
|
+
|
|
76
|
+
## Highlights
|
|
77
|
+
|
|
78
|
+
- **RADIUS users & groups** — full `radcheck`/`radreply`/`radusergroup` CRUD, bulk CSV, per-user session & auth history
|
|
79
|
+
- **NAS management** — vendor presets and NAS groups, ICMP reachability monitoring, plus an SSH/Telnet **NAS Manager** (pull, version, diff, and push config; one-click "point a NAS at RADIUS" deploy; encrypted credentials)
|
|
80
|
+
- **Firewall manager** — a dedicated nftables table with staged apply, snapshot + auto-rollback, and adaptive access control (brute-force / country blocking) built to keep you from locking yourself out
|
|
81
|
+
- **Sessions & analytics** — live sessions with CoA disconnect, accounting history, and auth logs with geo-location + anomaly detection
|
|
82
|
+
- **And more** — RADIUS proxy & realms, WireGuard / L2TP-IPsec VPN tunnels, automation & scheduling, webhooks, a scoped REST API, and integrations (Zabbix, Graylog, GeoIP2)
|
|
83
|
+
|
|
84
|
+
See the full capability list in the **[Reference](docs/reference.md)**.
|
|
85
|
+
|
|
86
|
+
## Get Started
|
|
87
|
+
|
|
88
|
+
Requires **Python 3.11+** and a reachable **PostgreSQL 15+** database (the same one FreeRADIUS uses).
|
|
89
|
+
|
|
90
|
+
### Production (recommended)
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
git clone https://github.com/NLRI65000/MonsterOps.git
|
|
94
|
+
cd MonsterOps
|
|
95
|
+
sudo bash deploy/install.sh
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
The installer sets up the service user, database, FreeRADIUS SQL integration, a systemd unit, and optional tooling (VPN backends, nftables, sudoers rules). Re-run `deploy/upgrade.sh` to update an existing install in place.
|
|
99
|
+
|
|
100
|
+
### From PyPI
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
pip install monsterops
|
|
104
|
+
export MONSTEROPS_DATABASE_URL=postgresql+asyncpg://user:pass@localhost/radius
|
|
105
|
+
export MONSTEROPS_SECRET_KEY=$(python -c "import secrets; print(secrets.token_urlsafe(32))")
|
|
106
|
+
monsterops migrate # create/upgrade the database schema
|
|
107
|
+
monsterops serve --host 0.0.0.0 --port 8000
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The migrations ship inside the package, so `monsterops migrate` works without a source checkout. (You can also put the settings in a `.env` file in the working directory instead of exporting them.)
|
|
111
|
+
|
|
112
|
+
### From source (manual)
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
git clone https://github.com/NLRI65000/MonsterOps.git
|
|
116
|
+
cd MonsterOps
|
|
117
|
+
pip install -e .
|
|
118
|
+
cp .env.example .env # set MONSTEROPS_DATABASE_URL and MONSTEROPS_SECRET_KEY
|
|
119
|
+
monsterops migrate # or, from a checkout: alembic upgrade head
|
|
120
|
+
monsterops serve --host 0.0.0.0 --port 8000
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Then open `http://localhost:8000` and complete the first-run wizard to create your superadmin account.
|
|
124
|
+
|
|
125
|
+
> **Before production:** change `MONSTEROPS_SECRET_KEY` from its default (the app warns until you do) and serve over HTTPS. See the [User Guide](docs/user-guide.md).
|
|
126
|
+
|
|
127
|
+
## Documentation
|
|
128
|
+
|
|
129
|
+
- **[User Guide](docs/user-guide.md)** — install, configure, navigate the UI, core features (including firewall safety), and finding logs
|
|
130
|
+
- **[Reference](docs/reference.md)** — full feature list, configuration variables, roles, CLI, architecture, plugins, tech stack, and roadmap
|
|
131
|
+
|
|
132
|
+
## Security
|
|
133
|
+
|
|
134
|
+
Found a security vulnerability? **Please don't open a public issue.** Report it privately by email to **nlrigithub@hotmail.com** — see [SECURITY.md](SECURITY.md).
|
|
135
|
+
|
|
136
|
+
## License
|
|
137
|
+
|
|
138
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="assets/MonsterOpsDO.png" alt="MonsterOps — Monitor. Manage. Automate." width="460" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# MonsterOps
|
|
6
|
+
|
|
7
|
+
**MonsterOps** is a self-hosted network operations platform for ISPs, enterprise networks, and anyone running a FreeRADIUS environment — RADIUS users & groups, NAS devices, IP pools, sessions & accounting, auth analytics, RADIUS proxy/realms, VPN tunnels, a safe nftables firewall manager, automation, and a REST API, all in one dashboard.
|
|
8
|
+
|
|
9
|
+
Built with **FastAPI + PostgreSQL** and a **vanilla-JS Web Components** frontend — a single Python package, no Node.js, no build step.
|
|
10
|
+
|
|
11
|
+
## Highlights
|
|
12
|
+
|
|
13
|
+
- **RADIUS users & groups** — full `radcheck`/`radreply`/`radusergroup` CRUD, bulk CSV, per-user session & auth history
|
|
14
|
+
- **NAS management** — vendor presets and NAS groups, ICMP reachability monitoring, plus an SSH/Telnet **NAS Manager** (pull, version, diff, and push config; one-click "point a NAS at RADIUS" deploy; encrypted credentials)
|
|
15
|
+
- **Firewall manager** — a dedicated nftables table with staged apply, snapshot + auto-rollback, and adaptive access control (brute-force / country blocking) built to keep you from locking yourself out
|
|
16
|
+
- **Sessions & analytics** — live sessions with CoA disconnect, accounting history, and auth logs with geo-location + anomaly detection
|
|
17
|
+
- **And more** — RADIUS proxy & realms, WireGuard / L2TP-IPsec VPN tunnels, automation & scheduling, webhooks, a scoped REST API, and integrations (Zabbix, Graylog, GeoIP2)
|
|
18
|
+
|
|
19
|
+
See the full capability list in the **[Reference](docs/reference.md)**.
|
|
20
|
+
|
|
21
|
+
## Get Started
|
|
22
|
+
|
|
23
|
+
Requires **Python 3.11+** and a reachable **PostgreSQL 15+** database (the same one FreeRADIUS uses).
|
|
24
|
+
|
|
25
|
+
### Production (recommended)
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
git clone https://github.com/NLRI65000/MonsterOps.git
|
|
29
|
+
cd MonsterOps
|
|
30
|
+
sudo bash deploy/install.sh
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The installer sets up the service user, database, FreeRADIUS SQL integration, a systemd unit, and optional tooling (VPN backends, nftables, sudoers rules). Re-run `deploy/upgrade.sh` to update an existing install in place.
|
|
34
|
+
|
|
35
|
+
### From PyPI
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install monsterops
|
|
39
|
+
export MONSTEROPS_DATABASE_URL=postgresql+asyncpg://user:pass@localhost/radius
|
|
40
|
+
export MONSTEROPS_SECRET_KEY=$(python -c "import secrets; print(secrets.token_urlsafe(32))")
|
|
41
|
+
monsterops migrate # create/upgrade the database schema
|
|
42
|
+
monsterops serve --host 0.0.0.0 --port 8000
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
The migrations ship inside the package, so `monsterops migrate` works without a source checkout. (You can also put the settings in a `.env` file in the working directory instead of exporting them.)
|
|
46
|
+
|
|
47
|
+
### From source (manual)
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
git clone https://github.com/NLRI65000/MonsterOps.git
|
|
51
|
+
cd MonsterOps
|
|
52
|
+
pip install -e .
|
|
53
|
+
cp .env.example .env # set MONSTEROPS_DATABASE_URL and MONSTEROPS_SECRET_KEY
|
|
54
|
+
monsterops migrate # or, from a checkout: alembic upgrade head
|
|
55
|
+
monsterops serve --host 0.0.0.0 --port 8000
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Then open `http://localhost:8000` and complete the first-run wizard to create your superadmin account.
|
|
59
|
+
|
|
60
|
+
> **Before production:** change `MONSTEROPS_SECRET_KEY` from its default (the app warns until you do) and serve over HTTPS. See the [User Guide](docs/user-guide.md).
|
|
61
|
+
|
|
62
|
+
## Documentation
|
|
63
|
+
|
|
64
|
+
- **[User Guide](docs/user-guide.md)** — install, configure, navigate the UI, core features (including firewall safety), and finding logs
|
|
65
|
+
- **[Reference](docs/reference.md)** — full feature list, configuration variables, roles, CLI, architecture, plugins, tech stack, and roadmap
|
|
66
|
+
|
|
67
|
+
## Security
|
|
68
|
+
|
|
69
|
+
Found a security vulnerability? **Please don't open a public issue.** Report it privately by email to **nlrigithub@hotmail.com** — see [SECURITY.md](SECURITY.md).
|
|
70
|
+
|
|
71
|
+
## License
|
|
72
|
+
|
|
73
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Reporting a Vulnerability
|
|
4
|
+
|
|
5
|
+
**Please do not report security vulnerabilities through public GitHub issues.**
|
|
6
|
+
|
|
7
|
+
If you believe you have found a security vulnerability in MonsterOps, report it
|
|
8
|
+
privately by email:
|
|
9
|
+
|
|
10
|
+
**nlrigithub@hotmail.com**
|
|
11
|
+
|
|
12
|
+
Please include as much of the following as you can:
|
|
13
|
+
|
|
14
|
+
- A description of the issue and its potential impact
|
|
15
|
+
- Steps to reproduce, or a proof of concept
|
|
16
|
+
- The affected version or commit
|
|
17
|
+
- Any suggested remediation
|
|
18
|
+
|
|
19
|
+
You will receive an acknowledgement, and we will work with you on a fix and
|
|
20
|
+
coordinated disclosure. Please give a reasonable amount of time for the issue
|
|
21
|
+
to be addressed before any public disclosure.
|
|
22
|
+
|
|
23
|
+
## Supported Versions
|
|
24
|
+
|
|
25
|
+
The latest released version receives security updates.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Generic single-database configuration.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
from logging.config import fileConfig
|
|
5
|
+
|
|
6
|
+
from sqlalchemy import pool
|
|
7
|
+
from sqlalchemy.ext.asyncio import async_engine_from_config
|
|
8
|
+
|
|
9
|
+
import monsterops.modules.accounting.models # noqa: F401
|
|
10
|
+
import monsterops.modules.apikeys.models # noqa: F401
|
|
11
|
+
|
|
12
|
+
import monsterops.modules.auth.models # noqa: F401
|
|
13
|
+
import monsterops.modules.auth_logs.models # noqa: F401
|
|
14
|
+
import monsterops.modules.automation.models # noqa: F401
|
|
15
|
+
import monsterops.modules.groups.models # noqa: F401
|
|
16
|
+
import monsterops.modules.integrations.models # noqa: F401
|
|
17
|
+
import monsterops.modules.ip_pools.models # noqa: F401
|
|
18
|
+
import monsterops.modules.nas.models # noqa: F401
|
|
19
|
+
import monsterops.modules.notifications.models # noqa: F401
|
|
20
|
+
import monsterops.modules.scheduler.models # noqa: F401
|
|
21
|
+
import monsterops.modules.users.models # noqa: F401
|
|
22
|
+
import monsterops.modules.webhooks.models # noqa: F401
|
|
23
|
+
from alembic import context
|
|
24
|
+
from monsterops.config import settings
|
|
25
|
+
from monsterops.database import Base
|
|
26
|
+
|
|
27
|
+
config = context.config
|
|
28
|
+
config.set_main_option("sqlalchemy.url", settings.database_url)
|
|
29
|
+
|
|
30
|
+
if config.config_file_name is not None:
|
|
31
|
+
fileConfig(config.config_file_name)
|
|
32
|
+
|
|
33
|
+
target_metadata = Base.metadata
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def run_migrations_offline() -> None:
|
|
37
|
+
url = config.get_main_option("sqlalchemy.url")
|
|
38
|
+
context.configure(
|
|
39
|
+
url=url,
|
|
40
|
+
target_metadata=target_metadata,
|
|
41
|
+
literal_binds=True,
|
|
42
|
+
dialect_opts={"paramstyle": "named"},
|
|
43
|
+
)
|
|
44
|
+
with context.begin_transaction():
|
|
45
|
+
context.run_migrations()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
_SKIP_INDEXES = {"radacct_calss_idx", "radpostauth_class_idx"}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _include_object(obj, name, type_, reflected, compare_to):
|
|
52
|
+
if type_ == "index" and name in _SKIP_INDEXES:
|
|
53
|
+
return False
|
|
54
|
+
return True
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def do_run_migrations(connection):
|
|
58
|
+
context.configure(
|
|
59
|
+
connection=connection,
|
|
60
|
+
target_metadata=target_metadata,
|
|
61
|
+
include_object=_include_object,
|
|
62
|
+
)
|
|
63
|
+
with context.begin_transaction():
|
|
64
|
+
context.run_migrations()
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
async def run_async_migrations() -> None:
|
|
68
|
+
connectable = async_engine_from_config(
|
|
69
|
+
config.get_section(config.config_ini_section, {}),
|
|
70
|
+
prefix="sqlalchemy.",
|
|
71
|
+
poolclass=pool.NullPool,
|
|
72
|
+
)
|
|
73
|
+
async with connectable.connect() as connection:
|
|
74
|
+
await connection.run_sync(do_run_migrations)
|
|
75
|
+
await connectable.dispose()
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def run_migrations_online() -> None:
|
|
79
|
+
asyncio.run(run_async_migrations())
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
if context.is_offline_mode():
|
|
83
|
+
run_migrations_offline()
|
|
84
|
+
else:
|
|
85
|
+
run_migrations_online()
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""${message}
|
|
2
|
+
|
|
3
|
+
Revision ID: ${up_revision}
|
|
4
|
+
Revises: ${down_revision | comma,n}
|
|
5
|
+
Create Date: ${create_date}
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from typing import Sequence, Union
|
|
9
|
+
|
|
10
|
+
from alembic import op
|
|
11
|
+
import sqlalchemy as sa
|
|
12
|
+
${imports if imports else ""}
|
|
13
|
+
|
|
14
|
+
# revision identifiers, used by Alembic.
|
|
15
|
+
revision: str = ${repr(up_revision)}
|
|
16
|
+
down_revision: Union[str, Sequence[str], None] = ${repr(down_revision)}
|
|
17
|
+
branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)}
|
|
18
|
+
depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def upgrade() -> None:
|
|
22
|
+
"""Upgrade schema."""
|
|
23
|
+
${upgrades if upgrades else "pass"}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def downgrade() -> None:
|
|
27
|
+
"""Downgrade schema."""
|
|
28
|
+
${downgrades if downgrades else "pass"}
|