Gérer les secrets avec HashiCorp Vault

Comment garder des secrets? Dans le référentiel, dans le système de déploiement ou dans le système de gestion de configuration? Sur un ordinateur personnel, sur des serveurs ou peut-être dans une boîte sous le lit? Et comment gérer les secrets pour éviter les fuites?

Sergey Noskov ( Albibek ) - le chef du groupe de sécurité de l'information de la plate-forme d'Avito , connaît la réponse à ces questions et partagera avec nous. À Avito, HashiCorp Vault utilise activement HashiCorp Vault depuis deux ans, période pendant laquelle ils ont obtenu des bosses et une expérience de pompage au niveau «Master».

Dans l'article, nous parlerons de Vault de manière détaillée: de quoi il s'agit, où et comment il est utilisé dans l'entreprise, comment Avito gère les secrets à l'aide de HashiCorp Vault, comment Puppet et Kubernetes sont utilisés, des cas d'utilisation avec Puppet et d'autres SCM, quels problèmes se posent, ce qui nuit à la sécurité et les développeurs, et, bien sûr, partager des idées sur la façon de résoudre ce problème.


Qu'est-ce qu'un secret?


Toute information confidentielle:

  • identifiant et mot de passe, par exemple, à la base de données;
  • Clés API
  • Clé de certificat du serveur (* .google.com)
  • clé de certificat client (partenaires, Yandex money, QIWI);
  • clé pour signer les applications mobiles.

Toutes les informations que nous voulons garder secrètes, nous appelons un secret. Cela crée un problème de stockage: il est mauvais de le stocker dans le référentiel, sous forme cryptée - vous devez conserver les clés de cryptage quelque part.

HashiCorp Vault est l'une des bonnes solutions au problème.

  • Stocke et gère les clés en toute sécurité.
  • Aiguisé sur le monde des microservices, depuis le microservice lui-même.
  • HashiCorp Vault a fait beaucoup pour authentifier et autoriser l'accès aux secrets, tels que les listes de contrôle d'accès et le principe des privilèges minimaux.
  • Interface REST avec JSON.
  • La sécurité n'est pas parfaite, mais à un niveau assez élevé.

À mon avis, c'est un outil assez pratique.

Nouveautés de HashiCorp Vault


L'outil se développe et ces dernières années, de nombreuses fonctionnalités intéressantes y sont apparues: en-têtes CORS pour GUI sans intermédiaires; interface graphique intégrée; intégration native avec Kubernetes; plugins pour les backends et le framework logiques et d'authentification.

La plupart des changements que j'ai personnellement appréciés sont la possibilité de ne pas écrire d'extensions et d'ajouts qui se trouveront en dehors de l'outil.

Par exemple, il y a Vault, vous voulez l'étendre - écrivez une logique supplémentaire ou votre propre interface utilisateur pour l'automatisation, qui automatisera quelque chose. Avant les modifications, j'ai dû lever un service supplémentaire auquel Vault est confronté, et procurer toutes les demandes par procuration: d'abord les demandes vont au service, puis à Vault. C'est mauvais car dans le service intermédiaire, le niveau de sécurité peut être réduit et tous les secrets le traversent. Les risques de sécurité sont beaucoup plus élevés lorsque le secret passe par plusieurs points à la fois!

Problème de poulet et d'oeufs


Lorsque vous soulevez le problème du stockage d'informations confidentielles et décidez de crypter, dès que vous cryptez quelque chose, votre secret se déplace du lieu de cryptage à l'endroit où la clé est stockée. Cela se produit tout le temps: dès que vous avez sauvegardé un secret quelque part ou changé un existant, vous en avez un autre et un cercle vicieux commence - où garder le secret pour accéder au secret .

Le secret pour accéder au secret est la partie de la sécurité appelée authentification . La sécurité a une autre partie - l' autorisation. Dans le processus d'autorisation, il est vérifié si l'utilisateur peut accéder exactement là où il demande. Dans le cas de Vault, un tiers de confiance décide de divulguer ou non le secret. L'autorisation ne résout que partiellement le problème.

HashiCorp Vault à Avito


Chez Avito, HashiCorp est installé dans la seule grande installation sur l'ensemble du réseau. HashiCorp Vault a de nombreux backends différents. Nous utilisons également le backend basé sur Consul de HashiCorp, car Vault ne peut prendre en charge sa propre tolérance aux pannes que via Consul.

Le descellement est un moyen de ne pas conserver la clé principale au même endroit. Lorsque Vault démarre, il crypte tout sur une clé, et à nouveau le problème du poulet et des œufs apparaît: où garder un secret, qui cryptera tous les autres secrets. Pour éviter ce problème, Vault fournit une clé composite, qui nécessite plusieurs parties de la clé, que nous distribuons à plusieurs employés. Dans Avito, nous avons configuré Unseal dans les options pour 3 personnes sur 7. Si nous démarrons Vault, au moins 3 personnes doivent entrer et entrer leur partie de la clé pour qu'elle commence à fonctionner. La clé est divisée en 7 parties et vous pouvez apporter n'importe laquelle d'entre elles.

Nous avons mis en place un petit test Vault, un bac à sable pour les développeurs où ils peuvent jouer. Il se présente sous la forme d'un conteneur Docker et crée des secrets simples pour que les gens puissent toucher l'outil avec leurs mains, se mettre à l'aise. Il n'y a pas de consul et de clustering dans le bac à sable, c'est juste un système de fichiers sur lequel Vault détient des secrets chiffrés et un petit script à initialiser.

Voici ce que nous stockons maintenant dans Vault:

  • Presque tous les secrets des microservices Kubernetes: mots de passe de base de données, clés API, tout cela.
  • Secrets de pose sur les serveurs "fer" et LXC.
  • Nous avons également mis des secrets pour les builds CI / CD dans TeamCity in Vault. La couverture n'est pas à 100%, mais tout à fait acceptable.
  • Les clés de tous les certificats: PKI interne, CA externes, par exemple, GeoTrust et similaires.
  • Secrets communs aux équipes.

À l'intérieur, Vault stocke tout uniquement en JSON, ce n'est pas toujours pratique et nécessite des actions supplémentaires de la part du développeur, donc en gros nous publions des secrets sous la forme d'un fichier.

Nous essayons de livrer des secrets sous forme de fichiers.

Nous ne disons pas au développeur: "Allez dans Vault, prenez un secret!", Mais placez le fichier sur le disque et dites: "Développeur, un fichier apparaîtra sur votre disque, prenez-lui le secret, et nous déterminerons déjà comment l'obtenir de Vault et l'apporter. à vous. "


Nous avons adopté un accord simple pour les champs JSON, dans lequel nous indiquons avec quels droits télécharger le fichier. Il s'agit de métadonnées pour le système de fichiers et le champ de données est une chaîne codée avec le secret lui-même, qui deviendra le contenu du fichier.

Marionnette + Hiera + Vault


Presque toute l'infrastructure Avito utilise Puppet, elle déploie tous les serveurs.

Puppet dispose d'un outil pratique pour organiser les hiérarchies - Hiera . Vault s'intègre très bien à Hiera via un module complémentaire, car une demande de valeur-clé est envoyée à cette bibliothèque, et Vault lui-même est une base de données de valeurs-clés, mais avec toutes les fonctionnalités de sécurité - avec un cryptage transparent et la possibilité de choisir l'accès aux clés.

Par conséquent, la première chose que nous avons implémentée est Vault in Puppet, mais avec un ajout - nous avons une couche intermédiaire appelée backend Router . Backend du routeur - un module Hiera séparé, juste des fichiers sur le disque qui indiquent où Hiera doit aller pour la clé - dans Vault ou dans un autre endroit.

Il est nécessaire pour que Hiera ne se rende pas à Vault en permanence, car elle parcourt toujours la hiérarchie. Ce n'est pas un problème ou une charge de Vault, mais une fonctionnalité de Hiera elle-même. Par conséquent, si vous ne laissez que le module pour Vault sans le backend du routeur, le maître Puppet prendra très longtemps pour collecter la configuration de l'agent Puppet, car il vérifiera chaque clé dans le coffre-fort.


Pour Puppet, le problème du poulet et des œufs est résolu du fait que la partie habilitante est le maître des marionnettes. C'est lui qui donne le secret pour accéder au secret. Le Puppet master a accès à tous les secrets à la fois, mais chaque hôte est autorisé à recevoir uniquement celui qui lui est destiné. L'hôte sur le Puppet master est déjà autorisé par son certificat, qui est généré localement et ne laisse pas les limites de l'hôte. En principe, le secret pour accéder au secret demeure, mais ce n'est pas si critique.

Notre processus de révélation d'un nouveau secret dans Puppet comprend les étapes suivantes.

  • Nous prenons un secret quelque part - quelqu'un nous le donne ou le dévoile.
  • Mettre un secret dans Vault, avec une hiérarchie comme dans Hiera: /puppet/role/www/site.ssl.key .
  • Nous enregistrons un préfixe dans le manifeste Puppet, indiquant que le fichier se trouve dans Vault et où l'obtenir.
  • Nous écrivons le chemin dans Vault en YAML pour le routeur Hiera et le backend afin que Hiera puisse le trouver.
  • Tirez la demande via GIT vers le référentiel de manifestes.
  • Exécutez ou attendez que l'agent Puppet s'exécute.

Des agents de marionnettes s'enfuient avec nous toutes les 30 minutes, vous devez donc attendre un peu jusqu'à ce que le secret soit dévoilé. Cela ne pose pas de problèmes - nous ne partageons pas tous les jours des secrets . Tant que Kubernetes n'est pas impliqué dans l'entreprise, il n'y a pas beaucoup de frais généraux et nous sommes prêts à divulguer des secrets dans Vault avec nos mains avec une automatisation minimale.

Un plus supplémentaire, nous obtenons la «puce» Hiera - le secret peut être défini immédiatement pour un groupe d'hôtes ou en fonction du rôle de l'hôte, que nous définissons dans le rôle variable.

Le seul danger : si vous avez Puppet et que vous utilisez Hiera, ne substituez rien aux modèles de variables, car de nombreux faits et variables sont collectés côté client. Si un attaquant substitue un fait au client, le maître des marionnettes lui donnera les secrets des autres. Assurez-vous de vérifier les variables : utilisez uniquement celles que le Puppet-master ne permet pas de déterminer du côté client.

Que faire avec SCM sans assistant?


Si, soudain, vous n'avez plus Puppet, alors très probablement Ansible. Pour Chef et autres SCM centralisés, leurs solutions sont un plugin pouvant accéder à Vault. J'offre plusieurs options qui peuvent être implémentées avec Ansible.

Agent local


Localement pour le serveur, générez un jeton, qui est en fait le mot de passe pour accéder au coffre-fort. Le jeton est valide tout le temps. Vous pouvez le mettre à jour ou l'automatiser. Avec ce jeton, vous allez dans Vault et emportez vos secrets.

L'idée est que sur votre serveur où vous devez livrer des secrets, l'agent qui vient dans Vault tourne, il regarde tous les secrets et les met sous forme de fichiers. Nous utilisons l'agent sur plusieurs serveurs distincts où il n'y a pas de marionnette.

Inconvénients:

  • Le jeton est facile à saisir dans un petit segment, mais si vous avez plusieurs dizaines de serveurs déployés par jour, vous devrez générer un jeton pour chaque serveur et prescrire une stratégie. C'est gênant.
  • Le jeton doit être mis à jour.
  • Le regroupement des serveurs par rôle, objectif ou faits est difficile, il doit être synchronisé avec Vault.

Cryptage de transit


Vault a une fonction de chiffrement de transit, dont l'essence est que Vault agit comme un serveur de chiffrement . Vous venez de lui apporter du texte en clair, et lui, sur sa clé privée, que lui seul possède, crypte et émet le texte fermé. Ensuite, vous choisissez qui peut déchiffrer ce texte fermé.

Ansible possède une entité, également appelée Vault. Ce n'est pas un coffre HashiCorp, mais un coffre Ansible . Il n'est pas nécessaire de confondre, et les secrets peuvent être stockés dans le premier et le second. Ansible a un plugin prêt à l'emploi pour livrer des secrets de Hashicorp Vault. Si vous accordez un accès personnel à Vault, vous pouvez décrypter les secrets. Lorsque vous lancez Ansible, il va à Vault en votre nom, déchiffre les secrets qui sont chiffrés dans le référentiel et le met en production.

Il y a aussi un inconvénient - chaque administrateur a accès aux secrets . Mais il y a un audit: Vault sait comment garder un journal d'activité sur quel utilisateur est entré, quel secret il a lu, lequel a eu accès. Vous savez toujours qui, quand et quoi a fait un secret. Cette option me semble bonne.

Big Flaw # 1


Le plus gros inconvénient qui nous cause le plus de peine est que dans Vault, vous ne pouvez déléguer le contrôle total à aucune partie des données à qui que ce soit. Dans Vault, l'accès au secret s'effectue de la même manière que dans UNIX - les noms sont généralement séparés par des barres obliques et le résultat est un "répertoire". Lorsque vous avez un tel chemin, vous voulez parfois prendre une partie du chemin et le donner à quelqu'un d'autre pour le contrôler.


Par exemple, vous avez obtenu des certificats, appelés / certs , et vous souhaitez les remettre à des agents de sécurité individuels qui traitent les PKI. Vault ne peut pas faire cela. Vous ne pouvez pas donner le droit d'émettre des droits à l'intérieur de ce préfixe - afin que les agents de sécurité eux-mêmes puissent distribuer les droits des certificats à quelqu'un d'autre.

Vault n'a pas la capacité d'accorder sélectivement des droits pour accorder des droits . Dès que vous avez donné le droit d'accorder des droits, vous avez également donné la possibilité d'accéder pleinement à tous les secrets. En d'autres termes, vous ne pouvez pas donner accès à la partie Vault.

C'est l'un des plus gros problèmes. J'ai une idée de comment le résoudre, je vous en parlerai plus tard.

Kubernetes


Chez RIT ++, j'ai parlé d'un système distinct que nous avons implémenté pour Kubernetes : il sert de tiers, va à l'API, vérifie l'accès et demande ensuite un secret dans Vault.

Maintenant, notre système a perdu de sa pertinence, car dans Vault 0.9, le support natif de Kubernetes est apparu. Maintenant, Vault lui-même sait comment se rendre à Kubernetes et s'assurer que l'accès au secret est autorisé. Il le fait avec un jeton de compte de service . Par exemple, lorsque vous avez déployé un module, il existe un JWT spécial, signé et autorisé pour celui-ci, conçu pour les demandes à l'API Kubernetes. Avec un jeton, vous pouvez également vous connecter à Vault et obtenir des secrets spécifiquement pour votre espace de noms.

Tout se fait au niveau de Vault lui-même. Certes, il sera nécessaire de démarrer un rôle pour chaque espace de noms, c'est-à-dire de dire à Vault qu'il existe un tel espace de noms, il y aura une autorisation et d'enregistrer où aller à Kubernetes. Cela est fait une fois, puis Vault ira à l'API elle-même, confirmera la validité du JWT et émettra son propre jeton d'accès.

Règles Kubernetes


En termes de nom de service et de métadonnées supplémentaires, nous faisons confiance aux développeurs. Il y a une petite chance que les développeurs obtiennent accidentellement ou intentionnellement les secrets d'autres services qui tournent dans un espace de noms, nous avons donc introduit une règle: un service - un espace de noms.

Nouveau microservice? Obtenez un nouvel espace de noms avec vos secrets. Vous ne pouvez pas traverser la frontière vers la voisine - ils ont leur propre jeton de compte de service. La frontière de sécurité à Kubernetes en ce moment est l'espace de noms. Si dans deux espaces de noms différents, vous avez besoin d'un secret - copiez-le.

Kubernetes a des secrets de kubernetes . Ils sont stockés dans etcd dans Kubernetes sous forme non chiffrée et peuvent «s'allumer» dans le tableau de bord ou lorsque kubectl get pods est démarré. Si l'authentification dans etcd est désactivée dans votre cluster, ou si vous avez accordé à quelqu'un un accès complet en lecture seule, tous les secrets lui sont visibles. C'est pourquoi nous avons introduit deux règles: il est interdit d'utiliser des secrets kubernetes et il est interdit de spécifier des secrets dans des variables d'environnement dans des manifestes . Si vous écrivez un secret dans l'environnement dans deployment.yaml, c'est mauvais, car le manifeste lui-même peut être vu par toute personne qui n'est pas paresseuse.

Livraison Kubernetes


Comme je l'ai dit, nous devons en quelque sorte mettre le fichier dans Kubernetes. Nous avons une sorte de secret: l'essence, le mot de passe, qui est écrit en JSON dans Vault. Comment le transformer en un fichier à l'intérieur du conteneur dans Kubernetes maintenant?


La première option de livraison.

  • Nous commençons un conteneur d'init spécial.
  • Cela part de notre image.
  • L'image contient un petit utilitaire qui va à Vault avec le jeton de compte de service, prend le secret et le place dans le volume partagé.
  • Pour l'utilitaire, un volume partagé spécial est monté uniquement dans la mémoire TMPFS afin que les secrets ne passent pas par le disque.
  • Init-container va dans Vault, met dans ce volume sous forme de fichiers tous les secrets qu'il trouve sur le chemin spécifié.
  • Ensuite, le volume partagé est monté dans le conteneur principal dans lequel il est requis.
  • Lorsque le conteneur principal est lancé, il obtient immédiatement ce dont le développeur a besoin - des secrets sous la forme d'un fichier sur disque.

Le développeur n'a qu'à se souvenir du chemin dans lequel se trouve son secret.

Nous utilisons quelque chose comme ce préfixe:

/k8s/<cluster>/<namespace>/<service>/some_secret 

Le nom du préfixe contient le nom du cluster, l'espace de noms et le nom du service. Chaque service a son propre secret, chaque espace de noms a son propre secret.

La deuxième option est votre propre point d'entrée . Nous y allons maintenant dans Avito, car les développeurs ont des problèmes avec init-container. Dans le diagramme, cette option est à droite.

Tout le monde ne peut pas se permettre son propre point d'entrée. Nous pouvons, donc dans chaque conteneur, nous forçons notre point d'entrée spécial.

Notre point d'entrée fait la même chose que init-container: il va dans Vault avec un jeton de compte de service, prend des secrets et les met à disposition. En plus des fichiers, il les remet dans l'environnement. Vous avez la possibilité d'exécuter l'application comme recommandé par le concept de l'application à douze facteurs : l'application prend tous les paramètres, y compris les secrets, des variables d'environnement.

Les variables d'environnement ne sont pas visibles dans le manifeste et le tableau de bord, car elles sont définies par PID 1 (le processus de conteneur principal) au démarrage. Ce ne sont pas des variables d'environnement de deployment.yaml, mais des variables d'environnement définies par point d'entrée dans le processus. Ils ne sont pas visibles dans le tableau de bord, ils ne sont pas visibles, même si vous faites exécuter kubectl dans un conteneur, car dans ce cas un autre processus est lancé, parallèle à PID1.

Workflow


D'un point de vue organisationnel, le processus est le suivant. Le développeur apprend du champion de la sécurité ou de la documentation qu'il ne doit pas garder de secrets dans le référentiel, mais uniquement dans Vault. Puis il vient vers nous et demande où mettre les secrets - il soumet une demande à la sécurité pour établir un préfixe. À l'avenir, vous pouvez créer un préfixe sans demande, immédiatement lors de la création d'un service.

Le développeur attend, et c'est mauvais, car l'essentiel pour lui est le time-to-market. Puis il lit les instructions, traite les longs fichiers - "insérez cette ligne là, insérez cette ligne ici". Un développeur n'a jamais démarré de conteneur d'initialisation auparavant, mais il est obligé de le découvrir et de l'enregistrer dans deployment.yaml (graphique de barre).

Commit -> deploy -> feel pain -> fix -> repeat

Il s'engage, attend que TeamCity se déploie, voit des erreurs dans TeamCity, commence à ressentir de la douleur, essaie de réparer quelque chose, éprouve à nouveau de la douleur. De plus, il est superposé que chaque déploiement dans TeamCity puisse toujours être mis en file d'attente. Parfois, un développeur ne peut pas le comprendre lui-même, vient à nous et nous le trions ensemble.

Fondamentalement, le développeur souffre de ses propres erreurs: init-container mal spécifié ou n'a pas lu la documentation .

La sécurité a également des problèmes. Le gardien de sécurité reçoit une application dans laquelle il y a toujours peu d'informations, et nous trouvons toujours les questions manquantes: trouver les noms des clusters, l'espace de noms du service, car le développeur ne les indique pas dans l'application et ne sait même pas toujours ce que c'est. Lorsque nous découvrons tout, créons des stratégies et des rôles dans Vault, prescrivons des stratégies aux groupes, et avec le développeur, nous commençons à découvrir où et pourquoi il a fait une erreur, et ensemble nous lisons les journaux.

L'unité «Architecture» permet de résoudre le problème en se cachant du développeur deployment.yaml. Ils développent une pièce qui génère tout pour le développeur, y compris le point d'entrée. Étant donné que nous substituons notre point d'entrée, nous pouvons l'utiliser non seulement pour livrer des secrets, mais aussi pour d'autres choses que vous devrez peut-être faire au démarrage.

Problèmes évidents avec les secrets de Kubernetes.


  • Flux de travail très compliqué pour le développeur et le gardien de sécurité.
  • Vous ne pouvez rien déléguer à personne. Le gardien de sécurité a un accès complet au coffre-fort et un accès partiel n'est pas possible (voir Big Flaw # 1).
  • Des difficultés surviennent lors du déplacement des développeurs d'un cluster à un autre, d'un espace de noms à un espace de noms, lorsque des secrets partagés sont nécessaires, car il est initialement supposé que différents secrets sont différents dans différents clusters.

Nous disons: «Pourquoi avez-vous besoin de secrets de production dans le cluster de développement? Obtenez un secret de test, allez-y! " En conséquence, il y a des mines et des secrets difficiles à gérer. Si le secret a changé, vous ne devez pas l'oublier, aller le changer partout, et bien qu'il n'y ait aucun moyen de déterminer qu'il s'agit du même secret, sauf par le nom du service.

Idée: Kubernetes KMS


Dans les nouvelles versions de Kubernetes, le sous-système KMS, Key Management Service, est une nouvelle fonctionnalité de chiffrement secret de Kubernetes. En v1.11, il était en état alpha, en v1.12, il a été transféré en version bêta.

L'image provient du site de projet du fournisseur KMS pour Vault et contient une erreur. Si vous trouvez - écrivez dans les commentaires.

Le sens de KMS est d'éliminer un seul inconvénient - le stockage de données non cryptées dans etcd.

KMS, comme Ansible, peut le faire.

  • Allez quelque part, cryptez le secret natif de Kubernetes et mettez-le sous forme cryptée.
  • Si nécessaire, livrez au pod, déchiffrez et mettez sous forme déchiffrée.

Les développeurs ont écrit un service spécial qui le fait en utilisant le cryptage de transit. L'idée semble fonctionner, mais il est important de se rappeler que les secrets cessent d'être uniquement sous le contrôle de Vault et vont ailleurs, dans le domaine de responsabilité des administrateurs de Kubernetes.

Contre KMS.

  • Décentralisation du stockage - Transfert de Vault à Kubernetes (etcd) . Les secrets deviennent incontrôlables par Vault, et c'est un bon dépôt centralisé de secrets. Il s'avère que la moitié des secrets de Vault et la moitié ailleurs.
  • Solution réservée à Kubernetes . Si vous avez une infrastructure réservée à Kubernetes, vous choisissez Vault et vous ne pensez presque pas à ce qui y est stocké, car il ne contient que les clés de chiffrement que vous gérez correctement - tournez régulièrement, etc ... Les secrets eux-mêmes sont dans Kubernetes, et c'est pratique.
  • Il est difficile de partager des secrets entre les clusters . Pour chaque nouveau cluster, vous devez tout recommencer, la copie des secrets comme dans le cas d'un seul coffre-fort peut ne pas fonctionner.

Avantages de KMS.

  • Prise en charge native dans Kubernetes, y compris le masquage lors de l'affichage de l'environnement.
  • Autorisation dans le domaine de responsabilité de Kubernetes .
  • Pratiquement aucun support Vault n'est requis .
  • Rotation des clés hors de la boîte .

CI / CD: TeamCity


Tout est simple dans TeamCity, car JetBrains a écrit un plug-in qui lui-même peut prescrire des secrets pour accéder au secret, les chiffrer avec TeamCity, puis le remplacer dans le modèle quelque part en tant que paramètre en pourcentage. À ce moment, l'agent TeamCity lui-même se rend dans Vault, prend le secret et l'apporte à la build comme paramètre.

Certains secrets sont nécessaires lors du déploiement, par exemple, la migration de la base de données ou des alertes dans Slack. AppRole est démarré pour chaque projet - les paramètres contiennent également un secret (données pour AppRole), mais il est entré en mode écriture seule - TeamCity ne permet pas de le lire plus tard.

TeamCity s'assure que lorsqu'un secret entre dans les journaux de build, il se déguise automatiquement. Par conséquent, le secret ne «passe» pas du tout sur le disque ou est effacé du disque à l'aide de TeamCity. En conséquence, toute la sécurité du secret est bien assurée par TeamCity lui-même et le plugin, et des danses supplémentaires avec un tambourin ne sont pas nécessaires

CI / CD n'est pas TeamCity?


Ce sont les principaux problèmes à considérer si vous utilisez un système différent (pas TeamCity) comme CI.

  • Isolement: limiter la portée d'un secret à un projet, une équipe, etc.
  • Qui autorise l'accès au secret.
  • Exclure la possibilité de consulter le secret de la partie autorisante.
  • Une étape distincte de la construction consiste à importer le secret dans des fichiers.
  • Nettoyez-vous après vous-même.

En conséquence, vous allez probablement écrire quelque chose de très similaire au plugin TeamCity pour votre CI / CD. La partie autorisée ici sera très probablement CI / CD, et ce sera elle qui décidera si cette version peut avoir accès à ce secret, et si elle doit ou non donner le secret lui-même en fonction des résultats.

Il est important de ne pas oublier de nettoyer les résultats de construction à la fin de l'assemblage , s'ils ont été disposés sur un disque, ou de s'assurer qu'ils ne sont qu'en mémoire.

Certifications


Il n'y a rien de spécial avec les certificats - nous utilisons Vault principalement pour leur stockage.


Vault dispose d'un backend PKI spécial pour l'émission de certificats, dans lequel vous pouvez créer une autorité de certification et signer de nouveaux certificats. Nous avons une PKI interne unique ... L'autorité de certification racine et l'autorité de certification de deuxième niveau existent séparément, et nous gérons déjà l'autorité de certification de troisième niveau via Vault. Pour stocker les certificats émis de tout niveau, y compris les certificats signés par des autorités de certification externes, nous utilisons un préfixe distinct et y mettons presque tous les certificats valides à des fins de comptabilité et de surveillance. Le format de stockage des certificats est propriétaire, adapté au stockage d'une clé privée distincte et du certificat lui-même.

Résumé


Trop de travail manuel pour le gardien de sécurité, trop de seuil d'entrée pour le développeur et pas d'outils de délégation intégrés, bien que je veuille vraiment ...

Comment être Alors les rêves commencent.

Idées: comment faire mieux


Comment puis-je me débarrasser d'un tas de copies d'un secret?

Livraison maître-esclave


Nous avons un maître secret et un démon spécial qui se promène, regarde le secret et ses métadonnées, le met là où c'est nécessaire, il se révèle être un secret d'esclave. Sur le chemin où le démon a posté l'esclave, rien ne peut être changé à la main, car le démon viendra et remettra le secret maître sur l'esclave.

Au début, nous voulions créer un mécanisme de lien symbolique pour simplement indiquer: «Cherchez ce secret là-bas!», Comme sous Linux. Il s'est avéré qu'il y avait des problèmes avec les droits d'accès: on ne sait pas comment vérifier les droits d'accès - comme sur Linux ou non, avec les chemins parent, avec les transitions entre les points de montage. Il y a trop de moments ambigus et de chances de faire une erreur, nous avons donc refusé les liens symboliques.

Autorisation de propriété


La deuxième chose que nous voulons faire est de déterminer le propriétaire de chaque secret . Par défaut, le secret appartient à la personne qui l'a créé. Si nécessaire, vous pouvez étendre la zone de responsabilité à l'unité en émettant un groupe de propriétaires.

Lorsque nous apprendrons à déléguer, nous donnerons au propriétaire le droit à un secret, et il pourra faire avec le secret ce qu'il veut.

  • Propagation en k8s - une politique est générée, une copie esclave est créée.
  • Réparties sur le serveur - une politique est générée, une copie esclave est créée.
  • Propagation en CI / CD - ...
  • Transfert à un autre propriétaire.
  • Donnez un nouvel accès, générez de nouvelles ACL.

Maintenant, nous sommes responsables de tous les secrets et de la sécurité, mais nous voulons transférer la responsabilité au créateur. La sécurité ne sera pas affectée , car la personne qui nous a demandé de garder un secret comprend qu'elle doit garder un secret en toute sécurité et est consciente de sa responsabilité.

Puisqu'il est le propriétaire du secret, pour l'option de livraison maître-esclave, il pourrait choisir où et dans quel format le secret devrait lui être livré. Il s'avère que le propriétaire gère tout lui-même, il n'est pas nécessaire de soumettre des demandes, vous pouvez prendre le préfixe nécessaire vous-même, vous pouvez également créer et supprimer des secrets vous-même.

Délégation via des modèles ACL


La stratégie d'accès à la liste de contrôle d'accès dans Vault est divisée en deux parties:

  • Liste de contrôle d'accès dans la vue classique, qui décrit l'accès au préfixe, la manière de lire et d'écrire, la lecture uniquement, etc.
  • Lors de la création d'une ACL à l'intérieur, vous pouvez écrire un astérisque à la fin, ce qui signifie "ce préfixe et tout ce qui se trouve en dessous". Le préfixe peut être attribué en tant qu'opération distincte, attribué à l'utilisateur ou au groupe, c'est-à-dire attaché à plusieurs entités différentes.

À l'heure actuelle, seul l'administrateur Vault peut modifier la liste de contrôle d'accès. Après avoir accédé à une telle ACL, vous pouvez prescrire tout ce que vous voulez à l'intérieur, par exemple, le path “*” { capabilities = [sudo, ...] } , et obtenir un accès complet. C'est l'essence de Biggest Flaw # 1 - il est impossible d'interdire de modifier le contenu de l'ACL.

Nous voulons définir les ACL avec un modèle prêt à l'emploi qui contient le chemin d'accès et les espaces réservés sur lesquels il est autorisé à générer de nouvelles ACL pour ce modèle.

Exemple


Vous trouverez ci-dessous la police jaune, le chemin d'accès de l'ACL standard terminée de Vault et les actions autorisées sur ce chemin. Nous le considérons comme une ACL pour l'autorisation de changer une autre ACL ci-dessous, qui est donnée sous la forme d'un modèle.


Nous voulons déléguer l'accès à / k8s, nous autorisons uniquement la génération de tels modèles. Par exemple, accordez un accès en lecture seule à un cluster, un espace de noms, un service spécifique, mais ne modifiez pas le champ des capacités.


De plus, nous voulons donner la permission de lier ces ACL et émettre différents droits.

Nous avons appliqué le modèle pour accorder des droits au développeur. Lors de la création de modèles, il a exécuté la commande $ vault write policy-mgr/create/k8s-microservice ... Et en conséquence, nous avons obtenu une ACL qui indique cluster = prod, namespace = ..., service = ... etc. Les droits ont été définis automatiquement, une stratégie a été créée avec le nom /k8s/some-srv - ce n'est que le nom ACL qui peut être généré à partir du modèle.


En conséquence, le développeur, à notre discrétion, attribue cette ACL à toute personne qui veut, et devient le propriétaire lui-même, peut le gérer en secret: supprimer, donner et retirer aux utilisateurs et aux groupes. Maintenant, la personne elle-même est responsable de son préfixe: elle gère tous les secrets, génère des ACL selon le modèle, peut attribuer des ACL à ceux qu'il veut. Naturellement, nous pouvons aussi le limiter.

Toute la magie fonctionne avec la nouvelle entité Vault - plugins . Il s'agit d'un service distinct, très similaire à celui que j'ai mentionné au début, et fonctionne presque exactement de la même manière. La seule différence importante est qu'ils ne sont pas des mandataires. Les plugins sont lancés «du côté» de Vault, et il lance leur principal processus Vault. Pour cette raison, toutes les demandes ne passent pas par le service, mais à Vault, qui lui-même interagit déjà avec le plug-in, lui envoyant une demande vérifiée et effacée.

À propos des plugins, comment ils sont organisés et comment les écrire, vous pouvez les lire sur le site Web de Vault . Il est préférable de les écrire sur Go, ce qui est assez simple, car Il existe un cadre pour Go. Vault communique avec le plugin via grpc, le lance en tant que service, mais n'ayez pas peur, vous ne le touchez pas - tout est déjà dans le cadre. Vous venez d'écrire une application REST plus ou moins standard dans laquelle vous spécifiez des points de terminaison, leur donnez des fonctions prêtes à l'emploi, des gestionnaires qui auront une logique sur eux.

N'ayez pas peur de casser quelque chose dans le coffre-fort principal. Un plugin est un service distinct. Même si votre plugin a paniqué et s'est écrasé, il ne cassera pas le travail de Vault. Vault redémarrera simplement le plugin et continuera de fonctionner.

De plus, il existe des paramètres supplémentaires pour le plugin lui-même: il vérifie toujours les sommes de hachage afin que personne ne modifie le binaire. La sécurité des plugins en cours d'exécution est assurée .

Liens utiles:



Nous parlerons de DevOps et de la sécurité, CI / CD, k8s, Puppet et tout cela dans HighLoad ++ (le plus proche de Saint-Pétersbourg en avril) et DevOpsConf . Venez partager votre expérience ou regarder les autres. Afin de ne pas oublier, abonnez-vous au blog et à la newsletter , dans lesquels nous vous rappellerons les dates limites et collecterons du matériel utile.

Source: https://habr.com/ru/post/fr438740/


All Articles