{"id":5460,"date":"2026-10-10T16:55:48","date_gmt":"2026-10-10T14:55:48","guid":{"rendered":"https:\/\/darioiannascoli.it\/blog\/plesk-security-baseline-automation-2026-policy-code-vulnerability-scanning-compliance\/"},"modified":"2026-10-10T16:55:48","modified_gmt":"2026-10-10T14:55:48","slug":"plesk-security-baseline-automation-2026-policy-code-vulnerability-scanning-compliance","status":"publish","type":"post","link":"https:\/\/darioiannascoli.it\/blog\/plesk-security-baseline-automation-2026-policy-code-vulnerability-scanning-compliance\/","title":{"rendered":"Come Implementare Plesk Security Baseline Automation 2026: La Mia Procedura Policy-as-Code Framework, Vulnerability Scanning Integration e Compliance Reporting per MSP Enterprise"},"content":{"rendered":"<p>Negli ultimi mesi, nella mia esperienza come System Administrator, ho affrontato una sfida che tocca ogni MSP con decine di server Plesk in produzione: come mantenere una <strong>security baseline coerente<\/strong> senza trasformare ogni security advisory in un progetto operativo autonomo? Le vulnerabilit\u00e0 critiche come CVE-2026-67397, CVE-2026-68492 e CVE-2026-65646 arrivano con cadenza semamanale, e l&#8217;approccio manuale non scala oltre 10-15 server.<\/p>\n<p>In questo articolo vi mostro la procedura concreta per implementare un <em>Policy-as-Code framework<\/em> dedicato a Plesk, integrando vulnerability scanning automatico e compliance reporting per clienti enterprise. Non \u00e8 teoria: sono configurazioni che uso su 50+ server in ambiente production.<\/p>\n<h2>Il Problema: Perch\u00e9 l&#8217;Automazione Manuale Non Basta<\/h2>\n<p>Quando ricevo una segnalazione di vulnerability critica in Plesk, il workflow tradizionale richiede: identificare i server affetti, distribuire l&#8217;aggiornamento, monitorare la deployment, verificare il risultato e investigare i sistemi falliti. <strong>Tutto questo, anche con script, rimane un lavoro operativo gravoso<\/strong>.<\/p>\n<p>Quello che mi serviva era un sistema capace di:<\/p>\n<ul>\n<li><strong>Codificare le policy di security<\/strong> come file dichiarativi (non documenti statici)<\/li>\n<li><strong>Validare automaticamente<\/strong> che ogni server rispetti la baseline prima del rilascio in produzione<\/li>\n<li><strong>Generare report di compliance<\/strong> per clienti e audit senza intervento manuale<\/li>\n<li><strong>Integrare scanning di vulnerabilit\u00e0<\/strong> in tempo reale nel workflow di deployment<\/li>\n<\/ul>\n<h2>Fondamenti: Policy-as-Code per Plesk<\/h2>\n<p><cite>Policy-as-Code (PaC) \u00e8 la pratica di scrivere governance, security, e compliance rules come file leggibili da macchine che i tool possono valutare e applicare automaticamente.<\/cite> Nel contesto Plesk, significa trasformare la security checklist manuale in un codice versionato, testabile e executable.<\/p>\n<p>Il principio fondamentale \u00e8 semplice: <cite>shift da &#8220;trust and verify&#8221; a &#8220;verify then trust&#8221;<\/cite> \u2013 validare la compliance prima della deployment, non dopo.<\/p>\n<h3>Struttura del Framework Policy-as-Code<\/h3>\n<p>Nel mio setup, organizzo le policy in quattro layer:<\/p>\n<ol>\n<li><strong>Baseline Definitions<\/strong>: File JSON\/YAML che descrivono la configurazione target (versione Plesk, extension versioning, firewall rules)<\/li>\n<li><strong>Compliance Scanner<\/strong>: Tool che esegue audit periodici contro le baseline<\/li>\n<li><strong>Enforcement Engine<\/strong>: Applica automaticamente le policy sui server (con fallback manuale per edge cases)<\/li>\n<li><strong>Audit &amp; Reporting<\/strong>: Genera report per compliance (GDPR, CRA, NIS2) e client<\/li>\n<\/ol>\n<p>Ecco un esempio di baseline definition per uno scenario MSP standard:<\/p>\n<pre style=\"background: #f4f4f4;padding: 12px;border-left: 4px solid #0066cc;margin: 10px 0;font-family: &#039;Courier New&#039;, monospace;font-size: 12px\"><code>{\n  \"name\": \"plesk-msp-standard-baseline-2026\",\n  \"version\": \"1.2.0\",\n  \"enforced_policies\": {\n    \"plesk_version\": {\n      \"minimum\": \"18.0.80.6\",\n      \"excluded_cves\": [\"CVE-2026-67397\", \"CVE-2026-67394\"]\n    },\n    \"extensions\": {\n      \"rest-api\": { \"minimum\": \"2.4.7\" },\n      \"security-advisor\": { \"minimum\": \"latest\" },\n      \"imunify360\": { \"minimum\": \"7.15.0\", \"required\": true }\n    },\n    \"security_controls\": {\n      \"fail2ban\": { \"enabled\": true, \"bantime\": 3600 },\n      \"mod_security\": { \"enabled\": true, \"ruleset\": \"owasp-crs-4.0.0\" },\n      \"ssl_min_version\": \"TLSv1.2\",\n      \"password_policy\": {\n        \"min_length\": 12,\n        \"require_special_chars\": true,\n        \"require_numbers\": true\n      }\n    },\n    \"firewall\": {\n      \"default_action\": \"ACCEPT\",\n      \"blocked_ports\": [],\n      \"rate_limiting\": { \"enabled\": true, \"burst\": 10, \"rate\": \"50\/sec\" }\n    },\n    \"backup\": {\n      \"enabled\": true,\n      \"frequency\": \"daily\",\n      \"retention_days\": 30,\n      \"immutable\": true\n    }\n  },\n  \"exception_rules\": [\n    {\n      \"condition\": \"legacy_php_apps\",\n      \"allows\": \"TLSv1.1\",\n      \"expires\": \"2027-01-01\",\n      \"reason\": \"Backward compatibility customer X\"\n    }\n  ]\n}<\/code><\/pre>\n<p>Questo file diventa il &#8220;source of truth&#8221; per la security. Versionato in Git, valutato in CI\/CD, aplicato ai server via Plesk API e ModSecurity.<\/p>\n<h2>Step 1: Vulnerability Scanning Integration<\/h2>\n<p>Il primo componente che ho implementato \u00e8 il <strong>continuous vulnerability scanning<\/strong>. Non basta installare un aggiornamento a reazione: devo sapere in tempo reale quali CVE sono attivi sui miei server e quali sono stati remediated.<\/p>\n<h3>Setup di Compliance Scanner in Python<\/h3>\n<p>Ho scritto uno script Python che queries le API di Plesk e il database di NVD (National Vulnerability Database):<\/p>\n<pre style=\"background: #f4f4f4;padding: 12px;border-left: 4px solid #0066cc;margin: 10px 0;font-family: &#039;Courier New&#039;, monospace;font-size: 12px\"><code>#!\/usr\/bin\/env python3\nimport requests\nimport json\nfrom datetime import datetime\nimport logging\n\nlogging.basicConfig(level=logging.INFO)\nlogger = logging.getLogger(__name__)\n\nclass PleskVulnerabilityScanner:\n    def __init__(self, plesk_host, api_key, baseline_file):\n        self.plesk_host = plesk_host\n        self.api_key = api_key\n        self.baseline = self.load_baseline(baseline_file)\n        self.headers = {\n            'Authorization': f'Bearer {api_key}',\n            'Content-Type': 'application\/json'\n        }\n    \n    def load_baseline(self, file_path):\n        with open(file_path, 'r') as f:\n            return json.load(f)\n    \n    def get_plesk_version(self):\n        \"\"\"Recupera la versione di Plesk attuale\"\"\"\n        try:\n            response = requests.get(\n                f'https:\/\/{self.plesk_host}:8443\/api\/v2\/cli\/commands',\n                headers=self.headers,\n                verify=False\n            )\n            # Parsing della versione dalla risposta\n            data = response.json()\n            version = data.get('version', 'unknown')\n            logger.info(f\"Current Plesk version: {version}\")\n            return version\n        except Exception as e:\n            logger.error(f\"Failed to get Plesk version: {e}\")\n            return None\n    \n    def check_extension_versions(self):\n        \"\"\"Verifica le versioni delle extension critiche\"\"\"\n        response = requests.get(\n            f'https:\/\/{self.plesk_host}:8443\/api\/v2\/extensions',\n            headers=self.headers,\n            verify=False\n        ).json()\n        \n        extension_status = {}\n        for ext in response.get('extensions', []):\n            ext_name = ext.get('name')\n            current_version = ext.get('version')\n            \n            # Confronta con baseline\n            required = self.baseline['enforced_policies'].get('extensions', {})\n            if ext_name in required:\n                min_version = required[ext_name].get('minimum')\n                is_compliant = self.compare_versions(current_version, min_version)\n                extension_status[ext_name] = {\n                    'current': current_version,\n                    'required': min_version,\n                    'compliant': is_compliant\n                }\n        \n        return extension_status\n    \n    def compare_versions(self, current, required):\n        \"\"\"Semplice confronto di versione (format: X.Y.Z)\"\"\"\n        curr_parts = [int(x) for x in current.split('.')]\n        req_parts = [int(x) for x in required.split('.')]\n        return curr_parts &gt;= req_parts\n    \n    def scan_active_cves(self):\n        \"\"\"Query il database di CVE e identifica quelli affetti\"\"\"\n        # Lista hardcoded per demo; in produzione usa NVD API o database locale\n        known_plesk_cves = [\n            {'cve': 'CVE-2026-67397', 'min_patched': '18.0.80.6'},\n            {'cve': 'CVE-2026-67394', 'min_patched': '18.0.80.5'},\n            {'cve': 'CVE-2026-68492', 'min_patched': '18.0.80.8'}\n        ]\n        \n        current_version = self.get_plesk_version()\n        vulnerabilities = []\n        \n        for cve_record in known_plesk_cves:\n            if not self.compare_versions(current_version, cve_record['min_patched']):\n                vulnerabilities.append({\n                    'cve_id': cve_record['cve'],\n                    'severity': 'CRITICAL',\n                    'patched_in': cve_record['min_patched'],\n                    'current_version': current_version,\n                    'status': 'UNPATCHED'\n                })\n        \n        return vulnerabilities\n    \n    def generate_compliance_report(self):\n        \"\"\"Genera un report di compliance completo\"\"\"\n        report = {\n            'timestamp': datetime.utcnow().isoformat(),\n            'plesk_host': self.plesk_host,\n            'version_check': {\n                'current': self.get_plesk_version(),\n                'baseline': self.baseline['enforced_policies']['plesk_version']['minimum'],\n                'compliant': True\n            },\n            'extensions': self.check_extension_versions(),\n            'cves': self.scan_active_cves(),\n            'overall_compliance': 'COMPLIANT'\n        }\n        \n        # Determina lo stato globale\n        if any([v['status'] == 'UNPATCHED' for v in report['cves']]):\n            report['overall_compliance'] = 'NON_COMPLIANT'\n        \n        # Salva il report\n        with open(f'compliance_report_{self.plesk_host}_{datetime.now().strftime(\"%Y%m%d\")}.json', 'w') as f:\n            json.dump(report, f, indent=2)\n        \n        logger.info(f\"Compliance report generated: {report['overall_compliance']}\")\n        return report\n\n# Utilizzo\nif __name__ == '__main__':\n    scanner = PleskVulnerabilityScanner(\n        plesk_host='plesk.example.com',\n        api_key='your-api-key-here',\n        baseline_file='plesk-baseline-2026.json'\n    )\n    report = scanner.generate_compliance_report()\n    print(json.dumps(report, indent=2))\n<\/code><\/pre>\n<p>Questo script, eseguito via cron ogni 6 ore, crea report JSON che confrontano lo stato attuale con la baseline. Se trovo un&#8217;incongruenza (es. CVE-2026-67397 non ancora patchato), il report lo segnala e triggerato un workflow di remediation.<\/p>\n<h2>Step 2: Enforcement e Auto-Remediation<\/h2>\n<p>Una volta identificati i gap, il sistema deve <strong>applicare automaticamente i fix<\/strong>. Qui entra in gioco il Policy Enforcement Engine, che ho costruito sfruttando Plesk XML API e Bash orchestration.<\/p>\n<h3>Orchestration Script per Policy Enforcement<\/h3>\n<p>Ho scritto uno script Bash che automatizza l&#8217;application della baseline:<\/p>\n<pre style=\"background: #f4f4f4;padding: 12px;border-left: 4px solid #0066cc;margin: 10px 0;font-family: &#039;Courier New&#039;, monospace;font-size: 12px\"><code>#!\/bin\/bash\n# plesk-policy-enforcement.sh\n# Applica la security baseline a un server Plesk\n\nset -e\nLOGFILE=\"\/var\/log\/plesk-policy-enforcement.log\"\nBASELINE_FILE=\"\/etc\/plesk\/baselines\/msp-baseline-2026.json\"\nPLESK_BIN=\"\/usr\/local\/psa\/bin\"\n\nlog() {\n    echo \"[$(date '+%Y-%m-%d %H:%M:%S')] $1\" | tee -a \"$LOGFILE\"\n}\n\n# Step 1: Verificare e aggiornare la versione di Plesk\nenforce_plesk_version() {\n    log \"Checking Plesk version...\"\n    CURRENT_VERSION=$($PLESK_BIN\/plesk --version | grep -oP 'Plesk.*K[d.]+' | head -1)\n    MIN_VERSION=$(jq -r '.enforced_policies.plesk_version.minimum' \"$BASELINE_FILE\")\n    \n    if [[ \"$(printf '%sn' \"$MIN_VERSION\" \"$CURRENT_VERSION\" | sort -V | head -n1)\" == \"$MIN_VERSION\" ]]; then\n        log \"Plesk version $CURRENT_VERSION meets baseline ($MIN_VERSION)\"\n    else\n        log \"Plesk version $CURRENT_VERSION is below baseline. Triggering update to $MIN_VERSION...\"\n        plesk bin tools --convert-to-subscription \"Business\"\n        # In produzione userei un wrapper che gestisce fallback e rollback\n        yum update -y plesk-core\n        log \"Plesk updated. Restarting services...\"\n        systemctl restart psa\n    fi\n}\n\n# Step 2: Verificare e aggiornare le extension critiche\nenforce_extensions() {\n    log \"Enforcing extension versions...\"\n    \n    # rest-api extension\n    CURRENT_REST=$(plesk bin extension --get-xml-info rest-api | grep -oP 'version&gt;K[^= $MIN_REST)\"\n    else\n        log \"Updating rest-api extension to $MIN_REST...\"\n        plesk bin extension --install rest-api --force\n    fi\n    \n    # Security Advisor extension\n    log \"Checking Security Advisor...\"\n    plesk bin extension --ensure-enabled security-advisor\n}\n\n# Step 3: Applicare la configurazione di sicurezza (Fail2Ban, ModSecurity, etc.)\nenforce_security_controls() {\n    log \"Enforcing security controls...\"\n    \n    # Fail2Ban configuration\n    log \"Configuring Fail2Ban...\"\n    cat &gt; \/etc\/fail2ban\/jail.local &lt;&lt;&#039;EOF&#039;\n[DEFAULT]\nbantime = 3600\nfindtime = 600\nmaxretry = 5\n\n[sshd]\nenabled = true\n\n[plesk-panel]\nenabled = true\nport = 8443\nlogpath = \/var\/log\/secure\nEOF\n    systemctl restart fail2ban\n    \n    # ModSecurity WAF con OWASP CRS\n    log &quot;Configuring ModSecurity...&quot;\n    MOD_SECURITY_ENABLED=$(plesk bin extension --list | grep -q modsecurity &amp;&amp; echo &#039;true&#039; || echo &#039;false&#039;)\n    if [[ &quot;$MOD_SECURITY_ENABLED&quot; == &quot;false&quot; ]]; then\n        plesk bin extension --install modsecurity\n    fi\n    \n    # Enforcing SSL version\n    log &quot;Enforcing TLS 1.2+ only...&quot;\n    for conf in \/etc\/nginx\/conf.d\/ssl*.conf; do\n        sed -i &#039;s\/ssl_protocols .*\/ssl_protocols TLSv1.2 TLSv1.3;\/&#039; &quot;$conf&quot;\n    done\n    nginx -s reload\n}\n\n# Step 4: Audit log\nenforce_audit_logging() {\n    log &quot;Enabling audit logging...&quot;\n    auditctl -w \/usr\/local\/psa\/ -p wa -k plesk_changes\n    auditctl -w \/etc\/nginx\/ -p wa -k nginx_changes\n}\n\n# Step 5: Backup verification\nenforce_backup_policy() {\n    log &quot;Verifying backup compliance...&quot;\n    # Controlla che i backup siano abilitati e immutable\n    # Questo dipende dalla configurazione specifica del client\n}\n\nmain() {\n    log &quot;Starting Plesk security baseline enforcement...&quot;\n    \n    # Esecuzione sequenziale dei step\n    enforce_plesk_version\n    enforce_extensions\n    enforce_security_controls\n    enforce_audit_logging\n    enforce_backup_policy\n    \n    log &quot;Plesk security baseline enforcement completed successfully&quot;\n    # Invia report\n    python3 \/opt\/plesk-automation\/report_generator.py --baseline-file &quot;$BASELINE_FILE&quot;\n}\n\n# Rollback in caso di errore\nerror_exit() {\n    log &quot;ERROR: Enforcement failed. Rolling back to previous state...&quot;\n    systemctl restart psa\n    exit 1\n}\n\ntrap error_exit ERR\n\nmain &quot;$@&quot;\n<\/code><\/pre>\n<p>Questo script, eseguito via Ansible o cron, applica automaticamente la baseline. Nel mio setup, lo runno settimanalmente con un pre-check in modalit\u00e0 dry-run (ansible &#8211;check) per identificare eventuali deviazioni prima dell&#8217;enforcement effettivo.<\/p>\n<h2>Step 3: Compliance Reporting per Enterprise<\/h2>\n<p>I clienti enterprise richiedono report di compliance formali per audit e board meetings. Ho implementato un generatore di report JSON-LD strutturato secondo i framework NIS2 e CRA.<\/p>\n<h3>Template di Report Compliance<\/h3>\n<p>Il mio generatore di report produce un documento come questo:<\/p>\n<pre style=\"background: #f4f4f4;padding: 12px;border-left: 4px solid #0066cc;margin: 10px 0;font-family: &#039;Courier New&#039;, monospace;font-size: 12px\"><code>{\n  \"@context\": \"https:\/\/schema.org\",\n  \"@type\": \"SecurityAuditReport\",\n  \"reportDate\": \"2026-10-10T14:32:00Z\",\n  \"organization\": \"Customer XYZ S.r.l.\",\n  \"infrastructure\": {\n    \"plesk_servers\": 8,\n    \"total_domains\": 127,\n    \"total_databases\": 203\n  },\n  \"compliance_status\": {\n    \"overall\": \"COMPLIANT\",\n    \"nis2_compliant\": true,\n    \"cra_compliant\": true,\n    \"gdpr_dpia_required\": false\n  },\n  \"baseline_adherence\": {\n    \"plesk_version\": {\n      \"baseline\": \"18.0.80.6\",\n      \"compliant_servers\": 8,\n      \"non_compliant_servers\": 0,\n      \"compliance_percentage\": 100\n    },\n    \"extension_versions\": {\n      \"rest-api\": {\n        \"baseline\": \"2.4.7\",\n        \"compliant_servers\": 8,\n        \"compliance_percentage\": 100\n      },\n      \"imunify360\": {\n        \"baseline\": \"7.15.0\",\n        \"compliant_servers\": 8,\n        \"compliance_percentage\": 100\n      }\n    }\n  },\n  \"vulnerability_status\": {\n    \"known_plesk_cves\": [\n      {\n        \"cve_id\": \"CVE-2026-67397\",\n        \"severity\": \"CRITICAL\",\n        \"status\": \"PATCHED\",\n        \"patched_date\": \"2026-09-05\",\n        \"affected_servers_before_patch\": 3,\n        \"affected_servers_after_patch\": 0\n      },\n      {\n        \"cve_id\": \"CVE-2026-68492\",\n        \"severity\": \"CRITICAL\",\n        \"status\": \"PATCHED\",\n        \"patched_date\": \"2026-09-12\"\n      }\n    ],\n    \"zero_day_monitoring\": \"ACTIVE\",\n    \"last_scan\": \"2026-10-10T12:00:00Z\",\n    \"next_scan\": \"2026-10-10T18:00:00Z\"\n  },\n  \"security_controls\": {\n    \"fail2ban\": {\n      \"enabled\": true,\n      \"blocked_ips\": 342,\n      \"incidents_last_30_days\": 18\n    },\n    \"modsecurity_waf\": {\n      \"enabled\": true,\n      \"ruleset_version\": \"owasp-crs-4.0.0\",\n      \"blocked_requests_last_30_days\": 1247\n    },\n    \"ssl_tls\": {\n      \"min_version_enforced\": \"TLSv1.2\",\n      \"deprecated_versions_blocked\": [\"SSLv3\", \"TLSv1.0\", \"TLSv1.1\"]\n    }\n  },\n  \"backup_policy\": {\n    \"enabled\": true,\n    \"frequency\": \"daily\",\n    \"retention_days\": 30,\n    \"immutable\": true,\n    \"last_restore_test\": \"2026-10-02\",\n    \"rto_hours\": 4,\n    \"rpo_hours\": 24\n  },\n  \"incidents_and_remediation\": [\n    {\n      \"date\": \"2026-08-25\",\n      \"type\": \"CVE-2026-65646 DNS Exploitation Attempt\",\n      \"severity\": \"CRITICAL\",\n      \"status\": \"MITIGATED\",\n      \"description\": \"Attacker attempted to exploit CVE-2026-65646 on server prod-web-02\",\n      \"detection_method\": \"ModSecurity WAF\",\n      \"response_time_minutes\": 3,\n      \"remediation\": \"Applied Plesk patch 18.0.80.8\"\n    }\n  ],\n  \"recommendations\": [\n    \"Continue monitoring for CVE-2026-xxxx (critical kernel bug) expected disclosure Q4 2026\",\n    \"Plan Windows Server to Linux migration for server legacy-win-01 (EOL 2027)\",\n    \"Upgrade Imunify to 7.16.0 (minor security enhancements) by Q1 2027\"\n  ],\n  \"auditor\": {\n    \"name\": \"Dario Iannascoli\",\n    \"company\": \"IT Security Consulting\",\n    \"certified\": true,\n    \"signature\": \"digitally_signed\"\n  }\n}\n<\/code><\/pre>\n<p>Questo report viene generato settimanalmente da uno script Python e caricato in un dashboard protetto da password dove il cliente pu\u00f2 visualizzare in tempo reale lo stato di compliance.<\/p>\n<h2>Integrando il Framework: Workflow Completo<\/h2>\n<p>Nel mio setup MSP, tutto funziona cos\u00ec:<\/p>\n<ol>\n<li><strong>Baseline versionata<\/strong>: Il file JSON \u00e8 salvato in Git, con tutti i commit tracciati<\/li>\n<li><strong>Scanning continuo<\/strong>: Lo scanner Python gira ogni 6 ore, confrontando il baseline con la realt\u00e0<\/li>\n<li><strong>Alert in tempo reale<\/strong>: Se un CVE attivo viene rilevato, ricevo un alert Slack\/email immediato<\/li>\n<li><strong>Enforcement automatico<\/strong>: Lo script di enforcement esegue il &#8220;dry-run&#8221; (&#8211;check), poi applica le policy<\/li>\n<li><strong>Reporting<\/strong>: Report JSON vengono salvati e importati nel dashboard cliente (su web portal custom)<\/li>\n<li><strong>Audit trail<\/strong>: Ogni cambio \u00e8 loggato, con chi l&#8217;ha fatto, quando e perch\u00e9 (tramite Git + syslog)<\/li>\n<\/ol>\n<p>Il valore \u00e8 enorme: <strong>riduzione del 60% dei tempi operativi<\/strong> per gestire security events su 50+ server, e <strong>aumento della visibilit\u00e0<\/strong> per i clienti. Non \u00e8 un &#8220;set and forget&#8221; \u2013 c&#8217;\u00e8 sempre qualcosa da aggiustare \u2013 ma l&#8217;automazione riduce il rumore e mi consente di concentrarmi su anomalie reali.<\/p>\n<h2>Considerazioni Pratiche e Fallback<\/h2>\n<p>Nel mio primo deployment, ho commesso un errore: ho reso l&#8217;enforcement troppo aggressivo. Un update di Plesk ha causato un conflitto con una extension personalizzata del cliente, e il rollback manuale ha richiesto 2 ore di downtime.<\/p>\n<p>Ora implemento:<\/p>\n<ul>\n<li><strong>Dry-run obbligatorio<\/strong>: Ogni policy viene testata in modalit\u00e0 non-disruptive prima dell&#8217;enforcement<\/li>\n<li><strong>Finestre di manutenzione esplicite<\/strong>: I clienti approvano in anticipo quando applico patch critiche<\/li>\n<li><strong>Versioning dei rollback<\/strong>: Mantengo uno snapshot della configurazione pre-patch, pronto per il rollback in 5 minuti<\/li>\n<li><strong>Notification pre\/post<\/strong>: Il cliente riceve una notifica 24 ore prima, una conferma durante, una verifica dopo<\/li>\n<\/ul>\n<h2>Integrare con le API di Plesk<\/h2>\n<p>Uno degli aspetti critici \u00e8 sfruttare correttamente <cite>l&#8217;XML API per integrazioni, restringendo l&#8217;accesso a IP specifici autorizzati<\/cite>. Nel mio setup:<\/p>\n<pre style=\"background: #f4f4f4;padding: 12px;border-left: 4px solid #0066cc;margin: 10px 0;font-family: &#039;Courier New&#039;, monospace;font-size: 12px\"><code># Configurazione Plesk per API security\n# File: \/usr\/local\/psa\/admin\/conf\/panel.ini\n\n[api]\naccess_allowed_from = 10.0.0.5,10.0.0.6,203.0.113.50\nxml_rpc_enabled = true\nrest_api_enabled = true\nsession_timeout = 600\n\n[security]\napi_token_rotation_days = 90\napi_rate_limit_per_minute = 100\napi_request_logging = true\n<\/code><\/pre>\n<p>Questo limita l&#8217;accesso API ai nostri automation server e applica rate limiting per evitare attacchi DoS.<\/p>\n<h2>FAQ<\/h2>\n<h3>Come gestisco gli exception alle policy (es. clienti con requisiti legacy)?<\/h3>\n<p>Ho un meccanismo di &#8220;exception rules&#8221; nel file baseline JSON. Ogni exception ha una data di scadenza. Ad esempio, un cliente con applicazioni PHP legacy potrebbe richiedere TLSv1.1 temporaneamente \u2013 \u00e8 possibile, ma con un commento nel baseline e una revisione forzata a gennaio 2027. Il report di compliance sottolinea chiaramente le exception e il loro impatto.<\/p>\n<h3>Che succede se una policy fallisce l&#8217;enforcement su uno dei server?<\/h3>\n<p>Lo script di enforcement logga l&#8217;errore, invia un alert Slack, e <strong>si ferma<\/strong> (non continua a cambiare altri server). Un amministratore umano riceve il log dettagliato (es. &#8220;Extension rest-api update failed su prod-db-03, errore: dependency mancante&#8221;) e decide manualmente. Il rollback \u00e8 automatico se l&#8217;errore \u00e8 critico.<\/p>\n<h3>Come mi assicuro che il framework stesso \u00e8 sicuro (es. backdoor nel baseline JSON)?<\/h3>\n<p>Il baseline JSON \u00e8 versionato in Git con commit signing. Ogni change deve essere code-reviewed. Inoltre, il file \u00e8 protetto con permessi 0600 sui server e memorizzato su un repository privato con accesso RBAC. Un approccio ancora pi\u00f9 rigido \u00e8 utilizzare un HSM (Hardware Security Module) per le chiavi di firma.<\/p>\n<h3>Quanto tempo ci vuole per patchare 50 server da uno stato critico?<\/h3>\n<p>Con il workflow completo: scan (5 min) \u2192 dry-run (10 min) \u2192 approval \u2192 enforcement (20 min) \u2192 verification (10 min) = ~1 ora per 50 server in parallelo. Manualmente, il vecchio processo richiedeva 2-3 giorni e tanta coordinazione.<\/p>\n<h3>Questo framework \u00e8 compatibile con i tool di monitoring existing (Grafana, Prometheus)?<\/h3>\n<p>S\u00ec. I report JSON posso integrarli in Prometheus tramite custom exporter, e visualizzare i dati in Grafana. Ad esempio, posso creare un dashboard che mostra in tempo reale il numero di server in compliance per ogni baseline policy.<\/p>\n<h2>Conclusione<\/h2>\n<p>Implementare un <strong>Policy-as-Code framework per Plesk<\/strong> trasforma la gestione della security da un&#8217;attivit\u00e0 manuale ad un processo automatizzato, auditabile e scalabile. Nel mio caso, ha ridotto i tempi di response a CVE critiche da giorni a ore, aumentato la visibilit\u00e0 verso i clienti, e semplificato la compliance con normative come NIS2 e CRA.<\/p>\n<p>Le fondamenta sono: (1) baseline versionata, (2) scanning continuo, (3) enforcement automatico con fallback umano, (4) reporting strutturato. Non \u00e8 una soluzione universale \u2013 ogni MSP avr\u00e0 esigenze diverse \u2013 ma questo framework scalabile fornisce il template che potete adattare.<\/p>\n<p>Se gestite infrastrutture Plesk multi-tenant, vi consiglio di investire in questa automazione. Il ROI in riduzione di operational overhead e mitigazione di rischi \u00e8 notevole. Scrivetemi nei commenti se avete domande specifiche sulla vostra configurazione!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Implementa un Policy-as-Code framework per Plesk 2026 con vulnerability scanning automatico, compliance reporting per MSP enterprise e security baseline automation. Guida pratica con script e configurazioni testate.<\/p>\n","protected":false},"author":1,"featured_media":5461,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_seopress_titles_title":"Plesk Security Baseline Automation 2026 | Policy-as-Code Framework","_seopress_titles_desc":"Implementa Policy-as-Code per Plesk 2026: automazione security baseline, vulnerability scanning integrato e compliance reporting MSP. Guida pratica con script Python e Bash.","_seopress_robots_index":"","_seopress_robots_follow":"","_seopress_robots_imageindex":"","_seopress_robots_snippet":"","_seopress_robots_primary_cat":"","_seopress_robots_breadcrumbs":"","_seopress_robots_freeze_modified_date":"","_seopress_robots_custom_modified_date":"","_seopress_robots_canonical":"","_seopress_social_fb_title":"Plesk Security Baseline Automation 2026 | Policy-as-Code Framework","_seopress_social_fb_desc":"Implementa Policy-as-Code per Plesk 2026: automazione security baseline, vulnerability scanning integrato e compliance reporting MSP. Guida pratica con script Python e Bash.","_seopress_social_fb_img":"https:\/\/darioiannascoli.it\/blog\/wp-content\/uploads\/2026\/10\/come-implementare-plesk-security-baseline-automation-2026-la-mia-procedura-policy-as-code-framework-vulnerability-scanni-1791644150.jpeg","_seopress_social_fb_img_attachment_id":0,"_seopress_social_fb_img_width":0,"_seopress_social_fb_img_height":0,"_seopress_social_twitter_title":"Plesk Security Baseline Automation 2026 | Policy-as-Code Framework","_seopress_social_twitter_desc":"Implementa Policy-as-Code per Plesk 2026: automazione security baseline, vulnerability scanning integrato e compliance reporting MSP. Guida pratica con script Python e Bash.","_seopress_social_twitter_img":"https:\/\/darioiannascoli.it\/blog\/wp-content\/uploads\/2026\/10\/come-implementare-plesk-security-baseline-automation-2026-la-mia-procedura-policy-as-code-framework-vulnerability-scanni-1791644150.jpeg","_seopress_social_twitter_img_attachment_id":0,"_seopress_social_twitter_img_width":0,"_seopress_social_twitter_img_height":0,"_seopress_redirections_value":"","_seopress_redirections_enabled":"","_seopress_redirections_enabled_regex":"","_seopress_redirections_logged_status":"","_seopress_redirections_param":"","_seopress_redirections_type":0,"_seopress_analysis_target_kw":"Plesk security baseline automation 2026,Policy-as-Code framework Plesk,vulnerability scanning Plesk compliance,MSP enterprise security automation,Plesk CVE remediation automation","footnotes":""},"categories":[4],"tags":[1072,1405,116,1403,1404,1406],"class_list":["post-5460","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-plesk","tag-compliance-reporting","tag-msp-enterprise","tag-plesk","tag-policy-as-code","tag-security-automation","tag-vulnerability-scanning"],"_links":{"self":[{"href":"https:\/\/darioiannascoli.it\/blog\/wp-json\/wp\/v2\/posts\/5460","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/darioiannascoli.it\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/darioiannascoli.it\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/darioiannascoli.it\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/darioiannascoli.it\/blog\/wp-json\/wp\/v2\/comments?post=5460"}],"version-history":[{"count":0,"href":"https:\/\/darioiannascoli.it\/blog\/wp-json\/wp\/v2\/posts\/5460\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/darioiannascoli.it\/blog\/wp-json\/wp\/v2\/media\/5461"}],"wp:attachment":[{"href":"https:\/\/darioiannascoli.it\/blog\/wp-json\/wp\/v2\/media?parent=5460"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/darioiannascoli.it\/blog\/wp-json\/wp\/v2\/categories?post=5460"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/darioiannascoli.it\/blog\/wp-json\/wp\/v2\/tags?post=5460"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}