Add Salt baseline states for Proxmox Mail Gateway.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Ruslan Piatrovich
2026-06-04 11:27:44 +03:00
co-authored by Cursor
parent 35d81332fa
commit 85cecf78f6
23 changed files with 729 additions and 1 deletions
+56
View File
@@ -0,0 +1,56 @@
{% set journald_system_max_use = salt['pillar.get']('pmg:journald_system_max_use', '1G') %}
{% set journald_max_file_sec = salt['pillar.get']('pmg:journald_max_file_sec', '1month') %}
pmg-journald-dropin-dir:
file.directory:
- name: /etc/systemd/journald.conf.d
- user: root
- group: root
- mode: '0755'
pmg-journald-retention:
file.managed:
- name: /etc/systemd/journald.conf.d/99-retention.conf
- source: salt://pmg/files/journald-retention.conf.jinja
- template: jinja
- context:
journald_system_max_use: {{ journald_system_max_use }}
journald_max_file_sec: {{ journald_max_file_sec }}
- user: root
- group: root
- mode: '0644'
pmg-restart-journald:
cmd.run:
- name: systemctl restart systemd-journald
- onchanges:
- file: pmg-journald-retention
pmg-auditd-package:
pkg.installed:
- name: auditd
pmg-audit-rules:
file.managed:
- name: /etc/audit/rules.d/99-pmg-baseline.rules
- source: salt://pmg/files/99-pmg-baseline.rules.jinja
- template: jinja
- user: root
- group: root
- mode: '0640'
pmg-reload-audit-rules:
cmd.run:
- name: augenrules --load
- onchanges:
- file: pmg-audit-rules
pmg-auditd-service:
service.running:
- name: auditd
- enable: true
pmg-rsyslog-service:
service.running:
- name: rsyslog
- enable: true
+28
View File
@@ -0,0 +1,28 @@
pmg-updates-packages:
pkg.installed:
- pkgs:
- unattended-upgrades
- apt-listchanges
pmg-apt-auto-upgrades:
file.managed:
- name: /etc/apt/apt.conf.d/20auto-upgrades
- source: salt://pmg/files/20auto-upgrades.jinja
- template: jinja
- user: root
- group: root
- mode: '0644'
pmg-unattended-policy:
file.managed:
- name: /etc/apt/apt.conf.d/50unattended-upgrades
- source: salt://pmg/files/50unattended-upgrades.jinja
- template: jinja
- user: root
- group: root
- mode: '0644'
pmg-unattended-service:
service.running:
- name: unattended-upgrades
- enable: true
+5
View File
@@ -0,0 +1,5 @@
{% set base_packages = salt['pillar.get']('pmg:base_packages', []) %}
pmg-base-packages:
pkg.installed:
- pkgs: {{ base_packages }}
+111
View File
@@ -0,0 +1,111 @@
{% set custom_check_enabled = salt['pillar.get']('pmg:custom_check:enabled', True) %}
{% set custom_check_script_path = salt['pillar.get']('pmg:custom_check:script_path', '/usr/local/bin/pmg-custom-check') %}
{% set custom_check_log_dir = salt['pillar.get']('pmg:custom_check:log_dir', '/var/log/mail_av') %}
{% set custom_check_managed_packages = salt['pillar.get']('pmg:custom_check:managed_packages', ['pwgen']) %}
{% set custom_check_required_services = salt['pillar.get']('pmg:custom_check:required_services', ['kesl', 'klnagent64']) %}
{% set ksc_superuser_enabled = salt['pillar.get']('pmg:custom_check:ksc_superuser:enabled', False) %}
{% set ksc_superuser_name = salt['pillar.get']('pmg:custom_check:ksc_superuser:name', '') %}
{% set ksc_superuser_manage_sudoers = salt['pillar.get']('pmg:custom_check:ksc_superuser:manage_sudoers', True) %}
{% set kesl_installed = salt['pkg.version']('kesl') != '' %}
{% set klnagent64_installed = salt['pkg.version']('klnagent64') != '' %}
{% set custom_check_kaspersky_ready = kesl_installed and klnagent64_installed %}
{% if custom_check_enabled %}
{% if ksc_superuser_enabled and ksc_superuser_name %}
pmg-custom-check-ksc-superuser:
user.present:
- name: {{ ksc_superuser_name }}
- shell: /bin/bash
- createhome: true
{% if ksc_superuser_manage_sudoers %}
pmg-custom-check-ksc-superuser-sudo-package:
pkg.installed:
- name: sudo
pmg-custom-check-ksc-superuser-sudoers:
file.managed:
- name: /etc/sudoers.d/90-kaspersky-superuser
- user: root
- group: root
- mode: '0440'
- contents:
- {{ ksc_superuser_name }} ALL = (ALL) NOPASSWD: ALL
- check_cmd: visudo -cf
- require:
- pkg: pmg-custom-check-ksc-superuser-sudo-package
- user: pmg-custom-check-ksc-superuser
{% endif %}
{% elif ksc_superuser_enabled %}
pmg-custom-check-ksc-superuser-missing-name:
test.fail_without_changes:
- name: "pmg.custom_check.ksc_superuser.enabled=true but pmg.custom_check.ksc_superuser.name is empty."
{% endif %}
pmg-custom-check-managed-packages:
pkg.installed:
- pkgs: {{ custom_check_managed_packages }}
pmg-custom-check-log-dir:
file.directory:
- name: {{ custom_check_log_dir }}
- user: root
- group: root
- mode: '0755'
pmg-custom-check-log-file:
file.touch:
- name: {{ custom_check_log_dir }}/checked
- require:
- file: pmg-custom-check-log-dir
pmg-custom-check-script:
file.managed:
- name: {{ custom_check_script_path }}
- source: salt://pmg/files/pmg-custom-check.jinja
- template: jinja
- user: root
- group: root
- mode: '0755'
- context:
custom_check_log_dir: {{ custom_check_log_dir }}
- require:
- pkg: pmg-custom-check-managed-packages
- file: pmg-custom-check-log-dir
{% if custom_check_kaspersky_ready %}
pmg-custom-check-kaspersky-ready:
test.nop:
- name: "KESL and klnagent64 are installed."
{% else %}
pmg-custom-check-kaspersky-missing-note:
test.show_notification:
- text: "KESL/klnagent64 не найдены. Установите через Kaspersky Administration Center (сервисный superuser/NOPASSWD), затем повторите state.apply pmg.custom_check."
{% endif %}
{% if custom_check_kaspersky_ready %}
{% for service_name in custom_check_required_services %}
pmg-custom-check-service-{{ service_name }}:
service.running:
- name: {{ service_name }}
- enable: true
- require:
- test: pmg-custom-check-kaspersky-ready
{% endfor %}
pmg-custom-check-enable-in-pmg:
cmd.run:
- name: pmgsh set /config/admin --custom_check 1
- unless: "pmgsh get /config/admin | grep -q '\"custom_check\" : 1'"
- require:
- file: pmg-custom-check-script
- pkg: pmg-custom-check-managed-packages
{% for service_name in custom_check_required_services %}
- service: pmg-custom-check-service-{{ service_name }}
{% endfor %}
{% endif %}
{% else %}
pmg-custom-check-disabled-note:
test.show_notification:
- text: "PMG custom_check disabled by pillar (pmg.custom_check.enabled=false)."
{% endif %}
+4
View File
@@ -0,0 +1,4 @@
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Download-Upgradeable-Packages "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::AutocleanInterval "7";
+14
View File
@@ -0,0 +1,14 @@
Unattended-Upgrade::Origins-Pattern {
"origin=Debian,codename=${distro_codename},label=Debian-Security";
"origin=Debian,codename=${distro_codename}-security,label=Debian-Security";
};
Unattended-Upgrade::Package-Blacklist {
};
Unattended-Upgrade::MinimalSteps "true";
Unattended-Upgrade::InstallOnShutdown "false";
Unattended-Upgrade::MailOnlyOnError "true";
Unattended-Upgrade::Remove-Unused-Dependencies "true";
Unattended-Upgrade::Automatic-Reboot "false";
Unattended-Upgrade::SyslogEnable "true";
+10
View File
@@ -0,0 +1,10 @@
# Managed by Salt.
PasswordAuthentication {{ "yes" if ssh_password_authentication else "no" }}
PermitRootLogin prohibit-password
PubkeyAuthentication yes
X11Forwarding no
MaxAuthTries 3
LoginGraceTime 30
{% if ssh_allow_users %}
AllowUsers {{ " ".join(ssh_allow_users) }}
{% endif %}
+14
View File
@@ -0,0 +1,14 @@
## Managed by Salt.
-D
-b 8192
-w /etc/passwd -p wa -k identity
-w /etc/group -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/gshadow -p wa -k identity
-w /etc/sudoers -p wa -k privilege-escalation
-w /etc/sudoers.d/ -p wa -k privilege-escalation
-w /etc/ssh/sshd_config -p wa -k ssh
-w /etc/ssh/sshd_config.d/ -p wa -k ssh
+3
View File
@@ -0,0 +1,3 @@
[Journal]
SystemMaxUse={{ journald_system_max_use }}
MaxFileSec={{ journald_max_file_sec }}
+49
View File
@@ -0,0 +1,49 @@
#!/bin/bash
# Managed by Salt: PMG custom check via Kaspersky KESL.
set -u
LOG_DIR="{{ custom_check_log_dir }}"
KESL_BIN="/opt/kaspersky/kesl/bin/kesl-control"
SCAN_TARGET="${2:-}"
if [ -z "${SCAN_TARGET}" ]; then
echo "v1"
echo "ERROR: empty scan target"
exit 0
fi
mkdir -p "${LOG_DIR}"
POLICY_NAME="$(pwgen 10 -1 -s -0)"
POLICY_FILE="${LOG_DIR}/${POLICY_NAME}.pol"
cat > "${POLICY_FILE}" <<EOF
ActionOnThreat=Inform
ReportCleanObjects=No
ScanFiles=Yes
ScanMailBases=Yes
ScanPlainMail=Yes
UseAnalyzer=Yes
HeuristicLevel=Medium
[ScanScope.item_0000]
Path=${SCAN_TARGET}
EOF
"${KESL_BIN}" --create-task "${POLICY_NAME}" --type ODS --file "${POLICY_FILE}" >/dev/null
VIRUS_NAME="$("${KESL_BIN}" --start-task "${POLICY_NAME}" -W | grep 'DetectName' | awk -F'=' '{print $2}' | head -1)"
"${KESL_BIN}" --delete-task "${POLICY_NAME}"
if [ -z "${VIRUS_NAME}" ]; then
rm -f "${POLICY_FILE}"
echo "Mail ${SCAN_TARGET} was checked successfully" >> "${LOG_DIR}/checked"
echo "v1"
echo "OK"
else
echo "In mail ${SCAN_TARGET} find ${VIRUS_NAME}" >> "${POLICY_FILE}"
echo "Mail ${SCAN_TARGET} was blocked. More info in ${POLICY_FILE}" >> "${LOG_DIR}/checked"
echo "v1"
echo "VIRUS: ${VIRUS_NAME}"
fi
exit 0
+8
View File
@@ -0,0 +1,8 @@
include:
- pmg.common
- pmg.ssh_hardening
- pmg.custom_check
- pmg.security_agents
- pmg.auto_updates
- pmg.audit_logging
- pmg.pmg_baseline
+31
View File
@@ -0,0 +1,31 @@
{% set pmg_services = salt['pillar.get']('pmg:pmg_services', []) %}
{% set manage_hosts_file = salt['pillar.get']('pmg:manage_hosts_file', False) %}
{% set hosts_file_entries = salt['pillar.get']('pmg:hosts_file_entries', []) %}
{% for svc in pmg_services %}
pmg-service-{{ svc }}:
service.running:
- name: {{ svc }}
- enable: true
{% endfor %}
pmg-cluster-status:
cmd.run:
- name: pmgcm status
{% if manage_hosts_file %}
pmg-managed-hosts:
file.blockreplace:
- name: /etc/hosts
- marker_start: "#-- SALT PMG HOSTS START --"
- marker_end: "#-- SALT PMG HOSTS END --"
- append_if_not_found: true
- content: |
{% for host in hosts_file_entries %}
{% if host.get('aliases', []) %}
{{ host['ip'] }} {{ host['hostname'] }} {{ ' '.join(host['aliases']) }}
{% else %}
{{ host['ip'] }} {{ host['hostname'] }}
{% endif %}
{% endfor %}
{% endif %}
+69
View File
@@ -0,0 +1,69 @@
{% set wazuh_enabled = salt['pillar.get']('pmg:wazuh:enabled', True) %}
{% set wazuh_version = salt['pillar.get']('pmg:wazuh:version', '4.14.0-1') %}
{% set wazuh_manager = salt['pillar.get']('pmg:wazuh:manager', '10.80.120.205') %}
{% set wazuh_group = salt['pillar.get']('pmg:wazuh:group', 'test_auditd_unix') %}
{% set wazuh_pkg_name = 'wazuh-agent_' ~ wazuh_version ~ '_amd64.deb' %}
{% set wazuh_pkg_url = 'https://packages.wazuh.com/4.x/apt/pool/main/w/wazuh-agent/' ~ wazuh_pkg_name %}
{% set wazuh_pkg_path = '/var/tmp/' ~ wazuh_pkg_name %}
{% set qualys_enabled = salt['pillar.get']('pmg:qualys:enabled', True) %}
{% set qualys_package_url = salt['pillar.get']('pmg:qualys:package_url', 'https://storage.yandexcloud.net/qualys-agent/QualysCloudAgent.deb') %}
{% set qualys_package_path = salt['pillar.get']('pmg:qualys:package_path', '/opt/QualysCloudAgent.deb') %}
{% set qualys_activation_id = salt['pillar.get']('pmg:qualys:activation_id', '') %}
{% set qualys_customer_id = salt['pillar.get']('pmg:qualys:customer_id', '') %}
{% set qualys_server_uri = salt['pillar.get']('pmg:qualys:server_uri', 'https://qagpublic.qg1.apps.qualys.eu/CloudAgent/') %}
{% if wazuh_enabled %}
pmg-wazuh-download:
cmd.run:
- name: wget -qO {{ wazuh_pkg_path }} {{ wazuh_pkg_url }}
- unless: test -f {{ wazuh_pkg_path }}
pmg-wazuh-install:
cmd.run:
- name: WAZUH_MANAGER='{{ wazuh_manager }}' WAZUH_AGENT_GROUP='{{ wazuh_group }}' WAZUH_AGENT_NAME="$(hostname -f)" dpkg -i {{ wazuh_pkg_path }}
- unless: dpkg-query -W -f='${Status}' wazuh-agent 2>/dev/null | grep -q 'install ok installed'
- require:
- cmd: pmg-wazuh-download
pmg-wazuh-service:
service.running:
- name: wazuh-agent
- enable: true
- require:
- cmd: pmg-wazuh-install
{% endif %}
{% if qualys_enabled and qualys_package_path and qualys_activation_id and qualys_customer_id %}
pmg-qualys-download:
cmd.run:
- name: wget -qO {{ qualys_package_path }} {{ qualys_package_url }}
- unless: test -f {{ qualys_package_path }}
pmg-qualys-install:
cmd.run:
- name: dpkg --install {{ qualys_package_path }}
- onlyif: test -f {{ qualys_package_path }}
- unless: dpkg-query -W -f='${Status}' qualys-cloud-agent 2>/dev/null | grep -q 'install ok installed'
- require:
- cmd: pmg-qualys-download
pmg-qualys-activate:
cmd.run:
- name: /usr/local/qualys/cloud-agent/bin/qualys-cloud-agent.sh ActivationId={{ qualys_activation_id }} CustomerId={{ qualys_customer_id }} ServerUri={{ qualys_server_uri }}
- onchanges:
- cmd: pmg-qualys-install
- onlyif: test -x /usr/local/qualys/cloud-agent/bin/qualys-cloud-agent.sh
pmg-qualys-service:
service.running:
- name: qualys-cloud-agent
- enable: true
- onlyif: test -f {{ qualys_package_path }}
- require:
- cmd: pmg-qualys-install
{% elif qualys_enabled %}
pmg-qualys-skipped:
test.show_notification:
- text: "Qualys agent skipped: set package_url + package_path + activation_id + customer_id in pillar."
{% endif %}
+35
View File
@@ -0,0 +1,35 @@
{% set ssh_allow_users = salt['pillar.get']('pmg:ssh_allow_users', []) %}
{% set ssh_password_authentication = salt['pillar.get']('pmg:ssh_password_authentication', True) %}
pmg-sshd-dropin-dir:
file.directory:
- name: /etc/ssh/sshd_config.d
- user: root
- group: root
- mode: '0755'
pmg-sshd-hardening-config:
file.managed:
- name: /etc/ssh/sshd_config.d/99-hardening.conf
- source: salt://pmg/files/99-hardening.conf.jinja
- template: jinja
- context:
ssh_allow_users: {{ ssh_allow_users }}
ssh_password_authentication: {{ ssh_password_authentication }}
- user: root
- group: root
- mode: '0644'
pmg-validate-sshd-config:
cmd.run:
- name: sshd -t
- onchanges:
- file: pmg-sshd-hardening-config
pmg-sshd-service:
service.running:
- name: ssh
- enable: true
- reload: true
- watch:
- cmd: pmg-validate-sshd-config
+50
View File
@@ -0,0 +1,50 @@
{% set pmg_services = salt['pillar.get']('pmg:pmg_services', []) %}
{% set pmg_update_dist_upgrade = salt['pillar.get']('pmg:update_dist_upgrade', True) %}
{% set pmg_update_auto_reboot = salt['pillar.get']('pmg:update_auto_reboot', False) %}
{% set pmg_update_reboot_delay_minutes = salt['pillar.get']('pmg:update_reboot_delay_minutes', 1) %}
pmg-update-precheck-cluster:
cmd.run:
- name: pmgcm status
{% for svc in pmg_services %}
pmg-update-precheck-service-{{ svc }}:
cmd.run:
- name: systemctl is-active --quiet {{ svc }}
{% endfor %}
pmg-update-packages:
pkg.uptodate:
- refresh: true
- dist_upgrade: {{ pmg_update_dist_upgrade }}
pmg-update-postcheck-cluster:
cmd.run:
- name: pmgcm status
- require:
- pkg: pmg-update-packages
{% for svc in pmg_services %}
pmg-update-postcheck-service-{{ svc }}:
cmd.run:
- name: systemctl is-active --quiet {{ svc }}
- require:
- pkg: pmg-update-packages
{% endfor %}
pmg-update-reboot-required-note:
test.show_notification:
- text: "После обновления требуется reboot: /var/run/reboot-required"
- onlyif: test -f /var/run/reboot-required
{% if pmg_update_auto_reboot %}
pmg-update-schedule-reboot:
cmd.run:
- name: "shutdown -r +{{ pmg_update_reboot_delay_minutes }} \"Salt pmg.update: reboot required\""
- onlyif: test -f /var/run/reboot-required
- require:
- cmd: pmg-update-postcheck-cluster
{% for svc in pmg_services %}
- cmd: pmg-update-postcheck-service-{{ svc }}
{% endfor %}
{% endif %}
+15
View File
@@ -0,0 +1,15 @@
{% set pmg_services = salt['pillar.get']('pmg:pmg_services', []) %}
{% for svc in pmg_services %}
pmg-verify-service-{{ svc }}:
cmd.run:
- name: systemctl is-active --quiet {{ svc }}
{% endfor %}
pmg-verify-cluster:
cmd.run:
- name: pmgcm status
pmg-verify-sshd-config:
cmd.run:
- name: sshd -t