mysqld

Auditando MySQL Com Mcafee Audit Plugin

mysql-audit

Auditar o MySQL com as funcionalidades padrão, não é uma tarefa fácil, pode se tentar algumas tecnicas utilizando tcpdump, escrever algum script baseado no general log (log geral), utilizar o MySQL proxy, ou pode se utilizar algum plugin designado a isso (como por exemplo Mcafee MySQL Audit Plugin ou MySQL Enterprise Audit Log Plugin) .

Neste poste vou abortar o Mcafee MySQL Audit Plugin (https://github.com/mcafee/mysql-audit), em um proximo post abortarei o MySQL Enterprise Audit Log Plugin.

A instalação é simples, requere apenas alguns passos, estou utilizando o MySQL 5.5 32 bits, então vou baixar a versão do plugin 32 bits para MySQL 5.5 em https://github.com/mcafee/mysql-audit/downloads

[root@mysql-audit marcelo]# wget https://github.com/downloads/mcafee/mysql-audit/audit-plugin-mysql-5.5-1.0.3-371-linux-i386.zip
[root@mysql-audit marcelo]# unzip audit-plugin-mysql-5.5-1.0.3-371-linux-i386.zip
Archive:  audit-plugin-mysql-5.5-1.0.3-371-linux-i386.zip
   creating: audit-plugin-mysql-5.5/
   creating: audit-plugin-mysql-5.5/lib/
  inflating: audit-plugin-mysql-5.5/lib/libaudit_plugin.so  
  inflating: audit-plugin-mysql-5.5/COPYING  
  inflating: audit-plugin-mysql-5.5/THIRDPARTY.txt  
  inflating: audit-plugin-mysql-5.5/README.txt

Proximo passo é copiar o arquivo libaudit_plugin.so para o plugin dir do MySQL:

mysql [localhost] {msandbox} ((none)) > SHOW VARIABLES LIKE 'plugin_dir';
+---------------+---------------------------------+
| Variable_name | Value                           |
+---------------+---------------------------------+
| plugin_dir    | /var/marcelo/5.5.33/lib/plugin/ |
+---------------+---------------------------------+
1 row in set (0.00 sec)

mysql [localhost] {msandbox} ((none)) > quit
Bye
[root@mysql-audit audit-plugin-mysql-5.5]# cp lib/libaudit_plugin.so /var/marcelo/5.5.33/lib/plugin/

Para que o plugin funcione, o Mcafee MySQL Audit Plugin precisa de alguns offsets do MySQL server, alguns já estão inclusos no código fonte, e outros não, precisamos extrair alguns offsets (veja https://github.com/mcafee/mysql-audit/wiki/Troubleshooting para mais informações).
Vamos precisar do GBD para extrair os offsets, o pacote pode ser obtido via yum install gdb or apt-get install gdb

[root@mysql-audit marcelo]# wget https://raw.github.com/mcafee/mysql-audit/v1.0.3/offset-extract/offset-extract.sh
[root@mysql-audit marcelo]# ./offset-extract.sh 5.5.33/bin/mysqld
//offsets for: 5.5.33/bin/mysqld (5.5.33)
{"5.5.33","3172729c5bf6e81c8d87fe26fe248204", 3816, 3844, 2368, 2700, 44, 1656},

Agora, vamos fazer algumas alterações no arquivo .cnf(my.cnf) para ativar o plugin:

# Adicione dentro da sessão [mysqld] 
plugin-load=AUDIT=libaudit_plugin.so
audit_offsets=3816, 3844, 2368, 2700, 44, 1656
audit_json_file=1

Agora o que precisamos fazer é apenas reinicar o serviço do MySQL, por padrão, um arquivo chamado mysql-audit.json é criado dentro do datadir do MySQL, basta agora tu extrair a informação que achares relevante, veja abaixo alguns exemplos:

Tentativas de conexão não bem sucedias:

[root@mysql-audit data]# cat mysql-audit.json | grep '\"cmd\":\"Failed Login\"'
{"msg-type":"activity","date":"1381764013653","thread-id":"65","query-id":"0","user":"msandbox","priv_user":"","ip":"10.10.2.68","cmd":"Failed Login","query":"Failed Login"}
{"msg-type":"activity","date":"1381764016225","thread-id":"66","query-id":"0","user":"msandbox","priv_user":"","ip":"10.10.2.68","cmd":"Failed Login","query":"Failed Login"}
{"msg-type":"activity","date":"1381764026005","thread-id":"67","query-id":"0","user":"root","priv_user":"","ip":"10.10.2.68","cmd":"Failed Login","query":"Failed Login"}

Tentativas de conexão bem sucedias:

[root@mysql-audit data]# cat mysql-audit.json | grep '\"cmd\":\"Connect\"'
{"msg-type":"activity","date":"1381763915626","thread-id":"60","query-id":"0","user":"msandbox","priv_user":"msandbox","ip":"10.10.2.68","cmd":"Connect","query":"Connect"}
{"msg-type":"activity","date":"1381763915626","thread-id":"61","query-id":"0","user":"msandbox","priv_user":"msandbox","ip":"10.10.2.68","cmd":"Connect","query":"Connect"}
{"msg-type":"activity","date":"1381763915626","thread-id":"62","query-id":"0","user":"msandbox","priv_user":"msandbox","ip":"10.10.2.68","cmd":"Connect","query":"Connect"}
{"msg-type":"activity","date":"1381763916006","thread-id":"64","query-id":"0","user":"msandbox","priv_user":"msandbox","ip":"10.10.2.68","cmd":"Connect","query":"Connect"}

Todas as atividades de um host especifico:

[root@mysql-audit data]# cat mysql-audit.json | grep '\"ip\":\"10.10.2.68\"'
{"msg-type":"activity","date":"1381763919836","thread-id":"60","query-id":"4798","user":"msandbox","priv_user":"msandbox","ip":"10.10.2.68","cmd":"select","objects":[{"db":"test","name":"sbtest8","obj_type":"TABLE"}],"query":"SELECT SUM(K) FROM sbtest8 WHERE id BETWEEN 151257 AND 151257+99"}
{"msg-type":"activity","date":"1381763919844","thread-id":"62","query-id":"4799","user":"msandbox","priv_user":"msandbox","ip":"10.10.2.68","cmd":"select","objects":[{"db":"test","name":"sbtest6","obj_type":"TABLE"}],"query":"SELECT c FROM sbtest6 WHERE id BETWEEN 141568 AND 141568+99 ORDER BY c"}
{"msg-type":"activity","date":"1381763919847","thread-id":"47","query-id":"4800","user":"msandbox","priv_user":"msandbox","ip":"10.10.2.68","cmd":"update","objects":[{"db":"test","name":"sbtest3","obj_type":"TABLE"}],"query":"UPDATE sbtest3 SET k=k+1 WHERE id=150189"}
{"msg-type":"activity","date":"1381763919848","thread-id":"60","query-id":"4801","user":"msandbox","priv_user":"msandbox","ip":"10.10.2.68","cmd":"select","objects":[{"db":"test","name":"sbtest8","obj_type":"TABLE"}],"query":"SELECT c FROM sbtest8 WHERE id BETWEEN 175916 AND 175916+99 ORDER BY c"}
{"msg-type":"activity","date":"1381763919869","thread-id":"64","query-id":"4803","user":"msandbox","priv_user":"msandbox","ip":"10.10.2.68","cmd":"select","objects":[{"db":"test","name":"sbtest10","obj_type":"TABLE"}],"query":"SELECT DISTINCT c FROM sbtest10 WHERE id BETWEEN 132850 AND 132850+99 ORDER BY c"}
{"msg-type":"activity","date":"1381763919881","thread-id":"57","query-id":"4784","user":"msandbox","priv_user":"msandbox","ip":"10.10.2.68","cmd":"commit","query":"COMMIT"}
{"msg-type":"activity","date":"1381763919930","thread-id":"37","query-id":"4802","user":"msandbox","priv_user":"msandbox","ip":"10.10.2.68","cmd":"commit","query":"COMMIT"}
{"msg-type":"activity","date":"1381764013653","thread-id":"65","query-id":"0","user":"msandbox","priv_user":"","ip":"10.10.2.68","cmd":"Failed Login","query":"Failed Login"}
{"msg-type":"activity","date":"1381764016225","thread-id":"66","query-id":"0","user":"msandbox","priv_user":"","ip":"10.10.2.68","cmd":"Failed Login","query":"Failed Login"}
{"msg-type":"activity","date":"1381764026005","thread-id":"67","query-id":"0","user":"root","priv_user":"","ip":"10.10.2.68","cmd":"Failed Login","query":"Failed Login"}

Todos os comandos DELETE em uma especifica tabela(sbtest8) de um especifico host:

[root@mysql-audit data]# cat mysql-audit.json | grep -i '\"cmd\":\"delete\"' | grep -i '\"name\":\"sbtest8\"' | grep '\"ip\":\"10.10.2.68\"'
{"msg-type":"activity","date":"1381763914163","thread-id":"53","query-id":"3366","user":"msandbox","priv_user":"msandbox","ip":"10.10.2.68","cmd":"delete","objects":[{"db":"test","name":"sbtest8","obj_type":"TABLE"}],"query":"DELETE FROM sbtest8 WHERE id=150652"}
{"msg-type":"activity","date":"1381763914947","thread-id":"44","query-id":"3513","user":"msandbox","priv_user":"msandbox","ip":"10.10.2.68","cmd":"delete","objects":[{"db":"test","name":"sbtest8","obj_type":"TABLE"}],"query":"DELETE FROM sbtest8 WHERE id=194099"}
{"msg-type":"activity","date":"1381763915718","thread-id":"36","query-id":"3630","user":"msandbox","priv_user":"msandbox","ip":"10.10.2.68","cmd":"delete","objects":[{"db":"test","name":"sbtest8","obj_type":"TABLE"}],"query":"DELETE FROM sbtest8 WHERE id=151405"}
{"msg-type":"activity","date":"1381763916273","thread-id":"48","query-id":"3799","user":"msandbox","priv_user":"msandbox","ip":"10.10.2.68","cmd":"delete","objects":[{"db":"test","name":"sbtest8","obj_type":"TABLE"}],"query":"DELETE FROM sbtest8 WHERE id=148546"}
{"msg-type":"activity","date":"1381763918698","thread-id":"40","query-id":"4437","user":"msandbox","priv_user":"msandbox","ip":"10.10.2.68","cmd":"delete","objects":[{"db":"test","name":"sbtest8","obj_type":"TABLE"}],"query":"DELETE FROM sbtest8 WHERE id=149492"}

Como pode ver, tu pode extrair e ajustar o log para se enquadrar as tuas necessidades, tu pode também adicionar algumas configurações ao plugin para mudar um pouco o seu comportamento (https://github.com/mcafee/mysql-audit/wiki/Configuration para mais informações) :

audit_record_cmds – lista de comandos que deseja gravar no log, por exemplo, se tu deseja gravar apenas tentativas de conexão configure esta opção como: audit_record_cmds=”Failed Login,Connect”
audit_record_objs – lista de banco de dados/tabelas que deseja gravar no log, por exemplo, se tu deseja gravar apenas atividades no banco de dados test, configure esta opcao como: audit_record_objs=”test.*” , se tu deseja gravar apenas atividades nas tabelas sbtest1 e sbtest2 do banco de dados chamado test, configure esta opção como: audit_record_objs=”test.sbtest1,test.sbtest2″

É isso ai, use sua imaginação e comece a auditar o seu MySQL.

Instalando MySQL 5.5 Parte 1 – Uma unica instancia

Hoje vou ensinar como instalar um servidor MySQL de forma simples. Com apenas uma unica instância, na segunda parte deste artigo, vou ensinar a instalar varias instâncias do MySQL e controla-las através do mysqld_multi.

Para este tutorial estou utilizando:

    VMWare
    CentOS 5.6 - 64bits
    512MB RAM
    40GB DISCO
    Instalação sem interface gráfica, somente linha de comando

Dito isso, vamos ao que realmente interessa:

  1. Vamos criar a estrutura de diretórios que vamos trabalhar com nossa instalação do MySQL, para este tutorial vou instalar na raiz da partição:
    cd /
    mkdir mysql
    cd mysql
  2. Vamos ao site de Downloads do MySQL e baixar da ultima versão Community Server que hoje é a 5.5.11. Utilizaremos a compilação Linux Generic e buscar pelo pacote tar.gz da sua versão de sistema operacional:
    wget http://mysql.cce.usp.br/Downloads/MySQL-5.5/mysql-5.5.11-linux2.6-x86_64.tar.gz
  3. Uma vez baixado o pacote do MySQL, vamos agora descompactar o pacote com o comando baixado:
    tar -vzxf mysql-5.5.11-linux2.6-x86_64.tar.gz
  4. Agora vamos apenas ajustar o nome da pasta para algo mais legível:
    mv mysql-5.5.11-linux2.6-x86_64 core-5.5.11
  5. Feito isso criaremos um link simbólico, pois o MySQL nos exige que sua pasta seja nomeada exatamente mysql
    ln -s core-5.5.11 mysql
  6. Após, criaremos a estrutura de diretórios da nossa instância do MySQL:
    mkdir 3306
    mkdir 3306/data
    mkdir 3306/logs
  7. O próximo passo é criar os bancos de dados padrões do MySQL. Mas antes disso, temos que definir com qual usuário o MySQL vai rodar, como padrão, sempre criamos (caso ainda não existe) um usuário com o próprio nome MySQL, vamos lá:
    useradd mysql
    Com nosso usuário criado no sistema, vamos alterar as permissões das pastas do MySQL para este usuário:
    chown -R mysql:mysql /mysql/
  8. Vamos então, criar os bancos de dados padrões do MySQL, dentro da nossa pasta/link simbólico mysql temos uma série de pastas, uma delas chamada scripts, dentro dela temos um script que faz a criação da estrutura de banco de dados necessária para iniciarmos nossa instância do MySQL, para rodar este script, vamos passar 3 parâmetros:
    user – usuário proprietário das pastas que serão criadas
    basedir – pasta onde instalamos o nosso MySQL (fontes)
    datadir – pasta onde desejamos que seja criada a estrutura de banco de dados
    No nosso caso, o comando irá ficar assim:
    cd /mysql/mysql/scripts/
    ./mysql_install_db --user=mysql --basedir=/mysql/mysql --datadir=/mysql/3306/data/
    Vamos receber um retorno na tela, o que temos que nos atentar é para receber 2 OK’s no inicio do retorno:

    Installing MySQL system tables...
    OK
    Filling help tables...
    OK

  9. Agora vamos criar nosso arquivo de configurações o my.cnf, vamos configurar alguns parâmetros básicos para subir nossa instância:
    datadir – caminho para a pasta onde está localizado o nosso datadir
    socket – onde vamos salvar o unix socket
    user – usuário que o mysql vai utilizar para subir nossa instância e acessar os arquivos no disco
    log-error – local e nome do arquivo de logs (muito importante, pois nele que diagnosticamos maior parte dos problemas que acontecem no nosso servidor MySQL)
    pid-file – arquivo onde ficará o PID do MySQL

    Vamos então de fato criar nosso arquivo de configuração:
    vi /mysql/my.cnf
    O conteúdo do nosso arquivo deve ficar assim:
    [mysqld]
    datadir=/mysql/3306/data
    socket=/mysql/3306/mysql.sock
    user=mysql
    [mysqld_safe]
    log-error=/mysql/3306/logs/mysqld.log
    pid-file=/mysql/3306/mysqld.pid

  10. E finalmente, vamos subir nossa instância do MySQL:
    cd /mysql/mysql
    bin/mysqld_safe --defaults-file=/mysql/my.cnf &
  11. Pronto, agora nosso MySQL já está no ar, vamos apenas fazer mais um ajuste: Colocar a pasta do MySQL no PATH para que possamos acessa-lo de qualquer lugar do sistema:
    export PATH=$PATH:/mysql/mysql/bin/
  12. Para se conectar no banco, via TCP/IP usamos:
    mysql -u root -h127.0.0.1
    ou via UNIX socket
    mysql -u root --socket=/mysql/3306/mysql.sock

Lembrando que as boas práticas de segurança do MySQL nos pedem para executar 3 tarefas:

  1. Remover o banco de dados test, pois nesse banco de dados, todos os usuários tem acesso total, e pode ser que algum usuário crie uma procedure com um loop infinito para inserir dados até que seu disco fique 100% cheio
  2. Remover o usuário anonymous, por motivos óbitos
  3. Mudar a senha do user root, pois por padrão ela vem em branco

É isso aí pessoal, espero que tenham gostado, postem suas dúvidas e sugestões, e fiquem ligados, no próximo post, vou ensinar a subir N instâncias em um mesmo servidor, pratica esta muito usada para não super-dimensionar o hardware, Abraços.