Garder les données et le code confidentiels dans les images de conteneurs
Au cours des derniÚres années, l'industrie du cloud a connu un changement majeur, passant du déploiement d'applications monolithiques sur des machines virtuelles à la division des applications en composants plus petits (microservices) et à leur conditionnement dans des conteneurs. La popularité de la conteneurisation aujourd'hui est largement tirée par le fonctionnement de Docker. Docker est la société qui est devenue le principal moteur des conteneurs: elle a fourni un outil facile à utiliser pour créer et exécuter des conteneurs Docker et un registre de conteneurs Docker pour le défi de la distribution.
Le succÚs de la technologie de conteneurisation dépend principalement de la sécurité des conteneurs à différentes étapes de leur cycle de vie. L'un des problÚmes de sécurité est la présence de vulnérabilités à l'intérieur des conteneurs individuels. Pour les identifier, les pipelines DevOps utilisés pour créer des conteneurs sont complétés par des scanners qui recherchent les packages présentant des vulnérabilités possibles dans les conteneurs et alertent leurs propriétaires ou techniciens s'ils sont trouvés. Vulnerability Advisor sur IBM Cloud est un exemple d'un tel utilitaire.
Un autre aspect de la sécurité est de s'assurer que le conteneur en cours de lancement est celui que vous souhaitez et qu'il n'a pas été modifié. Ce problÚme est résolu en utilisant des signatures numériques stockées dans le notaire, ce qui protégera les conteneurs de toute modification.Docker Notary est un exemple de référentiel public qui stocke les signatures d'image. à l'aide de Notary, un client peut vérifier la signature de l'image du conteneur pour s'assurer que l'image du conteneur n'a pas été modifiée depuis qu'elle a été signée avec la clé du propriétaire ou du technicien de service.
Un autre problÚme de sécurité potentiel est l'isolation des conteneurs. Les technologies de sécurité d'exécution Linux telles que les espaces de noms, les groupes de contrÎle, les fonctionnalités Linux et les profils SELinux, AppArmor et Seccomp aident à limiter les processus de conteneur et à isoler les conteneurs les uns des autres lors de l'exécution.
Cet article traite du problÚme de sécurité de l'entreprise encore d'actualité concernant la confidentialité des données et du code dans les images de conteneur. Le principal objectif de sécurité lorsque vous travaillez avec des images de conteneurs est de permettre la création et la distribution d'images de conteneurs chiffrées afin qu'elles ne soient disponibles que pour un ensemble spécifique de destinataires. Dans ce cas, d'autres personnes peuvent avoir accÚs à ces images, mais elles ne pourront pas les exécuter ni voir les données sensibles qu'elles contiennent. Le cryptage des conteneurs est basé sur la cryptographie existante telle que les technologies de cryptage Rivest-Shamir-Adleman (RSA), la courbe elliptique et Advanced Encryption Standard (AES), également connu sous le nom de Rijndael, un algorithme de chiffrement par blocs symétriques.
Introduction
Pour tirer le meilleur parti de cet article, vous devez ĂȘtre familiarisĂ© avec les conteneurs Linux et les images de conteneurs, et avoir une comprĂ©hension des bases de la sĂ©curitĂ©.
Travaux connexes sur le chiffrement et les conteneurs
à notre connaissance, il n'y a pas de travail dans le domaine du chiffrement des images de conteneurs. Cependant, il existe de nombreuses implémentations et produits qui prennent en charge la confidentialité des données et le cryptage antivol via le systÚme de fichiers, le périphérique de blocage ou le cryptage matériel. Ce dernier est implémenté à l'aide de disques auto-chiffrés. Il existe également des images de machines virtuelles chiffrées.
Les systĂšmes de fichiers chiffrĂ©s existent sur de nombreux systĂšmes d'exploitation dans les entreprises et peuvent prendre en charge le montage de partitions et de rĂ©pertoires chiffrĂ©s. Les systĂšmes de fichiers cryptĂ©s peuvent mĂȘme prendre en charge le dĂ©marrage Ă partir d'un lecteur de dĂ©marrage cryptĂ©. Linux prend en charge le chiffrement de pĂ©riphĂ©rique par bloc Ă l'aide du pilote dm-encrypt; ecryptfs est un exemple de systĂšme de fichiers chiffrĂ©. Autres solutions de cryptage de fichiers disponibles pour LinuxOpen source. Sous Windows, le chiffrement est pris en charge par le systĂšme de fichiers NTFS v3.0. De plus, de nombreux fabricants crĂ©ent des disques Ă auto-cryptage. Pour les images de machine virtuelle, il existe une solution similaire aux disques chiffrĂ©s. L'Ă©mulateur de machine (PC) QEMU open source et les produits de virtualisation VMware prennent en charge les images de machine virtuelle chiffrĂ©es.
Le cryptage des données vise généralement à se protéger contre le vol de données lorsque le systÚme est hors ligne. Une technologie connexe consiste à signer l'image du conteneur avec une clé fournie par le client et le serveur Docker Notary. Le serveur Docker Notary fonctionne à proximité du registre d'images de conteneurs. Les utilisateurs de l'outil client Docker ont la possibilité de signer l'image du conteneur et de télécharger la signature sur leurs comptes via Docker Notary. Au cours de ce processus, la signature est liée à l'image du conteneur via le chemin d'accÚs à l'image et à ses versions. La signature est créée à l'aide d'une fonction de hachage qui est calculée en fonction de la description de tout le contenu de l'image. Cette description est appelée le manifeste de l'image du conteneur.La technologie de signature d'image de conteneur résout le problÚme de la protection des images de conteneur contre tout accÚs non autorisé et aide à déterminer l'origine de l'image de conteneur.
Structure
L'Ă©cosystĂšme Docker a Ă©voluĂ© pour normaliser les formats d'image de conteneur Ă l'aide du groupe de normes Open Container Initiative (OCI), qui contrĂŽle dĂ©sormais le format d'exĂ©cution du conteneur (spĂ©cification d'exĂ©cution) et le format d'image du conteneur (spĂ©cification d'image). Ătant donnĂ© que le travail de l'Ă©quipe nĂ©cessitait une extension du format d'image du conteneur existant, nous avons identifiĂ© une extension de la norme pour prendre en charge les images cryptĂ©es. Les sections suivantes dĂ©crivent l'image de conteneur existante et le format d'extension.
Au niveau supĂ©rieur, un conteneur peut ĂȘtre constituĂ© d'un document JavaScript Object Notation (JSON), qui est une liste de manifestes d'image. Par exemple, vous pouvez utiliser cette liste de manifestes lorsque plusieurs architectures ou plates-formes sont utilisĂ©es pour l'image de conteneur. La liste des manifestes contient des liens vers des manifestes de conteneur, un pour chaque combinaison d'architecture et de systĂšme d'exploitation. Par exemple, les architectures prises en charge incluent amd64, arm et ppc64le, et les systĂšmes d'exploitation pris en charge incluent Linux ou Windows. Un exemple de liste de manifestes est illustrĂ© dans la capture d'Ă©cran ci-dessous:
Le champ mediaType décrit le format exact du document spécifié. Cette liste de manifestes permet une expansion future et la sélection de l'analyseur approprié pour le document concerné.
Le niveau en dessous de la liste des manifestes est le manifeste. Le manifeste est Ă©galement un document JSON et contient une liste ordonnĂ©e de rĂ©fĂ©rences aux couches d'image. Ces liens contiennent mediaType dĂ©crivant le format de la couche. Le format peut dĂ©crire si la couche est compressĂ©e, et si oui, comment. Par exemple, chaque niveau peut ĂȘtre enregistrĂ© en tant que fichier .tar contenant des fichiers qui ont Ă©tĂ© ajoutĂ©s Ă une Ă©tape spĂ©cifique de la gĂ©nĂ©ration lors de l'exĂ©cution de la build docker dans un Dockerfile. Les couches sont souvent compressĂ©es Ă l'aide de fichiers .gzip compressĂ©s pour amĂ©liorer l'efficacitĂ© du stockage. Un exemple de document manifeste est illustrĂ© dans la capture d'Ă©cran suivante:
Comme indiqué, les manifestes et les couches sont référencés via un "digest", qui est généralement une fonction de hachage sha256 dans les documents JSON. Les manifestes et les couches sont généralement stockés sous forme de fichiers sur le systÚme de fichiers. Souvent, les noms de fichiers sont des fonctions de hachage sur le contenu, ce qui facilite leur recherche et leur chargement. La conséquence de cette méthode de hachage est qu'un petit changement dans le document référencé entraßne des changements dans tous les documents qui le référencent, jusqu'à la liste des manifestes.
Dans le cadre du projet de notre équipe, nous avons créé un cryptage d'image basé sur un schéma de cryptage hybride utilisant des clés publiques et symétriques. Les clés symétriques sont utilisées pour le chiffrement en masse des données (utilisées pour le chiffrement à plusieurs niveaux), et les clés publiques sont utilisées pour le conditionnement des clés symétriques. Nous avons utilisé trois technologies de chiffrement à clé publique différentes: OpenPGP, JSON Web Encryption (JWE) et PKCS # 7.
OpenPGP
OpenPGP est une technologie de cryptage et de signature couramment utilisĂ©e pour crypter et signer les e-mails. Les communautĂ©s open source l'utilisent Ă©galement souvent pour signer les commits (balises) du code source dans les rĂ©fĂ©rentiels git. Il s'agit d'une norme Internet dĂ©finie par l'IETF dans RFC480 et peut ĂȘtre considĂ©rĂ©e comme une version ouverte de la technologie propriĂ©taire PGP prĂ©cĂ©dente.
OpenPGP a son propre format pour les clĂ©s RSA. Les clĂ©s sont gĂ©nĂ©ralement stockĂ©es dans un fichier de trousseau de clĂ©s et peuvent ĂȘtre importĂ©es Ă partir de fichiers de clĂ©s OpenPGP simples. L'aspect le plus pratique du trousseau de clĂ©s OpenPGP est que les clĂ©s publiques peuvent ĂȘtre liĂ©es aux adresses e-mail de leurs propriĂ©taires. Vous pouvez travailler avec plusieurs destinataires d'un message en sĂ©lectionnant simplement une liste de destinataires par leurs adresses e-mail, qui apparaissent ensuite dans les clĂ©s publiques de ces destinataires. De plus, une toile de confiance s'est construite autour de cette technologie: vous pouvez retrouver les clĂ©s publiques de nombreux utilisateurs, triĂ©es par leurs adresses email. Par exemple, ces clĂ©s sont souvent utilisĂ©es pour signer des balises git.
Vous pouvez utiliser le format de message cryptĂ© OpenPGP pour crypter un message en masse Ă plusieurs destinataires. L'en-tĂȘte du message OpenPGP contient un bloc pour chaque destinataire. Chaque bloc contient un identificateur de clĂ© 64 bits qui indique Ă l'algorithme de dĂ©chiffrement oĂč essayer de dĂ©chiffrer la clĂ© privĂ©e correspondante. Une fois que l'objet blob chiffrĂ© Ă l'intĂ©rieur du bloc est dĂ©chiffrĂ©, il affiche la clĂ© symĂ©trique qui peut ĂȘtre utilisĂ©e pour dĂ©chiffrer le message en masse. L'objet blob de clĂ© publique chiffrĂ©e de chaque destinataire prĂ©sente la mĂȘme clĂ© symĂ©trique.
Nous avons utilisĂ© OpenPGP de la mĂȘme maniĂšre, mais dans ce cas, le message chiffrĂ© qu'il envoie n'est pas une couche. Au lieu de cela, il contient un document JSON, qui Ă son tour contient une clĂ© symĂ©trique utilisĂ©e pour crypter et dĂ©crypter Ă la fois la couche et le vecteur d'initialisation. Nous appelons cette clĂ© la clĂ© de chiffrement de couche (LEK) et c'est une forme de clĂ© de chiffrement de donnĂ©es. L'avantage de cette mĂ©thode est que nous n'avons besoin que d'une LEK. Avec LEK, nous chiffrons la couche pour un ou plusieurs destinataires. Chaque destinataire (image de conteneur) peut avoir un type de clĂ© diffĂ©rent et il n'est pas nĂ©cessaire qu'il s'agisse d'une clĂ© OpenPGP. Par exemple, il peut s'agir d'une simple clĂ© RSA. Tant que nous avons la possibilitĂ© d'utiliser cette clĂ© RSA pour crypter la LEK, nous pouvons travailler avec plusieurs destinataires avec diffĂ©rents types de clĂ©s.
Chiffrement Web JSON (JWE)
Le cryptage Web JSON, également connu sous le nom de JWE, est une autre norme Internet de l'IETF et est défini dans la RFC7516 . Il s'agit d'une norme de chiffrement plus récente qu'OpenPGP, et utilise donc des chiffrements de bas niveau plus récents conçus pour répondre à des exigences de chiffrement plus strictes.
à plus grande échelle, JWE fonctionne de maniÚre similaire à OpenPGP en ce sens qu'il gÚre également une liste de destinataires et l'envoi en masse d'un message chiffré avec une clé symétrique à laquelle chaque destinataire du message a accÚs. Les destinataires d'un message JWE peuvent avoir différents types de clés, tels que des clés RSA, des types de clés de courbe elliptique spécifiques pour le chiffrement et des clés symétriques. Comme il s'agit d'une norme plus récente, il est toujours possible d'étendre le JWE pour prendre en charge les clés dans les périphériques matériels tels que les TPM ou les modules de sécurité matérielle (HSM) à l'aide des interfaces PKCS # 11 ou KMIP (Key Management and Interoperability Protocol). Les JWE sont utilisés de maniÚre similaire à OpenPGP si les destinataires ont des clés RSA ou des courbes elliptiques.à l'avenir, nous pourrions l'étendre pour prendre en charge les clés symétriques telles que KMIP dans HSM.
PKCS # 7
PKCS # 7, Ă©galement connu sous le nom de syntaxe de message cryptographique (CMS), est dĂ©fini dans IEFT RFC5652 . Selon Wikipedia Ă propos de CMS, «il peut ĂȘtre utilisĂ© pour signer, digĂ©rer, authentifier ou crypter numĂ©riquement toute forme de donnĂ©es numĂ©riques».
Il est similaire aux deux technologies décrites précédemment en ce sens qu'il permet plusieurs destinataires et le cryptage des messages en masse. Par conséquent, nous l'avons utilisé comme les autres technologies, mais uniquement pour les destinataires qui fournissent des certificats pour les clés de chiffrement.
Pour prendre en charge les technologies de chiffrement décrites précédemment, nous avons étendu le document manifeste pour inclure les informations suivantes:
- Les messages OpenPGP, JWE et PKCS # 7 sont stockés dans une carte d'annotations, qui fait partie du manifeste.
- Chaque couche spécifiée contient une carte. Une carte d'annotation est essentiellement un dictionnaire avec des chaßnes comme clés et des chaßnes comme valeurs (paires clé-valeur).
Pour prendre en charge le cryptage des images, nous avons défini les clés suivantes:
- org.opencontainers.image.enc.keys.openpgp
- org.opencontainers.image.enc.keys.jwe
- org.opencontainers.image.enc.keys.pkcs7
La valeur rĂ©fĂ©rencĂ©e par chaque clĂ© contient un ou plusieurs messages chiffrĂ©s pour la technologie de chiffrement correspondante. Ătant donnĂ© que ces messages peuvent ĂȘtre au format binaire, ils sont encodĂ©s en base64. Une couche chiffrĂ©e doit avoir au moins une de ces annotations, mais elle peut tout avoir si son destinataire dispose d'un nombre suffisant de types de clĂ©s diffĂ©rents.
Pour déterminer que la couche a été chiffrée avec LEK, nous avons étendu les types de média existants avec le suffixe '+ encrypted', comme indiqué dans les exemples suivants:
- application / vnd.docker.image.rootfs.diff.tar + chiffré
- application / vnd.docker.image.rootfs.diff.tar.gzip + chiffré
Ces exemples montrent que la couche est compressée dans un fichier .tar et chiffrée - ou les deux compressées dans un fichier .tar et compressées dans un fichier .gzip et chiffrées. La capture d'écran suivante montre un exemple de manifeste lié à des couches chiffrées. Il montre également une carte d'annotations contenant le message JWE chiffré.
Cryptage en couches à l'aide de clés symétriques
Pour le chiffrement symétrique avec LEK, notre équipe a choisi un chiffrement prenant en charge le chiffrement authentifié et basé sur la norme de chiffrement AES avec des clés de 128 et 256 bits.
Exemple d'implémentation: containerd
Nous avons implĂ©mentĂ© notre variante dans un nouveau projet d'exĂ©cution de conteneur appelĂ© containerd . Son code source sur golang peut ĂȘtre consultĂ© en suivant le lien . Le dĂ©mon Docker utilise containerd pour exĂ©cuter certains de ses services, et Kubernetes a un plugin pour utiliser directement containerd. Par consĂ©quent, nous espĂ©rons que nos extensions pour prendre en charge les images de conteneurs chiffrĂ©es seront utiles aux deux.
La mise en Ćuvre du chiffrement Ă plusieurs niveaux Ă l'aide de LEK se situe au niveau architectural le plus bas des extensions. L'une des exigences de mise en Ćuvre Ă©tait de prendre en charge des couches volumĂ©triques de plusieurs gigaoctets tout en gardant la quantitĂ© de mĂ©moire occupĂ©e par le processus effectuant l'opĂ©ration cryptographique sur la couche d'une taille de quelques mĂ©gaoctets seulement.
La prise en charge des algorithmes de chiffrement authentifiĂ©s dans Golang prend un tableau d'octets en entrĂ©e et effectue toute l'Ă©tape de chiffrement (scellage) ou de dĂ©chiffrement (ouverture), empĂȘchant le transfert et l'ajout de tableaux supplĂ©mentaires au flux. Ătant donnĂ© que cette API cryptographique nĂ©cessitait de charger toute la couche en mĂ©moire ou d'inventer un schĂ©ma pour changer le vecteur d'initialisation (IV) pour chaque bloc, nous avons dĂ©cidĂ© de ne pas utiliser le cryptage authentifiĂ© de Golang avec prise en charge des donnĂ©es liĂ©es (AEAD). Au lieu de cela, nous avons utilisĂ© la bibliothĂšque de crypto miscreant golang qui prend en charge AEAD sur les flux(blocs) et implĂ©mente son propre schĂ©ma pour changer IV dans chaque bloc. Dans notre implĂ©mentation, nous divisons la couche en blocs de 1 Mo, que nous transfĂ©rons un par un pour le chiffrement. Cette approche vous permet de rĂ©duire la quantitĂ© de mĂ©moire lors de l'utilisation d'un chiffrement authentifiĂ©. CĂŽtĂ© dĂ©cryptage, on fait le contraire et on fait attention aux erreurs renvoyĂ©es par la fonction Open () pour s'assurer que les blocs de cryptage n'ont pas Ă©tĂ© falsifiĂ©s.
Au-dessus du cryptage symétrique, des schémas cryptographiques asymétriques cryptent la LEK et le vecteur d'initialisation (IV). Pour ajouter ou supprimer des schémas cryptographiques, nous enregistrons chaque implémentation cryptographique asymétrique. Lorsque l'API de code cryptographique asymétrique est appelée pour crypter la couche, nous appelons les gestionnaires cryptographiques enregistrés un par un, en transmettant les clés publiques des destinataires. Une fois que toutes les clés de destinataire ont été utilisées pour le cryptage, nous retournons à la carte d'annotation avec les identifiants asymétriques de cryptoalgorithme comme clés de mappage et les valeurs contenant les messages encodés dans OpenPGP, JWE et PKCS # 7. Chaque message contient LEK et IV emballés. Les cartes d'annotations sont stockées dans le document manifeste, comme indiqué dans la capture d'écran précédente.
Nous pouvons également ajouter des destinataires à une image déjà cryptée. Les auteurs d'images ajoutent des destinataires s'ils figurent dans la liste. La clé privée est utilisée pour la liste des destinataires, qui est nécessaire pour décompresser les niveaux LEK et IV. Nous enveloppons ensuite le LEK et IV dans un nouveau message en utilisant la nouvelle clé de destinataire et ajoutons ce message à la carte d'annotations.
Nous avons utilisé trois types de schémas de chiffrement asymétriques pour différents types de clés. Nous utilisons des clés OpenPGP pour crypter les messages OpenPGP. Le PKCS # 7 que nous utilisons nécessite des certificats x.509 pour les clés de chiffrement. JWE gÚre tous les autres types de clés tels que les clés RSA simples, les courbes elliptiques et les clés symétriques. Nous avons prototypé une extension pour JWE qui permet des opérations cryptographiques à l'aide de clés gérées par le serveur KMIP.
Le runtime containerd inclut un outil client ctr pour interagir avec lui. Nous avons étendu ctr pour permettre de tester nos modifications et fournir un accÚs aux utilisateurs de conteneurs. ctr implémente déjà une sous-commande qui prend en charge les opérations sur les images, telles que l'interaction avec le registre d'images en les récupérant et en les envoyant.
Nous avons Ă©tendu cette sous-commande en ajoutant des fonctionnalitĂ©s pour crypter les images et activer le cryptage de couches spĂ©cifiques d'architectures spĂ©cifiques Ă l'aide d'un ensemble spĂ©cifique de clĂ©s. Cette approche permet aux utilisateurs de chiffrer uniquement les couches contenant des donnĂ©es sensibles et de laisser les autres couches non chiffrĂ©es. Ce dernier peut ĂȘtre dĂ©dupliquĂ©, mais cela n'est guĂšre possible pour les couches chiffrĂ©es.
De mĂȘme, nous pouvons dĂ©chiffrer les couches individuelles des architectures individuelles. Nous avons ajoutĂ© une sous-commande layerinfo qui montre l'Ă©tat de chiffrement de chaque couche et affiche les technologies de chiffrement utilisĂ©es pour cela. Pour OpenPGP, nous pouvons Ă©galement afficher les identifiants clĂ©s nĂ©cessaires au dĂ©cryptage, ou les convertir en adresses e-mail de leurs destinataires Ă l'aide d'un trousseau de clĂ©s.
De plus, vous pouvez exporter et importer des images de conteneurs. Nous avons implĂ©mentĂ© la prise en charge du cryptage des couches Ă l'exportation et du dĂ©cryptage Ă l'importation. MĂȘme si nous dĂ©chiffrons les couches pour crĂ©er le systĂšme de fichiers rootfs du conteneur, les couches chiffrĂ©es et les fichiers de mĂ©tadonnĂ©es d'origine tels que ses manifestes sont conservĂ©s. Cette approche vous permet d'exporter une image chiffrĂ©e et d'effectuer des vĂ©rifications d'autorisation lorsque les utilisateurs souhaitent dĂ©marrer un conteneur avec une image chiffrĂ©e.
Lorsqu'une image simple (non chiffrĂ©e) est extraite du registre, elle est automatiquement dĂ©compressĂ©e et dĂ©compressĂ©e afin que des conteneurs puissent ĂȘtre crĂ©Ă©s immĂ©diatement Ă partir de celle-ci. Pour faciliter la tĂąche des images chiffrĂ©es, nous vous suggĂ©rons de transmettre la clĂ© privĂ©e Ă l'Ă©quipe de dĂ©ballage afin qu'elle puisse dĂ©chiffrer les couches avant le dĂ©ballage. Si l'image est chiffrĂ©e avec plusieurs clĂ©s, plusieurs clĂ©s peuvent ĂȘtre transmises Ă la commande pull. Ce transfert est Ă©galement pris en charge. AprĂšs avoir extrait avec succĂšs l'image chiffrĂ©e du registre, toute personne ayant accĂšs Ă containerd peut crĂ©er un conteneur Ă partir de l'image. Pour confirmer que l'utilisateur a le droit d'utiliser l'image du conteneur, nous suggĂ©rons qu'il fournisse les clĂ©s privĂ©es utilisĂ©es pour dĂ©crypter le conteneur.Nous utilisons des clĂ©s pour vĂ©rifier l'autorisation de l'utilisateur, si elles peuvent ĂȘtre utilisĂ©es pour dĂ©chiffrer la LEK de chaque niveau chiffrĂ©, et si cela est confirmĂ©, nous autorisons le conteneur Ă dĂ©marrer.
Un guide Ă©tape par Ă©tape du chiffrement Ă l'aide de containerd
Dans cette section, nous allons démontrer les étapes de chiffrement qui sont appliquées avec containderd en utilisant ctr sur la ligne de commande. Nous allons vous montrer comment crypter et décrypter une image de conteneur.
Tout d'abord, vous devez cloner le référentiel git containerd / imgcrypt , qui est un sous-projet et peut crypter / décrypter l'image du conteneur. Ensuite, vous devez créer containerd et l'exécuter. Pour effectuer ces étapes, vous devez savoir comment l'environnement de développement golang est configuré:
imgcrypt nécessite containerd version 1.3 ou supérieure.
Construisez et installez imgcrypt:
# make
# sudo make install
Exécutez containerd avec le fichier de configuration vu dans l'exemple ci-dessous. Pour éviter les conflits dans containerd, utilisez le répertoire / tmp pour les répertoires. Construisez également la version 1.3 de containerd à partir des sources, mais ne l'installez pas.
# cat config.toml
disable_plugins = ["cri"]
root = "/tmp/var/lib/containerd"
state = "/tmp/run/containerd"
[grpc]
address = "/tmp/run/containerd/containerd.sock"
uid = 0
gid = 0
[stream_processors]
[stream_processors."io.containerd.ocicrypt.decoder.v1.tar.gzip"]
accepts = ["application/vnd.oci.image.layer.v1.tar+gzip+encrypted"]
returns = "application/vnd.oci.image.layer.v1.tar+gzip"
path = "/usr/local/bin/ctd-decoder"
[stream_processors."io.containerd.ocicrypt.decoder.v1.tar"]
accepts = ["application/vnd.oci.image.layer.v1.tar+encrypted"]
returns = "application/vnd.oci.image.layer.v1.tar"
path = "/usr/local/bin/ctd-decoder"
# sudo ~/src/github.com/containerd/containerd/bin/containerd -c config.toml
Créez une paire de clés RSA à l'aide de l'outil de ligne de commande openssl et cryptez l'image:
# openssl genrsa --out mykey.pem
Generating RSA private key, 2048 bit long modulus (2 primes)
...............................................+++++
............................+++++
e is 65537 (0x010001)
# openssl rsa -in mykey.pem -pubout -out mypubkey.pem
writing RSA key
# sudo chmod 0666 /tmp/run/containerd/containerd.sock
# CTR="/usr/local/bin/ctr-enc -a /tmp/run/containerd/containerd.sock"
# $CTR images pull --all-platforms docker.io/library/bash:latest
[...]
# $CTR images layerinfo --platform linux/amd64 docker.io/library/bash:latest
# DIGEST PLATFORM SIZE ENCRYPTION RECIPIENTS
0 sha256:9d48c3bd43c520dc2784e868a780e976b207cbf493eaff8c6596eb871cbd9609 linux/amd64 2789669
1 sha256:7dd01fd971d4ec7058c5636a505327b24e5fc8bd7f62816a9d518472bd9b15c0 linux/amd64 3174665
2 sha256:691cfbca522787898c8b37f063dd20e5524e7d103e1a3b298bd2e2b8da54faf5 linux/amd64 340
# $CTR images encrypt --recipient jwe:mypubkey.pem --platform linux/amd64 docker.io/library/bash:latest bash.enc:latest
Encrypting docker.io/library/bash:latest to bash.enc:latest
$ $CTR images layerinfo --platform linux/amd64 bash.enc:latest
# DIGEST PLATFORM SIZE ENCRYPTION RECIPIENTS
0 sha256:360be141b01f69b25427a9085b36ba8ad7d7a335449013fa6b32c1ecb894ab5b linux/amd64 2789669 jwe [jwe]
1 sha256:ac601e66cdd275ee0e10afead03a2722e153a60982122d2d369880ea54fe82f8 linux/amd64 3174665 jwe [jwe]
2 sha256:41e47064fd00424e328915ad2f7f716bd86ea2d0d8315edaf33ecaa6a2464530 linux/amd64 340 jwe [jwe]
Démarrez votre registre d'images local afin de pouvoir y télécharger l'image cryptée. Pour recevoir des images de conteneur chiffrées, vous avez besoin des derniÚres versions de registre.
# docker pull registry:latest
# docker run -d -p 5000:5000 --restart=always --name registry registry
Téléchargez l'image chiffrée dans votre registre local, extrayez-la à l'aide de ctr-enc, puis exécutez l'image:
# $CTR images tag bash.enc:latest localhost:5000/bash.enc:latest
# $CTR images push localhost:5000/bash.enc:latest
# $CTR images rm localhost:5000/bash.enc:latest bash.enc:latest
# $CTR images pull localhost:5000/bash.enc:latest
# sudo $CTR run --rm localhost:5000/bash.enc:latest test echo 'Hello World!'
ctr: you are not authorized to use this image: missing private key needed for decryption
# sudo $CTR run --rm --key mykey.pem localhost:5000/bash.enc:latest test echo 'Hello World!'
Hello World!
Conclusion
Le chiffrement des images de conteneurs est un bon ajout à leur sécurité, il garantit la confidentialité des données et l'intégrité des images de conteneurs sur le lieu de stockage. La technologie proposée est basée sur les technologies de cryptage RSA, courbe elliptique et AES accessibles au public. Il applique les clés aux schémas de chiffrement de niveau supérieur tels que OpenPGP, JWE et PKCS # 7. Si vous savez comment travailler avec OpenPGP, vous pouvez crypter les images de conteneurs pour les destinataires OpenPGP en utilisant leurs adresses e-mail, tandis que de simples clés RSA et des courbes elliptiques sont utilisées pour le cryptage comme JWE.