Auditoría de bases de datos en The Grid

Publicado: 2018-09-29

Como SendGrid se convirtió recientemente en una empresa que cotiza en bolsa, necesitábamos tener registros de auditoría completos de todos los cambios en un subconjunto de nuestras bases de datos. Este subconjunto incluía algunas instancias pequeñas que no vieron un gran volumen de tráfico, pero también algunos de nuestros clústeres más antiguos que son fundamentales para el tiempo de actividad de nuestro portal de clientes y el flujo de registro.

Esto también afectó a algunos almacenes de datos que tenían altas demandas de tiempo de actividad y era deseable una implementación en línea (sin tiempo de inactividad para escrituras). Con un plazo externo a la mano y conociendo el alcance del proyecto, nos dispusimos a realizar un plan.

En la fase de planificación, identificamos algunas preguntas abiertas para las que necesitábamos respuestas:

  1. ¿Qué opciones tenemos en cuanto a software que pueda hacer esto?
  2. ¿Qué impacto en el rendimiento se espera y cuánto podemos probar eso por adelantado?
  3. ¿Podemos hacer esto sin tiempo de inactividad para la disponibilidad de escritura?

Elecciones, elecciones

En SendGrid, seguimos un proceso de anteproyecto de diseño para cualquier proyecto grande o entre equipos. Este proyecto involucró a varios equipos como partes interesadas, entre ellos:

  • Auditoría interna como el equipo a cargo de definir qué almacén de datos está dentro del alcance de este control de cumplimiento y de recopilar evidencia en el momento de la auditoría.
  • InfoSec como el equipo que debía analizar y manejar la respuesta a incidentes derivada de estos registros de auditoría de la base de datos
  • DB Ops como el equipo que escribe el código que implementa, administra y ajusta esta nueva característica a las bases de datos en el alcance

Me propuse escribir este plano y asegurarme de que fuera revisado por todas las partes interesadas y aprobado por nuestro equipo de arquitectura. Aunque había investigado un poco sobre el tema del registro de auditoría en MySQL hace un par de años y tenía una idea de cómo era el panorama de las opciones, no quería abordar el proyecto con prejuicios y quería investigar más de uno. opción, y proporcionar a todos un caso sólido de por qué elegiríamos una solución sobre otra.

Este anteproyecto era inusual porque lo estaba escribiendo mientras investigaba cuál iba a ser la solución a la necesidad comercial. Así que sabía que se iban a completar muchos detalles a medida que investigamos un poco.

Nuestras opciones eran:

  • Complemento de auditoría de Percona
  • Auditoría MySQL de Mcafee

Si bien estas no son las únicas opciones en el mercado, sentimos que eran las más cercanas a nuestra escala y prácticas devops para justificar su inclusión en el horneado real. Otras opciones comerciales en el mercado no pasaron ese listón para ser incluidas en el índice de referencia.

Esta última era una solución más nueva que Mcafee abrió recientemente y fue lo suficientemente intrigante como para analizarla porque afirmaba admitir el filtrado a nivel de tabla que el complemento de Percona no admitía. Dado que sabíamos que uno de nuestros clústeres en el alcance en realidad necesitaba auditar alrededor de 24 tablas de un total de 300, esta parecía ser una característica lo suficientemente valiosa como para hacer que el complemento de Mcafee fuera un competidor.

Por otro lado, el complemento Percona Audit fue la solución de código abierto más utilizada para esta característica. Viene incorporado pero deshabilitado en Percona Server, que ya usamos. Sin embargo, no proporciona filtrado de eventos a nivel de tabla, lo que significa que necesitábamos hacerlo fuera de la capa de la base de datos.

horneado

Con la ayuda de nuestro equipo asociado en Pythian, comenzamos la comparación de horneado. Al principio, comparamos cómo instalar y ajustar cada opción. El equipo rápidamente determinó que teníamos una compensación en nuestras manos. Si bien el complemento de Mcafee admitía los filtros de tabla de forma nativa, no admitía el uso de rsyslog como método de transmisión de sus eventos. Esto significaba que si tuviéramos que usarlo, tendríamos que escribir los archivos localmente en el disco y administrar el envío a la pila de monitoreo.

Esto no se consideró deseable, ya que lo más probable es que aumentara la penalización del rendimiento al usar el complemento de auditoría. Escribir los eventos de auditoría localmente y luego volver a leerlos mediante un proceso separado quita la capacidad de IOPS de nuestro tráfico de producción real y aumenta el riesgo para las instancias de la base de datos, ya que significa que tenemos que administrar el tamaño de estos archivos en el disco para que no se hinchen y causen problemas en la base de datos. falta del tiempo.

Por otro lado, el compromiso fue el complemento Percona. Admite el envío de eventos a syslog de forma nativa, pero no ofrece ningún filtro de tabla. Sabíamos que esto significaba que los clústeres más ocupados en el ámbito enviarían una gran cantidad de eventos, la mayoría de los cuales en realidad no provienen de las tablas que queremos auditar. Esto presentaba un riesgo para la capa syslog-receive/logstash de la pila de monitoreo de InfoSec. Dado que DB ops no tiene acceso a eso, significaba que el éxito de este proyecto era un esfuerzo de propiedad compartida.

En última instancia, decidimos usar la solución con menos partes móviles y planificar nuestra implementación para saber lo antes posible si era necesario escalar Logstash para manejar el filtrado de miles de eventos por segundo. Entonces se tomó la decisión de seguir adelante con el complemento de auditoría de Percona.

Planificación de la implementación

Alcance de la instalación

Decidimos mantener esta implementación simple instalando y habilitando el complemento en todos los nodos en un clúster determinado, lo que significa que eliminamos la necesidad de orquestar la activación o desactivación de la función de auditoría cuando cambia el nodo escritor en un clúster. No nos preocupaba que el flujo de replicación causara eventos duplicados a medida que se aplicaba un cambio porque el complemento, por diseño, no registra los cambios en el flujo de replicación.

Sin tiempo de inactividad

Queríamos que esto fuera una implementación perfecta sin tiempo de inactividad en los clústeres afectados. Eso reduciría en gran medida la cantidad de planificación y orquestación que tendríamos que hacer con los equipos de entrega que usan estos clústeres y reduciría en gran medida el impacto en el cliente. Pero también queríamos que el complemento enviara sus eventos a rsyslog, en una instalación específica, con una configuración personalizada que enviaría los eventos al servidor de agregación de syslog del equipo de InfoSec. Algunas de estas configuraciones están documentadas como no dinámicas por Percona y eso presentaba la posibilidad de que cada instancia en el alcance de este proyecto incurriera en algún tiempo de inactividad a medida que reiniciamos la instancia de mysql con la configuración de complemento de auditoría requerida.

Comenzamos a probar diferentes órdenes de operación al implementar el complemento con una instancia de prueba dedicada en nuestro entorno de prueba y pudimos demostrar que si tuviéramos nuestra administración de configuración, establecería todas las configuraciones necesarias al principio y luego ejecutaría el comando cargar complemento , que el comando arranque con la configuración deseada.

Esto resultó fundamental tanto para simplificar el plan para completar este proyecto como para acortar el tiempo de lanzamiento en producción, lo que nos dio tiempo para ajustar el filtrado de eventos y trabajar con el equipo de seguridad en el análisis y la detección.

Utilizar la gestión de configuración

Usamos libros de cocina de chef para administrar nuestras bases de datos, por lo que obviamente planeamos usar chef para implementar, ajustar y monitorear el complemento de auditoría. Pero dado que esto debía habilitarse solo en un subconjunto de nuestros clústeres, esto significaba que necesitábamos una forma de controlar dónde estaba habilitado para no sobrecargar nuestro almacenamiento de registros con datos que no son pertinentes para nuestro objetivo comercial aquí.

Para administrar las bases de datos MySQL, usamos un modelo de libro de recetas contenedor para administrar la configuración. Un libro de recetas central 'base' define la mayor parte de cómo debe verse la instancia de la base de datos, luego un libro de recetas por clúster envuelve eso para modificar atributos o agregar configuración donde sea pertinente para el clúster específico. Ese diseño facilitó agregar la mayor parte del código que crearía los archivos de configuración necesarios y luego cargar el complemento en una nueva receta que luego podemos activar y desactivar en función de un atributo de chef. También decidimos, dado el alcance del cambio que estábamos realizando, que justificaba la publicación de este código como una nueva versión secundaria del libro de cocina.

También nos aseguramos de que el chef elimine cualquier verificación de sensu relacionada y desactive la transmisión de auditoría cuando el atributo se establezca en falso. Esto fue para garantizar que el chef pueda hacer lo correcto si alguna vez se considera que un clúster ya no está dentro del alcance o si es necesario detenerlo por algún motivo intermitente, por lo que no necesitamos cambiar manualmente un nodo para reflejar el cambio de atributo.

Supervisión

No puede declarar el éxito de algo que no está monitoreando. Pero también el monitoreo es más que simplemente hacer algunos controles sensu sin pensar en qué casos de falla estamos monitoreando y qué acción esperamos en respuesta a que estos controles fallen algún día. Así que me dispuse a planificar el monitoreo en este pipeline con 2 cosas en mente

  • Todos debemos estar de acuerdo en el alcance explícito de la propiedad en este sistema, especialmente porque abarca las responsabilidades de 2 equipos con rotaciones de guardia separadas.
  • Cualquier verificación nueva que se agregue para esto debe venir con un runbook al que vinculamos en la verificación, explicando en qué está fallando esta verificación y cómo solucionarlo.

Dadas esas 2 reglas, procedí a agregar controles muy específicos. En este punto, también consideré agregar una verificación 'sintética' de extremo a extremo, pero desde entonces me he abstenido de hacerlo, ya que una verificación de extremo a extremo aquí fallaría al decirnos exactamente qué parte del sistema falló, lo que significa que tendríamos una difícil tiempo incluso llamando al equipo correcto con él. Y no soy partidario de llamar a la gente por la noche 'por si acaso'

Decidimos monitorear lo siguiente:

  • Verifique la configuración mysql en vivo del complemento de auditoría para asegurarse de que
    • El complemento estaba en estado activo.
    • El audit_log_policy se estableció en CONSULTAS

Esta verificación confirma que una base de datos en el alcance no cambió su configuración sobre la marcha, ya que esta configuración es dinámica y podría cambiar fuera del archivo my.cnf en el disco.

  • Verifique el puerto en el que enviamos registros a la pila de monitoreo para asegurarse de que los datos fluyan. Básicamente, asegurarse de que el otro extremo del flujo de syslog esté funcionando. Esta verificación se maneja como lo que el sentido llama una verificación agregada, por lo que no llama de manera notoria al equipo de InfoSec.

Obstáculos en el camino

Configuración del complemento de auditoría

Una de las iteraciones iniciales de este proyecto pretendía aprovechar la función audit_log_exclude_commands para limitar los eventos que emitimos solo a la manipulación de datos o esquemas. Rápidamente aprendimos que la lista en la que se basa esta configuración es mucho más larga de lo que cabría esperar.

configuración de rsyslog

Aquí hay algo que no sabía antes de este proyecto. La configuración de Rsyslog es casi su propio idioma. Por ejemplo:

  • Utilice una segunda @ delante del destino remoto para enviar registros a través de TCP en lugar de UDP. Queríamos utilizar esta función para dar un poco más de garantía de que se están entregando los registros.
  • rsyslog tiene una página dedicada a cómo configurarlo para un reenvío confiable, lo que resultó muy útil para un novato en la herramienta como yo.
  • rsyslog, de forma predeterminada, también conectará sus datos a /var/log/messages , lo que no era deseable en mi caso porque se trata de MUCHOS eventos. Si necesita hacer que la instalación que está utilizando NO haga eso, debe agregar local5.* ~ al final de su configuración

simulacro de incendio

Hablaré sobre las implicaciones de rendimiento para las bases de datos en el alcance más adelante, pero dado que rsyslog se usó como una parte crucial para este diseño, también necesitábamos simulacros de cómo se comportaría rsyslog cuando su destino remoto no está disponible o no responde. La mejor manera de hacerlo era interrumpir esa comunicación usando reglas de iptables en producción en una de las bases de datos en el alcance que sabíamos que tenía un alto rendimiento de transacciones y, por lo tanto, un gran volumen de eventos de auditoría por segundo. Así es como se desarrolló ese simulacro de incendio.

  • Confirme que los eventos de auditoría fluyan a través del puerto TCP designado
  • Use una regla de iptables para descartar todo el tráfico en ese puerto /sbin/iptables -A OUTPUT -p tcp –dport {NÚMERO-DE-PUERTO-AQUÍ} -j DROP
  • Observe la actividad de escritura en disco y los archivos en el directorio de trabajo configurado en la configuración de rsyslog . Los nombres de los archivos se basarán en el ActionQueueFileName de la instalación que recibe estos eventos.

Como era de esperar, los archivos comenzaron a almacenarse en este directorio. Vimos un aumento en la actividad de IOP de disco. Una vez que la cantidad de archivos que definieron el nombre de la cola se sumó en tamaño al valor de ActionQueueMaxDiskSpace , rsyslog dejó de crear estos archivos, las IOP del disco se normalizaron y quedó claro que ahora estábamos descartando eventos en la capa rsyslog. Lo que fue más impresionante de ver fue que después de que eliminamos la regla potable, rsyslog reenvió todos los eventos que había almacenado en el disco, por lo que no tuvimos pérdida de eventos para nuestro almacén de análisis siempre que no excediéramos el tamaño de la cola. Aprendimos algunas cosas basadas en ese experimento.

  • rsyslog se comporta como se documenta. Siempre es mejor demostrarlo con experimentos de primera mano.
  • Es muy probable que necesitemos definir un espacio de disco de cola diferente por clúster según el volumen de eventos que genere cada uno. Dado que hacer cola en el disco agrega riesgo a la capacidad de los IOP y la capacidad del disco, es algo que tendremos que revisar periódicamente y volver a examinar.

En la próxima publicación, hablaré sobre cuáles fueron nuestras observaciones después de implementar este proyecto en producción y qué cosas hicieron que esto fuera lo menos disruptivo posible para la producción.