Prüfung von Datenbanken bei The Grid
Veröffentlicht: 2018-09-29Da SendGrid vor kurzem ein börsennotiertes Unternehmen wurde, benötigten wir vollständige Prüfprotokolle aller Änderungen an einer Teilmenge unserer Datenbanken. Diese Teilmenge umfasste einige kleine Instanzen, die keinen großen Datenverkehr verzeichneten, aber auch einige unserer älteren Cluster, die für die Betriebszeit unseres Kundenportals und den Anmeldefluss von entscheidender Bedeutung sind.
Dies wirkte sich auch auf einige Datenspeicher aus, die hohe Anforderungen an die Betriebszeit stellten und eine Online-Einführung (ohne Ausfallzeiten für Schreibvorgänge) wünschenswert war. Mit einer externen Deadline in der Hand und dem Umfang des Projekts kannten wir einen Plan.
In der Planungsphase identifizierten wir einige offene Fragen, auf die wir Antworten brauchten:
- Welche Optionen haben wir in Bezug auf Software, die dies tun kann?
- Welche Auswirkungen auf die Leistung werden erwartet und wie viel können wir das im Voraus testen?
- Können wir dies ohne Ausfallzeiten für die Schreibverfügbarkeit tun?
Entscheidungen, Entscheidungen
Bei SendGrid folgen wir einem Design-Blueprint-Prozess für alle großen oder teamübergreifenden Projekte. An diesem Projekt waren eine Reihe von Teams als Stakeholder beteiligt, darunter:
- Interne Revision als das Team, das für die Definition, welcher Datenspeicher in den Geltungsbereich dieser Compliance-Kontrolle fällt, und für die Sammlung von Nachweisen zum Zeitpunkt der Prüfung zuständig ist
- InfoSec als das Team, das die aus diesen Datenbank-Audit-Protokollen abgeleitete Reaktion auf Vorfälle analysieren und handhaben sollte
- DB Ops als das Team, das den Code schreibt, der diese neue Funktion für die Datenbanken im Geltungsbereich bereitstellt, verwaltet und optimiert
Ich machte mich daran, diesen Entwurf zu schreiben und sicherzustellen, dass er von allen Beteiligten überprüft und von unserem Architekturteam genehmigt wurde. Obwohl ich vor ein paar Jahren einige Nachforschungen zum Thema Audit-Logging in MySQL angestellt hatte und eine Vorstellung davon hatte, wie die Landschaft für Optionen aussah, wollte ich nicht mit Vorurteilen an das Projekt herangehen und dennoch mehr als eine untersuchen Option, und jedem einen soliden Grund liefern, warum wir eine Lösung einer anderen vorziehen würden.
Dieser Entwurf war insofern ungewöhnlich, als ich ihn gleichzeitig schrieb, während ich untersuchte, wie die Lösung für die Geschäftsanforderungen aussehen würde. Ich wusste also, dass viele Details ausgefüllt werden würden, während wir einige Nachforschungen anstellten.
Unsere Optionen waren:
- Percona-Audit-Plugin
- Mcafee MySQL-Audit
Dies sind zwar nicht die einzigen Optionen auf dem Markt, aber wir waren der Meinung, dass sie unserer Größenordnung und unseren Entwicklungspraktiken am nächsten kommen, um eine Einbeziehung in den eigentlichen Bake-Off zu rechtfertigen. Andere kommerzielle Optionen auf dem Markt haben diese Messlatte nicht überschritten, um in die Benchmark aufgenommen zu werden.
Letzteres war eine neuere Lösung, die erst kürzlich von Mcafee bezogen wurde, und war faszinierend genug, um sie sich anzusehen, da sie behauptete, Filterung auf Tabellenebene zu unterstützen, was das Percona-Plugin nicht tat. Da wir wussten, dass einer unserer In-Scope-Cluster tatsächlich etwa 24 Tabellen von insgesamt 300 prüfen musste, schien dies eine Funktion zu sein, die wertvoll genug war, um das Mcafee-Plugin zu einem Konkurrenten zu machen.
Andererseits war das Percona Audit-Plugin die am weitesten verbreitete Open-Source-Lösung für diese Funktion. Es ist in Percona Server integriert, aber deaktiviert – den wir bereits verwenden. Es bietet jedoch keine Filterung von Ereignissen auf Tabellenebene, was bedeutete, dass wir dies außerhalb der Datenbankschicht tun mussten.
Bake-off
Mit Hilfe unseres Partnerteams von Pythian haben wir den Bake-Off-Vergleich gestartet. Zuerst haben wir verglichen, wie jede Option installiert und eingestellt wird. Das Team stellte schnell fest, dass wir einen Kompromiss hatten. Während das Mcafee-Plugin Tabellenfilter nativ unterstützte, unterstützte es nicht die Verwendung von rsyslog als Methode zum Streamen seiner Ereignisse. Das bedeutete, dass wir, wenn wir es verwenden würden, die Dateien lokal auf die Festplatte schreiben und sie an den Überwachungsstapel senden müssten.
Dies wurde als nicht wünschenswert erachtet, da es höchstwahrscheinlich die Leistungseinbußen bei der Verwendung des Audit-Plugins erhöhen würde. Das lokale Schreiben der Audit-Ereignisse und das anschließende erneute Lesen durch einen separaten Prozess nimmt IOPS-Kapazität von unserem tatsächlichen Produktionsdatenverkehr weg und erhöht das Risiko für die Datenbankinstanzen, da wir die Größe dieser Dateien auf der Festplatte verwalten müssen, damit sie nicht aufgebläht werden und Datenbank verursachen Ausfallzeit.
Auf der anderen Seite war der Kompromiss das Percona-Plugin. Es unterstützt das native Senden der Ereignisse an Syslog, bietet jedoch keine Tabellenfilter. Wir wussten, dass die stärker ausgelasteten Cluster im Geltungsbereich eine große Anzahl von Ereignissen senden werden, von denen die meisten nicht aus Tabellen stammen, die wir prüfen möchten. Dies stellte ein Risiko für die Syslog-Empfangs-/Logstash-Schicht des Überwachungsstapels von InfoSec dar. Da DB ops keinen Zugriff darauf hat, bedeutete dies, dass der Erfolg dieses Projekts ein gemeinsames Unterfangen war.
Letztendlich haben wir uns entschieden, die Lösung mit weniger beweglichen Teilen zu verwenden und unsere Bereitstellung so zu planen, dass sie so früh wie möglich weiß, ob Logstash skaliert werden muss, um Tausende von Ereignissen pro Sekunde zu filtern. Daher wurde die Entscheidung getroffen, mit dem Audit-Plugin von Percona fortzufahren.
Einsatzplanung
Installationsumfang
Wir haben uns entschieden, diese Bereitstellung einfach zu halten, indem wir das Plugin auf allen Knoten in einem bestimmten Cluster installiert und aktiviert haben, was bedeutet, dass wir die Notwendigkeit beseitigt haben, die Audit-Funktion zu orchestrieren, wenn sich der Writer-Knoten in einem Cluster ein- oder ausschaltet. Wir hatten keine Bedenken, dass der Replikationsstream doppelte Ereignisse verursacht, wenn eine Änderung angewendet wird, da das Plug-in standardmäßig keine Änderungen des Replikationsstreams aufzeichnet.
Keine Ausfallzeiten
Wir wollten dies zu einer nahtlosen Bereitstellung ohne Ausfallzeiten in den betroffenen Clustern machen. Dies würde den Planungs- und Orchestrierungsaufwand für die Bereitstellungsteams, die diese Cluster verwenden, erheblich reduzieren und die Auswirkungen auf die Kunden erheblich reduzieren. Aber wir wollten auch, dass das Plugin seine Ereignisse an rsyslog auf einer bestimmten Einrichtung mit einer benutzerdefinierten Konfiguration sendet, die die Ereignisse an den Syslog-Aggregationsserver des InfoSec-Teams sendet. Einige dieser Konfigurationen werden von Percona als nicht dynamisch dokumentiert und dies stellte die Möglichkeit dar, dass jede Instanz im Umfang dieses Projekts einige Ausfallzeiten verursachen würde, wenn wir die MySQL-Instanz mit der erforderlichen Audit-Plugin-Konfiguration neu starten.
Wir begannen mit dem Testen verschiedener Betriebsreihenfolgen beim Bereitstellen des Plugins mit einer dedizierten Testinstanz in unserer Staging-Umgebung und konnten zeigen, dass, wenn unser Konfigurationsmanagement alle erforderlichen Konfigurationen zuerst anlegen und dann den Befehl zum Laden des Plugins ausführen würde, der Befehl dies tun würde Starten Sie mit der gewünschten Konfiguration.
Dies erwies sich als maßgeblich, um sowohl den Plan für den Abschluss dieses Projekts zu vereinfachen als auch die Zeit bis zur Veröffentlichung in der Produktion zu verkürzen, uns Zeit für die Feinabstimmung der Ereignisfilterung zu verschaffen und mit dem Sicherheitsteam an Analyse und Erkennung zu arbeiten.
Verwenden Sie das Konfigurationsmanagement
Wir verwenden Chef-Kochbücher, um unsere Datenbanken zu verwalten, also planten wir offensichtlich, Chef zum Bereitstellen, Optimieren und Überwachen des Audit-Plugins zu verwenden. Da dies jedoch nur in einer Teilmenge unserer Cluster aktiviert werden musste, bedeutete dies, dass wir eine Möglichkeit brauchten, um zu steuern, wo es aktiviert wurde, um unseren Protokollspeicher nicht mit Daten zu belasten, die für unser Geschäftsziel hier nicht relevant sind.
Für die Verwaltung von MySQL-Datenbanken verwenden wir ein Wrapper-Cookbook-Modell, um die Konfiguration zu verwalten. Ein zentrales „Basis“-Kochbuch definiert den Großteil dessen, wie die Datenbankinstanz aussehen sollte, und ein Kochbuch pro Cluster umschließt dies, um Attribute zu ändern oder Konfigurationen hinzuzufügen, wo dies für den spezifischen Cluster relevant ist. Dieses Design machte es einfach, den Großteil des Codes hinzuzufügen, der die erforderlichen Konfigurationsdateien erstellen würde, und dann das Plugin in einem neuen Rezept zu laden, das wir dann basierend auf einem Kochattribut ein- und ausschalten können. Wir entschieden auch angesichts des Umfangs der von uns vorgenommenen Änderung, dass dies die Veröffentlichung dieses Codes als neue Nebenversion des Kochbuchs rechtfertigte.
Wir haben auch dafür gesorgt, dass chef alle zugehörigen Sensu-Prüfungen entfernt und das Audit-Streaming deaktiviert, wenn das Attribut auf „false“ gesetzt war. Dadurch sollte sichergestellt werden, dass Chef das Richtige tun kann, wenn ein Cluster jemals als nicht mehr im Geltungsbereich gilt oder aus irgendeinem zeitweiligen Grund gestoppt werden musste, sodass wir einen Knoten nicht manuell ändern müssen, um die Attributänderung widerzuspiegeln.
Überwachung
Sie können den Erfolg von etwas nicht erklären, das Sie nicht überwachen. Aber auch Überwachung ist mehr als nur ein paar sensu-Checks zu machen, ohne darüber nachzudenken, auf welche Fehlerfälle wir überwachen und welche Maßnahmen wir erwarten, wenn diese Checks eines Tages fehlschlagen. Also machte ich mich daran, die Überwachung in dieser Pipeline zu planen, wobei ich zwei Dinge im Hinterkopf hatte
- Wir müssen uns alle auf einen ausdrücklichen Umfang der Eigentumsverhältnisse in diesem System einigen, zumal es die Verantwortlichkeiten von 2 Teams mit separaten Bereitschaftsrotationen überspannt
- Alle neuen Prüfungen, die dafür hinzugefügt werden, müssen mit einem Runbook geliefert werden, auf das wir in der Prüfung verlinken und erklären, was bei dieser Prüfung fehlschlägt und wie es behoben werden kann
In Anbetracht dieser beiden Regeln habe ich dann sehr spezifische Überprüfungen hinzugefügt. An diesem Punkt habe ich darüber nachgedacht, auch eine „synthetische“ End-to-End-Prüfung hinzuzufügen, aber ich habe seitdem davon Abstand genommen, da eine End-to-End-Prüfung hier uns nicht genau sagen würde, welcher Teil des Systems ausgefallen ist, was bedeutet, dass wir ein hartes Problem hätten Zeit, sogar das richtige Team damit anzurufen. Und ich bin kein Befürworter des nächtlichen Pagings, „nur für den Fall“.
Wir haben uns entschieden, Folgendes zu überwachen:
- Überprüfen Sie die Live-Mysql-Konfiguration des Audit-Plugins, um dies sicherzustellen
- Das Plugin war im aktiven Zustand
- Die audit_log_policy wurde auf QUERIES gesetzt
Diese Prüfung bestätigt, dass die Konfiguration einer Datenbank im Gültigkeitsbereich nicht spontan geändert wurde, da diese Einstellungen dynamisch sind und sich außerhalb der Datei my.cnf auf der Festplatte ändern könnten .
- Überprüfen Sie den Port, auf dem wir Protokolle an den Überwachungsstapel senden, um sicherzustellen, dass Daten fließen. Stellen Sie grundsätzlich sicher, dass das andere Ende des Syslog-Streams funktioniert. Diese Prüfung wird so gehandhabt, als würde sie eine aggregierte Prüfung nennen , damit sie das InfoSec-Team nicht ungeheuerlich ausruft
Hürden auf dem Weg
Audit-Plugin-Konfiguration
Eine der ersten Iterationen dieses Projekts zielte darauf ab, die Funktion „audit_log_exclude_commands“ zu nutzen , um die von uns ausgegebenen Ereignisse auf Daten- oder Schemamanipulationen zu beschränken. Wir haben schnell festgestellt, dass die Liste, auf der diese Konfiguration basiert, viel länger ist, als man erwarten würde.
rsyslog-Konfiguration
Hier ist etwas, was ich vor diesem Projekt nicht wusste. Die Rsyslog-Konfiguration ist fast eine eigene Sprache. Zum Beispiel:
- Verwenden Sie ein zweites @ vor dem Remote-Ziel, um Protokolle über TCP statt UDP zu senden. Wir wollten diese Einrichtung nutzen, um ein wenig mehr Garantie dafür zu geben, dass Protokolle geliefert werden.
- rsyslog hat eine spezielle Seite , wie man es für eine zuverlässige Weiterleitung konfiguriert, was sich für einen Neuling des Tools wie mich als sehr nützlich erwiesen hat.
- rsyslog wird seine Daten standardmäßig auch an /var/log/messages senden , was in meinem Fall unerwünscht war, da dies eine Menge Ereignisse sind. Wenn Sie die von Ihnen verwendete Einrichtung dazu bringen müssen, dies NICHT zu tun, müssen Sie local5.* ~ am Ende Ihrer Konfiguration hinzufügen
Feuerübung
Ich werde später über die Leistungsauswirkungen für die Datenbanken im Geltungsbereich sprechen, aber da rsyslog als entscheidender Bestandteil für dieses Design verwendet wurde, mussten wir auch eine Feuerübung durchführen, wie sich rsyslog verhalten würde, wenn sein Remote-Ziel nicht verfügbar ist oder nicht antwortet. Der beste Weg, dies zu tun, bestand darin, diese Kommunikation mithilfe von iptables-Regeln in der Produktion auf einer der Datenbanken im Geltungsbereich zu unterbrechen, von denen wir wussten, dass sie einen hohen Transaktionsdurchsatz und daher eine große Anzahl von Audit-Ereignissen pro Sekunde hatten. So lief diese Feuerwehrübung ab.
- Bestätigen Sie, dass Überwachungsereignisse über den angegebenen TCP-Port fließen
- Verwenden Sie eine iptables-Regel, um den gesamten Datenverkehr auf diesem Port zu löschen /sbin/iptables -A OUTPUT -p tcp –dport {PORT-NUMBER-HERE} -j DROP
- Beobachten Sie die Festplattenschreibaktivität und Dateien im konfigurierten WorkDirectory in der Konfiguration von rsyslog. Die Dateinamen basieren auf dem ActionQueueFileName der Einrichtung, die diese Ereignisse empfängt
Wie erwartet begann das Spoolen von Dateien in diesem Verzeichnis. Wir haben einen Anstieg der Festplatten-IOPs-Aktivität festgestellt. Nachdem die Anzahl der Dateien, die den Warteschlangennamen definierten, in der Größe auf den Wert von ActionQueueMaxDiskSpace summiert wurde, hörte rsyslog auf, diese Dateien zu erstellen, die Datenträger-IOPs normalisierten sich und es war klar, dass wir jetzt Ereignisse auf dem Boden in der rsyslog-Schicht löschen. Was noch beeindruckender war, war, dass rsyslog nach dem Entfernen der Potable-Regel alle Ereignisse erneut sendete, die es auf die Festplatte gespoolt hatte, sodass wir keinen Verlust von Ereignissen für unseren Analysespeicher hatten, solange wir die Spool-Größe nicht überschritten. Basierend auf diesem Experiment haben wir ein paar Dinge gelernt
- rsyslog verhält sich wie dokumentiert. Es ist immer besser, das mit Experimenten aus erster Hand zu beweisen
- Wir werden sehr wahrscheinlich einen anderen Speicherplatz für die Warteschlange pro Cluster definieren müssen, abhängig von der Menge der Ereignisse, die jeder generiert. Da die Warteschlange auf der Festplatte ein Risiko für die IOPs-Kapazität und die Festplattenkapazität darstellt, müssen wir dies regelmäßig überprüfen und erneut untersuchen
Im nächsten Beitrag werde ich darüber sprechen, was unsere Beobachtungen waren, nachdem wir dieses Projekt in der Produktion bereitgestellt hatten, und was dies für die Produktion so unterbrechungsfrei wie möglich gemacht hat.