Auditoria de bancos de dados no Grid
Publicados: 2018-09-29Como o SendGrid se tornou recentemente uma empresa de capital aberto, precisávamos ter logs de auditoria completos de todas as alterações em um subconjunto de nossos bancos de dados. Esse subconjunto inclui algumas instâncias pequenas que não viram um grande volume de tráfego, mas também alguns de nossos clusters mais antigos que são essenciais para o tempo de atividade do portal do cliente e o fluxo de inscrição.
Isso também afetou alguns armazenamentos de dados que tinham altas demandas de tempo de atividade e uma distribuição online (sem tempo de inatividade para gravações) era desejável. Com um prazo externo em mãos e conhecendo o escopo do projeto, nos propusemos a fazer um plano.
Na fase de planejamento, identificamos algumas perguntas em aberto para as quais precisávamos de respostas:
- Que opções temos em termos de software que pode fazer isso?
- Que impacto de desempenho é esperado e quanto podemos testar isso com antecedência?
- Podemos fazer isso sem tempo de inatividade para disponibilidade de gravação?
Escolhas, escolhas
No SendGrid, seguimos um processo de projeto de projeto para qualquer projeto grande ou entre equipes. Este projeto envolveu várias equipes como partes interessadas, incluindo:
- Auditoria Interna como a equipe encarregada de definir qual armazenamento de dados está no escopo desse controle de conformidade e de coletar evidências na hora da auditoria
- InfoSec como a equipe que deveria analisar e lidar com a resposta a incidentes derivada desses logs de auditoria do banco de dados
- DB Ops como a equipe que escreve o código que implanta, gerencia e ajusta esse novo recurso aos bancos de dados no escopo
Eu me propus a escrever este plano e garantir que ele fosse revisado por todas as partes interessadas e aprovado por nossa equipe de arquitetura. Embora eu tivesse feito alguma pesquisa sobre o tópico de log de auditoria no MySQL alguns anos atrás e tivesse alguma ideia de como era o cenário para as opções, eu não queria abordar o projeto com preconceitos e ainda queria investigar mais de um opção e fornecer a todos um caso sólido de por que escolheríamos uma solução em vez de outra.
Esse projeto era incomum, pois eu o escrevia simultaneamente enquanto investigava qual seria a solução para a necessidade do negócio. Então eu sabia que muitos detalhes seriam preenchidos enquanto fazíamos algumas pesquisas.
Nossas opções foram:
- Plugin de auditoria Percona
- Auditoria do McAfee MySQL
Embora essas não sejam as únicas opções no mercado, sentimos que elas eram as mais próximas de nossa escala e práticas de DevOps para garantir a inclusão no bake-off real. Outras opções comerciais no mercado não ultrapassaram essa barreira para serem incluídas no benchmark.
O último foi uma solução mais recente aberta recentemente pela Mcafee e foi intrigante o suficiente para investigar porque alegava oferecer suporte à filtragem de nível de tabela que o plug-in Percona não suportava. Como sabíamos que um de nossos clusters no escopo realmente precisava auditar cerca de 24 tabelas de um total de 300, esse parecia ser um recurso valioso o suficiente para tornar o plug-in Mcafee um concorrente.
Por outro lado, o plugin Percona Audit foi a solução de código aberto mais utilizada para este recurso. Ele vem embutido, mas desabilitado no Percona Server – que já usamos. No entanto, ele não fornece filtragem de eventos em nível de tabela, o que significa que precisávamos fazer isso fora da camada do banco de dados.
Mão na massa
Com a ajuda de nossa equipe parceira da Pythian, iniciamos a comparação inicial. Inicialmente, comparamos como instalar e ajustar cada opção. A equipe rapidamente determinou que tínhamos uma troca em nossas mãos. Embora o plug-in Mcafee suportasse filtros de tabela nativamente, ele não suportava o uso de rsyslog como um método de transmissão de seus eventos. Isso significava que, se fôssemos usá-lo, teríamos que gravar os arquivos localmente no disco e gerenciar enviá-los para a pilha de monitoramento.
Isso não foi considerado desejável, pois provavelmente aumentaria a penalidade de desempenho ao usar o plug-in de auditoria. Gravar os eventos de auditoria localmente e depois lê-los novamente por um processo separado tira a capacidade de IOPS do nosso tráfego de produção real e aumenta o risco para as instâncias do banco de dados, pois isso significa que temos que gerenciar o tamanho desses arquivos no disco para que eles não inchem e causem o banco de dados tempo de inatividade.
Por outro lado do compromisso estava o plugin Percona. Ele suporta o envio de eventos para o syslog nativamente, mas não oferece nenhum filtro de tabela. Sabíamos que isso significava que os clusters mais ocupados no escopo enviariam um grande número de eventos, a maioria dos quais não são realmente das tabelas que queremos auditar. Isso apresentou um risco para a camada syslog-receive/logstash da pilha de monitoramento do InfoSec. Como as operações de banco de dados não têm acesso a isso, isso significa que o sucesso deste projeto foi um empreendimento de propriedade compartilhada.
Por fim, decidimos usar a solução com menos partes móveis e planejar nossa implantação para saber o quanto antes se o logstash precisava ser dimensionado para lidar com a filtragem de milhares de eventos por segundo. Então foi tomada a decisão de avançar com o plugin de auditoria do Percona.
Planejamento de implantação
Escopo de instalação
Decidimos manter essa implantação simples instalando e habilitando o plug-in em todos os nós em um determinado cluster, o que significa que eliminamos a necessidade de orquestrar a ativação ou desativação do recurso de auditoria quando o nó do gravador em um cluster é alterado. Não tivemos nenhuma preocupação com o fluxo de replicação causando eventos duplicados à medida que uma alteração é aplicada porque o plug-in, por design, não registra alterações no fluxo de replicação.
Sem tempo de inatividade
Queríamos que isso fosse uma implantação perfeita, sem tempo de inatividade nos clusters afetados. Isso reduziria bastante a quantidade de planejamento e orquestração que precisaríamos fazer com as equipes de entrega que usam esses clusters e reduziria bastante o impacto no cliente. Mas também queríamos que o plug-in enviasse seus eventos para o rsyslog, em uma instalação específica, com uma configuração personalizada que enviaria os eventos para o servidor de agregação syslog da equipe do InfoSec. Algumas dessas configurações são documentadas como não dinâmicas pela Percona e apresentaram a possibilidade de que todas as instâncias no escopo deste projeto incorressem em algum tempo de inatividade à medida que reiniciamos a instância mysql com a configuração do plug-in de auditoria necessária.
Começamos a testar diferentes ordens de operação na implantação do plug-in com uma instância de teste dedicada em nosso ambiente de teste e pudemos mostrar que, se tivéssemos nosso gerenciamento de configuração, estabelecesse todas as configurações necessárias primeiro e depois executasse o comando load plugin , que o comando inicialize com a configuração desejada.
Isso se mostrou fundamental para simplificar o plano de conclusão deste projeto e reduzir o tempo para liberá-lo em produção, ganhando tempo para ajustar a filtragem de eventos e trabalhar com a equipe de segurança na análise e detecção.
Use o gerenciamento de configuração
Usamos livros de receitas do chef para gerenciar nossos bancos de dados, então obviamente planejamos usar o chef para implantar, ajustar e monitorar o plug-in de auditoria. Mas como isso precisava ser habilitado em apenas um subconjunto de nossos clusters, isso significava que precisávamos de uma maneira de controlar onde ele era habilitado para não sobrecarregar nosso armazenamento de log com dados não pertinentes ao nosso objetivo de negócios aqui.
Para gerenciar bancos de dados MySQL, usamos um modelo de livro de receitas wrapper para gerenciar a configuração. Um livro de receitas 'base' central define a maior parte de como a instância do banco de dados deve se parecer, então um livro de receitas por cluster envolve isso para modificar atributos ou adicionar configuração quando pertinente ao cluster específico. Esse design facilitou a adição da maior parte do código que criaria os arquivos de configuração necessários e, em seguida, carregaria o plug-in em uma nova receita que podemos ativar e desativar com base em um atributo do chef. Também decidimos, dado o escopo da mudança que estávamos fazendo, que isso justificava o lançamento deste código como uma nova versão secundária do livro de receitas.
Também nos certificamos de que o chef removesse todas as verificações sensu relacionadas e desativasse o streaming de auditoria quando o atributo fosse definido como false. Isso foi para garantir que o chef possa fazer a coisa certa se um cluster for considerado fora do escopo ou precisar ser interrompido por qualquer motivo intermitente, portanto, não precisamos alterar manualmente um nó para refletir a alteração do atributo.
Monitoramento
Você não pode declarar o sucesso de algo que não está monitorando. Mas também monitorar é mais do que apenas aplicar algumas verificações sensu sem pensar em quais casos de falha estamos monitorando e qual ação esperamos em resposta a essas verificações que falham algum dia. Então decidi planejar o monitoramento neste pipeline com 2 coisas em mente
- Precisamos concordar com o escopo de propriedade explícito neste sistema, especialmente porque abrange as responsabilidades de 2 equipes com rotações de plantão separadas
- Quaisquer novas verificações adicionadas para isso precisam vir com um runbook ao qual vinculamos na verificação, explicando em que essa verificação está falhando e como corrigi-la
Dadas essas 2 regras, passei a adicionar verificações muito específicas. Neste ponto, considerei também adicionar uma verificação 'sintética' de ponta a ponta, mas desde então me abstive de fazer isso, pois uma verificação de ponta a ponta aqui falharia em nos dizer exatamente qual parte do sistema falhou, o que significa que teríamos um difícil tempo até mesmo paging a equipe certa com ele. E eu não sou um defensor de chamar as pessoas à noite 'apenas no caso'
Decidimos monitorar o seguinte:
- Verifique a configuração do mysql ao vivo do plug-in de auditoria para certificar-se de que
- O plugin estava no estado ativo
- A audit_log_policy foi definida como QUERIES
Essa verificação confirma que um banco de dados no escopo não teve sua configuração alterada em tempo real, pois essas configurações são dinâmicas e podem ser alteradas fora do arquivo my.cnf no disco .
- Verifique a porta na qual enviamos logs para a pilha de monitoramento para garantir que os dados estejam fluindo. Basicamente, certificando-se de que a outra extremidade do fluxo syslog esteja funcionando. Essa verificação é tratada como o que o sentido chama de verificação agregada , para que não chame a equipe de InfoSec de forma flagrante
Obstáculos ao longo do caminho
Configuração do plug-in de auditoria
Uma das iterações iniciais deste projeto pretendia aproveitar o recurso audit_log_exclude_commands para limitar os eventos que emitimos apenas para manipulação de dados ou esquema. Aprendemos rapidamente que a lista na qual essa configuração se baseia é muito maior do que o esperado.
configuração do rsyslog
Aqui está algo que eu não sabia antes deste projeto. A configuração do Rsyslog é quase sua própria linguagem. Por exemplo:
- Use um segundo @ na frente do destino remoto para enviar logs por TCP em vez de UDP. Queríamos utilizar esse recurso para dar um pouco mais de garantia de que os logs estão sendo entregues.
- O rsyslog tem uma página dedicada sobre como configurá-lo para encaminhamento confiável, o que se mostrou muito útil para um novato na ferramenta como eu.
- O rsyslog, por padrão, também colocará seus dados em /var/log/messages , o que era indesejável no meu caso, porque são MUITOS eventos. Se você precisar fazer com que o recurso que você está usando NÃO faça isso, você deve adicionar local5.* ~ ao final de sua configuração
Simulação de incêndio
Falarei sobre as implicações de desempenho para os bancos de dados no escopo mais tarde, mas como o rsyslog estava sendo usado como uma parte crucial para esse design, precisávamos também testar como o rsyslog se comportaria quando seu destino remoto não estiver disponível ou não estiver respondendo. A melhor maneira de fazer isso era causar a interrupção dessa comunicação usando as regras do iptables em produção em um dos bancos de dados no escopo que sabíamos ter uma alta taxa de transferência de transações e, portanto, um grande volume de eventos de auditoria por segundo. Aqui está como essa simulação de incêndio aconteceu.
- Confirme se os eventos de auditoria estão fluindo pela porta TCP designada
- Use uma regra iptables para descartar todo o tráfego nessa porta /sbin/iptables -A OUTPUT -p tcp –dport {PORT-NUMBER-HERE} -j DROP
- Observe a atividade de gravação do disco e os arquivos no WorkDirectory configurado na configuração do rsyslog. Os nomes dos arquivos serão baseados no ActionQueueFileName da instalação que recebe esses eventos
Conforme esperado, os arquivos começaram a ser colocados em spool neste diretório. Vimos um aumento na atividade de IOPs de disco. Uma vez que o número de arquivos que definiram o nome da fila foi totalizado em tamanho para o valor de ActionQueueMaxDiskSpace , o rsyslog parou de criar esses arquivos, os IOPs de disco normalizaram e ficou claro que agora estávamos descartando eventos no chão na camada rsyslog. O que foi mais impressionante de observar foi que, depois que removemos a regra potável, o rsyslog reenviou todos os eventos que ele havia colocado em spool para o disco, para que não houvesse perda de eventos para nosso armazenamento de análise, desde que não excedêssemos o tamanho do spool. Aprendemos algumas coisas com base nesse experimento
- rsyslog está se comportando conforme documentado. É sempre melhor provar isso com experimentos em primeira mão
- Muito provavelmente, precisaremos definir um espaço em disco de fila diferente por cluster, dependendo do volume de eventos que cada um gera. Como o enfileiramento no disco adiciona risco à capacidade dos IOPs e à capacidade do disco, é algo que precisaremos revisitar periodicamente e reexaminar
No próximo post, falarei sobre quais foram nossas observações após a implantação deste projeto na produção e o que tornou isso o menos disruptivo possível para a produção.