Audit des bases de données sur The Grid
Publié: 2018-09-29Comme SendGrid est récemment devenue une société cotée en bourse, nous avions besoin de journaux d'audit complets de toutes les modifications apportées à un sous-ensemble de nos bases de données. Ce sous-ensemble comprenait quelques petites instances qui n'ont pas vu un volume de trafic important, mais également certains de nos clusters plus anciens qui sont essentiels à la disponibilité de notre portail client et au flux d'inscription.
Cela a également eu un impact sur certaines banques de données qui avaient des demandes de disponibilité élevées et un déploiement en ligne (sans temps d'arrêt pour les écritures) était souhaitable. Avec une échéance externe à portée de main et connaissant la portée du projet, nous avons décidé d'établir un plan.
Lors de la phase de planification, nous avons identifié quelques questions ouvertes auxquelles nous avions besoin de réponses :
- Quelles options avons-nous en ce qui concerne les logiciels qui peuvent le faire ?
- Quel impact sur les performances est attendu et dans quelle mesure pouvons-nous le tester à l'avance ?
- Pouvons-nous le faire sans temps d'arrêt pour la disponibilité en écriture ?
Des choix, des choix
Chez SendGrid, nous suivons un processus de conception pour tout projet de grande envergure ou inter-équipes. Ce projet a impliqué un certain nombre d'équipes en tant que parties prenantes, notamment :
- Audit interne en tant qu'équipe chargée de définir quel magasin de données est concerné par ce contrôle de conformité et de collecter des preuves au moment de l'audit
- InfoSec en tant qu'équipe chargée d'analyser et de gérer la réponse aux incidents dérivée de ces journaux d'audit de base de données
- DB Ops en tant qu'équipe écrivant le code qui déploie, gère et adapte cette nouvelle fonctionnalité aux bases de données concernées
J'ai entrepris d'écrire ce plan et de m'assurer qu'il a été examiné par toutes les parties prenantes et approuvé par notre équipe d'architecture. Même si j'avais fait des recherches sur le sujet de la journalisation d'audit dans MySQL il y a quelques années et que j'avais une idée de ce à quoi ressemblait le paysage des options, je ne voulais pas aborder le projet avec des préjugés et je voulais toujours enquêter sur plus d'un option, et fournissez à chacun un argumentaire solide expliquant pourquoi nous choisirions une solution plutôt qu'une autre.
Ce plan était inhabituel dans la mesure où je l'écrivais simultanément tout en recherchant quelle allait être la solution au besoin de l'entreprise. Je savais donc que beaucoup de détails allaient être remplis au fur et à mesure que nous faisions des recherches.
Nos options étaient :
- Module d'audit Percona
- Audit McAfee MySQL
Bien que ce ne soient pas les seules options sur le marché, nous avons estimé qu'elles étaient les plus proches de notre échelle et des pratiques devops pour justifier d'être incluses dans le bake-off réel. D'autres options commerciales sur le marché n'ont pas franchi cette barre pour être incluses dans l'indice de référence.
Cette dernière était une solution plus récente qui n'avait été ouverte que récemment par Mcafee et était suffisamment intrigante pour être examinée car elle prétendait prendre en charge le filtrage au niveau de la table, ce que le plug-in Percona ne faisait pas. Étant donné que nous savions que l'un de nos clusters concernés avait en fait besoin d'auditer environ 24 tables sur un total de 300, cela semblait être une fonctionnalité suffisamment précieuse pour faire du plugin Mcafee un concurrent.
D'autre part, le plugin Percona Audit était la solution open source la plus utilisée pour cette fonctionnalité. Il est intégré mais désactivé dans Percona Server, que nous utilisons déjà. Cependant, il ne fournit pas de filtrage des événements au niveau de la table, ce qui signifie que nous devions le faire en dehors de la couche de base de données.
Patisserie
Avec l'aide de notre équipe partenaire chez Pythian, nous avons commencé la comparaison des cuissons. Au début, nous avons comparé comment installer et régler chaque option. L'équipe a rapidement déterminé que nous avions un compromis à faire. Alors que le plug-in Mcafee prenait en charge les filtres de table de manière native, il ne prenait pas en charge l'utilisation de rsyslog comme méthode de diffusion de ses événements. Cela signifiait que si nous devions l'utiliser, nous devions écrire les fichiers localement sur le disque et gérer leur envoi vers la pile de surveillance.
Cela n'a pas été jugé souhaitable car cela augmenterait très probablement la pénalité de performance liée à l'utilisation du plug-in d'audit. L'écriture locale des événements d'audit, puis leur lecture à nouveau par un processus séparé, supprime la capacité IOPS de notre trafic de production réel et augmente le risque pour les instances de base de données, car cela signifie que nous devons gérer la taille de ces fichiers sur le disque, de peur qu'ils ne gonflent et ne causent la base de données. temps d'arrêt.
D'autre part du compromis était le plugin Percona. Il prend en charge l'envoi natif des événements vers syslog mais n'offre aucun filtre de table. Nous savions que cela signifiait que les clusters les plus occupés enverraient un grand nombre d'événements, dont la plupart ne proviennent pas réellement des tables que nous souhaitons auditer. Cela présentait un risque pour la couche syslog-receive/logstash de la pile de surveillance d'InfoSec. Étant donné que DB ops n'y a pas accès, cela signifie que le succès de ce projet était une entreprise de propriété partagée.
En fin de compte, nous avons décidé d'utiliser la solution avec moins de pièces mobiles et de planifier notre déploiement pour savoir le plus tôt possible si logstash devait être mis à l'échelle pour gérer le filtrage de milliers d'événements par seconde. La décision a donc été prise d'aller de l'avant avec le plugin d'audit de Percona.
Planification du déploiement
Portée de l'installation
Nous avons décidé de garder ce déploiement simple en installant et en activant le plug-in sur tous les nœuds d'un cluster donné, ce qui signifie que nous avons éliminé le besoin d'orchestrer l'activation ou la désactivation de la fonction d'audit lorsque le nœud écrivain d'un cluster change. Nous n'avions aucune inquiétude concernant le flux de réplication provoquant des événements en double lorsqu'une modification est appliquée car le plug-in, de par sa conception, n'enregistre pas les modifications du flux de réplication.
Pas de temps d'arrêt
Nous voulions en faire un déploiement transparent sans temps d'arrêt dans les clusters concernés. Cela réduirait considérablement la quantité de planification et d'orchestration que nous aurions à faire avec les équipes de livraison utilisant ces clusters et réduirait considérablement l'impact sur les clients. Mais nous voulions également que le plug-in envoie ses événements à rsyslog, sur une installation spécifique, avec une configuration personnalisée qui enverrait les événements au serveur d'agrégation syslog de l'équipe InfoSec. Certaines de ces configurations sont documentées comme non dynamiques par Percona et cela présentait la possibilité que chaque instance dans le cadre de ce projet subisse des temps d'arrêt lorsque nous redémarrons l'instance mysql avec la configuration de plug-in d'audit requise.
Nous avons commencé à tester différents ordres de fonctionnement lors du déploiement du plug-in avec une instance de test dédiée dans notre environnement de test et avons pu montrer que si notre gestion de la configuration posait d'abord toutes les configurations nécessaires, puis exécutait la commande load plugin , que la commande serait démarrer avec la configuration souhaitée.
Cela s'est avéré déterminant à la fois pour simplifier le plan de réalisation de ce projet et pour raccourcir le délai de mise en production, nous faire gagner du temps pour affiner le filtrage des événements et travailler avec l'équipe de sécurité sur l'analyse et la détection.
Utiliser la gestion de configuration
Nous utilisons des livres de recettes de chef pour gérer nos bases de données, nous avons donc prévu d'utiliser chef pour déployer, régler et surveiller le plug-in d'audit. Mais comme cela ne devait être activé que dans un sous-ensemble de nos clusters, cela signifiait que nous avions besoin d'un moyen de contrôler où il était activé afin de ne pas encombrer notre stockage de journaux avec des données non pertinentes pour notre objectif commercial ici.
Pour gérer les bases de données MySQL, nous utilisons un modèle de livre de recettes wrapper pour gérer la configuration. Un livre de recettes "de base" définit l'essentiel de l'apparence de l'instance de base de données, puis un livre de recettes par cluster l'enveloppe pour modifier les attributs ou ajouter une configuration, le cas échéant, au cluster spécifique. Cette conception a facilité l'ajout de la majeure partie du code qui créerait les fichiers de configuration nécessaires, puis chargerait le plug-in dans une nouvelle recette que nous pouvons ensuite activer et désactiver en fonction d'un attribut chef. Nous avons également décidé, compte tenu de l'ampleur du changement que nous apportions, que cela justifiait la publication de ce code en tant que nouvelle version mineure du livre de recettes.
Nous nous sommes également assurés que le chef supprime toutes les vérifications sensu associées et désactive le streaming d'audit lorsque l'attribut était défini sur faux. Il s'agissait de s'assurer que le chef peut faire ce qu'il faut si un cluster est considéré comme n'étant plus dans la portée ou doit être arrêté pour une raison intermittente, nous n'avons donc pas besoin de modifier manuellement un nœud afin de refléter le changement d'attribut.
Surveillance
Vous ne pouvez pas déclarer le succès de quelque chose que vous ne surveillez pas. Mais la surveillance ne se limite pas à effectuer des vérifications sensu sans réfléchir aux cas d'échec que nous surveillons et à l'action que nous attendons en réponse à l'échec de ces vérifications un jour. J'ai donc entrepris de planifier la surveillance dans ce pipeline avec 2 choses à l'esprit
- Nous devons tous nous mettre d'accord sur la portée explicite de la propriété dans ce système, d'autant plus qu'il chevauche les responsabilités de 2 équipes avec des rotations d'astreinte distinctes
- Toute nouvelle vérification ajoutée pour cela doit être accompagnée d'un runbook auquel nous lions dans la vérification, expliquant ce sur quoi cette vérification échoue et comment y remédier
Compte tenu de ces 2 règles, j'ai procédé à l'ajout de contrôles très spécifiques. À ce stade, j'ai également envisagé d'ajouter une vérification `` synthétique '' de bout en bout, mais je me suis abstenu de le faire car une vérification de bout en bout échouerait ici à nous dire exactement quelle partie du système a échoué, ce qui signifie que nous aurions un dur temps même de paginer la bonne équipe avec. Et je ne suis pas partisan d'appeler les gens la nuit "juste au cas où"
Nous avons décidé de surveiller les éléments suivants :
- Vérifiez la configuration mysql en direct du plugin d'audit pour vous assurer que
- Le plugin était à l'état actif
- audit_log_policy a été défini sur QUERIES
Cette vérification confirme qu'une base de données dans la portée n'a pas vu sa configuration modifiée à la volée puisque ces paramètres sont dynamiques et peuvent changer en dehors du fichier my.cnf sur le disque .
- Vérifiez le port sur lequel nous envoyons les journaux à la pile de surveillance pour vous assurer que les données circulent. Fondamentalement, assurez-vous que l'autre extrémité du flux syslog fonctionne. Cette vérification est traitée comme ce que le sens appelle une vérification agrégée afin qu'elle ne signale pas de manière flagrante l'équipe InfoSec
Obstacles le long du chemin
Vérification de la configuration du plug-in
L'une des premières itérations de ce projet visait à tirer parti de la fonctionnalité audit_log_exclude_commands pour limiter les événements que nous émettons à la seule manipulation de données ou de schéma. Nous avons rapidement appris que la liste sur laquelle cette configuration est basée est beaucoup plus longue que ce à quoi on pourrait s'attendre.
configuration rsyslog
Voici quelque chose que je ne savais pas avant ce projet. La configuration de Rsyslog est presque son propre langage. Par exemple:
- Utilisez un deuxième @ devant la destination distante pour envoyer les journaux via TCP au lieu d'UDP. Nous voulions utiliser cette fonctionnalité pour donner un peu plus de garantie que les grumes sont livrées.
- rsyslog a une page dédiée sur la façon de le configurer pour un transfert fiable, ce qui s'est avéré très utile pour un débutant dans l'outil comme moi.
- rsyslog, par défaut, transmettra également ses données à /var/log/messages, ce qui n'était pas souhaitable dans mon cas car il s'agit de BEAUCOUP d'événements. Si vous devez faire en sorte que l'installation que vous utilisez ne le fasse PAS, vous devez ajouter local5.* ~ à la fin de votre configuration
Exercice d'incendie
Je parlerai plus tard des implications en termes de performances pour les bases de données concernées, mais comme rsyslog était utilisé comme un élément crucial pour cette conception, nous devions également déterminer comment rsyslog se comporterait lorsque sa destination distante n'est pas disponible ou ne répond pas. La meilleure façon d'y parvenir était de perturber cette communication en utilisant des règles iptables en production sur l'une des bases de données dont nous savions qu'elle avait un débit de transactions élevé et donc un grand volume d'événements d'audit par seconde. Voici comment s'est déroulé cet exercice d'incendie.
- Confirmer que les événements d'audit circulent sur le port TCP désigné
- Utilisez une règle iptables pour supprimer tout le trafic sur ce port /sbin/iptables -A OUTPUT -p tcp –dport {PORT-NUMBER-HERE} -j DROP
- Surveillez l'activité d'écriture sur disque et les fichiers dans le WorkDirectory configuré dans la configuration de rsyslog. Les noms de fichiers seront basés sur l' ActionQueueFileName de l'établissement recevant ces événements
Comme prévu, les fichiers ont commencé à être mis en file d'attente dans ce répertoire. Nous avons constaté un pic d'activité des IOP de disque. Une fois que le nombre de fichiers définissant le nom de la file d'attente a atteint la valeur de ActionQueueMaxDiskSpace , rsyslog a cessé de créer ces fichiers, les IOP de disque se sont normalisées et il était clair que nous supprimions maintenant les événements par terre dans la couche rsyslog. Ce qui était plus impressionnant à observer, c'est qu'après avoir supprimé la règle potable, rsyslog renvoyait tous les événements qu'il avait mis en file d'attente sur le disque, de sorte que nous n'avions aucune perte d'événements pour notre magasin d'analyse tant que nous ne dépassions pas la taille de la file d'attente. Nous avons appris quelques choses sur la base de cette expérience
- rsyslog se comporte comme documenté. Toujours mieux de le prouver avec des expériences de première main
- Nous aurons très probablement besoin de définir un espace disque de file d'attente différent par cluster en fonction du volume d'événements que chacun génère. Étant donné que la mise en file d'attente sur disque ajoute un risque à la capacité des IOP et à la capacité du disque, c'est une chose que nous devrons revoir périodiquement et réexaminer
Dans le prochain article, je parlerai de nos observations après le déploiement de ce projet en production et de ce qui a rendu cela aussi peu perturbateur que possible pour la production.