Provisioning idempotente di un'azienda cliente cloud-only (Aruba/Hetzner/AI, no server in sede, PC portatili): - Fase 1: org + classificazione NIS2 (important, sub_threshold_candidate/preliminary) + 3 membri esistenti collegati + organigramma 8 ruoli - Fase 2: 12 asset (NIS2-rilevanti) + 4 fornitori + 10 rischi + gap analysis (80 risposte, 45%) - Fase 3: ISMS model + SoA 111 controlli (27001/27017/27018) + 31 documenti (Manuale/10 politiche/13 procedure/7 istruzioni) - Fase 4: 15 piani di controllo periodici + 5 corsi formazione Documenti AI-redatti con regole fonti-certe (D.Lgs.138/2024 art.23/24/25; 24h/72h/1 mese). Sorgenti in _docs_na/. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
104 lines
7.7 KiB
PHP
104 lines
7.7 KiB
PHP
<?php
|
|
/**
|
|
* build_nuova_agile_p3a.php — FASE 3a: ISMS model + SoA (ISO 27001 + 27017 + 27018). IDEMPOTENTE.
|
|
*/
|
|
if (PHP_SAPI !== 'cli') { http_response_code(403); exit("CLI only\n"); }
|
|
require_once __DIR__ . '/../config/env.php';
|
|
require_once __DIR__ . '/../config/database.php';
|
|
$pdo = Database::getInstance();
|
|
function ex(PDO $p, string $sql, array $a = []): void { $s=$p->prepare($sql); $s->execute($a); }
|
|
function one(PDO $p, string $sql, array $a = []) { $s=$p->prepare($sql); $s->execute($a); return $s->fetch(PDO::FETCH_ASSOC); }
|
|
$NOW='2026-06-20 10:40:00';
|
|
|
|
$org=one($pdo,"SELECT id FROM organizations WHERE name=?",['Nuova Agile Technology srl']);
|
|
if(!$org) exit("ORG mancante\n"); $orgId=(int)$org['id']; $RSGSI=326; $PRES=103;
|
|
|
|
/* ---- ISMS MODEL ------------------------------------------------------------ */
|
|
$scope = "Il Sistema di Gestione per la Sicurezza delle Informazioni (SGSI) di Nuova Agile Technology srl copre lo "
|
|
."sviluppo, l'erogazione e la manutenzione dei prodotti software forniti in licenza d'uso (installati presso i "
|
|
."clienti) e dei servizi SaaS erogati in cloud, inclusi i processi di supporto, la gestione dell'infrastruttura "
|
|
."cloud (Aruba, Hetzner) e delle piattaforme AI, la gestione degli endpoint (PC portatili) e il trattamento dei "
|
|
."dati personali dei clienti. Sedi: ufficio operativo in Italia; nessun data center proprio.";
|
|
$ctxInt = "Software house di piccole dimensioni (9 dipendenti, 2 collaboratori esterni a P.IVA, Presidente Silvia Garretto). "
|
|
."Modello di lavoro agile, infrastruttura interamente cloud, parco PC portatili. Competenze tecniche interne su sviluppo e cloud; "
|
|
."DPO/privacy in outsourcing.";
|
|
$ctxExt = "Clienti che richiedono garanzie di sicurezza e conformita (alcuni soggetti NIS2 obbligati che estendono i requisiti lungo "
|
|
."la supply chain, Art.21 D.Lgs.138/2024). Fornitori cloud UE (Aruba IT, Hetzner DE) e sub-fornitori AI. Quadro normativo: "
|
|
."GDPR (UE 2016/679), Direttiva NIS2 (UE 2022/2555) e D.Lgs.138/2024, standard ISO/IEC 27001:2022, 27017:2015, 27018:2019.";
|
|
$parties = json_encode([
|
|
['parte'=>'Clienti','esigenze'=>'Riservatezza, integrita e disponibilita dei dati; conformita contrattuale e supply chain NIS2'],
|
|
['parte'=>'Dipendenti e collaboratori','esigenze'=>'Strumenti sicuri, regole chiare, formazione'],
|
|
['parte'=>'Fornitori cloud (Aruba, Hetzner)','esigenze'=>'Uso conforme dei servizi, modello di responsabilita condivisa'],
|
|
['parte'=>'Sub-fornitori AI','esigenze'=>'Trattamento conforme dei dati, DPA, minimizzazione'],
|
|
['parte'=>'Autorita (Garante, ACN)','esigenze'=>'Conformita GDPR e NIS2, notifica incidenti'],
|
|
['parte'=>'Soci / Direzione','esigenze'=>'Sostenibilita, reputazione, continuita del business'],
|
|
], JSON_UNESCAPED_UNICODE);
|
|
$method = "Valutazione del rischio basata su asset/minaccia/vulnerabilita con scala Probabilita x Impatto (1-5), soglia di "
|
|
."accettabilita definita dalla Direzione, opzioni di trattamento mitigare/accettare/trasferire/evitare. Coerente con ISO/IEC 27005. "
|
|
."Riesame almeno annuale e ad ogni cambiamento significativo.";
|
|
$objs = json_encode([
|
|
'Nessuna violazione di dati personali dei clienti con impatto significativo',
|
|
'Disponibilita del servizio SaaS >= 99,5% su base annua',
|
|
'100% degli accessi privilegiati protetti da MFA',
|
|
'Ripristino dei backup testato con esito positivo almeno 2 volte/anno',
|
|
'Tutti i fornitori critici coperti da DPA/clausole di sicurezza',
|
|
'Formazione sicurezza completata dal 100% del personale/anno',
|
|
], JSON_UNESCAPED_UNICODE);
|
|
$boundaries = "Incluso: sviluppo, SaaS, supporto, infrastruttura cloud, endpoint, dati clienti. ";
|
|
$exclusions = "Escluso: data center fisici (non posseduti — responsabilita dei fornitori cloud secondo modello di responsabilita condivisa).";
|
|
|
|
$m=one($pdo,"SELECT id FROM isms_models WHERE organization_id=?",[$orgId]);
|
|
if(!$m){
|
|
ex($pdo,"INSERT INTO isms_models (organization_id,status,scope_statement,context_internal,context_external,interested_parties,boundaries,exclusions,risk_methodology,isms_objectives,uses_public_cloud,is_cloud_provider,processes_pii_in_cloud,version,created_by,created_at,updated_at)
|
|
VALUES (?, 'active', ?,?,?,?,?,?,?,?, 1,1,1, '1.0', ?, ?, ?)",
|
|
[$orgId,$scope,$ctxInt,$ctxExt,$parties,$boundaries,$exclusions,$method,$objs,$RSGSI,$NOW,$NOW]);
|
|
$modelId=(int)$pdo->lastInsertId(); echo "ISMS model creato id=$modelId\n";
|
|
} else {
|
|
$modelId=(int)$m['id'];
|
|
ex($pdo,"UPDATE isms_models SET status='active',scope_statement=?,context_internal=?,context_external=?,interested_parties=?,boundaries=?,exclusions=?,risk_methodology=?,isms_objectives=?,uses_public_cloud=1,is_cloud_provider=1,processes_pii_in_cloud=1,version='1.0',updated_at=? WHERE id=?",
|
|
[$scope,$ctxInt,$ctxExt,$parties,$boundaries,$exclusions,$method,$objs,$NOW,$modelId]);
|
|
echo "ISMS model esistente id=$modelId (aggiornato)\n";
|
|
}
|
|
|
|
/* ---- ISMS ROLES (mappa Direzione/RSGSI) ------------------------------------ */
|
|
$ir=[['Alta Direzione',$PRES,'Approva politica e obiettivi SGSI, fornisce risorse, conduce il riesame','A'],
|
|
['Responsabile SGSI (RSGSI)',$RSGSI,'Gestisce e mantiene il SGSI, coordina rischi/audit/SoA','R'],
|
|
['Responsabile IT/Sicurezza',330,'Attua i controlli tecnici su cloud, endpoint, accessi','R'],
|
|
['Referente Privacy/DPO',null,'Presidio GDPR e ISO 27018','C']];
|
|
foreach($ir as [$rn,$uid,$resp,$raci]){
|
|
$exr=one($pdo,"SELECT id FROM isms_roles WHERE isms_model_id=? AND role_name=?",[$modelId,$rn]);
|
|
if(!$exr) ex($pdo,"INSERT INTO isms_roles (isms_model_id,organization_id,role_name,user_id,responsibility,raci,created_at) VALUES (?,?,?,?,?,?,?)",
|
|
[$modelId,$orgId,$rn,$uid,$resp,$raci,$NOW]);
|
|
}
|
|
echo "ISMS roles ok\n";
|
|
|
|
/* ---- SoA (deriva da catalogo 111 controlli) -------------------------------- */
|
|
$standards=['iso27001','iso27017','iso27018']; // cloud + PII tutti applicabili
|
|
$ph=implode(',',array_fill(0,count($standards),'?'));
|
|
$controls=$pdo->prepare("SELECT control_code,standard,theme,title_it FROM iso27001_annex_controls WHERE standard IN ($ph) ORDER BY sort_order");
|
|
$controls->execute($standards);
|
|
$rows=$controls->fetchAll(PDO::FETCH_ASSOC);
|
|
$jt=[
|
|
'organizational'=>"Controllo organizzativo applicabile: politiche, ruoli, accordi e processi di sicurezza definiti nel SGSI.",
|
|
'people'=>"Controllo sul personale applicabile: dipendenti e collaboratori esterni (P.IVA) soggetti a formazione, riservatezza e regole d'uso.",
|
|
'physical'=>"Ambito fisico ridotto (nessun server/data center in sede, solo PC portatili): sicurezza dei data center ereditata dai fornitori cloud (responsabilita condivisa); restano applicabili clear desk e gestione/dismissione apparecchiature.",
|
|
'technological'=>"Controllo tecnologico applicabile a infrastruttura cloud (Aruba/Hetzner), endpoint, piattaforma SaaS e piattaforme AI.",
|
|
];
|
|
$js=[
|
|
'iso27017'=>"Controllo cloud ISO/IEC 27017:2015 applicabile: l'azienda e sia cloud customer (Aruba/Hetzner/AI) sia cloud service provider (SaaS).",
|
|
'iso27018'=>"Controllo ISO/IEC 27018:2019 applicabile: la piattaforma SaaS tratta dati personali (PII) dei clienti nel cloud pubblico.",
|
|
];
|
|
$added=0;$skip=0;
|
|
foreach($rows as $c){
|
|
$code=$c['control_code'];
|
|
$exs=one($pdo,"SELECT id FROM isms_soa WHERE isms_model_id=? AND control_code=?",[$modelId,$code]);
|
|
if($exs){ $skip++; continue; }
|
|
$just = $c['standard']==='iso27001' ? ($jt[$c['theme']] ?? "Applicabile al SGSI.") : ($js[$c['standard']] ?? "Applicabile.");
|
|
ex($pdo,"INSERT INTO isms_soa (isms_model_id,organization_id,control_code,standard,applicable,justification_inclusion,implementation_status,implementation_pct,derived_from_nis2,updated_by,updated_at)
|
|
VALUES (?,?,?,?,1,?, 'not_started',0,0,?,?)",
|
|
[$modelId,$orgId,$code,$c['standard'],$just,$RSGSI,$NOW]);
|
|
$added++;
|
|
}
|
|
echo "SoA: +$added controlli (skip $skip). Totale catalogo: ".count($rows)."\n";
|
|
echo "\nFASE 3a OK — model_id=$modelId\n";
|