Odoo Security Hardening: Authentication, Access Rights, and Encryption

Comprehensive Odoo 19 security hardening guide covering authentication, access rights, record rules, encryption, network security, and audit logging for enterprise deployments.

E
ECOSIRE Research and Development Team
|19 mars 202610 min de lecture2.2k Mots|

Renforcement de la sécurité Odoo : authentification, droits d'accès et cryptage

Les systèmes ERP d'entreprise sont des cibles de grande valeur pour les cyberattaques. Une instance Odoo contenant les informations personnelles des clients, les dossiers financiers, les contrats de fournisseurs et les données des employés représente une surface d'attaque importante qui nécessite des contrôles de sécurité délibérés et à plusieurs niveaux.

Ce guide couvre le processus complet de renforcement de la sécurité pour Odoo 19 Enterprise : du renforcement de l'authentification et de la conception des droits d'accès au renforcement du réseau, au cryptage, à la journalisation d'audit et à la préparation à la réponse aux incidents.

Points clés à retenir

  • Les configurations Odoo par défaut ne sont pas prêtes pour la production du point de vue de la sécurité
  • L'authentification à deux facteurs (2FA) devrait être obligatoire pour tous les utilisateurs disposant d'un accès sensible
  • Les droits d'accès suivent le principe du moindre privilège : les utilisateurs n'obtiennent que ce dont ils ont besoin
  • Les règles d'enregistrement fournissent une sécurité au niveau des lignes pour appliquer l'isolation des données
  • Toutes les communications interservices doivent utiliser TLS ; jamais HTTP en production
  • Les informations d'identification de la base de données doivent être alternées régulièrement et jamais codées en dur
  • Les journaux d'audit doivent être infalsifiables et conservés pour les exigences de conformité
  • Les correctifs de sécurité doivent être appliqués dans les 48 heures suivant les annonces d'Odoo SA

Renforcement de l'authentification

Politique de mot de passe

Odoo 19 prend en charge les politiques de mot de passe configurables sous Paramètres → Utilisateurs et entreprises → Politique de réinitialisation du mot de passe.

Paramètres recommandés :

  • Longueur minimale : 12 caractères
  • Exiger des majuscules, des minuscules, des chiffres et des caractères spéciaux
  • Expiration du mot de passe : 90 jours
  • Empêcher la réutilisation des 12 derniers mots de passe
  • Verrouillage du compte après 5 tentatives infructueuses (verrouillage de 15 minutes)
# Custom password validator in a security module
from odoo import api, models
from odoo.exceptions import UserError
import re

class ResUsers(models.Model):
    _inherit = 'res.users'

    @api.constrains('password')
    def _check_password_strength(self):
        for user in self:
            if user.password:
                pwd = user.password
                if len(pwd) < 12:
                    raise UserError("Password must be at least 12 characters.")
                if not re.search(r'[A-Z]', pwd):
                    raise UserError("Password must contain an uppercase letter.")
                if not re.search(r'[a-z]', pwd):
                    raise UserError("Password must contain a lowercase letter.")
                if not re.search(r'\d', pwd):
                    raise UserError("Password must contain a number.")
                if not re.search(r'[!@#$%^&*(),.?":{}|<>]', pwd):
                    raise UserError("Password must contain a special character.")

Authentification à deux facteurs (2FA)

Activez 2FA sous Paramètres → Autorisations → Authentification à deux facteurs.

Options de configuration :

  • Facultatif : les utilisateurs choisissent d'activer ou non la 2FA.
  • Obligatoire pour des groupes spécifiques : postuler aux administrateurs et aux comptables
  • Obligatoire pour tous les utilisateurs : Sécurité maximale

Pour les déploiements en entreprise, exigez 2FA pour :

  • Comptes administrateur (base.group_system)
  • Utilisateurs financiers (account.group_account_manager)
  • Responsables RH avec accès à la paie
  • Tous les utilisateurs ayant accès à la clé API

Intégration OAuth et SSO

Pour les organisations disposant de fournisseurs d'identité existants, configurez Odoo pour utiliser SAML 2.0 ou OAuth 2.0 :

# In odoo.conf — configure OAuth
oauth_providers = [
    {
        'name': 'Your SSO Provider',
        'client_id': 'odoo-client-id',
        'auth_endpoint': 'https://sso.company.com/auth',
        'validation_endpoint': 'https://sso.company.com/userinfo',
        'scope': 'openid email profile',
    }
]

Cela centralise l'authentification dans votre fournisseur d'identité, permettant des fonctionnalités telles que l'authentification unique, la MFA centralisée et la suppression automatique des comptes lorsque les employés quittent.

Sécurité des clés API

# Restrict API key creation to administrators only
# In custom security module:

# ir.rule to prevent non-admin users from creating API keys
<record id="rule_api_key_admin_only" model="ir.rule">
    <field name="name">API Keys: Admin Only</field>
    <field name="model_id" ref="base.model_auth_api_key"/>
    <field name="domain_force">[('create_uid', '=', user.id)]</field>
    <field name="groups" eval="[(4, ref('base.group_user'))]"/>
    <field name="perm_create" eval="False"/>
    <field name="perm_unlink" eval="False"/>
</record>

Appliquez une politique : les clés API expirent après 90 jours, sont liées à des comptes de service dédiés avec des autorisations minimales et sont alternées en cas de compromission suspectée.


Architecture des droits d'accès

Group Hierarchy Design

Le contrôle d'accès d'Odoo est basé sur des groupes. Concevez une hiérarchie de groupe qui reflète votre structure organisationnelle :

base.group_user (Internal User)
├── sales.group_sale_salesman (Salesperson)
│   └── sales.group_sale_manager (Sales Manager)
├── account.group_account_user (Accounting User)
│   └── account.group_account_manager (Accounting Manager)
├── stock.group_stock_user (Inventory User)
│   └── stock.group_stock_manager (Inventory Manager)
└── base.group_system (Administrator)

Principe du moindre privilège : chaque utilisateur doit disposer de l'accès minimum requis pour effectuer son travail. Cela limite le rayon d’action des comptes compromis.

Listes de contrôle d'accès (ACL)

Les entrées ACL dans ir.model.access définissent les autorisations CRUD au niveau du modèle :

id,name,model_id,group_id,perm_read,perm_write,perm_create,perm_unlink
# Salesperson: can read/write own orders, cannot delete
access_sale_order_salesman,sale.order.salesman,sale.model_sale_order,sales.group_sale_salesman,1,1,1,0
# Manager: full CRUD
access_sale_order_manager,sale.order.manager,sale.model_sale_order,sales.group_sale_manager,1,1,1,1
# Accounting user: read-only on sales orders
access_sale_order_accountant,sale.order.accountant,sale.model_sale_order,account.group_account_user,1,0,0,0

Règles d'enregistrement (sécurité au niveau des lignes)

Filtre de règles d'enregistrement qui permet à un utilisateur de voir les enregistrements dans un modèle :

<!-- Salesperson sees only their own opportunities -->
<record id="rule_crm_salesman" model="ir.rule">
    <field name="name">CRM: Own Leads</field>
    <field name="model_id" ref="crm.model_crm_lead"/>
    <field name="domain_force">
        ['|', ('user_id', '=', user.id), ('user_id', '=', False)]
    </field>
    <field name="groups" eval="[(4, ref('sales.group_sale_salesman'))]"/>
</record>

<!-- Multi-company isolation: users see only their company's records -->
<record id="rule_sale_order_company" model="ir.rule">
    <field name="name">Sale Order: Company</field>
    <field name="model_id" ref="sale.model_sale_order"/>
    <field name="domain_force">
        [('company_id', 'in', company_ids)]
    </field>
    <field name="groups" eval="[(4, ref('base.group_user'))]"/>
</record>

Avertissement relatif aux performances : des règles d'enregistrement complexes comportant de nombreux opérateurs search() ou child_of peuvent ralentir considérablement l'affichage des listes. Testez toutes les règles d'enregistrement sur des ensembles de données volumineux avant de les déployer en production.


Sécurité du réseau

Application de TLS/HTTPS

N'exécutez jamais Odoo sur HTTP simple en production. Tout le trafic doit être crypté.

Configuration Nginx TLS :

server {
    listen 80;
    server_name your-odoo.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name your-odoo.com;

    ssl_certificate /etc/ssl/certs/your-odoo.com.pem;
    ssl_certificate_key /etc/ssl/private/your-odoo.com.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:
                ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;
    ssl_session_timeout 1d;
    ssl_session_cache shared:MozSSL:10m;
    ssl_session_tickets off;

    # HSTS: 2 years, include subdomains
    add_header Strict-Transport-Security
        "max-age=63072000; includeSubDomains; preload" always;

    # Security headers
    add_header X-Frame-Options DENY always;
    add_header X-Content-Type-Options nosniff always;
    add_header Referrer-Policy strict-origin-when-cross-origin always;
    add_header Permissions-Policy
        "camera=(), microphone=(), geolocation=()" always;
}

Configuration du pare-feu

# UFW firewall rules for Odoo server
ufw default deny incoming
ufw default allow outgoing

# Allow SSH from management IP only
ufw allow from 10.0.1.100 to any port 22

# Allow HTTPS from anywhere
ufw allow 443/tcp

# Allow HTTP (for Let's Encrypt renewal)
ufw allow 80/tcp

# Allow PostgreSQL only from Odoo server (if separate DB server)
ufw allow from 10.0.1.10 to any port 5432

# Block direct access to Odoo port (must go through Nginx)
ufw deny 8069/tcp
ufw deny 8072/tcp

ufw enable

Limitation du débit

Configurez la limitation de débit dans Nginx pour empêcher les attaques par force brute :

# Rate limiting zones
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
limit_req_zone $binary_remote_addr zone=api:10m rate=60r/m;

server {
    # Apply rate limiting to login endpoint
    location /web/login {
        limit_req zone=login burst=3 nodelay;
        limit_req_status 429;
        proxy_pass http://odoo;
    }

    # Apply rate limiting to API
    location /web/dataset/ {
        limit_req zone=api burst=20 nodelay;
        proxy_pass http://odoo;
    }
}

Chiffrement des données

Chiffrement au niveau de la base de données

Pour les données très sensibles, les champs Odoo peuvent être chiffrés au repos :

# Custom encrypted field using Fernet symmetric encryption
from cryptography.fernet import Fernet
from odoo import api, fields, models
import base64, os

class EncryptedField(models.Model):
    _name = 'my.sensitive.model'

    _fernet_key = os.environ.get('ODOO_FIELD_ENCRYPTION_KEY')

    ssn_encrypted = fields.Char(string='SSN (Encrypted)', groups='hr.group_hr_user')
    ssn_display = fields.Char(
        string='SSN', compute='_compute_ssn_display',
        inverse='_inverse_ssn_display'
    )

    def _get_fernet(self):
        return Fernet(self._fernet_key.encode())

    def _compute_ssn_display(self):
        f = self._get_fernet()
        for record in self:
            if record.ssn_encrypted:
                decrypted = f.decrypt(record.ssn_encrypted.encode()).decode()
                record.ssn_display = f"***-**-{decrypted[-4:]}"
            else:
                record.ssn_display = False

    def _inverse_ssn_display(self):
        f = self._get_fernet()
        for record in self:
            if record.ssn_display:
                encrypted = f.encrypt(record.ssn_display.encode()).decode()
                record.ssn_encrypted = encrypted

Sécurité des variables d'environnement

Ne stockez jamais de secrets dans odoo.conf en texte brut. Utilisez des variables d'environnement :

# /etc/systemd/system/odoo.service
[Service]
Environment="ODOO_DB_PASSWORD=your_secure_password"
Environment="ODOO_ADMIN_PASSWD=your_master_password"
Environment="ODOO_FIELD_ENCRYPTION_KEY=your_fernet_key"
EnvironmentFile=/etc/odoo/secrets.env
# odoo.conf — reference env vars
[options]
db_password = ${ODOO_DB_PASSWORD}
admin_passwd = ${ODOO_ADMIN_PASSWD}

Journal d'audit

La journalisation d'audit intégrée d'Odoo suit toutes les modifications du modèle. Activez-le pour les modèles sensibles :

# Enable audit logging via the Audit Trail module
# Or implement custom logging:

class AuditableMixin(models.AbstractModel):
    _name = 'audit.mixin'

    def write(self, vals):
        # Log what changed before the write
        for record in self:
            old_vals = {f: record[f] for f in vals if f in record._fields}
            self.env['audit.log'].create({
                'model_name': self._name,
                'record_id': record.id,
                'user_id': self.env.uid,
                'action': 'write',
                'old_values': str(old_vals),
                'new_values': str(vals),
                'ip_address': self.env.context.get('remote_addr'),
            })
        return super().write(vals)

    def unlink(self):
        for record in self:
            self.env['audit.log'].create({
                'model_name': self._name,
                'record_id': record.id,
                'user_id': self.env.uid,
                'action': 'unlink',
                'old_values': str({f: record[f] for f in ['name', 'id']}),
            })
        return super().unlink()

Modèles critiques en matière de conformité à auditer :

  • res.users (création d'utilisateur, modifications d'autorisation)
  • account.move (modifications de facture)
  • hr.payslip (modifications de paie)
  • res.partner (modifications des informations personnelles du client/fournisseur)
  • ir.model.access, ir.rule (modifications d'autorisation)
  • ir.config_parameter (modifications de la configuration du système)

Gestion des correctifs de sécurité

Abonnez-vous aux avis de sécurité Odoo :

Odoo SA publie des avis de sécurité à https://github.com/odoo/odoo/security/advisories. Abonnez-vous aux notifications GitHub pour ce référentiel.

Processus de demande de correctif :

# Check current Odoo version
python3 odoo-bin --version

# Pull latest security patches (within a minor version)
cd /opt/odoo
git fetch origin
git log origin/19.0..HEAD --oneline  # See what's changed

# Apply patches on staging first
git merge origin/19.0
python3 odoo-bin -d staging_db -u all --stop-after-init

# Test critical workflows on staging
# If all clear, apply to production during maintenance window

Cible : patch dans les 48 heures suivant un avis de gravité critique ou élevée. Sévérité moyenne : dans un délai d'une semaine. Faible gravité : prochaine fenêtre de maintenance planifiée.


Questions fréquemment posées

Comment puis-je vérifier qui a supprimé un enregistrement dans Odoo ?

Odoo n'enregistre pas les suppressions par défaut. Installez le module auditlog d'Odoo Community Association (OCA) ou implémentez un remplacement unlink() personnalisé dans vos modèles sensibles. Le module OCA auditlog enregistre les opérations de création, d'écriture et de dissociation à un modèle auditlog.log avec suivi des modifications au niveau de l'utilisateur, de l'horodatage et du champ.

Puis-je restreindre l'accès à Odoo par adresse IP ?

Pas nativement dans Odoo. Implémentez la liste blanche IP au niveau de Nginx ou du pare-feu. Pour un accès administratif, exigez une connexion VPN comme condition préalable. Le ir.config_parameter d'Odoo prend en charge une restriction web.base.url, mais le véritable contrôle d'accès basé sur IP appartient à la couche réseau.

What is the difference between access rights (ACL) and record rules?

Les droits d'accès (ACL, stockés dans ir.model.access) contrôlent si un groupe d'utilisateurs peut lire, écrire, créer ou supprimer n'importe quel enregistrement d'un modèle — il s'agit d'un contrôle au niveau du modèle. Les règles d'enregistrement filtrent les enregistrements spécifiques auxquels un utilisateur peut accéder dans un modèle à l'aide d'expressions de domaine : il s'agit d'un contrôle au niveau des lignes. Les deux fonctionnent ensemble : un utilisateur a besoin d'une autorisation de lecture ACL ET doit passer le filtre de domaine de règle d'enregistrement pour voir un enregistrement.

Comment dois-je gérer le mot de passe principal Odoo (admin_passwd) ?

Le admin_passwd dans odoo.conf contrôle l'accès à l'interface de gestion de base de données à /web/database/manager. En production : définissez-la sur une longue chaîne aléatoire (plus de 32 caractères), stockez-la dans un gestionnaire de mots de passe, ne la partagez jamais et envisagez de désactiver entièrement le gestionnaire de base de données avec list_db = False dans odoo.conf si vous gérez la base de données via un accès direct à PostgreSQL.

Dois-je exécuter Odoo en tant que root ?

Jamais. Créez un utilisateur système odoo dédié sans accès au shell et avec des autorisations limitées sur le système de fichiers. L'utilisateur d'Odoo a besoin d'un accès en lecture à la base de code Odoo et d'un accès en écriture uniquement aux répertoires de stockage de fichiers et de journaux. Exécutez le service systemd en tant qu'utilisateur. L'exécution en tant que root viole le principe du moindre privilège et maximise les dommages causés par toute vulnérabilité d'exécution de code.


Prochaines étapes

Le renforcement de la sécurité n'est pas une tâche ponctuelle : c'est une pratique continue. De nouvelles vulnérabilités apparaissent, les exigences d’accès des utilisateurs changent et les cadres de conformité évoluent. Un déploiement Odoo sécurisé nécessite des examens de sécurité réguliers, une discipline de gestion des correctifs et des audits des droits d'accès.

ECOSIRE fournit des évaluations de renforcement de la sécurité Odoo qui identifient les erreurs de configuration, les autorisations excessives, les contrôles manquants et les lacunes de conformité. Notre équipe de sécurité a de l'expérience avec les exigences ISO 27001, SOC 2 et RGPD dans les environnements Odoo.

Demander une évaluation de sécurité Odoo auprès d'ECOSIRE →

Nous examinerons votre configuration actuelle par rapport aux normes de l'industrie et vous fournirons un plan de correction hiérarchisé avec une assistance à la mise en œuvre.

E

Rédigé par

ECOSIRE Research and Development Team

Création de produits numériques de niveau entreprise chez ECOSIRE. Partage d'analyses sur les intégrations Odoo, l'automatisation e-commerce et les solutions d'entreprise propulsées par l'IA.

Discutez sur WhatsApp