Agent DNS - load_config() lit maintenant la section `redis` du config.yaml (host, port, password, ssl, ssl_ca_cert, ssl_certfile, ssl_keyfile) → l'agent ne tombait plus sur localhost:6379 par défaut - Suppression de retry_on_timeout (déprécié redis-py 6.0) - Suppression de socket_keepalive_options (clés string invalides) - int() forcé sur port et db dans run() pour éviter TypeError - Traceback complet sur fatal error - get_state: relativize=False → dnspython conserve les FQDN complets - get_state: parse les enregistrements "; [DISABLED]" pour les inclure avec active=False dans le state retourné - _fmt_value: ne ajoute plus le point final sur les noms relatifs (srvweb → reste srvweb, srvweb.infolix.fr → srvweb.infolix.fr.) - save_zone_raw: named-checkzone + snapshot (même logique qu'apply_zone) - gen_certs.sh: REDIS_HOST obligatoire, détection IP vs FQDN pour le SAN Backend DNS - _sync_zone_from_state: normalise les noms FQDN → court avant _stable_id (mail.infolix.fr. → mail pour correspondre à ce qui est en BDD) - _sync_zone_from_state: active=%s au lieu de COALESCE(active,1) → les enregistrements désactivés importés depuis le fichier de zone sont correctement marqués active=0 en BDD Frontend - App.jsx: VITE_API_BASE prioritaire sur localStorage - validateRecord: accepte les noms relatifs sans point pour CNAME/MX/NS
408 lines
12 KiB
Markdown
408 lines
12 KiB
Markdown
# 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
|
|
|