Introduction

Ok, je le reconnais, le titre de cet article est pourri ! Mais pourtant, il décrit précisément le problème que j'ai résolu il y a peu.

Je ne sais pas pour vous mais, à mon boulot, pour accéder à Internet, on utilise un serveur mandataire. C'est en général le cas dans les endroits où on a besoin de partager un accès Internet à plusieurs. Le serveur mandataire fait office de cache et il permet également de filtrer les accès et surtout de savoir qui fait quoi lorsqu'on le couple à une authentification. C'est ce schéma qui est appliqué là où je travaille. Il faut donc montrer patte blanche pour accéder à Internet et indiquer le bon login/mot de passe.

L'avantage premier c'est qu'on bénéficie d'une certaine sécurité car tout le flux Internet de la boîte passe par des choses connues et administrées. L'inconvénient majeur est lié à toute la floppée d'outils qui ont besoin de se connecter à Internet directement. En règle générale, l'implémentation de la gestion des serveurs mandataires est assez bien gérée dans les navigateurs web. Mais il en est tout autrement pour des choses aussi simples que curl,wget ou encore ne serait-ce que apt-get.

La source du problème est généralement liée au fait qu'il existe toujours un embryon de gestion des proxy dans ces outils mais que cette implémentation ne va pas assez loin. En effet, il existe plusieurs méthodes pour authentifier un utilisateur sur un serveur mandataire. Étant donné que nous sommes dans un domaine de travail qui est proche d'HTTP, les méthodes d'authentification des serveurs mandataires sont les mêmes que celles des serveurs HTTP. On trouve ainsi:

  • méthode Basic: le couple login/mot de passe est balancé en clair (en base64 certes).
  • méthode Digest: le couple login/mot de passe est chiffré en mode défi-réponse avec le serveur.
  • méthode NTLM: un mode d'authentification propre à MS-Windows NT et suivants.

Dans la méthode Digest, le login/mot de passe ne circule pas en clair mais est chiffré en fonction de ce que le serveur demande. Cette méthode est plus complexe car, en plus de toute l'algorithmique liée au chiffrement, il faut gérer deux requêtes HTTP vers le serveur. La première sert d'introduction, la seconde permet de répondre au défi du serveur (renvoyé à l'aide d'un code HTTP 407). Cette complexité fait que, bien souvent, les développeurs se contentent de gérer l'authentification en mode Basic (quand la gestion de l'authentification existe !).

Une conséquence majeure c'est qu'apt-get ne fonctionne plus car il ne gère que l'authentification en mode Basic. C'est un vrai problème lorsqu'on se retrouve derrière un tel serveur mandataire pour faire des mises à jour Debian. Un autre problème que je rencontre, c'est dans l'utilisation de pip (Python): impossible de télécharger le moindre paquet avec cet outil. Il fallait donc que je trouve une vraie solution pour que l'authentification Digest ne soit plus un problème pour ces outils.

Comment régler notre problème ?

Pour régler mon problème, je me suis dit que je devais simplement ajouter un intermédiaire entre le serveur mandataire et les outils. Cet intermédiaire est finalement un serveur mandataire lui aussi. En effet, son rôle consiste à récupérer des requêtes HTTP des clients, de les exposer vers le serveur mandataire Digest, récupérer sa réponse et la rebalancer au client. Cette description est justement celle d'un serveur mandataire minimaliste qui joue le rôle de "rustine" entre le client et le vrai serveur mandataire. En voici un petit schéma en Ascii (réalisé avec AsciiFlow):

.------------.
|  Clients   |                       .-------------.                              .-------------------------.
|------------|    (5) Réponse HTTP   | "Rustine"   |       (4) Réponse HTTP       |       Mandataire        |
| apt-get    |<----------------------|             |<-----------------------------| Authentification Digest |
| wget       |                       |             |                              |                         |
| ...        |---------------------->|             |----------------------------->|                         |
|            |   (1) Accès direct    '-------------' (2) Authentification Digest  '-------------------------'
'------------'                                                                              |
                                                                                            |(3) Requête HTTP
                                                                                            |
                                                                                            v
                                                                                       .-,(  ),-.    
                                                                                    .-(          )-. 
                                                                                   (    internet    )
                                                                                    '-(          ).-'
                                                                                        '-.( ).-'    

Avant de me mettre à coder, je me suis dit qu'un tel logiciel devait déjà exister et qu'il serait plus efficace de le trouver plutôt que d'essayer de développer quelque-chose. J'ai donc consulté Internet pour trouver des serveurs mandataires légers et faciles à configurer. J'ai fini par trouver des choses bien foutues comme Polipo ou Privoxy qui s'approchent assez de ce que je souhaite mettre en place. Mais après avoir parcouru leur documentation, je me suis rendu compte qu'aucun ne prenait en compte l'authentification Digest pour les serveurs mandataires parents. Comme d'habitude, le mode Digest est souvent peu implémenté.

Je savais pourtant que cURL gérait très bien ce type de requêtes puisque j'étais capable de récupérer des fichiers directement grâce à quelques éléments de configuration. Sachant que j'ai des notions de Python et que mes souvenirs m'indiquaient qu'il y avait une implémentation de serveur HTTP dans la bibliothèque standarde de Python, je me suis mis à essayer de lier les deux.

J'ai donc réalisé un bout de code qui utilise l'implémentation Python de cURL (pycurl) pour faire la requête vers le serveur mandataire qui demande une authentification Digest. L'autre bout de code s'occupe de balancer le résultat de pycurl vers le client initial. Bien sûr, vu le temps imparti (3h), l'implémentation est très crade avec plein de trucs en dur mais elle a le mérite de fonctionner.

Le code

Voici le code Python (version 2) qui permet de faire ça. Vous aurez besoin du paquet python-pycurl pour qu'il fonctionne. Je me suis fait avoir avec la gestion du code 407: pas mal d'applications qui reçoivent un code 407 s'arrêtent directement.

#!/usr/bin/python
# -*- coding: utf-8 -*-
# a truly minimal HTTP proxy
# with Digest Auth backend

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>

import SocketServer
import SimpleHTTPServer
import pycurl
import cStringIO
import re

LISTEN_PORT = 8080
DIGEST_PROXY_URL="http://mon.digest.proxy.example.com"
DIGEST_PROXY_PORT = 8080
USERNAME= "moi"
PASSWORD= "mon_mot_de_passe"

class Proxy(SimpleHTTPServer.SimpleHTTPRequestHandler):
    def do_GET(self):
        headers=[]
        # On récupère la requête
        print "Requête: "+self.command+" "+self.path

        for f in self.headers:
            headers.append(str(f)+": "+str(self.headers.getheaders(str(f))[0]))
        #print headers

        # Quelques objets dont nous aurons besoin plus tard
        buf = cStringIO.StringIO()
        answer = cStringIO.StringIO()

        # consutrction de la requête CURL
        c = pycurl.Curl()
        c.setopt(c.URL, self.path)
        if len(headers)>0:
            c.setopt(c.HTTPHEADER, headers)
        c.setopt(c.HEADER, 1)
        c.setopt(c.PROXY, DIGEST_PROXY_URL)
        c.setopt(c.PROXYPORT, DIGEST_PROXY_PORT)
        c.setopt(c.HTTP_VERSION, c.CURL_HTTP_VERSION_1_1)
        c.setopt(c.PROXYUSERPWD, USERNAME+':'+PASSWORD)
        c.setopt(c.PROXYAUTH, pycurl.HTTPAUTH_DIGEST)
        c.setopt(c.WRITEFUNCTION, buf.write)
        c.setopt(c.CONNECTTIMEOUT, 30)
        c.setopt(c.IPRESOLVE, c.IPRESOLVE_V4)
        c.setopt(c.TIMEOUT, 80)
        c.perform()

        # Pour virer les erreurs 407 et ne garder qu'à partir de codes HTTP différents:  
        #print buf.getvalue()
        buf.seek(0)
        send = False
        for line in buf:
            if re.match('^HTTP/1.[10] [0-9]{2}', line):
                send = True
            if send :
                answer.write(line)

        answer.seek(0)
        #self.copyfile(urllib.urlopen(self.path), self.wfile) 
        self.copyfile(answer,self.wfile)
        answer.close()
        buf.close()
        c.close()

    def do_POST(self):
        '''Gestion des requêtes POST'''
        post_body=False
        headers=[]
        print "Requête POST: "+self.path

        # Gestion des formulaires POST
        if self.headers.getheaders('content-length'):
            content_len = int(self.headers.getheaders('content-length')[0])
            post_body = self.rfile.read(content_len)
        else:
            headers.append('content-length: 0')

        for f in self.headers:
            headers.append(str(f)+": "+str(self.headers.getheaders(str(f))[0]))
        print headers

        # Quelques objets dont nous aurons besoin plus tard
        buf = cStringIO.StringIO()
        answer = cStringIO.StringIO()

        # Construction de la requête
        c = pycurl.Curl()
        c.setopt(c.URL, self.path)
        c.setopt(c.HEADER, 1)
        c.setopt(c.POST, 1)
        if len(headers)>0:
            print "Headers"
            c.setopt(c.HTTPHEADER, headers)
        if post_body:
            print "post_body="+post_body
            c.setopt(c.POSTFIELDS, post_body)
        c.setopt(c.PROXY, DIGEST_PROXY_URL)
        c.setopt(c.PROXYPORT, DIGEST_PROXY_PORT)
        c.setopt(c.HTTP_VERSION, c.CURL_HTTP_VERSION_1_1)
        c.setopt(c.PROXYUSERPWD, USERNAME+':'+PASSWORD)
        c.setopt(c.PROXYAUTH, pycurl.HTTPAUTH_DIGEST)
        c.setopt(c.WRITEFUNCTION, buf.write)
        c.setopt(c.CONNECTTIMEOUT, 30)
        c.setopt(c.IPRESOLVE, c.IPRESOLVE_V4)
        c.setopt(c.TIMEOUT, 80)
        c.perform()

        #print buf.getvalue()
        buf.seek(0)
        send = False
        for line in buf:
            if re.match('^HTTP/1.[10] [0-9]{2}', line):
                send = True
            if send :
                answer.write(line)

        answer.seek(0)
        #self.copyfile(urllib.urlopen(self.path), self.wfile) 
        self.copyfile(answer,self.wfile)
        answer.close()
        buf.close()
        c.close()


    def do_PUT(self):
        post_body=False
        content_len=False
        headers=[]
        print "Requête PUT: "+self.path

        # Gestion des formulaires P
        if self.headers.getheaders('content-length'):
            content_len = int(self.headers.getheaders('content-length')[0])
        #    post_body = self.rfile.read(content_len)
        #else:
        #    headers.append('content-length: 0')

        for f in self.headers:
            headers.append(str(f)+": "+str(self.headers.getheaders(str(f))[0]))

        # Quelques objets dont nous aurons besoin plus tard
        buf = cStringIO.StringIO()
        answer = cStringIO.StringIO()

        # Construction de la requête
        c = pycurl.Curl()
        c.setopt(c.URL, self.path)
        c.setopt(c.HEADER, 1)
        c.setopt(c.UPLOAD, 1)
        if len(headers)>0:
            print headers
            c.setopt(c.HTTPHEADER, headers)
        c.setopt(c.READFUNCTION, self.rfile.read)
        if content_len:
            print "Content-Length:"+str(content_len)
            c.setopt(c.INFILESIZE, content_len)
        c.setopt(c.PROXY, DIGEST_PROXY_URL)
        c.setopt(c.PROXYPORT, DIGEST_PROXY_PORT)
        c.setopt(c.HTTP_VERSION, c.CURL_HTTP_VERSION_1_1)
        c.setopt(c.PROXYUSERPWD, USERNAME+':'+PASSWORD)
        c.setopt(c.PROXYAUTH, pycurl.HTTPAUTH_DIGEST)
        c.setopt(c.WRITEFUNCTION, buf.write)
        c.setopt(c.CONNECTTIMEOUT, 30)
        c.setopt(c.IPRESOLVE, c.IPRESOLVE_V4)
        c.setopt(c.TIMEOUT, 80)
        c.perform()

        print buf.getvalue()
        buf.seek(0)
        send = False
        for line in buf:
            if re.match('^HTTP/1.[10] [0-9]{2}', line):
                send = True
            if send :
                answer.write(line)

        answer.seek(0)
        #self.copyfile(urllib.urlopen(self.path), self.wfile) 
        self.copyfile(answer,self.wfile)
        answer.close()
        buf.close()
        c.close()


#httpd = SocketServer.ForkingTCPServer(('', PORT), Proxy)
httpd = SocketServer.TCPServer(('', LISTEN_PORT), Proxy)
print "serving at port", LISTEN_PORT
httpd.serve_forever()

Conclusion

Le code ci-dessus fonctionne à peu près correctement. Je suis sûr qu'il serait fortement améliorable. Par exemple, il ne gère pas les connexions TLS ce qui peut se révéler limite parfois. Néanmoins, il me permet de pouvoir légitimement mettre à jour une distribution GNU/Linux ou de faire fonctionner des outils qui ne savent parler qu'à des proxy sans authentification ou avec une authentification basique.

J'avais déjà identifié ce problème il y a près de dix ans. Force est de constater qu'en 2013, l'authentification Digest dans les serveurs mandataires n'a toujours pas pris au niveau de l'implémentation des clients. C'est un problème important car ce mode d'authentification est le seul qui soit à peu près sécurisé et qui empêche la capture de mots de passe sur le réseau ! Même si je conçois bien que c'est plus complexe techniquement à gérer pour le développeur, ce problème aurait déjà dû être réglé depuis quelques années.

Pour nuancer ce propos, sachez que tout ce qui fonctionne avec la libCurl est susceptible de fonctionner en mode Digest, pour peu que les bons paramètres aient été passés aux fonctions de connexion.

Posted lun. 01 juil. 2013 21:50:35

Introduction

Les méthodes d'authentification courantes utilisent le schéma classique du mot de passe. Mais en fait, ce mécanisme est basé sur un objet qui permet de définir l'identité d'un utilisateur. Le mot de passe étant un élément connu de seul l'utilisateur, c'est un élément de preuve de l'identité de l'utilisateur.

Pourtant, il existe d'autres mécanismes de preuve. On peut utiliser plusieurs mots de passe, ou encore une réponse à une opération de chiffrement asymétrique. On peut également s'appuyer sur un objet que seul l'utilisateur possède. Une clef USB par exemple.

L'objectif de cet article est de présenter un mécanisme d'authentification par clef USB sous GNU/Linux.

Les concepts de pam_usb

Le module PAM pam_usb permet justement de réaliser cette authentification sous GNU/Linux et ce, de manière sécurisée. On peut penser qu'une simple clef USB est facile à contrefaire ce qui est juste.

Pam_usb identifie la clef USB selon plusieurs paramètres internes de l'appareil (vendor-id, product-id et le numéro de série). Mais nous sommes tous d'accord que ce n'est pas suffisant pour prouver que c'est bien la bonne clef usb. Il faut quelquechose en plus.

Ce quelquechose se nomme One-Time Pad ou Masque jetable en français. Il s'agit d'un algorithme et d'une méthode de chiffrement théoriquement incassable.

Dans la pratique, le one-time pad est un fichier qui est contenu sur la clef usb sous une forme chiffrée dans /.pamusb de la clef USB (ou de la partition de la clef que vous aurez choisie pour effectuer l'authentification). De même, l'autre partie du one-time pad est située dans le répertoire utilisateur (dans ~/.pamusb). Vu le fonctionnement de l'algorithme de chiffrement, même si on réplique complètement la clef, il suffira d'un seule authentification avec la clef originelle entre temps pour invalider la copie falsifiée.

Ainsi, l'algorithme one-time pad permet de rendre, grâce aux opération répétées d'authentification, une clef unique: c'est son contenu qui est changé à chaque authentification qui permet de la caractériser par rapport à des copies.

En ce qui concerne sa configuration, pam_usb utilise un simple fichier, nommé /etc/pamusb.conf. Néanmoins, ce fichier est au format XML ! Il faudra faire attention en l'éditant manuellement. Quelques outils, que nous verrons plus loin, permettent d'éviter ces erreurs de saisie.

Installation

Sous Debian Wheezy, l'installation est simple:

aptitude install libpam-usb

Le paquet libpam-usb contient uniquement le module PAM. Il dépend du paquet pamusb-common qui contient l'ensemble des applications utiles pour gérer des comptes via pamusb.

Il existe également un paquet pamusb-tools mais il ne contient rien. Donc, ne perdez pas de temps à l'installer.

Configuration simple

Je veux pouvoir m'authentifier avec mon compte nominatif à partir d'une clef USB. C'est le cas d'utilisation le plus simple à gérer avec pam_usb.

Voici ce que nous allons faire dans l'ordre:

  • Préparer la clef USB pour la rendre "compatible" avec pam_usb.
  • Ajouter une authentification avec un utilisateur simple
  • Configurer PAM pour utiliser pam_usb.

Pour préparer la clef USB, nous allons utiliser la commande pamusb-conf du paquet pamusb-common. Cette commande permet d'ajouter un périphérique USB ainsi que des utilisateurs. Comme nous allons ajouter notre clef USB, il faut bien entendu la brancher sur votre machine auparavant puis exécuter la commande suivante:

# pamusb-conf --add-device MA_CLEF
Please select the device you wish to add.
* Using "090c 1000 (B1211510002536)" (only option)

Which volume would you like to use for storing data ?
0) /dev/sdb2 (UUID: 753D-1A37)
1) /dev/sdb3 (UUID: 4cfe69b8-e5b1-4faa-a57a-73422c549b01)
2) /dev/sdb1 (UUID: <UNDEFINED>)

[0-2]: 0

Name    : MA_CLEF
Vendor    : 090c
Model       : 1000
Serial        : B1211510002536
UUID            : 753D-1A37

Save to /etc/pamusb.conf ?
Y/n] Y
Done.
# 

pamusb-conf prend en compte les réponses aux questions que vous donnez et modifie le fichier de configuration de pam_usb (/etc/pamusb.conf par défaut).

Maintenant que la clef est ajoutée, il reste à ajouter l'authentification pour un utilisateur simple:

# pamusb-conf --add-user mederic.ribreux
Which device would you like to use for authentication ?
* Using "MA_CLEF" (only option)

User          : mederic.ribreux
Device          : MA_CLEF

Save to /etc/pamusb.conf ?
[Y/n] Y
Done.
#

Nous venons d'ajouter l'utilisateur mederic.ribreux dans la configuration de pam_usb.

Maintenant, effectuons une vérification simple pour voir si tout fonctionne (avec la clef USB branchée). Nous allons utiliser la commande pamusb-check:

# pamusb-check mederic.ribreux
* Authentication request for user "mederic.ribreux" (pamusb-check)
* Device "MA_CLEF" is connected (good).
* Performing one time pad verification...
* Regenerating new pads...
* Access granted.
#

On voit que l'accès est bien autorisé. Il reste maintenant à configurer PAM pour prendre en compte le module pam_usb. C'est une opération assez facile. Il suffit de modifier le fichier /etc/pam.d/common-auth. Dans la pratique, l'installation du paquet debian a directement modifié ce fichier pour faire prendre en compte le module via la ligne ci dessous:

auth    sufficient      pam_usb.so
auth    [success=1 default=ignore]      pam_unix.so nullok_secure try_first_pass

On voit que la ligne concernant le module pam_usb.so est à un niveau sufficient. Ce dernier indique que si pam_usb réussi à authentifier l'utilisateur (parce que sa clef usb telle que configurée est présente et que l'algorithme de chiffrement a bien fonctionné), c'est suffisant pour considérer l'authentification comme valide.

On peut mettre cette option à required pour imposer l'utilisation de la clef USB pour se connecter. Bien entendu, si l'on perd la clef, on perd cette autorisation et on ne pourra pas se connecter.

Au final, je vous invite à consulter le fichier /etc/pamusb.conf. Il contiendra tout ce que vous venez de configurer avec pamusb-conf.

Aller plus loin avec pam_usb

Il existent d'autres fonctionnalités implémentées dans pam_usb. En effet, le paquet pamusb-common embarque une dernière commande assez intéressante qui se nomme pamusb-agent. Il s'agit d'un programme en tâche de fond qui lancera des commandes lors du retrait ou de l'insertion de votre clef USB.

On peut par exemple s'en servir pour verrouiller et dévérouiller son économiseur d'écran. Je vous laisse lire la partie de la documentation officielle sur pamusb-agent pour en savoir plus.

Conclusion

Pam_usb permet de s'authentifier de manière assez fiable et assez sécurisée sur une machine bien configurée pour ça. Toutefois, il reste quelques impératifs: vous devez nécessairement renseigner votre identifiant. Suivant votre "gestionnaire" de connexion, il faudra souvent taper votre identifiant (pour la console ou pour slim par exemple).

Pam_usb évite juste de taper le mot de passe. C'est bien mais ça entraîne également quelques effets de bord. En effet, certains modules PAM ont justement besoin d'un mot de passe. C'est le cas de pam_mount par exemple. Son utilisation sera donc incompatible avec pam_usb et c'est bien dommage...

Pour ma part, étant donné que j'utilise Slim et pam_mount et que, de surcroît, l'accès à un port USB sur ma station de travail n'est pas simple, je n'ai pas donné suite à l'utilisation de pam_usb.

Posted jeu. 04 juil. 2013 21:47:12 Tags:

Introduction

La déduplication est une opération destinée à factoriser les données communes d'un ensemble de données. On retrouve cette notion dans les logiciels de sauvegardes ainsi que dans certains systèmes de fichiers. L'idée est de ne pas répéter des blocs de données identiques, présents au sein d'un groupe de fichiers ou de tout un système de fichiers. L'intérêt de cette technique est de minimiser l'espace de stockage occupé par les fichiers (ou les données) tout en restant moins complexe à gérer qu'une vraie compression. Pour résumer, on peut dire que la déduplication est une méthode de compression de premier niveau, dont l'algorithme est limité à une factorisation de données répétées plusieurs fois à l'identique dans l'espace de stockage.

En ce qui concerne la sauvegarde, la déduplication montre de vrais avantages. Bien souvent, on sauvegarde des contenus proches, ne serait-ce que les mêmes fichiers qu'on sauvegarde tous les jours. Dans un environnement de machines virtuelles, on comprend également qu'il y a de fortes redondances, ne serait-ce que dans les fichiers systèmes communs (fichiers de configuration et binaires systèmes). Disposer d'une option de déduplication dans un système permet donc, à moindre frais, de gagner de l'espace de stockage.

La déduplication peut prendre plusieurs formes. La plus simple des méthodes de déduplication consiste à remplacer les fichiers identiques par des liens vers une seule et même source. Ce principe permet d'utiliser au mieux les capacités de systèmes de fichiers de type Unix qui permettent de créer facilement ces liens. La deuxième forme de déduplication consiste à découper les fichiers (ou les données) en blocs de taille identique et de supprimer les blocs identiques en les remplaçant par des index situés dans une base de référence.

Voilà pour les principes des méthodes de déduplication. En matière d'implémentation, il existe des logiciels dédiés qui gèrent la déduplication des données dans un ensemble fermé. Les logiciels de sauvegarde en font partie: ils ne stockent pas de fichiers exploitables directement mais des ensembles de données dans un format qui leur est propre. Cela peut être dans une base de données SQL ou dans des fichiers. Au niveau des logiciels libres qui gèrent cette déduplication à part entière, on peut citer Obnam et Bup.

Il existe une autre implémentation de la déduplication: celle qui est directement intégrée aux systèmes de fichiers. Cette fonctionnalité existe par exemple depuis quelques années dans le système de fichiers ZFS développé par Sun Microsystems (puis par Oracle). BTRFS, le remplaçant d'ext4 dans le noyau Linux est actuellement développé pour offrir, entre autres, cette fonctionnalité de déduplication. L'intérêt d'une telle option se comprend aisément: plus besoin de logiciel à part pour organiser la déduplication, tout est fait lors des opérations d'écritures des fichiers, de manière transparente. De plus, on peut alors travailler sur une base large de fichiers, c'est-à-dire, tout ce qui sera contenu par le système de fichier au lieu de réserver un espace pour cela.

Hormis les questions de performances des différents algorithmes de déduplication mis en œuvres dans les différentes solutions, se pose la question de l'impact du chiffrement. En effet, il est n'est pas rare de vouloir chiffrer le contenu d'un système de fichiers et bien souvent, ces derniers offrent directement des fonctionnalités sur ce sujet. On peut penser, de prime abord, que le chiffrement des données contenues dans un ensemble de données va nécessairement les transformer. Cette transformation peut remettre en question les blocs de données communs entre plusieurs données

L'objectif de cet article est donc d'essayer de déterminer si le chiffrement des données a un réel impact sur la performance de la déduplication et si oui, dans quelle mesure. Pour ce faire, nous allons déterminer un protocole de tests destiné à prendre en compte des cas concrets de stockage de fichiers dédupliqués. Nous aurons également soin de diversifier les outils, les protocoles, les algorithmes de chiffrement.

Protocole de tests

Jeux de fichiers

En ce qui concerne les données à dédupliquer, nous allons créer deux jeux:

  • un jeu de petits fichiers dont la taille est inférieure à 4Ko (nombre de blocs faibles voire inférieure à celle d'un bloc). Il y aura donc de nombreux fichiers.
  • un jeu de fichiers plus volumineux, dont la taille sera comprise entre 5 et 50Mo.
  • L'ensemble de ces fichiers occupera une taille similaire d'environ 820Mo pour pouvoir éviter l'effet de bord inhérent au volume.

Voici ce que nous retiendrons pour la création automatisée de ces données.

Pour l'ensemble de fichiers volumineux, nous allons partir de fichiers dits primaires, remplis de données aléatoires et créés par la commande dd qui utilisera le générateur de nombre aléatoire /dev/urandom pour des questions de rapidité (création de 10 fichiers de 5 à 50Mo):

$ for f in $(seq 0 9);do dd if=/dev/urandom of=fichier_$f.data bs=1M count=$(( (f+1)*5 )); done

Pour l'ensemble de petits fichiers , nous allons partir de fichiers textes primaires du répertoire /etc. Il s'agit de fichiers de configuration dont la taille est très souvent inférieure à 4Ko. De plus, ces fichiers seront un bon exemple de ce qu'on peut retrouver comme petits fichiers à dédupliquer dans un système courant. Nous n'allons pas réimporter toute l'arborescence de /etc que nous allons plutôt aplanir grâce à la commande suivante:

$ for f in $(find /etc/ -type f);do cp $f ./$(basename $f); done

Pour permettre la déduplication, nous allons recopier cet ensemble de fichiers dans d'autres répertoires en nous contentant d'en faire varier 10% du contenu. Cette variation doit avoir lieu aléatoirement dans le fichier. Le script suivant doit nous permettre de générer de nouveaux fichiers dans un autre répertoire en respectant les règles énoncées:

    #!/bin/bash
    # Script pour faire varier des fichiers

    # Il faut renseigner un répertoire source et un répertoire cible
    if [ "$#" -lt "2" ];then
      echo "Usage: $0 repertoire_source repertoire_cible"
      exit 1
    fi

    REP_SRC="$1"
    REP_DST="$2"

    # vérification du répertoire source
    if [ ! -d "$REP_SRC" ]; then
       echo -e "Le répertoire source: $REP_SRC n'existe pas !\n"
       exit 2
    fi

    if [ ! -d "$REP_DST" ]; then
       mkdir "$REP_DST"
    fi

    # Création des fichiers initiaux:
    for f in $(find "$REP_SRC" -maxdepth 1 -name '*' -type f)
    do
      TARGET=$(basename $f)
      TARGET="${REP_DST}/${TARGET}"
      echo "Modification de $f dans $TARGET"

      # Quelques calculs
      SIZE=$(stat -c %s $f) # Taille du fichier à traiter
      # gestion des fichiers vides:
      if [ "$SIZE" -eq "0" ];then
        continue
      fi
      USIZE=$(( SIZE/10 ))              # 10% du fichier
      # Pour définir un emplacement aléatoire dans le fichier, on utilise 
      # la variable Bash $RANDOM. Comme cette dernière varie de 0 à 32767,
      # il faut faire un petit produit en croix pour obtenir une vraie taille variable.
      if [ "$(( SIZE-USIZE ))" -le "32767" ]; then
        CUTTER=$(( $RANDOM % (SIZE-USIZE) ))
      else
        CUTTER=$(( (($SIZE-$USIZE)/32767)*$RANDOM ))
      fi
      # L'espace commun aux fichiers recommence à l'emplacement suivant:
      BCUTTER=$(( $CUTTER + $USIZE ))
      TARGET=$(basename $f)
      TARGET="${REP_DST}/${TARGET}"
      echo "Modification de $f dans $TARGET" 
      # On commence ensuite la création de l'autre fichier
      ## le premier pas est de récupérer ce qui ne change pas (avant le CUTTER)
      dd if=$f of=$TARGET bs=1 count=$CUTTER
      ## Ensuite, on remplit avec d'autres nombres aléatoires:
      dd if=/dev/urandom of=$TARGET bs=1 seek=$CUTTER count=$USIZE
      ## Enfin, on termine le remplissage du fichier cible avec le reste du fichier source:
      dd if=$f of=$TARGET bs=1 seek=$BCUTTER skip=$BCUTTER count=$(( $SIZE - $BCUTTER ))
    done

En utilisant le script plusieurs fois, on obtient l'arborescence suivante:

.
├── big
│   ├── dedup1
│   ├── dedup2
│   └── orig
└── small
    ├── dedup1
    ├── dedup2
    ├── dedup3
...
├── dedup31
    └── orig

Dans le répertoire big/orig sont contenus nos gros fichiers originels. Dans small/orig, c'est la même chose pour les petits fichiers. Ensuite, les répertoires dedup"n" correspondent aux répertoires où nous avons fait jouer le script présent plus haut.

Logiciels pour la déduplication

En ce qui concerne les logiciels qui font de la déduplication, nous allons évaluer Obnam, Bup et ZFS. Les trois solutions agissent à des niveaux bien différents:

  • ZFS est un système de fichiers et la déduplication intervient dans les couches basses.
  • Obnam est un logiciel de sauvegarde qui s'appuie sur une déduplication en blocs de tailles identiques. Les blocs sont répartis dans des répertoires et des fichiers.
  • Bup est également un logiciel de sauvegarde qui agit au niveau blocs. Les blocs sont répartis dans un arbre git.

Quels scores de déduplication initiaux ?

Réalisons la déduplication des petits fichiers avec obnam:

$ mkdir obnam_small
$ obnam --repository=./obnam_small --root=./small backup
Backed up 3331 files, uploaded 52.9 MiB in 19s at 2.8 MiB/s average speed
$ SRC=$(du -s ./small | awk '{ print $1 }');CIB=$(du -s ./obnam_small | awk '{ print $1 }'); echo "scale=4;($SRC/$CIB)" | bc
1.9072

On a donc un taux de 1.9072 de déduplication pour les petits fichiers. Voyons maintenant ce qui se passe avec les gros fichiers:

$ mkdir obnam_big
$ obnam --repository=./obnam_big --root=./big backup
Backed up 34 files, uploaded 350.0 MiB in 11s at 32.9 MiB/s average speed
$ SRC=$(du -s ./big | awk '{ print $1 }');CIB=$(du -s ./obnam_big | awk '{ print $1 }'); echo "scale=4;($SRC/$CIB)" | bc
2.3439

Pour les gros fichiers, ça se passe mieux: nous avons un taux de déduplication de 2.3439. On voit donc que même avec un ratio de variation identique de 10% (environ car les petits fichiers de moins de 10 octets ne se découpent pas facilement par pas de 10%) il y a une différence notable entre un ensemble de petits fichiers répétés plusieurs fois.

Faisons la même chose avec bup. Nous voulons dédupliquer nos fichiers dans le répertoire de sauvegarde ./bup:

$ mkdir bup_small
$ bup -d ./bup_small init
$ bup -d ./bup_small index -uv ./small -f ./bup_small/bupindex
$ bup -d ./bup_small save -n small ./small
$ SRC=$(du -s ./small | awk '{ print $1 }');CIB=$(du -s ./bup_small | awk '{ print $1 }'); echo "scale=4;($SRC/$CIB)" | bc
7.2160

Très rapidement, nous pouvons voir que le taux de déduplication de bup sur les petits fichiers est bien meilleur que celui d'obnam. Maintenant, voyons quels sont les résultats de cette même méthode sur les fichiers de grosse taille:

$ mkdir bup_big
$ bup -d ./bup_big init
$ bup -d ./bup_big index -uv ./big -f ./bup_big/bupindex
$ bup -d ./bup_big save -n big ./big
$ SRC=$(du -s ./big | awk '{ print $1 }');CIB=$(du -s ./bup_big | awk '{ print $1 }'); echo "scale=4;($SRC/$CIB)" | bc
2.4723

Pour les gros fichiers, on voit que bup se révèle un peu au dessus d'obnam.

Etudions maintenant la déduplication sur un système ZFS. Nous disposons d'un pool ZFS (un zpool) nommé tank. Celui-ci dispose de l'option de déduplication. Nous allons juste copier les fichiers des répertoires dans le point de montage du système de fichiers ZFS: /tank.

$ zpool status
NAME     SIZE  ALLOC   FREE    CAP  DEDUP  HEALTH  ALTROOT
tank    1008M  1,17M  1007M    16%  1.00x  ONLINE  -
$ zfs list

zfs list
NAME   USED  AVAIL  REFER  MOUNTPOINT
tank  1,10M   975M    30K  /tank
$ cp -r ./small /tank
$ zpool status
NAME     SIZE  ALLOC   FREE    CAP  DEDUP  HEALTH  ALTROOT
tank    1008M   233M   775M    23%  3.61x  ONLINE  -
$ rm -r /tank/small
$ cp -r ./big /tank
$ zpool status
NAME     SIZE  ALLOC   FREE    CAP  DEDUP  HEALTH  ALTROOT
tank    1008M   335M   673M    33%  2.48x  ONLINE  -

Sur la déduplication des gros fichiers, on voit que ZFS est proche des autres logiciels, un peu meilleur qu'Obnam. Toutefois, sur les petits fichiers, ZFS tire plutôt bien son jeu avec un taux intermédiaire à celui de Bup.

Faisons un petit tableau récapitulatif:

Méthode small big
Obnam 1.9072 2.3439
Bup 7.2160 2.4723
ZFS 3.61 2.48

Nous pouvons en retenir que Bup se détache du lot avec les petits fichiers. Globalement, pour les gros fichiers, les performances des trois logiciels évalués sont similaires. Les chiffres ne sont pas vraiment suprenant pour ces fichiers. En effet, si on fait un peu de calculs manuels, on voit qu'il n'y a qu'un jeu de 3 répertoires contenant la même chose (orig, dedup1 et dedup2). Sachant que pour chaque lot de fichiers, j'ai fait varier le contenu de 10%, le contenu fixe qui n'a pas changé représente 1,2 fois le lot originel. 3 que divise 1,2 fait 2,5. On est donc dans l'ordre naturel des performances de la déduplication.

Méthodes de chiffrement

Nous pouvons chiffrer de plusieurs manières et selon de nombreux critères qu'on peut rassembler dans la liste suivante:

  • Chiffrement en amont ou en aval de la déduplication. Dans le premier cas, on chiffre des fichiers avant de les injecter dans le système de déduplication. Dans le second cas, on chiffre les blocs déjà dédupliqués. Suivant ce critère, on se doute bien que les performances de la déduplication seront différentes. C'est ce que nous essayerons de mesurer.
  • Chiffrement symétrique/asymétrique. Dans le premier cas, on utilise des algorithmes connus tels qu'AES ou Blowfish. Il faut juste posséder un mot de passe pour pouvoir déchiffrer. Dans le second cas, on utilise les systèmes de clefs publiques et privées. Ces deux méthodes étant bien différentes, il peut y avoir également un impact soupçonné sur les performances de la déduplication.
  • Bien entendu, peut-être que les différents algorithmes utilisés pour chiffrer les fichiers ont un effet. Dans notre cas, nous allons comparer AES et Blowfish pour le chiffrement symétrique.
  • Il existe également plusieurs outils pour réaliser le chiffrement. Nous allons en évaluer deux dans nos tests: openssl et gnupg.
  • Enfin, certains logiciels intègrent le chiffrement en leur sein. C'est le cas d'Obnam. Il faut également vérifier comment il se comporte en mode chiffrement amont ou chiffrement interne (aval).

Les différents cas qui découlent de ces critères seront maintenant explicités.

Chiffrement amont symétrique AES avec GnuPG

Pour ce cas de figure, nous allons utiliser gnupg et ses fonctionnalités de chiffrement symétriques. Nous allons utiliser l'algorithme AES et chiffrer l'intégralité des répertoires small et big. Voici les commandes à lancer:

find small/ -type d -exec mkdir ./chiffre/{} \;
for f in $(find small -type f);do gpg --symmetric -o ./chiffre/$f --passphrase thepassphrase --cipher-algo AES256 $f; done
find big/ -type d -exec mkdir ./chiffre/{} \;
for f in $(find big -type f);do gpg --symmetric -o ./chiffre/$f --passphrase thepassphrase --cipher-algo AES256 $f; done

Ces commandes produisent une arborescence de fichiers similaire à celle située dans les répertoires d'origine mais qui dispose uniquement de fichiers chiffrés. Ils partagent tous le même mot de passe.

On peut déjà remarquer que le chiffrement symétrique de cet ensemble de fichiers prend un temps non négligeable dans le cas de nombreux petits fichiers. En revanche, sur les fichiers volumineux, le chiffrement symétrique ne pose aucun problème (différence de l'ordre d'une seconde sur 20 soit aux alentours de 5% de perte).

  • copie de petits fichiers: 40.098s
  • copie des petits fichiers avec chiffrement: 3m52.952s
  • copie des gros fichiers: 18.699s
  • copie des gros fichiers avec chiffrement: 19.793s

Réappliquons les procédures évoquées plus haut avec Obnam, Bup et ZFS et comparons les résultats:

Méthode small clair small chiffré big clair big chiffré
Obnam 1.9072 .9666 2.3439 .9953
Bup 7.2160 1.1857 2.4723 .9903
ZFS 3.61 1.00 2.48 1.00

La conclusion s'impose d'elle-même: le chiffrement symétrique avec gnupg et l'algorithme AES supprime complètement les capacités de déduplication des trois logiciels utilisés. Ce comportement semble quasi-universel et s'explique par la méthode de chiffrement: une très petite variation du fichier entraîne un changement complet de son contenu chiffré. On ne retrouve donc pas de motifs répétés.

Chiffrement amont symétrique Blowfish avec GnuPG

Nous allons reprendre le même protocole que précédemment mais en utilisant l'algorithme blowfish à la place d'AES. La commande gpg va légèrement évoler:

find small/ -type d -exec mkdir ./chiffre/{} \;
for f in $(find small -type f);do gpg --symmetric -o ./chiffre/$f --passphrase thepassphrase --cipher-algo BLOWFISH $f; done
find big/ -type d -exec mkdir ./chiffre/{} \;
for f in $(find big -type f);do gpg --symmetric -o ./chiffre/$f --passphrase thepassphrase --cipher-algo BLOWFISH $f; done

Voyons quels chiffres nous pouvons sortir de ce mode de chiffrement:

Méthode small clair small chiffré big clair big chiffré
Obnam 1.9072 .9665 2.3439 .9953
Bup 7.2160 1.1880 2.4723 .9903
ZFS 3.61 1.00 2.48 1.00

On voit donc ici que dans un mode de chiffrement symétrique, l'algorithme n'a pas d'influence sur la déduplication.

Chiffrement amont symétrique AES avec OpenSSL

Cette partie a pour objectif de vérifier s'il existe une différence de comportement entre deux outils de chiffrement qui mettent en oeuvre les mêmes algorithmes.

La suite de commandes pour réaliser le chiffrement deviendra donc:

find small/ -type d -exec mkdir ./chiffre/{} \;
for f in $(find small -type f);do openssl enc -aes256 -out ./chiffre/$f -pass pass:thepassphrase -in $f; done
find big/ -type d -exec mkdir ./chiffre/{} \;
for f in $(find big -type f);do openssl enc -aes256 -out ./chiffre/$f -pass pass:thepassphrase -in $f; done
Méthode small clair small chiffré big clair big chiffré
Obnam 1.9072 .9799 2.3439 .9953
Bup 7.2160 1.0795 2.4723 .9903
ZFS 3.61 1.00 2.48 1.00

Là encore, les chiffres sont sans appel: les outils de chiffrement ont le même impact.

Chiffrement amont asymétrique avec GnuPG

Cette fois, nous allons utiliser un chiffrement asymétrique qui implique de disposer de clefs publiques et privées. Nous allons utiliser GnuPG pour gérer nos clefs de chiffrement ainsi que pour effectuer le chiffrement.

D'abord, il nous faut générer notre clef. Nous allons générer des clefs DSA et RSA d'une taille de 2048 octets pour l'utilisateur Joe Dassin. Je ne reviendrai pas sur la méthode de génération de clef (commande interactive gpg --gen-key). Disons que nous disposons de cette clef:

gpg --list-keys
/home/mederic.ribreux/.gnupg/pubring.gpg
----------------------------------------
pub   2048R/E73ACBFD 2013-05-30
uid                  Médéric RIBREUX <mederic.ribreux@agriculture.gouv.fr>
sub   2048R/37258210 2013-05-30

Nous allons chiffrer à destination de cet utilisateur en utilisant les commandes suivantes:

find small/ -type d -exec mkdir ./chiffre/{} \;
for f in $(find small -type f);do gpg --output ./chiffre/$f --encrypt --recipient mederic.ribreux@agriculture.gouv.fr $f; done
find big/ -type d -exec mkdir ./chiffre/{} \;
for f in $(find big -type f);do gpg --output ./chiffre/$f --encrypt --recipient mederic.ribreux@agriculture.gouv.fr $f; done
Méthode small clair small chiffré big clair big chiffré
Obnam 1.9072 .9660 2.3439 .9953
Bup 7.2160 1.1720 2.4723 .9903
ZFS 3.61 1.00 2.48 1.00

Encore une fois, on peut mesurer que le chiffrement asymétrique annule la déduplication.

Chiffrement interne d'Obnam

Obnam propose des options pour réaliser le chiffrement des données qui sont sauvegardées. Il s'appuie sur GnuPG pour réaliser toutes les opérations de cryptographie. Le chiffrement intervient après la déduplication. Dans notre cas, une seule clef publique sera utilisée pour notre ensemble de données.

Il convient de vérifier si ce chiffrement interne a le même comportement que le chiffrement amont.

Les performances en lecture/écriture d'obnam sont légèrement dégradées par le fait d'utiliser le chiffrement interne. Elles sont similaires aux dégradations constatées lors du chiffrement asymétrique, c'est-à-dire un facteur 4 à 5 pour les petits fichiers et un facteur 1 à 2 pour les fichiers volumineux.

Voici les résultats du taux de déduplication pour obnam:

  • Petits fichiers (clair/chiffrement interne): 1.9072 en clair contre 2.9586 avec le chiffrement interne.
  • Fichiers volumineux: 2.4723 en clair contre 2.3457 avec le chiffrement interne.

On voit bien que le chiffrement interne d'Obnam montre des performances très proches du mode non chiffré, voire meilleures pour ce qui concerne les petits fichiers. L'inconvénient de notre test, c'est qu'il utilise la même clef pour tout le dépôt obnam. Il n'est donc pas garanti que ces taux de déduplication s'appliquent pour un pool de clients disposant chacun de leur clef.

Chiffrement en aval avec ZFS

Pour ce cas précis, nous allons utiliser un système de fichiers ZFS. Ce dernier offre une couche de déduplication de blocs directement intégrée au niveau du système de fichiers. Les opérations de déduplication ont lieu en arrière plan de manière complètement transparente pour l'utilisateur. Pour le chiffrement, nous allons utiliser une couche nécéssairement située en dessous de ZFS. Elle s'appuiera sur les mécanismes dm-crypt du noyau Linux.

Voici un schéma qui correspond à l'opération d'écriture d'un fichier dans ZFS:

Schéma de couches chiffrement système de fichiers ZFS

On voit bien que le chiffrement sera géré après la déduplication. D'ailleurs, ZFS ne saura rien du chiffrement situé en dessous de lui: il est géré directement par le noyau qui réalise les opérations cryptographiques nécessaires. On peut donc penser que la déduplication ne sera pas affectée. Il convient toutefois de le mesurer et pour cela, nous allons devoir mettre en place cette infrastructure.

Commençons par créer des volumes dm-crypt. Nous allons créer deux volumes dm-crypt simplement pour pouvoir disposer d'un pool ZFS en miroir. Ces volumes s'appuieront sur les disques durs entiers /dev/sdd et /dev/sde:

# cryptsetup luksFormat /dev/sdd

WARNING!
========
Cette action écrasera définitivement les données sur /dev/sdd.

Are you sure? (Type uppercase yes): YES
Entrez la phrase secrète LUKS :
Verify passphrase:

# cryptsetup luksFormat /dev/sde

WARNING!
========
Cette action écrasera définitivement les données sur /dev/sdd.

Are you sure? (Type uppercase yes): YES
Entrez la phrase secrète LUKS :
Verify passphrase:

Nous pouvons ensuite nommer et utiliser nos volumes chiffrés:

# cryptsetup luksOpen /dev/sdd crypted_sdd
Entrez la phrase secrète pour /dev/sdd
# cryptsetup luksOpen /dev/sde crypted_sde
Entrez la phrase secrète pour /dev/sde

Ensuite, nous pouvons créer un zpool en utilisant nos volumes crypted_sdd et crypted_sde en mode miroir. Ce pool sera nommé backup. Le miroir sert à rendre redondant nos informations. Il correspond également à la configuration qui a été utilisée pour le pool ZFS non chiffré (tank):

# zpool create -f backup mirror /dev/mapper/crypted_sdd /dev/mapper/crypted_sde
# zpool status backup
    pool: backup
   state: ONLINE
    scan: none requested
config:

NAME             STATE     READ WRITE CKSUM
backup           ONLINE       0     0     0
  mirror-0       ONLINE       0     0     0
      crypted_sdd  ONLINE     0     0     0
          crypted_sde  ONLINE     0     0     0

Activons la déduplication sur le filesystem ZFS qui repose sur le pool backup:

# zfs set dedup=on backup

Enfin, nous pouvons ajouter nos données dans le répertoire backup. Après l'avoir fait, nous pouvons retenir les scores suivants de déduplication:

Méthode small big
ZFS+dm-crypt 3.61 2.48
ZFS 3.61 2.48

J'ajoute au passage les données relatives aux temps de traitement:

Méthode small big
ZFS+dm-crypt 6m24s 6m21s
ZFS 6m18s 4m29s

Comme on pouvait s'y attendre, sous ZFS, le chiffrement en aval de la déduplication n'a aucun impact sur la performance de la déduplication. En revanche, les performances disques deviennent légèrement moindres.

Conclusion

Voici un petit tableau récaptitulatif des différents cas d'utilisation du chiffrement dans la déduplication:

Méthode\Outil Obnam big Obnam small Bup big Bup small ZFS big ZFS small
Pas de chiffrement 2.3439 1.9072 2.4723 7.2160 2.48 3.61
Chiffrement amont symétrique AES GPG 0.9953 0.9666 0.9903 1.1857 1.00 1.00
Chiffrement amont symétrique Blofish GPG 0.9953 0.9665 0.9903 1.1880 1.00 1.00
Chiffrement amont symétrique AES OpenSSL 0.9953 0.9799 0.9903 1.1795 1.00 1.00
Chiffrement amont asymétrique GPG 0.9953 0.9660 0.9903 1.1720 1.00 1.00
Chifrrement aval interne Obnam 2.3457 2.9586 x x x x
Chiffrement aval ZFS + dm-crypt x x x x 2.48 3.61

Nous pouvons retenir deux points importants. D'abord, nous pouvons dire que le chiffrement en amont avec des solutions non intégrées annule la déduplication, et ce peu importe la méthode de chiffrement ou l'algorithme utilisé !

Ensuite, on a également pu observer que l'utilisation de solutions de chiffrement directement intégrées à la déduplication permet à cette dernière d'être complète. C'est le cas pour le chiffrement interne d'Obnam qui repose sur GnuPG et qui offre des chiffres comparables à ceux du mode non chiffré. A l'inverse, nous avons pu constater que l'utilisation seule de GnuPG en amont pose des problèmes. L'utilisation de ZFS avec une couche d'encryption située sous le pool ZFS permet à ce dernier d'être pleinement opérationnel du point de vue de la déduplication. Ces opérations de chiffrement se font au détriment des performances globales (vitesse d'écriture notamment).

La recommandation qui découle de ces observations, c'est qu'il faut limiter à un périmètre très restreint les sauvegardes chiffrées en amont si l'on ne souhaite pas mettre en péril l'intérêt d'une solution de déduplication.

A l'inverse, on ne peut pas considérer le chiffrement aval comme une solution sécurisée. En effet, dans tous les cas présentés, la clef de chiffrement est identique pour tout l'ensemble ce qui est une sécurité bien faible et peu adaptée dans un contexte où on cherche à se prémunir de malveillances internes.

De plus, pour le cas de ZFS, le chiffrement se déroule sur le système en activité. Cela ne permet de se prémunir que du vol d'un disque dur. Un accès frauduleux sur un système en activité, utilisant ZFS+dm-crypt, permettra de récupérer l'intégralité des données en clair ce qui est loin de répondre à certaines exigences de sécurité.

Pour terminer, je retiendrai tout de même que la déduplication est une technologie intéressante. Il existe quelques logiciels libres qui la prennent en charge avec des scores tout à fait honorables. Tout ceci devrait nous permettre de trouver de bonnes bases techniques pour mettre en place une sauvegarde dédupliquée à grande échelle. Mais ceci est pour un autre article !

Posted mar. 16 juil. 2013 20:04:12 Tags: