Showing posts with label MYSQL InnoDB Cluster. Show all posts
Showing posts with label MYSQL InnoDB Cluster. Show all posts

Thursday, 2 July 2020

How to config and enable MySQL Enterprise Audit in MySQL

Here is the steps to show you how to config and enable the MySQL Enterprise Audit in MySQL.

A. Config and enable the MySQL Enterprise Audit in MySQL.
Step 1: Append the following lines in config file
plugin-load-add=authentication_pam.so
plugin-load-add=audit_log.so
audit_log_flush=on
audit_log_rotate_on_size=200MB
#Example of audit log name is audit_host01_3306.log
audit_log_file=/db_log/audit/audit_host01_3306.log 
#Log connection error only
audit_log_connection_policy=ERRORS

Step 2: Check plugin status
SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS 
WHERE PLUGIN_NAME LIKE 'audit%';
   
Step 3: Create audit function and tables
USE mysql;
CREATE TABLE IF NOT EXISTS audit_log_filter(NAME VARCHAR(64) BINARY NOT NULL PRIMARY KEY, FILTER JSON NOT NULL) engine= InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_as_ci;
CREATE TABLE IF NOT EXISTS audit_log_user(USER VARCHAR(32) BINARY NOT NULL, 
HOST VARCHAR(60) BINARY NOT NULL, FILTERNAME VARCHAR(64) BINARY NOT NULL, 
PRIMARY KEY (USER, HOST), FOREIGN KEY (FILTERNAME) REFERENCES mysql.audit_log_filter(NAME)) 
engine= InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_as_ci;
INSTALL PLUGIN audit_log SONAME 'audit_log.so';
CREATE FUNCTION audit_log_filter_set_filter RETURNS STRING SONAME 'audit_log.so';
CREATE FUNCTION audit_log_filter_remove_filter RETURNS STRING SONAME 'audit_log.so';
CREATE FUNCTION audit_log_filter_set_user RETURNS STRING SONAME 'audit_log.so';
CREATE FUNCTION audit_log_filter_remove_user RETURNS STRING SONAME 'audit_log.so';
CREATE FUNCTION audit_log_filter_flush RETURNS STRING SONAME 'audit_log.so';
CREATE FUNCTION audit_log_read_bookmark RETURNS STRING SONAME 'audit_log.so';
CREATE FUNCTION audit_log_read RETURNS STRING SONAME 'audit_log.so';
CREATE FUNCTION audit_log_encryption_password_set RETURNS INTEGER SONAME 'audit_log.so';
CREATE FUNCTION audit_log_encryption_password_get RETURNS STRING SONAME 'audit_log.so';
SELECT audit_log_filter_flush() AS 'Result';


Step 4: Rotate the log file when the audit log reached 200MB
SET GLOBAL audit_log_rotate_on_size = 1024*1024*1024;
B. Create the log filter and assigned it to specified user. 
Reference: 

Step 5: Create the log filter for logging specified DDL
set @log_ddl_filter='
{
"filter": {
  "class": {
    "name": "general",
    "event": {
      "name": "status",
      "log": {
        "and": [
        {
           "or": [
           {"field": { "name": "general_command.str", "value": "Query" }},
           {"field": { "name": "general_command.str", "value": "Execute" }}
           ]
        },
       {
          "or": [
          {"field": { "name": "general_sql_command.str", "value": "alter_db" }},
          {"field": { "name": "general_sql_command.str", "value": "alter_db_upgrade" }},
          {"field": { "name": "general_sql_command.str", "value": "alter_event" }},
          {"field": { "name": "general_sql_command.str", "value": "alter_function" }},
          {"field": { "name": "general_sql_command.str", "value": "alter_instance" }},
          {"field": { "name": "general_sql_command.str", "value": "alter_procedure" }},
          {"field": { "name": "general_sql_command.str", "value": "alter_server" }},
          {"field": { "name": "general_sql_command.str", "value": "alter_table" }},
          {"field": { "name": "general_sql_command.str", "value": "alter_tablespace" }},
          {"field": { "name": "general_sql_command.str", "value": "create_db" }},
          {"field": { "name": "general_sql_command.str", "value": "create_event" }},
          {"field": { "name": "general_sql_command.str", "value": "create_function" }},
          {"field": { "name": "general_sql_command.str", "value": "create_index" }},
          {"field": { "name": "general_sql_command.str", "value": "create_procedure" }},
          {"field": { "name": "general_sql_command.str", "value": "create_server" }},
          {"field": { "name": "general_sql_command.str", "value": "create_table" }},
          {"field": { "name": "general_sql_command.str", "value": "create_trigger" }},
          {"field": { "name": "general_sql_command.str", "value": "create_udf" }},
          {"field": { "name": "general_sql_command.str", "value": "create_view" }},
          {"field": { "name": "general_sql_command.str", "value": "drop_db" }},
          {"field": { "name": "general_sql_command.str", "value": "drop_event" }},
          {"field": { "name": "general_sql_command.str", "value": "drop_function" }},
          {"field": { "name": "general_sql_command.str", "value": "drop_index" }},
          {"field": { "name": "general_sql_command.str", "value": "drop_procedure" }},
          {"field": { "name": "general_sql_command.str", "value": "drop_server" }},
          {"field": { "name": "general_sql_command.str", "value": "drop_table" }},
          {"field": { "name": "general_sql_command.str", "value": "drop_trigger" }},
          {"field": { "name": "general_sql_command.str", "value": "drop_view" }},
          {"field": { "name": "general_sql_command.str", "value": "rename_table" }}
          ]
       }
    ]
    }
   }
  }
 }
}';

Step 6: Apply the filter for all DB users
Verify the filter is a valid JSON object:
use mysql;
select json_valid(@log_ddl_filter);
Remove any previous version of the filter:
select audit_log_filter_remove_filter('log_specified_ddl');
Set the new filter:
select audit_log_filter_set_filter('log_specified_ddl',@log_ddl_filter); 
Specify which user(s) the filter should apply to, e.g. apply the filter to all user.
Remark: The filter can be assigned to any user account if the user has no assigned filter.
select audit_log_filter_set_user('%','log_specified_ddl');
Enquiry the created audit filter 
select * from audit_log_filter where name = 'log_specified_ddl' \G
Enquiry the audit user account that has assigned filter.
select * from audit_log_user;

Friday, 16 August 2019

Restoring the failed member in MySQL InnoDB cluster with MySQL Enterprise Backup

Using MySQL Enterprise Backup to restore and rebuild the failed member in secondary node

Testing Environment:

Linux OS: CentOS 7.4
MySQL Server Version: 8.0
MySQL Enterprise Backup 8.0
MySQL Enterprise Transparent Encryption Encryption 
MySQL InnoDB cluster 8.0

Host: primary01 as primary node
Host: second02 as secondary node

A. Pre-Task: 

1. Taking Full-backup with Compression on secondary using MySQL Enterprise Backup

mysqlbackup --defaults-file=my.cnf --backup_image=/backup/mysqld/my.mbi_`date +%d%m_%H%M` --backup-dir=/backup/mysqld/backup_`date +%d%m_%H%M` --user=mysbackup -p --host=second02 --port=3306 --encrypt-password= --compress --compress-level=5  backup-to-image &>> `date +%d%m_%H%M`_full_compress_tde_mysqld_backup.log

2. check backup log with "completed" and please ignore the warning since the backup was taken on secondary node.

ySQL Enterprise Backup  Ver 8.0.15-commercial for linux-glibc2.12 on x86_64 (MySQL Enterprise - Commercial)
Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

190816 16:56:26 MAIN    INFO: A thread created with Id '140676524181376'
190816 16:56:26 MAIN    INFO: Starting with following command line ...
 mysqlbackup
        --defaults-file=my.cnf
        --backup_image=/backup/mysqld/my.mbi_1608_1656
        --backup-dir=/backup/mysqld/backup_1608_1656
        --user=mysbackup -pxxxxxxxxxxxx --host=second02 --port=3306
        --encrypt-password=xxxxxxxxxx --compress --compress-level=5
        backup-to-image

190816 16:56:26 MAIN    INFO:
190816 16:56:26 MAIN    INFO: No SSL options specified.
190816 16:56:26 MAIN    INFO: MySQL server version is '8.0.15-commercial'
190816 16:56:26 MAIN    INFO: MySQL server compile os version is 'linux-glibc2.12'
190816 16:56:26 MAIN    INFO: SSL/TLS version used for connection is TLSv1.2
190816 16:56:26 MAIN WARNING: This backup operation cannot write to backup progress. The MySQL server is running with the --super-read-only option.
....
mysqlbackup completed OK! with 1 warnings

B. Task: Restore the backup on secondary node
1.Stop MySQL server
mysql -u mysql -p password  -hsecond02 -P3306 -e "shutdown"

2. remove all data files under mysql database data directory
rm -rf /data/mysqld
mkdir -p /data/mysqld

3. remove all log files and the keyring files 
rm -rf /data/mysql-keyring
mkdir -p /data/mysql-keyring
rm -rf /data/log
mkdir -p /data/log

4. create restore directory
mkdir -p /backup/mysqld/restore

5. restore backup 
mysqlbackup --defaults-file=/my.cnf --backup-image=/backup/mysqld/ --backup-dir=/backup/mysqld/restore --datadir=/data/mysqld --user=mysbackup -p password  --host=second02 --port=3306 --encrypt-password= encryption_password  --uncompress copy-back-and-apply-log &>> `date +%d%m_%H%M`_full_compress_tde_mysqld_restore.log

C. Post-Task: Re-join as a New Member in MySQL InnoDB cluster
1. Start restored MySQL Server
mysqld_safe --defaults-file=my.cnf &

2. Reset group replication member status
mysql -u mysql -p password -hsecond02 -P3306
mysql> RESET MASTER;
mysql> RESET SLAVE ALL;


*Remark: please follow the below steps if enabled auto recover using group replication's built-in mechanism with the variable "gtid_executed
//start

mysql> SET sql_log_bin=off;
mysql> source /data/mysqld/backup_gtid_executed.sql
mysql> SET sql_log_bin=on;

//end

3. Re-join the restored server in MySQL InnoDB cluster
mysqlsh --uri=mysql:password @primary01:3306

MySQL  primary01:3306 ssl  JS > var x = dba.getCluster();
MySQL  primary01:3306 ssl  JS > x.rescan();
Rescanning the cluster...

Result of the rescanning operation for the 'default' ReplicaSet:
{
    "name": "default", 
    "newTopologyMode": null, 
    "newlyDiscoveredInstances": [], 
    "unavailableInstances": [
        {
            "host": "second02:3306", 
            "label": "second02:3306", 
            "member_id": "4e1eff7d-bf22-11e9-93f4-080027ea2dcf"
        }
    ]
}

The instance 'second02:3306' is no longer part of the ReplicaSet.
The instance is either offline or left the HA group. You can try to add it to the cluster again with the cluster.rejoinInstance('second02:3306') command or you can remove it from the cluster configuration.
Would you like to remove it from the cluster metadata? [Y/n]: y 
Removing instance from the cluster metadata...
The instance 'second02:3306' was successfully removed from the cluster metadata.

MySQL  primary01:3306 ssl  JS > dba.checkInstanceConfiguration('group_replication_user:group_replication_password@second02:3306');
MySQL  primary01:3306 ssl  JS > dba.configureInstance('mysadm:mysadm43d@second02:3306', {clusterAdmin:'group_replication_user',clusterAdminPassword:'group_replication_password'});
dba.checkInstanceConfiguration('group_replication_user:group_replication_password@second02:3306');
MySQL  primary01:3306 ssl  JS > x.status();
MySQL  primary01:3306 ssl  JS >x.addInstance('group_replication_user:group_replication_password>@second02:3306');
MySQL  primary01:3306 ssl  JS > x.status();
{
    "clusterName": "CC_CLU01", 
    "defaultReplicaSet": {
        "name": "default", 
        "primary": "primary01:3306", 
        "ssl": "REQUIRED", 
        "status": "OK_NO_TOLERANCE", 
        "statusText": "Cluster is NOT tolerant to any failures.", 
        "topology": {
            "primary01:3310": {
                "address": "primary01:3306", 
                "mode": "R/W", 
                "readReplicas": {}, 
                "role": "HA", 
                "status": "ONLINE"
            }, 
            "second02:3310": {
                "address": "second02:3306", 
                "mode": "R/O", 
                "readReplicas": {}, 
                "role": "HA", 
                "status": "ONLINE"
            }
        }, 
        "topologyMode": "Single-Primary"
    }, 
    "groupInformationSourceMember": "primary01:3306"
}


3. check member status after re-join the restored server in MySQL InnoDB cluster
mysql -u mysql -p password  -hsecond02 -P3306
mysql> SELECT member_host, member_port, member_state FROM performance_schema.replication_group_members;
+-------------+-------------+--------------+
| member_host | member_port | member_state |
+-------------+-------------+--------------+
| primary01   |        3306 | ONLINE       |
| second02    |        3306 | ONLINE       |
+-------------+-------------+--------------+
2 rows in set (0.00 sec)

mysql>