# NetAdmin — Console DNS & Mail Interface d'administration DNS et Mail pour serveurs BIND9 + Postfix/Dovecot. --- ## Architecture ``` ┌─────────────────────────────────────────────────────────┐ │ Frontend React (Vite) :3000 │ │ Backend FastAPI :8000 │ │ MariaDB (base: netadmin) — données NetAdmin │ │ MariaDB (base: netadmin_mail) — données Postfix │ │ Redis mTLS broker :6380 │ │ │ │ │ dns_agent.py ←→ dns.commands/acks → BIND9 │ │ mail_agent.py ←→ mail.commands/acks → Postfix │ └─────────────────────────────────────────────────────────┘ ``` --- ## Installation ### Prérequis - Python 3.11+ - Node.js 18+ - MariaDB 10.6+ - Redis 7+ - BIND9 9.20+ - Postfix + Dovecot - Rspamd (optionnel, pour DKIM) ### Bases de données MariaDB #### Base NetAdmin (gestion interne) ```sql -- Se connecter en root MariaDB mysql -u root -p -- Créer l'utilisateur et la base CREATE DATABASE netadmin CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER 'netadmin'@'localhost' IDENTIFIED BY 'mot_de_passe_fort'; GRANT ALL PRIVILEGES ON netadmin.* TO 'netadmin'@'localhost'; FLUSH PRIVILEGES; ``` Les tables sont créées automatiquement au premier démarrage du backend. #### Base netadmin_mail (lue par Postfix/Dovecot) À créer sur le **serveur mail** : ```sql CREATE DATABASE netadmin_mail CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER 'postfix'@'localhost' IDENTIFIED BY 'mot_de_passe_fort'; GRANT ALL PRIVILEGES ON netadmin_mail.* TO 'postfix'@'localhost'; FLUSH PRIVILEGES; ``` Créer les tables manuellement : ```sql USE netadmin_mail; CREATE TABLE domain ( domain VARCHAR(253) NOT NULL, description VARCHAR(255) NOT NULL DEFAULT '', max_accounts INT NOT NULL DEFAULT 0, max_aliases INT NOT NULL DEFAULT 0, max_quota_mb INT NOT NULL DEFAULT 0, mb_quota_mb INT NOT NULL DEFAULT 0, active TINYINT(1) NOT NULL DEFAULT 1, created DATETIME NOT NULL DEFAULT NOW(), modified DATETIME NOT NULL DEFAULT NOW(), PRIMARY KEY (domain) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE mailbox ( username VARCHAR(128) NOT NULL, password VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL DEFAULT '', domain VARCHAR(253) NOT NULL, quota_mb INT NOT NULL DEFAULT 1024, active TINYINT(1) NOT NULL DEFAULT 1, created DATETIME NOT NULL DEFAULT NOW(), modified DATETIME NOT NULL DEFAULT NOW(), PRIMARY KEY (username), FOREIGN KEY (domain) REFERENCES domain(domain) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE alias ( address VARCHAR(253) NOT NULL, goto TEXT NOT NULL, domain VARCHAR(253) NOT NULL, active TINYINT(1) NOT NULL DEFAULT 1, created DATETIME NOT NULL DEFAULT NOW(), modified DATETIME NOT NULL DEFAULT NOW(), PRIMARY KEY (address), FOREIGN KEY (domain) REFERENCES domain(domain) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE sender_login_maps ( sender VARCHAR(255) NOT NULL, authorized VARCHAR(255) NOT NULL, domain VARCHAR(253) NOT NULL, PRIMARY KEY (sender, authorized) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ``` Si le backend NetAdmin tourne sur un serveur différent du serveur mail, autoriser la connexion distante : ```sql CREATE USER 'netadmin_agent'@'IP_SERVEUR_NETADMIN' IDENTIFIED BY 'mot_de_passe_fort'; GRANT ALL PRIVILEGES ON netadmin_mail.* TO 'netadmin_agent'@'IP_SERVEUR_NETADMIN'; FLUSH PRIVILEGES; ``` #### Permissions du fichier de configuration ```bash # Le fichier config.yaml doit être lisible par l'utilisateur netadmin chown root:netadmin /etc/netadmin/config.yaml chmod 640 /etc/netadmin/config.yaml chown root:netadmin /etc/netadmin chmod 750 /etc/netadmin ``` ### Backend ```bash cd backend/ python3 -m venv ../venv source ../venv/bin/activate pip install -r requirements.txt cp config.yaml /etc/netadmin/config.yaml # adapter les valeurs uvicorn main:app --host 0.0.0.0 --port 8000 ``` ### Frontend ```bash cd frontend/ npm install npm run build # production # ou npm run dev # développement :3000 ``` ### Agents ```bash # Agent DNS (sur le serveur BIND9) cd agents/ pip install -r requirements.txt cp ../backend/config.yaml /etc/netadmin/config.yaml # section dns_agent python3 dns_agent.py # Agent Mail (sur le serveur Postfix) python3 mail_agent.py ``` ### Services systemd ```bash cp agents/netadmin-dns-agent.service /etc/systemd/system/ cp agents/netadmin-mail-agent.service /etc/systemd/system/ systemctl enable --now netadmin-dns-agent netadmin-mail-agent ``` --- ## Configuration ### `backend/config.yaml` ```yaml dns: default_ns: - "ns1.example.fr." - "ns2.example.fr." default_soa_admin: "hostmaster.example.fr" dnssec_enabled: true key_dir: "/etc/bind/keys" mail_default_aliases: abuse: "postmaster@example.fr" hostmaster: "postmaster@example.fr" postmaster: "admin@example.fr" webmaster: "admin@example.fr" dns_agent: zones_dir: "/etc/bind/zones" named_conf_local: "/etc/bind/named.conf.local" rndc_cmd: "rndc" key_dir: "/etc/bind/keys" dnssec_policy: "default" mail_agent: dkim_dir: "/var/lib/rspamd/dkim" dkim_selector: "mail" ``` ### Postfix `main.cf` ```ini virtual_mailbox_domains = mysql:/etc/postfix/mysql_virtual_mailbox_domains.cf virtual_mailbox_maps = mysql:/etc/postfix/mysql_virtual_mailbox_maps.cf virtual_alias_maps = mysql:/etc/postfix/mysql_virtual_alias_maps.cf smtpd_sender_login_maps = mysql:/etc/postfix/mysql_sender_login_maps.cf smtpd_sender_restrictions = reject_sender_login_mismatch, permit ``` ### Fichiers `.cf` Postfix (pointent sur `netadmin_mail`) ```ini # mysql_virtual_mailbox_domains.cf query = SELECT domain FROM domain WHERE domain='%s' AND active=1 # mysql_virtual_mailbox_maps.cf query = SELECT CONCAT(domain,'/',SUBSTRING_INDEX(username,'@',1),'/') FROM mailbox WHERE username='%s' AND active=1 # mysql_virtual_alias_maps.cf query = SELECT goto FROM alias WHERE address='%s' AND active=1 # mysql_sender_login_maps.cf query = SELECT authorized FROM sender_login_maps WHERE sender='%s' ``` --- ## Migration depuis PostfixAdmin ```bash # Aperçu sans modification python3 migrate_postfixadmin.py --dry-run \ --user root --password xxx \ --source-db postfix --target-db netadmin_mail # Migration réelle python3 migrate_postfixadmin.py \ --user root --password xxx \ --source-db postfix --target-db netadmin_mail ``` Le script migre : domaines, boîtes aux lettres (SHA512-CRYPT conservé), alias. Les mots de passe `$1$` (MD5) ou `$2$` (bcrypt) sont marqués `{MIGRATION_REQUIRED}` et le compte est désactivé — reset admin requis. ### Scripts SQL de correction ```bash # Corriger les alias avec source en partie locale seulement mysql netadmin -e "UPDATE aliases SET source = CONCAT(source, '@', domain) WHERE source NOT LIKE '%@%';" # Corriger les double domaines dans mailbox (si migration partielle) mysql netadmin_mail -e " UPDATE mailbox SET username = CONCAT(SUBSTRING_INDEX(username,'@',1),'@',SUBSTRING_INDEX(username,'@',-1)) WHERE username LIKE '%@%@%';" ``` --- ## Fonctionnalités ### DNS - Gestion des zones BIND9 (création via Domaines uniquement) - Enregistrements : A, AAAA, CNAME, MX, TXT, NS, PTR, SRV, CAA, TLSA, DS - DNSSEC par zone (activation/désactivation, récupération des clés DS) - NS par défaut configurables, email SOA admin par défaut - Archivage automatique des clés DNSSEC dans `key_dir/old/` ### Mail - Gestion des domaines mail avec quotas (global + par BAL) - Boîtes aux lettres avec quota individuel et nom affiché - Alias avec activation/désactivation - DKIM via Rspamd (`rspamadm dkim_keygen`) - Alias RFC obligatoires créés automatiquement (abuse, postmaster, hostmaster, webmaster) - Sender login maps (prochainement) - Mots de passe hashés en `{SHA512-CRYPT}` via `passlib` ### Administration - Authentification locale + OpenID Connect (Keycloak) - TOTP (2FA) par compte, obligatoire ou optionnel - RBAC : global_admin, dns_admin, mail_admin, domain_admin, dns_zone_admin - Préférences utilisateur (thème clair/sombre) persistées en BDD - Audit log complet - Notifications email à la connexion ### Interface - Thème sombre / clair - Création de domaine unifiée (DNS + Mail) - Validation des enregistrements DNS (FQDN, IPv4, IPv6) - Affichage des enregistrements DS détaillés (Key Tag, Algorithme, Digest) - Interface entièrement en français --- ## Sécurité ### Génération du session_secret Le `session_secret` dans `config.yaml` est utilisé pour signer les tokens de session. Il doit être une clé aléatoire forte, unique par installation : ```bash # Avec Python (recommandé) python3 -c "import secrets; print(secrets.token_hex(32))" # Avec OpenSSL openssl rand -hex 32 ``` Les deux génèrent une clé de 64 caractères hexadécimaux (256 bits). À renseigner dans `config.yaml` : ```yaml auth: session_secret: "coller_la_clé_générée_ici" ``` ⚠ Ne jamais committer cette valeur dans un dépôt Git. Utiliser une variable d'environnement ou un gestionnaire de secrets en production. ### Certificats mTLS Redis ```bash cd agents/ bash gen_certs.sh # génère CA + certificats agents ``` Copier les certificats dans `/etc/netadmin/certs/`. ### Premier compte admin Au premier démarrage, NetAdmin crée automatiquement : - Utilisateur : `admin` - Mot de passe : `admin` - **Changer immédiatement après connexion.** --- ## Structure des fichiers ``` netadmin/ ├── backend/ │ ├── main.py # FastAPI app │ ├── config.py # Dataclasses de configuration │ ├── config.yaml # Configuration principale │ ├── db.py # Connexion MariaDB (netadmin) │ ├── broker.py # File Redis + pending_actions │ ├── audit.py # Audit log │ ├── notify.py # Notifications email │ ├── requirements.txt │ └── routers/ │ ├── auth.py # Auth locale + OIDC + TOTP + RBAC │ ├── dns.py # Zones + enregistrements + DNSSEC │ └── mail.py # Domaines + comptes + alias + DKIM ├── agents/ │ ├── dns_agent.py # Agent BIND9 │ ├── mail_agent.py # Agent Postfix/Dovecot/Rspamd │ ├── requirements.txt │ ├── gen_certs.sh # Génération certificats mTLS │ ├── netadmin-dns-agent.service │ └── netadmin-mail-agent.service ├── frontend/ │ ├── src/ │ │ ├── App.jsx # Routing + sidebar + auth │ │ ├── App.css # Thème sombre/clair │ │ ├── main.jsx # Point d'entrée + polices │ │ └── components/ │ │ ├── LoginPage.jsx │ │ ├── DomainsManager.jsx # DNS + Mail par domaine │ │ ├── DNSManager.jsx # Enregistrements + DNSSEC │ │ ├── MailManager.jsx # Comptes + alias │ │ ├── UsersManager.jsx # Utilisateurs + rôles │ │ ├── UserProfile.jsx # Mon compte + 2FA + thème │ │ ├── AuditLog.jsx │ │ ├── SyncDashboard.jsx │ │ └── SyncToast.jsx │ ├── package.json │ └── vite.config.js ├── migrate_postfixadmin.py # Migration depuis PostfixAdmin ├── fix_alias_source.sql # Correction alias partiels ├── fix_double_domain.sql # Correction double domaine └── README.md ``` --- ## Bases de données ### `netadmin` (gestion NetAdmin) - `users`, `user_roles`, `sessions`, `user_preferences` - `zones`, `records` (DNS) - `domains`, `accounts`, `aliases` (Mail NetAdmin) - `pending_actions`, `audit_log`, `sync_history` ### `netadmin_mail` (lue par Postfix/Dovecot) - `domain` — domaines hébergés - `mailbox` — boîtes aux lettres (username = email complet) - `alias` — alias et redirections (inclut self-aliases pour virtual_alias_maps) - `sender_login_maps` — autorisations d'envoi