diff --git a/app/config.py b/app/config.py index d15ae4a9..f504ba82 100644 --- a/app/config.py +++ b/app/config.py @@ -93,11 +93,11 @@ if serv is not None and form.getvalue('config') is not None: print("error: Cannot read import config file") if service == 'keepalived': - stderr = funct.upload_and_restart(serv, cfg, just_save=save, keepalived=1) + stderr = funct.upload_and_restart(serv, cfg, just_save=save, keepalived=1, oldcfg=oldcfg) elif service == 'nginx': - stderr = funct.master_slave_upload_and_restart(serv, cfg, just_save=save, nginx=1) + stderr = funct.master_slave_upload_and_restart(serv, cfg, just_save=save, nginx=1, oldcfg=oldcfg) else: - stderr = funct.master_slave_upload_and_restart(serv, cfg, just_save=save) + stderr = funct.master_slave_upload_and_restart(serv, cfg, just_save=save, oldcfg=oldcfg) funct.diff_config(oldcfg, cfg) diff --git a/app/create_db.py b/app/create_db.py index 61e0e268..5d984187 100644 --- a/app/create_db.py +++ b/app/create_db.py @@ -806,7 +806,7 @@ def update_db_v_5_3_0(**kwargs): def update_ver(): - query = Version.update(version='5.3.0.0') + query = Version.update(version='5.3.1.0') try: query.execute() except: diff --git a/app/db_model.py b/app/db_model.py index 047a7376..e3c662fd 100644 --- a/app/db_model.py +++ b/app/db_model.py @@ -438,9 +438,23 @@ class ActionHistory(BaseModel): primary_key = False +class ConfigVersion(BaseModel): + id = AutoField() + server_id = IntegerField() + user_id = IntegerField() + service = CharField() + local_path = CharField() + remote_path = CharField() + diff = TextField() + message = CharField(null=True) + date = DateTimeField(default=datetime.now) + + class Meta: + table_name = 'config_versions' + def create_tables(): with conn: - conn.create_tables([User, Server, Role, Telegram, Slack, UUID, Token, ApiToken, Groups, UserGroups, + conn.create_tables([User, Server, Role, Telegram, Slack, UUID, Token, ApiToken, Groups, UserGroups, ConfigVersion, Setting, Cred, Backup, Metrics, WafMetrics, Version, Option, SavedServer, Waf, ActionHistory, PortScannerSettings, PortScannerPorts, PortScannerHistory, ProvidersCreds, ServiceSetting, ProvisionedServers, MetricsHttpStatus, SMON, WafRules, Alerts, GeoipCodes, NginxMetrics]) diff --git a/app/funct.py b/app/funct.py index 2713e0ff..4605bda1 100644 --- a/app/funct.py +++ b/app/funct.py @@ -294,6 +294,18 @@ def check_login(**kwargs): return False +def get_user_id(): + import sql + import http.cookies + cookie = http.cookies.SimpleCookie(os.environ.get("HTTP_COOKIE")) + user_uuid = cookie.get('uuid') + + if user_uuid is not None: + user_id = sql.get_user_id_by_uuid(user_uuid.value) + + return user_id + + def is_admin(**kwargs): import sql import http.cookies @@ -425,7 +437,7 @@ def get_config(server_ip, cfg, **kwargs): return -def diff_config(oldcfg, cfg): +def diff_config(oldcfg, cfg, **kwargs): import http.cookies import sql cookie = http.cookies.SimpleCookie(os.environ.get("HTTP_COOKIE")) @@ -443,8 +455,14 @@ def diff_config(oldcfg, cfg): output, stderr = subprocess_execute(cmd) - for line in output: - diff += date + " user: " + login + ", group: " + user_group + " " + line + "\n" + if kwargs.get('return_diff'): + for line in output: + diff += line + "\n" + return diff + else: + for line in output: + diff += date + " user: " + login + ", group: " + user_group + " " + line + "\n" + try: log = open(log_path + "/config_edit-"+get_data('logs')+".log", "a") log.write(diff) @@ -811,7 +829,6 @@ def check_haproxy_version(server_ip): def upload(server_ip, path, file, **kwargs): - error = "" full_path = path + file if kwargs.get('dir') == "fullpath": full_path = path @@ -854,6 +871,7 @@ def upload_and_restart(server_ip, cfg, **kwargs): import sql error = '' container_name = '' + server_id = sql.select_server_id_by_ip(server_ip=server_ip) if kwargs.get("nginx"): service = 'nginx' @@ -892,7 +910,6 @@ def upload_and_restart(server_ip, cfg, **kwargs): else: commands = ["sudo mv -f " + tmp_file + " /etc/keepalived/keepalived.conf && sudo systemctl restart keepalived"] elif service == "nginx": - server_id = sql.select_server_id_by_ip(server_ip=server_ip) is_docker = sql.select_service_setting(server_id, 'nginx', 'dockerized') if is_docker == '1': container_name = sql.get_setting('nginx_container_name') @@ -917,7 +934,6 @@ def upload_and_restart(server_ip, cfg, **kwargs): if sql.return_firewall(server_ip): commands[0] += open_port_firewalld(cfg, server_ip=server_ip, service='nginx') else: - server_id = sql.select_server_id_by_ip(server_ip=server_ip) is_docker = sql.select_service_setting(server_id, 'haproxy', 'dockerized') haproxy_service_name = "haproxy" @@ -958,6 +974,18 @@ def upload_and_restart(server_ip, cfg, **kwargs): service=service) except Exception as e: logging('localhost', str(e), haproxywi=1) + # If master then save version of config in a new way + if not kwargs.get('slave'): + try: + diff = diff_config(kwargs.get('oldcfg'), cfg, return_diff=1) + except Exception as e: + logging('localhost', str(e), haproxywi=1) + + try: + user_id = get_user_id() + sql.insert_config_version(server_id, user_id, service, cfg, config_path, diff) + except Exception as e: + logging('localhost', str(e), haproxywi=1) except Exception as e: logging('localhost', str(e), haproxywi=1) return error @@ -983,9 +1011,9 @@ def master_slave_upload_and_restart(server_ip, cfg, just_save, **kwargs): masters = sql.is_master(server_ip) for master in masters: if master[0] is not None: - error = upload_and_restart(master[0], cfg, just_save=just_save, nginx=kwargs.get('nginx')) + error = upload_and_restart(master[0], cfg, just_save=just_save, nginx=kwargs.get('nginx'), slave=1) - error = upload_and_restart(server_ip, cfg, just_save=just_save, nginx=kwargs.get('nginx')) + error = upload_and_restart(server_ip, cfg, just_save=just_save, nginx=kwargs.get('nginx'), oldcfg=kwargs.get('oldcfg')) return error diff --git a/app/history.py b/app/history.py new file mode 100644 index 00000000..14af51e0 --- /dev/null +++ b/app/history.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 +import funct +import sql +from jinja2 import Environment, FileSystemLoader + +env = Environment(loader=FileSystemLoader('templates/'), autoescape=True) +template = env.get_template('history.html') + +print('Content-type: text/html\n') +funct.check_login() + +try: + user, user_id, role, token, servers, user_services = funct.get_users_params() + services = [] +except: + pass + +form = funct.form +serv = funct.is_ip_or_dns(form.getvalue('serv')) +service = form.getvalue('service') + + +if service == 'nginx': + if funct.check_login(service=2): + title = 'Nginx service history' + if serv: + if funct.check_is_server_in_group(serv): + server_id = sql.select_server_id_by_ip(serv) + history = sql.select_action_history_by_server_id_and_service(server_id, service) +elif service == 'keepalived': + if funct.check_login(service=3): + title = 'Keepalived service history' + if serv: + if funct.check_is_server_in_group(serv): + server_id = sql.select_server_id_by_ip(serv) + history = sql.select_action_history_by_server_id_and_service(server_id, service) +elif service == 'haproxy': + if funct.check_login(service=1): + title = "HAProxy service history" + if serv: + if funct.check_is_server_in_group(serv): + server_id = sql.select_server_id_by_ip(serv) + history = sql.select_action_history_by_server_id_and_service(server_id, service) + +users = sql.select_users() + +template = template.render(h2=1, + autorefresh=0, + title=title, + role=role, + user=user, + users=users, + serv=serv, + service=service, + history=history, + user_services=user_services, + token=token) +print(template) \ No newline at end of file diff --git a/app/options.py b/app/options.py index 090b6c56..e2882515 100644 --- a/app/options.py +++ b/app/options.py @@ -393,7 +393,8 @@ if form.getvalue('session_delete_id') is not None: if form.getvalue("change_pos") is not None: pos = form.getvalue('change_pos') - sql.update_server_pos(pos, serv) + server_id = form.getvalue('pos_server_id') + sql.update_server_pos(pos, server_id) if form.getvalue('show_ip') is not None and serv is not None: commands = ["sudo ip a |grep inet |egrep -v '::1' |awk '{ print $2 }' |awk -F'/' '{ print $1 }'"] @@ -1397,7 +1398,7 @@ if form.getvalue('haproxy_exp_install'): proxy_serv = '' commands = ["chmod +x " + script + " && ./" + script + " PROXY=" + proxy_serv + - " STAT_PORT=" + stats_port + " STAT_FILE=" + server_state_file + + " STAT_PORT=" + str(stats_port) + " STAT_FILE=" + server_state_file + " SSH_PORT=" + ssh_port + " STAT_PAGE=" + stat_page + " STATS_USER=" + stats_user + " STATS_PASS='" + stats_password + "' HOST=" + serv + " USER=" + ssh_user_name + " PASS='" + ssh_user_password + "' KEY=" + ssh_key_name] @@ -1434,7 +1435,7 @@ if form.getvalue('nginx_exp_install'): proxy_serv = '' commands = ["chmod +x " + script + " && ./" + script + " PROXY=" + proxy_serv + - " STAT_PORT=" + stats_port + " SSH_PORT=" + ssh_port + " STAT_PAGE=" + stats_page + + " STAT_PORT=" + str(stats_port) + " SSH_PORT=" + ssh_port + " STAT_PAGE=" + stats_page + " STATS_USER=" + stats_user + " STATS_PASS='" + stats_password + "' HOST=" + serv + " USER=" + ssh_user_name + " PASS='" + ssh_user_password + "' KEY=" + ssh_key_name] @@ -3817,3 +3818,40 @@ if form.getvalue('serverSettingsSave') is not None: else: funct.logging(server_ip, 'Service has been flagged as a system service', haproxywi=1, login=1, keep_history=1, service=service) + +if act == 'showListOfVersion': + service = form.getvalue('service') + configver = form.getvalue('configver') + for_delver = form.getvalue('for_delver') + style = form.getvalue('style') + if service == 'keepalived': + configs_dir = funct.get_config_var('configs', 'kp_save_configs_dir') + files = funct.get_files(dir=configs_dir, format='conf') + configs = sql.select_config_version(serv, service) + action = 'versions.py?service=keepalived' + elif service == 'nginx': + configs_dir = funct.get_config_var('configs', 'nginx_save_configs_dir') + files = funct.get_files(dir=configs_dir, format='conf') + configs = sql.select_config_version(serv, service) + action = 'versions.py?service=nginx' + else: + service = 'haproxy' + files = funct.get_files() + configs = sql.select_config_version(serv, service) + action = "versions.py" + + from jinja2 import Environment, FileSystemLoader + + env = Environment(loader=FileSystemLoader('templates/'), autoescape=True, + extensions=["jinja2.ext.loopcontrols", "jinja2.ext.do"]) + template = env.get_template('ajax/show_list_version.html') + + template = template.render(serv=serv, + service=service, + action=action, + return_files=files, + configver=configver, + for_delver=for_delver, + configs=configs, + style=style) + print(template) \ No newline at end of file diff --git a/app/scripts/ansible/roles/haproxy/tasks/configure.yml b/app/scripts/ansible/roles/haproxy/tasks/configure.yml index 0e70b14c..f9834470 100644 --- a/app/scripts/ansible/roles/haproxy/tasks/configure.yml +++ b/app/scripts/ansible/roles/haproxy/tasks/configure.yml @@ -33,18 +33,6 @@ - sestatus.stdout is defined - '"Enforcing" in sestatus.stdout' -- name: Get HAProxy version. - command: haproxy -v - register: haproxy_version_result - changed_when: false - check_mode: false - - -- name: Set HAProxy version. - set_fact: - haproxy_version: "{{ '1.5' if '1.5.' in haproxy_version_result.stdout else '1.6' }}" - - - name: Open stat port for firewalld firewalld: port: "{{ item }}/tcp" @@ -70,16 +58,36 @@ ignore_errors: yes with_items: [ "{{ STAT_PORT }}", "{{ SOCK_PORT }}" ] +- name: Create the haproxy group + group: + name: haproxy + state: present + system: true + +- name: Create the haproxy user + user: + name: haproxy + groups: haproxy + append: true + shell: /usr/sbin/nologin + system: true + create_home: false + home: / + +- name: Creates HAProxy directory + file: + path: /etc/haproxy + owner: haproxy + group: haproxy + state: directory + ignore_errors: yes - name: Copy HAProxy configuration in place. template: src: haproxy.cfg.j2 dest: /etc/haproxy/haproxy.cfg mode: 0644 - validate: haproxy -f %s -c -q force: no - notify: restart haproxy - - name: Creates HAProxy stats directory file: @@ -88,13 +96,3 @@ group: haproxy state: directory ignore_errors: yes - - -- name: Enable and start service HAProxy - systemd: - name: haproxy - daemon_reload: yes - state: started - enabled: yes - force: no - ignore_errors: yes diff --git a/app/scripts/ansible/roles/haproxy/tasks/main.yml b/app/scripts/ansible/roles/haproxy/tasks/main.yml index f3f64cd8..41d541df 100644 --- a/app/scripts/ansible/roles/haproxy/tasks/main.yml +++ b/app/scripts/ansible/roles/haproxy/tasks/main.yml @@ -12,10 +12,10 @@ - include: logs.yml -- include: installation.yml - - include: configure.yml +- include: installation.yml + - name: Add syn_flood tasks include: syn_flood.yml when: (SYN_FLOOD is defined) and (SYN_FLOOD|length > 0) diff --git a/app/scripts/ansible/roles/haproxy/templates/haproxy.cfg.j2 b/app/scripts/ansible/roles/haproxy/templates/haproxy.cfg.j2 index 43b6f366..cc2d9590 100644 --- a/app/scripts/ansible/roles/haproxy/templates/haproxy.cfg.j2 +++ b/app/scripts/ansible/roles/haproxy/templates/haproxy.cfg.j2 @@ -9,9 +9,7 @@ global stats socket /var/lib/haproxy/stats stats socket *:{{SOCK_PORT}} level admin stats socket /var/run/haproxy.sock mode 600 level admin - {% if haproxy_version == '1.6' %} server-state-file {{STAT_FILE}} - {% endif %} defaults mode http diff --git a/app/sql.py b/app/sql.py index 7e41ab0d..3556d425 100644 --- a/app/sql.py +++ b/app/sql.py @@ -1943,6 +1943,7 @@ def update_firewall(serv): def update_server_pos(pos, server_id): query = Server.update(pos=pos).where(Server.server_id == server_id) + print(query) try: query.execute() return True @@ -1960,17 +1961,8 @@ def check_token_exists(token): if get_token(user_id.value) == token: return True else: - # try: - # funct.logging('localhost', ' Tried do action with wrong token', haproxywi=1, login=1) - # except: - # funct.logging('localhost', ' An action with wrong token', haproxywi=1) return False except: - # try: - # funct.logging('localhost', ' Cannot check token', haproxywi=1, login=1) - # except: - # funct.logging('localhost', ' Cannot check token', haproxywi=1) - # finally: return False @@ -1992,7 +1984,6 @@ def insert_smon(server, port, enable, proto, uri, body, group, desc, telegram, u def select_smon(user_group, **kwargs): cursor = conn.cursor() - funct.check_user_group() if user_group == 1: @@ -2862,3 +2853,67 @@ def delete_action_history(server_id: int): return False else: return True + + +def select_action_history_by_server_id(server_id: int): + query = ActionHistory.select().where(ActionHistory.server_id == server_id) + try: + query_res = query.execute() + except Exception as e: + out_error(e) + else: + return query_res + + +def select_action_history_by_server_id_and_service(server_id: int, service: str): + query = ActionHistory.select().where( + (ActionHistory.server_id == server_id) & + (ActionHistory.service == service) + ) + try: + query_res = query.execute() + except Exception as e: + out_error(e) + else: + return query_res + + +def insert_config_version(server_id: int, user_id: int, service: str, local_path: str, remote_path: str, diff: str): + try: + ConfigVersion.insert(server_id=server_id, + user_id=user_id, + service=service, + local_path=local_path, + remote_path=remote_path, + diff=diff, + date=funct.get_data('regular')).execute() + except Exception as e: + out_error(e) + + +def select_config_version(server_ip: str, service: str) -> str: + server_id = select_server_id_by_ip(server_ip) + query = ConfigVersion.select().where( + (ConfigVersion.server_id == server_id) & + (ConfigVersion.service == service) + ) + try: + query_res = query.execute() + except Exception as e: + out_error(e) + else: + return query_res + + +def delete_config_version(service: str, local_path: str): + query_res = ConfigVersion.delete().where( + (ConfigVersion.service == service) & + (ConfigVersion.local_path == local_path) + ) + try: + query_res.execute() + except Exception as e: + out_error(e) + return False + else: + return True diff --git a/app/templates/ajax/show_list_version.html b/app/templates/ajax/show_list_version.html new file mode 100644 index 00000000..04878c7b --- /dev/null +++ b/app/templates/ajax/show_list_version.html @@ -0,0 +1,200 @@ +{% from 'include/input_macros.html' import copy_to_clipboard %} +{% if style == 'new' %} + {% if for_delver == '1' %} + + +
+ {% else %} ++ + + + + Select +
+ ++ + + + + Select +
+ +- - - - - Select -
-- {% if not aftersave and not open %} -
Service | +User | +User IP | +Action | +Date | +
---|---|---|---|---|
{{h.service[0].upper()}}{{h.service[1:]}} | ++ {% for u in users %} + {% if u.user_id == h.user_id %} + {{ u.username }} + {% endif %} + {% endfor %} + | +{{ copy_to_clipboard(id=h.ip, value=h.ip) }} | +{{h.action}} | +{{h.date}} | +