Compare commits
1
Commits
master
..
4cf4def1f6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4cf4def1f6 |
-13
@@ -1,13 +0,0 @@
|
|||||||
# Python / virtualenv
|
|
||||||
.venv/
|
|
||||||
venv/
|
|
||||||
__pycache__/
|
|
||||||
*.pyc
|
|
||||||
|
|
||||||
# Salt runtime artifacts
|
|
||||||
.salt/
|
|
||||||
|
|
||||||
# IDE / OS files
|
|
||||||
.idea/
|
|
||||||
.vscode/
|
|
||||||
.DS_Store
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
extends: default
|
|
||||||
|
|
||||||
ignore: |
|
|
||||||
.git/
|
|
||||||
.venv/
|
|
||||||
venv/
|
|
||||||
|
|
||||||
rules:
|
|
||||||
comments-indentation: disable
|
|
||||||
document-start:
|
|
||||||
present: false
|
|
||||||
line-length:
|
|
||||||
max: 120
|
|
||||||
level: warning
|
|
||||||
truthy:
|
|
||||||
check-keys: false
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
SHELL := /usr/bin/env bash
|
|
||||||
.RECIPEPREFIX := >
|
|
||||||
|
|
||||||
SALT_CALL ?= salt-call
|
|
||||||
SALT_LINT ?= salt-lint
|
|
||||||
YAMLLINT ?= yamllint
|
|
||||||
STATE_ROOT ?= .
|
|
||||||
PILLAR_ROOT ?= ./pillar
|
|
||||||
MINION_ID ?= p-mailgw-x2-01.lmru.tech
|
|
||||||
MASTER_IP ?= 10.80.38.152
|
|
||||||
MASTER_HOST ?= p-mailgw-x1-01.lmru.tech
|
|
||||||
|
|
||||||
.PHONY: lint check apply verify update-check update cluster-bootstrap
|
|
||||||
|
|
||||||
lint:
|
|
||||||
>@if command -v $(SALT_LINT) >/dev/null 2>&1; then \
|
|
||||||
> $(SALT_LINT) pmg/*.sls pillar/*.sls top.sls; \
|
|
||||||
>else \
|
|
||||||
> echo "salt-lint не найден, пропускаю"; \
|
|
||||||
>fi
|
|
||||||
>@if command -v $(YAMLLINT) >/dev/null 2>&1; then \
|
|
||||||
> $(YAMLLINT) .; \
|
|
||||||
>else \
|
|
||||||
> echo "yamllint не найден, пропускаю"; \
|
|
||||||
>fi
|
|
||||||
|
|
||||||
check:
|
|
||||||
>sudo $(SALT_CALL) --local --id $(MINION_ID) --file-root=$(STATE_ROOT) --pillar-root=$(PILLAR_ROOT) state.apply pmg.init test=True
|
|
||||||
|
|
||||||
apply:
|
|
||||||
>sudo $(SALT_CALL) --local --id $(MINION_ID) --file-root=$(STATE_ROOT) --pillar-root=$(PILLAR_ROOT) state.apply pmg.init
|
|
||||||
|
|
||||||
verify:
|
|
||||||
>sudo $(SALT_CALL) --local --id $(MINION_ID) --file-root=$(STATE_ROOT) --pillar-root=$(PILLAR_ROOT) state.apply pmg.verify
|
|
||||||
|
|
||||||
update-check:
|
|
||||||
>sudo $(SALT_CALL) --local --id $(MINION_ID) --file-root=$(STATE_ROOT) --pillar-root=$(PILLAR_ROOT) state.apply pmg.update test=True
|
|
||||||
|
|
||||||
update:
|
|
||||||
>sudo $(SALT_CALL) --local --id $(MINION_ID) --file-root=$(STATE_ROOT) --pillar-root=$(PILLAR_ROOT) state.apply pmg.update
|
|
||||||
|
|
||||||
cluster-bootstrap:
|
|
||||||
>bash "./scripts/cluster-bootstrap.sh" "$(MINION_ID)" "$(MASTER_HOST)" "$(MASTER_IP)"
|
|
||||||
@@ -1,143 +1,2 @@
|
|||||||
# Salt baseline для PMG
|
# mailgw-salt
|
||||||
|
|
||||||
Репозиторий содержит автономный набор Salt states для базовой эксплуатации и hardening Proxmox Mail Gateway.
|
|
||||||
|
|
||||||
## Что внутри
|
|
||||||
|
|
||||||
- `top.sls` — привязка состояний к minion ID.
|
|
||||||
- `pillar/pmg.sls` — переменные и параметры PMG.
|
|
||||||
- `pmg/*.sls` — состояния:
|
|
||||||
- `common` (базовые пакеты),
|
|
||||||
- `node_exporter` (установка и включение Prometheus node exporter),
|
|
||||||
- `smtp_monitoring` (SMTP-метрики: blackbox probe для 25/26 и postfix queue/connection gauges),
|
|
||||||
- `ssh_hardening`,
|
|
||||||
- `custom_check` (кастомная AV-проверка PMG через KESL),
|
|
||||||
- `security_agents` (Wazuh/Qualys),
|
|
||||||
- `update` (пакетные обновления + pre/post проверки PMG),
|
|
||||||
- `auto_updates` (security-only, без auto reboot),
|
|
||||||
- `audit_logging`,
|
|
||||||
- `pmg_baseline` (проверка/поддержание сервисов PMG),
|
|
||||||
- `verify` (проверки состояния).
|
|
||||||
- `pmg/files/*` — шаблоны конфигов.
|
|
||||||
|
|
||||||
## Требования
|
|
||||||
|
|
||||||
- Salt (рекомендуется актуальная LTS-ветка).
|
|
||||||
- Debian/PMG узлы с systemd.
|
|
||||||
- root-доступ на узел.
|
|
||||||
|
|
||||||
## Быстрый запуск
|
|
||||||
|
|
||||||
```bash
|
|
||||||
make lint
|
|
||||||
make check
|
|
||||||
make apply
|
|
||||||
make verify
|
|
||||||
make update-check
|
|
||||||
make update
|
|
||||||
```
|
|
||||||
|
|
||||||
По умолчанию `MINION_ID=p-mailgw-x2-01.lmru.tech`. Можно переопределить:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
make check MINION_ID=p-mailgw-x1-01.lmru.tech
|
|
||||||
```
|
|
||||||
|
|
||||||
## Основные переменные
|
|
||||||
|
|
||||||
Все параметры задаются в `pillar/pmg.sls`:
|
|
||||||
|
|
||||||
- `pmg.base_packages`
|
|
||||||
- `pmg.ssh_allow_users`
|
|
||||||
- `pmg.ssh_password_authentication`
|
|
||||||
- `pmg.journald_system_max_use`
|
|
||||||
- `pmg.journald_max_file_sec`
|
|
||||||
- `pmg.node_exporter.*`
|
|
||||||
- `pmg.smtp_monitoring.*`
|
|
||||||
- `pmg.pmg_services`
|
|
||||||
- `pmg.pmg_cluster_only_services`
|
|
||||||
- `pmg.cluster_join.*`
|
|
||||||
- `pmg.update_dist_upgrade`
|
|
||||||
- `pmg.update_auto_reboot`
|
|
||||||
- `pmg.update_reboot_delay_minutes`
|
|
||||||
- `pmg.custom_check.*`
|
|
||||||
- `pmg.custom_check.log_dir_user|log_dir_group|log_dir_mode|log_file_mode`
|
|
||||||
- `pmg.manage_hosts_file`
|
|
||||||
- `pmg.hosts_file_entries`
|
|
||||||
- `pmg.wazuh.*`
|
|
||||||
- `pmg.kesl.*`
|
|
||||||
- `pmg.klnagent.*`
|
|
||||||
- `pmg.qualys.*`
|
|
||||||
|
|
||||||
`pmg.node_exporter.args` по умолчанию включает textfile collector:
|
|
||||||
`--collector.textfile.directory=/var/lib/prometheus/node-exporter`.
|
|
||||||
|
|
||||||
`pmg.smtp_monitoring` публикует расширенные SMTP метрики в node_exporter:
|
|
||||||
- queue total/deferred + age oldest message;
|
|
||||||
- SMTP listen/established для портов 25/26;
|
|
||||||
- recent window counters (`pmg.smtp_monitoring.log_window_seconds`) по логам postfix:
|
|
||||||
sent, received, deferred, bounced, rejected, tls failures, smtp connections.
|
|
||||||
|
|
||||||
`pmg.cluster_join` делает:
|
|
||||||
- precheck passwordless SSH с новой ноды на `pmg.cluster_join.master_ip`;
|
|
||||||
- non-interactive `pmgcm join` при заданном `pmg.cluster_join.password`.
|
|
||||||
|
|
||||||
Важно: `pmgcm join` использует пароль PMG (`root@pam` на master) для получения ticket
|
|
||||||
(это не SSH-пароль). Без `pmg.cluster_join.password` state делает skip-уведомление.
|
|
||||||
|
|
||||||
Рекомендуется передавать пароль через переменную окружения (без сохранения в `pillar/pmg.sls`):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
export PMG_CLUSTER_JOIN_PASSWORD='***'
|
|
||||||
PILLAR_B64="$(python3 -c 'import json, os, base64; print(base64.b64encode(json.dumps({\"pmg\": {\"cluster_join\": {\"password\": os.environ[\"PMG_CLUSTER_JOIN_PASSWORD\"]}}}).encode()).decode())')"
|
|
||||||
ssh root@p-mailgw-x1-02.lmru.tech "cd /root/mailgw-salt && salt-call --local --id p-mailgw-x1-02.lmru.tech --file-root=. --pillar-root=./pillar state.apply pmg.cluster_join pillar=\"\$(python3 -c \"import base64; print(base64.b64decode(\\\"${PILLAR_B64}\\\").decode())\")\""
|
|
||||||
```
|
|
||||||
|
|
||||||
Для полностью автоматического bootstrap SSH-доверия (без паролей) с управляющей машины:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
make cluster-bootstrap MINION_ID=p-mailgw-x1-02.lmru.tech MASTER_HOST=p-mailgw-x1-01.lmru.tech MASTER_IP=10.80.38.152
|
|
||||||
```
|
|
||||||
|
|
||||||
## Отдельное обновление PMG
|
|
||||||
|
|
||||||
Перед обновлением:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
make update-check MINION_ID=p-mailgw-x1-01.lmru.tech
|
|
||||||
```
|
|
||||||
|
|
||||||
Применение:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
make update MINION_ID=p-mailgw-x1-01.lmru.tech
|
|
||||||
make verify MINION_ID=p-mailgw-x1-01.lmru.tech
|
|
||||||
```
|
|
||||||
|
|
||||||
State `pmg.update` выполняет:
|
|
||||||
- precheck кластера (`pmgcm status`);
|
|
||||||
- precheck критичных PMG сервисов;
|
|
||||||
- пакетное обновление (`pkg.uptodate`, с `dist_upgrade` по `pmg.update_dist_upgrade=true`);
|
|
||||||
- postcheck кластера и сервисов;
|
|
||||||
- уведомление, если требуется reboot (`/var/run/reboot-required`).
|
|
||||||
- опциональный автоперезапуск по `pmg.update_auto_reboot=true` (через `shutdown -r +N`).
|
|
||||||
|
|
||||||
## PMG custom check (Kaspersky)
|
|
||||||
|
|
||||||
Коротко про `pmg.custom_check`:
|
|
||||||
- готовит окружение (`pwgen`, `/var/log/mail_av`, `/usr/local/bin/pmg-custom-check`);
|
|
||||||
- готовит Kaspersky-учетку (`pmg.custom_check.ksc_superuser.*`; сейчас `superuser` + `NOPASSWD`);
|
|
||||||
- настраивает исключения KESL из сканирования через `pmg.custom_check.kesl_excluded_paths`
|
|
||||||
(по умолчанию: `/var/spool/pmg`, `/var/lib/clamav`, `/tmp/.proxdump_*`) и делает
|
|
||||||
`systemctl restart kesl` только при изменении этих настроек;
|
|
||||||
- если `kesl/klnagent64` установлены — включает сервисы и `custom_check` в PMG, если нет — выводит уведомление "ставится через Kaspersky Administration Center"; сервисы включатся вторым прогоном после установки пакетов.
|
|
||||||
|
|
||||||
`pmg.security_agents` дополнительно ставит/настраивает `kesl` и `klnagent64`:
|
|
||||||
- для `kesl`:
|
|
||||||
- скачивает `.deb` из `pmg.kesl.package_url`;
|
|
||||||
- формирует `autoinstall.ini` и запускает `/opt/kaspersky/kesl/bin/kesl-setup.pl --autoinstall=...`;
|
|
||||||
- поднимает сервис `kesl`;
|
|
||||||
- скачивает `.deb` из `pmg.klnagent.package_url`;
|
|
||||||
- формирует файл ответов `KLAUTOANSWERS` (минимум: `KLNAGENT_SERVER`,
|
|
||||||
`KLNAGENT_AUTOINSTALL`, `EULA_ACCEPTED`);
|
|
||||||
- устанавливает/переустанавливает пакет в тихом режиме и поднимает сервис `klnagent64`.
|
|
||||||
|
|||||||
-129
@@ -1,129 +0,0 @@
|
|||||||
pmg:
|
|
||||||
base_packages:
|
|
||||||
- curl
|
|
||||||
- vim-tiny
|
|
||||||
- rsync
|
|
||||||
- ca-certificates
|
|
||||||
- jq
|
|
||||||
|
|
||||||
ssh_allow_users: []
|
|
||||||
ssh_password_authentication: true
|
|
||||||
|
|
||||||
journald_system_max_use: 1G
|
|
||||||
journald_max_file_sec: 1month
|
|
||||||
|
|
||||||
node_exporter:
|
|
||||||
enabled: true
|
|
||||||
package: prometheus-node-exporter
|
|
||||||
service: prometheus-node-exporter
|
|
||||||
textfile_directory: /var/lib/prometheus/node-exporter
|
|
||||||
args: --collector.textfile.directory=/var/lib/prometheus/node-exporter
|
|
||||||
|
|
||||||
smtp_monitoring:
|
|
||||||
enabled: true
|
|
||||||
log_window_seconds: 300
|
|
||||||
ports:
|
|
||||||
- 25
|
|
||||||
- 26
|
|
||||||
blackbox:
|
|
||||||
package: prometheus-blackbox-exporter
|
|
||||||
service: prometheus-blackbox-exporter
|
|
||||||
|
|
||||||
pmg_services:
|
|
||||||
- postfix
|
|
||||||
- pmg-smtp-filter
|
|
||||||
- pmgpolicy
|
|
||||||
- pmgdaemon
|
|
||||||
- pmgmirror
|
|
||||||
- pmgtunnel
|
|
||||||
pmg_cluster_only_services:
|
|
||||||
- pmgmirror
|
|
||||||
- pmgtunnel
|
|
||||||
cluster_join:
|
|
||||||
enabled: true
|
|
||||||
master_ip: 10.80.38.152
|
|
||||||
fingerprint: "4C:63:ED:BB:01:F0:63:5B:92:AC:37:D8:52:D9:0A:CB:5B:78:EE:3A:36:83:86:29:C8:19:D2:EC:CE:AC:88:EC"
|
|
||||||
password: ""
|
|
||||||
update_dist_upgrade: true
|
|
||||||
update_auto_reboot: false
|
|
||||||
update_reboot_delay_minutes: 1
|
|
||||||
|
|
||||||
custom_check:
|
|
||||||
enabled: true
|
|
||||||
script_path: /usr/local/bin/pmg-custom-check
|
|
||||||
log_dir: /var/log/mail_av
|
|
||||||
log_dir_user: pmg-smtp-filter
|
|
||||||
log_dir_group: pmg
|
|
||||||
log_dir_mode: "0770"
|
|
||||||
log_file_mode: "0660"
|
|
||||||
managed_packages:
|
|
||||||
- pwgen
|
|
||||||
ksc_superuser:
|
|
||||||
enabled: true
|
|
||||||
name: superuser
|
|
||||||
manage_sudoers: true
|
|
||||||
required_services:
|
|
||||||
- kesl
|
|
||||||
- klnagent64
|
|
||||||
kesl_excluded_paths:
|
|
||||||
- /var/spool/pmg
|
|
||||||
- /var/lib/clamav
|
|
||||||
- /tmp/.proxdump_*
|
|
||||||
|
|
||||||
manage_hosts_file: false
|
|
||||||
hosts_file_entries:
|
|
||||||
- ip: 10.80.38.152
|
|
||||||
hostname: p-mailgw-x1-01
|
|
||||||
aliases:
|
|
||||||
- p-mailgw-x1-01.lmru.tech
|
|
||||||
- ip: 10.80.38.153
|
|
||||||
hostname: p-mailgw-x1-02
|
|
||||||
aliases:
|
|
||||||
- p-mailgw-x1-02.lmru.tech
|
|
||||||
- ip: 10.220.41.152
|
|
||||||
hostname: p-mailgw-x2-01
|
|
||||||
aliases:
|
|
||||||
- p-mailgw-x2-01.lmru.tech
|
|
||||||
- ip: 10.220.41.153
|
|
||||||
hostname: p-mailgw-x2-02
|
|
||||||
aliases:
|
|
||||||
- p-mailgw-x2-02.lmru.tech
|
|
||||||
|
|
||||||
wazuh:
|
|
||||||
enabled: true
|
|
||||||
version: 4.14.0-1
|
|
||||||
manager: 10.80.120.205
|
|
||||||
group: test_auditd_unix
|
|
||||||
|
|
||||||
kesl:
|
|
||||||
enabled: true
|
|
||||||
package_url: https://products.s.kaspersky-labs.com/endpoints/keslinux10/12.4.0.1225/multilanguage-INT-12.4.0.1225/167a2f9c5bdb4e869f4603fbc3a829c1/kesl_12.4.0-1225_amd64.deb
|
|
||||||
package_path: /opt/kesl_12.4.0-1225_amd64.deb
|
|
||||||
autoinstall_path: /etc/opt/kaspersky/kesl/autoinstall.ini
|
|
||||||
ksvla_mode: "No"
|
|
||||||
endpoint_agent_mode: "No"
|
|
||||||
eula_agreed: "Yes"
|
|
||||||
privacy_policy_agreed: "Yes"
|
|
||||||
use_ksn: "No"
|
|
||||||
group_clean: "No"
|
|
||||||
locale: ""
|
|
||||||
install_license: ""
|
|
||||||
updater_source: SCServer
|
|
||||||
update_execute: "No"
|
|
||||||
|
|
||||||
klnagent:
|
|
||||||
enabled: true
|
|
||||||
package_url: https://products.s.kaspersky-labs.com/administrationkit/ksc10/16.2.0.1023/russian-INT-29664057-ru/2129c97dba254c9fb8a4161f29a2241c/klnagent64_16.2.0-1023_amd64.deb
|
|
||||||
package_path: /opt/klnagent64_16.2.0-1023_amd64.deb
|
|
||||||
administration_server: 10.80.38.76
|
|
||||||
autoanswers_path: /etc/opt/kaspersky/klnagent64/autoanswers.conf
|
|
||||||
autoinstall: true
|
|
||||||
eula_accepted: true
|
|
||||||
|
|
||||||
qualys:
|
|
||||||
enabled: true
|
|
||||||
package_url: https://storage.yandexcloud.net/qualys-agent/QualysCloudAgent.deb
|
|
||||||
package_path: /opt/QualysCloudAgent.deb
|
|
||||||
activation_id: 5eb9ad8e-02cc-431a-9afb-b8caad175ec1
|
|
||||||
customer_id: 4d868109-dad3-5536-82b4-9f3a6f3010bc
|
|
||||||
server_uri: https://qagpublic.qg1.apps.qualys.eu/CloudAgent/
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
base:
|
|
||||||
'*':
|
|
||||||
- pmg
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
{% 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
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
{% set cluster_join_enabled = salt['pillar.get']('pmg:cluster_join:enabled', False) %}
|
|
||||||
{% set cluster_join_master_ip = salt['pillar.get']('pmg:cluster_join:master_ip', '') %}
|
|
||||||
{% set cluster_join_fingerprint = salt['pillar.get']('pmg:cluster_join:fingerprint', '') %}
|
|
||||||
{% set cluster_join_password = salt['pillar.get']('pmg:cluster_join:password', '') %}
|
|
||||||
|
|
||||||
{% if cluster_join_enabled and cluster_join_master_ip and cluster_join_fingerprint %}
|
|
||||||
pmg-cluster-join-passwordless-ssh-check:
|
|
||||||
cmd.run:
|
|
||||||
- name: ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new root@{{ cluster_join_master_ip }} "exit 0"
|
|
||||||
- timeout: 20
|
|
||||||
|
|
||||||
{% if cluster_join_password %}
|
|
||||||
pmg-cluster-join:
|
|
||||||
cmd.run:
|
|
||||||
- name: pmgcm join {{ cluster_join_master_ip }} --fingerprint {{ cluster_join_fingerprint }}
|
|
||||||
- stdin: "{{ cluster_join_password }}"
|
|
||||||
- timeout: 60
|
|
||||||
- require:
|
|
||||||
- cmd: pmg-cluster-join-passwordless-ssh-check
|
|
||||||
- unless: "pmgcm status 2>/dev/null | awk 'BEGIN { ok=1 } /no cluster defined/ { ok=0 } END { exit(ok ? 0 : 1) }'"
|
|
||||||
{% else %}
|
|
||||||
pmg-cluster-join-skipped-password:
|
|
||||||
test.show_notification:
|
|
||||||
- text: "Cluster join skipped: set pmg.cluster_join.password (PMG root@pam password on master) for non-interactive join."
|
|
||||||
{% endif %}
|
|
||||||
{% elif cluster_join_enabled %}
|
|
||||||
pmg-cluster-join-skipped:
|
|
||||||
test.show_notification:
|
|
||||||
- text: "Cluster join skipped: set pmg.cluster_join.master_ip and pmg.cluster_join.fingerprint in pillar."
|
|
||||||
{% endif %}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{% set base_packages = salt['pillar.get']('pmg:base_packages', []) %}
|
|
||||||
|
|
||||||
pmg-base-packages:
|
|
||||||
pkg.installed:
|
|
||||||
- pkgs: {{ base_packages }}
|
|
||||||
@@ -1,151 +0,0 @@
|
|||||||
{% 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_log_dir_user = salt['pillar.get']('pmg:custom_check:log_dir_user', 'pmg-smtp-filter') %}
|
|
||||||
{% set custom_check_log_dir_group = salt['pillar.get']('pmg:custom_check:log_dir_group', 'pmg') %}
|
|
||||||
{% set custom_check_log_dir_mode = salt['pillar.get']('pmg:custom_check:log_dir_mode', '0770') %}
|
|
||||||
{% set custom_check_log_file_mode = salt['pillar.get']('pmg:custom_check:log_file_mode', '0660') %}
|
|
||||||
{% 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 custom_check_kesl_excluded_paths = salt['pillar.get']('pmg:custom_check:kesl_excluded_paths', ['/var/spool/pmg', '/var/lib/clamav', '/tmp/.proxdump_*']) %}
|
|
||||||
{% 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: {{ custom_check_log_dir_user }}
|
|
||||||
- group: {{ custom_check_log_dir_group }}
|
|
||||||
- mode: '{{ custom_check_log_dir_mode }}'
|
|
||||||
- recurse:
|
|
||||||
- user
|
|
||||||
- group
|
|
||||||
|
|
||||||
pmg-custom-check-log-file:
|
|
||||||
file.managed:
|
|
||||||
- name: {{ custom_check_log_dir }}/checked
|
|
||||||
- user: {{ custom_check_log_dir_user }}
|
|
||||||
- group: {{ custom_check_log_dir_group }}
|
|
||||||
- mode: '{{ custom_check_log_file_mode }}'
|
|
||||||
- replace: false
|
|
||||||
- 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 %}
|
|
||||||
|
|
||||||
{% for excluded_path in custom_check_kesl_excluded_paths %}
|
|
||||||
pmg-custom-check-kesl-excluded-scope-{{ loop.index0 }}:
|
|
||||||
cmd.run:
|
|
||||||
- name: >-
|
|
||||||
kesl-control --set-settings File_Threat_Protection
|
|
||||||
ExcludedFromScanScope.item_{{ "%04d" | format(loop.index0) }}.Path='{{ excluded_path }}'
|
|
||||||
ExcludedFromScanScope.item_{{ "%04d" | format(loop.index0) }}.UseScanArea=Yes
|
|
||||||
ExcludedFromScanScope.item_{{ "%04d" | format(loop.index0) }}.AreaMask.item_0000='*'
|
|
||||||
- unless: >-
|
|
||||||
kesl-control --get-settings File_Threat_Protection 2>/dev/null
|
|
||||||
| grep -Fq "Path={{ excluded_path }}"
|
|
||||||
- require:
|
|
||||||
- test: pmg-custom-check-kaspersky-ready
|
|
||||||
{% for service_name in custom_check_required_services %}
|
|
||||||
- service: pmg-custom-check-service-{{ service_name }}
|
|
||||||
{% endfor %}
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
pmg-custom-check-kesl-restart:
|
|
||||||
cmd.wait:
|
|
||||||
- name: systemctl restart kesl
|
|
||||||
- watch:
|
|
||||||
{% for excluded_path in custom_check_kesl_excluded_paths %}
|
|
||||||
- cmd: pmg-custom-check-kesl-excluded-scope-{{ loop.index0 }}
|
|
||||||
{% endfor %}
|
|
||||||
- require:
|
|
||||||
- test: pmg-custom-check-kaspersky-ready
|
|
||||||
|
|
||||||
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 %}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
APT::Periodic::Update-Package-Lists "1";
|
|
||||||
APT::Periodic::Download-Upgradeable-Packages "1";
|
|
||||||
APT::Periodic::Unattended-Upgrade "1";
|
|
||||||
APT::Periodic::AutocleanInterval "7";
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
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";
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
# 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 %}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
## 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
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
modules:
|
|
||||||
{% for port in smtp_ports %}
|
|
||||||
smtp_{{ port }}:
|
|
||||||
prober: tcp
|
|
||||||
timeout: 5s
|
|
||||||
tcp:
|
|
||||||
preferred_ip_protocol: ip4
|
|
||||||
query_response:
|
|
||||||
- expect: "^220[ -]"
|
|
||||||
- send: "EHLO blackbox.local"
|
|
||||||
- expect: "^250[ -]"
|
|
||||||
{% endfor %}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
[Journal]
|
|
||||||
SystemMaxUse={{ journald_system_max_use }}
|
|
||||||
MaxFileSec={{ journald_max_file_sec }}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
#!/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
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=Generate PMG SMTP metrics for node_exporter textfile collector
|
|
||||||
After=network-online.target
|
|
||||||
Wants=network-online.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=oneshot
|
|
||||||
ExecStart=/usr/local/bin/pmg-smtp-metrics.sh
|
|
||||||
@@ -1,219 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
outfile="/var/lib/prometheus/node-exporter/pmg_smtp.prom"
|
|
||||||
tmpfile="$(mktemp)"
|
|
||||||
statefile="/var/lib/prometheus/node-exporter/pmg_smtp.state"
|
|
||||||
statetmp="$(mktemp)"
|
|
||||||
now_epoch="$(date +%s)"
|
|
||||||
window_seconds={{ smtp_log_window_seconds | int }}
|
|
||||||
|
|
||||||
if [ "${window_seconds}" -lt 60 ]; then
|
|
||||||
window_seconds=60
|
|
||||||
fi
|
|
||||||
|
|
||||||
to_int() {
|
|
||||||
local value="${1:-0}"
|
|
||||||
if [[ "${value}" =~ ^[0-9]+$ ]]; then
|
|
||||||
echo "${value}"
|
|
||||||
else
|
|
||||||
echo "0"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
get_established_count() {
|
|
||||||
local port="$1"
|
|
||||||
ss -Htn state established "( sport = :${port} )" 2>/dev/null | awk 'END { print NR + 0 }'
|
|
||||||
}
|
|
||||||
|
|
||||||
get_listen_up() {
|
|
||||||
local port="$1"
|
|
||||||
if ss -Hln "( sport = :${port} )" 2>/dev/null | awk 'END { exit(NR > 0 ? 0 : 1) }'; then
|
|
||||||
echo "1"
|
|
||||||
else
|
|
||||||
echo "0"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
service_up() {
|
|
||||||
local service="$1"
|
|
||||||
if systemctl is-active --quiet "${service}" 2>/dev/null; then
|
|
||||||
echo "1"
|
|
||||||
else
|
|
||||||
echo "0"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
last_cursor=""
|
|
||||||
total_smtp_connections=0
|
|
||||||
total_smtp_received=0
|
|
||||||
total_smtp_sent=0
|
|
||||||
total_smtp_deferred=0
|
|
||||||
total_smtp_bounced=0
|
|
||||||
total_smtp_rejected=0
|
|
||||||
total_smtp_tls_failures=0
|
|
||||||
prev_queue_total=0
|
|
||||||
prev_queue_ts=0
|
|
||||||
|
|
||||||
if [ -f "${statefile}" ]; then
|
|
||||||
while IFS='=' read -r key value; do
|
|
||||||
case "${key}" in
|
|
||||||
last_cursor) last_cursor="${value}" ;;
|
|
||||||
total_smtp_connections) total_smtp_connections="$(to_int "${value}")" ;;
|
|
||||||
total_smtp_received) total_smtp_received="$(to_int "${value}")" ;;
|
|
||||||
total_smtp_sent) total_smtp_sent="$(to_int "${value}")" ;;
|
|
||||||
total_smtp_deferred) total_smtp_deferred="$(to_int "${value}")" ;;
|
|
||||||
total_smtp_bounced) total_smtp_bounced="$(to_int "${value}")" ;;
|
|
||||||
total_smtp_rejected) total_smtp_rejected="$(to_int "${value}")" ;;
|
|
||||||
total_smtp_tls_failures) total_smtp_tls_failures="$(to_int "${value}")" ;;
|
|
||||||
prev_queue_total) prev_queue_total="$(to_int "${value}")" ;;
|
|
||||||
prev_queue_ts) prev_queue_ts="$(to_int "${value}")" ;;
|
|
||||||
esac
|
|
||||||
done < "${statefile}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
queue_total="$(postqueue -j 2>/dev/null | awk 'END { print NR + 0 }')"
|
|
||||||
queue_deferred="$(postqueue -j 2>/dev/null | awk -F'"' '/"queue_name":/ { if ($4 == "deferred") c++ } END { print c + 0 }')"
|
|
||||||
if command -v jq >/dev/null 2>&1; then
|
|
||||||
oldest_queue_epoch="$(postqueue -j 2>/dev/null | jq -sr 'map(.arrival_time // empty) | if length == 0 then 0 else min end' 2>/dev/null || echo "0")"
|
|
||||||
else
|
|
||||||
oldest_queue_epoch="0"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "${oldest_queue_epoch}" -gt 0 ] 2>/dev/null; then
|
|
||||||
queue_oldest_age_seconds="$(( now_epoch - oldest_queue_epoch ))"
|
|
||||||
if [ "${queue_oldest_age_seconds}" -lt 0 ]; then
|
|
||||||
queue_oldest_age_seconds=0
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
queue_oldest_age_seconds=0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "${prev_queue_ts}" -gt 0 ] && [ "${now_epoch}" -gt "${prev_queue_ts}" ]; then
|
|
||||||
queue_delta_seconds="$(( now_epoch - prev_queue_ts ))"
|
|
||||||
queue_drain_per_minute="$(awk -v prev="${prev_queue_total}" -v curr="${queue_total}" -v dt="${queue_delta_seconds}" 'BEGIN { d = prev - curr; if (dt <= 0 || d <= 0) print 0; else printf "%.3f", (d * 60.0) / dt }')"
|
|
||||||
else
|
|
||||||
queue_drain_per_minute="0"
|
|
||||||
fi
|
|
||||||
|
|
||||||
log_slice="$(journalctl --no-pager -o cat --since "-${window_seconds} sec" 2>/dev/null || true)"
|
|
||||||
smtp_connections_recent="$(printf '%s\n' "${log_slice}" | grep -Ec 'postfix/smtpd.*connect from' || true)"
|
|
||||||
smtp_received_recent="$(printf '%s\n' "${log_slice}" | grep -Ec 'postfix/qmgr.*: .*: from=<' || true)"
|
|
||||||
smtp_sent_recent="$(printf '%s\n' "${log_slice}" | grep -Ec 'status=sent' || true)"
|
|
||||||
smtp_deferred_recent="$(printf '%s\n' "${log_slice}" | grep -Ec 'status=deferred' || true)"
|
|
||||||
smtp_bounced_recent="$(printf '%s\n' "${log_slice}" | grep -Ec 'status=bounced' || true)"
|
|
||||||
smtp_rejected_recent="$(printf '%s\n' "${log_slice}" | grep -Ec 'NOQUEUE: reject:| reject:' || true)"
|
|
||||||
smtp_tls_fail_recent="$(printf '%s\n' "${log_slice}" | grep -Eci '(tls|starttls).*(fail|error|warning|lost)' || true)"
|
|
||||||
|
|
||||||
journal_cursor_args=()
|
|
||||||
if [ -n "${last_cursor}" ]; then
|
|
||||||
journal_cursor_args+=(--after-cursor "${last_cursor}")
|
|
||||||
fi
|
|
||||||
journal_delta="$(journalctl --no-pager -o cat "${journal_cursor_args[@]}" 2>/dev/null || true)"
|
|
||||||
delta_smtp_connections="$(printf '%s\n' "${journal_delta}" | grep -Ec 'postfix/smtpd.*connect from' || true)"
|
|
||||||
delta_smtp_received="$(printf '%s\n' "${journal_delta}" | grep -Ec 'postfix/qmgr.*: .*: from=<' || true)"
|
|
||||||
delta_smtp_sent="$(printf '%s\n' "${journal_delta}" | grep -Ec 'status=sent' || true)"
|
|
||||||
delta_smtp_deferred="$(printf '%s\n' "${journal_delta}" | grep -Ec 'status=deferred' || true)"
|
|
||||||
delta_smtp_bounced="$(printf '%s\n' "${journal_delta}" | grep -Ec 'status=bounced' || true)"
|
|
||||||
delta_smtp_rejected="$(printf '%s\n' "${journal_delta}" | grep -Ec 'NOQUEUE: reject:| reject:' || true)"
|
|
||||||
delta_smtp_tls_failures="$(printf '%s\n' "${journal_delta}" | grep -Eci '(tls|starttls).*(fail|error|warning|lost)' || true)"
|
|
||||||
|
|
||||||
total_smtp_connections="$(( total_smtp_connections + delta_smtp_connections ))"
|
|
||||||
total_smtp_received="$(( total_smtp_received + delta_smtp_received ))"
|
|
||||||
total_smtp_sent="$(( total_smtp_sent + delta_smtp_sent ))"
|
|
||||||
total_smtp_deferred="$(( total_smtp_deferred + delta_smtp_deferred ))"
|
|
||||||
total_smtp_bounced="$(( total_smtp_bounced + delta_smtp_bounced ))"
|
|
||||||
total_smtp_rejected="$(( total_smtp_rejected + delta_smtp_rejected ))"
|
|
||||||
total_smtp_tls_failures="$(( total_smtp_tls_failures + delta_smtp_tls_failures ))"
|
|
||||||
|
|
||||||
current_cursor="$(journalctl --no-pager -n 1 -o cat --show-cursor 2>/dev/null | awk -F': ' '/^-- cursor: / { c = $2 } END { print c }')"
|
|
||||||
if [ -z "${current_cursor}" ]; then
|
|
||||||
current_cursor="${last_cursor}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
{
|
|
||||||
echo "# HELP pmg_postfix_queue_messages_total Number of messages in Postfix queue."
|
|
||||||
echo "# TYPE pmg_postfix_queue_messages_total gauge"
|
|
||||||
echo "pmg_postfix_queue_messages_total ${queue_total}"
|
|
||||||
echo "# HELP pmg_postfix_queue_deferred_messages Number of deferred messages in Postfix queue."
|
|
||||||
echo "# TYPE pmg_postfix_queue_deferred_messages gauge"
|
|
||||||
echo "pmg_postfix_queue_deferred_messages ${queue_deferred}"
|
|
||||||
echo "# HELP pmg_postfix_queue_oldest_age_seconds Age of oldest queued message in seconds."
|
|
||||||
echo "# TYPE pmg_postfix_queue_oldest_age_seconds gauge"
|
|
||||||
echo "pmg_postfix_queue_oldest_age_seconds ${queue_oldest_age_seconds}"
|
|
||||||
echo "# HELP pmg_postfix_queue_drain_per_minute Queue drain rate in messages per minute (only positive drain)."
|
|
||||||
echo "# TYPE pmg_postfix_queue_drain_per_minute gauge"
|
|
||||||
echo "pmg_postfix_queue_drain_per_minute ${queue_drain_per_minute}"
|
|
||||||
echo "# HELP pmg_smtp_metrics_window_seconds Time window in seconds used for recent SMTP counters."
|
|
||||||
echo "# TYPE pmg_smtp_metrics_window_seconds gauge"
|
|
||||||
echo "pmg_smtp_metrics_window_seconds ${window_seconds}"
|
|
||||||
echo "# HELP pmg_smtp_connections_recent Number of SMTP connections observed in recent window."
|
|
||||||
echo "# TYPE pmg_smtp_connections_recent gauge"
|
|
||||||
echo "pmg_smtp_connections_recent ${smtp_connections_recent}"
|
|
||||||
echo "# HELP pmg_smtp_received_recent Number of received messages observed in recent window."
|
|
||||||
echo "# TYPE pmg_smtp_received_recent gauge"
|
|
||||||
echo "pmg_smtp_received_recent ${smtp_received_recent}"
|
|
||||||
echo "# HELP pmg_smtp_sent_recent Number of sent messages observed in recent window."
|
|
||||||
echo "# TYPE pmg_smtp_sent_recent gauge"
|
|
||||||
echo "pmg_smtp_sent_recent ${smtp_sent_recent}"
|
|
||||||
echo "# HELP pmg_smtp_deferred_recent Number of deferred deliveries observed in recent window."
|
|
||||||
echo "# TYPE pmg_smtp_deferred_recent gauge"
|
|
||||||
echo "pmg_smtp_deferred_recent ${smtp_deferred_recent}"
|
|
||||||
echo "# HELP pmg_smtp_bounced_recent Number of bounced deliveries observed in recent window."
|
|
||||||
echo "# TYPE pmg_smtp_bounced_recent gauge"
|
|
||||||
echo "pmg_smtp_bounced_recent ${smtp_bounced_recent}"
|
|
||||||
echo "# HELP pmg_smtp_rejected_recent Number of rejected SMTP attempts observed in recent window."
|
|
||||||
echo "# TYPE pmg_smtp_rejected_recent gauge"
|
|
||||||
echo "pmg_smtp_rejected_recent ${smtp_rejected_recent}"
|
|
||||||
echo "# HELP pmg_smtp_tls_failures_recent Number of TLS/STARTTLS failures observed in recent window."
|
|
||||||
echo "# TYPE pmg_smtp_tls_failures_recent gauge"
|
|
||||||
echo "pmg_smtp_tls_failures_recent ${smtp_tls_fail_recent}"
|
|
||||||
echo "# HELP pmg_smtp_connections_total Total SMTP connections seen in logs since metrics script state start."
|
|
||||||
echo "# TYPE pmg_smtp_connections_total counter"
|
|
||||||
echo "pmg_smtp_connections_total ${total_smtp_connections}"
|
|
||||||
echo "# HELP pmg_smtp_messages_total Total SMTP message events by direction/status since metrics script state start."
|
|
||||||
echo "# TYPE pmg_smtp_messages_total counter"
|
|
||||||
echo "pmg_smtp_messages_total{direction=\"received\",status=\"accepted\"} ${total_smtp_received}"
|
|
||||||
echo "pmg_smtp_messages_total{direction=\"sent\",status=\"sent\"} ${total_smtp_sent}"
|
|
||||||
echo "pmg_smtp_messages_total{direction=\"delivery\",status=\"deferred\"} ${total_smtp_deferred}"
|
|
||||||
echo "pmg_smtp_messages_total{direction=\"delivery\",status=\"bounced\"} ${total_smtp_bounced}"
|
|
||||||
echo "pmg_smtp_messages_total{direction=\"inbound\",status=\"rejected\"} ${total_smtp_rejected}"
|
|
||||||
echo "# HELP pmg_smtp_tls_failures_total Total TLS/STARTTLS failures seen in logs since metrics script state start."
|
|
||||||
echo "# TYPE pmg_smtp_tls_failures_total counter"
|
|
||||||
echo "pmg_smtp_tls_failures_total ${total_smtp_tls_failures}"
|
|
||||||
echo "# HELP pmg_smtp_port_listen_up SMTP listen status on port (1 up, 0 down)."
|
|
||||||
echo "# TYPE pmg_smtp_port_listen_up gauge"
|
|
||||||
echo "# HELP pmg_smtp_port_established_connections Established SMTP connections on port."
|
|
||||||
echo "# TYPE pmg_smtp_port_established_connections gauge"
|
|
||||||
echo "# HELP pmg_service_up PMG-related service status (1 up, 0 down)."
|
|
||||||
echo "# TYPE pmg_service_up gauge"
|
|
||||||
{% for port in smtp_ports %}
|
|
||||||
echo "pmg_smtp_port_listen_up{port=\"{{ port }}\"} $(get_listen_up {{ port }})"
|
|
||||||
echo "pmg_smtp_port_established_connections{port=\"{{ port }}\"} $(get_established_count {{ port }})"
|
|
||||||
{% endfor %}
|
|
||||||
echo "pmg_service_up{service=\"postfix\"} $(service_up postfix)"
|
|
||||||
echo "pmg_service_up{service=\"pmg-smtp-filter\"} $(service_up pmg-smtp-filter)"
|
|
||||||
echo "pmg_service_up{service=\"pmgpolicy\"} $(service_up pmgpolicy)"
|
|
||||||
echo "pmg_service_up{service=\"pmgdaemon\"} $(service_up pmgdaemon)"
|
|
||||||
echo "pmg_service_up{service=\"pmgmirror\"} $(service_up pmgmirror)"
|
|
||||||
echo "pmg_service_up{service=\"pmgtunnel\"} $(service_up pmgtunnel)"
|
|
||||||
} > "${tmpfile}"
|
|
||||||
|
|
||||||
mv "${tmpfile}" "${outfile}"
|
|
||||||
chmod 0644 "${outfile}"
|
|
||||||
|
|
||||||
{
|
|
||||||
echo "last_cursor=${current_cursor}"
|
|
||||||
echo "total_smtp_connections=${total_smtp_connections}"
|
|
||||||
echo "total_smtp_received=${total_smtp_received}"
|
|
||||||
echo "total_smtp_sent=${total_smtp_sent}"
|
|
||||||
echo "total_smtp_deferred=${total_smtp_deferred}"
|
|
||||||
echo "total_smtp_bounced=${total_smtp_bounced}"
|
|
||||||
echo "total_smtp_rejected=${total_smtp_rejected}"
|
|
||||||
echo "total_smtp_tls_failures=${total_smtp_tls_failures}"
|
|
||||||
echo "prev_queue_total=${queue_total}"
|
|
||||||
echo "prev_queue_ts=${now_epoch}"
|
|
||||||
} > "${statetmp}"
|
|
||||||
|
|
||||||
mv "${statetmp}" "${statefile}"
|
|
||||||
chmod 0644 "${statefile}"
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=Run PMG SMTP metrics exporter script every minute
|
|
||||||
|
|
||||||
[Timer]
|
|
||||||
OnBootSec=30s
|
|
||||||
OnUnitActiveSec=1min
|
|
||||||
AccuracySec=15s
|
|
||||||
Unit=pmg-smtp-metrics.service
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=timers.target
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
include:
|
|
||||||
- pmg.common
|
|
||||||
- pmg.node_exporter
|
|
||||||
- pmg.smtp_monitoring
|
|
||||||
- pmg.ssh_hardening
|
|
||||||
- pmg.custom_check
|
|
||||||
- pmg.security_agents
|
|
||||||
- pmg.cluster_join
|
|
||||||
- pmg.auto_updates
|
|
||||||
- pmg.audit_logging
|
|
||||||
- pmg.pmg_baseline
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{% set node_exporter_enabled = salt['pillar.get']('pmg:node_exporter:enabled', True) %}
|
|
||||||
{% set node_exporter_package = salt['pillar.get']('pmg:node_exporter:package', 'prometheus-node-exporter') %}
|
|
||||||
{% set node_exporter_service = salt['pillar.get']('pmg:node_exporter:service', 'prometheus-node-exporter') %}
|
|
||||||
{% set node_exporter_textfile_dir = salt['pillar.get']('pmg:node_exporter:textfile_directory', '/var/lib/prometheus/node-exporter') %}
|
|
||||||
{% set node_exporter_args = salt['pillar.get']('pmg:node_exporter:args', '--collector.textfile.directory=' ~ node_exporter_textfile_dir) %}
|
|
||||||
|
|
||||||
{% if node_exporter_enabled %}
|
|
||||||
pmg-node-exporter-package:
|
|
||||||
pkg.installed:
|
|
||||||
- name: {{ node_exporter_package }}
|
|
||||||
|
|
||||||
pmg-node-exporter-textfile-dir:
|
|
||||||
file.directory:
|
|
||||||
- name: {{ node_exporter_textfile_dir }}
|
|
||||||
- user: root
|
|
||||||
- group: root
|
|
||||||
- mode: "0755"
|
|
||||||
|
|
||||||
pmg-node-exporter-defaults:
|
|
||||||
file.managed:
|
|
||||||
- name: /etc/default/prometheus-node-exporter
|
|
||||||
- user: root
|
|
||||||
- group: root
|
|
||||||
- mode: "0644"
|
|
||||||
- contents:
|
|
||||||
- "# Managed by Salt."
|
|
||||||
- "ARGS=\"{{ node_exporter_args }}\""
|
|
||||||
|
|
||||||
pmg-node-exporter-service:
|
|
||||||
service.running:
|
|
||||||
- name: {{ node_exporter_service }}
|
|
||||||
- enable: true
|
|
||||||
- require:
|
|
||||||
- pkg: pmg-node-exporter-package
|
|
||||||
- file: pmg-node-exporter-textfile-dir
|
|
||||||
- file: pmg-node-exporter-defaults
|
|
||||||
- watch:
|
|
||||||
- file: pmg-node-exporter-defaults
|
|
||||||
{% endif %}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
{% set pmg_services = salt['pillar.get']('pmg:pmg_services', []) %}
|
|
||||||
{% set pmg_cluster_only_services = salt['pillar.get']('pmg:pmg_cluster_only_services', ['pmgmirror', 'pmgtunnel']) %}
|
|
||||||
{% 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
|
|
||||||
{% if svc in pmg_cluster_only_services %}
|
|
||||||
- onlyif: "pmgcm status 2>/dev/null | awk 'BEGIN { ok=1 } /no cluster defined/ { ok=0 } END { exit(ok ? 0 : 1) }'"
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
pmg-cluster-status:
|
|
||||||
cmd.run:
|
|
||||||
- name: pmgcm status
|
|
||||||
|
|
||||||
pmg-postfix-identity-from-system-hostname:
|
|
||||||
cmd.run:
|
|
||||||
- name: >-
|
|
||||||
HN="$(hostname -f)" &&
|
|
||||||
DM="${HN#*.}" &&
|
|
||||||
postconf -e "myhostname=${HN}" "mydomain=${DM}" &&
|
|
||||||
systemctl reload postfix
|
|
||||||
- unless: >-
|
|
||||||
HN="$(hostname -f)" &&
|
|
||||||
DM="${HN#*.}" &&
|
|
||||||
[ "$(postconf -h myhostname)" = "${HN}" ] &&
|
|
||||||
[ "$(postconf -h mydomain)" = "${DM}" ]
|
|
||||||
- require:
|
|
||||||
- service: pmg-service-postfix
|
|
||||||
|
|
||||||
{% 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 %}
|
|
||||||
@@ -1,208 +0,0 @@
|
|||||||
{% 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 kesl_enabled = salt['pillar.get']('pmg:kesl:enabled', True) %}
|
|
||||||
{% set kesl_package_url = salt['pillar.get']('pmg:kesl:package_url', 'https://products.s.kaspersky-labs.com/endpoints/keslinux10/12.4.0.1225/multilanguage-INT-12.4.0.1225/167a2f9c5bdb4e869f4603fbc3a829c1/kesl_12.4.0-1225_amd64.deb') %}
|
|
||||||
{% set kesl_package_path = salt['pillar.get']('pmg:kesl:package_path', '/opt/kesl_12.4.0-1225_amd64.deb') %}
|
|
||||||
{% set kesl_autoinstall_path = salt['pillar.get']('pmg:kesl:autoinstall_path', '/etc/opt/kaspersky/kesl/autoinstall.ini') %}
|
|
||||||
{% set kesl_eula_agreed = salt['pillar.get']('pmg:kesl:eula_agreed', 'Yes') %}
|
|
||||||
{% set kesl_privacy_policy_agreed = salt['pillar.get']('pmg:kesl:privacy_policy_agreed', 'Yes') %}
|
|
||||||
{% set kesl_use_ksn = salt['pillar.get']('pmg:kesl:use_ksn', 'No') %}
|
|
||||||
{% set kesl_group_clean = salt['pillar.get']('pmg:kesl:group_clean', 'No') %}
|
|
||||||
{% set kesl_locale = salt['pillar.get']('pmg:kesl:locale', '') %}
|
|
||||||
{% set kesl_updater_source = salt['pillar.get']('pmg:kesl:updater_source', 'SCServer') %}
|
|
||||||
{% set kesl_install_license = salt['pillar.get']('pmg:kesl:install_license', '') %}
|
|
||||||
{% set kesl_update_execute = salt['pillar.get']('pmg:kesl:update_execute', 'No') %}
|
|
||||||
{% set kesl_ksvla_mode = salt['pillar.get']('pmg:kesl:ksvla_mode', 'No') %}
|
|
||||||
{% set kesl_endpoint_agent_mode = salt['pillar.get']('pmg:kesl:endpoint_agent_mode', 'No') %}
|
|
||||||
{% set kesl_setup_bin = '/opt/kaspersky/kesl/bin/kesl-setup.pl' %}
|
|
||||||
{% set kesl_setup_marker = '/var/lib/salt/pmg-kesl-autoinstall.done' %}
|
|
||||||
|
|
||||||
{% set klnagent_enabled = salt['pillar.get']('pmg:klnagent:enabled', True) %}
|
|
||||||
{% set klnagent_package_url = salt['pillar.get']('pmg:klnagent:package_url', 'https://products.s.kaspersky-labs.com/administrationkit/ksc10/16.2.0.1023/russian-INT-29664057-ru/2129c97dba254c9fb8a4161f29a2241c/klnagent64_16.2.0-1023_amd64.deb') %}
|
|
||||||
{% set klnagent_package_path = salt['pillar.get']('pmg:klnagent:package_path', '/opt/klnagent64_16.2.0-1023_amd64.deb') %}
|
|
||||||
{% set klnagent_server = salt['pillar.get']('pmg:klnagent:administration_server', '10.80.38.76') %}
|
|
||||||
{% set klnagent_autoanswers_path = salt['pillar.get']('pmg:klnagent:autoanswers_path', '/etc/opt/kaspersky/klnagent64/autoanswers.conf') %}
|
|
||||||
{% set klnagent_autoinstall = salt['pillar.get']('pmg:klnagent:autoinstall', True) %}
|
|
||||||
{% set klnagent_eula_accepted = salt['pillar.get']('pmg:klnagent:eula_accepted', True) %}
|
|
||||||
{% set klnagent_config_marker = '/var/lib/salt/pmg-klnagent-autoinstall.done' %}
|
|
||||||
|
|
||||||
{% 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 kesl_enabled and kesl_package_path %}
|
|
||||||
pmg-kesl-download:
|
|
||||||
cmd.run:
|
|
||||||
- name: wget -qO {{ kesl_package_path }} {{ kesl_package_url }}
|
|
||||||
- unless: test -f {{ kesl_package_path }}
|
|
||||||
|
|
||||||
pmg-kesl-autoinstall-config:
|
|
||||||
file.managed:
|
|
||||||
- name: {{ kesl_autoinstall_path }}
|
|
||||||
- user: root
|
|
||||||
- group: root
|
|
||||||
- mode: '0600'
|
|
||||||
- makedirs: true
|
|
||||||
- contents:
|
|
||||||
- "KSVLA_MODE={{ kesl_ksvla_mode }}"
|
|
||||||
- "ENDPOINT_AGENT_MODE={{ kesl_endpoint_agent_mode }}"
|
|
||||||
- "EULA_AGREED={{ kesl_eula_agreed }}"
|
|
||||||
- "PRIVACY_POLICY_AGREED={{ kesl_privacy_policy_agreed }}"
|
|
||||||
- "USE_KSN={{ kesl_use_ksn }}"
|
|
||||||
- "GROUP_CLEAN={{ kesl_group_clean }}"
|
|
||||||
{% if kesl_locale %}
|
|
||||||
- "LOCALE={{ kesl_locale }}"
|
|
||||||
{% endif %}
|
|
||||||
{% if kesl_install_license %}
|
|
||||||
- "INSTALL_LICENSE={{ kesl_install_license }}"
|
|
||||||
{% endif %}
|
|
||||||
- "UPDATER_SOURCE={{ kesl_updater_source }}"
|
|
||||||
- "UPDATE_EXECUTE={{ kesl_update_execute }}"
|
|
||||||
- require:
|
|
||||||
- cmd: pmg-kesl-install
|
|
||||||
|
|
||||||
pmg-kesl-install:
|
|
||||||
cmd.run:
|
|
||||||
- name: apt-get install -y {{ kesl_package_path }}
|
|
||||||
- onlyif: test -f {{ kesl_package_path }}
|
|
||||||
- unless: dpkg-query -W -f='${Status}' kesl 2>/dev/null | grep -q 'install ok installed'
|
|
||||||
- require:
|
|
||||||
- cmd: pmg-kesl-download
|
|
||||||
|
|
||||||
pmg-kesl-setup:
|
|
||||||
cmd.run:
|
|
||||||
- name: mkdir -p /var/lib/salt && {{ kesl_setup_bin }} --autoinstall={{ kesl_autoinstall_path }} && touch {{ kesl_setup_marker }}
|
|
||||||
- onlyif: test -x {{ kesl_setup_bin }}
|
|
||||||
- unless: test -f {{ kesl_setup_marker }}
|
|
||||||
- require:
|
|
||||||
- cmd: pmg-kesl-install
|
|
||||||
- file: pmg-kesl-autoinstall-config
|
|
||||||
|
|
||||||
pmg-kesl-service:
|
|
||||||
service.running:
|
|
||||||
- name: kesl
|
|
||||||
- enable: true
|
|
||||||
- require:
|
|
||||||
- cmd: pmg-kesl-install
|
|
||||||
- cmd: pmg-kesl-setup
|
|
||||||
{% elif kesl_enabled %}
|
|
||||||
pmg-kesl-skipped:
|
|
||||||
test.show_notification:
|
|
||||||
- text: "Kaspersky Endpoint Security skipped: set package_url + package_path in pillar."
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if klnagent_enabled and klnagent_package_path and klnagent_server %}
|
|
||||||
pmg-klnagent-download:
|
|
||||||
cmd.run:
|
|
||||||
- name: wget -qO {{ klnagent_package_path }} {{ klnagent_package_url }}
|
|
||||||
- unless: test -f {{ klnagent_package_path }}
|
|
||||||
|
|
||||||
pmg-klnagent-autoanswers:
|
|
||||||
file.managed:
|
|
||||||
- name: {{ klnagent_autoanswers_path }}
|
|
||||||
- user: root
|
|
||||||
- group: root
|
|
||||||
- mode: '0600'
|
|
||||||
- makedirs: true
|
|
||||||
- contents:
|
|
||||||
- "KLNAGENT_SERVER={{ klnagent_server }}"
|
|
||||||
- "KLNAGENT_AUTOINSTALL={{ '1' if klnagent_autoinstall else '0' }}"
|
|
||||||
- "EULA_ACCEPTED={{ '1' if klnagent_eula_accepted else '0' }}"
|
|
||||||
|
|
||||||
pmg-klnagent-install:
|
|
||||||
cmd.run:
|
|
||||||
- name: DEBIAN_FRONTEND=noninteractive KLAUTOANSWERS={{ klnagent_autoanswers_path }} apt-get install -y {{ klnagent_package_path }}
|
|
||||||
- onlyif: test -f {{ klnagent_package_path }}
|
|
||||||
- unless: dpkg-query -W -f='${Status}' klnagent64 2>/dev/null | grep -q 'install ok installed'
|
|
||||||
- require:
|
|
||||||
- cmd: pmg-klnagent-download
|
|
||||||
- file: pmg-klnagent-autoanswers
|
|
||||||
|
|
||||||
pmg-klnagent-autoinstall-configure:
|
|
||||||
cmd.run:
|
|
||||||
- name: >-
|
|
||||||
mkdir -p /var/lib/salt &&
|
|
||||||
DEBIAN_FRONTEND=noninteractive KLAUTOANSWERS={{ klnagent_autoanswers_path }} apt-get install -y --reinstall {{ klnagent_package_path }} &&
|
|
||||||
touch {{ klnagent_config_marker }}
|
|
||||||
- onlyif: dpkg-query -W -f='${Status}' klnagent64 2>/dev/null | grep -q 'install ok installed'
|
|
||||||
- unless: test -f {{ klnagent_config_marker }}
|
|
||||||
- require:
|
|
||||||
- cmd: pmg-klnagent-install
|
|
||||||
- file: pmg-klnagent-autoanswers
|
|
||||||
|
|
||||||
pmg-klnagent-service:
|
|
||||||
service.running:
|
|
||||||
- name: klnagent64
|
|
||||||
- enable: true
|
|
||||||
- require:
|
|
||||||
- cmd: pmg-klnagent-install
|
|
||||||
- cmd: pmg-klnagent-autoinstall-configure
|
|
||||||
{% elif klnagent_enabled %}
|
|
||||||
pmg-klnagent-skipped:
|
|
||||||
test.show_notification:
|
|
||||||
- text: "Kaspersky Administration Agent skipped: set package_url + package_path + administration_server in pillar."
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% 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 %}
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
{% set smtp_monitoring_enabled = salt['pillar.get']('pmg:smtp_monitoring:enabled', True) %}
|
|
||||||
{% set blackbox_package = salt['pillar.get']('pmg:smtp_monitoring:blackbox:package', 'prometheus-blackbox-exporter') %}
|
|
||||||
{% set blackbox_service = salt['pillar.get']('pmg:smtp_monitoring:blackbox:service', 'prometheus-blackbox-exporter') %}
|
|
||||||
{% set smtp_ports = salt['pillar.get']('pmg:smtp_monitoring:ports', [25, 26]) %}
|
|
||||||
{% set smtp_log_window_seconds = salt['pillar.get']('pmg:smtp_monitoring:log_window_seconds', 300) %}
|
|
||||||
|
|
||||||
{% if smtp_monitoring_enabled %}
|
|
||||||
pmg-smtp-monitoring-packages:
|
|
||||||
pkg.installed:
|
|
||||||
- pkgs:
|
|
||||||
- {{ blackbox_package }}
|
|
||||||
- iproute2
|
|
||||||
- jq
|
|
||||||
|
|
||||||
pmg-smtp-monitoring-metrics-dir:
|
|
||||||
file.directory:
|
|
||||||
- name: /var/lib/prometheus/node-exporter
|
|
||||||
- user: root
|
|
||||||
- group: root
|
|
||||||
- mode: "0755"
|
|
||||||
|
|
||||||
pmg-smtp-monitoring-script:
|
|
||||||
file.managed:
|
|
||||||
- name: /usr/local/bin/pmg-smtp-metrics.sh
|
|
||||||
- source: salt://pmg/files/pmg-smtp-metrics.sh.jinja
|
|
||||||
- template: jinja
|
|
||||||
- context:
|
|
||||||
smtp_ports: {{ smtp_ports }}
|
|
||||||
smtp_log_window_seconds: {{ smtp_log_window_seconds }}
|
|
||||||
- user: root
|
|
||||||
- group: root
|
|
||||||
- mode: "0755"
|
|
||||||
- require:
|
|
||||||
- file: pmg-smtp-monitoring-metrics-dir
|
|
||||||
|
|
||||||
pmg-smtp-monitoring-service:
|
|
||||||
file.managed:
|
|
||||||
- name: /etc/systemd/system/pmg-smtp-metrics.service
|
|
||||||
- source: salt://pmg/files/pmg-smtp-metrics.service.jinja
|
|
||||||
- user: root
|
|
||||||
- group: root
|
|
||||||
- mode: "0644"
|
|
||||||
|
|
||||||
pmg-smtp-monitoring-timer:
|
|
||||||
file.managed:
|
|
||||||
- name: /etc/systemd/system/pmg-smtp-metrics.timer
|
|
||||||
- source: salt://pmg/files/pmg-smtp-metrics.timer.jinja
|
|
||||||
- user: root
|
|
||||||
- group: root
|
|
||||||
- mode: "0644"
|
|
||||||
|
|
||||||
pmg-smtp-monitoring-blackbox-config:
|
|
||||||
file.managed:
|
|
||||||
- name: /etc/prometheus/blackbox.yml
|
|
||||||
- source: salt://pmg/files/blackbox.yml.jinja
|
|
||||||
- template: jinja
|
|
||||||
- context:
|
|
||||||
smtp_ports: {{ smtp_ports }}
|
|
||||||
- user: root
|
|
||||||
- group: root
|
|
||||||
- mode: "0644"
|
|
||||||
- require:
|
|
||||||
- pkg: pmg-smtp-monitoring-packages
|
|
||||||
|
|
||||||
pmg-smtp-monitoring-systemd-reload:
|
|
||||||
cmd.run:
|
|
||||||
- name: systemctl daemon-reload
|
|
||||||
- onchanges:
|
|
||||||
- file: pmg-smtp-monitoring-service
|
|
||||||
- file: pmg-smtp-monitoring-timer
|
|
||||||
|
|
||||||
pmg-smtp-monitoring-blackbox-service:
|
|
||||||
service.running:
|
|
||||||
- name: {{ blackbox_service }}
|
|
||||||
- enable: true
|
|
||||||
- require:
|
|
||||||
- pkg: pmg-smtp-monitoring-packages
|
|
||||||
- watch:
|
|
||||||
- file: pmg-smtp-monitoring-blackbox-config
|
|
||||||
|
|
||||||
pmg-smtp-monitoring-timer-running:
|
|
||||||
service.running:
|
|
||||||
- name: pmg-smtp-metrics.timer
|
|
||||||
- enable: true
|
|
||||||
- require:
|
|
||||||
- cmd: pmg-smtp-monitoring-systemd-reload
|
|
||||||
- file: pmg-smtp-monitoring-script
|
|
||||||
|
|
||||||
pmg-smtp-monitoring-run-once:
|
|
||||||
cmd.run:
|
|
||||||
- name: /usr/local/bin/pmg-smtp-metrics.sh
|
|
||||||
- require:
|
|
||||||
- file: pmg-smtp-monitoring-script
|
|
||||||
{% endif %}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
{% 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
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
{% 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 %}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
{% set pmg_services = salt['pillar.get']('pmg:pmg_services', []) %}
|
|
||||||
{% set pmg_cluster_only_services = salt['pillar.get']('pmg:pmg_cluster_only_services', ['pmgmirror', 'pmgtunnel']) %}
|
|
||||||
|
|
||||||
{% for svc in pmg_services %}
|
|
||||||
pmg-verify-service-{{ svc }}:
|
|
||||||
cmd.run:
|
|
||||||
- name: systemctl is-active --quiet {{ svc }}
|
|
||||||
{% if svc in pmg_cluster_only_services %}
|
|
||||||
- onlyif: "pmgcm status 2>/dev/null | awk 'BEGIN { ok=1 } /no cluster defined/ { ok=0 } END { exit(ok ? 0 : 1) }'"
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
pmg-verify-cluster:
|
|
||||||
cmd.run:
|
|
||||||
- name: pmgcm status
|
|
||||||
|
|
||||||
pmg-verify-sshd-config:
|
|
||||||
cmd.run:
|
|
||||||
- name: sshd -t
|
|
||||||
|
|
||||||
pmg-verify-blackbox-service:
|
|
||||||
cmd.run:
|
|
||||||
- name: systemctl is-active --quiet prometheus-blackbox-exporter
|
|
||||||
|
|
||||||
pmg-verify-smtp-metrics-timer:
|
|
||||||
cmd.run:
|
|
||||||
- name: systemctl is-active --quiet pmg-smtp-metrics.timer
|
|
||||||
|
|
||||||
pmg-verify-smtp-metrics-exposed:
|
|
||||||
cmd.run:
|
|
||||||
- name: "curl -fsS http://127.0.0.1:9100/metrics | awk 'BEGIN { ok=0 } /^pmg_smtp_sent_recent / { ok=1 } END { exit(ok ? 0 : 1) }'"
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
if [[ $# -ne 3 ]]; then
|
|
||||||
echo "usage: $0 <target_host> <master_host> <master_ip>" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
target_host="$1"
|
|
||||||
master_host="$2"
|
|
||||||
master_ip="$3"
|
|
||||||
|
|
||||||
ssh "root@${target_host}" "mkdir -p /root/.ssh && chmod 700 /root/.ssh && [ -f /root/.ssh/id_ed25519 ] || ssh-keygen -t ed25519 -N '' -f /root/.ssh/id_ed25519 >/dev/null"
|
|
||||||
|
|
||||||
pubkey_b64="$(ssh "root@${target_host}" "python3 -c 'import base64, pathlib; print(base64.b64encode(pathlib.Path(\"/root/.ssh/id_ed25519.pub\").read_bytes()).decode())'")"
|
|
||||||
|
|
||||||
ssh "root@${master_host}" "python3 -c 'import base64, pathlib; pub = base64.b64decode(\"${pubkey_b64}\").decode().strip(); ssh_dir = pathlib.Path(\"/root/.ssh\"); ssh_dir.mkdir(mode=0o700, parents=True, exist_ok=True); auth = ssh_dir / \"authorized_keys\"; lines = auth.read_text().splitlines() if auth.exists() else []; auth.write_text((\"\\n\".join(lines + [pub]) + \"\\n\") if pub not in lines else ((\"\\n\".join(lines) + \"\\n\") if lines else \"\")); auth.chmod(0o600)'"
|
|
||||||
|
|
||||||
ssh "root@${target_host}" "ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new root@${master_ip} 'exit 0'"
|
|
||||||
Reference in New Issue
Block a user