MySQL Audit 사용하기

1. Plugin file 확인

  • audit log plugin(audit_log) library object file이 MySQL plugin directory에 위치하는지 확인
  • Community version을 사용한다면, Enterprise edition을 받아 해당 library directory에서 audit_log.so를 복사한 후 Community version의 library directory에 넣어 사용할 수 있다.

2. Plugin load

  • my.cnf 에 명시하고 restart 하는 방법
    • my.cnf의 [mysqld] 섹션에 아래와 같이 명시해주거나 startup comman-line에서 –plugin-load 을 사용한다.
    • restart시 plugin-load 명시해주지 않으면 load하지 않는다.
    • mysql 에 접속하여 show plugin 명령어를 통해 해당 plugin의 상태를 확인할 수 있다.
    [mysqld]
    plugin-load=audit_log.so

    -- MySQL Restart
    mysql> show plugins;
    +----------------------------+----------+--------------------+--------------+-------------+
    | Name                       | Status   | Type               | Library      | License     |
    +----------------------------+----------+--------------------+--------------+-------------+
    ...
    | audit_log                  | ACTIVE   | AUDIT              | audit_log.so | PROPRIETARY |
    +----------------------------+----------+--------------------+--------------+-------------+
  • INSTALL PLUGIN문으로 인스톨하는 방법
    • mysql 에 접속하여 아래의 명령어로 활성화 시킬 수 있다.

      mysql> INSTALL PLUGIN audit_log SONAME 'audit_log.so';

    • mysql.plugin 테이블에 해당 plugin을 등록하고 restart시에도 load된다.

3. Audit log file 관련 옵션

  • audit log file : audit.log
  • audit log format : OLD(default) 와 NEW 를 쓸 수 있다.
    • NEW format은 5.6.14부터 생겼고, Oracle Audit Vault와의 나은 호환성을 가짐.
    • 뒤에 이야기 하겠지만, MySQL table에 넣고 분석할 경우, OLD 포맷만이 가능하다. 현재 bug로 fix 중에 있다. 2015-07-21
  • audit_log_strategy : ASYNCHRONOUS(default) | PERFORMANCE | SEMISYNCHRONOUS | SYNCHRONOUS
    • ASYNCHRONOUS : asynchronously, buffer가 다 차면 쓴다. minimal impact
    • PERFORMACE : asynchronously, buffer가 부족해지면 쓴다.
    • SEMISYNCHRONOUS : synchronously, 즉각 OS 캐시에 씀, 캐시에서 내려쓰는건 OS에 맡김.
    • SYNCHRONOUS : synchronously, 매 write request마다 call sync()
  • audit_log_buffer_size : async방식일 때만 이만큼 buffer할당
  • audit_log_rotate_on_size, audit_log_flush : rotation, flush 관련 옵션

4. Audit Log

     <AUDIT_RECORD TIMESTAMP="2015-06-16T09:20:17 UTC" RECORD_ID="307_2015-06-16T08:23:17" NAME="Query" CONNECTION_ID="60" STATUS="1064" STATUS_CODE="1" USER="root[root] @ localhost []" OS_LOGIN="" HOST="localhost" IP="" COMMAND_CLASS="grant" SQLTEXT="grant all on *.* to 'dba'@'%' indentified by 'dba'"/>
     <AUDIT_RECORD TIMESTAMP="2015-06-16T09:21:01 UTC" RECORD_ID="308_2015-06-16T08:23:17" NAME="Query" CONNECTION_ID="60" STATUS="0" STATUS_CODE="0" USER="root[root] @ localhost []" OS_LOGIN="" HOST="localhost" IP="" COMMAND_CLASS="grant" SQLTEXT="GRANT ALL PRIVILEGES ON *.* TO 'dba'@'%' IDENTIFIED BY PASSWORD '*381AD08BBFA647B14C82AC1094A29AD4D7E4F51D'"/>

5. Audit Log Filtering

6. Audit file rotate 시키기

  • audit_log_rotate_on_size 설정
  • 수동 설정
    • 먼저 해당 테이블로 저장하기위해는 온전한 파일이어야 한다. 수동으로 해당 파일을 분리해보자.
    • mv로 옮겨도 file descriptor를 mysql이 가지고 있기 때문에 지속적으로 변경된 파일에 쓰게 된다.

      ## MySQL 의 Data Home Directory는 /data1/5.6/data 로 설정되어 있다. SHELL> mv /data1/5.6/data/audit.log /data1/5.6/data/audit.log.bak

    • audit log를 flush 한다.
    • 기존의 /data1/5.6/data/audit.log.bak 에 대해서는 닫고 새로운 /data1/5.6/data/audit.log 을 열게 된다.

      mysql> SET GLOBAL audit_log_flush = 1;

7. Audit 파일 테이블로 저장하기

  • table을 만들고, LOAD XML을 통해 올려보자.
    • 해당 /data1/5.6/data/audit.log.bak 을 테이블로 넣어보자. 물론 mv로 해당 파일을 바꾸지 않고 쓰고 있는 파일에 대하여 넣어도 상관없다.
    • 중복을 방지하기 위해 UNIQUE U_RECORD_ID 를 추가했다.
    • 필요한 business logic에 맞춰 테이블의 인덱스를 추가해서 넣자.
mysql> CREATE TABLE audit_log_to_table (
    id bigint PRIMARY KEY auto_increment,
    TIMESTAMP timestamp,
    CONNECTION_ID bigint,
    USER varchar(128),
    HOST varchar(128),
    IP varchar(25),
    OS_LOGIN varchar(64),
    RECORD_ID varchar(64),
    NAME varchar(64),
    STATUS int,
    STATUS_CODE int,
    COMMAND_CLASS varchar(64),
    SQLTEXT longtext,
    UNIQUE U_RECORD_ID (RECORD_ID)
    ) DEFAULT CHARSET utf8mb4;

mysql> LOAD XML LOCAL INFILE '/data1/5.6/data/audit.log.bak'
     INTO TABLE audit_log_to_table
     CHARACTER SET utf8mb4
     ROWS IDENTIFIED BY ''
    (@TIMESTAMP, CONNECTION_ID, USER, HOST, IP, OS_LOGIN, RECORD_ID, NAME, STATUS, STATUS_CODE, COMMAND_CLASS, SQLTEXT)
    SET TIMESTAMP = CONVERT_TZ(STR_TO_DATE(@TIMESTAMP, '%Y-%m-%dT%H:%i:%s UTC'), 'UTC', '+9:00');