Auditarea bazelor de date la The Grid

Publicat: 2018-09-29

Deoarece SendGrid a devenit recent o companie cotată la bursă, trebuia să avem jurnalele de audit complete ale tuturor modificărilor aduse unui subset al bazelor noastre de date. Acest subset a inclus câteva cazuri mici care nu au văzut un volum mare de trafic, dar și câteva dintre grupurile noastre mai vechi, care sunt esențiale pentru timpul de funcționare al portalului pentru clienți și fluxul de înscriere.

Acest lucru a afectat, de asemenea, unele depozite de date care aveau cerințe mari de funcționare și era de dorit o lansare online (fără timpi de nefuncționare pentru scrieri). Cu un termen extern la îndemână și cunoscând domeniul de aplicare al proiectului, ne-am propus să facem un plan.

În faza de planificare, am identificat câteva întrebări deschise la care aveam nevoie de răspunsuri:

  1. Ce opțiuni avem în ceea ce privește software-ul care poate face acest lucru?
  2. Ce impact asupra performanței este de așteptat și cât de mult îl putem testa în avans?
  3. Putem face acest lucru fără timp de nefuncționare pentru disponibilitatea scrierii?

Alegeri, alegeri

La SendGrid, urmăm un proces de proiectare pentru orice proiect mare sau între echipe. Acest proiect a implicat un număr de echipe ca părți interesate, inclusiv:

  • Auditul intern ca echipă responsabilă de definirea depozitului de date care se află în domeniul de aplicare al acestui control al conformității și pentru colectarea dovezilor vine momentul auditului
  • InfoSec ca echipă care urma să analizeze și să gestioneze răspunsul la incident derivat din aceste jurnale de audit a bazei de date
  • DB Ops ca echipa care scrie codul care implementează, gestionează și ajustează această nouă caracteristică la bazele de date în domeniu

Mi-am propus să scriu acest plan și să mă asigur că a fost revizuit de toate părțile interesate și aprobat de echipa noastră de arhitectură. Chiar dacă făcusem câteva cercetări pe tema logării de audit în MySQL cu câțiva ani în urmă și aveam o idee despre cum arată peisajul opțiunilor, nu am vrut să abordez proiectul cu prejudecăți și am vrut totuși să investighez mai mult de una. opțiune și oferiți tuturor un caz solid de ce am alege o soluție în locul alta.

Acest plan era neobișnuit, deoarece îl scriam simultan în timp ce investigam care va fi soluția la nevoia de afaceri. Așa că știam că o mulțime de detalii urmau să fie completate pe măsură ce am făcut câteva cercetări.

Opțiunile noastre au fost:

  • Plugin de audit Percona
  • Audit Mcafee MySQL

Deși acestea nu sunt singurele opțiuni de pe piață, am simțit că sunt cele mai apropiate de scara noastră și de practicile de devops care să garanteze includerea în procesul de coacere. Alte opțiuni comerciale de pe piață nu au trecut de această bară pentru a fi incluse în benchmark.

Aceasta din urmă a fost o soluție mai nouă, deschisă recent de Mcafee și a fost suficient de interesantă pentru a fi analizată, deoarece pretindea că acceptă filtrarea la nivel de tabel, ceea ce pluginul Percona nu a făcut-o. Întrucât știam că unul dintre clusterele noastre în domeniu trebuie să auditeze aproximativ 24 de tabele dintr-un total de 300, aceasta părea a fi o caracteristică suficient de valoroasă pentru a face din pluginul Mcafee un candidat.

Pe de altă parte, pluginul Percona Audit a fost cea mai utilizată soluție open source pentru această caracteristică. Este încorporat, dar este dezactivat în Percona Server – pe care îl folosim deja. Cu toate acestea, nu oferă filtrare la nivel de tabel a evenimentelor, ceea ce a însemnat că trebuie să facem asta în afara stratului bazei de date.

Se coace

Cu ajutorul echipei noastre partenere de la Pythian, am început comparația de coacere. La început, am comparat cum să instalăm și să reglam fiecare opțiune. Echipa a stabilit rapid că avem un compromis pe mâini. Deși pluginul Mcafee a acceptat filtre de tabel în mod nativ, nu a acceptat utilizarea rsyslog ca metodă de transmitere a evenimentelor sale. Acest lucru însemna că, dacă ar fi să-l folosim, ar trebui să scriem fișierele local pe disc și să reușim să le trimitem la stiva de monitorizare.

Acest lucru nu a fost considerat de dorit, deoarece cel mai probabil ar crește penalizarea de performanță a utilizării pluginului de audit. Scrierea locală a evenimentelor de audit, apoi citirea lor din nou printr-un proces separat elimină capacitatea IOPS din traficul nostru real de producție și crește riscul pentru instanțele bazei de date, deoarece înseamnă că trebuie să gestionăm dimensiunea acestor fișiere de pe disc pentru ca nu cumva să se umfle și să provoace baza de date. timp de nefuncţionare.

Pe de altă parte a compromisului a fost pluginul Percona. Acceptă trimiterea evenimentelor către syslog în mod nativ, dar nu oferă niciun filtru de tabel. Știam că acest lucru însemna că clusterele mai aglomerate în domeniu vor trimite un număr mare de evenimente, dintre care majoritatea nu provin de fapt din tabele pe care dorim să le audităm. Acest lucru a prezentat un risc pentru stratul syslog-receive/logstash al stivei de monitorizare InfoSec. Deoarece DB ops nu are acces la asta, înseamnă că succesul acestui proiect a fost un efort de proprietate comună.

În cele din urmă, am decis să folosim soluția cu mai puține părți în mișcare și să ne planificăm implementarea pentru a ști cât mai curând posibil dacă logstash trebuie extins pentru a gestiona filtrarea a mii de evenimente pe secundă. Așa că a fost luată decizia de a merge mai departe cu pluginul de audit al Percona.

Planificarea desfășurării

Domeniul de instalare

Am decis să menținem această implementare simplă, instalând și activând pluginul pe toate nodurile dintr-un cluster dat, ceea ce a însemnat că am eliminat nevoia de orchestrare, pornind sau dezactivând facilitatea de audit atunci când nodul writer dintr-un cluster se schimbă. Nu am avut nicio îngrijorare cu privire la fluxul de replicare care cauzează evenimente duplicate pe măsură ce se aplică o modificare, deoarece pluginul, prin proiectare, nu înregistrează modificările fluxului de replicare.

Fără timp de nefuncționare

Am dorit ca aceasta să fie o implementare fără întreruperi, fără timpi de nefuncționare în clusterele afectate. Acest lucru ar reduce foarte mult cantitatea de planificare și orchestrare pe care ar trebui să o facem cu echipele de livrare care folosesc aceste clustere și ar reduce foarte mult impactul asupra clienților. Dar am vrut, de asemenea, ca pluginul să-și trimită evenimentele către rsyslog, pe o anumită facilitate, cu o configurație personalizată care să trimită evenimentele către serverul de agregare syslog al echipei InfoSec. Unele dintre aceste configurații sunt documentate ca fiind nedinamice de către Percona și acest lucru a prezentat posibilitatea ca fiecare instanță în domeniul de aplicare al acestui proiect să suporte o perioadă de nefuncționare pe măsură ce repornim instanța mysql cu configurația pluginului de audit necesară.

Am început să testăm diferite ordine de operare în implementarea plugin-ului cu o instanță de testare dedicată în mediul nostru de pregătire și am putut arăta că, dacă am avea managementul nostru de configurare, la început, am executat toate configurațiile necesare, apoi rulăm comanda load plugin , că comanda ar fi porniți cu configurația dorită.

Acest lucru s-a dovedit esențial atât pentru simplificarea planului de finalizare a acestui proiect, cât și pentru scurtarea timpului de lansare a acestuia în producție, oferindu-ne timp pentru a ajusta filtrarea evenimentelor și pentru a lucra cu echipa de securitate pentru analiză și detectare.

Utilizați gestionarea configurației

Folosim cărți de bucate pentru a ne gestiona bazele de date, așa că, evident, am plănuit să folosim chef pentru a implementa, regla și monitoriza pluginul de audit. Dar, deoarece acest lucru trebuia activat doar într-un subset al clusterelor noastre, aceasta însemna că aveam nevoie de o modalitate de a controla unde a fost activat, astfel încât să nu ne îngreunem stocarea jurnalelor cu date care nu sunt relevante pentru obiectivul nostru de afaceri aici.

Pentru gestionarea bazelor de date MySQL, folosim un model de carte de bucate wrapper pentru a gestiona configurația. O carte de bucate de bază „de bază” definește cea mai mare parte a modului în care ar trebui să arate instanța bazei de date, apoi o carte de bucate pe cluster o înfășoară pentru a modifica atributele sau pentru a adăuga configurație acolo unde este relevant pentru clusterul specific. Acest design a făcut ușor să adăugați cea mai mare parte a codului care ar crea fișierele de configurare necesare, apoi să încărcați pluginul într-o rețetă nouă pe care apoi o putem activa și dezactiva pe baza unui atribut de chef. De asemenea, am decis, având în vedere amploarea modificării pe care o facem, că acest lucru a justificat lansarea acestui cod ca o nouă versiune minoră a cărții de bucate.

De asemenea, ne-am asigurat că chef să elimine orice verificări sensu aferente și să dezactiveze fluxul de auditare atunci când atributul a fost setat la fals. Acest lucru a fost pentru a ne asigura că chef poate face lucrul corect dacă un cluster este considerat vreodată că nu mai este în domeniu sau trebuie oprit din orice motiv intermitent, deci nu trebuie să schimbăm manual un nod pentru a reflecta modificarea atributului.

Monitorizarea

Nu poți declara succesul a ceva ce nu monitorizezi. Dar, de asemenea, monitorizarea înseamnă mai mult decât simpla punere în aplicare a unor verificări sensuale fără a ne gândi la ce cazuri de eșec monitorizăm și la ce acțiuni ne așteptăm ca răspuns la eșecul acestor verificări într-o zi. Așa că mi-am propus să planific monitorizarea în această conductă având în vedere două lucruri

  • Trebuie să fim cu toții de acord asupra domeniului de aplicare explicit al proprietății în acest sistem, mai ales că se încadrează în responsabilitățile a două echipe cu rotații separate de gardă.
  • Orice verificări noi adăugate pentru această necesitate să vină cu un runbook la care facem legătura în verificare, explicând ce eșuează această verificare și cum să o remediem

Având în vedere aceste 2 reguli, am trecut la adăugarea unor verificări foarte specifice. În acest moment, m-am gândit să adaug și o verificare „sintetică” de la capăt la capăt, dar de atunci m-am abținut să fac asta, deoarece o verificare de la capăt la capăt aici nu ar reuși să ne spună exact care parte a sistemului a eșuat, ceea ce înseamnă că ne-ar fi greu. timp chiar și pentru a căuta echipa potrivită cu ea. Și nu sunt un susținător al apelării oamenilor noaptea „pentru orice eventualitate”

Am decis să monitorizăm următoarele:

  • Verificați configurația mysql live a pluginului de audit pentru a vă asigura că
    • Pluginul era în stare activă
    • Audit_log_policy a fost setat la QUERIES

Această verificare confirmă că configurația unei baze de date în domeniu nu a fost schimbată din mers, deoarece aceste setări sunt dinamice și s-ar putea modifica în afara fișierului my.cnf de pe disc.

  • Verificați portul pe care trimitem jurnalele către stiva de monitorizare pentru a vă asigura că datele circulă. Practic, asigurându-vă că celălalt capăt al fluxului syslog funcționează. Această verificare este tratată ca ceea ce sensul numește o verificare agregată, astfel încât să nu viziteze în mod flagrant echipa InfoSec

Obstacole pe parcurs

Verificați configurația pluginului

Una dintre iterațiile inițiale ale acestui proiect a intenționat să utilizeze funcția audit_log_exclude_commands pentru a limita evenimentele pe care le emitem doar la manipularea datelor sau a schemei. Am aflat rapid că lista pe care se bazează această configurație este mult mai lungă decât ne-am aștepta.

configurația rsyslog

Iată ceva ce nu știam înainte de acest proiect. Configurația Rsyslog este aproape propria limbă. De exemplu:

  • Utilizați un al doilea @ în fața destinației de la distanță pentru a trimite jurnalele prin TCP în loc de UDP. Am vrut să folosim această facilitate pentru a oferi puțin mai multă garanție că buștenii sunt livrați.
  • rsyslog are o pagină dedicată despre cum să-l configurezi pentru redirecționare fiabilă, care s-a dovedit cu adevărat utilă pentru un începător la instrument, cum ar fi mine.
  • rsyslog își va trimite, în mod implicit, datele la /var/log/messages, ceea ce nu era de dorit în cazul meu, deoarece acestea sunt O MULTE de evenimente. Dacă trebuie să faceți ca facilitatea pe care o utilizați NU face asta, trebuie să adăugați local5.* ~ la sfârșitul config.

Exercițiu de incendiu

Voi vorbi mai târziu despre implicațiile de performanță pentru bazele de date din domeniu, dar deoarece rsyslog a fost folosit ca o parte crucială pentru acest design, trebuia să declanșăm și cum se va comporta rsyslog atunci când destinația sa la distanță nu este disponibilă sau nu răspunde. Cea mai bună modalitate de a face acest lucru a fost să provoace întreruperea acelei comunicări folosind regulile iptables în producție pe una dintre bazele de date în domeniu despre care știam că avea un debit mare de tranzacții și, prin urmare, un volum mare de evenimente de audit pe secundă. Iată cum s-a desfășurat acel exercițiu de incendiu.

  • Confirmați că evenimentele de audit circulă peste portul TCP desemnat
  • Utilizați o regulă iptables pentru a elimina tot traficul de pe acel port /sbin/iptables -A OUTPUT -p tcp –dport {PORT-NUMBER-HERE} -j DROP
  • Urmăriți activitatea de scriere pe disc și fișierele din WorkDirectory configurat în configurația rsyslog. Numele fișierelor se vor baza pe ActionQueueFileName al unității care primește aceste evenimente

După cum era de așteptat, fișierele au început să fie spool în acest director. Am observat o creștere a activității IOP-urilor pe disc. Odată ce numărul de fișiere care defineau numele cozii a fost totalizat în dimensiune la valoarea ActionQueueMaxDiskSpace , rsyslog a încetat să creeze aceste fișiere, IOP-urile discului s-au normalizat și era clar că acum aruncăm evenimente pe podea în stratul rsyslog. Ceea ce a fost mai impresionant de urmărit a fost că, după ce am eliminat regula potabil, rsyslog a retrimis toate evenimentele pe care le-a spool pe disc, astfel încât să nu avem pierderi de evenimente pentru magazinul nostru de analize, atâta timp cât nu am depășit dimensiunea spool. Am învățat câteva lucruri pe baza acelui experiment

  • rsyslog se comportă conform documentelor. Întotdeauna mai bine să demonstrezi asta cu experimente de primă mână
  • Va trebui foarte probabil să definim un spațiu de disc diferit în coadă pentru fiecare cluster, în funcție de volumul de evenimente pe care fiecare le generează. Deoarece punerea în coadă pe disc adaugă risc la capacitatea IOP-urilor și a capacității discului, este un lucru pe care va trebui să îl revedem periodic și să-l reexaminăm

În următoarea postare, voi vorbi despre care au fost observațiile noastre după implementarea acestui proiect în producție și ce lucruri au făcut ca acest lucru să nu perturbe producția.