diff --git a/README.md b/README.md index 668a08f..116ef2d 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Repository pubblico contenente l'installer di prima fase e il Web Setup Wizard d ## Installazione rapida (one-liner) -Su una macchina Ubuntu 24.04 LTS vergine, esegui: +Su una macchina Ubuntu 24.04 o 26.04 LTS vergine, esegui: ```bash curl -fsSL https://argos-update.tecnotelsrl.com/tecnotel/argos-setup/raw/branch/main/bootstrap.sh | sudo bash @@ -33,25 +33,32 @@ sudo bash first-setup.sh | `first-setup.sh` | Installer ambiente base: sistema, utenti, firewall, nginx temp, avvia wizard web | | `setup_server.py` | Backend Python del Web Installer (porta 8888, self-contained) | | `setup.html` | Frontend del Web Installer β€” wizard in 6 step | -| `gen_config.py` | Helper per generazione iniziale di `argos.json` | ## Flusso d'installazione 1. Il cliente esegue il bootstrap (o il clone manuale + first-setup.sh). -2. `first-setup.sh` predispone l'ambiente base Ubuntu 24.04 (pacchetti, utente argos, cartelle, firewall) e avvia il Web Installer su `http://IP:8888`. +2. `first-setup.sh` predispone l'ambiente base Ubuntu (pacchetti, utente argos, cartelle, firewall) e avvia il Web Installer su `http://IP:8888`. 3. Il cliente apre il browser e segue il wizard in 6 step: 1. **Licenza ARGOS** β€” il wizard mostra il `machine_id` di questo server. Il cliente lo invia a Tecnotel, riceve `license.json`, lo carica nel wizard. - 2. **Informazioni cliente** (nome, dominio, logo) - 3. **Rete & SSL** (hostname, certificato) + 2. **Informazioni cliente** (nome, dominio, logo, contesto AI opzionale) + 3. **Rete & SSL** (hostname, certificato: Let's Encrypt / caricamento / autofirmato) 4. **SIEM** (OpenSearch) 5. **Utente admin** 6. **Riepilogo & Installazione** β€” il wizard clona il repository privato `tecnotel/argos` usando il token della licenza, crea virtualenv, configura servizi e avvia ARGOS SOC. Al termine il Web Installer viene disattivato automaticamente e la porta 8888 chiusa. +## Opzioni certificato SSL + +Il wizard offre tre modalitΓ  per il certificato: + +- **πŸ”’ Let's Encrypt** β€” automatico e gratuito. Richiede DNS pubblico giΓ  puntato al server. +- **πŸ“„ Certificato esistente** β€” caricamento di file `.crt` e `.key` esistenti (es. cert wildcard aziendale, cert di CA interna). +- **πŸ” Autofirmato** β€” generato localmente con RSA 4096 e validitΓ  10 anni. Utile per installazioni in LAN / dev / ambienti isolati senza DNS pubblico. ⚠️ I browser segnaleranno il certificato come non attendibile. + ## Requisiti -- Ubuntu 24.04 LTS (verificato dallo script) +- Ubuntu **24.04 LTS** o **26.04 LTS** (verificato dallo script) - Accesso root (sudo) - Connessione internet verso `argos-update.tecnotelsrl.com` - Una licenza ARGOS valida emessa da Tecnotel per il `machine_id` del server @@ -63,3 +70,4 @@ Al termine il Web Installer viene disattivato automaticamente e la porta 8888 ch ## Versioning Questo repository segue lo stesso schema di versioning di `argos` (SemVer tag `vX.Y.Z`). + diff --git a/first-setup.sh b/first-setup.sh index a7515af..73f2fb5 100755 --- a/first-setup.sh +++ b/first-setup.sh @@ -16,7 +16,14 @@ section() { echo -e "\n${BLUE}════════════════ [[ $EUID -ne 0 ]] && error "Eseguire come root: sudo bash first-setup.sh" . /etc/os-release -[[ "$ID" != "ubuntu" || "$VERSION_ID" != "24.04" ]] && error "Richiesto Ubuntu 24.04 LTS" +SUPPORTED_VERSIONS=("24.04" "26.04") +VERSION_OK=0 +for v in "${SUPPORTED_VERSIONS[@]}"; do + [[ "$VERSION_ID" == "$v" ]] && VERSION_OK=1 +done +[[ "$ID" != "ubuntu" || $VERSION_OK -eq 0 ]] && \ + error "Richiesto Ubuntu 24.04 o 26.04 LTS (rilevato: $ID $VERSION_ID)" +info "Sistema rilevato: Ubuntu $VERSION_ID LTS" echo "" echo -e "${BLUE}╔══════════════════════════════════════════╗${NC}" @@ -39,7 +46,7 @@ apt-get install -y -qq \ ufw fail2ban \ build-essential libssl-dev libffi-dev python3-dev \ sqlite3 net-tools dnsutils lsof tcpdump nmap \ - ca-certificates gnupg apt-transport-https + ca-certificates gnupg apt-transport-https openssl success "Pacchetti sistema installati" # ══════════════════════════════════════════════════════════════════════════════ diff --git a/setup.html b/setup.html index 023ab57..7e71b55 100644 --- a/setup.html +++ b/setup.html @@ -172,7 +172,7 @@ html,body{height:100%;background:var(--bg);color:var(--text);font-family:var(--s
Dominio utenti (es. nome@azienda.it)
-
Solo se Microsoft 365. Vuoto se non usato.
+
3-4 frasi sul cliente per contestualizzare i prompt AI. Iniettato in ogni richiesta AI per sintesi piΓΉ accurate.
Logo cliente (per i PDF report)
@@ -196,6 +196,7 @@ html,body{height:100%;background:var(--bg);color:var(--text);font-family:var(--s
πŸ”’ Let's EncryptAutomatico e gratuito
πŸ“„ Certificato esistenteCarica .crt e .key
+
πŸ” AutofirmatoLAN / dev β€” 10 anni
Per notifiche di scadenza certificato
+ @@ -400,8 +412,10 @@ function setSsl(mode) { sslMode = mode; document.getElementById('ssl-le').classList.toggle('active', mode === 'letsencrypt'); document.getElementById('ssl-manual').classList.toggle('active', mode === 'manual'); + document.getElementById('ssl-selfsigned').classList.toggle('active', mode === 'selfsigned'); document.getElementById('le-block').style.display = mode === 'letsencrypt' ? 'block' : 'none'; document.getElementById('manual-block').style.display = mode === 'manual' ? 'block' : 'none'; + document.getElementById('selfsigned-block').style.display = mode === 'selfsigned' ? 'block' : 'none'; } async function uploadSsl(input, type) { @@ -438,7 +452,8 @@ function collectData() { return { cliente_name: g('cliente_name'), cliente_full: g('cliente_full'), cliente_domain: g('cliente_domain'), cliente_type: g('cliente_type'), - sp_tenant: g('sp_tenant'), domain: g('domain'), aliases: g('aliases'), + ai_context: g('ai_context'), + domain: g('domain'), aliases: g('aliases'), ssl_mode: sslMode, admin_email: g('admin_email'), os_url: g('os_url'), os_user: g('os_user') || 'admin', os_pass: g('os_pass'), admin_username: g('admin_username') || 'admin', @@ -460,13 +475,19 @@ function buildSummary() { const row = (l, v) => '
' + l + '
' + (v || 'non configurato') + '
'; + const sslLabel = sslMode === 'letsencrypt' ? "Let's Encrypt (automatico)" + : sslMode === 'manual' ? "Certificato esistente caricato" + : sslMode === 'selfsigned' ? "Autofirmato (RSA 4096, 10 anni)" + : "Non configurato"; + document.getElementById('summary-box').innerHTML = '
' + '
Cliente
' + row('Nome', d.cliente_name) + row('Nome completo', d.cliente_full) + row('Dominio email', d.cliente_domain) + row('Tipo', d.cliente_type) + + (d.ai_context ? row('Contesto AI', d.ai_context.substring(0, 80) + (d.ai_context.length > 80 ? '…' : '')) : '') + '
Rete & SSL
' + row('Hostname', d.domain) + row('Alias', d.aliases) + - row('SSL', sslMode === 'letsencrypt' ? "Let's Encrypt" : 'Certificato manuale') + + row('SSL', sslLabel) + '
SIEM
' + row('OpenSearch URL', d.os_url) + row('Username', d.os_user) + '
Utente admin
' + diff --git a/setup_server.py b/setup_server.py index 5859753..57dac97 100644 --- a/setup_server.py +++ b/setup_server.py @@ -177,9 +177,8 @@ def generate_argos_json(data): "full_name": data.get("cliente_full", ""), "domain": data.get("cliente_domain", ""), "type": data.get("cliente_type", "enterprise"), - "ai_context": "", - "sharepoint_tenant": "", - "console_url": "" + "ai_context": data.get("ai_context", ""), + "console_url": "" }, "network": { "hostname": hostname, @@ -364,6 +363,19 @@ def install(data): chown(CONFIG_DIR / "modules.json") log("modules.json copiato") + # 5b. File .example aggiuntivi (config sezioni recenti) + # - automations.json: config feed TI sources + cron daemon TI + # - siem_integrations.json: catalogo SIEM Integration Builder + # - subnet_registry.json: mapping sede/reparto da subnet + for stem in ("automations", "siem_integrations", "subnet_registry"): + src = APP_DIR / f"config/{stem}.json.example" + dst = CONFIG_DIR / f"{stem}.json" + if src.exists() and not dst.exists(): + shutil.copy(src, dst) + os.chmod(dst, 0o640) + chown(dst) + log(f"{stem}.json copiato da template") + # 6. Logo cliente logo_src = SETUP_DIR / "logo_cliente.png" if logo_src.exists(): @@ -413,6 +425,74 @@ def install(data): ssl_crt = str(CERTS_DIR / "fullchain.pem") ssl_key = str(CERTS_DIR / "privkey.pem") log("Certificato SSL manuale copiato") + elif ssl_mode == "selfsigned": + # Cert autofirmato β€” utile per installazioni LAN/dev senza DNS + # pubblico. Validita' 10 anni, RSA 4096, SAN da hostname+alias. + log("Generazione certificato autofirmato (RSA 4096, validita' 10 anni)") + CERTS_DIR.mkdir(parents=True, exist_ok=True) + crt_path = CERTS_DIR / "fullchain.pem" + key_path = CERTS_DIR / "privkey.pem" + cnf_path = CERTS_DIR / "openssl-selfsigned.cnf" + + # Build subjectAltName list: tutti i nomi DNS + IP server + san_dns = [n for n in all_names.split() if n] + try: + server_ip = subprocess.check_output( + ["hostname", "-I"], text=True + ).strip().split()[0] + except Exception: + server_ip = "" + + san_lines = "\n".join(f"DNS.{i+1} = {n}" for i, n in enumerate(san_dns)) + if server_ip: + san_lines += f"\nIP.1 = {server_ip}" + + # Subject info: cliente_full come O, domain come CN + client_full = data.get("cliente_full") or data.get("cliente_name") or "ARGOS" + cn = domain or "argos.local" + + cnf = f"""[req] +default_bits = 4096 +prompt = no +default_md = sha256 +distinguished_name = dn +req_extensions = req_ext +x509_extensions = v3_ext + +[dn] +C = IT +O = {client_full} +OU = ARGOS SOC +CN = {cn} + +[req_ext] +subjectAltName = @alt_names + +[v3_ext] +subjectAltName = @alt_names +basicConstraints = critical, CA:FALSE +keyUsage = critical, digitalSignature, keyEncipherment +extendedKeyUsage = serverAuth + +[alt_names] +{san_lines} +""" + cnf_path.write_text(cnf) + # Genero la chiave e il cert in un solo passo + run( + f"openssl req -x509 -nodes -days 3650 -newkey rsa:4096 " + f"-keyout {key_path} -out {crt_path} -config {cnf_path}" + ) + os.chmod(key_path, 0o600) + os.chmod(crt_path, 0o644) + chown(key_path) + chown(crt_path) + ssl_crt = str(crt_path) + ssl_key = str(key_path) + log(f"Cert autofirmato generato (CN={cn}, SAN: {len(san_dns)} DNS" + f"{' + 1 IP' if server_ip else ''})") + log("⚠️ ATTENZIONE: i browser segnaleranno il cert come non attendibile.") + log(" Usare solo per LAN/test. Per produzione: Let's Encrypt o cert CA.") else: _write_nginx_http(all_names) run("nginx -t && systemctl restart nginx")