Mysql:6.4.2-6.4.8:Security Plugins & Component & Enterprise-Extend
- 6.4.2 The Connection-Control Plugins
- 6.4.3 The Password Validation Component
- 6.4.4 The MySQL Keyring
- 6.4.5 MySQL Enterprise Audit
- 6.4.6 The Audit Message Component
- 6.4.7 MySQL Enterprise Firewall
- 6.4.8 MySQL Enterprise Data Masking and De-Identification
MySQL Server includes a plugin library that enables administrators to introduce an increasing delay in server response to clients after a certain number of consecutive failed connection attempts. This capability provides a deterrent that slows down brute force attacks that attempt to access MySQL user accounts. The plugin library contains two plugins:
-
CONNECTION_CONTROL
checks incoming connections and adds a delay to server responses as necessary. This plugin also exposes system variables that enable its operation to be configured and a status variable that provides rudimentary monitoring information.The
CONNECTION_CONTROL
plugin uses the audit plugin interface (see Section 29.2.4.8, “Writing Audit Plugins”). To collect information, it subscribes to theMYSQL_AUDIT_CONNECTION_CLASSMASK
event class, and processesMYSQL_AUDIT_CONNECTION_CONNECT
andMYSQL_AUDIT_CONNECTION_CHANGE_USER
subevents to check whether the server should introduce a delay before responding to client connection attempts. -
CONNECTION_CONTROL_FAILED_LOGIN_ATTEMPTS
implements anINFORMATION_SCHEMA
table that exposes more detailed monitoring information for failed connection attempts.
The following sections provide information about connection-control plugin installation and configuration. For information about the CONNECTION_CONTROL_FAILED_LOGIN_ATTEMPTS
table, see Section 25.47.1, “The INFORMATION_SCHEMA CONNECTION_CONTROL_FAILED_LOGIN_ATTEMPTS Table”.
This section describes how to install the connection-control plugins, CONNECTION_CONTROL
and CONNECTION_CONTROL_FAILED_LOGIN_ATTEMPTS
. For general information about installing plugins, see Section 5.6.1, “Installing and Uninstalling Plugins”.
To be usable by the server, the plugin library file must be located in the MySQL plugin directory (the directory named by the plugin_dir
system variable). If necessary, configure the plugin directory location by setting the value of plugin_dir
at server startup.
The plugin library file base name is connection_control
. The file name suffix differs per platform (for example, .so
for Unix and Unix-like systems, .dll
for Windows).
To load the plugins at server startup, use the --plugin-load-add
option to name the library file that contains them. With this plugin-loading method, the option must be given each time the server starts. For example, put these lines in the server my.cnf
file (adjust the .so
suffix for your platform as necessary):
[mysqld] plugin-load-add=connection_control.so
After modifying my.cnf
, restart the server to cause the new settings to take effect.
Alternatively, to load the plugins at runtime, use these statements (adjust the .so
suffix for your platform as necessary):
INSTALL PLUGIN CONNECTION_CONTROL SONAME 'connection_control.so'; INSTALL PLUGIN CONNECTION_CONTROL_FAILED_LOGIN_ATTEMPTS SONAME 'connection_control.so';
INSTALL PLUGIN
loads the plugin immediately, and also registers it in the mysql.plugins
system table to cause the server to load it for each subsequent normal startup without the need for --plugin-load-add
.
To verify plugin installation, examine the INFORMATION_SCHEMA.PLUGINS
table or use the SHOW PLUGINS
statement (see Section 5.6.2, “Obtaining Server Plugin Information”). For example:
SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME LIKE 'connection%';
If a plugin fails to initialize, check the server error log for diagnostic messages.
If the plugins have been previously registered with INSTALL PLUGIN
or are loaded with --plugin-load-add
, you can use the --connection-control
and --connection-control-failed-login-attempts
options at server startup to control plugin activation. For example, to load the plugins at startup and prevent them from being removed at runtime, use these options:
[mysqld] plugin-load-add=connection_control.so connection-control=FORCE_PLUS_PERMANENT connection-control-failed-login-attempts=FORCE_PLUS_PERMANENT
If it is desired to prevent the server from running without a given connection-control plugin, use an option value of FORCE
or FORCE_PLUS_PERMANENT
to force server startup to fail if the plugin does not initialize successfully.
It is possible to install one plugin without the other, but both must be installed for full connection-control capability. In particular, installing only the CONNECTION_CONTROL_FAILED_LOGIN_ATTEMPTS
plugin is of little use because without the CONNECTION_CONTROL
plugin to provide the data that populates the CONNECTION_CONTROL_FAILED_LOGIN_ATTEMPTS
table, retrievals from the table will always be empty.
To enable you to configure its operation, the CONNECTION_CONTROL
plugin exposes several system variables:
-
connection_control_failed_connections_threshold
: The number of consecutive failed connection attempts permitted to clients before the server adds a delay for subsequent connection attempts. -
connection_control_min_connection_delay
: The amount of delay to add for each consecutive connection failure above the threshold. -
connection_control_max_connection_delay
: The maximum delay to add.
To entirely disable checking for failed connection attempts, set connection_control_failed_connections_threshold
to zero. If connection_control_failed_connections_threshold
is nonzero, the amount of delay is zero up through that many consecutive failed connection attempts. Thereafter, the amount of delay is the number of failed attempts above the threshold, multiplied by connection_control_min_connection_delay
milliseconds. For example, with the default connection_control_failed_connections_threshold
and connection_control_min_connection_delay
values of 3 and 1000, respectively, there is no delay for the first three consecutive failed connection attempts by a client, a delay of 1000 milliseconds for the fourth failed attempt, 2000 milliseconds for the fifth failed attempt, and so on, up to the maximum delay permitted by connection_control_max_connection_delay
.
You can set the CONNECTION_CONTROL
system variables at server startup or runtime. Suppose that you want to permit four consecutive failed connection attempts before the server starts delaying its responses, and to increase the delay by 1500 milliseconds for each additional failure after that. To set the relevant variables at server startup, put these lines in the server my.cnf
file:
[mysqld] plugin-load-add=connection_control.so connection_control_failed_connections_threshold=4 connection_control_min_connection_delay=1500
To set and persist the variables at runtime, use these statements:
SET PERSIST connection_control_failed_connections_threshold = 4; SET PERSIST connection_control_min_connection_delay = 1500;
SET PERSIST
sets the value for the running MySQL instance. It also saves the value, causing it to be used for subsequent server restarts. To change a value for the running MySQL instance without saving it for subsequent restarts, use the GLOBAL
keyword rather than PERSIST
. See Section 13.7.6.1, “SET Syntax for Variable Assignment”.
The connection_control_min_connection_delay
and connection_control_max_connection_delay
system variables have fixed minimum and maximum values of 1000 and 2147483647, respectively. In addition, the permitted range of values of each variable also depends on the current value of the other:
-
connection_control_min_connection_delay
cannot be set greater than the current value ofconnection_control_max_connection_delay
. -
connection_control_max_connection_delay
cannot be set less than the current value ofconnection_control_min_connection_delay
.
Thus, to make the changes required for some configurations, you might need to set the variables in a specific order. Suppose that the current minimum and maximum delays are 1000 and 2000, and that you want to set them to 3000 and 5000. You cannot first set connection_control_min_connection_delay
to 3000 because that is greater than the current connection_control_max_connection_delay
value of 2000. Instead, set connection_control_max_connection_delay
to 5000, then set connection_control_min_connection_delay
to 3000.
When the CONNECTION_CONTROL
plugin is installed, it checks connection attempts and tracks whether they fail or succeed. For this purpose, a failed connection attempt is one for which the client user and host match a known MySQL account but the provided credentials are incorrect, or do not match any known account.
Failed-connection counting is based on the user/host combination for each connection attempt. Determination of the applicable user name and host name takes proxying into account and occurs as follows:
-
If the client user proxies another user, the proxying user's information is used. For example, if
external_user@example.com
proxiesproxy_user@example.com
, connection counting uses the proxying user,external_user@example.com
, rather than the proxied user,proxy_user@example.com
. Bothexternal_user@example.com
andproxy_user@example.com
must have valid entries in themysql.user
system table and a proxy relationship between them must be defined in themysql.proxies_priv
system table (see Section 6.2.18, “Proxy Users”). -
If the client user does not proxy another user, but does match a
mysql.user
entry, counting uses theCURRENT_USER()
value corresponding to that entry. For example, if a useruser1
connecting from a hosthost1.example.com
matches auser1@host1.example.com
entry, counting usesuser1@host1.example.com
. If the user matches auser1@%.example.com
,user1@%.com
, oruser1@%
entry instead, counting usesuser1@%.example.com
,user1@%.com
, oruser1@%
, respectively.
For the cases just described, the connection attempt matches some mysql.user
entry, and whether the request succeeds or fails depends on whether the client provides the correct authentication credentials. For example, if the client presents an incorrect password, the connection attempt fails.
If the connection attempt matches no mysql.user
entry, the attempt fails. In this case, no CURRENT_USER()
value is available and connection-failure counting uses the user name provided by the client and the client host as determined by the server. For example, if a client attempts to connect as user user2
from host host2.example.com
, the user name part is available in the client request and the server determines the host information. The user/host combination used for counting is user2@host2.example.com
.
The server maintains information about which client hosts can possibly connect to the server (essentially the union of host values for mysql.user
entries). If a client attempts to connect from any other host, the server rejects the attempt at an early stage of connection setup:
ERROR 1130 (HY000): Host 'host_name
' is not
allowed to connect to this MySQL server
Because this type of rejection occurs so early, CONNECTION_CONTROL
does not see it, and does not count it.
To monitor failed connections, use these information sources:
-
The
Connection_control_delay_generated
status variable indicates the number of times the server added a delay to its response to a failed connection attempt. This does not count attempts that occur before reaching the threshold defined by theconnection_control_failed_connections_threshold
system variable. -
The
INFORMATION_SCHEMA
CONNECTION_CONTROL_FAILED_LOGIN_ATTEMPTS
table provides information about the current number of consecutive failed connection attempts per client user/host combination. This counts all failed attempts, regardless of whether they were delayed.
Assigning a value to connection_control_failed_connections_threshold
at runtime resets all accumulated failed-connection counters to zero, which has these visible effects:
-
The
Connection_control_delay_generated
status variable is reset to zero. -
The
CONNECTION_CONTROL_FAILED_LOGIN_ATTEMPTS
table becomes empty.
This section describes the system and status variables that the CONNECTION_CONTROL
plugin provides to enable its operation to be configured and monitored.
If the CONNECTION_CONTROL
plugin is installed, it exposes these system variables:
-
connection_control_failed_connections_threshold
Property Value Command-Line Format --connection-control-failed-connections-threshold=#
System Variable connection_control_failed_connections_threshold
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type Integer Default Value 3
Minimum Value 0
Maximum Value 2147483647
The number of consecutive failed connection attempts permitted to clients before the server adds a delay for subsequent connection attempts:
-
If the variable has a nonzero value
N
, the server adds a delay beginning with consecutive failed attemptN
+1. If a client has reached the point where connection responses are delayed, the delay also occurs for the next subsequent successful connection. -
Setting this variable to zero disables failed-connection counting. In this case, the server never adds delays.
For information about how
connection_control_failed_connections_threshold
interacts with other connection-control system and status variables, see Section 6.4.2.1, “Connection-Control Plugin Installation”. -
-
connection_control_max_connection_delay
Property Value Command-Line Format --connection-control-max-connection-delay=#
System Variable connection_control_max_connection_delay
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type Integer Default Value 2147483647
Minimum Value 1000
Maximum Value 2147483647
The maximum delay in milliseconds for server response to failed connection attempts, if
connection_control_failed_connections_threshold
is greater than zero.For information about how
connection_control_max_connection_delay
interacts with other connection-control system and status variables, see Section 6.4.2.1, “Connection-Control Plugin Installation”. -
connection_control_min_connection_delay
Property Value Command-Line Format --connection-control-min-connection-delay=#
System Variable connection_control_min_connection_delay
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type Integer Default Value 1000
Minimum Value 1000
Maximum Value 2147483647
The minimum delay in milliseconds for server response to failed connection attempts, if
connection_control_failed_connections_threshold
is greater than zero. This is also the amount by which the server increases the delay for additional successive failures once it begins delaying.For information about how
connection_control_min_connection_delay
interacts with other connection-control system and status variables, see Section 6.4.2.1, “Connection-Control Plugin Installation”.
If the CONNECTION_CONTROL
plugin is installed, it exposes this status variable:
-
Connection_control_delay_generated
The number of times the server added a delay to its response to a failed connection attempt. This does not count attempts that occur before reaching the threshold defined by the
connection_control_failed_connections_threshold
system variable.This variable provides a simple counter. For more detailed connection-control monitoring information, examine the
INFORMATION_SCHEMA
CONNECTION_CONTROL_FAILED_LOGIN_ATTEMPTS
table; see Section 25.47.1, “The INFORMATION_SCHEMA CONNECTION_CONTROL_FAILED_LOGIN_ATTEMPTS Table”.Assigning a value to
connection_control_failed_connections_threshold
at runtime resetsConnection_control_delay_generated
to zero.
The validate_password
component serves to improve security by requiring account passwords and enabling strength testing of potential passwords. This component exposes system variables that enable you to configure password policy, and status variables for component monitoring.
In MySQL 8.0, the validate_password
plugin was reimplemented as the validate_password
component. (For general information about server components, see Section 5.5, “MySQL Server Components”.) The following instructions describe how to use the component, not the plugin. For instructions on using the plugin form of validate_password
, see The Password Validation Plugin in MySQL 5.7 Reference Manual.
The plugin form of validate_password
is still available but is deprecated and will be removed in a future version of MySQL. MySQL installations that use the plugin should make the transition to using the component instead. See Section 6.4.3.3, “Transitioning to the Password Validation Component”.
The validate_password
component implements these capabilities:
-
For SQL statements that assign a password supplied as a cleartext value,
validate_password
checks the password against the current password policy and rejects the password if it is weak (the statement returns anER_NOT_VALID_PASSWORD
error). This applies to theALTER USER
,CREATE USER
, andSET PASSWORD
statements. -
For
CREATE USER
statements,validate_password
requires that a password be given, and that it satisfies the password policy. This is true even if an account is locked initially because otherwise unlocking the account later would cause it to become accessible without a password that satisfies the policy. -
validate_password
implements aVALIDATE_PASSWORD_STRENGTH()
SQL function that assesses the strength of potential passwords. This function takes a password argument and returns an integer from 0 (weak) to 100 (strong).
For statements that assign or modify account passwords (ALTER USER
, CREATE USER
, and SET PASSWORD
), the validate_password
capabilities described here apply only to accounts that use an authentication plugin that stores credentials internally to MySQL. For accounts that use plugins that perform authentication against a credentials system external to MySQL, password management must be handled externally against that system as well. For more information about internal credentials storage, see Section 6.2.15, “Password Management”.
The preceding restriction does not apply to use of the VALIDATE_PASSWORD_STRENGTH()
function because it does not affect accounts directly.
Examples:
-
validate_password
checks the cleartext password in the following statement. Under the default password policy, which requires passwords to be at least 8 characters long, the password is weak and the statement produces an error:mysql>
ALTER USER USER() IDENTIFIED BY 'abc';
ERROR 1819 (HY000): Your password does not satisfy the current policy requirements -
Passwords specified as hashed values are not checked because the original password value is not available for checking:
ALTER USER 'jeffrey'@'localhost' IDENTIFIED WITH mysql_native_password AS '*0D3CED9BEC10A777AEC23CCC353A8C08A633045E'; -
This account-creation statement fails, even though the account is locked initially, because it does not include a password that satisfies the current password policy:
mysql>
CREATE USER 'juanita'@'localhost' ACCOUNT LOCK;
ERROR 1819 (HY000): Your password does not satisfy the current policy requirements -
To check a password, use the
VALIDATE_PASSWORD_STRENGTH()
function:SELECT VALIDATE_PASSWORD_STRENGTH('weak'); SELECT VALIDATE_PASSWORD_STRENGTH('lessweak$_@123'); SELECT VALIDATE_PASSWORD_STRENGTH('N0Tweak$_@123!');
To configure password checking, modify the system variables having names of the form validate_password.
; these are the parameters that control password policy. See Section 6.4.3.2, “Password Validation Options and Variables”.xxx
If validate_password
is not installed, the validate_password.
system variables are not available, passwords in statements are not checked, and the xxx
VALIDATE_PASSWORD_STRENGTH()
function always returns 0. For example, without the plugin installed, accounts can be assigned passwords shorter than 8 characters, or no password at all.
Assuming that validate_password
is installed, it implements three levels of password checking: LOW
, MEDIUM
, and STRONG
. The default is MEDIUM
; to change this, modify the value of validate_password.policy
. The policies implement increasingly strict password tests. The following descriptions refer to default parameter values, which can be modified by changing the appropriate system variables.
-
LOW
policy tests password length only. Passwords must be at least 8 characters long. To change this length, modifyvalidate_password.length
. -
MEDIUM
policy adds the conditions that passwords must contain at least 1 numeric character, 1 lowercase character, 1 uppercase character, and 1 special (nonalphanumeric) character. To change these values, modifyvalidate_password.number_count
,validate_password.mixed_case_count
, andvalidate_password.special_char_count
. -
STRONG
policy adds the condition that password substrings of length 4 or longer must not match words in the dictionary file, if one has been specified. To specify the dictionary file, modifyvalidate_password.dictionary_file
.
In addition, validate_password
supports the capability of rejecting passwords that match the user name part of the effective user account for the current session, either forward or in reverse. To provide control over this capability, validate_password
exposes a validate_password.check_user_name
system variable, which is enabled by default.
This section describes how to install and uninstall the validate_password
password-validation component. For general information about installing and uninstalling components, see Section 5.5, “MySQL Server Components”.
If you install MySQL 8.0 using the MySQL Yum repository, MySQL SLES Repository, or RPM packages provided by Oracle, the validate_password
component is enabled by default after you start your MySQL Server for the first time.
Upgrades to MySQL 8.0 from 5.7 using Yum or RPM packages leave the validate_password
plugin in place. To make the transition from the validate_password
plugin to the validate_password
component, see Section 6.4.3.3, “Transitioning to the Password Validation Component”.
To be usable by the server, the component library file must be located in the MySQL plugin directory (the directory named by the plugin_dir
system variable). If necessary, configure the plugin directory location by setting the value of plugin_dir
at server startup.
To install the validate_password
component, use this statement:
INSTALL COMPONENT 'file://component_validate_password';
Component installation is a one-time operation that need not be done per server startup. INSTALL COMPONENT
loads the component, and also registers it in the mysql.component
system table to cause it to be loaded during subsequent server startups.
To uninstall the validate_password
component, use this statement:
UNINSTALL COMPONENT 'file://component_validate_password';
UNINSTALL COMPONENT
unloads the component, and deregisters it from the mysql.component
system table to cause it not to be loaded during subsequent server startups.
This section describes the system and status variables that validate_password
provides to enable its operation to be configured and monitored.
If the validate_password
component is enabled, it exposes several system variables that enable configuration of password checking:
mysql> SHOW VARIABLES LIKE 'validate_password.%';
+--------------------------------------+--------+
| Variable_name | Value |
+--------------------------------------+--------+
| validate_password.check_user_name | ON |
| validate_password.dictionary_file | |
| validate_password.length | 8 |
| validate_password.mixed_case_count | 1 |
| validate_password.number_count | 1 |
| validate_password.policy | MEDIUM |
| validate_password.special_char_count | 1 |
+--------------------------------------+--------+
To change how passwords are checked, you can set these system variables at server startup or at runtime. The following list describes the meaning of each variable.
-
validate_password.check_user_name
Property Value Command-Line Format --validate-password.check-user-name[={OFF|ON}]
System Variable validate_password.check_user_name
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type Boolean Default Value ON
Whether
validate_password
compares passwords to the user name part of the effective user account for the current session and rejects them if they match. This variable is unavailable unlessvalidate_password
is installed.By default,
validate_password.check_user_name
is enabled. This variable controls user name matching independent of the value ofvalidate_password.policy
.When
validate_password.check_user_name
is enabled, it has these effects:-
Checking occurs in all contexts for which
validate_password
is invoked, which includes use of statements such asALTER USER
orSET PASSWORD
to change the current user's password, and invocation of functions such asVALIDATE_PASSWORD_STRENGTH()
. -
The user names used for comparison are taken from the values of the
USER()
andCURRENT_USER()
functions for the current session. An implication is that a user who has sufficient privileges to set another user's password can set the password to that user's name, and cannot set that user's password to the name of the user executing the statement. For example,'root'@'localhost'
can set the password for'jeffrey'@'localhost'
to'jeffrey'
, but cannot set the password to'root
. -
Only the user name part of the
USER()
andCURRENT_USER()
function values is used, not the host name part. If a user name is empty, no comparison occurs. -
If a password is the same as the user name or its reverse, a match occurs and the password is rejected.
-
User-name matching is case sensitive. The password and user name values are compared as binary strings on a byte-by-byte basis.
-
If a password matches the user name,
VALIDATE_PASSWORD_STRENGTH()
returns 0 regardless of how othervalidate_password
system variables are set.
-
-
validate_password.dictionary_file
Property Value Command-Line Format --validate-password.dictionary-file=file_name
System Variable validate_password.dictionary_file
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type File name The path name of the dictionary file that
validate_password
uses for checking passwords. This variable is unavailable unlessvalidate_password
is installed.By default, this variable has an empty value and dictionary checks are not performed. For dictionary checks to occur, the variable value must be nonempty. If the file is named as a relative path, it is interpreted relative to the server data directory. File contents should be lowercase, one word per line. Contents are treated as having a character set of
utf8
. The maximum permitted file size is 1MB.For the dictionary file to be used during password checking, the password policy must be set to 2 (
STRONG
); see the description of thevalidate_password.policy
system variable. Assuming that is true, each substring of the password of length 4 up to 100 is compared to the words in the dictionary file. Any match causes the password to be rejected. Comparisons are not case sensitive.For
VALIDATE_PASSWORD_STRENGTH()
, the password is checked against all policies, includingSTRONG
, so the strength assessment includes the dictionary check regardless of thevalidate_password.policy
value.validate_password.dictionary_file
can be set at runtime and assigning a value causes the named file to be read without a server restart. -
Property Value Command-Line Format --validate-password.length=#
System Variable validate_password.length
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type Integer Default Value 8
Minimum Value 0
The minimum number of characters that
validate_password
requires passwords to have. This variable is unavailable unlessvalidate_password
is installed.The
validate_password.length
minimum value is a function of several other related system variables. The value cannot be set less than the value of this expression:validate_password.number_count + validate_password.special_char_count + (2 * validate_password.mixed_case_count)
If
validate_password
adjusts the value ofvalidate_password.length
due to the preceding constraint, it writes a message to the error log. -
validate_password.mixed_case_count
Property Value Command-Line Format --validate-password.mixed-case-count=#
System Variable validate_password.mixed_case_count
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type Integer Default Value 1
Minimum Value 0
The minimum number of lowercase and uppercase characters that
validate_password
requires passwords to have if the password policy isMEDIUM
or stronger. This variable is unavailable unlessvalidate_password
is installed.For a given
validate_password.mixed_case_count
value, the password must have that many lowercase characters, and that many uppercase characters. -
validate_password.number_count
Property Value Command-Line Format --validate-password.number-count=#
System Variable validate_password.number_count
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type Integer Default Value 1
Minimum Value 0
The minimum number of numeric (digit) characters that
validate_password
requires passwords to have if the password policy isMEDIUM
or stronger. This variable is unavailable unlessvalidate_password
is installed. -
Property Value Command-Line Format --validate-password.policy=value
System Variable validate_password.policy
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type Enumeration Default Value 1
Valid Values 0
1
2
The password policy enforced by
validate_password
. This variable is unavailable unlessvalidate_password
is installed.validate_password.policy
affects howvalidate_password
uses its other policy-setting system variables, except for checking passwords against user names, which is controlled independently byvalidate_password.check_user_name
.The
validate_password.policy
value can be specified using numeric values 0, 1, 2, or the corresponding symbolic valuesLOW
,MEDIUM
,STRONG
. The following table describes the tests performed for each policy. For the length test, the required length is the value of thevalidate_password.length
system variable. Similarly, the required values for the other tests are given by othervalidate_password.
variables.xxx
Policy Tests Performed 0
orLOW
Length 1
orMEDIUM
Length; numeric, lowercase/uppercase, and special characters 2
orSTRONG
Length; numeric, lowercase/uppercase, and special characters; dictionary file -
validate_password.special_char_count
Property Value Command-Line Format --validate-password.special-char-count=#
System Variable validate_password.special_char_count
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type Integer Default Value 1
Minimum Value 0
The minimum number of nonalphanumeric characters that
validate_password
requires passwords to have if the password policy isMEDIUM
or stronger. This variable is unavailable unlessvalidate_password
is installed.
If the validate_password
component is enabled, it exposes status variables that provide operational information:
mysql> SHOW STATUS LIKE 'validate_password.%';
+-----------------------------------------------+---------------------+
| Variable_name | Value |
+-----------------------------------------------+---------------------+
| validate_password.dictionary_file_last_parsed | 2019-10-03 08:33:49 |
| validate_password.dictionary_file_words_count | 1902 |
+-----------------------------------------------+---------------------+
The following list describes the meaning of each status variable.
-
validate_password.dictionary_file_last_parsed
When the dictionary file was last parsed. This variable is unavailable unless
validate_password
is installed. -
validate_password.dictionary_file_words_count
The number of words read from the dictionary file. This variable is unavailable unless
validate_password
is installed.
In MySQL 8.0, the validate_password
plugin was reimplemented as the validate_password
component. The validate_password
plugin is deprecated and will be removed in a future version of MySQL. Consequently, its options are also deprecated and will be removed. MySQL installations that use the plugin should make the transition to using the component instead. See Section 6.4.3.3, “Transitioning to the Password Validation Component”.
To control activation of the validate_password
plugin, use this option:
-
Property Value Command-Line Format --validate-password[=value]
Type Enumeration Default Value ON
Valid Values ON
OFF
FORCE
FORCE_PLUS_PERMANENT
This option controls how the server loads the deprecated
validate_password
plugin at startup. The value should be one of those available for plugin-loading options, as described in Section 5.6.1, “Installing and Uninstalling Plugins”. For example,--validate-password=FORCE_PLUS_PERMANENT
tells the server to load the plugin at startup and prevents it from being removed while the server is running.This option is available only if the
validate_password
plugin has been previously registered withINSTALL PLUGIN
or is loaded with--plugin-load-add
. See Section 6.4.3.1, “Password Validation Component Installation and Uninstallation”.
In MySQL 8.0, the validate_password
plugin was reimplemented as the validate_password
component. The validate_password
plugin is deprecated and will be removed in a future version of MySQL. Consequently, its system variables are also deprecated and will be removed. Use the corresponding system variables of the validate_password
component; see Password Validation Component System Variables. MySQL installations that use the plugin should make the transition to using the component instead. See Section 6.4.3.3, “Transitioning to the Password Validation Component”.
-
validate_password_check_user_name
Property Value Command-Line Format --validate-password-check-user-name[={OFF|ON}]
System Variable validate_password_check_user_name
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type Boolean Default Value ON
This
validate_password
plugin system variable is deprecated and will be removed in a future version of MySQL. Use the correspondingvalidate_password.check_user_name
system variable of thevalidate_password
component instead. -
validate_password_dictionary_file
Property Value Command-Line Format --validate-password-dictionary-file=file_name
System Variable validate_password_dictionary_file
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type File name This
validate_password
plugin system variable is deprecated and will be removed in a future version of MySQL. Use the correspondingvalidate_password.dictionary_file
system variable of thevalidate_password
component instead. -
Property Value Command-Line Format --validate-password-length=#
System Variable validate_password_length
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type Integer Default Value 8
Minimum Value 0
This
validate_password
plugin system variable is deprecated and will be removed in a future version of MySQL. Use the correspondingvalidate_password.length
system variable of thevalidate_password
component instead. -
validate_password_mixed_case_count
Property Value Command-Line Format --validate-password-mixed-case-count=#
System Variable validate_password_mixed_case_count
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type Integer Default Value 1
Minimum Value 0
This
validate_password
plugin system variable is deprecated and will be removed in a future version of MySQL. Use the correspondingvalidate_password.mixed_case_count
system variable of thevalidate_password
component instead. -
validate_password_number_count
Property Value Command-Line Format --validate-password-number-count=#
System Variable validate_password_number_count
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type Integer Default Value 1
Minimum Value 0
This
validate_password
plugin system variable is deprecated and will be removed in a future version of MySQL. Use the correspondingvalidate_password.number_count
system variable of thevalidate_password
component instead. -
Property Value Command-Line Format --validate-password-policy=value
System Variable validate_password_policy
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type Enumeration Default Value 1
Valid Values 0
1
2
This
validate_password
plugin system variable is deprecated and will be removed in a future version of MySQL. Use the correspondingvalidate_password.policy
system variable of thevalidate_password
component instead. -
validate_password_special_char_count
Property Value Command-Line Format --validate-password-special-char-count=#
System Variable validate_password_special_char_count
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type Integer Default Value 1
Minimum Value 0
This
validate_password
plugin system variable is deprecated and will be removed in a future version of MySQL. Use the correspondingvalidate_password.special_char_count
system variable of thevalidate_password
component instead.
In MySQL 8.0, the validate_password
plugin was reimplemented as the validate_password
component. The validate_password
plugin is deprecated and will be removed in a future version of MySQL. Consequently, its status variables are also deprecated and will be removed. Use the corresponding status variables of the validate_password
component; see Password Validation Component Status Variables. MySQL installations that use the plugin should make the transition to using the component instead. See Section 6.4.3.3, “Transitioning to the Password Validation Component”.
-
validate_password_dictionary_file_last_parsed
This
validate_password
plugin status variable is deprecated and will be removed in a future version of MySQL. Use the correspondingvalidate_password.dictionary_file_last_parsed
status variable of thevalidate_password
component instead. -
validate_password_dictionary_file_words_count
This
validate_password
plugin status variable is deprecated and will be removed in a future version of MySQL. Use the correspondingvalidate_password.dictionary_file_words_count
status variable of thevalidate_password
component instead.
In MySQL 8.0, the validate_password
plugin was reimplemented as the validate_password
component. The validate_password
plugin is deprecated and will be removed in a future version of MySQL.
MySQL installations that currently use the validate_password
plugin should make the transition to using the validate_password
component instead. To do so, use the following procedure. The procedure installs the component before uninstalling the plugin, to avoid having a time window during which no password validation occurs. (The component and plugin can be installed simultaneously. In this case, the server attempts to use the component, falling back to the plugin if the component is unavailable.)
-
Install the
validate_password
component:INSTALL COMPONENT 'file://component_validate_password';
-
Test the
validate_password
component to ensure that it works as expected. If you need to set anyvalidate_password.
system variables, you can do so at runtime usingxxx
SET GLOBAL
. (Any option file changes that must be made are performed in the next step.) -
Adjust any references to the plugin system and status variables to refer to the corresponding component system and status variables. Suppose that you configure the plugin at startup using an option file like this:
[mysqld] validate-password=FORCE_PLUS_PERMANENT validate_password_dictionary_file=/usr/share/dict/words validate_password_length=10 validate_password_number_count=2
To adjust the option file, omit the
--validate-password
option (it applies only to the plugin, not the component), and modify the system variable references:[mysqld] validate_password.dictionary_file=/usr/share/dict/words validate_password.length=10 validate_password.number_count=2
Similar adjustments are needed for applications that refer at runtime to
validate_password
plugin system and status variables. -
Uninstall the
validate_password
plugin:UNINSTALL PLUGIN validate_password;
If the
validate_password
plugin is loaded at server startup using a--plugin-load
or--plugin-load-add
option, omit that option from the server startup procedure. For example, if the option is listed in a server option file, remove it from the file. -
Restart the server.
- 6.4.4.1 Keyring Plugin Installation
- 6.4.4.2 Using the keyring_file File-Based Plugin
- 6.4.4.3 Using the keyring_encrypted_file Keyring Plugin
- 6.4.4.4 Using the keyring_okv KMIP Plugin
- 6.4.4.5 Using the keyring_aws Amazon Web Services Keyring Plugin
- 6.4.4.6 Using the HashiCorp Vault Keyring Plugin
- 6.4.4.7 Migrating Keys Between Keyring Keystores
- 6.4.4.8 Supported Keyring Key Types and Lengths
- 6.4.4.9 General-Purpose Keyring Key-Management Functions
- 6.4.4.10 Plugin-Specific Keyring Key-Management Functions
- 6.4.4.11 Keyring Command Options
- 6.4.4.12 Keyring System Variables
MySQL Server supports a keyring that enables internal server components and plugins to securely store sensitive information for later retrieval. The implementation is plugin-based:
-
The
keyring_file
plugin stores keyring data in a file local to the server host. This plugin is available in all MySQL distributions, Community Edition and Enterprise Edition included. See Section 6.4.4.2, “Using the keyring_file File-Based Plugin”. -
The
keyring_encrypted_file
plugin stores keyring data in an encrypted file local to the server host. This plugin is available in MySQL Enterprise Edition distributions. See Section 6.4.4.3, “Using the keyring_encrypted_file Keyring Plugin”. -
keyring_okv
is a KMIP 1.1 plugin for use with KMIP-compatible back end keyring storage products such as Oracle Key Vault and Gemalto SafeNet KeySecure Appliance. This plugin is available in MySQL Enterprise Edition distributions. See Section 6.4.4.4, “Using the keyring_okv KMIP Plugin”. -
The
keyring_aws
plugin communicates with the Amazon Web Services Key Management Service for key generation and uses a local file for key storage. This plugin is available in MySQL Enterprise Edition distributions. See Section 6.4.4.5, “Using the keyring_aws Amazon Web Services Keyring Plugin”. -
MySQL 8.0.18 and higher includes
keyring_hashicorp
, a plugin that communicates with HashiCorp Vault for back end storage. This plugin is available in MySQL Enterprise Edition distributions. See Section 6.4.4.6, “Using the HashiCorp Vault Keyring Plugin”. -
A MySQL server operational mode enables migration of keys between underlying keyring keystores. This enables DBAs to switch a MySQL installation from one keyring plugin to another. See Section 6.4.4.7, “Migrating Keys Between Keyring Keystores”.
-
An SQL interface for keyring key management is implemented as a set of user-defined functions (UDFs). See Section 6.4.4.9, “General-Purpose Keyring Key-Management Functions”.
-
In MySQL 8.0.16 and higher, the
keyring_keys
table exposes metadata for keys in the keyring. Key metadata includes key IDs, key owners, and backend key IDs. Thekeyring_keys
table does not expose any sensitive keyring data such as key contents. See Section 26.12.18.2, “The keyring_keys table”.
The keyring_file
and keyring_encrypted_file
plugins for encryption key management are not intended as a regulatory compliance solution. Security standards such as PCI, FIPS, and others require use of key management systems to secure, manage, and protect encryption keys in key vaults or hardware security modules (HSMs).
Uses for the keyring within MySQL include:
-
The
InnoDB
storage engine uses the keyring to store its key for tablespace encryption.InnoDB
can use any supported keyring plugin. -
MySQL Enterprise Audit uses the keyring to store the audit log file encryption password. The audit log plugin can use any supported keyring plugin.
-
When binary log encryption has been activated for a MySQL server (by setting
binlog_encryption=ON
), the binary log encryption keys used to encrypt the file passwords for the binary log files and relay log files are stored in the keyring. Any supported keyring plugin can be used to store binary log encryption keys. Binary log encryption keys are retained as long as there are files on the server that were encrypted using them. When the binary log master key is rotated manually, all binary log encryption keys that no longer apply to any retained binary log files or relay log files are cleared from the keyring. If a retained binary log file or relay log file cannot be initialized for re-encryption, the relevant binary log encryption keys are not deleted in case the files can be recovered in the future. For example, this might be the case if a file listed in a binary log index file is currently unreadable, or if a channel fails to initialize. For more information, see Section 17.3.2, “Encrypting Binary Log Files and Relay Log Files”.
For general keyring installation instructions, see Section 6.4.4.1, “Keyring Plugin Installation”. For information specific to a given keyring plugin, see the section describing that plugin.
For information about using the keyring UDFs, see Section 6.4.4.9, “General-Purpose Keyring Key-Management Functions”.
Keyring plugins and UDFs access a keyring service that provides the interface for server components to the keyring. For information about accessing the keyring plugin service and writing keyring plugins, see Section 29.3.2, “The Keyring Service”, and Section 29.2.4.12, “Writing Keyring Plugins”.
Keyring service consumers require a keyring plugin to be installed. MySQL provides these plugin choices:
-
keyring_file
: A plugin that stores keyring data in a file local to the server host. Available in all MySQL distributions. -
keyring_encrypted_file
: A plugin that stores keyring data in an encrypted file local to the server host. Available in MySQL Enterprise Edition distributions. -
keyring_okv
: A plugin that uses KMIP-compatible back end keyring storage products such as Oracle Key Vault and Gemalto SafeNet KeySecure Appliance. Available in MySQL Enterprise Edition distributions. -
keyring_aws
: A plugin that communicates with the Amazon Web Services Key Management Service as a back end for key generation and uses a local file for key storage. Available in MySQL Enterprise Edition distributions. -
keyring_hashicorp
: A plugin that communicates with HashiCorp Vault for back end storage. Available in MySQL Enterprise Edition distributions.
This section describes how to install the keyring plugin of your choosing. For general information about installing plugins, see Section 5.6.1, “Installing and Uninstalling Plugins”.
If you intend to use keyring user-defined functions (UDFs) in conjunction with the keyring plugin, install the UDFs following keyring installation using the instructions in Section 6.4.4.9, “General-Purpose Keyring Key-Management Functions”.
To be usable by the server, the plugin library file must be located in the MySQL plugin directory (the directory named by the plugin_dir
system variable). If necessary, configure the plugin directory location by setting the value of plugin_dir
at server startup.
Installation for each keyring plugin is similar. The following instructions use keyring_file
. Users of a different keyring plugin can substitute its name for keyring_file
.
The keyring_file
plugin library file base name is keyring_file
. The file name suffix differs per platform (for example, .so
for Unix and Unix-like systems, .dll
for Windows).
Only one keyring plugin should be enabled at a time. Enabling multiple keyring plugins is unsupported and results may not be as anticipated.
The keyring plugin must be loaded early during the server startup sequence so that server components can access it as necessary during their own initialization. For example, the InnoDB
storage engine uses the keyring for tablespace encryption, so the keyring plugin must be loaded and available prior to InnoDB
initialization.
To load the plugin, use the --early-plugin-load
option to name the plugin library file that contains it. For example, on platforms where the plugin library file suffix is .so
, use these lines in the server my.cnf
file (adjust the .so
suffix for your platform as necessary):
[mysqld] early-plugin-load=keyring_file.so
Before starting the server, check the notes for your chosen keyring plugin to see whether it permits or requires additional configuration:
-
For
keyring_file
: Section 6.4.4.2, “Using the keyring_file File-Based Plugin”. -
For
keyring_okv
: Section 6.4.4.4, “Using the keyring_okv KMIP Plugin”. -
For
keyring_aws
: Section 6.4.4.5, “Using the keyring_aws Amazon Web Services Keyring Plugin” -
For
keyring_hashicorp
: Section 6.4.4.6, “Using the HashiCorp Vault Keyring Plugin”
After performing any plugin-specific configuration, verify plugin installation. With the MySQL server running, examine the INFORMATION_SCHEMA.PLUGINS
table or use the SHOW PLUGINS
statement (see Section 5.6.2, “Obtaining Server Plugin Information”). For example:
SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME LIKE 'keyring%';
If the plugin fails to initialize, check the server error log for diagnostic messages.
If no keyring plugin is available when a server component tries to access the keyring service, the service cannot be used by that component. As a result, the component may fail to initialize or may initialize with limited functionality. For example, if InnoDB
finds that there are encrypted tablespaces when it initializes, it attempts to access the keyring. If the keyring is unavailable, InnoDB
can access only unencrypted tablespaces. To ensure that InnoDB
can access encrypted tablespaces as well, use --early-plugin-load
to load the keyring plugin.
Plugins can be loaded by other methods, such as the --plugin-load
or --plugin-load-add
option or the INSTALL PLUGIN
statement. However, keyring plugins loaded using those methods may be available too late in the server startup sequence for certain server components, such as InnoDB
:
-
Plugin loading using
--plugin-load
or--plugin-load-add
occurs afterInnoDB
initialization. -
Plugins installed using
INSTALL PLUGIN
are registered in themysql.plugin
system table and loaded automatically for subsequent server restarts. However, becausemysql.plugin
is anInnoDB
table, any plugins named in it can be loaded during startup only afterInnoDB
initialization.
The keyring_file
plugin is a keyring plugin that stores keyring data in a file local to the server host.
The keyring_file
plugin for encryption key management is not intended as a regulatory compliance solution. Security standards such as PCI, FIPS, and others require use of key management systems to secure, manage, and protect encryption keys in key vaults or hardware security modules (HSMs).
To install the keyring_file
plugin, use the general keyring installation instructions found in Section 6.4.4.1, “Keyring Plugin Installation”, together with the configuration information specific to keyring_file
found here.
To be usable during the server startup process, keyring_file
must be loaded using the --early-plugin-load
option. The keyring_file_data
system variable optionally configures the location of the file used by the keyring_file
plugin for data storage. The default value is platform specific. To configure the file location explicitly, set the variable value at startup. For example, use these lines in the server my.cnf
file (adjust the .so
suffix and file location for your platform as necessary):
[mysqld] early-plugin-load=keyring_file.so keyring_file_data=/usr/local/mysql/mysql-keyring/keyring
Keyring operations are transactional: The keyring_file
plugin uses a backup file during write operations to ensure that it can roll back to the original file if an operation fails. The backup file has the same name as the value of the keyring_file_data
system variable with a suffix of .backup
.
For additional information about keyring_file_data
, see Section 6.4.4.12, “Keyring System Variables”.
To ensure that keys are flushed only when the correct keyring storage file exists, keyring_file
stores a SHA-256 checksum of the keyring in the file. Before updating the file, the plugin verifies that it contains the expected checksum.
The keyring_file
plugin supports the functions that comprise the standard MySQL Keyring service interface. Keyring operations performed by those functions are accessible at two levels:
-
SQL interface: In SQL statements, call the user-defined functions (UDFs) described in Section 6.4.4.9, “General-Purpose Keyring Key-Management Functions”.
-
C interface: In C-language code, call the keyring service functions described in Section 29.3.2, “The Keyring Service”.
Example (using UDFs):
SELECT keyring_key_generate('MyKey', 'AES', 32); SELECT keyring_key_remove('MyKey');
For information about the key types permitted by keyring_file
, see Section 6.4.4.8, “Supported Keyring Key Types and Lengths”.
The keyring_encrypted_file
plugin is an extension included in MySQL Enterprise Edition, a commercial product. To learn more about commercial products, see https://www.mysql.com/products/.
The keyring_encrypted_file
plugin is a keyring plugin that stores keyring data in an encrypted file local to the server host.
The keyring_encrypted_file
plugin for encryption key management is not intended as a regulatory compliance solution. Security standards such as PCI, FIPS, and others require use of key management systems to secure, manage, and protect encryption keys in key vaults or hardware security modules (HSMs).
To install the keyring_encrypted_file
plugin, use the general keyring installation instructions found in Section 6.4.4.1, “Keyring Plugin Installation”, together with the configuration information specific to keyring_encrypted_file
found here.
To be usable during the server startup process, keyring_encrypted_file
must be loaded using the --early-plugin-load
option. To specify the password for encrypting the keyring data file, set the keyring_encrypted_file_password
system variable. (The password is mandatory; if not specified at server startup, keyring_encrypted_file
initialization fails.) The keyring_encrypted_file_data
system variable optionally configures the location of the file used by the keyring_encrypted_file
plugin for data storage. The default value is platform specific. To configure the file location explicitly, set the variable value at startup. For example, use these lines in the server my.cnf
file (adjust the .so
suffix and file location for your platform as necessary and substitute your chosen password):
[mysqld]
early-plugin-load=keyring_encrypted_file.so
keyring_encrypted_file_data=/usr/local/mysql/mysql-keyring/keyring-encrypted
keyring_encrypted_file_password=password
Because the my.cnf
file stores a password when written as shown, it should have a restrictive mode and be accessible only to the account used to run the MySQL server.
Keyring operations are transactional: The keyring_encrypted_file
plugin uses a backup file during write operations to ensure that it can roll back to the original file if an operation fails. The backup file has the same name as the value of the keyring_encrypted_file_data
system variable with a suffix of .backup
.
For additional information about the system variables used to configure the keyring_encrypted_file
plugin, see Section 6.4.4.12, “Keyring System Variables”.
To ensure that keys are flushed only when the correct keyring storage file exists, keyring_encrypted_file
stores a SHA-256 checksum of the keyring in the file. Before updating the file, the plugin verifies that it contains the expected checksum. In addition, keyring_encrypted_file
encrypts file contents using AES before writing the file, and decrypts file contents after reading the file.
The keyring_encrypted_file
plugin supports the functions that comprise the standard MySQL Keyring service interface. Keyring operations performed by those functions are accessible at two levels:
-
SQL interface: In SQL statements, call the user-defined functions (UDFs) described in Section 6.4.4.9, “General-Purpose Keyring Key-Management Functions”.
-
C interface: In C-language code, call the keyring service functions described in Section 29.3.2, “The Keyring Service”.
Example (using UDFs):
SELECT keyring_key_generate('MyKey', 'AES', 32); SELECT keyring_key_remove('MyKey');
For information about the key types permitted by keyring_encrypted_file
, see Section 6.4.4.8, “Supported Keyring Key Types and Lengths”.
The keyring_okv
plugin is an extension included in MySQL Enterprise Edition, a commercial product. To learn more about commercial products, see https://www.mysql.com/products/.
The Key Management Interoperability Protocol (KMIP) enables communication of cryptographic keys between a key management server and its clients. The keyring_okv
keyring plugin uses the KMIP 1.1 protocol to communicate securely as a client of a KMIP back end. Keyring material is generated exclusively by the back end, not by keyring_okv
. The plugin works with these KMIP-compatible products:
-
Oracle Key Vault
-
Gemalto SafeNet KeySecure Appliance
The keyring_okv
plugin supports the functions that comprise the standard MySQL Keyring service interface. Keyring operations performed by those functions are accessible at two levels:
-
SQL interface: In SQL statements, call the user-defined functions (UDFs) described in Section 6.4.4.9, “General-Purpose Keyring Key-Management Functions”.
-
C interface: In C-language code, call the keyring service functions described in Section 29.3.2, “The Keyring Service”.
Example (using UDFs):
SELECT keyring_key_generate('MyKey', 'AES', 32); SELECT keyring_key_remove('MyKey');
For information about the key types permitted by keyring_okv
, Section 6.4.4.8, “Supported Keyring Key Types and Lengths”.
To install the keyring_okv
plugin, use the general keyring installation instructions found in Section 6.4.4.1, “Keyring Plugin Installation”, together with the configuration information specific to keyring_okv
found here.
Regardless of which KMIP back end the keyring_okv
plugin uses for keyring storage, the keyring_okv_conf_dir
system variable configures the location of the directory used by keyring_okv
for its support files. The default value is empty, so you must set the variable to name a properly configured directory before the plugin can communicate with the KMIP back end. Unless you do so, keyring_okv
writes a message to the error log during server startup that it cannot communicate:
[Warning] Plugin keyring_okv reported: 'For keyring_okv to be initialized, please point the keyring_okv_conf_dir variable to a directory containing Oracle Key Vault configuration file and ssl materials'
The keyring_okv_conf_dir
variable must name a directory that contains the following items:
-
okvclient.ora
: A file that contains details of the KMIP back end with whichkeyring_okv
will communicate. -
ssl
: A directory that contains the certificate and key files required to establish a secure connection with the KMIP back end:CA.pem
,cert.pem
, andkey.pem
. If the key file is password-protected, thessl
directory can contain a single-line text file namedpassword.txt
containing the password needed to decrypt the key file.
Both the okvclient.ora
file and ssl
directory with the certificate and key files are required for keyring_okv
to work properly. The procedure used to populate the configuration directory with these files depends on the KMIP back end used with keyring_okv
, as described elsewhere.
The configuration directory used by keyring_okv
as the location for its support files should have a restrictive mode and be accessible only to the account used to run the MySQL server. For example, on Unix and Unix-like systems, to use the /usr/local/mysql/mysql-keyring-okv
directory, the following commands (executed as root
) create the directory and set its mode and ownership:
cd /usr/local/mysql mkdir mysql-keyring-okv chmod 750 mysql-keyring-okv chown mysql mysql-keyring-okv chgrp mysql mysql-keyring-okv
To be usable during the server startup process, keyring_okv
must be loaded using the --early-plugin-load
option. Also, set the keyring_okv_conf_dir
system variable to tell keyring_okv
where to find its configuration directory. For example, use these lines in the server my.cnf
file (adjust the .so
suffix and directory location for your platform as necessary):
[mysqld] early-plugin-load=keyring_okv.so keyring_okv_conf_dir=/usr/local/mysql/mysql-keyring-okv
For additional information about keyring_okv_conf_dir
, see Section 6.4.4.12, “Keyring System Variables”.
The discussion here assumes that you are familiar with Oracle Key Vault. Some pertinent information sources:
In Oracle Key Vault terminology, clients that use Oracle Key Vault to store and retrieve security objects are called endpoints. To communicate with Oracle Key Vault, it is necessary to register as an endpoint and enroll by downloading and installing endpoint support files.
The following procedure briefly summarizes the process of setting up keyring_okv
for use with Oracle Key Vault:
-
Create the configuration directory for the
keyring_okv
plugin to use. -
Register an endpoint with Oracle Key Vault to obtain an enrollment token.
-
Use the enrollment token to obtain the
okvclient.jar
client software download. -
Install the client software to populate the
keyring_okv
configuration directory that contains the Oracle Key Vault support files.
Use the following procedure to configure keyring_okv
and Oracle Key Vault to work together. This description only summarizes how to interact with Oracle Key Vault. For details, visit the Oracle Key Vault site and consult the Oracle Key Vault Administrator's Guide.
-
Create the configuration directory that will contain the Oracle Key Vault support files, and make sure that the
keyring_okv_conf_dir
system variable is set to name that directory (for details, see General keyring_okv Configuration). -
Log in to the Oracle Key Vault management console as a user who has the System Administrator role.
-
Select the Endpoints tab to arrive at the Endpoints page. On the Endpoints page, click Add.
-
Provide the required endpoint information and click Register. The endpoint type should be Other. Successful registration results in an enrollment token.
-
Log out from the Oracle Key Vault server.
-
Connect again to the Oracle Key Vault server, this time without logging in. Use the endpoint enrollment token to enroll and request the
okvclient.jar
software download. Save this file to your system. -
Install the
okvclient.jar
file using the following command (you must have JDK 1.4 or higher):java -jar okvclient.jar -d
dir_name
[-v]The directory name following the
-d
option is the location in which to install extracted files. The-v
option, if given, causes log information to be produced that may be useful if the command fails.When the command asks for an Oracle Key Vault endpoint password, do not provide one. Instead, press Enter. (The result is that no password will be required when the endpoint connects to Oracle Key Vault.)
-
The preceding command produces an
okvclient.ora
file, which should be in this location under the directory named by the-d
option in the preceding java -jar command:install_dir/conf/okvclient.ora
The file contents include lines that look something like this:
host_ip port_num host_ip port_num The
keyring_okv
plugin attempts to communicate with the server running on the host named by theSERVER
variable and falls back toSTANDBY_SERVER
if that fails:-
For the
SERVER
variable, a setting in theokvclient.ora
file is mandatory. -
For the
STANDBY_SERVER
variable, a setting in theokvclient.ora
file is optional.
-
-
Go to the Oracle Key Vault installer directory and test the setup by running this command:
okvutil/bin/okvutil list
The output should look something like this:
Unique ID Type Identifier 255AB8DE-C97F-482C-E053-0100007F28B9 Symmetric Key - 264BF6E0-A20E-7C42-E053-0100007FB29C Symmetric Key -
For a fresh Oracle Key Vault server (a server without any key in it), the output looks like this instead, to indicate that there are no keys in the vault:
no objects found
-
Use this command to extract the
ssl
directory containing SSL materials from theokvclient.jar
file:jar xf okvclient.jar ssl
-
Copy the Oracle Key Vault support files (the
okvclient.ora
file and thessl
directory) into the configuration directory. -
(Optional) If you wish to password-protect the key file, use the instructions in Password-Protecting the keyring_okv Key File.
After completing the preceding procedure, restart the MySQL server. It loads the keyring_okv
plugin and keyring_okv
uses the files in its configuration directory to communicate with Oracle Key Vault.
Gemalto SafeNet KeySecure Appliance uses the KMIP protocol (version 1.1 or 1.2). The keyring_okv
keyring plugin (which supports KMIP 1.1) can use KeySecure as its KMIP back end for keyring storage.
Use the following procedure to configure keyring_okv
and KeySecure to work together. The description only summarizes how to interact with KeySecure. For details, consult the section named Add a KMIP Server in the KeySecure User Guide.
-
Create the configuration directory that will contain the KeySecure support files, and make sure that the
keyring_okv_conf_dir
system variable is set to name that directory (for details, see General keyring_okv Configuration). -
In the configuration directory, create a subdirectory named
ssl
to use for storing the required SSL certificate and key files. -
In the configuration directory, create a file named
okvclient.ora
. It should have following format:host_ip port_num host_ip port_num For example, if KeySecure is running on host 198.51.100.20 and listening on port 9002, the
okvclient.ora
file looks like this:SERVER=198.51.100.20:9002 STANDBY_SERVER=198.51.100.20:9002
-
Connect to the KeySecure Management Console as an administrator with credentials for Certificate Authorities access.
-
Navigate to Security >> Local CAs and create a local certificate authority (CA).
-
Go to Trusted CA Lists. Select Default and click on Properties. Then select Edit for Trusted Certificate Authority List and add the CA just created.
-
Download the CA and save it in the
ssl
directory as a file namedCA.pem
. -
Navigate to Security >> Certificate Requests and create a certificate. Then you will be able to download a compressed tar file containing certificate PEM files.
-
Extract the PEM files from in the downloaded file. For example, if the file name is
csr_w_pk_pkcs8.gz
, decompress and unpack it using this command:tar zxvf csr_w_pk_pkcs8.gz
Two files result from the extraction operation:
certificate_request.pem
andprivate_key_pkcs8.pem
. -
Use this openssl command to decrypt the private key and create a file named
key.pem
:openssl pkcs8 -in private_key_pkcs8.pem -out key.pem
-
Copy the
key.pem
file into thessl
directory. -
Copy the certificate request in
certificate_request.pem
into the clipboard. -
Navigate to Security >> Local CAs. Select the same CA that you created earlier (the one you downloaded to create the
CA.pem
file), and click Sign Request. Paste the Certificate Request from the clipboard, choose a certificate purpose of Client (the keyring is a client of KeySecure), and click Sign Request. The result is a certificate signed with the selected CA in a new page. -
Copy the signed certificate to the clipboard, then save the clipboard contents as a file named
cert.pem
in thessl
directory. -
(Optional) If you wish to password-protect the key file, use the instructions in Password-Protecting the keyring_okv Key File.
After completing the preceding procedure, restart the MySQL server. It loads the keyring_okv
plugin and keyring_okv
uses the files in its configuration directory to communicate with KeySecure.
You can optionally protect the key file with a password and supply a file containing the password to enable the key file to be decrypted. To so do, change location to the ssl
directory and perform these steps:
-
Encrypt the
key.pem
key file. For example, use a command like this, and enter the encryption password at the prompts:shell>
openssl rsa -des3 -in key.pem -out key.pem.new
Enter PEM pass phrase: Verifying - Enter PEM pass phrase: -
Save the encryption password in a single-line text file named
password.txt
in thessl
directory. -
Verify that the encrypted key file can be decrypted using the following command. The decrypted file should display on the console:
shell>
openssl rsa -in key.pem.new -passin file:password.txt
-
Remove the original
key.pem
file and renamekey.pem.new
tokey.pem
. -
Change the ownership and access mode of new
key.pem
file andpassword.txt
file as necessary to ensure that they have the same restrictions as other files in thessl
directory.
The keyring_aws
plugin is an extension included in MySQL Enterprise Edition, a commercial product. To learn more about commercial products, see https://www.mysql.com/products/.
The keyring_aws
plugin is a keyring plugin that communicates with the Amazon Web Services Key Management Service (AWS KMS) as a back end for key generation and uses a local file for key storage. All keyring material is generated exclusively by the AWS server, not by keyring_aws
.
keyring_aws
is available on these platforms:
-
Debian 8
-
EL7
-
macOS 10.13 and 10.14
-
SLES 12
-
Ubuntu 14.04 and 16.04
-
Windows
The discussion here assumes that you are familiar with AWS in general and KMS in particular. Some pertinent information sources:
The following sections provide configuration and usage information for the keyring_aws
keyring plugin:
To install the keyring_aws
plugin, use the general keyring installation instructions found in Section 6.4.4.1, “Keyring Plugin Installation”, together with the plugin-specific configuration information found here.
The plugin library file contains the keyring_aws
plugin and two user-defined functions (UDFs), keyring_aws_rotate_cmk()
and keyring_aws_rotate_keys()
.
To configure keyring_aws
, you must obtain a secret access key that provides credentials for communicating with AWS KMS and write it to a configuration file:
-
Create an AWS KMS account.
-
Use AWS KMS to create a secret access key ID and secret access key. The access key serves to verify your identity and that of your applications.
-
Use the AWS KMS account to create a customer master key (CMK) ID. At MySQL startup, set the
keyring_aws_cmk_id
system variable to the CMK ID value. This variable is mandatory and there is no default. (Its value can be changed at runtime if desired usingSET GLOBAL
.) -
If necessary, create the directory in which the configuration file will be located. The directory should have a restrictive mode and be accessible only to the account used to run the MySQL server. For example, on Unix and Unix-like systems, to use
/usr/local/mysql/mysql-keyring/keyring_aws_conf
as the file name, the following commands (executed asroot
) create its parent directory and set the directory mode and ownership:cd /usr/local/mysql mkdir mysql-keyring chmod 750 mysql-keyring chown mysql mysql-keyring chgrp mysql mysql-keyring At MySQL startup, set the
keyring_aws_conf_file
system variable to/usr/local/mysql/mysql-keyring/keyring_aws_conf
to indicate the configuration file location to the server. -
Prepare the
keyring_aws
configuration file, which should contain two lines:-
Line 1: The secret access key ID
-
Line 2: The secret access key
For example, if the key ID is
wwwwwwwwwwwwwEXAMPLE
and the key isxxxxxxxxxxxxx/yyyyyyy/zzzzzzzzEXAMPLEKEY
, the configuration file looks like this:wwwwwwwwwwwwwEXAMPLE xxxxxxxxxxxxx/yyyyyyy/zzzzzzzzEXAMPLEKEY
-
To be usable during the server startup process, keyring_aws
must be loaded using the --early-plugin-load
option. The keyring_aws_cmk_id
system variable is mandatory and configures the customer master key (CMK) ID obtained from the AWS KMS server. The keyring_aws_conf_file
and keyring_aws_data_file
system variables optionally configure the locations of the files used by the keyring_aws
plugin for configuration information and data storage. The file location variable default values are platform specific. To configure the locations explicitly, set the variable values at startup. For example, use these lines in the server my.cnf
file (adjust the .so
suffix and file locations for your platform as necessary):
[mysqld] early-plugin-load=keyring_aws.so keyring_aws_cmk_id='arn:aws:kms:us-west-2:111122223333:key/abcd1234-ef56-ab12-cd34-ef56abcd1234' keyring_aws_conf_file=/usr/local/mysql/mysql-keyring/keyring_aws_conf keyring_aws_data_file=/usr/local/mysql/mysql-keyring/keyring_aws_data
For the keyring_aws
plugin to start successfully, the configuration file must exist and contain valid secret access key information, initialized as described previously. The storage file need not exist. If it does not, keyring_aws
attempts to create it (as well as its parent directory, if necessary).
For additional information about the system variables used to configure the keyring_aws
plugin, see Section 6.4.4.12, “Keyring System Variables”.
Start the MySQL server and install the UDFs associated with the keyring_aws
plugin. This is a one-time operation, performed by executing the following statements (adjust the .so
suffix for your platform as necessary):
CREATE FUNCTION keyring_aws_rotate_cmk RETURNS INTEGER SONAME 'keyring_aws.so'; CREATE FUNCTION keyring_aws_rotate_keys RETURNS INTEGER SONAME 'keyring_aws.so';
For additional information about the keyring_aws
UDFs, see Section 6.4.4.10, “Plugin-Specific Keyring Key-Management Functions”.
At plugin startup, the keyring_aws
plugin reads the AWS secret access key ID and key from its configuration file. It also reads any encrypted keys contained in its storage file into its in-memory cache.
During operation, keyring_aws
maintains encrypted keys in the in-memory cache and uses the storage file as local persistent storage. Each keyring operation is transactional: keyring_aws
either successfully changes both the in-memory key cache and the keyring storage file, or the operation fails and the keyring state remains unchanged.
To ensure that keys are flushed only when the correct keyring storage file exists, keyring_aws
stores a SHA-256 checksum of the keyring in the file. Before updating the file, the plugin verifies that it contains the expected checksum.
The keyring_aws
plugin supports the functions that comprise the standard MySQL Keyring service interface. Keyring operations performed by these functions are accessible at two levels:
-
C interface: In C-language code, call the keyring service functions described in Section 29.3.2, “The Keyring Service”.
-
SQL interface: In SQL statements, call the user-defined functions (UDFs) described in Section 6.4.4.9, “General-Purpose Keyring Key-Management Functions”.
Example (using UDFs):
SELECT keyring_key_generate('MyKey', 'AES', 32); SELECT keyring_key_remove('MyKey');
In addition, the keyring_aws_rotate_cmk()
and keyring_aws_rotate_keys()
UDFs “extend” the keyring plugin interface to provide AWS-related capabilities not covered by the standard keyring service interface. These capabilities are accessible only by calling the UDFs. There are no corresponding C-languge key service functions.
For information about the key types permitted by keyring_aws
, see Section 6.4.4.8, “Supported Keyring Key Types and Lengths”.
Assuming that the keyring_aws
plugin has initialized properly at server startup, it is possible to change the credentials used for communicating with AWS KMS:
-
Use AWS KMS to create a new secret access key ID and secret access key.
-
Store the new credentials in the configuration file (the file named by the
keyring_aws_conf_file
system variable). The file format is as described previously. -
Reinitialize the
keyring_aws
plugin so that it rereads the configuration file. Assuming that the new credentials are valid, the plugin should initialize successfully.There are two ways to reinitialize the plugin:
-
Restart the server. This is simpler and has no side effects, but is not suitable for installations that require minimal server downtime with as few restarts as possible.
-
Reinitialize the plugin without restarting the server by executing the following statements (adjust the
.so
suffix for your platform as necessary):UNINSTALL PLUGIN keyring_aws; INSTALL PLUGIN keyring_aws SONAME 'keyring_aws.so';
NoteIn addition to loading a plugin at runtime,
INSTALL PLUGIN
has the side effect of registering the plugin it in themysql.plugin
system table. Because of this, if you decide to stop usingkeyring_aws
, it is not sufficient to remove the--early-plugin-load
option from the set of options used to start the server. That stops the plugin from loading early, but the server still attempts to load it when it gets to the point in the startup sequence where it loads the plugins registered inmysql.plugin
.Consequently, if you execute the
UNINSTALL PLUGIN
plusINSTALL PLUGIN
sequence just described to change the AWS KMS credentials, then to stop usingkeyring_aws
, it is necessary to executeUNINSTALL PLUGIN
again to unregister the plugin in addition to removing the--early-plugin-load
option.
-
The keyring_hashicorp
plugin is an extension included in MySQL Enterprise Edition, a commercial product. To learn more about commercial products, see https://www.mysql.com/products/.
The keyring_hashicorp
plugin is a keyring plugin that communicates with HashiCorp Vault for back end storage. The plugin supports HashiCorp Vault AppRole authentication. All keys are stored in HashiCorp Vault. No key information is permanently stored in MySQL server local storage. (An optional in-memory key cache may be used as intermediate storage.) Random key generation is performed on the MySQL server side, and the keys are subsequently stored to Hashicorp Vault.
The keyring_hashicorp
plugin supports the functions that comprise the standard MySQL Keyring service interface. Keyring operations performed by those functions are accessible at two levels:
-
SQL interface: In SQL statements, call the user-defined functions (UDFs) described in Section 6.4.4.9, “General-Purpose Keyring Key-Management Functions”.
-
C interface: In C-language code, call the keyring service functions described in Section 29.3.2, “The Keyring Service”.
Example (using UDFs):
SELECT keyring_key_generate('MyKey', 'AES', 32); SELECT keyring_key_remove('MyKey');
For information about the key types permitted by keyring_hashicorp
, see Section 6.4.4.8, “Supported Keyring Key Types and Lengths”.
To install the keyring_hashicorp
plugin, use the general keyring installation instructions found in Section 6.4.4.1, “Keyring Plugin Installation”, together with the configuration information specific to keyring_hashicorp
found here. Plugin-specific information includes preparation of the certificate and key files needed for connecting to HashiCorp Vault, as well as configuring Vault itself. The following sections provide the necessary instructions.
The keyring_hashicorp
plugin requires a secure connection to the HashiCorp Vault server, employing the HTTPS protocol. A typical setup includes a set of certificate and key files:
-
company.crt
: A custom CA certificate belonging to the organization. This file is used both by HashiCorp Vault server and thekeyring_hashicorp
plugin. -
vault.key
: The private key of the HashiCorp Vault server instance. This file is used by HashiCorp Vault server. -
vault.crt
: The certificate of the HashiCorp Vault server instance. This file must be signed by the organization CA certificate.
The following instructions describe how to create the certificate and key files using OpenSSL. (If you already have the files, proceeed to HashiCorp Vault Setup.) The instructions as shown apply to Linux platforms and may require adjustment for other platforms.
Certificates generated by these instructions are self-signed, which may not be very secure. After you gain experience using such files, consider obtaining certificate/key material from a registered certificate authority.
-
Prepare the company and HashiCorp Vault server keys.
Use the following commands to generate the key files:
openssl genrsa -aes256 -out company.key 4096 openssl genrsa -aes256 -out vault.key 2048
The commands produce files holding the company private key (
company.key
) and the Vault server private key (vault.key
). The keys are randomly generated RSA keys of 4,096 and 2,048 bits, respectively.Each command prompts for a password. (For testing purposes, the password is not required. To disable it, omit the
-aes256
argument.)The key files hold sensitive information and should be stored in a secure location. The password (also sensitive) is required later, so write it down and store it in a secure location.
(Optional) To check key file content and validity, use the following commands:
openssl rsa -in company.key -check openssl rsa -in vault.key -check
-
Create the company CA certificate.
Use the following command to create a company CA certificate file named
company.crt
that is valid for 365 days (enter the command on a single line):openssl req -x509 -new -nodes -key company.key -sha256 -days 365 -out company.crt
You will be prompted for the company key password during CA certificate creation, if you used the
-aes256
argument to perform key encryption during key generation. You will also be prompted for information about the certificate holder (that is, you or your company), as shown here:Country Name (2 letter code) [AU]: State or Province Name (full name) [Some-State]: Locality Name (eg, city) []: Organization Name (eg, company) [Internet Widgits Pty Ltd]: Organizational Unit Name (eg, section) []: Common Name (e.g. server FQDN or YOUR name) []: Email Address []:
Answer the prompts with appropriate values.
-
Create a certificate signing request.
To create a HashiCorp Vault server certificate, a Certificate Signing Request (CSR) must be prepared for the newly created server key. Create a configuration file named
request.conf
containing the following lines. If the HashiCorp Vault server does not run on the local host, substitute appropriate CN and IP values, and make any other changes required.[req] distinguished_name = vault x509_entensions = v3_req prompt = no [vault] C = US ST = CA L = RWC O = Company CN = 127.0.0.1 [v3_req] subjectAltName = @alternatives authorityKeyIdentifier = keyid,issuer basicConstraints = CA:TRUE [alternatives] IP = 127.0.0.1
Use this command to create the signing request:
openssl req -new -key vault.key -config request.conf -out request.csr
The output file (
request.csr
) is an intermediate file that serves as input for creation of the server certificate. -
Create the HashiCorp Vault server certificate.
Sign the combined information from the HashiCorp Vault server key (
vault.key
) and the CSR (request.csr
) with the company certificate (company.crt
) to create the HashiCorp Vault server certificate (vault.crt
). Use the following command to do this (enter the command on a single line):openssl x509 -req -in request.csr -CA company.crt -CAkey company.key -CAcreateserial -out vault.crt -days 365 -sha256
To make the
vault.crt
server certificate useful, append the contents of thecompany.crt
company certificate to it. This is required so that the company certificate is delivered along with the server certificate in requests.cat company.crt >> vault.crt
If you open the
vault.crt
file with a text editor, its content should look like this:content of HashiCorp Vault server certificate content of company certificate
The following instructions describe how to create a HashiCorp Vault setup that facilitates testing the keyring_hashicorp
plugin.
A test setup is similar to a production setup, but production use of HashiCorp Vault entails additional security considerations such as use of non-self-signed certificates and storing the company certificate in the system trust store. It is assumed that you will implement whatever additional security steps are needed to satisfy your operational requirements.
These instructions assume availability of the certificate and key files created in Certificate and Key Preparation. See that section if you do not have the files.
-
Fetch the HashiCorp Vault binary.
Download the HashiCorp Vault binary appropriate for your platform from https://www.vaultproject.io/downloads.html.
Extract the content of the archive to produce the executable vault command, which is used to perform HashiCorp Vault operations. If necessary, add the directory where you install the command to the system path.
(Optional) HashiCorp Vault supports autocomplete options that make it easier to use. For more information, see https://learn.hashicorp.com/vault/getting-started/install#command-completion.
-
Create the HashiCorp Vault server configuration file.
Prepare a configuration file named
config.hcl
with the following content. For thetls_cert_file
,tls_key_file
, andpath
values, substitute path names appropriate for your system.listener "tcp" { address="127.0.0.1:8200" tls_cert_file="/home/username/certificates/vault.crt" tls_key_file="/home/username/certificates/vault.key" } storage "file" { path = "/home/username/vaultstorage/storage" } ui = true
-
Start the HashiCorp Vault server.
To start the Vault server, use the following command, where the
-config
option specifies the path to the configuration file just created:vault server -config=config.hcl
During this step, you may be prompted for a password for the Vault server private key stored in the
vault.key
file.The server should start, displaying some information on the console (IP, port, and so forth).
So that you can enter the remaining commands, put the vault server command in the background or open another terminal before continuing.
-
Initialize the HashiCorp Vault server.
NoteThe operations described in this step are required only when starting Vault the first time, to obtain the unseal key and root token. Subsequent Vault instance restarts require only unsealing using the unseal key.
Issue the following commands (assuming Bourne shell syntax):
export VAULT_SKIP_VERIFY=1 vault operator init -n 1 -t 1
The first command enables the vault command to temporarily ignore the fact that no company certificate has been added to the system trust store. It compensates for the fact that our self-signed CA is not added to that store. (For production use, such a certificate should be added.)
The second command creates a single unseal key with a requirement for a single unseal key to be present for unsealing. (For production use, an instance would have multiple unseal keys with up to that many keys required to be entered to unseal it. The unseal keys should be delivered to key custodians within the company. Use of a single key might be considered a security issue because that permits the vault to be unsealed by a single key custodian.)
Vault should reply with information about the unseal key and root token, plus some additional text (the actual unseal key and root token values will differ from those shown here):
... Unseal Key 1: I2xwcFQc892O0Nt2pBiRNlnkHzTUrWS+JybL39BjcOE= Initial Root Token: s.vTvXeo3tPEYehfcd9WH7oUKz ...
Store the unseal key and root token in a secure location.
-
Unseal the HashiCorp Vault server.
Use this command to unseal the Vault server:
vault operator unseal
When prompted to enter the unseal key, use the key obtained previously during Vault initialization.
Vault should produce output indicating that setup is complete and the vault is unsealed.
-
Log in to the HashiCorp Vault server and verify its status.
Prepare the environment variables required for logging in as root:
vault login s.vTvXeo3tPEYehfcd9WH7oUKz
For the token value in that command, substitute the content of the root token obtained previously during Vault initialization.
Verify the Vault server status:
vault status
The output should contain these lines (among others):
... Initialized true Sealed false ...
-
Set up HashiCorp Vault authentication and storage.
NoteThe operations described in this step are needed only the first time the Vault instance is run. They need not be repeated afterward.
Enable the AppRole authentication method and verify that it is in the authentication method list:
vault auth enable approle vault auth list
Enable the Vault KeyValue storage engine:
vault secrets enable -version=1 kv
Create and set up a role for use with the
keyring_hashicorp
plugin (enter the command on a single line):vault write auth/approle/role/mysql token_num_uses=0 token_ttl=20m token_max_ttl=30m secret_id_num_uses=0
-
Add an AppRole security policy.
NoteThe operations described in this step are needed only the first time the Vault instance is run. They need not be repeated afterward.
Prepare a policy that to permit the previously created role to access appropriate secrets. Create a new file named
mysql.hcl
with the following content:path "kv/mysql/*" { capabilities = ["create", "read", "update", "delete", "list"] }
Import the policy file to the Vault server to create a policy named
mysql-policy
, then assign the policy to the new role:vault policy write mysql-policy mysql.hcl vault write auth/approle/role/mysql policies=mysql-policy
Obtain the ID of the newly created role and store it in a secure location:
vault read auth/approle/role/mysql/role-id
Generate a secret ID for the role and store it in a secure location:
vault write -f auth/approle/role/mysql/secret-id
After these AppRole role ID and secret ID credentials are generated, they are expected to remain valid indefinitely. They need not be generated again and the
keyring_hashicorp
plugin can be configured with them for use on an ongoing basis. For more information about AuthRole authentication, visit https://www.vaultproject.io/docs/auth/approle.html.
The plugin library file contains the keyring_hashicorp
plugin and a user-defined function (UDF), keyring_hashicorp_update_config()
. When the plugin initializes and terminates, it automatically loads and unloads the UDF, so there is no need to load and unload the UDF manually.
The keyring_hashicorp
plugin supports the configuration arguments shown in the following table, specified by assigning values to a set of system variables.
Configuration Parameter | System Variable | Mandatory |
---|---|---|
HashiCorp Server URL | keyring_hashicorp_server_url |
|
AppRole role ID | keyring_hashicorp_role_id |
Yes |
AppRole secret ID | keyring_hashicorp_secret_id |
Yes |
Store path | keyring_hashicorp_store_path |
Yes |
Authorization Path | keyring_hashicorp_auth_path |
|
CA certificate file path | keyring_hashicorp_ca_path |
|
Caching | keyring_hashicorp_caching |
To be usable during the server startup process, keyring_hashicorp
must be loaded using the --early-plugin-load
option. As indicated by the preceding table, several plugin-related system variables are mandatory and must also be set. For example, use these lines in the server my.cnf
file (adjust the .so
suffix and file locations for your platform as necessary):
[mysqld] early-plugin-load=keyring_hashicorp.so keyring_hashicorp_role_id='ee3b495c-d0c9-11e9-8881-8444c71c32aa' keyring_hashicorp_secret_id='0512af29-d0ca-11e9-95ee-0010e00dd718' keyring_hashicorp_store_path='/v1/kv/mysql'
MySQL Server authenticates against HashiCorp Vault using AppRole authentication. Successful authentication requires that two secrets be provided to Vault, a role ID and a secret ID, which are similar in concept to user name and password. The role ID and secret ID values to use are those obtained during the HashiCorp Vault setup procedure performed previously. To specify the two IDs, assign their respective values to the keyring_hashicorp_role_id
and keyring_hashicorp_secret_id
system variables. The setup procedure also results in a store path of /v1/kv/mysql
, which is the value to assign to keyring_hashicorp_commit_store_path
.
At plugin initialization time, keyring_hashicorp
attempts to connect to the HashiCorp Vault server using the configuration values. If the connection is successful, the plugin stores the values in corresponding system variables that have _commit_
in their name. For example, upon successful connection, the plugin stores the values of keyring_hashicorp_role_id
and keyring_hashicorp_store_path
in keyring_hashicorp_commit_role_id
and keyring_hashicorp_commit_store_path
.
Reconfiguration at runtime can be performed with the assistance of the keyring_hashicorp_update_config()
UDF:
-
Use
SET
statements to assign the desired new values to the configuration system variables shown in the preceding table. These assignments in themselves have no effect on ongoing plugin operation. -
Invoke
keyring_hashicorp_update_config()
to cause the plugin to reconfigure and reconnect to the HashiCorp Vault server using the new variable values. -
If the connection is successful, the plugin stores the updated configuration values in corresponding system variables that have
_commit_
in their name.
For example, if you have reconfigured HashiCorp Vault to listen on port 8201 rather than the default 8200, reconfigure keyring_hashicorp
like this:
SET GLOBAL keyring_hashicorp_server_url = 'https://127.0.0.1:8201'; SELECT keyring_hashicorp_update_config();
If the plugin is not able to connect to HashiCorp Vault during initialization or reconfiguration and there was no existing connection, the _commit_
system variables are set to 'Not committed'
for string-valued variables, and OFF
for Boolean-valued variables. If the plugin is not able to connect but there was an existing connection, that connection remains active and the _commit_
variables reflect the values used for it.
If you do not set the mandatory system variables at server startup, or if some other plugin initialization error occurs, initialization fails. In this case, you can use the runtime reconfiguration procedure to initialize the plugin without restarting the server.
For additional information about the keyring_hashicorp
plugin-specific system variables and UDF, see Section 6.4.4.12, “Keyring System Variables”, and Section 6.4.4.10, “Plugin-Specific Keyring Key-Management Functions”.
The MySQL server supports an operational mode that enables migration of keys between underlying keyring keystores. This enables DBAs to switch a MySQL installation from one keyring plugin to another. A migration server (that is, a server started in key migration mode) does not accept client connections. Instead, it runs only long enough to migrate keys, then exits. A migration server reports errors to the console (the standard error output).
It is possible to perform offline or online key migration:
-
If you are sure that no running server on the local host is using the source or destination keystore, an offline migration is possible. In this case, the migration server can modify the keystores without possibility of a running server modifying keystore content during the migration.
-
If a running server on the local host is using the source or destination keystore, an online migration must be performed. In this case, the migration server connects to the running server and instructs it to pause keyring operations while key migration is in progress.
The result of a key migration operation is that the destination keystore contains the keys it had prior to the migration, plus the keys from the source keystore. The source keystore is the same before and after the migration because keys are copied, not moved. If a key to be copied already exists in the destination keystore, an error occurs and the destination keystore is restored to its premigration state.
The user who invokes the server in key-migration mode must not be the root
operating system user, and must have permission to read and write the keyring files.
To perform a key migration operation, determine which key migration options are needed. Migration options indicate which keyring plugins are involved, and whether to perform an offline or online migration:
-
To indicate the source and destination keyring plugins, specify these options:
-
--keyring-migration-source
: The source keyring plugin that manages the keys to be migrated. -
--keyring-migration-destination
: The destination keyring plugin to which the migrated keys are to be copied.
These options tell the server to run in key migration mode. Both options are mandatory for all key migration operations. The source and destination plugins must differ, and the migration server must support both plugins.
-
-
For an offline migration, no additional key migration options are needed.
WarningDo not perform offline migration involving a keystore that is in use by a running server.
-
For an online migration, some running server currently is using the source or destination keystore. Specify the key migration options that indicate how to connect to the running server. This is necessary so that the migration server can connect to the running server and tell it to pause keyring use during the migration operation.
Use of any of the following options signifies an online migration:
-
--keyring-migration-host
: The host where the running server is located. This is always the local host. -
--keyring-migration-user
,--keyring-migration-password
: The user name and password for the account to use to connect to the running server. -
--keyring-migration-port
: For TCP/IP connections, the port number to connect to on the running server. -
--keyring-migration-socket
: For Unix socket file or Windows named pipe connections, the socket file or named pipe to connect to on the running server.
-
For additional details about the key migration options, see Section 6.4.4.11, “Keyring Command Options”.
Start the migration server with the key migration options determined as just described, possibly with other options. Keep the following considerations in mind:
-
Other server options might be required, such as other configuration parameters for the two keyring plugins. For example, if
keyring_file
is one of the plugins, you must set thekeyring_file_data
system variable if the keyring data file location is not the default location. Other non-keyring options may be required as well. One way to specify these options is by using--defaults-file
to name an option file that contains the required options. -
If you invoke the migration server from a system account different from that normally used to run MySQL, it might create keyring directories or files that are inaccessible to the server during normal operation. Suppose that mysqld normally runs as the
mysql
operating system user, but you invoke the migration server while logged in asisabel
. Any new directories or files created by the migration server will be owned byisabel
. Subsequent startup will fail when a server run as themysql
operating system user attempts to access file system objects owned byisabel
.To avoid this issue, start the migration server as the
root
operating system user and provide a--user=
option, whereuser_name
user_name
is the system account normally used to run MySQL. -
The migration server expects path name option values to be full paths. Relative path names may not be resolved as you expect.
Example command line for offline key migration:
mysqld --defaults-file=/usr/local/mysql/etc/my.cnf
--keyring-migration-source=keyring_file.so
--keyring-migration-destination=keyring_encrypted_file.so
--keyring_encrypted_file_password=password
Example command line for online key migration:
password root_password
The key migration server performs the migration operation as follows:
-
(Online migration only) Connect to the running server using the connection options. The account used to connect must have the privileges required to modify the global
keyring_operations
system variable (ENCRYPTION_KEY_ADMIN
in addition to eitherSYSTEM_VARIABLES_ADMIN
orSUPER
). -
(Online migration only) Disable
keyring_operations
on the running server. (The running server must supportkeyring_operations
.) -
Load the source and destination keyring plugins.
-
Copy keys from the source keyring to the destination keyring.
-
Unload the keyring plugins.
-
(Online migration only) Enable
keyring_operations
on the running server. -
(Online migration only) Disconnect from the running server.
-
Exit.
If an error occurs during key migration, any keys that were copied to the destination plugin are removed, leaving the destination keystore unchanged.
For an online migration operation, the migration server takes care of enabling and disabling keyring_operations
on the running server. However, if the migration server exits abnormally (for example, if someone forcibly terminates it), it is possible that keyring_operations
will not have been re-enabled on the running server, leaving it unable to perform keyring operations. In this case, it may be necessary to connect to the running server and enable keyring_operations
manually.
After a successful online key migration operation, the running server might need to be restarted:
-
If the running server was using the source keystore, it need not be restarted after the migration.
-
If the running server was using the source keystore before the migration but should use the destination keystore after the migration, it must be reconfigured to use the destination keyring plugin and restarted.
-
If the running server was using the destination keystore and will continue to use it, it should be restarted after the migration to load all keys migrated into the destination keystore.
MySQL server key migration mode supports pausing a single running server. To perform a key migration if multiple key servers are using the keystores involved, use this procedure:
-
Connect to each running server manually and set
keyring_operations=OFF
. -
Use the migration server to perform an offline key migration.
-
Connect to each running server manually and set
keyring_operations=ON
.
All running servers must support the keyring_operations=ON
system variable.
MySQL Keyring supports keys of different types (encryption algorithms) and lengths:
-
The available key types depend on which keyring plugin is installed.
-
The permitted key lengths are subject to multiple factors:
-
General keyring UDF interface limits (for keys managed using one of the keyring UDFs described in Section 6.4.4.9, “General-Purpose Keyring Key-Management Functions”), or limits from back end implementations. These length limits can vary by key operation type.
-
In addition to the general limits, individual plugins may impose restrictions on key lengths per key type.
-
Table 6.26, “General Keyring Key Length Limits” shows the general key length limits. (The lower limits for keyring_aws
are imposed by the AWS KMS interface, not the keyring UDFs.) Table 6.27, “Keyring Plugin Key Types and Lengths” shows for each keyring plugin the key types it permits, as well as any plugin-specific key-length restrictions.
Table 6.26 General Keyring Key Length Limits
Key Operation | Maximum Key Length |
---|---|
Generate key |
16,384 bytes (2,048 prior to MySQL 8.0.18); 1,024 for |
Store key |
16,384 bytes (2,048 prior to MySQL 8.0.18); 4,096 for |
Fetch key |
16,384 bytes (2,048 prior to MySQL 8.0.18); 4,096 for |
Table 6.27 Keyring Plugin Key Types and Lengths
Plugin Name | Permitted Key Type | Plugin-Specific Length Restrictions |
---|---|---|
keyring_encrypted_file |
|
None None None None |
keyring_file |
|
None None None None |
keyring_okv |
|
16, 24, or 32 bytes None |
keyring_aws |
|
16, 24, or 32 bytes None |
keyring_hashicorp |
|
None None None None |
The SECRET
key type, available as of MySQL 8.0.19,
is intended for general-purpose storage of sensitive data using the MySQL
keyring, and is supported by all keyring plugins. The keyring encrypts and
decrypts SECRET
data as a byte stream upon storage
and retrieval.
Example keyring operations involving the SECRET
key type:
SELECT keyring_key_generate('MySecret1', 'SECRET', 20); SELECT keyring_key_remove('MySecret1'); SELECT keyring_key_store('MySecret2', 'SECRET', 'MySecretData'); SELECT keyring_key_fetch('MySecret2'); SELECT keyring_key_length_fetch('MySecret2'); SELECT keyring_key_type_fetch('MySecret2'); SELECT keyring_key_remove('MySecret2');
MySQL Server supports a keyring service that enables internal server components and plugins to securely store sensitive information for later retrieval.
MySQL Server also includes an SQL interface for keyring key management, implemented as a set of general-purpose user-defined functions (UDFs) that access the functions provided by the internal keyring service. The keyring UDFs are contained in a plugin library file, which also contains a keyring_udf
plugin that must be enabled prior to UDF invocation. For these UDFs to be used, a keyring plugin such as keyring_file
or keyring_okv
must be enabled.
The UDFs described here are general purpose and intended for use with any keyring plugin. A given keyring plugin might have UDFs of its own that are intended for use only with that plugin; see Section 6.4.4.10, “Plugin-Specific Keyring Key-Management Functions”.
The following sections provide installation instructions for the keyring UDFs and demonstrate how to use them. For information about the keyring service functions invoked by the UDFs, see Section 29.3.2, “The Keyring Service”. For general keyring information, see Section 6.4.4, “The MySQL Keyring”.
This section describes how to install or uninstall the keyring user-defined functions (UDFs), which are implemented in a plugin library file that also contains a keyring_udf
plugin. For general information about installing or uninstalling plugins and UDFs, see Section 5.6.1, “Installing and Uninstalling Plugins”, and Section 5.7.1, “Installing and Uninstalling User-Defined Functions”.
The keyring UDFs enable keyring key management operations, but the keyring_udf
plugin must also be installed because the UDFs will not work correctly without it. Attempts to use the UDFs without the keyring_udf
plugin result in an error.
To be usable by the server, the plugin library file must be located in the MySQL plugin directory (the directory named by the plugin_dir
system variable). If necessary, configure the plugin directory location by setting the value of plugin_dir
at server startup.
The plugin library file base name is keyring_udf
. The file name suffix differs per platform (for example, .so
for Unix and Unix-like systems, .dll
for Windows).
To install the keyring_udf
plugin and the UDFs, use the INSTALL PLUGIN
and CREATE FUNCTION
statements (adjust the .so
suffix for your platform as necessary):
INSTALL PLUGIN keyring_udf SONAME 'keyring_udf.so'; CREATE FUNCTION keyring_key_generate RETURNS INTEGER SONAME 'keyring_udf.so'; CREATE FUNCTION keyring_key_fetch RETURNS STRING SONAME 'keyring_udf.so'; CREATE FUNCTION keyring_key_length_fetch RETURNS INTEGER SONAME 'keyring_udf.so'; CREATE FUNCTION keyring_key_type_fetch RETURNS STRING SONAME 'keyring_udf.so'; CREATE FUNCTION keyring_key_store RETURNS INTEGER SONAME 'keyring_udf.so'; CREATE FUNCTION keyring_key_remove RETURNS INTEGER SONAME 'keyring_udf.so';
If the plugin and UDFs are used on a master replication server, install them on all slave servers as well to avoid replication issues.
Once installed as just described, the plugin and UDFs remain installed until uninstalled. To remove them, use the UNINSTALL PLUGIN
and DROP FUNCTION
statements:
UNINSTALL PLUGIN keyring_udf; DROP FUNCTION keyring_key_generate; DROP FUNCTION keyring_key_fetch; DROP FUNCTION keyring_key_length_fetch; DROP FUNCTION keyring_key_type_fetch; DROP FUNCTION keyring_key_store; DROP FUNCTION keyring_key_remove;
Before using the keyring user-defined functions (UDFs), install them according to the instructions provided in Installing or Uninstalling General-Purpose Keyring Functions.
The keyring UDFs are subject to these constraints:
-
To use any keyring UDF, the
keyring_udf
plugin must be enabled. Otherwise, an error occurs:ERROR 1123 (HY000): Can't initialize function 'keyring_key_generate'; This function requires keyring_udf plugin which is not installed. Please install
To install the
keyring_udf
plugin, see Installing or Uninstalling General-Purpose Keyring Functions. -
The keyring UDFs invoke keyring service functions (see Section 29.3.2, “The Keyring Service”). The service functions in turn use whatever keyring plugin is installed (for example,
keyring_file
orkeyring_okv
). Therefore, to use any keyring UDF, some underlying keyring plugin must be enabled. Otherwise, an error occurs:ERROR 3188 (HY000): Function 'keyring_key_generate' failed because underlying keyring service returned an error. Please check if a keyring plugin is installed and that provided arguments are valid for the keyring you are using.
To install a keyring plugin, see Section 6.4.4.1, “Keyring Plugin Installation”.
-
To use any keyring UDF, a user must possess the global
EXECUTE
privilege. Otherwise, an error occurs:ERROR 1123 (HY000): Can't initialize function 'keyring_key_generate'; The user is not privileged to execute this function. User needs to have EXECUTE
To grant the global
EXECUTE
privilege to a user, use this statement:GRANT EXECUTE ON *.* TO
user
;Alternatively, should you prefer to avoid granting the global
EXECUTE
privilege while still permitting users to access specific key-management operations, “wrapper” stored programs can be defined (a technique described later in this section). -
A key stored in the keyring by a given user can be manipulated later only by the same user. That is, the value of the
CURRENT_USER()
function at the time of key manipulation must have the same value as when the key was stored in the keyring. (This constraint rules out the use of the keyring UDFs for manipulation of instance-wide keys, such as those created byInnoDB
to support tablespace encryption.)To enable multiple users to perform operations on the same key, “wrapper” stored programs can be defined (a technique described later in this section).
-
Keyring UDFs support the key types and lengths supported by the underlying keyring plugin. For information about keys specific to a particular keyring plugin, see Section 6.4.4.8, “Supported Keyring Key Types and Lengths”.
To create a new random key and store it in the keyring, call keyring_key_generate()
, passing to it an ID for the key, along with the key type (encryption method) and its length in bytes. The following call creates a 2,048-bit DSA-encrypted key named MyKey
:
mysql> SELECT keyring_key_generate('MyKey', 'DSA', 256);
+-------------------------------------------+
| keyring_key_generate('MyKey', 'DSA', 256) |
+-------------------------------------------+
| 1 |
+-------------------------------------------+
A return value of 1 indicates success. If the key cannot be created, the return value is NULL
and an error occurs. One reason this might be is that the underlying keyring plugin does not support the specified combination of key type and key length; see Section 6.4.4.8, “Supported Keyring Key Types and Lengths”.
To be able to check the return type regardless of whether an error occurs, use SELECT ... INTO @
and test the variable value:var_name
SELECT keyring_key_generate('', '', -1) INTO @x; SELECT @x; SELECT keyring_key_generate('x', 'AES', 16) INTO @x; SELECT @x;
This technique also applies to other keyring UDFs that for failure return a value and an error.
The ID passed to keyring_key_generate()
provides a means by which to refer to the key in subsequent UDF calls. For example, use the key ID to retrieve its type as a string or its length in bytes as an integer:
SELECT keyring_key_type_fetch('MyKey'); SELECT keyring_key_length_fetch('MyKey');
To retrieve a key value, pass the key ID to keyring_key_fetch()
. The following example uses HEX()
to display the key value because it may contain nonprintable characters. The example also uses a short key for brevity, but be aware that longer keys provide better security:
SELECT keyring_key_generate('MyShortKey', 'DSA', 8); SELECT HEX(keyring_key_fetch('MyShortKey'));
Keyring UDFs treat key IDs, types, and values as binary strings, so comparisons are case-sensitive. For example, IDs of MyKey
and mykey
refer to different keys.
To remove a key, pass the key ID to keyring_key_remove()
:
mysql> SELECT keyring_key_remove('MyKey');
+-----------------------------+
| keyring_key_remove('MyKey') |
+-----------------------------+
| 1 |
+-----------------------------+
To obfuscate and store a key that you provide, pass the key ID, type, and value to keyring_key_store()
:
mysql> SELECT keyring_key_store('AES_key', 'AES', 'Secret string');
+------------------------------------------------------+
| keyring_key_store('AES_key', 'AES', 'Secret string') |
+------------------------------------------------------+
| 1 |
+------------------------------------------------------+
As indicated previously, a user must have the global EXECUTE
privilege to call keyring UDFs, and the user who stores a key in the keyring initially must be the same user who performs subsequent operations on the key later, as determined from the CURRENT_USER()
value in effect for each UDF call. To permit key operations to users who do not have the global EXECUTE
privilege or who may not be the key “owner,” use this technique:
-
Define “wrapper” stored programs that encapsulate the required key operations and have a
DEFINER
value equal to the key owner. -
Grant the
EXECUTE
privilege for specific stored programs to the individual users who should be able to invoke them. -
If the operations implemented by the wrapper stored programs do not include key creation, create any necessary keys in advance, using the account named as the
DEFINER
in the stored program definitions.
This technique enables keys to be shared among users and provides to DBAs more fine-grained control over who can do what with keys, without having to grant global privileges.
The following example shows how to set up a shared key named SharedKey
that is owned by the DBA, and a get_shared_key()
stored function that provides access to the current key value. The value can be retrieved by any user with the EXECUTE
privilege for that function, which is created in the key_schema
schema.
From a MySQL administrative account ('root'@'localhost'
in this example), create the administrative schema and the stored function to access the key:
CREATE SCHEMA key_schema; CREATE DEFINER = 'root'@'localhost' FUNCTION key_schema.get_shared_key() RETURNS BLOB READS SQL DATA RETURN keyring_key_fetch('SharedKey');
From the administrative account, ensure that the shared key exists:
mysql> SELECT keyring_key_generate('SharedKey', 'DSA', 8);
+---------------------------------------------+
| keyring_key_generate('SharedKey', 'DSA', 8) |
+---------------------------------------------+
| 1 |
+---------------------------------------------+
From the administrative account, create an ordinary user account to which key access is to be granted:
CREATE USER 'key_user'@'localhost' IDENTIFIED BY 'key_user_pwd';
From the key_user
account, verify that, without the proper EXECUTE
privilege, the new account cannot access the shared key:
mysql> SELECT HEX(key_schema.get_shared_key());
ERROR 1370 (42000): execute command denied to user 'key_user'@'localhost'
for routine 'key_schema.get_shared_key'
From the administrative account, grant EXECUTE
to key_user
for the stored function:
GRANT EXECUTE ON FUNCTION key_schema.get_shared_key TO 'key_user'@'localhost';
From the key_user
account, verify that the key is now accessible:
mysql> SELECT HEX(key_schema.get_shared_key());
+----------------------------------+
| HEX(key_schema.get_shared_key()) |
+----------------------------------+
| 9BAFB9E75CEEB013 |
+----------------------------------+
For each general-purpose keyring user-defined function (UDF), this section describes its purpose, calling sequence, and return value. For information about the conditions under which these UDFs can be invoked, see Using General-Purpose Keyring Functions.
-
Given a key ID, deobfuscates and returns the key value.
Arguments:
-
key_id
: A string that specifies the key ID.
Return value:
Returns the key value as a string for success,
NULL
if the key does not exist, orNULL
and an error for failure.NoteKey values retrieved using
keyring_key_fetch()
are subject to the general keyring UDF limits described in Section 6.4.4.8, “Supported Keyring Key Types and Lengths”. A key value longer than that length can be stored using a keyring service function (see Section 29.3.2, “The Keyring Service”), but if retrieved usingkeyring_key_fetch()
is truncated to the general keyring UDF limit.Example:
SELECT keyring_key_generate('RSA_key', 'RSA', 16); SELECT HEX(keyring_key_fetch('RSA_key')); SELECT keyring_key_type_fetch('RSA_key'); SELECT keyring_key_length_fetch('RSA_key'); The example uses
HEX()
to display the key value because it may contain nonprintable characters. The example also uses a short key for brevity, but be aware that longer keys provide better security. -
-
keyring_key_generate(
key_id
,key_type
,key_length
)Generates a new random key with a given ID, type, and length, and stores it in the keyring. The type and length values must be consistent with the values supported by the underlying keyring plugin. See Section 6.4.4.8, “Supported Keyring Key Types and Lengths”.
Arguments:
-
key_id
: A string that specifies the key ID. -
key_type
: A string that specifies the key type. -
key_length
: An integer that specifies the key length in bytes.
Return value:
Returns 1 for success, or
NULL
and an error for failure.Example:
mysql>
SELECT keyring_key_generate('RSA_key', 'RSA', 384);
+---------------------------------------------+ | keyring_key_generate('RSA_key', 'RSA', 384) | +---------------------------------------------+ | 1 | +---------------------------------------------+ -
-
keyring_key_length_fetch(
key_id
)Given a key ID, returns the key length.
Arguments:
-
key_id
: A string that specifies the key ID.
Return value:
Returns the key length in bytes as an integer for success,
NULL
if the key does not exist, orNULL
and an error for failure.Example:
See the description of
keyring_key_fetch()
. -
-
Removes the key with a given ID from the keyring.
Arguments:
-
key_id
: A string that specifies the key ID.
Return value:
Returns 1 for success, or
NULL
for failure.Example:
mysql>
SELECT keyring_key_remove('AES_key');
+-------------------------------+ | keyring_key_remove('AES_key') | +-------------------------------+ | 1 | +-------------------------------+ -
-
keyring_key_store(
key_id
,key_type
,key
)Obfuscates and stores a key in the keyring.
Arguments:
-
key_id
: A string that specifies the key ID. -
key_type
: A string that specifies the key type. -
key
: A string that specifies the key value.
Return value:
Returns 1 for success, or
NULL
and an error for failure.Example:
mysql>
SELECT keyring_key_store('new key', 'DSA', 'My key value');
+-----------------------------------------------------+ | keyring_key_store('new key', 'DSA', 'My key value') | +-----------------------------------------------------+ | 1 | +-----------------------------------------------------+ -
-
keyring_key_type_fetch(
key_id
)Given a key ID, returns the key type.
Arguments:
-
key_id
: A string that specifies the key ID.
Return value:
Returns the key type as a string for success,
NULL
if the key does not exist, orNULL
and an error for failure.Example:
See the description of
keyring_key_fetch()
. -
For each keyring plugin-specific user-defined function (UDF), this section describes its purpose, calling sequence, and return value. For information about general-purpose keyring UDFs, see Section 6.4.4.9, “General-Purpose Keyring Key-Management Functions”.
-
Associated keyring plugin:
keyring_aws
keyring_aws_rotate_cmk()
rotates the customer master key (CMK). Rotation changes only the key that AWS KMS uses for subsequent data key-encryption operations. AWS KMS maintains previous CMK versions, so keys generated using previous CMKs remain decryptable after rotation.Rotation changes the CMK value used inside AWS KMS but does not change the ID used to refer to it, so there is no need to change the
keyring_aws_cmk_id
system variable after callingkeyring_aws_rotate_cmk()
.This UDF requires the
SUPER
privilege.Arguments:
None.
Return value:
Returns 1 for success, or
NULL
and an error for failure. -
Associated keyring plugin:
keyring_aws
keyring_aws_rotate_keys()
rotates keys stored in thekeyring_aws
storage file named by thekeyring_aws_data_file
system variable. Rotation sends each key stored in the file to AWS KMS for re-encryption using the value of thekeyring_aws_cmk_id
system variable as the CMK value, and stores the new encrypted keys in the file.keyring_aws_rotate_keys()
is useful for key re-encryption under these circumstances:-
After rotating the CMK; that is, after invoking the
keyring_aws_rotate_cmk()
UDF -
After changing the
keyring_aws_cmk_id
system variable to a different key value
This UDF requires the
SUPER
privilege.Arguments:
None.
Return value:
Returns 1 for success, or
NULL
and an error for failure. -
-
keyring_hashicorp_update_config()
Associated keyring plugin:
keyring_hashicorp
When invoked, the
keyring_hashicorp_update_config()
UDF causeskeyring_hashicorp
to perform a runtime reconfiguration, as described in keyring_hashicorp Configuration.This UDF requires the
SYSTEM_VARIABLES_ADMIN
privilege because it modifies global system variables.Arguments:
None.
Return value:
Returns the string
'Configuration update was successful.'
for success, or'Configuration update failed.'
for failure.
MySQL supports the following keyring-related command-line options:
-
--keyring-migration-destination=
plugin
Property Value Command-Line Format --keyring-migration-destination=plugin_name
Type String The destination keyring plugin for key migration. See Section 6.4.4.7, “Migrating Keys Between Keyring Keystores”. The format and interpretation of the option value is the same as described for the
--keyring-migration-source
option.Note--keyring-migration-source
and--keyring-migration-destination
are mandatory for all keyring migration operations. The source and destination plugins must differ, and the migration server must support both plugins. -
--keyring-migration-host=
host_name
Property Value Command-Line Format --keyring-migration-host=host_name
Type String Default Value localhost
The host location of the running server that is currently using one of the key migration keystores. See Section 6.4.4.7, “Migrating Keys Between Keyring Keystores”. Migration always occurs on the local host, so the option always specifies a value for connecting to a local server, such as
localhost
,127.0.0.1
,::1
, or the local host IP address or host name. -
--keyring-migration-password[=
password
]Property Value Command-Line Format --keyring-migration-password[=password]
Type String The password for connecting to the running server that is currently using one of the key migration keystores. See Section 6.4.4.7, “Migrating Keys Between Keyring Keystores”. If you omit the
password
value following the option name on the command line, the server prompts for one.Specifying a password on the command line should be considered insecure. See Section 6.1.2.1, “End-User Guidelines for Password Security”. You can use an option file to avoid giving the password on the command line. In this case, the file should have a restrictive mode and be accessible only to the account used to run the migration server.
-
--keyring-migration-port=
port_num
Property Value Command-Line Format --keyring-migration-port=port_num
Type Numeric Default Value 3306
For TCP/IP connections, the port number for connecting to the running server that is currently using one of the key migration keystores. See Section 6.4.4.7, “Migrating Keys Between Keyring Keystores”.
-
--keyring-migration-socket=
path
Property Value Command-Line Format --keyring-migration-socket={file_name|pipe_name}
Type String For Unix socket file or Windows named pipe connections, the socket file or named pipe for connecting to the running server that is currently using one of the key migration keystores. See Section 6.4.4.7, “Migrating Keys Between Keyring Keystores”.
-
--keyring-migration-source=
plugin
Property Value Command-Line Format --keyring-migration-source=plugin_name
Type String The source keyring plugin for key migration. See Section 6.4.4.7, “Migrating Keys Between Keyring Keystores”.
The option value is similar to that for
--plugin-load
, except that only one plugin library can be specified. The value is given asname
=
plugin_library
orplugin_library
. Thename
is the name of a plugin to load, andplugin_library
is the name of the library file that contains the plugin code. If the plugin library is named without any preceding plugin name, the server loads all plugins in the library. The server looks for plugin library files in the directory named by theplugin_dir
system variable.Note--keyring-migration-source
and--keyring-migration-destination
are mandatory for all keyring migration operations. The source and destination plugins must differ, and the migration server must support both plugins. -
--keyring-migration-user=
user_name
Property Value Command-Line Format --keyring-migration-user=user_name
Type String The user name for connecting to the running server that is currently using one of the key migration keystores. See Section 6.4.4.7, “Migrating Keys Between Keyring Keystores”.
MySQL Keyring plugins support the following system variables. Use them to configure keyring plugin operation. These variables are unavailable unless the appropriate keyring plugin is installed (see Section 6.4.4.1, “Keyring Plugin Installation”).
-
Property Value Command-Line Format --keyring-aws-cmk-id=value
System Variable keyring_aws_cmk_id
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type String The customer master key (CMK) ID obtained from the AWS KMS server and used by the
keyring_aws
plugin. This variable is unavailable unless that plugin is installed, but if it is installed, a value for this variable is mandatory. -
Property Value Command-Line Format --keyring-aws-conf-file=file_name
System Variable keyring_aws_conf_file
Scope Global Dynamic No SET_VAR
Hint AppliesNo Type File name Default Value platform specific
The location of the configuration file for the
keyring_aws
keyring plugin. This variable is unavailable unless that plugin is installed.At plugin startup,
keyring_aws
reads the AWS secret access key ID and key from the configuration file. For thekeyring_aws
plugin to start successfully, the configuration file must exist and contain valid secret access key information, initialized as described in Section 6.4.4.5, “Using the keyring_aws Amazon Web Services Keyring Plugin”.The default file name is
keyring_aws_conf
, located in the default keyring file directory. The location of this default directory is the same as for thekeyring_file_data
system variable. See the description of that variable for details, as well as for considerations to take into account if you create the directory manually. -
Property Value Command-Line Format --keyring-aws-data-file
System Variable keyring_aws_data_file
Scope Global Dynamic No SET_VAR
Hint AppliesNo Type File name Default Value platform specific
The location of the storage file for the
keyring_aws
keyring plugin. This variable is unavailable unless that plugin is installed.At plugin startup, if the value assigned to
keyring_aws_data_file
specifies a file that does not exist, thekeyring_aws
plugin attempts to create it (as well as its parent directory, if necessary). If the file does exist,keyring_aws
reads any encrypted keys contained in the file into its in-memory cache.keyring_aws
does not cache unencrypted keys in memory.The default file name is
keyring_aws_data
, located in the default keyring file directory. The location of this default directory is the same as for thekeyring_file_data
system variable. See the description of that variable for details, as well as for considerations to take into account if you create the directory manually. -
Property Value Command-Line Format --keyring-aws-region=value
System Variable keyring_aws_region
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type Enumeration Default Value us-east-1
Valid Values ap-northeast-1
ap-northeast-2
ap-south-1
ap-southeast-1
ap-southeast-2
eu-central-1
eu-west-1
sa-east-1
us-east-1
us-west-1
us-west-2
The AWS region.
-
Property Value Command-Line Format --keyring-encrypted-file-data=file_name
System Variable keyring_encrypted_file_data
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type File name Default Value platform specific
The path name of the data file used for secure data storage by the
keyring_encrypted_file
plugin. This variable is unavailable unless that plugin is installed. The file location should be in a directory considered for use only by keyring plugins. For example, do not locate the file under the data directory.Keyring operations are transactional: The
keyring_encrypted_file
plugin uses a backup file during write operations to ensure that it can roll back to the original file if an operation fails. The backup file has the same name as the value of thekeyring_encrypted_file_data
system variable with a suffix of.backup
.Do not use the same
keyring_encrypted_file
data file for multiple MySQL instances. Each instance should have its own unique data file.The default file name is
keyring_encrypted
, located in a directory that is platform specific and depends on the value of theINSTALL_LAYOUT
CMake option, as shown in the following table. To specify the default directory for the file explicitly if you are building from source, use theINSTALL_MYSQLKEYRINGDIR
CMake option.INSTALL_LAYOUT
ValueDefault keyring_encrypted_file_data
ValueDEB
,RPM
,SVR4
/var/lib/mysql-keyring/keyring_encrypted
Otherwise keyring/keyring_encrypted
under theCMAKE_INSTALL_PREFIX
valueAt plugin startup, if the value assigned to
keyring_encrypted_file_data
specifies a file that does not exist, thekeyring_encrypted_file
plugin attempts to create it (as well as its parent directory, if necessary).If you create the directory manually, it should have a restrictive mode and be accessible only to the account used to run the MySQL server. For example, on Unix and Unix-like systems, to use the
/usr/local/mysql/mysql-keyring
directory, the following commands (executed asroot
) create the directory and set its mode and ownership:cd /usr/local/mysql mkdir mysql-keyring chmod 750 mysql-keyring chown mysql mysql-keyring chgrp mysql mysql-keyring
If the
keyring_encrypted_file
plugin cannot create or access its data file, it writes an error message to the error log. If an attempted runtime assignment tokeyring_encrypted_file_data
results in an error, the variable value remains unchanged.ImportantOnce the
keyring_encrypted_file
plugin has created its data file and started to use it, it is important not to remove the file. Loss of the file will cause data encrypted using its keys to become inaccessible. (It is permissible to rename or move the file, as long as you change the value ofkeyring_encrypted_file_data
to match.) -
keyring_encrypted_file_password
Property Value Command-Line Format --keyring-encrypted-file-password=password
System Variable keyring_encrypted_file_password
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type String The password used by the
keyring_encrypted_file
plugin. This variable is unavailable unless that plugin is installed. The password is mandatory for plugin operation; if not specified at server startup,keyring_encrypted_file
initialization fails.If this variable is specified in an option file, the file should have a restrictive mode and be accessible only to the account used to run the MySQL server.
ImportantOnce the
keyring_encrypted_file_password
value has been set, changing it does not rotate the keyring password and could make the server inaccessible. If an incorrect password is provided, thekeyring_encrypted_file
plugin cannot load keys from the encrypted keyring file.The password value cannot be displayed at runtime with
SHOW VARIABLES
or the Performance Schemaglobal_variables
table because the display value is obfuscated. -
Property Value Command-Line Format --keyring-file-data=file_name
System Variable keyring_file_data
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type File name Default Value platform specific
The path name of the data file used for secure data storage by the
keyring_file
plugin. This variable is unavailable unless that plugin is installed. The file location should be in a directory considered for use only by keyring plugins. For example, do not locate the file under the data directory.Keyring operations are transactional: The
keyring_file
plugin uses a backup file during write operations to ensure that it can roll back to the original file if an operation fails. The backup file has the same name as the value of thekeyring_file_data
system variable with a suffix of.backup
.Do not use the same
keyring_file
data file for multiple MySQL instances. Each instance should have its own unique data file.The default file name is
keyring
, located in a directory that is platform specific and depends on the value of theINSTALL_LAYOUT
CMake option, as shown in the following table. To specify the default directory for the file explicitly if you are building from source, use theINSTALL_MYSQLKEYRINGDIR
CMake option.INSTALL_LAYOUT
ValueDefault keyring_file_data
ValueDEB
,RPM
,SVR4
/var/lib/mysql-keyring/keyring
Otherwise keyring/keyring
under theCMAKE_INSTALL_PREFIX
valueAt plugin startup, if the value assigned to
keyring_file_data
specifies a file that does not exist, thekeyring_file
plugin attempts to create it (as well as its parent directory, if necessary).If you create the directory manually, it should have a restrictive mode and be accessible only to the account used to run the MySQL server. For example, on Unix and Unix-like systems, to use the
/usr/local/mysql/mysql-keyring
directory, the following commands (executed asroot
) create the directory and set its mode and ownership:cd /usr/local/mysql mkdir mysql-keyring chmod 750 mysql-keyring chown mysql mysql-keyring chgrp mysql mysql-keyring
If the
keyring_file
plugin cannot create or access its data file, it writes an error message to the error log. If an attempted runtime assignment tokeyring_file_data
results in an error, the variable value remains unchanged.ImportantOnce the
keyring_file
plugin has created its data file and started to use it, it is important not to remove the file. For example,InnoDB
uses the file to store the master key used to decrypt the data in tables that useInnoDB
tablespace encryption; see Section 15.13, “InnoDB Data-at-Rest Encryption”. Loss of the file will cause data in such tables to become inaccessible. (It is permissible to rename or move the file, as long as you change the value ofkeyring_file_data
to match.) It is recommended that you create a separate backup of the keyring data file immediately after you create the first encrypted table and before and after master key rotation. -
Property Value Command-Line Format --keyring-hashicorp-auth-path=value
Introduced 8.0.18 System Variable keyring_hashicorp_auth_path
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type String Default Value /v1/auth/approle/login
The authentication path where AppRole authentication is enabled within the HashiCorp Vault server.
-
Property Value Command-Line Format --keyring-hashicorp-ca-path=file_name
Introduced 8.0.18 System Variable keyring_hashicorp_ca_path
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type File name Default Value empty string
The absolute path name of a local file accessible to the MySQL server that contains a properly formatted TLS certificate authority.
If this variable is not set, the
keyring_hashicorp
plugin opens an HTTPS connection without using server certificate verification, and trusts any certificate delivered by the HashiCorp Vault server. For this to be safe, it must be assumed that the Vault server is not malicious and that no man-in-the-middle attack is possible. If those assumptions are invalid, setkeyring_hashicorp_ca_path
to the path of a trusted CA certificate. (For example, for the instructions in Certificate and Key Preparation, this is thecompany.crt
file.) -
Property Value Command-Line Format --keyring-hashicorp-caching[={OFF|ON}]
Introduced 8.0.18 System Variable keyring_hashicorp_caching
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type Boolean Default Value OFF
Whether to enable the optional in-memory key cache used by the
keyring_hashicorp
plugin to cache keys from the HashiCorp Vault server. If the cache is enabled, the plugin populates it during initialization. Otherwise, the plugin populates only the key list during initialization.Enabling the cache is a compromise: It improves performance, but maintains a copy of sensitive key information in memory, which may be undesirable for security purposes.
-
keyring_hashicorp_commit_auth_path
Property Value Introduced 8.0.18 System Variable keyring_hashicorp_commit_auth_path
Scope Global Dynamic No SET_VAR
Hint AppliesNo Type String This variable is associated with
keyring_hashicorp_auth_path
, from which it takes its value duringkeyring_hashicorp
plugin initialization. It reflects the “committed” value actually used for plugin operation if initialization succeeds. For additional information, see keyring_hashicorp Configuration. -
keyring_hashicorp_commit_ca_path
Property Value Introduced 8.0.18 System Variable keyring_hashicorp_commit_ca_path
Scope Global Dynamic No SET_VAR
Hint AppliesNo Type String This variable is associated with
keyring_hashicorp_ca_path
. See the description of thekeyring_hashicorp_commit_auth_path
system variable for information about_commit_
variables. -
keyring_hashicorp_commit_caching
Property Value Introduced 8.0.18 System Variable keyring_hashicorp_commit_caching
Scope Global Dynamic No SET_VAR
Hint AppliesNo Type String This variable is associated with
keyring_hashicorp_caching
. See the description of thekeyring_hashicorp_commit_auth_path
system variable for information about_commit_
variables. -
keyring_hashicorp_commit_role_id
Property Value Introduced 8.0.18 System Variable keyring_hashicorp_commit_role_id
Scope Global Dynamic No SET_VAR
Hint AppliesNo Type String This variable is associated with
keyring_hashicorp_role_id
. See the description of thekeyring_hashicorp_commit_auth_path
system variable for information about_commit_
variables. -
keyring_hashicorp_commit_server_url
Property Value Introduced 8.0.18 System Variable keyring_hashicorp_commit_server_url
Scope Global Dynamic No SET_VAR
Hint AppliesNo Type String This variable is associated with
keyring_hashicorp_server_url
. See the description of thekeyring_hashicorp_commit_auth_path
system variable for information about_commit_
variables. -
keyring_hashicorp_commit_store_path
Property Value Introduced 8.0.18 System Variable keyring_hashicorp_commit_store_path
Scope Global Dynamic No SET_VAR
Hint AppliesNo Type String This variable is associated with
keyring_hashicorp_store_path
. See the description of thekeyring_hashicorp_commit_auth_path
system variable for information about_commit_
variables. -
Property Value Command-Line Format --keyring-hashicorp-role-id=value
Introduced 8.0.18 System Variable keyring_hashicorp_role_id
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type String Default Value empty string
The HashiCorp Vault AppRole authentication role ID. The value must be in UUID format.
This variable is mandatory. If not specified,
keyring_hashicorp
initialization fails. -
Property Value Command-Line Format --keyring-hashicorp-secret-id=value
Introduced 8.0.18 System Variable keyring_hashicorp_secret_id
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type String Default Value empty string
The HashiCorp Vault AppRole authentication secret ID. The value must be in UUID format.
This variable is mandatory. If not specified,
keyring_hashicorp
initialization fails.The value of this variable is sensitive, so its value is masked by
*
characters when displayed. -
Property Value Command-Line Format --keyring-hashicorp-server-url=value
Introduced 8.0.18 System Variable keyring_hashicorp_server_url
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type String Default Value https://127.0.0.1:8200
The HashiCorp Vault server URL. The value must begin with
https://
. -
Property Value Command-Line Format --keyring-hashicorp-store-path=value
Introduced 8.0.18 System Variable keyring_hashicorp_store_path
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type String Default Value empty string
A store path within the HashiCorp Vault server that is writeable when appropiate AppRole AppRole credentials are provided by
keyring_hashicorp
. To specify the credentials, set thekeyring_hashicorp_role_id
andkeyring_hashicorp_secret_id
system variables (for example, as shown in keyring_hashicorp Configuration).This variable is mandatory. If not specified,
keyring_hashicorp
initialization fails. -
Property Value Command-Line Format --keyring-okv-conf-dir=dir_name
System Variable keyring_okv_conf_dir
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type Directory name Default Value empty string
The path name of the directory that stores configuration information used by the
keyring_okv
plugin. This variable is unavailable unless that plugin is installed. The location should be a directory considered for use only by thekeyring_okv
plugin. For example, do not locate the directory under the data directory.The default
keyring_okv_conf_dir
value is empty. For thekeyring_okv
plugin to be able to access Oracle Key Vault, the value must be set to a directory that contains Oracle Key Vault configuration and SSL materials. For instructions on setting up this directory, see Section 6.4.4.4, “Using the keyring_okv KMIP Plugin”.The directory should have a restrictive mode and be accessible only to the account used to run the MySQL server. For example, on Unix and Unix-like systems, to use the
/usr/local/mysql/mysql-keyring-okv
directory, the following commands (executed asroot
) create the directory and set its mode and ownership:cd /usr/local/mysql mkdir mysql-keyring-okv chmod 750 mysql-keyring-okv chown mysql mysql-keyring-okv chgrp mysql mysql-keyring-okv
If the value assigned to
keyring_okv_conf_dir
specifies a directory that does not exist, or that does not contain configuration information that enables a connection to Oracle Key Vault to be established,keyring_okv
writes an error message to the error log. If an attempted runtime assignment tokeyring_okv_conf_dir
results in an error, the variable value and keyring operation remain unchanged. -
Property Value System Variable keyring_operations
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type Boolean Default Value ON
Whether keyring operations are enabled. This variable is used during key migration operations. See Section 6.4.4.7, “Migrating Keys Between Keyring Keystores”. The privileges required to modify this variable are
ENCRYPTION_KEY_ADMIN
in addition to eitherSYSTEM_VARIABLES_ADMIN
orSUPER
.
- 6.4.5.1 Audit Log Components
- 6.4.5.2 Installing or Uninstalling MySQL Enterprise Audit
- 6.4.5.3 MySQL Enterprise Audit Security Considerations
- 6.4.5.4 Audit Log File Formats
- 6.4.5.5 Audit Log Logging Configuration
- 6.4.5.6 Audit Log Filtering
- 6.4.5.7 Writing Audit Log Filter Definitions
- 6.4.5.8 Legacy Mode Audit Log Filtering
- 6.4.5.9 Audit Log Reference
- 6.4.5.10 Audit Log Restrictions
MySQL Enterprise Audit is an extension included in MySQL Enterprise Edition, a commercial product. To learn more about commercial products, see https://www.mysql.com/products/.
MySQL Enterprise Edition includes MySQL Enterprise Audit, implemented using a server plugin named audit_log
. MySQL Enterprise Audit uses the open MySQL Audit API to enable standard, policy-based monitoring, logging, and blocking of connection and query activity executed on specific MySQL servers. Designed to meet the Oracle audit specification, MySQL Enterprise Audit provides an out of box, easy to use auditing and compliance solution for applications that are governed by both internal and external regulatory guidelines.
When installed, the audit plugin enables MySQL Server to produce a log file containing an audit record of server activity. The log contents include when clients connect and disconnect, and what actions they perform while connected, such as which databases and tables they access.
After you install the audit plugin (see Section 6.4.5.2, “Installing or Uninstalling MySQL Enterprise Audit”), it writes an audit log file. By default, the file is named audit.log
in the server data directory. To change the name of the file, set the audit_log_file
system variable at server startup.
By default, audit log file contents are written in new-style XML format, without compression or encryption. To select the file format, set the audit_log_format
system variable at server startup. For details on file format and contents, see Section 6.4.5.4, “Audit Log File Formats”.
For more information about controlling how logging occurs, including audit log file naming and format selection, see Section 6.4.5.5, “Audit Log Logging Configuration”. To perform filtering of audited events, see Section 6.4.5.6, “Audit Log Filtering”. For descriptions of the parameters used to configure the audit log plugin, see Audit Log Options and Variables.
If the audit log plugin is enabled, the Performance Schema (see Chapter 26, MySQL Performance Schema) has instrumentation for it. To identify the relevant instruments, use this query:
SELECT NAME FROM performance_schema.setup_instruments WHERE NAME LIKE '%/alog/%';
MySQL Enterprise Audit is based on the audit log plugin and related components:
-
A server-side plugin named
audit_log
examines auditable events and determines whether to write them to the audit log. -
User-defined functions enable manipulation of filtering definitions that control logging behavior, the encryption password, and log file reading.
-
Tables in the
mysql
system database provide persistent storage of filter and user account data. -
System variables enable audit log configuration and status variables provide runtime operational information.
-
An
AUDIT_ADMIN
privilege enable users to administer the audit log.
This section describes how to install or uninstall MySQL Enterprise Audit, which is implemented using the audit log plugin and related components described in Section 6.4.5.1, “Audit Log Components”. For general information about installing plugins, see Section 5.6.1, “Installing and Uninstalling Plugins”.
Read this entire section before following its instructions. Parts of the procedure differ depending on your environment.
If installed, the audit_log
plugin involves some minimal overhead even when disabled. To avoid this overhead, do not install MySQL Enterprise Audit unless you plan to use it.
To be usable by the server, the plugin library file must be located in the MySQL plugin directory (the directory named by the plugin_dir
system variable). If necessary, configure the plugin directory location by setting the value of plugin_dir
at server startup.
To install MySQL Enterprise Audit, look in the share
directory of your MySQL installation and choose the script that is appropriate for your platform. The available scripts differ in the suffix used to refer to the plugin library file:
-
audit_log_filter_win_install.sql
: Choose this script for Windows systems that use.dll
as the file name suffix. -
audit_log_filter_linux_install.sql
: Choose this script for Linux and similar systems that use.so
as the file name suffix.
Run the script as follows. The example here uses the Linux installation script. Make the appropriate substitution for your system.
mysql -u root -p < audit_log_filter_linux_install.sql (enter root password here)
Some MySQL versions have introduced changes to the structure of the MySQL Enterprise Audit tables. To ensure that your tables are up to date for upgrades from earlier versions of MySQL 8.0, perform the MySQL upgrade procedure, making sure to use the option that forces an update (see Section 2.11, “Upgrading MySQL”). If you prefer to run the update statements only for the MySQL Enterprise Audit tables, see the following discussion.
As of MySQL 8.0.12, for new MySQL installations, the USER
and HOST
columns in the audit_log_user
table used by MySQL Enterprise Audit have definitions that better correspond to the definitions of the User
and Host
columns in the mysql.user
system table. For upgrades to an installation for which MySQL Enterprise Audit is already installed, it is recommended that you alter the table definitions as follows:
ALTER TABLE mysql.audit_log_user DROP FOREIGN KEY audit_log_user_ibfk_1; ALTER TABLE mysql.audit_log_filter CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_as_ci; ALTER TABLE mysql.audit_log_user CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_as_ci; ALTER TABLE mysql.audit_log_user MODIFY COLUMN USER VARCHAR(32); ALTER TABLE mysql.audit_log_user ADD FOREIGN KEY (FILTERNAME) REFERENCES mysql.audit_log_filter(NAME);
To use MySQL Enterprise Audit in the context of master/slave replication, Group Replication, or InnoDB cluster, you must prepare the slave or secondary nodes prior to running the installation script on the master or primary node. This is necessary because the INSTALL PLUGIN
statement in the script is not replicated.
-
On each slave or secondary node, extract the
INSTALL PLUGIN
statement from the installation script and execute it manually. -
On the master or primary node, run the installation script as described previously.
To verify plugin installation, examine the INFORMATION_SCHEMA.PLUGINS
table or use the SHOW PLUGINS
statement (see Section 5.6.2, “Obtaining Server Plugin Information”). For example:
SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME LIKE 'audit%';
If the plugin fails to initialize, check the server error log for diagnostic messages.
After MySQL Enterprise Audit is installed, you can use the --audit-log
option for subsequent server startups to control audit_log
plugin activation. For example, to prevent the plugin from being removed at runtime, use this option:
[mysqld] audit-log=FORCE_PLUS_PERMANENT
If it is desired to prevent the server from running without the audit plugin, use --audit-log
with a value of FORCE
or FORCE_PLUS_PERMANENT
to force server startup to fail if the plugin does not initialize successfully.
By default, rule-based audit log filtering logs no auditable events for any users. This differs from legacy audit log behavior, which logs all auditable events for all users (see Section 6.4.5.8, “Legacy Mode Audit Log Filtering”). Should you wish to produce log-everything behavior with rule-based filtering, create a simple filter to enable logging and assign it to the default account:
SELECT audit_log_filter_set_filter('log_all', '{ "filter": { "log": true } }'); SELECT audit_log_filter_set_user('%', 'log_all');
The filter assigned to %
is used for connections from any account that has no explicitly assigned filter (which initially is true for all accounts).
Once installed as just described, MySQL Enterprise Audit remains installed until uninstalled. To remove it, execute the following statements:
DROP TABLE IF EXISTS mysql.audit_log_user; DROP TABLE IF EXISTS mysql.audit_log_filter; UNINSTALL PLUGIN audit_log; DROP FUNCTION audit_log_filter_set_filter; DROP FUNCTION audit_log_filter_remove_filter; DROP FUNCTION audit_log_filter_set_user; DROP FUNCTION audit_log_filter_remove_user; DROP FUNCTION audit_log_filter_flush; DROP FUNCTION audit_log_encryption_password_get; DROP FUNCTION audit_log_encryption_password_set; DROP FUNCTION audit_log_read; DROP FUNCTION audit_log_read_bookmark;
By default, contents of audit log files produced by the audit log plugin are not encrypted and may contain sensitive information, such as the text of SQL statements. For security reasons, audit log files should be written to a directory accessible only to the MySQL server and to users with a legitimate reason to view the log. The default file name is audit.log
in the data directory. This can be changed by setting the audit_log_file
system variable at server startup. Other audit log files may exist due to log rotation.
For additional security, enable audit log file encryption. See Audit Log File Encryption.
The MySQL server calls the audit log plugin to write an audit record to its log file whenever an auditable event occurs. Typically the first audit record written after plugin startup contains the server description and startup options. Elements following that one represent events such as client connect and disconnect events, executed SQL statements, and so forth. Only top-level statements are logged, not statements within stored programs such as triggers or stored procedures. Contents of files referenced by statements such as LOAD DATA
are not logged.
To select the log format that the audit log plugin uses to write its log file, set the audit_log_format
system variable at server startup. These formats are available:
-
New-style XML format (
audit_log_format=NEW
): An XML format that has better compatibility with Oracle Audit Vault than old-style XML format. MySQL 8.0 uses new-style XML format by default. -
Old-style XML format (
audit_log_format=OLD
): The original audit log format used by default in older MySQL series. -
JSON format (
audit_log_format=JSON
)
By default, audit log file contents are written in new-style XML format, without compression or encryption.
For information about issues to consider when changing the log format, see Audit Log File Format.
The following sections describe the available audit logging formats:
Here is a sample log file in new-style XML format (audit_log_format=NEW
), reformatted slightly for readability:
<?xml version="1.0" encoding="utf-8"?> <AUDIT> <AUDIT_RECORD> <TIMESTAMP>2019-10-03T14:06:33 UTC</TIMESTAMP> <RECORD_ID>1_2019-10-03T14:06:33</RECORD_ID> <NAME>Audit</NAME> <SERVER_ID>1</SERVER_ID> <VERSION>1</VERSION> <STARTUP_OPTIONS>/usr/local/mysql/bin/mysqld --socket=/usr/local/mysql/mysql.sock --port=3306</STARTUP_OPTIONS> <OS_VERSION>i686-Linux</OS_VERSION> <MYSQL_VERSION>5.7.21-log</MYSQL_VERSION> </AUDIT_RECORD> <AUDIT_RECORD> <TIMESTAMP>2019-10-03T14:09:38 UTC</TIMESTAMP> <RECORD_ID>2_2019-10-03T14:06:33</RECORD_ID> <NAME>Connect</NAME> <CONNECTION_ID>5</CONNECTION_ID> <STATUS>0</STATUS> <STATUS_CODE>0</STATUS_CODE> <USER>root</USER> <OS_LOGIN/> <HOST>localhost</HOST> <IP>127.0.0.1</IP> <COMMAND_CLASS>connect</COMMAND_CLASS> <CONNECTION_TYPE>SSL/TLS</CONNECTION_TYPE> <CONNECTION_ATTRIBUTES> <ATTRIBUTE> <NAME>_pid</NAME> <VALUE>42794</VALUE> </ATTRIBUTE> ... <ATTRIBUTE> <NAME>program_name</NAME> <VALUE>mysqladmin</VALUE> </ATTRIBUTE> </CONNECTION_ATTRIBUTES> <PRIV_USER>root</PRIV_USER> <PROXY_USER/> <DB>test</DB> </AUDIT_RECORD> ... <AUDIT_RECORD> <TIMESTAMP>2019-10-03T14:09:38 UTC</TIMESTAMP> <RECORD_ID>6_2019-10-03T14:06:33</RECORD_ID> <NAME>Query</NAME> <CONNECTION_ID>5</CONNECTION_ID> <STATUS>0</STATUS> <STATUS_CODE>0</STATUS_CODE> <USER>root[root] @ localhost [127.0.0.1]</USER> <OS_LOGIN/> <HOST>localhost</HOST> <IP>127.0.0.1</IP> <COMMAND_CLASS>drop_table</COMMAND_CLASS> <SQLTEXT>DROP TABLE IF EXISTS t</SQLTEXT> </AUDIT_RECORD> ... <AUDIT_RECORD> <TIMESTAMP>2019-10-03T14:09:39 UTC</TIMESTAMP> <RECORD_ID>8_2019-10-03T14:06:33</RECORD_ID> <NAME>Quit</NAME> <CONNECTION_ID>5</CONNECTION_ID> <STATUS>0</STATUS> <STATUS_CODE>0</STATUS_CODE> <USER>root</USER> <OS_LOGIN/> <HOST>localhost</HOST> <IP>127.0.0.1</IP> <COMMAND_CLASS>connect</COMMAND_CLASS> <CONNECTION_TYPE>SSL/TLS</CONNECTION_TYPE> </AUDIT_RECORD> ... <AUDIT_RECORD> <TIMESTAMP>2019-10-03T14:09:43 UTC</TIMESTAMP> <RECORD_ID>11_2019-10-03T14:06:33</RECORD_ID> <NAME>Quit</NAME> <CONNECTION_ID>6</CONNECTION_ID> <STATUS>0</STATUS> <STATUS_CODE>0</STATUS_CODE> <USER>root</USER> <OS_LOGIN/> <HOST>localhost</HOST> <IP>127.0.0.1</IP> <COMMAND_CLASS>connect</COMMAND_CLASS> <CONNECTION_TYPE>SSL/TLS</CONNECTION_TYPE> </AUDIT_RECORD> <AUDIT_RECORD> <TIMESTAMP>2019-10-03T14:09:45 UTC</TIMESTAMP> <RECORD_ID>12_2019-10-03T14:06:33</RECORD_ID> <NAME>NoAudit</NAME> <SERVER_ID>1</SERVER_ID> </AUDIT_RECORD> </AUDIT>
The audit log file is written as XML, using UTF-8 (up to 4 bytes per character). The root element is <AUDIT>
. The root element contains <AUDIT_RECORD>
elements, each of which provides information about an audited event. When the audit log plugin begins writing a new log file, it writes the XML declaration and opening <AUDIT>
root element tag. When the plugin closes a log file, it writes the closing </AUDIT>
root element tag. The closing tag is not present while the file is open.
Elements within <AUDIT_RECORD>
elements have these characteristics:
-
Some elements appear in every
<AUDIT_RECORD>
element. Others are optional and may appear depending on the audit record type. -
Order of elements within an
<AUDIT_RECORD>
element is not guaranteed. -
Element values are not fixed length. Long values may be truncated as indicated in the element descriptions given later.
-
The
<
,>
,"
, and&
characters are encoded as<
,>
,"
, and&
, respectively. NUL bytes (U+00) are encoded as the?
character. -
Characters not valid as XML characters are encoded using numeric character references. Valid XML characters are:
#x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
The following elements are mandatory in every <AUDIT_RECORD>
element:
-
<NAME>
A string representing the type of instruction that generated the audit event, such as a command that the server received from a client.
Example:
<NAME>Query</NAME>
Some common
<NAME>
values:Audit When auditing starts, which may be server startup time Connect When a client connects, also known as logging in Query An SQL statement (executed directly) Prepare Preparation of an SQL statement; usually followed by Execute Execute Execution of an SQL statement; usually follows Prepare Shutdown Server shutdown Quit When a client disconnects NoAudit Auditing has been turned off
The possible values are
Audit
,Binlog Dump
,Change user
,Close stmt
,Connect Out
,Connect
,Create DB
,Daemon
,Debug
,Delayed insert
,Drop DB
,Execute
,Fetch
,Field List
,Init DB
,Kill
,Long Data
,NoAudit
,Ping
,Prepare
,Processlist
,Query
,Quit
,Refresh
,Register Slave
,Reset stmt
,Set option
,Shutdown
,Sleep
,Statistics
,Table Dump
,TableDelete
,TableInsert
,TableRead
,TableUpdate
,Time
.Many of these values correspond to the
COM_
command values listed in thexxx
my_command.h
header file. For example,Create DB
andChange user
correspond toCOM_CREATE_DB
andCOM_CHANGE_USER
, respectively.Events having
<NAME>
values ofTable
accompanyXXX
Query
events. For example, the following statement generates oneQuery
event, twoTableRead
events, and aTableInsert
events:INSERT INTO t3 SELECT t1.* FROM t1 JOIN t2;
Each
Table
event containsXXX
<DB>
and<TABLE>
elements to identify the table to which the event refers. -
<RECORD_ID>
A unique identifier for the audit record. The value is composed from a sequence number and timestamp, in the format
. When the audit log plugin opens the audit log file, it initializes the sequence number to the size of the audit log file, then increments the sequence by 1 for each record logged. The timestamp is a UTC value inSEQ_TIMESTAMP
format indicating the date and time when the audit log plugin opened the file.YYYY-MM-DD
Thh:mm:ss
Example:
<RECORD_ID>12_2019-10-03T14:06:33</RECORD_ID>
-
<TIMESTAMP>
A string representing a UTC value in
format indicating the date and time when the audit event was generated. For example, the event corresponding to execution of an SQL statement received from a client has aYYYY-MM-DD
Thh:mm:ss
UTC<TIMESTAMP>
value occurring after the statement finishes, not when it was received.Example:
<TIMESTAMP>2019-10-03T14:09:45 UTC</TIMESTAMP>
The following elements are optional in <AUDIT_RECORD>
elements. Many of them occur only with specific <NAME>
element values.
-
<COMMAND_CLASS>
A string that indicates the type of action performed.
Example:
<COMMAND_CLASS>drop_table</COMMAND_CLASS>
The values correspond to the
statement/sql/
command counters. For example,xxx
xxx
isdrop_table
andselect
forDROP TABLE
andSELECT
statements, respectively. The following statement displays the possible names:SELECT REPLACE(EVENT_NAME, 'statement/sql/', '') AS name FROM performance_schema.events_statements_summary_global_by_event_name WHERE EVENT_NAME LIKE 'statement/sql/%' ORDER BY name;
-
<CONNECTION_ATTRIBUTES>
As of MySQL 8.0.19, events with a
<COMMAND_CLASS>
value ofconnect
may include a<CONNECTION_ATTRIBUTES>
element to display the connection attributes passed by the client at connect time. (For information about these attributes, which are also exposed in Performance Schema tables, see Section 26.12.9, “Performance Schema Connection Attribute Tables”.)The
<CONNECTION_ATTRIBUTES>
element contains one<ATTRIBUTE>
element per attribute, each of which contains<NAME>
and<VALUE>
elements to indicate the attribute name and value, respectively.Example:
<CONNECTION_ATTRIBUTES> <ATTRIBUTE> <NAME>_pid</NAME> <VALUE>42794</VALUE> </ATTRIBUTE> <ATTRIBUTE> <NAME>_os</NAME> <VALUE>osx10.14</VALUE> </ATTRIBUTE> <ATTRIBUTE> <NAME>_platform</NAME> <VALUE>x86_64</VALUE> </ATTRIBUTE> <ATTRIBUTE> <NAME>_client_version</NAME> <VALUE>8.0.19</VALUE> </ATTRIBUTE> <ATTRIBUTE> <NAME>_client_name</NAME> <VALUE>libmysql</VALUE> </ATTRIBUTE> <ATTRIBUTE> <NAME>program_name</NAME> <VALUE>mysqladmin</VALUE> </ATTRIBUTE> </CONNECTION_ATTRIBUTES>
If no connection attributes are present in the event, none are logged and no
<CONNECTION_ATTRIBUTES>
element appears. This can occur if the connection attempt is unsucessful, the client passes no attributes, or the connection occurs internally such as during server startup or when initiated by a plugin. -
<CONNECTION_ID>
An unsigned integer representing the client connection identifier. This is the same as the value returned by the
CONNECTION_ID()
function within the session.Example:
<CONNECTION_ID>127</CONNECTION_ID>
-
<CONNECTION_TYPE>
The security state of the connection to the server. Permitted values are
TCP/IP
(TCP/IP connection established without encryption),SSL/TLS
(TCP/IP connection established with encryption),Socket
(Unix socket file connection),Named Pipe
(Windows named pipe connection), andShared Memory
(Windows shared memory connection).Example:
<CONNECTION_TYPE>SSL/TLS</CONNECTION_TYPE>
-
<DB>
A string representing the default database name.
Example:
<DB>test</DB>
-
<HOST>
A string representing the client host name.
Example:
<HOST>localhost</HOST>
-
<IP>
A string representing the client IP address.
Example:
<IP>127.0.0.1</IP>
-
<MYSQL_VERSION>
A string representing the MySQL server version. This is the same as the value of the
VERSION()
function orversion
system variable.Example:
<MYSQL_VERSION>5.7.21-log</MYSQL_VERSION>
-
<OS_LOGIN>
A string representing the external user name used during the authentication process, as set by the plugin used to authenticate the client. With native (built-in) MySQL authentication, or if the plugin does not set the value, this element is empty. The value is the same as that of the
external_user
system variable (see Section 6.2.18, “Proxy Users”).Example:
<OS_LOGIN>jeffrey</OS_LOGIN>
-
<OS_VERSION>
A string representing the operating system on which the server was built or is running.
Example:
<OS_VERSION>x86_64-Linux</OS_VERSION>
-
<PRIV_USER>
A string representing the user that the server authenticated the client as. This is the user name that the server uses for privilege checking, and may differ from the
<USER>
value.Example:
<PRIV_USER>jeffrey</PRIV_USER>
-
<PROXY_USER>
A string representing the proxy user (see Section 6.2.18, “Proxy Users”). The value is empty if user proxying is not in effect.
Example:
<PROXY_USER>developer</PROXY_USER>
-
<SERVER_ID>
An unsigned integer representing the server ID. This is the same as the value of the
server_id
system variable.Example:
<SERVER_ID>1</SERVER_ID>
-
<SQLTEXT>
A string representing the text of an SQL statement. The value can be empty. Long values may be truncated. The string, like the audit log file itself, is written using UTF-8 (up to 4 bytes per character), so the value may be the result of conversion. For example, the original statement might have been received from the client as an SJIS string.
Example:
<SQLTEXT>DELETE FROM t1</SQLTEXT>
-
<STARTUP_OPTIONS>
A string representing the options that were given on the command line or in option files when the MySQL server was started. The first option is the path to the server executable.
Example:
<STARTUP_OPTIONS>/usr/local/mysql/bin/mysqld --port=3306 --log_output=FILE</STARTUP_OPTIONS>
-
<STATUS>
An unsigned integer representing the command status: 0 for success, nonzero if an error occurred. This is the same as the value of the
mysql_errno()
C API function. See the description for<STATUS_CODE>
for information about how it differs from<STATUS>
.The audit log does not contain the SQLSTATE value or error message. To see the associations between error codes, SQLSTATE values, and messages, see Section B.3.1, “Server Error Message Reference”.
Warnings are not logged.
Example:
<STATUS>1051</STATUS>
-
<STATUS_CODE>
An unsigned integer representing the command status: 0 for success, 1 if an error occurred.
The
STATUS_CODE
value differs from theSTATUS
value:STATUS_CODE
is 0 for success and 1 for error, which is compatible with the EZ_collector consumer for Audit Vault.STATUS
is the value of themysql_errno()
C API function. This is 0 for success and nonzero for error, and thus is not necessarily 1 for error.Example:
<STATUS_CODE>0</STATUS_CODE>
-
<TABLE>
A string representing a table name.
Example:
<TABLE>t3</TABLE>
-
<USER>
A string representing the user name sent by the client. This may differ from the
<PRIV_USER>
value.Example:
<USER>root[root] @ localhost [127.0.0.1]</USER>
-
<VERSION>
An unsigned integer representing the version of the audit log file format.
Example:
<VERSION>1</VERSION>
Here is a sample log file in old-style XML format (audit_log_format=OLD
), reformatted slightly for readability:
<?xml version="1.0" encoding="utf-8"?> <AUDIT> <AUDIT_RECORD TIMESTAMP="2019-10-03T14:25:00 UTC" RECORD_ID="1_2019-10-03T14:25:00" NAME="Audit" SERVER_ID="1" VERSION="1" STARTUP_OPTIONS="--port=3306" OS_VERSION="i686-Linux" MYSQL_VERSION="5.7.21-log"/> <AUDIT_RECORD TIMESTAMP="2019-10-03T14:25:24 UTC" RECORD_ID="2_2019-10-03T14:25:00" NAME="Connect" CONNECTION_ID="4" STATUS="0" STATUS_CODE="0" USER="root" OS_LOGIN="" HOST="localhost" IP="127.0.0.1" COMMAND_CLASS="connect" CONNECTION_TYPE="SSL/TLS" PRIV_USER="root" PROXY_USER="" DB="test"/> ... <AUDIT_RECORD TIMESTAMP="2019-10-03T14:25:24 UTC" RECORD_ID="6_2019-10-03T14:25:00" NAME="Query" CONNECTION_ID="4" STATUS="0" STATUS_CODE="0" USER="root[root] @ localhost [127.0.0.1]" OS_LOGIN="" HOST="localhost" IP="127.0.0.1" COMMAND_CLASS="drop_table" SQLTEXT="DROP TABLE IF EXISTS t"/> ... <AUDIT_RECORD TIMESTAMP="2019-10-03T14:25:24 UTC" RECORD_ID="8_2019-10-03T14:25:00" NAME="Quit" CONNECTION_ID="4" STATUS="0" STATUS_CODE="0" USER="root" OS_LOGIN="" HOST="localhost" IP="127.0.0.1" COMMAND_CLASS="connect" CONNECTION_TYPE="SSL/TLS"/> <AUDIT_RECORD TIMESTAMP="2019-10-03T14:25:32 UTC" RECORD_ID="12_2019-10-03T14:25:00" NAME="NoAudit" SERVER_ID="1"/> </AUDIT>
The audit log file is written as XML, using UTF-8 (up to 4 bytes per character). The root element is <AUDIT>
. The root element contains <AUDIT_RECORD>
elements, each of which provides information about an audited event. When the audit log plugin begins writing a new log file, it writes the XML declaration and opening <AUDIT>
root element tag. When the plugin closes a log file, it writes the closing </AUDIT>
root element tag. The closing tag is not present while the file is open.
Attributes of <AUDIT_RECORD>
elements have these characteristics:
-
Some attributes appear in every
<AUDIT_RECORD>
element. Others are optional and may appear depending on the audit record type. -
Order of attributes within an
<AUDIT_RECORD>
element is not guaranteed. -
Attribute values are not fixed length. Long values may be truncated as indicated in the attribute descriptions given later.
-
The
<
,>
,"
, and&
characters are encoded as<
,>
,"
, and&
, respectively. NUL bytes (U+00) are encoded as the?
character. -
Characters not valid as XML characters are encoded using numeric character references. Valid XML characters are:
#x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
The following attributes are mandatory in every <AUDIT_RECORD>
element:
-
NAME
A string representing the type of instruction that generated the audit event, such as a command that the server received from a client.
Example:
NAME="Query"
Some common
NAME
values:Audit When auditing starts, which may be server startup time Connect When a client connects, also known as logging in Query An SQL statement (executed directly) Prepare Preparation of an SQL statement; usually followed by Execute Execute Execution of an SQL statement; usually follows Prepare Shutdown Server shutdown Quit When a client disconnects NoAudit Auditing has been turned off
The possible values are
Audit
,Binlog Dump
,Change user
,Close stmt
,Connect Out
,Connect
,Create DB
,Daemon
,Debug
,Delayed insert
,Drop DB
,Execute
,Fetch
,Field List
,Init DB
,Kill
,Long Data
,NoAudit
,Ping
,Prepare
,Processlist
,Query
,Quit
,Refresh
,Register Slave
,Reset stmt
,Set option
,Shutdown
,Sleep
,Statistics
,Table Dump
,TableDelete
,TableInsert
,TableRead
,TableUpdate
,Time
.Many of these values correspond to the
COM_
command values listed in thexxx
my_command.h
header file. For example,"Create DB"
and"Change user"
correspond toCOM_CREATE_DB
andCOM_CHANGE_USER
, respectively.Events having
NAME
values ofTable
accompanyXXX
Query
events. For example, the following statement generates oneQuery
event, twoTableRead
events, and aTableInsert
events:INSERT INTO t3 SELECT t1.* FROM t1 JOIN t2;
Each
Table
event hasXXX
DB
andTABLE
attributes to identify the table to which the event refers.Connect
events for old-style XML audit log format do not include connection attributes. -
RECORD_ID
A unique identifier for the audit record. The value is composed from a sequence number and timestamp, in the format
. When the audit log plugin opens the audit log file, it initializes the sequence number to the size of the audit log file, then increments the sequence by 1 for each record logged. The timestamp is a UTC value inSEQ_TIMESTAMP
format indicating the date and time when the audit log plugin opened the file.YYYY-MM-DD
Thh:mm:ss
Example:
RECORD_ID="12_2019-10-03T14:25:00"
-
TIMESTAMP
A string representing a UTC value in
format indicating the date and time when the audit event was generated. For example, the event corresponding to execution of an SQL statement received from a client has aYYYY-MM-DD
Thh:mm:ss
UTCTIMESTAMP
value occurring after the statement finishes, not when it was received.Example:
TIMESTAMP="2019-10-03T14:25:32 UTC"
The following attributes are optional in <AUDIT_RECORD>
elements. Many of them occur only for elements with specific values of the NAME
attribute.
-
COMMAND_CLASS
A string that indicates the type of action performed.
Example:
COMMAND_CLASS="drop_table"
The values correspond to the
statement/sql/
command counters. For example,xxx
xxx
isdrop_table
andselect
forDROP TABLE
andSELECT
statements, respectively. The following statement displays the possible names:SELECT REPLACE(EVENT_NAME, 'statement/sql/', '') AS name FROM performance_schema.events_statements_summary_global_by_event_name WHERE EVENT_NAME LIKE 'statement/sql/%' ORDER BY name;
-
CONNECTION_ID
An unsigned integer representing the client connection identifier. This is the same as the value returned by the
CONNECTION_ID()
function within the session.Example:
CONNECTION_ID="127"
-
CONNECTION_TYPE
The security state of the connection to the server. Permitted values are
TCP/IP
(TCP/IP connection established without encryption),SSL/TLS
(TCP/IP connection established with encryption),Socket
(Unix socket file connection),Named Pipe
(Windows named pipe connection), andShared Memory
(Windows shared memory connection).Example:
CONNECTION_TYPE="SSL/TLS"
-
DB
A string representing the default database name.
Example:
DB="test"
-
HOST
A string representing the client host name.
Example:
HOST="localhost"
-
IP
A string representing the client IP address.
Example:
IP="127.0.0.1"
-
MYSQL_VERSION
A string representing the MySQL server version. This is the same as the value of the
VERSION()
function orversion
system variable.Example:
MYSQL_VERSION="5.7.21-log"
-
OS_LOGIN
A string representing the external user name used during the authentication process, as set by the plugin used to authenticate the client. With native (built-in) MySQL authentication, or if the plugin does not set the value, this attribute is empty. The value is the same as that of the
external_user
system variable (see Section 6.2.18, “Proxy Users”).Example:
OS_LOGIN="jeffrey"
-
OS_VERSION
A string representing the operating system on which the server was built or is running.
Example:
OS_VERSION="x86_64-Linux"
-
PRIV_USER
A string representing the user that the server authenticated the client as. This is the user name that the server uses for privilege checking, and it may differ from the
USER
value.Example:
PRIV_USER="jeffrey"
-
PROXY_USER
A string representing the proxy user (see Section 6.2.18, “Proxy Users”). The value is empty if user proxying is not in effect.
Example:
PROXY_USER="developer"
-
SERVER_ID
An unsigned integer representing the server ID. This is the same as the value of the
server_id
system variable.Example:
SERVER_ID="1"
-
SQLTEXT
A string representing the text of an SQL statement. The value can be empty. Long values may be truncated. The string, like the audit log file itself, is written using UTF-8 (up to 4 bytes per character), so the value may be the result of conversion. For example, the original statement might have been received from the client as an SJIS string.
Example:
SQLTEXT="DELETE FROM t1"
-
STARTUP_OPTIONS
A string representing the options that were given on the command line or in option files when the MySQL server was started.
Example:
STARTUP_OPTIONS="--port=3306 --log_output=FILE"
-
STATUS
An unsigned integer representing the command status: 0 for success, nonzero if an error occurred. This is the same as the value of the
mysql_errno()
C API function. See the description forSTATUS_CODE
for information about how it differs fromSTATUS
.The audit log does not contain the SQLSTATE value or error message. To see the associations between error codes, SQLSTATE values, and messages, see Section B.3.1, “Server Error Message Reference”.
Warnings are not logged.
Example:
STATUS="1051"
-
STATUS_CODE
An unsigned integer representing the command status: 0 for success, 1 if an error occurred.
The
STATUS_CODE
value differs from theSTATUS
value:STATUS_CODE
is 0 for success and 1 for error, which is compatible with the EZ_collector consumer for Audit Vault.STATUS
is the value of themysql_errno()
C API function. This is 0 for success and nonzero for error, and thus is not necessarily 1 for error.Example:
STATUS_CODE="0"
-
TABLE
A string representing a table name.
Example:
TABLE="t3"
-
USER
A string representing the user name sent by the client. This may differ from the
PRIV_USER
value. -
VERSION
An unsigned integer representing the version of the audit log file format.
Example:
VERSION="1"
For JSON-format audit logging (audit_log_format=JSON
), the log file contents form a JSON
array with each array element representing an audited event as a JSON
hash of key-value pairs. Examples of complete event records appear later in this section. The following is an excerpt of partial events:
[ { "timestamp": "2019-10-03 13:50:01", "id": 0, "class": "audit", "event": "startup", ... }, { "timestamp": "2019-10-03 15:02:32", "id": 0, "class": "connection", "event": "connect", ... }, ... { "timestamp": "2019-10-03 17:37:26", "id": 0, "class": "table_access", "event": "insert", ... } ... ]
The audit log file is written using UTF-8 (up to 4 bytes per character). When the audit log plugin begins writing a new log file, it writes the opening [
array marker. When the plugin closes a log file, it writes the closing ]
array marker. The closing marker is not present while the file is open.
Items within audit records have these characteristics:
-
Some items appear in every audit record. Others are optional and may appear depending on the audit record type.
-
Order of items within an audit record is not guaranteed.
-
Item values are not fixed length. Long values may be truncated as indicated in the item descriptions given later.
-
The
"
and\
characters are encoded as\"
and\\
, respectively.
The following examples show the JSON object formats for different event types (as indicated by the class
and event
items), reformatted slightly for readability:
Auditing startup event:
{ "timestamp": "2019-10-03 14:21:56", "id": 0, "class": "audit", "event": "startup", "connection_id": 0, "startup_data": { "server_id": 1, "os_version": "i686-Linux", "mysql_version": "5.7.21-log", "args": ["/usr/local/mysql/bin/mysqld", "--loose-audit-log-format=JSON", "--log-error=log.err", "--pid-file=mysqld.pid", "--port=3306" ] } }
When the audit log plugin starts as a result of server startup (as opposed to being enabled at runtime), connection_id
is set to 0, and account
and login
are not present.
Auditing shutdown event:
{ "timestamp": "2019-10-03 14:28:20", "id": 3, "class": "audit", "event": "shutdown", "connection_id": 0, "shutdown_data": { "server_id": 1 } }
When the audit log plugin is uninstalled as a result of server shutdown (as opposed to being disabled at runtime), connection_id
is set to 0, and account
and login
are not present.
Connect or change-user event:
{ "timestamp": "2019-10-03 14:23:18", "id": 1, "class": "connection", "event": "connect", "connection_id": 5, "account": { "user": "root", "host": "localhost" }, "login": { "user": "root", "os": "", "ip": "::1", "proxy": "" }, "connection_data": { "connection_type": "ssl", "status": 0, "db": "test", "connection_attributes": { "_pid": "43236", ... "program_name": "mysqladmin" } } }
Disconnect event:
{ "timestamp": "2019-10-03 14:24:45", "id": 3, "class": "connection", "event": "disconnect", "connection_id": 5, "account": { "user": "root", "host": "localhost" }, "login": { "user": "root", "os": "", "ip": "::1", "proxy": "" }, "connection_data": { "connection_type": "ssl" } }
Query event:
{ "timestamp": "2019-10-03 14:23:35", "id": 2, "class": "general", "event": "status", "connection_id": 5, "account": { "user": "root", "host": "localhost" }, "login": { "user": "root", "os": "", "ip": "::1", "proxy": "" }, "general_data": { "command": "Query", "sql_command": "show_variables", "query": "SHOW VARIABLES", "status": 0 } }
Table access event (read, delete, insert, update):
{ "timestamp": "2019-10-03 14:23:41", "id": 0, "class": "table_access", "event": "insert", "connection_id": 5, "account": { "user": "root", "host": "localhost" }, "login": { "user": "root", "os": "", "ip": "127.0.0.1", "proxy": "" }, "table_access_data": { "db": "test", "table": "t1", "query": "INSERT INTO t1 (i) VALUES(1),(2),(3)", "sql_command": "insert" } }
The items in the following list appear at the top level of JSON-format audit records: Each item value is either a scalar or a JSON
hash. For items that have a hash value, the description lists only the item names within that hash. For more complete descriptions of second-level hash items, see later in this section.
-
account
The MySQL account associated with the event. The value is a hash containing these items equivalent to the value of the
CURRENT_USER()
function within the section:user
,host
.Example:
"account": { "user": "root", "host": "localhost" }
-
class
A string representing the event class. The class defines the type of event, when taken together with the
event
item that specifies the event subclass.Example:
"class": "connection"
The following table shows the permitted combinations of
class
andevent
values.Table 6.28 Audit Log Class and Event Combinations
Class Value Permitted Event Values audit
startup
,shutdown
connection
connect
,change_user
,disconnect
general
status
table_access_data
read
,delete
,insert
,update
-
connection_data
Information about a client connection. The value is a hash containing these items:
connection_type
,status
,db
, and possiblyconnection_attributes
. This item occurs only for audit records with aclass
value ofconnection
.Example:
"connection_data": { "connection_type": "ssl", "status": 0, "db": "test" }
As of MySQL 8.0.19, events with a
class
value ofconnection
andevent
value ofconnect
may include aconnection_attributes
item to display the connection attributes passed by the client at connect time. (For information about these attributes, which are also exposed in Performance Schema tables, see Section 26.12.9, “Performance Schema Connection Attribute Tables”.)The
connection_attributes
value is a hash that represents each attribute by its name and value.Example:
"connection_attributes": { "_pid": "43236", "_os": "osx10.14", "_platform": "x86_64", "_client_version": "8.0.19", "_client_name": "libmysql", "program_name": "mysqladmin" }
If no connection attributes are present in the event, none are logged and no
connection_attributes
item appears. This can occur if the connection attempt is unsucessful, the client passes no attributes, or the connection occurs internally such as during server startup or when initiated by a plugin. -
connection_id
An unsigned integer representing the client connection identifier. This is the same as the value returned by the
CONNECTION_ID()
function within the session.Example:
"connection_id": 5
-
event
A string representing the subclass of the event class. The subclass defines the type of event, when taken together with the
class
item that specifies the event class. For more information, see theclass
item description.Example:
"event": "connect"
-
general_data
Information about an executed statement or command. The value is a hash containing these items:
command
,sql_command
,query
,status
. This item occurs only for audit records with aclass
value ofgeneral
.Example:
"general_data": { "command": "Query", "sql_command": "show_variables", "query": "SHOW VARIABLES", "status": 0 }
-
id
An unsigned integer representing an event ID.
Example:
"id": 2
For audit records that have the same
timestamp
value, theirid
values distinguish them and form a sequence. Within the audit log,timestamp
/id
pairs are unique. These pairs are bookmarks that identify event locations within the log. -
login
Information indicating how a client connected to the server. The value is a hash containing these items:
user
,os
,ip
,proxy
.Example:
"login": { "user": "root", "os": "", "ip": "::1", "proxy": "" }
-
shutdown_data
Information pertaining to audit log plugin termination. The value is a hash containing these items:
server_id
This item occurs only for audit records withclass
andevent
values ofaudit
andshutdown
, respectively.Example:
"shutdown_data": { "server_id": 1 }
-
startup_data
Information pertaining to audit log plugin initialization. The value is a hash containing these items:
server_id
,os_version
,mysql_version
,args
. This item occurs only for audit records withclass
andevent
values ofaudit
andstartup
, respectively.Example:
"startup_data": { "server_id": 1, "os_version": "i686-Linux", "mysql_version": "5.7.21-log", "args": ["/usr/local/mysql/bin/mysqld", "--loose-audit-log-format=JSON", "--log-error=log.err", "--pid-file=mysqld.pid", "--port=3306" ] }
-
table_access_data
Information about an access to a table. The value is a hash containing these items:
db
,table
,query
,sql_command
, This item occurs only for audit records with aclass
value oftable_access
.Example:
"table_access_data": { "db": "test", "table": "t1", "query": "INSERT INTO t1 (i) VALUES(1),(2),(3)", "sql_command": "insert" }
-
timestamp
A string representing a UTC value in
YYYY-MM-DD hh:mm:ss
format indicating the date and time when the audit event was generated. For example, the event corresponding to execution of an SQL statement received from a client has atimestamp
value occurring after the statement finishes, not when it was received.Example:
"timestamp": "2019-10-03 13:50:01"
For audit records that have the same
timestamp
value, theirid
values distinguish them and form a sequence. Within the audit log,timestamp
/id
pairs are unique. These pairs are bookmarks that identify event locations within the log.
These items appear within hash values associated with top-level items of JSON-format audit records:
-
args
An array of options that were given on the command line or in option files when the MySQL server was started. The first option is the path to the server executable.
Example:
"args": ["/usr/local/mysql/bin/mysqld", "--loose-audit-log-format=JSON", "--log-error=log.err", "--pid-file=mysqld.pid", "--port=3306" ]
-
command
A string representing the type of instruction that generated the audit event, such as a command that the server received from a client.
Example:
"command": "Query"
-
connection_type
The security state of the connection to the server. Permitted values are
tcp/ip
(TCP/IP connection established without encryption),ssl
(TCP/IP connection established with encryption),socket
(Unix socket file connection),named_pipe
(Windows named pipe connection), andshared_memory
(Windows shared memory connection).Example:
"connection_type": "tcp/tcp"
-
db
A string representing a database name. For
connection_data
, it is the default database. Fortable_access_data
, it is the table database.Example:
"db": "test"
-
host
A string representing the client host name.
Example:
"host": "localhost"
-
ip
A string representing the client IP address.
Example:
"ip": "::1"
-
mysql_version
A string representing the MySQL server version. This is the same as the value of the
VERSION()
function orversion
system variable.Example:
"mysql_version": "5.7.21-log"
-
os
A string representing the external user name used during the authentication process, as set by the plugin used to authenticate the client. With native (built-in) MySQL authentication, or if the plugin does not set the value, this attribute is empty. The value is the same as that of the
external_user
system variable. See Section 6.2.18, “Proxy Users”.Example:
"os": "jeffrey"
-
os_version
A string representing the operating system on which the server was built or is running.
Example:
"os_version": "i686-Linux"
-
proxy
A string representing the proxy user (see Section 6.2.18, “Proxy Users”). The value is empty if user proxying is not in effect.
Example:
"proxy": "developer"
-
query
A string representing the text of an SQL statement. The value can be empty. Long values may be truncated. The string, like the audit log file itself, is written using UTF-8 (up to 4 bytes per character), so the value may be the result of conversion. For example, the original statement might have been received from the client as an SJIS string.
Example:
"query": "DELETE FROM t1"
-
server_id
An unsigned integer representing the server ID. This is the same as the value of the
server_id
system variable.Example:
"server_id": 1
-
sql_command
A string that indicates the SQL statement type.
Example:
"sql_command": "insert"
The values correspond to the
statement/sql/
command counters. For example,xxx
xxx
isdrop_table
andselect
forDROP TABLE
andSELECT
statements, respectively. The following statement displays the possible names:SELECT REPLACE(EVENT_NAME, 'statement/sql/', '') AS name FROM performance_schema.events_statements_summary_global_by_event_name WHERE EVENT_NAME LIKE 'statement/sql/%' ORDER BY name;
-
status
An unsigned integer representing the command status: 0 for success, nonzero if an error occurred. This is the same as the value of the
mysql_errno()
C API function.The audit log does not contain the SQLSTATE value or error message. To see the associations between error codes, SQLSTATE values, and messages, see Section B.3.1, “Server Error Message Reference”.
Warnings are not logged.
Example:
"status": 1051
-
table
A string representing a table name.
Example:
"table": "t1"
-
user
A string representing a user name. The meaning differs depending on the item within which
user
occurs:-
Within
account
items,user
is a string representing the user that the server authenticated the client as. This is the user name that the server uses for privilege checking. -
Within
login
items,user
is a string representing the user name sent by the client.
Example:
"user": "root"
-
This section describes how to configure audit logging characteristics, such as the file to which the audit log plugin writes events, the format of written events, and whether to enable log file compression and encryption.
Encryption capabilities described here apply as of MySQL 8.0.17, with the exception of the section that compares current encryption capabilities to the previous more-limited capabilities (see Audit Log File Encryption Prior to MySQL 8.0.17).
For additional information about the user-defined functions and system variables that affect audit logging, see Audit Log Functions, and Audit Log Options and Variables.
The audit log plugin can also control which audited events are written to the audit log file, based on event content or the account from which events originate. See Section 6.4.5.6, “Audit Log Filtering”.
To configure the audit log file name, set the audit_log_file
system variable at server startup. By default, the name is audit.log
in the server data directory. For security reasons, write the audit log file to a directory accessible only to the MySQL server and to users with a legitimate reason to view the log.
The plugin interprets the audit_log_file
value as composed of a base name and an optional suffix. If compression or encryption are enabled, the effective file name (the name actually used to create the log file) differs from the configured file name because it has additional suffixes:
-
If compression is enabled, the plugin adds a suffix of
.gz
. -
If encryption is enabled, the plugin adds a suffix of
.
, wherepwd_id
.encpwd_id
indicates which encryption password to use for log file operations.
The effective audit log file name is the name resulting from the addition of applicable compression and encryption suffixes to the configured file name. For example, if the configured audit_log_file
value is audit.log
, the effective file name is one of the values shown in the following table.
Enabled Features | Effective File Name |
---|---|
No compression or encryption | audit.log |
Compression | audit.log.gz |
Encryption | audit.log. |
Compression, encryption | audit.log.gz. |
pwd_id
indicates the ID of the password used to encrypt or decrypt a file. pwd_id
format is pwd_timestamp-seq
, where:
-
pwd_timestamp
is a UTC value in
format indicating when the password was created.YYYYMMDD
Thhmmss
-
seq
is a sequence number. Sequence numbers start at 1 and increase for passwords that have the samepwd_timestamp
value.
Here are some example password ID values:
20190403T142359-1 20190403T142400-1 20190403T142400-2
The audit log plugin stores encryption passwords in the keyring (see Section 6.4.4, “The MySQL Keyring”). The IDs of audit log passwords in the keyring are based on pwd_id
values, with a prefix of audit_log-
. For the example password IDs just shown, the corresponding keyring IDs are:
audit_log-20190403T142359-1 audit_log-20190403T142400-1 audit_log-20190403T142400-2
The password currently used for encryption by the audit log plugin is the one having the largest pwd_timestamp
value. If multiple passwords have the largest pwd_timestamp
value, the current password is the one with the largest sequence number. For example, in the preceding set of password IDs, two of them have the largest timestamp, 20190403T142400
, so the current password is the one with the largest sequence number (2).
The audit log plugin performs certain actions during initialization and termination based on the effective audit log file name:
-
During initialization, the plugin checks whether a file with the audit log file name already exists and renames it if so. (In this case, the plugin assumes that the previous server invocation exited unexpectedly with the audit log plugin running.) The plugin then writes to a new empty audit log file.
-
During termination, the plugin renames the audit log file.
-
File renaming (whether during plugin initialization or termination) occurs according to the usual rules for automatic log file rotation; see Automatic Audit Log File Rotation.
To configure the audit log file format, set the audit_log_format
system variable at server startup. By default, the format is NEW
(new-style XML format). For details about each format, see Section 6.4.5.4, “Audit Log File Formats”.
If you change audit_log_format
, it is recommended that you also change audit_log_file
. Otherwise, there will be two sets of log files with the same base name but different formats.
Audit log file compression can be enabled for any logging format.
To configure audit log file compression, set the audit_log_compression
system variable at server startup. Permitted values are NONE
(no compression; the default) and GZIP
(GNU Zip compression).
If both compression and encryption are enabled, compression occurs before encryption. To recover the original file manually, first decrypt it, then uncompress it. See Audit Log File Manual Uncompression and Decryption.
Audit log file encryption can be enabled for any logging format. Encryption is based on user-defined passwords (with the exception of the initial password that the audit log plugin generates). To use this feature, the MySQL keyring must be enabled because audit logging uses it for password storage. Any keyring plugin can be used; for instructions, see Section 6.4.4, “The MySQL Keyring”.
To configure audit log file encryption, set the audit_log_encryption
system variable at server startup. Permitted values are NONE
(no encryption; the default) and AES
(AES-256-CBC cipher encryption).
To set or get an encryption password, use these user-defined functions (UDFs):
-
To set the current encryption password, invoke
audit_log_encryption_password_set()
. This function stores the new password in the keyring, If encryption is enabled, it also performs a log file rotation operation that renames the current log file, and begins a new log file encrypted with the password. File renaming occurs according to the usual rules for automatic log file rotation; see Automatic Audit Log File Rotation. -
To get the current encryption password, invoke
audit_log_encryption_password_get()
with no argument. To get a password by ID, pass an argument specifying the keyring ID of the current password or an archived password.To determine which audit log keyring IDs exist, query the Performance Schema
keyring_keys
table:SELECT * FROM performance_schema.keyring_keys WHERE KEY_ID LIKE 'audit_log%' ORDER BY KEY_ID;
For additional information about audit log encryption functions, see Audit Log Functions.
When the audit log plugin initializes, if it finds that log file encryption is enabled, it checks whether the keyring contains an audit log encryption password. If not, the plugin automatically generates a random initial encryption password and stores it in the keyring. To discover this password, invoke audit_log_encryption_password_get()
.
If both compression and encryption are enabled, compression occurs before encryption. To recover the original file manually, first decrypt it, then uncompress it. See Audit Log File Manual Uncompression and Decryption.
Audit log files can be uncompressed and decrypted using standard tools. This should be done only for log files that have been closed (archived) and are no longer in use, not for the log file that the audit log plugin is currently writing. You can recognize archived log files because they have been renamed by the audit log plugin to include a timestamp in the file name just after the base name.
For this discussion, assume that audit_log_file
is set to audit.log
. In that case, an archived audit log file has one of the names shown in the following table.
Enabled Features | Archived File Name |
---|---|
No compression or encryption | audit. |
Compression | audit. |
Encryption | audit. |
Compression, encryption | audit. |
As discussed in Audit Log File Name, pwd_id
format is pwd_timestamp-seq
. Thus, the names of archived encrypted log files actually contain two timestamps. The first indicates rotation time, and the second indicates when the password was created.
Consider the following set of archived encrypted log file names:
audit.20190410T205827.log.20190403T185337-1.enc audit.20190410T210243.log.20190403T185337-1.enc audit.20190415T145309.log.20190414T223342-1.enc audit.20190415T151322.log.20190414T223342-2.enc
Each file name has a unique rotation-time timestamp. By contrast, the password timestamps are not unique:
-
The first two files have the same password ID and sequence number (
20190403T185337-1
). They have the same encryption password. -
The second two files have the same paswword ID (
20190414T223342
) but different sequence numbers (1
,2
). These files have different encryption passwords.
To uncompress a compressed log file manually, use gunzip, gzip -d, or equivalent command. For example:
timestamp timestamp
To decrypt an encrypted log file manually, use the openssl command. For example:
password timestamp pwd_id timestamp
If both compression and encryption are enabled for audit logging, compression occurs before encryption. In this case, the file name has .gz
and .
suffixes added, corresponding to the order in which those operations occur. To recover the original file manually, perform the operations in reverse. That is, first decrypt the file, then uncompress it:pwd_id
.enc
password timestamp pwd_id timestamp timestamp timestamp
This section covers the differences in audit log file encryption capabilities prior to and as of MySQL 8.0.17, which is when password archiving and expiration were implemented. It also indicates how the audit log plugin handles upgrades to MySQL 8.0.17 or higher from versions lower than 8.0.17.
Feature | Prior to MySQL 8.0.17 | As of MySQL 8.0.17 |
---|---|---|
Number of passwords | Single password only | Multiple passwords permitted |
Encrypted log file names | .enc suffix |
. suffix |
Password keyring ID | audit_log |
audit_log- |
Password history | No | Yes |
Password expiration | No | Yes |
Prior to MySQL 8.0.17, there is no password history, so setting a new password makes the old password inaccessible, rendering MySQL Enterprise Audit unable to read log files encrypted with the old password. You must keep a record of the previous password should you need to decrypt those files manually.
If audit log file encryption is enabled when you upgrade to MySQL 8.0.17 or higher from a lower version, the audit log plugin performs these upgrade actions:
-
During plugin initialization, the plugin checks for an encryption password with a keyring ID of
audit_log
. If it finds one, the plugin duplicates the password using a keyring ID inaudit_log-
format and uses it as the current encryption password.pwd_id
-
Existing encrypted log files have a suffix of
.enc
. The plugin does not rename these to have a suffix of.
, but can read them as long as the key with the ID ofpwd_id
.encaudit_log
remains in the keyring. -
When password cleanup occurs, if the plugin expires any password with a keyring ID in
audit_log-
format, it also expires the password with a keyring ID ofpwd_id
audit_log
, if it exists. (At this point, encrypted log files that have a suffix of.enc
rather than.
become unreadable by the plugin, so it is assumed that you no longer need them.)pwd_id
.enc
The audit log file has the potential to grow very large and consume a lot of disk space. To enable management of the space used by its log files, the audit log plugin provides for log file rotation, either manually or automatically. Rotation capabilities use the audit_log_flush
and audit_log_rotate_on_size
system variables:
-
By default,
audit_log_rotate_on_size=0
and no log rotation occurs unless performed manually. In this case, useaudit_log_flush
to close and reopen the current log file after manually renaming it. -
If
audit_log_rotate_on_size
is greater than 0, automatic rotation occurs when a write to the current log file causes its size to exceed this value. The audit log plugin closes the file, renames it, and opens a new log file. With automatic rotation enabled,audit_log_flush
has no effect. -
Automatic rotation also occurs under several other conditions, described later.
Renamed log files are not removed automatically. For example, with size-based log file rotation, renamed log files do not rotate off the end of the name sequence. Instead, they have unique names and accumulate indefinitely. To avoid excessive space use, remove old files periodically, backing them up first as necessary. If backed-up log files are encrypted, also back up the corresponding encryption passwords to a safe place, should you need to decrypt the files later.
The following discussion describes log file rotation methods in greater detail.
Manual Audit Log File Rotation
If audit_log_rotate_on_size=0
(the default), no log rotation occurs unless performed manually. In this case, the audit log plugin closes and reopens the log file when the audit_log_flush
value changes from disabled to enabled. Log file renaming must be done externally to the server. Suppose that the log file name is audit.log
and you want to maintain the three most recent log files, cycling through the names audit.log.1
through audit.log.3
. On Unix, perform rotation manually like this:
-
From the command line, rename the current log files:
mv audit.log.2 audit.log.3 mv audit.log.1 audit.log.2 mv audit.log audit.log.1
This strategy overwrites the current
audit.log.3
contents, placing a bound on the number of archived log files and the space they use. -
At this point, the plugin is still writing to the current log file, which has been renamed to
audit.log.1
. Connect to the server and flush the log file so the plugin closes it and reopens a newaudit.log
file:SET GLOBAL audit_log_flush = ON;
audit_log_flush
is special in that its value remainsOFF
so that you need not disable it explicitly before enabling it again to perform another flush.
If compression or encryption are enabled, log file names include suffixes that signify the enabled features, as well as a password ID if encryption is enabled. If file names include a password ID, be sure to retain the ID in the name of any files you rename manually so that the password to use for decryption operations can be determined.
For JSON-format logging, renaming audit log files manually makes them unavailable to the log-reading functions because the audit log plugin no longer can determine that they are part of the log file sequence (see Audit Log File Reading). Consider setting audit_log_rotate_on_size
greater than 0 to use size-based rotation instead.
Automatic Audit Log File Rotation
If audit_log_rotate_on_size
is greater than 0, setting audit_log_flush
has no effect. Instead, whenever a write to the current log file causes its size to exceed the audit_log_rotate_on_size
value, the audit log plugin closes the file, renames it, and opens a new log file.
Automatic rotation also occurs under these conditions:
-
During plugin initialization, if a file with the audit log file name already exists (see Audit Log File Name).
-
During plugin termination.
-
When the
audit_log_encryption_password_set()
function is called to set the encryption password, if encryption is enabled. (Rotation does not occur if encryption is disabled.)
The plugin renames the original file by inserting a timestamp just after its base name. For example, if the file name is audit.log
, the plugin renames it to a value such as audit.20190115T140633.log
. The timestamp is a UTC value in
format. The timestamp indicates rotation time for XML logging, and the timestamp of the last event written to the file for JSON logging.YYYYMMDD
Thhmmss
The audit log plugin can use any of several strategies for log writes. Regardless of strategy, logging occurs on a best-effort basis, with no guarantee of consistency.
To specify a write strategy, set the audit_log_strategy
system variable at server startup. By default, the strategy value is ASYNCHRONOUS
and the plugin logs asynchronously to a buffer, waiting if the buffer is full. It's possible to tell the plugin not to wait (PERFORMANCE
) or to log synchronously, either using file system caching (SEMISYNCHRONOUS
) or forcing output with a sync()
call after each write request (SYNCHRONOUS
).
For asynchronous write strategy, the audit_log_buffer_size
system variable is the buffer size in bytes. Set this variable at server startup to change the buffer size. The plugin uses a single buffer, which it allocates when it initializes and removes when it terminates. The plugin does not allocate this buffer for nonasynchronous write strategies.
Asynchronous logging strategy has these characteristics:
-
Minimal impact on server performance and scalability.
-
Blocking of threads that generate audit events for the shortest possible time; that is, time to allocate the buffer plus time to copy the event to the buffer.
-
Output goes to the buffer. A separate thread handles writes from the buffer to the log file.
With asynchronous logging, the integrity of the log file may be compromised if a problem occurs during a write to the file or if the plugin does not shut down cleanly (for example, in the event that the server host exits unexpectedly). To reduce this risk, set audit_log_strategy
to use synchronous logging.
A disadvantage of PERFORMANCE
strategy is that it drops events when the buffer is full. For a heavily loaded server, the audit log may have events missing.
The audit log plugin enables bookmarking and reading of JSON-format audit log files. (These capabilities do not apply to files written in other log formats.)
When the audit log plugin initializes and is configured for JSON logging, it uses the directory containing the audit log file (determined from the audit_log_file
value) as the location to search for readable audit log files. To do this, it uses the value of audit_log_file
to determine the file base name and suffix values, then looks for files with names that match the following pattern, where [...]
indicates optional file name parts:
basename timestamp suffix pwd_id
A file is encrypted if its name ends with .enc
. The plugin determines the keyring ID of the decryption password needed to read it as follows:
-
If
.enc
is preceded bypwd_id
, the keyring ID isaudit_log-
.pwd_id
-
If
.enc
is not preceded bypwd_id
, the file has an old name from before password history was implemented. The keyring ID isaudit_log
.
The plugin opens each file matching the pattern, checks that the file really contains JSON audit records, and sorts the files using the timestamps from the first record of each file to construct a list of files that are subject to use with the log-reading functions.
The plugin cannot include in the sequence files that were renamed manually and do not match the preceding pattern, or that were encrypted with a password no longer available in the keyring.
To read events from the audit log, use these user-defined functions (UDFs):
-
audit_log_read_bookmark()
returns aJSON
string representing a bookmark for the most recently written audit log event. This bookmark is suitable for passing toaudit_log_read()
to indicate to that function where to begin reading. Example bookmark:{ "timestamp": "2019-10-03 21:03:44", "id": 0 }
-
audit_log_read()
reads events from the audit log and returns aJSON
string containing an array of audit events.
Example audit_log_read()
invocation using the current bookmark:
mysql> SELECT audit_log_read(audit_log_read_bookmark());
+-----------------------------------------------------------------------+
| audit_log_read(audit_log_read_bookmark()) |
+-----------------------------------------------------------------------+
| [ {"timestamp":"2019-10-03 22:41:24","id":0,"class":"connection", ... |
+-----------------------------------------------------------------------+
Each event in the audit_log_read()
return value is a JSON
hash, except that the last array element may be a JSON
null
value to indicate no following events are available to read. For example:
[ { "timestamp": "2019-10-03 22:08:08", "id": 10, "class": "general", "event": "status", ... }, { "timestamp": "2019-10-03 22:08:08", "id": 11, "class": "connection", "event": "disconnect", ... }, { "timestamp": "2019-10-03 13:39:33", "id": 0, "class": "connection", "event": "connect", ... }, { "timestamp": "2019-10-03 13:39:33", "id": 1, "class": "general", "event": "status", ... }, { "timestamp": "2019-10-03 13:39:33", "id": 2, "class": "connection", "event": "disconnect", ... }, null ]
Use audit_log_read()
like this:
-
For the first call to
audit_log_read()
within a session, pass a bookmark indicating where to begin reading. -
If the final value of the returned array is not a
JSON
null
value, there are more events following those just read andaudit_log_read()
can be called without or with a bookmark argument. Without an argument, reading continues with the next unread event. With a bookmark argument, reading continues from the bookmark. -
If the final value of the returned array is a
JSON
null
value, there are no more events left to be read and the next call toaudit_log_read()
must include a bookmark argument.
A bookmark is a JSON
hash that indicates where and how much to read. The following items are significant in the bookmark value (other items are ignored):
-
timestamp
,id
: The location within the audit log of the first event to read. Both items must be present to completely specify a position. -
max_array_length
: The maximum number of events to read from the log. If omitted, the default is to read to the end of the log or until the read buffer is full, whichever comes first.
The result returned from either log-reading function is a string, which can be manipulated as necessary. Suppose that a bookmark has this value:
SET @mark := audit_log_read_bookmark(); SELECT @mark;
Calling audit_log_read()
with that bookmark can return multiple events. To limit audit_log_read()
to reading a single event, add to the bookmark a max_array_length
item with a value of 1. For example, convert the preceding bookmark as follows:
SET @mark := JSON_SET(@mark, '$.max_array_length', 1); SELECT @mark;
The modified bookmark, when passed to audit_log_read()
, produces a result of a single audit record.
Prior to MySQL 8.0.19, string return values from audit log UDFs are binary strings. To use a binary string with functions that require a nonbinary string (such as functions that manipulate JSON
values), perform a conversion to utf8mb4
. For example, before passing the bookmark to JSON_SET()
, convert it as follows:
SET @mark = CONVERT(@mark USING utf8mb4);
That statement can be included even for MySQL 8.0.19 and higher because for those versions it is essentially a no-op and is harmless.
To set a limit on the number of bytes that audit_log_read()
reads, set the audit_log_read_buffer_size
system variable. As of MySQL 8.0.12, this variable has a default of 32KB and can be set at runtime. Each client should set its session value of audit_log_read_buffer_size
appropriately for its use of audit_log_read()
. Prior to MySQL 8.0.12, audit_log_read_buffer_size
has a default of 1MB, affects all clients, and can be changed only at server startup.
Each call to audit_log_read()
returns as many available items as fit within the buffer size, skipping items that do not fit within the buffer size. Given this behavior, consider these factors when assessing the proper buffer size for an application:
-
There is a tradeoff between number of calls to
audit_log_read()
and items returned per call. With a smaller buffer size, calls return fewer items, so more calls are needed. With a larger buffer size, calls return more items, so fewer calls are needed. -
With a smaller buffer size, such as the default size of 32KB, there is a greater chance that items will exceed the buffer size and
audit_log_read()
will skip them. Skipped items generate warnings.
For additional information about audit log-reading functions, see Audit Log Functions.
This section describes how audit log filtering works if the audit log plugin and the accompanying audit tables and UDFs are installed. If the plugin is installed but not the accompanying audit tables and UDFs, the plugin operates in legacy filtering mode, described in Section 6.4.5.8, “Legacy Mode Audit Log Filtering”. Legacy mode is filtering behavior as it was prior to MySQL 5.7.13; that is, before the introduction of rule-based filtering.
The audit log plugin has the capability of controlling logging of audited events by filtering them:
-
Audited events can be filtered using these characteristics:
-
User account
-
Audit event class
-
Audit event subclass
-
Value of event fields such as those that indicate operation status or SQL statement executed
-
-
Audit filtering is rule based:
-
A filter definition creates a set of auditing rules. Definitions can be configured to include or exclude events for logging based on the characteristics just described.
-
Filter rules have the capability of blocking (aborting) execution of qualifying events, in addition to existing capabilities for event logging.
-
Multiple filters can be defined, and any given filter can be assigned to any number of user accounts.
-
It is possible to define a default filter to use with any user account that has no explicitly assigned filter.
-
-
Audit filters can be defined, displayed, and modified using an SQL interface based on user-defined functions (UDFs).
-
Audit filter definitions are stored in the tables in the
mysql
system database. -
Within a given session, the value of the read-only
audit_log_filter_id
system variable indicates whether a filter has been assigned to the session.
By default, rule-based audit log filtering logs no auditable events for any users. To log all auditable events for all users, use the following statements, which create a simple filter to enable logging and assign it to the default account:
SELECT audit_log_filter_set_filter('log_all', '{ "filter": { "log": true } }'); SELECT audit_log_filter_set_user('%', 'log_all');
The filter assigned to %
is used for connections from any account that has no explicitly assigned filter (which initially is true for all accounts).
The following list briefly summarizes the UDFs that implement the SQL interface for audit filtering control:
-
audit_log_filter_set_filter()
: Define a filter -
audit_log_filter_remove_filter()
: Remove a filter -
audit_log_filter_set_user()
: Start filtering a user account -
audit_log_filter_remove_user()
: Stop filtering a user account -
audit_log_filter_flush()
: Flush manual changes to the filter tables to affect ongoing filtering
For usage examples and complete details about the filtering functions, see Using Audit Log Filtering Functions, and Audit Log Functions.
Audit log filtering functions are subject to these constraints:
-
To use any filtering function, the
audit_log
plugin must be enabled or an error occurs. In addition, the audit tables must exist or an error occurs. To install theaudit_log
plugin and its accompanying UDFs and tables, see Section 6.4.5.2, “Installing or Uninstalling MySQL Enterprise Audit”. -
To use any filtering function, a user must possess the
SUPER
privilege or an error occurs. To grant theSUPER
privilege to a user account, use this statement:GRANT SUPER ON *.* TO
user
;Alternatively, should you prefer to avoid granting the
SUPER
privilege while still permitting users to access specific filtering functions, “wrapper” stored programs can be defined. This technique is described in the context of keyring UDFs in Using General-Purpose Keyring Functions; it can be adapted for use with filtering UDFs. -
The
audit_log
plugin operates in legacy mode if it is installed but the accompanying audit tables and functions are not created. The plugin writes these messages to the error log at server startup:[Warning] Plugin audit_log reported: 'Failed to open the audit log filter tables.' [Warning] Plugin audit_log reported: 'Audit Log plugin supports a filtering, which has not been installed yet. Audit Log plugin will run in the legacy mode, which will be disabled in the next release.'
In legacy mode, filtering can be done based only on event account or status. For details, see Section 6.4.5.8, “Legacy Mode Audit Log Filtering”.
Before using the audit log user-defined functions (UDFs), install them according to the instructions provided in Section 6.4.5.2, “Installing or Uninstalling MySQL Enterprise Audit”. The SUPER
privilege is required to use any of these functions.
The audit log filtering functions enable filtering control by providing an interface to create, modify, and remove filter definitions and assign filters to user accounts.
Filter definitions are JSON
values. For information about using JSON
data in MySQL, see Section 11.5, “The JSON Data Type”. This section shows some simple filter definitions. For more information about filter definitions, see Section 6.4.5.7, “Writing Audit Log Filter Definitions”.
When a connection arrives, the audit log plugin determines which filter to use for the new session by searching for the user account name in the current filter assignments:
-
If a filter is assigned to the user, the audit log uses that filter.
-
Otherwise, if no user-specific filter assignment exists, but there is a filter assigned to the default account (
%
), the audit log uses the default filter. -
Otherwise, the audit log selects no audit events from the session for processing.
If a change-user operation occurs during a session (see Section 28.7.6.3, “mysql_change_user()”), filter assignment for the session is updated using the same rules but for the new user.
By default, no accounts have a filter assigned, so no processing of auditable events occurs for any account.
Suppose that instead you want the default to be to log only connection-related activity (for example, to see connect, change-user, and disconnect events, but not the SQL statements users execute while connected). To achieve this, define a filter (shown here named log_conn_events
) that enables logging only of events in the connection
class, and assign that filter to the default account, represented by the %
account name:
SET @f = '{ "filter": { "class": { "name": "connection" } } }'; SELECT audit_log_filter_set_filter('log_conn_events', @f); SELECT audit_log_filter_set_user('%', 'log_conn_events');
Now the audit log uses this default account filter for connections from any account that has no explicitly defined filter.
To assign a filter explicitly to a particular user account or accounts, define the filter, then assign it to the relevant accounts:
SELECT audit_log_filter_set_filter('log_all', '{ "filter": { "log": true } }'); SELECT audit_log_filter_set_user('user1@localhost', 'log_all'); SELECT audit_log_filter_set_user('user2@localhost', 'log_all');
Now full logging is enabled for user1@localhost
and user2@localhost
. Connections from other accounts continue to be filtered using the default account filter.
To disassociate a user account from its current filter, either unassign the filter or assign a different filter:
-
To unassign the filter from the user account:
SELECT audit_log_filter_remove_user('user1@localhost');
Filtering of current sessions for the account remains unaffected. Subsequent connections from the account are filtered using the default account filter if there is one, and are not logged otherwise.
-
To assign a different filter to the user account:
SELECT audit_log_filter_set_filter('log_nothing', '{ "filter": { "log": false } }'); SELECT audit_log_filter_set_user('user1@localhost', 'log_nothing');
Filtering of current sessions for the account remains unaffected. Subsequent connections from the account are filtered using the new filter. For the filter shown here, that means no logging for new connections from
user1@localhost
.
For audit log filtering, user name and host name comparisons are case-sensitive. This differs from comparisons for privilege checking, for which host name comparisons are not case-sensitive.
To remove a filter, do this:
SELECT audit_log_filter_remove_filter('log_nothing');
Removing a filter also unassigns it from any users to whom it has been assigned, including any current sessions for those users.
The filtering UDFs just described affect audit filtering immediately and update the audit log tables in the mysql
system database that store filters and user accounts (see Audit Log Tables). It is also possible to modify the audit log tables directly using statements such as INSERT
, UPDATE
, and DELETE
, but such changes do not affect filtering immediately. To flush your changes and make them operational, call audit_log_filter_flush()
:
SELECT audit_log_filter_flush();
audit_log_filter_flush()
should be used only after modifying the audit tables directly, to force reloading all filters. Otherwise, this function should be avoided. It is, in effect, a simplified version of unloading and reloading the audit_log
plugin with UNINSTALL PLUGIN
plus INSTALL PLUGIN
.
audit_log_filter_flush()
affects all current sessions and detaches them from their previous filters. Current sessions are no longer logged unless they disconnect and reconnect, or execute a change-user operation.
To determine whether a filter has been assigned to the current session, check the session value of the read-only audit_log_filter_id
system variable. If the value is 0, no filter is assigned. A nonzero value indicates the internally maintained ID of the assigned filter:
mysql> SELECT @@audit_log_filter_id;
+-----------------------+
| @@audit_log_filter_id |
+-----------------------+
| 2 |
+-----------------------+
Filter definitions are JSON
values. For information about using JSON
data in MySQL, see Section 11.5, “The JSON Data Type”.
Filter definitions have this form, where actions
indicates how filtering takes place:
{ "filter": actions
}
The following discussion describes permitted constructs in filter definitions.
To explicitly enable or disable logging of all events, use a log
element in the filter:
{ "filter": { "log": true } }
The log
value can be either true
or false
.
The preceding filter enables logging of all events. It is equivalent to:
{ "filter": { } }
Logging behavior depends on the log
value and whether class
or event
items are specified:
-
With
log
specified, its given value is used. -
Without
log
specified, logging istrue
if noclass
orevent
item is specified, andfalse
otherwise (in which case,class
orevent
can include their ownlog
item).
To log events of a specific class, use a class
element in the filter, with its name
field denoting the name of the class to log:
{ "filter": { "class": { "name": "connection" } } }
The name
value can be connection
, general
, or table_access
to log connection, general, or table-access events, respectively.
The preceding filter enables logging of events in the connection
class. It is equivalent to the following filter with log
items made explicit:
{ "filter": { "log": false, "class": { "log": true, "name": "connection" } } }
To enable logging of multiple classes, define the class
value as a JSON
array element that names the classes:
{ "filter": { "class": [ { "name": "connection" }, { "name": "general" }, { "name": "table_access" } ] } }
When multiple instances of a given item appear at the same level within a filter definition, the item values can be combined into a single instance of that item within an array value. The preceding definition can be written like this:
{ "filter": { "class": [ { "name": [ "connection", "general", "table_access" ] } ] } }
To select specific event subclasses, use an event
item containing a name
item that names the subclasses. The default action for events selected by an event
item is to log them. For example, this filter enables logging for the named event subclasses:
{ "filter": { "class": [ { "name": "connection", "event": [ { "name": "connect" }, { "name": "disconnect" } ] }, { "name": "general" }, { "name": "table_access", "event": [ { "name": "insert" }, { "name": "delete" }, { "name": "update" } ] } ] } }
The event
item can also contain explicit log
items to indicate whether to log qualifying events. This event
item selects multiple events and explicitly indicates logging behavior for them:
"event": [ { "name": "read", "log": false }, { "name": "insert", "log": true }, { "name": "delete", "log": true }, { "name": "update", "log": true } ]
The event
item can also indicate whether to block qualifying events, if it contains an abort
item. For details, see Blocking Execution of Specific Events.
Table 6.29, “Event Class and Subclass Combinations” describes the permitted subclass values for each event class.
Table 6.29 Event Class and Subclass Combinations
Event Class | Event Subclass | Description |
---|---|---|
connection |
connect |
Connection initiation (successful or unsuccessful) |
connection |
change_user |
User re-authentication with different user/password during session |
connection |
disconnect |
Connection termination |
general |
status |
General operation information |
message |
internal |
Internally generated message |
message |
user |
Message generated by audit_api_message_emit_udf() |
table_access |
read |
Table read statements, such as SELECT or INSERT INTO ... SELECT |
table_access |
delete |
Table delete statements, such as DELETE or TRUNCATE TABLE |
table_access |
insert |
Table insert statements, such as INSERT or REPLACE |
table_access |
update |
Table update statements, such as UPDATE |
Table 6.30, “Log and Abort Characteristics Per Event Class and Subclass Combination” describes for each event subclass whether it can be logged or aborted.
Table 6.30 Log and Abort Characteristics Per Event Class and Subclass Combination
Event Class | Event Subclass | Can be Logged | Can be Aborted |
---|---|---|---|
connection |
connect |
Yes | No |
connection |
change_user |
Yes | No |
connection |
disconnect |
Yes | No |
general |
status |
Yes | No |
message |
internal |
Yes | Yes |
message |
user |
Yes | Yes |
table_access |
read |
Yes | Yes |
table_access |
delete |
Yes | Yes |
table_access |
insert |
Yes | Yes |
table_access |
update |
Yes | Yes |
A filter can be defined in inclusive or exclusive mode:
-
Inclusive mode logs only explicitly specified items.
-
Exclusive mode logs everything but explicitly specified items.
To perform inclusive logging, disable logging globally and enable logging for
specific classes. This filter logs connect
and disconnect
events in the connection
class, and events in the general
class:
{ "filter": { "log": false, "class": [ { "name": "connection", "event": [ { "name": "connect", "log": true }, { "name": "disconnect", "log": true } ] }, { "name": "general", "log": true } ] } }
To perform exclusive logging, enable logging globally and disable logging for specific classes. This filter logs everything except events in the general
class:
{ "filter": { "log": true, "class": { "name": "general", "log": false } } }
This filter logs change_user
events in the connection
class, message
events, and table_access
events:
{ "filter": { "log": true, "class": [ { "name": "connection", "event": [ { "name": "connect", "log": false }, { "name": "disconnect", "log": false } ] }, { "name": "general", "log": false } ] } }
To enable logging based on specific event field values, specify a field
item within the log
item that indicates the field name and its expected value:
{ "filter": { "class": { "name": "general", "event": { "name": "status", "log": { "field": { "name": "general_command.str", "value": "Query" } } } } } }
Each event contains event class-specific fields that can be accessed from within a filter to perform custom filtering.
A connection event indicates when a connection-related activity occurs during a session, such as a user connecting to or disconnecting from the server. Table 6.31, “Connection Event Fields” indicates the permitted fields for connection events.
Table 6.31 Connection Event Fields
Field Name | Field Type | Description |
---|---|---|
status |
integer |
Event status: 0: OK Otherwise: Failed |
connection_id |
unsigned integer | Connection ID |
user.str |
string | User name specified during authentication |
user.length |
unsigned integer | User name length |
priv_user.str |
string | Authenticated user name (account user name) |
priv_user.length |
unsigned integer | Authenticated user name length |
external_user.str |
string | External user name (provided by third-party authentication plugin) |
external_user.length |
unsigned integer | External user name length |
proxy_user.str |
string | Proxy user name |
proxy_user.length |
unsigned integer | Proxy user name length |
host.str |
string | Connected user host |
host.length |
unsigned integer | Connected user host length |
ip.str |
string | Connected user IP address |
ip.length |
unsigned integer | Connected user IP address length |
database.str |
string | Database name specified at connect time |
database.length |
unsigned integer | Database name length |
connection_type |
integer |
Connection type: or or or or or or |
The "::
values are symbolic
pseudo-constants that may be given instead of the literal numeric values. They
must be quoted as strings and are case-sensitive. xxx
"
A general event indicates the status code of an operation and its details. Table 6.32, “General Event Fields” indicates the permitted fields for general events.
Table 6.32 General Event Fields
Field Name | Field Type | Description |
---|---|---|
general_error_code |
integer |
Event status: 0: OK Otherwise: Failed |
general_thread_id |
unsigned integer | Connection/thread ID |
general_user.str |
string | User name specified during authentication |
general_user.length |
unsigned integer | User name length |
general_command.str |
string | Command name |
general_command.length |
unsigned integer | Command name length |
general_query.str |
string | SQL statement text |
general_query.length |
unsigned integer | SQL statement text length |
general_host.str |
string | Host name |
general_host.length |
unsigned integer | Host name length |
general_sql_command.str |
string | SQL command type name |
general_sql_command.length |
unsigned integer | SQL command type name length |
general_external_user.str |
string | External user name (provided by third-party authentication plugin) |
general_external_user.length |
unsigned integer | External user name length |
general_ip.str |
string | Connected user IP address |
general_ip.length |
unsigned integer | Connection user IP address length |
general_command.str
indicates a command name:
Query
, Execute
, Quit
, or Change user
.
A general event with the general_command.str
field
set to Query
or Execute
contains general_sql_command.str
set to a value that
specifies the type of SQL command: alter_db
, alter_db_upgrade
, admin_commands
, and so forth. These values can be seen as
the last components of the Performance Schema instruments displayed by this
statement:
SELECT NAME FROM performance_schema.setup_instruments WHERE NAME LIKE 'statement/sql/%' ORDER BY NAME;
A table-access event provides information about specific table accesses. Table 6.33, “Table-Access Event Fields” indicates the permitted fields for table-access events.
Table 6.33 Table-Access Event Fields
Field Name | Field Type | Description |
---|---|---|
connection_id |
unsigned integer | Event connection ID |
sql_command_id |
integer | SQL command ID |
query.str |
string | SQL statement text |
query.length |
unsigned integer | SQL statement text length |
table_database.str |
string | Database name associated with event |
table_database.length |
unsigned integer | Database name length |
table_name.str |
string | Table name associated with event |
table_name.length |
unsigned integer | Table name length |
The following list shows which statements produce which table-access events:
-
read
event:-
SELECT
-
INSERT ... SELECT
(for tables referenced inSELECT
clause) -
REPLACE ... SELECT
(for tables referenced inSELECT
clause) -
UPDATE ... WHERE
(for tables referenced inWHERE
clause) -
HANDLER ... READ
-
-
delete
event:-
DELETE
-
TRUNCATE TABLE
-
-
insert
event:-
INSERT
-
INSERT ... SELECT
(for table referenced inINSERT
clause) -
REPLACE
-
REPLACE ... SELECT
(for table referenced inREPLACE
clause -
LOAD DATA
-
LOAD XML
-
-
update
event:-
UPDATE
-
UPDATE ... WHERE
(for tables referenced inUPDATE
clause)
-
event
items can include an abort
item that indicates whether to prevent qualifying
events from executing. For example, abort
enables
rules to be written that block execution of specific SQL statements.
The abort
item must appear within an event
item. For example:
qualifying event subclass names condition
For event subclasses selected by the name
item, the abort
action is true or false, depending on condition
evaluation. If the condition evaluates to true, the event is blocked. Otherwise, the event continues executing.
The condition
specification can be as simple as true
or false
, or it can be more complex such that evaluation depends on event characteristics.
This filter blocks INSERT
, UPDATE
, and DELETE
statements:
{ "filter": { "class": { "name": "table_access", "event": { "name": [ "insert", "update", "delete" ], "abort": true } } } }
This more complex filter blocks the same statements, but only for a specific table (finances.bank_account
):
{ "filter": { "class": { "name": "table_access", "event": { "name": [ "insert", "update", "delete" ], "abort": { "and": [ { "field": { "name": "table_database.str", "value": "finances" } }, { "field": { "name": "table_name.str", "value": "bank_account" } } ] } } } } }
Statements matched and blocked by the filter return an error to the client:
ERROR 1045 (28000): Statement was aborted by an audit log filter
Not all events can be blocked (see Table 6.30, “Log and Abort Characteristics Per Event Class and Subclass Combination”). For an event that cannot, the audit log writes a warning to the error log rather than blocking it.
For attempts to define a filter in which the abort
item appears elsewhere than in an event
item, an error occurs.
Logical operators (and
, or
, not
) can be used in log
items. This permits construction of more advanced filtering configurations:
{ "filter": { "class": { "name": "general", "event": { "name": "status", "log": { "or": [ { "and": [ { "field": { "name": "general_command.str", "value": "Query" } }, { "field": { "name": "general_command.length", "value": 5 } } ] }, { "and": [ { "field": { "name": "general_command.str", "value": "Execute" } }, { "field": { "name": "general_command.length", "value": 7 } } ] } ] } } } } }
To refer to a predefined variable in a log
condition, use a variable
item, which tests equality against a given value:
{ "filter": { "class": { "name": "general", "event": { "name": "status", "log": { "variable": { "name": "audit_log_connection_policy_value", "value": "::none" } } } } } }
Each predefined variable corresponds to a system variable. By writing a filter that tests a predefined variable, you can modify filter operation by setting the corresponding system variable, without having to redefine the filter. For example, by writing a filter that tests the value of the audit_log_connection_policy_value
predefined variable, you can modify filter operation by changing the value of the audit_log_connection_policy
system variable.
The audit_log_
system variables are used for the legacy mode audit log (see Section 6.4.5.8, “Legacy Mode Audit Log Filtering”). With rule-based audit log filtering, those variables remain visible (for example, using xxx
_policySHOW VARIABLES
), but changes to them have no effect unless you write filters containing constructs that refer to them.
The following list describes the permitted predefined variables for variable
items:
-
audit_log_connection_policy_value
This variable corresponds to the value of the
audit_log_connection_policy
system variable. The value is an unsigned integer. Table 6.34, “audit_log_connection_policy_value Values” shows the permitted values and the correspondingaudit_log_connection_policy
values.Table 6.34 audit_log_connection_policy_value Values
Value Corresponding audit_log_connection_policy Value 0
or"::none"
NONE
1
or"::errors"
ERRORS
2
or"::all"
ALL
The
"::
values are symbolic pseudo-constants that may be given instead of the literal numeric values. They must be quoted as strings and are case-sensitive.xxx
" -
audit_log_policy_value
This variable corresponds to the value of the
audit_log_policy
system variable. The value is an unsigned integer. Table 6.35, “audit_log_policy_value Values” shows the permitted values and the correspondingaudit_log_policy
values.Table 6.35 audit_log_policy_value Values
Value Corresponding audit_log_policy Value 0
or"::none"
NONE
1
or"::logins"
LOGINS
2
or"::all"
ALL
3
or"::queries"
QUERIES
The
"::
values are symbolic pseudo-constants that may be given instead of the literal numeric values. They must be quoted as strings and are case-sensitive.xxx
" -
audit_log_statement_policy_value
This variable corresponds to the value of the
audit_log_statement_policy
system variable. The value is an unsigned integer. Table 6.36, “audit_log_statement_policy_value Values” shows the permitted values and the correspondingaudit_log_statement_policy
values.Table 6.36 audit_log_statement_policy_value Values
Value Corresponding audit_log_statement_policy Value 0
or"::none"
NONE
1
or"::errors"
ERRORS
2
or"::all"
ALL
The
"::
values are symbolic pseudo-constants that may be given instead of the literal numeric values. They must be quoted as strings and are case-sensitive.xxx
"
To refer to a predefined function in a log
condition, use a function
item, which takes name
and args
values to specify
the function name and its arguments, respectively:
{ "filter": { "class": { "name": "general", "event": { "name": "status", "log": { "function": { "name": "find_in_include_list", "args": [ { "string": [ { "field": "user.str" }, { "string": "@"}, { "field": "host.str" } ] } ] } } } } } }
The function as specified in the name
item should be the function name only, without parentheses or the argument list. Arguments in the args
item, if there is one, must be given in the order listed in the function description. Arguments can refer to predefined variables, event fields, or string or numeric constants.
The preceding filter determines whether to log general
class status
events depending on whether the current user is found in the audit_log_include_accounts
system variable. That user is constructed using fields in the event.
The following list describes the permitted predefined functions for function
items:
-
audit_log_exclude_accounts_is_null()
Checks whether the
audit_log_exclude_accounts
system variable isNULL
. This function can be helpful when defining filters that correspond to the legacy audit log implementation.Arguments:
None.
-
audit_log_include_accounts_is_null()
Checks whether the
audit_log_include_accounts
system variable isNULL
. This function can be helpful when defining filters that correspond to the legacy audit log implementation.Arguments:
None.
-
debug_sleep(millisec)
Sleeps for the given number of milliseconds. This function is used during performance measurement.
debug_sleep()
is available for debug builds only.Arguments:
-
millisec
: An unsigned integer that specifies the number of milliseconds to sleep.
-
-
find_in_exclude_list(account)
Checks whether an account string exists in the audit log exclude list (the value of the
audit_log_exclude_accounts
system variable).Arguments:
-
account
: A string that specifies the user account name.
-
-
find_in_include_list(account)
Checks whether an account string exists in the audit log include list (the value of the
audit_log_include_accounts
system variable).Arguments:
-
account
: A string that specifies the user account name.
-
-
string_find(text, substr)
Checks whether the
substr
value is contained in thetext
value. This search is case-sensitive.Arguments:
-
text
: The text string to search. -
substr
: The substring to search for intext
.
-
In some cases, the filter definition can be changed dynamically. To do this, define a filter
configuration within an existing filter
. For example:
{ "filter": { "id": "main", "class": { "name": "table_access", "event": { "name": [ "update", "delete" ], "log": false, "filter": { "class": { "name": "general", "event" : { "name": "status", "filter": { "ref": "main" } } }, "activate": { "or": [ { "field": { "name": "table_name.str", "value": "temp_1" } }, { "field": { "name": "table_name.str", "value": "temp_2" } } ] } } } } } }
A new filter is activated when the activate
element within a subfilter evaluates to true
. Using activate
in a top-level filter
is not permitted.
A new filter can be replaced with the original one by using a ref
item inside the subfilter to refer to the original filter id
.
The filter shown operates like this:
-
The
main
filter waits fortable_access
events, eitherupdate
ordelete
. -
If the
update
ordelete
table_access
event occurs on thetemp_1
ortemp_2
table, the filter is replaced with the internal one (without anid
, since there is no need to refer to it explicitly). -
If the end of the command is signalled (
general
/status
event), an entry is written to the audit log file and the filter is replaced with themain
filter.
The filter is useful to log statements that update or delete anything from the temp_1
or temp_2
tables, such as this one:
UPDATE temp_1, temp_3 SET temp_1.a=21, temp_3.a=23;
The statement generates multiple table_access
events, but the audit log file will contain only general
/ status
entries.
Any id
values used in the definition are evaluated with respect only to that definition. They have nothing to do with the value of the audit_log_filter_id
system variable.
This section describes legacy audit log filtering, which applies if the audit_log
plugin is installed but not the accompanying audit tables and UDFs needed for rule-based filtering.
The audit log plugin can filter audited events. This enables you to control whether audited events are written to the audit log file based on the account from which events originate or event status. Status filtering occurs separately for connection events and statement events.
To filter audited events based on the originating account, set one of these system variables at server startup or runtime:
-
audit_log_include_accounts
: The accounts to include in audit logging. If this variable is set, only these accounts are audited. -
audit_log_exclude_accounts
: The accounts to exclude from audit logging. If this variable is set, all but these accounts are audited.
The value for either variable can be NULL
or a string containing one or more comma-separated account names, each in
format. By default, both variables are user_name
@host_name
NULL
, in which case, no account filtering is done and auditing occurs for all accounts.
Modifications to audit_log_include_accounts
or audit_log_exclude_accounts
affect only connections created subsequent to the modification, not existing connections.
Example: To enable audit logging only for the user1
and user2
local host account accounts, set the audit_log_include_accounts
system variable like this:
SET GLOBAL audit_log_include_accounts = 'user1@localhost,user2@localhost';
Only one of audit_log_include_accounts
or audit_log_exclude_accounts
can be non-NULL
at a time:
-
If you set
audit_log_include_accounts
, the server setsaudit_log_exclude_accounts
toNULL
. -
If you attempt to set
audit_log_exclude_accounts
, an error occurs unlessaudit_log_include_accounts
isNULL
. In this case, you must first clearaudit_log_include_accounts
by setting it toNULL
.
value value value
If you inspect the value of either variable, be aware that SHOW VARIABLES
displays NULL
as an empty string. To avoid this, use SELECT
instead:
SHOW VARIABLES LIKE 'audit_log_include_accounts'; SELECT @@audit_log_include_accounts;
If a user name or host name requires quoting because it contains a comma, space, or other special character, quote it using single quotes. If the variable value itself is quoted with single quotes, double each inner single quote or escape it with a backslash. The following statements each enable audit logging for the local root
account and are equivalent, even though the quoting styles differ:
SET GLOBAL audit_log_include_accounts = 'root@localhost'; SET GLOBAL audit_log_include_accounts = '''root''@''localhost'''; SET GLOBAL audit_log_include_accounts = '\'root\'@\'localhost\''; SET GLOBAL audit_log_include_accounts = "'root'@'localhost'";
The last statement will not work if the ANSI_QUOTES
SQL mode is enabled because in that mode double quotes signify identifier quoting, not string quoting.
To filter audited events based on status, set the following system variables at server startup or runtime. These variables apply only for legacy audit log filtering. For JSON audit log filtering, different status variables apply; see Audit Log Options and Variables.
-
audit_log_connection_policy
: Logging policy for connection events -
audit_log_statement_policy
: Logging policy for statement events
Each variable takes a value of ALL
(log all associated events; this is the default), ERRORS
(log only failed events), or NONE
(do not log events). For example, to log all statement events but only failed connection events, use these settings:
SET GLOBAL audit_log_statement_policy = ALL; SET GLOBAL audit_log_connection_policy = ERRORS;
Another policy system variable, audit_log_policy
, is available but does not afford as much control as audit_log_connection_policy
and audit_log_statement_policy
. It can be set only at server startup. At runtime, it is a read-only variable. It takes a value of ALL
(log all events; this is the default), LOGINS
(log connection events), QUERIES
(log statement events), or NONE
(do not log events). For any of those values, the audit log plugin logs all selected events without distinction as to success or failure. Use of audit_log_policy
at startup works as follows:
-
If you do not set
audit_log_policy
or set it to its default ofALL
, any explicit settings foraudit_log_connection_policy
oraudit_log_statement_policy
apply as specified. If not specified, they default toALL
. -
If you set
audit_log_policy
to a non-ALL
value, that value takes precedence over and is used to setaudit_log_connection_policy
andaudit_log_statement_policy
, as indicated in the following table. If you also set either of those variables to a value other than their default ofALL
, the server writes a message to the error log to indicate that their values are being overridden.Startup audit_log_policy Value Resulting audit_log_connection_policy Value Resulting audit_log_statement_policy Value LOGINS
ALL
NONE
QUERIES
NONE
ALL
NONE
NONE
NONE
The following discussion serves as a reference to MySQL Enterprise Audit components:
To install the audit log tables and functions, use the instructions provided in Section 6.4.5.2, “Installing or Uninstalling MySQL Enterprise Audit”. Unless those components are installed, the audit_log
plugin operates in legacy mode. See Section 6.4.5.8, “Legacy Mode Audit Log Filtering”.
MySQL Enterprise Audit uses tables in the mysql
system database for persistent storage of filter and user account data. The tables can be accessed only by users with privileges for that database. The tables use the InnoDB
storage engine.
If these tables are missing, the audit_log
plugin operates in legacy mode. See Section 6.4.5.8, “Legacy Mode Audit Log Filtering”.
The audit_log_filter
table stores filter definitions. The table has these columns:
-
NAME
The filter name.
-
FILTER
The filter definition associated with the filter name. Definitions are stored as
JSON
values.
The audit_log_user
table stores user account information. The table has these columns:
-
USER
The user name part of an account. For an account
user1@localhost
, theUSER
part isuser1
. -
HOST
The host name part of an account. For an account
user1@localhost
, theHOST
part islocalhost
. -
FILTERNAME
The name of the filter assigned to the account. The filter name associates the account with a filter defined in the
audit_log_filter
table.
This section describes, for each audit log user-defined function (UDF), its purpose, calling sequence, and return value. For information about the conditions under which these UDFs can be invoked, see Section 6.4.5.6, “Audit Log Filtering”.
Each audit log UDF returns a string that indicates whether the operation succeeded. OK
indicates success. ERROR:
indicates failure.message
As of MySQL 8.0.19, audit log UDFs convert string arguments to utf8mb4
and string return values are utf8mb4
strings. Prior to MySQL 8.0.19, audit log UDFs treat string arguments as binary strings (which means they do not distinguish lettercase), and string return values are binary strings.
These audit log UDFs are available:
-
audit_log_encryption_password_get([
keyring_id
])This function fetches an audit log encryption password from the MySQL keyring, which must be enabled or an error occurs. Any keyring plugin can be used; for instructions, see Section 6.4.4, “The MySQL Keyring”.
With no argument, the function retrieves the current encryption password as a binary string. An argument may be given to specify which audit log encryption password to retrieve. The argument must be the keyring ID of the current password or an archived password.
For additional information about audit log encryption, see Audit Log File Encryption.
Arguments:
keyring_id
: As of MySQL 8.0.17, this optional argument indicates the keyring ID of the password to retrieve. The maximum permitted length is 766 bytes. If omitted, the function retrieves the current password.Prior to MySQL 8.0.17, no argument is permitted. The function always retrieves the current password.
Return value:
The password string for success (up to 766 bytes), or
NULL
and an error for failure.Example:
Retrieve the current password:
mysql>
SELECT audit_log_encryption_password_get();
+-------------------------------------+ | audit_log_encryption_password_get() | +-------------------------------------+ | secret | +-------------------------------------+To retrieve a password by ID, you can determine which audit log keyring IDs exist by querying the Performance Schema
keyring_keys
table:SELECT * FROM performance_schema.keyring_keys WHERE KEY_ID LIKE 'audit_log%' ORDER BY KEY_ID; SELECT audit_log_encryption_password_get('audit_log-20190416T125122-1'); -
audit_log_encryption_password_set(
password
)Sets the current audit log encryption password to the argument and stores the password in the MySQL keyring. As of MySQL 8.0.19, the password is stored as a
utf8mb4
string. Prior to MySQL 8.0.19, the password is stored in binary form.If encryption is enabled, this function performs a log file rotation operation that renames the current log file, and begins a new log file encrypted with the password. The keyring must be enabled or an error occurs. Any keyring plugin can be used; for instructions, see Section 6.4.4, “The MySQL Keyring”.
For additional information about audit log encryption, see Audit Log File Encryption.
Arguments:
password
: The password string. The maximum permitted length is 766 bytes.Return value:
1 for success, 0 for failure.
Example:
SELECT audit_log_encryption_password_set(password); password password -
Calling any of the other filtering UDFs affects operational audit log filtering immediately and updates the audit log tables. If instead you modify the contents of those tables directly using statements such as
INSERT
,UPDATE
, andDELETE
, the changes do not affect filtering immediately. To flush your changes and make them operational, callaudit_log_filter_flush()
.Warningaudit_log_filter_flush()
should be used only after modifying the audit tables directly, to force reloading all filters. Otherwise, this function should be avoided. It is, in effect, a simplified version of unloading and reloading theaudit_log
plugin withUNINSTALL PLUGIN
plusINSTALL PLUGIN
.audit_log_filter_flush()
affects all current sessions and detaches them from their previous filters. Current sessions are no longer logged unless they disconnect and reconnect, or execute a change-user operation.If this function fails, an error message is returned and the audit log is disabled until the next successful call to
audit_log_filter_flush()
.Arguments:
None.
Return value:
A string that indicates whether the operation succeeded.
OK
indicates success.ERROR:
indicates failure.message
Example:
mysql>
SELECT audit_log_filter_flush();
+--------------------------+ | audit_log_filter_flush() | +--------------------------+ | OK | +--------------------------+ -
audit_log_filter_remove_filter(
filter_name
)Given a filter name, removes the filter from the current set of filters. It is not an error for the filter not to exist.
If a removed filter is assigned to any user accounts, those users stop being filtered (they are removed from the
audit_log_user
table). Termination of filtering includes any current sessions for those users: They are detached from the filter and no longer logged.Arguments:
-
filter_name
: A string that specifies the filter name.
Return value:
A string that indicates whether the operation succeeded.
OK
indicates success.ERROR:
indicates failure.message
Example:
mysql>
SELECT audit_log_filter_remove_filter('SomeFilter');
+----------------------------------------------+ | audit_log_filter_remove_filter('SomeFilter') | +----------------------------------------------+ | OK | +----------------------------------------------+ -
-
audit_log_filter_remove_user(
user_name
)Given a user account name, cause the user to be no longer assigned to a filter. It is not an error if the user has no filter assigned. Filtering of current sessions for the user remains unaffected. New connections for the user are filtered using the default account filter if there is one, and are not logged otherwise.
If the name is
%
, the function removes the default account filter that is used for any user account that has no explicitly assigned filter.Arguments:
-
user_name
: The user account name as a string in
format, oruser_name
@host_name
%
to represent the default account.
Return value:
A string that indicates whether the operation succeeded.
OK
indicates success.ERROR:
indicates failure.message
Example:
mysql>
SELECT audit_log_filter_remove_user('user1@localhost');
+-------------------------------------------------+ | audit_log_filter_remove_user('user1@localhost') | +-------------------------------------------------+ | OK | +-------------------------------------------------+ -
-
audit_log_filter_set_filter(
filter_name
,definition
)Given a filter name and definition, adds the filter to the current set of filters. If the filter already exists and is used by any current sessions, those sessions are detached from the filter and are no longer logged. This occurs because the new filter definition has a new filter ID that differs from its previous ID.
Arguments:
-
filter_name
: A string that specifies the filter name. -
definition
: AJSON
value that specifies the filter definition.
Return value:
A string that indicates whether the operation succeeded.
OK
indicates success.ERROR:
indicates failure.message
Example:
SET @f = '{ "filter": { "log": false } }'; SELECT audit_log_filter_set_filter('SomeFilter', @f); -
-
audit_log_filter_set_user(
user_name
,filter_name
)Given a user account name and a filter name, assigns the filter to the user. A user can be assigned only one filter, so if the user was already assigned a filter, the assignment is replaced. Filtering of current sessions for the user remains unaffected. New connections are filtered using the new filter.
As a special case, the name
%
represents the default account. The filter is used for connections from any user account that has no explicitly assigned filter.Arguments:
-
user_name
: The user account name as a string in
format, oruser_name
@host_name
%
to represent the default account. -
filter_name
: A string that specifies the filter name.
Return value:
A string that indicates whether the operation succeeded.
OK
indicates success.ERROR:
indicates failure.message
Example:
mysql>
SELECT audit_log_filter_set_user('user1@localhost', 'SomeFilter');
+------------------------------------------------------------+ | audit_log_filter_set_user('user1@localhost', 'SomeFilter') | +------------------------------------------------------------+ | OK | +------------------------------------------------------------+ -
-
Reads events from the audit log and returns a binary
JSON
string containing an array of audit events. If the audit log format is notJSON
, an error occurs.Each event in the return value is a
JSON
hash, except that the last array element may be aJSON
null
value to indicate no following events are available to read.For the first call to
audit_log_read()
within a session, pass a bookmark indicating where to begin reading. If the final value of the returned array is not aJSON
null
value, there are more events following those just read andaudit_log_read()
can be called without or with a bookmark argument. Without an argument, reading continues with the next unread event. With a bookmark argument, reading continues from the bookmark.If the final value of the returned array is a
JSON
null
value, there are no more events left to be read and the next call toaudit_log_read()
must include a bookmark argument.To obtain a bookmark for the most recently written event, call
audit_log_read_bookmark()
.For additional information about audit log-reading functions, see Audit Log File Reading.
Arguments:
arg
: An optional bookmark, represented as a string containing aJSON
hash that indicates where and how much to read. The following items are significant in thearg
value (other items are ignored):-
timestamp
,id
: The location within the audit log of the first event to read. Both items must be present to completely specify a position. -
max_array_length
: The maximum number of events to read from the log. If omitted, the default is to read to the end of the log or until the read buffer is full, whichever comes first.
Return value:
A binary
JSON
string containing an array of audit events for success, orNULL
and an error for failure.Example:
mysql>
SELECT audit_log_read(audit_log_read_bookmark());
+-----------------------------------------------------------------------+ | audit_log_read(audit_log_read_bookmark()) | +-----------------------------------------------------------------------+ | [ {"timestamp":"2019-10-03 22:41:24","id":0,"class":"connection", ... | +-----------------------------------------------------------------------+ -
-
Returns a binary
JSON
string representing a bookmark for the most recently written audit log event. If the audit log format is notJSON
, an error occurs.The bookmark is a
JSON
hash withtimestamp
andid
items indicating the event position within the audit log. It is suitable for passing toaudit_log_read()
to indicate to that function where to begin reading.For additional information about audit log-reading functions, see Audit Log File Reading.
Arguments:
None.
Return value:
A binary
JSON
string containing a bookmark for success, orNULL
and an error for failure.Example:
mysql>
SELECT audit_log_read_bookmark();
+-------------------------------------------------+ | audit_log_read_bookmark() | +-------------------------------------------------+ | { "timestamp": "2019-10-03 21:03:44", "id": 0 } | +-------------------------------------------------+
Table 6.37 Audit Log Option and Variable Reference
This section describes the command options and system variables that configure operation of MySQL Enterprise Audit. If values specified at startup time are incorrect, the audit_log
plugin may fail to initialize properly and the server does not load it. In this case, the server may also produce error messages for other audit log settings because it will not recognize them.
To configure activation of the audit log plugin, use this option:
-
Property Value Command-Line Format --audit-log[=value]
Type Enumeration Default Value ON
Valid Values ON
OFF
FORCE
FORCE_PLUS_PERMANENT
This option controls how the server loads the
audit_log
plugin at startup. It is available only if the plugin has been previously registered withINSTALL PLUGIN
or is loaded with--plugin-load
or--plugin-load-add
. See Section 6.4.5.2, “Installing or Uninstalling MySQL Enterprise Audit”.The option value should be one of those available for plugin-loading options, as described in Section 5.6.1, “Installing and Uninstalling Plugins”. For example,
--audit-log=FORCE_PLUS_PERMANENT
tells the server to load the plugin and prevent it from being removed while the server is running.
If the audit log plugin is enabled, it exposes several system variables that permit control over logging:
mysql> SHOW VARIABLES LIKE 'audit_log%';
+-----------------------------+--------------+
| Variable_name | Value |
+-----------------------------+--------------+
| audit_log_buffer_size | 1048576 |
| audit_log_connection_policy | ALL |
| audit_log_current_session | OFF |
| audit_log_exclude_accounts | |
| audit_log_file | audit.log |
| audit_log_filter_id | 0 |
| audit_log_flush | OFF |
| audit_log_format | NEW |
| audit_log_include_accounts | |
| audit_log_policy | ALL |
| audit_log_rotate_on_size | 0 |
| audit_log_statement_policy | ALL |
| audit_log_strategy | ASYNCHRONOUS |
+-----------------------------+--------------+
You can set any of these variables at server startup, and some of them at runtime. Those that are available only for legacy mode audit log filtering are so noted.
-
Property Value Command-Line Format --audit-log-buffer-size=#
System Variable audit_log_buffer_size
Scope Global Dynamic No SET_VAR
Hint AppliesNo Type Integer Default Value 1048576
Minimum Value 4096
Maximum Value (64-bit platforms) 18446744073709547520
Maximum Value (32-bit platforms) 4294967295
When the audit log plugin writes events to the log asynchronously, it uses a buffer to store event contents prior to writing them. This variable controls the size of that buffer, in bytes. The server adjusts the value to a multiple of 4096. The plugin uses a single buffer, which it allocates when it initializes and removes when it terminates. The plugin allocates this buffer only if logging is asynchronous.
-
Property Value Command-Line Format --audit-log-compression=value
System Variable audit_log_compression
Scope Global Dynamic No SET_VAR
Hint AppliesNo Type Enumeration Default Value NONE
Valid Values NONE
GZIP
The type of compression for the audit log file. Permitted values are
NONE
(no compression; the default) andGZIP
(GNU Zip compression). For more information, see Audit Log File Compression. -
Property Value Command-Line Format --audit-log-connection-policy=value
System Variable audit_log_connection_policy
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type Enumeration Default Value ALL
Valid Values ALL
ERRORS
NONE
NoteThis variable applies only to legacy mode audit log filtering (see Section 6.4.5.8, “Legacy Mode Audit Log Filtering”).
The policy controlling how the audit log plugin writes connection events to its log file. The following table shows the permitted values.
Value Description ALL
Log all connection events ERRORS
Log only failed connection events NONE
Do not log connection events NoteAt server startup, any explicit value given for
audit_log_connection_policy
may be overridden ifaudit_log_policy
is also specified, as described in Section 6.4.5.5, “Audit Log Logging Configuration”. -
Property Value System Variable audit_log_current_session
Scope Global, Session Dynamic No SET_VAR
Hint AppliesNo Type Boolean Default Value depends on filtering policy
Whether audit logging is enabled for the current session. The session value of this variable is read only. It is set when the session begins based on the values of the
audit_log_include_accounts
andaudit_log_exclude_accounts
system variables. The audit log plugin uses the session value to determine whether to audit events for the session. (There is a global value, but the plugin does not use it.) -
Property Value Command-Line Format --audit-log-encryption=value
System Variable audit_log_encryption
Scope Global Dynamic No SET_VAR
Hint AppliesNo Type Enumeration Default Value NONE
Valid Values NONE
AES
The type of encryption for the audit log file. Permitted values are
NONE
(no encryption; the default) andAES
(AES-256-CBC cipher encryption). For more information, see Audit Log File Encryption. -
Property Value Command-Line Format --audit-log-exclude-accounts=value
System Variable audit_log_exclude_accounts
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type String Default Value NULL
NoteThis variable applies only to legacy mode audit log filtering (see Section 6.4.5.8, “Legacy Mode Audit Log Filtering”).
The accounts for which events should not be logged. The value should be
NULL
or a string containing a list of one or more comma-separated account names. For more information, see Section 6.4.5.6, “Audit Log Filtering”.Modifications to
audit_log_exclude_accounts
affect only connections created subsequent to the modification, not existing connections. -
Property Value Command-Line Format --audit-log-file=file_name
System Variable audit_log_file
Scope Global Dynamic No SET_VAR
Hint AppliesNo Type File name Default Value audit.log
The base name and suffix of the file to which the audit log plugin writes events. The default value is
audit.log
, regardless of logging format. To have the name suffix correspond to the format, set the name explicitly, choosing a different suffix (for example,audit.xml
for XML format,audit.json
for JSON format).If the value of
audit_log_file
is a relative path name, the plugin interprets it relative to the data directory. If the value is a full path name, the plugin uses the value as is. A full path name may be useful if it is desirable to locate audit files on a separate file system or directory. For security reasons, write the audit log file to a directory accessible only to the MySQL server and to users with a legitimate reason to view the log.For details about how the audit log plugin interprets the
audit_log_file
value and the rules for file renaming that occurs at plugin initialization and termination, see Audit Log File Name.The audit log plugin uses the directory containing the audit log file (determined from the
audit_log_file
value) as the location to search for readable audit log files. From these log files and the current file, the plugin constructs a list of the ones that are subject to use with the audit log bookmarking and reading functions. See Audit Log File Reading. -
Property Value System Variable audit_log_filter_id
Scope Global, Session Dynamic No SET_VAR
Hint AppliesNo Type Integer The session value of this variable indicates the internally maintained ID of the audit filter for the current session. A value of 0 means that the session has no filter assigned.
-
Property Value System Variable audit_log_flush
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type Boolean Default Value OFF
When this variable is set to enabled (1 or
ON
), the audit log plugin closes and reopens its log file to flush it. (The value remainsOFF
so that you need not disable it explicitly before enabling it again to perform another flush.) Enabling this variable has no effect unlessaudit_log_rotate_on_size
is 0. For more information, see Section 6.4.5.5, “Audit Log Logging Configuration”. -
Property Value Command-Line Format --audit-log-format=value
System Variable audit_log_format
Scope Global Dynamic No SET_VAR
Hint AppliesNo Type Enumeration Default Value NEW
Valid Values OLD
NEW
JSON
The audit log file format. Permitted values are
OLD
(old-style XML),NEW
(new-style XML; the default), andJSON
. For details about each format, see Section 6.4.5.4, “Audit Log File Formats”.NoteFor information about issues to consider when changing the log format, see Audit Log File Format.
-
Property Value Command-Line Format --audit-log-include-accounts=value
System Variable audit_log_include_accounts
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type String Default Value NULL
NoteThis variable applies only to legacy mode audit log filtering (see Section 6.4.5.8, “Legacy Mode Audit Log Filtering”).
The accounts for which events should be logged. The value should be
NULL
or a string containing a list of one or more comma-separated account names. For more information, see Section 6.4.5.6, “Audit Log Filtering”.Modifications to
audit_log_include_accounts
affect only connections created subsequent to the modification, not existing connections. -
audit_log_password_history_keep_days
Property Value Command-Line Format --audit-log-password-history-keep-days=#
Introduced 8.0.17 System Variable audit_log_password_history_keep_days
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type Integer Default Value 0
Minimum Value 0
Maximum Value 4294967295
When a new encryption password is created, the audit log plugin archives the previous password, if one exists, for later use. The
audit_log_password_history_keep_days
variable controls automatic removal of archived passwords. Its value indicates the number of days after which archived audit log encryption passwords are removed. The default is 0, which disables password removal; the password retention period is forever.New audit log encryption passwords are created under these circumstances:
-
During plugin initialization, if the plugin finds that log file encryption is enabled, it checks whether the keyring contains an audit log encryption password. If not, the plugin automatically generates a random initial encryption password.
-
When the
audit_log_encryption_password_set()
function is called to set a specific password.
In each case, the plugin stores the password in the key ring and uses it to encrypt new log files.
Cleanup of old audit log encryption passwords occurs under these circumstances:
-
During plugin initialization.
-
When the
audit_log_encryption_password_set()
function is called. -
When the runtime value of
audit_log_password_history_keep_days
is changed from its current value to a value greater than 0. Runtime value changes may occur forSET
statements that use theGLOBAL
orPERSIST
keyword, but not thePERSIST_ONLY
keyword.PERSIST_ONLY
writes the variable setting tomysqld-auto.cnf
, but has no effect on the runtime value.
When password cleanup occurs, the current value of
audit_log_password_history_keep_days
determines which passwords to remove:-
If the value is
N
> 0, the plugin removes passwords more thanN
days old. -
If the value is 0, the plugin removes no passwords.
NoteTake care not to expire old passwords that are still needed to read archived encrypted log files.
If you normally leave password expiration disabled (
audit_log_password_history_keep_days=0
), it is possible to perform an on-demand cleanup operation by temporarily assigning the variable a value greater than zero. For example, to expire passwords older than 365 days, do this:SET GLOBAL audit_log_password_history_keep_days = 365; SET GLOBAL audit_log_password_history_keep_days = 0;
Setting the runtime value of
audit_log_password_history_keep_days
requires theAUDIT_ADMIN
privilege, in addition to theSYSTEM_VARIABLES_ADMIN
orSUPER
privilege normally required to set a global system variable runtime value. -
-
Property Value Command-Line Format --audit-log-policy=value
System Variable audit_log_policy
Scope Global Dynamic No SET_VAR
Hint AppliesNo Type Enumeration Default Value ALL
Valid Values ALL
LOGINS
QUERIES
NONE
NoteThis variable applies only to legacy mode audit log filtering (see Section 6.4.5.8, “Legacy Mode Audit Log Filtering”).
The policy controlling how the audit log plugin writes events to its log file. The following table shows the permitted values.
Value Description ALL
Log all events LOGINS
Log only login events QUERIES
Log only query events NONE
Log nothing (disable the audit stream) audit_log_policy
can be set only at server startup. At runtime, it is a read-only variable. Two other system variables,audit_log_connection_policy
andaudit_log_statement_policy
, provide finer control over logging policy and can be set either at startup or at runtime. If you useaudit_log_policy
at startup instead of the other two variables, the server uses its value to set those variables. For more information about the policy variables and their interaction, see Section 6.4.5.5, “Audit Log Logging Configuration”. -
Property Value Command-Line Format --audit-log-read-buffer-size=#
System Variable audit_log_read_buffer_size
Scope (>= 8.0.12) Global, Session Scope (8.0.11) Global Dynamic (>= 8.0.12) Yes Dynamic (8.0.11) No SET_VAR
Hint AppliesNo Type Integer Default Value (>= 8.0.12) 32768
Default Value (8.0.11) 1048576
Minimum Value (>= 8.0.12) 32768
Minimum Value (8.0.11) 1024
Maximum Value 4194304
The buffer size for reading from the audit log file, in bytes. The
audit_log_read()
function reads no more than this many bytes. Log file reading is supported only for JSON log format. For more information, see Audit Log File Reading.As of MySQL 8.0.12, this variable has a default of 32KB and can be set at runtime. Each client should set its session value of
audit_log_read_buffer_size
appropriately for its use ofaudit_log_read()
. Prior to MySQL 8.0.12,audit_log_read_buffer_size
has a default of 1MB, affects all clients, and can be changed only at server startup. -
Property Value Command-Line Format --audit-log-rotate-on-size=#
System Variable audit_log_rotate_on_size
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type Integer Default Value 0
If the
audit_log_rotate_on_size
value is 0, the audit log plugin does not perform automatic log file rotation. Instead, useaudit_log_flush
to close and reopen the log on demand. In this case, manually rename the file externally to the server before flushing it.If the
audit_log_rotate_on_size
value is greater than 0, automatic size-based log file rotation occurs. Whenever a write to the log file causes its size to exceed theaudit_log_rotate_on_size
value, the audit log plugin closes the current log file, renames it, and opens a new log file.For more information about audit log file rotation, see Audit Log File Space Management and Name Rotation.
If you set this variable to a value that is not a multiple of 4096, it is truncated to the nearest multiple. (Thus, setting it to a value less than 4096 has the effect of setting it to 0 and no rotation occurs, except manually.)
-
Property Value Command-Line Format --audit-log-statement-policy=value
System Variable audit_log_statement_policy
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type Enumeration Default Value ALL
Valid Values ALL
ERRORS
NONE
NoteThis variable applies only to legacy mode audit log filtering (see Section 6.4.5.8, “Legacy Mode Audit Log Filtering”).
The policy controlling how the audit log plugin writes statement events to its log file. The following table shows the permitted values.
Value Description ALL
Log all statement events ERRORS
Log only failed statement events NONE
Do not log statement events NoteAt server startup, any explicit value given for
audit_log_statement_policy
may be overridden ifaudit_log_policy
is also specified, as described in Section 6.4.5.5, “Audit Log Logging Configuration”. -
Property Value Command-Line Format --audit-log-strategy=value
System Variable audit_log_strategy
Scope Global Dynamic No SET_VAR
Hint AppliesNo Type Enumeration Default Value ASYNCHRONOUS
Valid Values ASYNCHRONOUS
PERFORMANCE
SEMISYNCHRONOUS
SYNCHRONOUS
The logging method used by the audit log plugin. These strategy values are permitted:
-
ASYNCHRONOUS
: Log asynchronously. Wait for space in the output buffer. -
PERFORMANCE
: Log asynchronously. Drop requests for which there is insufficient space in the output buffer. -
SEMISYNCHRONOUS
: Log synchronously. Permit caching by the operating system. -
SYNCHRONOUS
: Log synchronously. Callsync()
after each request.
-
If the audit log plugin is enabled, it exposes several status variables that provide operational information. These variables are available for legacy mode audit filtering and JSON mode audit filtering.
-
The size of the current audit log file. The value increases when an event is written to the log and is reset to 0 when the log is rotated.
-
The size of the largest dropped event in performance logging mode. For a description of logging modes, see Section 6.4.5.5, “Audit Log Logging Configuration”.
-
The number of events handled by the audit log plugin, whether or not they were written to the log based on filtering policy (see Section 6.4.5.5, “Audit Log Logging Configuration”).
-
The number of events handled by the audit log plugin that were filtered (not written to the log) based on filtering policy (see Section 6.4.5.5, “Audit Log Logging Configuration”).
-
The number of events lost in performance logging mode because an event was larger than than the available audit log buffer space. This value may be useful for assessing how to set
audit_log_buffer_size
to size the buffer for performance mode. For a description of logging modes, see Section 6.4.5.5, “Audit Log Logging Configuration”. -
The number of events written to the audit log.
-
The total size of events written to all audit log files. Unlike
Audit_log_current_size
, the value ofAudit_log_total_size
increases even when the log is rotated. -
The number of times an event had to wait for space in the audit log buffer in asynchronous logging mode. For a description of logging modes, see Section 6.4.5.5, “Audit Log Logging Configuration”.
MySQL Enterprise Audit is subject to these general restrictions:
-
Only SQL statements are logged. Changes made by no-SQL APIs, such as memcached, Node.JS, and the NDB API, are not logged.
-
Only top-level statements are logged, not statements within stored programs such as triggers or stored procedures.
-
Contents of files referenced by statements such as
LOAD DATA
are not logged.
NDB Cluster. It is possible to use MySQL Enterprise Audit with MySQL NDB Cluster, subject to the following conditions:
-
All changes to be logged must be done using the SQL interface. Changes using no-SQL interfaces, such as those provided by the NDB API, memcached, or ClusterJ, are not logged.
-
The plugin must be installed on each MySQL server that is used to execute SQL on the cluster.
-
Audit plugin data must be aggregated amongst all MySQL servers used with the cluster. This aggregation is the responsibility of the application or user.
As of MySQL 8.0.14, the audit_api_message_emit
component enables applications to add their own message events to the audit log, using the audit_api_message_emit_udf()
user-defined function.
The audit_api_message_emit
component cooperates with all plugins of audit type. For concreteness, examples use the audit_log
plugin described in Section 6.4.5, “MySQL Enterprise Audit”.
To be usable by the server, the component library file must be located in the MySQL plugin directory (the directory named by the plugin_dir
system variable). If necessary, configure the plugin directory location by setting the value of plugin_dir
at server startup.
To install the audit_api_message_emit
component, use this statement:
INSTALL COMPONENT "file://component_audit_api_message_emit";
Component installation is a one-time operation that need not be done per server startup. INSTALL COMPONENT
loads the component, and also registers it in the mysql.component
system table to cause it to be loaded during subsequent server startups.
To uninstall the audit_api_message_emit
component, use this statement:
UNINSTALL COMPONENT "file://component_audit_api_message_emit";
UNINSTALL COMPONENT
unloads the component, and deregisters it from the mysql.component
system table to cause it not to be loaded during subsequent server startups.
Installing or uninstalling the audit_api_message_emit
component installs or uninstalls the audit_api_message_emit_udf()
function that the component implements. It is not necessary to use CREATE FUNCTION
or DROP FUNCTION
to do so.
This section describes the audit_api_message_emit_udf()
user-defined function (UDF) implemented by the audit_api_message_emit
component.
Before using the audit message function, install the audit message component according to the instructions provided at Installing or Uninstalling the Audit Message Component.
-
audit_api_message_emit_udf(
component
,producer
,message
[,key
,value
] ...)Adds a message event to the audit log. Message events include component, producer, and message strings of the caller's choosing, and optionally a set of key-value pairs.
An event posted by this UDF is sent to all enabled plugins of audit type, each of which handles the event according to its own rules. If no plugin of audit type is enabled, posting the event has no effect.
Arguments:
-
component
: A string that specifies a component name. -
producer
: A string that specifies a producer name. -
message
: A string that specifies the event message. -
key
,value
: Events may include 0 or more key-value pairs that specify an arbitrary application-provided data map. Eachkey
argument is a string that specifies a name for its immediately followingvalue
argument. Eachvalue
argument specifies a value for its immediately followingkey
argument. Eachvalue
can be a string or numeric value, orNULL
.
Return value:
The string
OK
to indicate success. An error occurs if the function fails.Example:
SELECT audit_api_message_emit_udf('component_text', 'producer_text', 'message_text', 'key1', 'value1', 'key2', 123, 'key3', NULL) AS 'Message'; Additional information:
Each audit plugin that receives an event posted by
audit_api_message_emit_udf()
logs the event in plugin-specific format. For example, theaudit_log
plugin (see Section 6.4.5, “MySQL Enterprise Audit”) logs message values as follows, depending on the log format configured by theaudit_log_format
system variable:-
JSON format (
audit_log_format=JSON
):{ ... "class": "message", "event": "user", ... "message_data": { "component": "component_text", "producer": "producer_text", "message": "message_text", "map": { "key1": "value1", "key2": 123, "key3": null } } }
-
New-style XML format (
audit_log_format=NEW
):<AUDIT_RECORD> ... <NAME>Message</NAME> ... <COMMAND_CLASS>user</COMMAND_CLASS> <COMPONENT>component_text</COMPONENT> <PRODUCER>producer_text</PRODUCER> <MESSAGE>message_text</MESSAGE> <MAP> <ELEMENT> <KEY>key1</KEY> <VALUE>value1</VALUE> </ELEMENT> <ELEMENT> <KEY>key2</KEY> <VALUE>123</VALUE> </ELEMENT> <ELEMENT> <KEY>key3</KEY> <VALUE/> </ELEMENT> </MAP> </AUDIT_RECORD>
-
Old-style XML format (
audit_log_format=OLD
):<AUDIT_RECORD ... NAME="Message" ... COMMAND_CLASS="user" COMPONENT="component_text" PRODUCER="producer_text" MESSAGE="message_text"/>
NoteMessage events logged in old-style XML format do not include the key-value map due to representational constraints imposed by this format.
Messages posted by
audit_api_message_emit_udf()
have an event class ofMYSQL_AUDIT_MESSAGE_CLASS
and a subclass ofMYSQL_AUDIT_MESSAGE_USER
. (Interally generated audit messages have the same class and a subclass ofMYSQL_AUDIT_MESSAGE_INTERNAL
; this subclass currently is unused.) To refer to such events inaudit_log
filtering rules, use aclass
element with aname
value ofmessage
. For example:{ "filter": { "class": { "name": "message" } } }
Should it be necessary to distinguish user-generated and internally generated message events, test the
subclass
value againstuser
orinternal
.Filtering based on the contents of the key-value map is not supported.
For information about writing filtering rules, see Section 6.4.5.6, “Audit Log Filtering”.
-
MySQL Enterprise Firewall is an extension included in MySQL Enterprise Edition, a commercial product. To learn more about commercial products, see https://www.mysql.com/products/.
MySQL Enterprise Edition includes MySQL Enterprise Firewall, an application-level firewall that enables database administrators to permit or deny SQL statement execution based on matching against whitelists of accepted statement patterns. This helps harden MySQL Server against attacks such as SQL injection or attempts to exploit applications by using them outside of their legitimate query workload characteristics.
Each MySQL account registered with the firewall has its own statement whitelist, enabling protection to be tailored per account. For a given account, the firewall can operate in recording, protecting, or detecting mode, for training in the accepted statement patterns, active protection against unacceptable statements, or passive detection of unacceptable statements. The diagram illustrates how the firewall processes incoming statements in each mode.
The following sections describe the components of MySQL Enterprise Firewall, discuss how to install and use it, and provide reference information for its components.
MySQL Enterprise Firewall is based on a plugin library that implements these components:
-
A server-side plugin named
MYSQL_FIREWALL
examines SQL statements before they execute and, based on its in-memory cache, renders a decision whether to execute or reject each statement. -
Server-side plugins named
MYSQL_FIREWALL_USERS
andMYSQL_FIREWALL_WHITELIST
implementINFORMATION_SCHEMA
tables that provide views into the firewall data cache. -
System tables named
firewall_users
andfirewall_whitelist
in themysql
database provide persistent storage of firewall data. -
Stored procedures named
sp_set_firewall_mode()
andsp_reload_firewall_rules()
perform tasks such as registering MySQL accounts with the firewall, establishing their operational mode, and managing transfer of firewall data between the cache and the underlying system tables. -
A set of user-defined functions provides an SQL-level API for lower-level tasks such as synchronizing the cache with the underlying system tables.
-
System variables enable firewall configuration and status variables provide runtime operational information.
-
FIREWALL_ADMIN
andFIREWALL_USER
privileges enable users to administer firewall rules for any user, and their own firewall rules, respectively.
MySQL Enterprise Firewall installation is a one-time operation that installs the components described in Section 6.4.7.1, “MySQL Enterprise Firewall Components”. Installation can be performed using a graphical interface or manually:
-
On Windows, MySQL Installer includes an option to enable MySQL Enterprise Firewall for you.
-
MySQL Workbench 6.3.4 or higher can install MySQL Enterprise Firewall, enable or disable an installed firewall, or uninstall the firewall.
-
Manual MySQL Enterprise Firewall installation involves running a script located in the
share
directory of your MySQL installation.
Read this entire section before following its instructions. Parts of the procedure differ depending on your environment.
If installed, MySQL Enterprise Firewall involves some minimal overhead even when disabled. To avoid this overhead, do not install the firewall unless you plan to use it.
For usage instructions, see Section 6.4.7.3, “Using MySQL Enterprise Firewall”. For reference information, see Section 6.4.7.4, “MySQL Enterprise Firewall Reference”.
If MySQL Enterprise Firewall is already installed from an older version of MySQL, uninstall it using the instructions given later in this section and then restart your server before installing the current version. In this case, it is also necessary to register your configuration again.
On Windows, you can use MySQL Installer to install MySQL Enterprise Firewall, as shown in Figure 6.2, “MySQL Enterprise Firewall Installation on Windows”. Check the Enable MySQL Enterprise Firewall check box. (Open Firewall port for network access has a different purpose. It refers to Windows Firewall and controls whether Windows blocks the TCP/IP port on which the MySQL server listens for client connections.)
There is an issue for MySQL 8.0.19 installed using MySQL Installer that prevents the server from starting if MySQL Enterprise Firewall is selected during the server configuration steps. If the server startup operation fails, click
The workaround is to run MySQL Installer without MySQL Enterprise Firewall selected. (That is, do not select the Enable MySQL Enterprise Firewall check box.) Then install MySQL Enterprise Firewall afterward using the instructions for manual installation later in this section. This problem is corrected in MySQL 8.0.20.
To install MySQL Enterprise Firewall using MySQL Workbench 6.3.4 or higher, see MySQL Enterprise Firewall Interface.
To install MySQL Enterprise Firewall manually, look in the share
directory of your MySQL installation and choose the
script that is appropriate for your platform. The available scripts differ in
the suffix used to refer to the plugin library file:
-
win_install_firewall.sql
: Choose this script for Windows systems that use.dll
as the file name suffix. -
linux_install_firewall.sql
: Choose this script for Linux and similar systems that use.so
as the file name suffix.
The installation script creates stored procedures in the default database, so
choose a database to use. Then run the script as follows, naming the chosen
database on the command line. The example here uses the mysql
database and the Linux installation script. Make the
appropriate substitutions for your system.
mysql -u root -p mysql < linux_install_firewall.sql (enter root password here)
To use MySQL Enterprise Firewall in the context of master/slave replication, Group Replication, or InnoDB cluster, you must prepare the slave or secondary nodes prior to running the installation script on the master or primary node. This is necessary because the INSTALL PLUGIN
statements in the script are not replicated.
-
On each slave or secondary node, extract the
INSTALL PLUGIN
statements from the installation script and execute them manually. -
On the master or primary node, run the installation script as described previously.
Installing MySQL Enterprise Firewall either using a graphical interface or manually should enable the firewall. To verify that, connect to the server and execute this statement:
mysql> SHOW GLOBAL VARIABLES LIKE 'mysql_firewall_mode';
+---------------------+-------+
| Variable_name | Value |
+---------------------+-------+
| mysql_firewall_mode | ON |
+---------------------+-------+
If the plugin fails to initialize, check the server error log for diagnostic messages.
MySQL Enterprise Firewall can be uninstalled using MySQL Workbench or manually.
To uninstall MySQL Enterprise Firewall using MySQL Workbench 6.3.4 or higher, see MySQL Enterprise Firewall Interface.
To uninstall MySQL Enterprise Firewall manually, execute the following statements. It is assumed that the stored procedures were created in the mysql
database. Adjust the DROP PROCEDURE
statements appropriately if the procedures were created in a different database.
DROP TABLE mysql.firewall_whitelist; DROP TABLE mysql.firewall_users; UNINSTALL PLUGIN mysql_firewall; UNINSTALL PLUGIN mysql_firewall_whitelist; UNINSTALL PLUGIN mysql_firewall_users; DROP FUNCTION set_firewall_mode; DROP FUNCTION normalize_statement; DROP FUNCTION read_firewall_whitelist; DROP FUNCTION read_firewall_users; DROP FUNCTION mysql_firewall_flush_status; DROP PROCEDURE mysql.sp_set_firewall_mode; DROP PROCEDURE mysql.sp_reload_firewall_rules;
Before using MySQL Enterprise Firewall, install it according to the instructions provided in Section 6.4.7.2, “Installing or Uninstalling MySQL Enterprise Firewall”.
This section describes how to configure MySQL Enterprise Firewall using SQL statements. Alternatively, MySQL Workbench 6.3.4 or higher provides a graphical interface for firewall control. See MySQL Enterprise Firewall Interface.
To enable or disable the firewall, set the mysql_firewall_mode
system variable. By default, this variable is enabled when the firewall is installed. To control the initial firewall state explicitly, you can set the variable at server startup. For example, to enable the firewall in an option file, use these lines:
[mysqld] mysql_firewall_mode=ON
It is also possible to disable or enable the firewall at runtime:
SET GLOBAL mysql_firewall_mode = OFF; SET GLOBAL mysql_firewall_mode = ON;
In addition to the global on/off firewall mode, each account registered with the firewall has its own operational mode. For an account in recording mode, the firewall learns an application's “fingerprint,” that is, the acceptable statement patterns that, taken together, form a whitelist. After training, switch the firewall to protecting mode to harden MySQL against access by statements that deviate from the fingerprint. For additional training, switch the firewall back to recording mode as necessary to update the whitelist with new statement patterns. An intrusion-detection mode is available that writes suspicious statements to the error log but does not deny access.
The firewall maintains whitelist rules on a per-account basis, enabling implementation of protection strategies such as these:
-
For an application that has unique protection requirements, configure it to use an account that is not used for any other purpose.
-
For applications that are related and share protection requirements, configure them as a group to use the same account.
Firewall operation is based on conversion of SQL statements to normalized digest form. Firewall digests are like the statement digests used by the Performance Schema (see Section 26.10, “Performance Schema Statement Digests and Sampling”). However, unlike the Performance Schema, the relevant digest-related system variable is max_digest_length
.
For a connection from a registered account, the firewall converts each incoming statement to normalized form and processes it according to the account mode:
-
In recording mode, the firewall adds the normalized statement to the account whitelist rules.
-
In protecting mode, the firewall compares the normalized statement to the account whitelist rules. If there is a match, the statement passes and the server continues to process it. Otherwise, the server rejects the statement and returns an error to the client. The firewall also writes the rejected statement to the error log if the
mysql_firewall_trace
system variable is enabled. -
In detecting mode, the firewall matches statements as in protecting mode, but writes nonmatching statements to the error log without denying access.
Accounts that have a mode of OFF
or are not registered with the firewall are ignored by it.
To protect an account using MySQL Enterprise Firewall, follow these steps:
-
Register the account and put it in recording mode.
-
Connect to the MySQL server using the registered account and execute statements to be learned. This establishes the account's whitelist of accepted statements.
-
Switch the registered account to protecting mode.
The following example shows how to register an account with the firewall, use the firewall to learn acceptable statements for that account, and protect the account against execution of unacceptable statements. The example account, 'fwuser'@'localhost'
, is for use by an application that accesses tables in the sakila
database. (This database is available at https://dev.mysql.com/doc/index-other.html.)
The user and host parts of the account name are quoted separately for statements such as CREATE USER
and GRANT
, whereas to specify an account for use with a firewall component, name it as a single quoted string 'fwuser@localhost'
.
The convention for naming accounts as a single quoted string for firewall components means that you cannot use accounts that have embedded @
characters in the user name.
Perform the steps in the following procedure using an administrative MySQL account, except those designated for execution by the account registered with the firewall. The default database should be sakila
for statements executed using the registered account.
-
If necessary, create the account to be protected (choose an appropriate password) and grant it privileges for the
sakila
database:CREATE USER 'fwuser'@'localhost' IDENTIFIED BY 'fWp@3sw0rd'; GRANT ALL ON sakila.* TO 'fwuser'@'localhost'; -
Use the
sp_set_firewall_mode()
stored procedure to register the account with the firewall and place it in recording mode (if the procedure is located in a database other thanmysql
, adjust the statement accordingly):mysql>
CALL mysql.sp_set_firewall_mode('fwuser@localhost', 'RECORDING');
During the course of its execution, the stored procedure invokes firewall user-defined functions, which may produce output of their own.
-
Using the registered account, connect to the server, then execute some statements that are legitimate for it:
SELECT first_name, last_name FROM customer WHERE customer_id = 1; UPDATE rental SET return_date = NOW() WHERE rental_id = 1; SELECT get_customer_balance(1, NOW()); The firewall converts the statements to digest form and records them in the account whitelist.
NoteUntil the account executes statements in recording mode, its whitelist is empty, which is equivalent to “deny all.” If switched to protecting mode, the account will be effectively prohibited from executing statements.
-
At this point, the user and whitelist information is cached and can be seen in the firewall
INFORMATION_SCHEMA
tables:SELECT MODE FROM INFORMATION_SCHEMA.MYSQL_FIREWALL_USERS WHERE USERHOST = 'fwuser@localhost'; SELECT RULE FROM INFORMATION_SCHEMA.MYSQL_FIREWALL_WHITELIST WHERE USERHOST = 'fwuser@localhost'; NoteThe
@@version_comment
rule comes from a statement sent automatically by the mysql client when you connect to the server as the registered user.It is important to train the firewall under conditions matching application use. For example, a given MySQL connector might send statements to the server at the beginning of a connection to determine server characteristics and capabilities. If an application normally is used through that connector, train the firewall that way, too. That enables those initial statements to become part of the whitelist for the account associated with the application.
-
Use the stored procedure to switch the registered user to protecting mode:
mysql>
CALL mysql.sp_set_firewall_mode('fwuser@localhost', 'PROTECTING');
ImportantSwitching the account out of
RECORDING
mode synchronizes its firewall cache data to the underlyingmysql
system database tables for persistent storage. If you do not switch the mode for a user who is being recorded, the cached whitelist data is not written to the system tables and will be lost when the server is restarted. -
Using the registered account, execute some acceptable and unacceptable statements. The firewall matches each one against the account whitelist and accepts or rejects it.
This statement is not identical to a training statement but produces the same normalized statement as one of them, so the firewall accepts it:
mysql>
SELECT first_name, last_name FROM customer WHERE customer_id = '48';
+------------+-----------+ | first_name | last_name | +------------+-----------+ | ANN | EVANS | +------------+-----------+These statements do not match anything in the whitelist and each results in an error:
SELECT first_name, last_name FROM customer WHERE customer_id = 1 OR TRUE; SHOW TABLES LIKE 'customer%'; TRUNCATE TABLE mysql.slow_log; The firewall also writes the rejected statements to the error log if the
mysql_firewall_trace
system variable is enabled. For example:[Note] Plugin MYSQL_FIREWALL reported: 'ACCESS DENIED for fwuser@localhost. Reason: No match in whitelist. Statement: TRUNCATE TABLE `mysql` . `slow_log` '
You can use these log messages in your efforts to identify the source of attacks.
-
You can log nonmatching statements as suspicious without denying access. To do this, put the account in intrusion-detecting mode:
mysql>
CALL mysql.sp_set_firewall_mode('fwuser@localhost', 'DETECTING');
-
Using the registered account, connect to the server, then execute a statement that does not match the whitelist:
mysql>
SHOW TABLES LIKE 'customer%';
+------------------------------+ | Tables_in_sakila (customer%) | +------------------------------+ | customer | | customer_list | +------------------------------+In detecting mode, the firewall permits the nonmatching statement to execute but writes a message to the error log:
[Note] Plugin MYSQL_FIREWALL reported: 'SUSPICIOUS STATEMENT from 'fwuser@localhost'. Reason: No match in whitelist. Statement: SHOW TABLES LIKE ? '
NoteDetection mode writes messages as Notes, which are information messages. To ensure that such messages appear in the error log and are not discarded, make sure that the
log_error_verbosity
system variable is set to a value of 3. -
To assess firewall activity, examine its status variables:
mysql>
SHOW GLOBAL STATUS LIKE 'Firewall%';
+----------------------------+-------+ | Variable_name | Value | +----------------------------+-------+ | Firewall_access_denied | 3 | | Firewall_access_granted | 4 | | Firewall_access_suspicious | 1 | | Firewall_cached_entries | 4 | +----------------------------+-------+The variables indicate the number of statements rejected, accepted, logged as suspicious, and added to the cache, respectively. The
Firewall_access_granted
count is 4 because of the@@version_comment
statement sent by the mysql client each of the three time you used it to connect as the registered user, plus theSHOW TABLES
statement that was not blocked inDETECTING
mode.
Should additional training for an account be necessary, switch it to recording mode again, then back to protecting mode after executing statements to be added to the whitelist.
The following discussion serves as a reference to MySQL Enterprise Firewall components:
MySQL Enterprise Firewall maintains account and whitelist information. It uses tables in the mysql
system database to store this data in persistent form, and INFORMATION_SCHEMA
tables to provide views into cached data. When enabled, the firewall bases its operational decisions on the cached data.
The mysql
tables can be accessed only by users with privileges for that database. The INFORMATION_SCHEMA
tables are accessible by anyone.
The mysql.firewall_users
table lists registered firewall accounts and their operational modes. The table has the following columns (with the corresponding INFORMATION_SCHEMA.MYSQL_FIREWALL_USERS
table having similar but not necessarily identical columns):
-
USERHOST
An account registered with the firewall. Each account has the format
and represents actual user and host names as authenticated by the server. Patterns and netmasks should not be used when registering users.user_name
@host_name
-
MODE
The current firewall operational mode for the account. The permitted mode values are
OFF
,DETECTING
,PROTECTING
,RECORDING
, andRESET
. For details about their meanings, see the description ofsp_set_firewall_mode()
in MySQL Enterprise Firewall Procedures and Functions.
The mysql.firewall_whitelist
table lists registered firewall accounts and their whitelists. The table has the following columns (with the corresponding INFORMATION_SCHEMA.MYSQL_FIREWALL_WHITELIST
table having similar but not necessarily identical columns):
-
USERHOST
An account registered with the firewall. The format is the same as for the user account tables.
-
RULE
A normalized statement indicating an acceptable statement pattern for the account. An account whitelist is the union of its rules.
-
ID
An integer column that is a primary key for the table. This column was added in MySQL 8.0.12.
MySQL Enterprise Firewall has stored procedures that perform tasks such as registering MySQL accounts with the firewall, establishing their operational mode, and managing transfer of firewall data between the cache and the underlying system tables. It also has a set of user-defined functions (UDFs) that provides an SQL-level API for lower-level tasks such as synchronizing the cache with the underlying system tables.
Under normal operation, the stored procedures implement the user interface. The UDFs are invoked by the stored procedures, not directly by users.
To invoke a stored procedure when the default database is not the database that contains the procedure, qualify the procedure name with the database name. For example:
user mode
The following list describes each firewall stored procedure and UDF:
-
sp_reload_firewall_rules(
user
)This stored procedure uses firewall UDFs to reset a registered account and reload the in-memory rules for it from the rules stored in the
mysql.firewall_whitelist
table. This procedure provides control over firewall operation for individual accounts.The
user
argument names the affected account, as a string in
format.user_name
@host_name
Example:
CALL mysql.sp_reload_firewall_rules('fwuser@localhost');
WarningThis procedure sets the account mode to
RESET
, which clears the account whitelist and sets its mode toOFF
. If the account mode was notOFF
prior to thesp_reload_firewall_rules()
call, usesp_set_firewall_mode()
to restore its previous mode after reloading the rules. For example, if the account was inPROTECTING
mode, that is no longer true after callingsp_reload_firewall_rules()
and you must set it toPROTECTING
again explicitly. -
sp_set_firewall_mode(
user
,mode
)This stored procedure registers a MySQL account with the firewall and establishes its operational mode. The procedure also invokes firewall UDFs as necessary to transfer firewall data between the cache and the underlying system tables. This procedure may be called even if the
mysql_firewall_mode
system variable isOFF
, although setting the mode for an account has no operational effect while the firewall is disabled.The
user
argument names the affected account, as a string in
format.user_name
@host_name
The
mode
is the operational mode for the user, as a string. These mode values are permitted:-
OFF
: Disable the firewall for the account. -
DETECTING
: Intrusion-detection mode: Write suspicious (nonmatching) statements to the error log but do not deny access. -
PROTECTING
: Protect the account by matching incoming statements against the account whitelist. -
RECORDING
: Training mode: Record acceptable statements for the account. Incoming statements that do not immediately fail with a syntax error are recorded to become part of the account whitelist rules. -
RESET
: Clear the account whitelist and set the account mode toOFF
.
Switching the mode for an account to any mode but
RECORDING
synchronizes the firewall cache data to the underlyingmysql
system database tables for persistent storage. Switching the mode fromOFF
toRECORDING
reloads the whitelist from themysql.firewall_whitelist
table into the cache.If an account has an empty whitelist, setting its mode to
PROTECTING
produces an error message that is returned in a result set, but not an SQL error:mysql>
CALL mysql.sp_set_firewall_mode('a@b','PROTECTING');
+----------------------------------------------------------------------+ | set_firewall_mode(arg_userhost, arg_mode) | +----------------------------------------------------------------------+ | ERROR: PROTECTING mode requested for a@b but the whitelist is empty. | +----------------------------------------------------------------------+ 1 row in set (0.02 sec) Query OK, 0 rows affected (0.02 sec) -
-
mysql_firewall_flush_status()
This UDF resets several firewall status variables to 0:
Firewall_access_denied Firewall_access_granted Firewall_access_suspicious
Example:
SELECT mysql_firewall_flush_status();
-
normalize_statement(
stmt
)This UDF normalizes an SQL statement into the digest form used for whitelist rules.
Example:
SELECT normalize_statement('SELECT * FROM t1 WHERE c1 > 2');
-
read_firewall_users(
user
,mode
)This aggregate UDF updates the firewall user cache through a
SELECT
statement on themysql.firewall_users
table.Example:
SELECT read_firewall_users('fwuser@localhost', 'RECORDING') FROM mysql.firewall_users;
-
read_firewall_whitelist(
user
,rule
)This aggregate UDF updates the recorded statement cache through a
SELECT
statement on themysql.firewall_whitelist
table.Example:
SELECT read_firewall_whitelist('fwuser@localhost', 'RECORDING') FROM mysql.firewall_whitelist;
-
set_firewall_mode(
user
,mode
)This UDF manages the user cache and establishes the user operational mode.
Example:
SELECT set_firewall_mode('fwuser@localhost', 'RECORDING');
MySQL Enterprise Firewall supports the following system variables. Use them to configure firewall operation. These variables are unavailable unless the firewall is installed (see Section 6.4.7.2, “Installing or Uninstalling MySQL Enterprise Firewall”).
-
Property Value Command-Line Format --mysql-firewall-mode[={OFF|ON}]
System Variable mysql_firewall_mode
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type Boolean Default Value ON
Whether MySQL Enterprise Firewall is enabled (the default) or disabled.
-
Property Value Command-Line Format --mysql-firewall-trace[={OFF|ON}]
System Variable mysql_firewall_trace
Scope Global Dynamic Yes SET_VAR
Hint AppliesNo Type Boolean Default Value OFF
Whether the MySQL Enterprise Firewall trace is enabled or disabled (the default). When
mysql_firewall_trace
is enabled, forPROTECTING
mode, the firewall writes rejected statements to the error log.
MySQL Enterprise Firewall supports the following status variables. Use them to obtain information about firewall operational status. These variables are unavailable unless the firewall is installed (see Section 6.4.7.2, “Installing or Uninstalling MySQL Enterprise Firewall”). Firewall status variables are set to 0 whenever the MYSQL_FIREWALL
plugin is installed or the server is started. Many of them are reset to zero by the mysql_firewall_flush_status()
UDF (see MySQL Enterprise Firewall Procedures and Functions).
-
The number of statements rejected by MySQL Enterprise Firewall.
-
The number of statements accepted by MySQL Enterprise Firewall.
-
The number of statements logged by MySQL Enterprise Firewall as suspicious for users who are in
DETECTING
mode. -
The number of statements recorded by MySQL Enterprise Firewall, including duplicates.
- 6.4.8.1 MySQL Enterprise Data Masking and De-Identification Components
- 6.4.8.2 Installing or Uninstalling MySQL Enterprise Data Masking and De-Identification
- 6.4.8.3 Using MySQL Enterprise Data Masking and De-Identification
- 6.4.8.4 MySQL Enterprise Data Masking and De-Identification User-Defined Function Reference
MySQL Enterprise Data Masking and De-Identification is an extension included in MySQL Enterprise Edition, a commercial product. To learn more about commercial products, https://www.mysql.com/products/.
As of MySQL 8.0.13, MySQL Enterprise Edition provides data masking and de-identification capabilities:
-
Transformation of existing data to mask it and remove identifying characteristics, such as changing all digits of a credit card number but the last four to
'X'
characters. -
Generation of random data, such as email addresses and payment card numbers.
The way that applications use these capabilities depends on the purpose for which the data will be used and who will access it:
-
Applications that use sensitive data may protect it by performing data masking and permitting use of partially masked data for client identification. Example: A call center may ask for clients to provide their last four Social Security number digits.
-
Applications that require properly formatted data, but not necessarily the original data, can synthesize sample data. Example: An application developer who is testing data validators but has no access to original data may synthesize random data with the same format.
Example 1:
Medical research facilities can hold patient data that comprises a mix of personal and medical data. This may include genetic sequences (long strings), test results stored in JSON format, and other data types. Although the data may be used mostly by automated analysis software, access to genome data or test results of particular patients is still possible. In such cases, data masking should be used to render this information not personally identifiable.
Example 2:
A credit card processor company provides a set of services using sensitive data, such as:
-
Processing a large number of financial transactions per second.
-
Storing a large amount of transaction-related data.
-
Protecting transaction-related data with strict requirements for personal data.
-
Handling client complaints about transactions using reversible or partially masked data.
A typical transaction may include many types of sensitive information, including:
-
Credit card number.
-
Transaction type and amount.
-
Merchant type.
-
Transaction cryptogram (to confirm transaction legitimacy).
-
Geolocation of GPS-equipped terminal (for fraud detection).
Those types of information may then be joined within a bank or other card-issuing financial institution with client personal data, such as:
-
Full client name (either person or company).
-
Address.
-
Date of birth.
-
Social Security number.
-
Email address.
-
Phone number.
Various employee roles within both the card processing company and the financial institution require access to that data. Some of these roles may require access only to masked data. Other roles may require access to the original data on a case-to-case basis, which is recorded in audit logs.
Masking and de-identification are core to regulatory compliance, so MySQL Enterprise Data Masking and De-Identification can help application developers satisfy privacy requirements:
-
PCI – DSS: Payment Card Data.
-
HIPAA: Privacy of Health Data, Health Information Technology for Economic and Clinical Health Act (HITECH Act).
-
EU General Data Protection Directive (GDPR): Protection of Personal Data.
-
Data Protection Act (UK): Protection of Personal Data.
-
Sarbanes Oxley, GLBA, The USA Patriot Act, Identity Theft and Assumption Deterrence Act of 1998.
-
FERPA – Student Data, NASD, CA SB1386 and AB 1950, State Data Protection Laws, Basel II.
The following sections describe the components of MySQL Enterprise Data Masking and De-Identification, discuss how to install and use it, and provide reference information for its components.
MySQL Enterprise Data Masking and De-Identification is based on a plugin library that implements these components:
-
A server-side plugin named
data_masking
. -
A set of user-defined functions (UDFs) provides an SQL-level API for performing masking and de-identification operations. Some of these functions require the
SUPER
privilege.
This section describes how to install or uninstall MySQL Enterprise Data Masking and De-Identification, which is implemented as a plugin library file containing a plugin and user-defined functions (UDFs). For general information about installing or uninstalling plugins and UDFs, see Section 5.6.1, “Installing and Uninstalling Plugins”, and Section 5.7.1, “Installing and Uninstalling User-Defined Functions”.
To be usable by the server, the plugin library file must be located in the MySQL plugin directory (the directory named by the plugin_dir
system variable). If necessary, configure the plugin directory location by setting the value of plugin_dir
at server startup.
The plugin library file base name is data_masking
. The file name suffix differs per platform (for example, .so
for Unix and Unix-like systems, .dll
for Windows).
To install the MySQL Enterprise Data Masking and De-Identification plugin and UDFs, use the INSTALL PLUGIN
and CREATE FUNCTION
statements (adjust the .so
suffix for your platform as necessary):
INSTALL PLUGIN data_masking SONAME 'data_masking.so'; CREATE FUNCTION gen_blacklist RETURNS STRING SONAME 'data_masking.so'; CREATE FUNCTION gen_dictionary RETURNS STRING SONAME 'data_masking.so'; CREATE FUNCTION gen_dictionary_drop RETURNS STRING SONAME 'data_masking.so'; CREATE FUNCTION gen_dictionary_load RETURNS STRING SONAME 'data_masking.so'; CREATE FUNCTION gen_range RETURNS INTEGER SONAME 'data_masking.so'; CREATE FUNCTION gen_rnd_email RETURNS STRING SONAME 'data_masking.so'; CREATE FUNCTION gen_rnd_pan RETURNS STRING SONAME 'data_masking.so'; CREATE FUNCTION gen_rnd_ssn RETURNS STRING SONAME 'data_masking.so'; CREATE FUNCTION gen_rnd_us_phone RETURNS STRING SONAME 'data_masking.so'; CREATE FUNCTION mask_inner RETURNS STRING SONAME 'data_masking.so'; CREATE FUNCTION mask_outer RETURNS STRING SONAME 'data_masking.so'; CREATE FUNCTION mask_pan RETURNS STRING SONAME 'data_masking.so'; CREATE FUNCTION mask_pan_relaxed RETURNS STRING SONAME 'data_masking.so'; CREATE FUNCTION mask_ssn RETURNS STRING SONAME 'data_masking.so';
If the plugin and UDFs are used on a master replication server, install them on all slave servers as well to avoid replication issues.
Once installed as just described, the plugin and UDFs remain installed until uninstalled. To remove them, use the UNINSTALL PLUGIN
and DROP FUNCTION
statements:
UNINSTALL PLUGIN data_masking; DROP FUNCTION gen_blacklist; DROP FUNCTION gen_dictionary; DROP FUNCTION gen_dictionary_drop; DROP FUNCTION gen_dictionary_load; DROP FUNCTION gen_range; DROP FUNCTION gen_rnd_email; DROP FUNCTION gen_rnd_pan; DROP FUNCTION gen_rnd_ssn; DROP FUNCTION gen_rnd_us_phone; DROP FUNCTION mask_inner; DROP FUNCTION mask_outer; DROP FUNCTION mask_pan; DROP FUNCTION mask_pan_relaxed; DROP FUNCTION mask_ssn;
Before using MySQL Enterprise Data Masking and De-Identification, install it according to the instructions provided at Section 6.4.8.2, “Installing or Uninstalling MySQL Enterprise Data Masking and De-Identification”.
To use MySQL Enterprise Data Masking and De-Identification in applications, invoke the functions that are appropriate for the operations you wish to perform. For detailed function descriptions, see Section 6.4.8.4, “MySQL Enterprise Data Masking and De-Identification User-Defined Function Reference”. This section demonstrates how to use the functions to carry out some representative tasks. It first presents an overview of the available functions, followed by some examples of how the functions might be used in real-world context:
MySQL provides general-purpose masking functions that mask arbitrary strings, and special-purpose masking functions that mask specific types of values.
General-Purpose Masking Functions
mask_inner()
and mask_outer()
are general-purpose functions that mask parts of arbitrary strings based on position within the string:
-
mask_inner()
masks the interior of its string argument, leaving the ends unmasked. Other arguments specify the sizes of the unmasked ends.SELECT mask_inner('This is a string', 5, 1); SELECT mask_inner('This is a string', 1, 5); -
mask_outer()
does the reverse, masking the ends of its string argument, leaving the interior unmasked. Other arguments specify the sizes of the masked ends.SELECT mask_outer('This is a string', 5, 1); SELECT mask_outer('This is a string', 1, 5);
By default, mask_inner()
and mask_outer()
use 'X'
as the masking character, but permit an optional masking-character argument:
SELECT mask_inner('This is a string', 5, 1, '*'); SELECT mask_outer('This is a string', 5, 1, '#');
Special-Purpose Masking Functions
Other masking functions expect a string argument representing a specific type of value and mask it to remove identifying characteristics.
The examples here supply function arguments using the random value generation functions that return the appropriate type of value. For more information about generation functions, see Generating Random Data with Specific Characteristics.
Payment card Primary Account Number masking. Masking functions provide strict and relaxed masking of Primary Account Numbers.
-
mask_pan()
masks all but the last four digits of the number:mysql>
SELECT mask_pan(gen_rnd_pan());
+-------------------------+ | mask_pan(gen_rnd_pan()) | +-------------------------+ | XXXXXXXXXXXX2461 | +-------------------------+ -
mask_pan_relaxed()
is similar but does not mask the first six digits that indicate the payment card issuer unmasked:mysql>
SELECT mask_pan_relaxed(gen_rnd_pan());
+---------------------------------+ | mask_pan_relaxed(gen_rnd_pan()) | +---------------------------------+ | 770630XXXXXX0807 | +---------------------------------+
US Social Security number masking. mask_ssn()
masks all but the last four digits of the number:
mysql> SELECT mask_ssn(gen_rnd_ssn());
+-------------------------+
| mask_ssn(gen_rnd_ssn()) |
+-------------------------+
| XXX-XX-1723 |
+-------------------------+
Several functions generate random values. These values can be used for testing, simulation, and so forth.
gen_range()
returns a random integer selected from a given range:
mysql> SELECT gen_range(1, 10);
+------------------+
| gen_range(1, 10) |
+------------------+
| 6 |
+------------------+
gen_rnd_email()
returns a random email address in the example.com
domain:
mysql> SELECT gen_rnd_email();
+---------------------------+
| gen_rnd_email() |
+---------------------------+
| ayxnq.xmkpvvy@example.com |
+---------------------------+
gen_rnd_pan()
returns a random payment card Primary Account Number:
mysql> SELECT gen_rnd_pan();
(The gen_rnd_pan()
function result is not shown because its return values should be used only for testing purposes, and not for publication. It cannot be guaranteed the number is not assigned to a legitimate payment account.)
gen_rnd_ssn()
returns a random US Social Security number with the first and second parts each chosen from a range not used for legitimate numbers:
mysql> SELECT gen_rnd_ssn();
+---------------+
| gen_rnd_ssn() |
+---------------+
| 912-45-1615 |
+---------------+
gen_rnd_us_phone()
returns a random US phone number in the 555 area code not used for legitimate numbers:
mysql> SELECT gen_rnd_us_phone();
+--------------------+
| gen_rnd_us_phone() |
+--------------------+
| 1-555-747-5627 |
+--------------------+
MySQL Enterprise Data Masking and De-Identification enables dictionaries to be used as sources of random values. To use a dictionary, it must first be loaded from a file and given a name. Each loaded dictionary becomes part of the dictionary registry. Items then can be selected from registered dictionaries and used as random values or as replacements for other values.
A valid dictionary file has these characteristics:
-
The file contents are plain text, one term per line.
-
Empty lines are ignored.
-
The file must contain at least one term.
Suppose that a file named de_cities.txt
contains these city names in Germany:
Berlin Munich Bremen
Also suppose that a file named us_cities.txt
contains these city names in the United States:
Chicago Houston Phoenix El Paso Detroit
Assume that the secure_file_priv
system variable is set to /usr/local/mysql/mysql-files
. In that case, copy the dictionary files to that directory so that the MySQL server can access them. Then use gen_dictionary_load()
to load the dictionaries into the dictionary registry and assign them names:
SELECT gen_dictionary_load('/usr/local/mysql/mysql-files/de_cities.txt', 'DE_Cities'); SELECT gen_dictionary_load('/usr/local/mysql/mysql-files/us_cities.txt', 'US_Cities');
To select a random term from a dictionary, use gen_dictionary()
:
SELECT gen_dictionary('DE_Cities'); SELECT gen_dictionary('US_Cities');
To select a random term from multiple dictionaries, randomly select one of the dictionaries, then select a term from it:
SELECT gen_dictionary(ELT(gen_range(1,2), 'DE_Cities', 'US_Cities')); SELECT gen_dictionary(ELT(gen_range(1,2), 'DE_Cities', 'US_Cities'));
The gen_blacklist()
function enables a term from one dictionary to be replaced by a term from another dictionary, which effects masking by substitution. Its arguments are the term to replace, the dictionary in which the term appears, and the dictionary from which to choose a replacement. For example, to substitute a US city for a German city, or vice versa, use gen_blacklist()
like this:
SELECT gen_blacklist('Munich', 'DE_Cities', 'US_Cities'); SELECT gen_blacklist('El Paso', 'US_Cities', 'DE_Cities');
If the term to replace is not in the first dictionary, gen_blacklist()
returns it unchanged:
mysql> SELECT gen_blacklist('Moscow', 'DE_Cities', 'US_Cities');
+---------------------------------------------------+
| gen_blacklist('Moscow', 'DE_Cities', 'US_Cities') |
+---------------------------------------------------+
| Moscow |
+---------------------------------------------------+
At customer-service call centers, one common identity verification technique is to ask customers to provide their last four Social Security number (SSN) digits. For example, a customer might say her name is Joanna Bond and that her last four SSN digits are 0007
.
Suppose that a customer
table containing customer records has these columns:
-
id
: Customer ID number. -
first_name
: Customer first name. -
last_name
: Customer last name. -
ssn
: Customer Social Security number.
For example, the table might be defined as follows:
CREATE TABLE customer ( id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, first_name VARCHAR(40), last_name VARCHAR(40), ssn VARCHAR(11) );
The application used by customer-service representatives to check the customer SSN might execute a query like this:
SELECT id, ssn FROM customer WHERE first_name = 'Joanna' AND last_name = 'Bond';
However, that exposes the SSN to the customer-service representative, who has no need to see anything but the last four digits. Instead, the application can use this query to display only the masked SSN:
SELECT id, mask_ssn(CONVERT(ssn USING binary)) AS masked_ssn FROM customer WHERE first_name = 'Joanna' AND last_name = 'Bond';
Now the representative sees only what is necessary, and customer privacy is preserved.
Why was the CONVERT()
function used for the argument to mask_ssn()
? Because mask_ssn()
requires an argument of length 11. Thus, even though ssn
is defined as VARCHAR(11)
, if the ssn
column has a multibyte character set, it may appear to be longer than 11 bytes when passed to a UDF, and an error occurs. Converting the value to a binary string ensures that the UDF sees an argument of length 11.
A similar technique may be needed for other data masking functions when string arguments do not have a single-byte character set.
If masked data from a table is used for multiple queries, it may be convenient to define a view that produces masked data. That way, applications can select from the view without performing masking in individual queries.
For example, a masking view on the customer
table from the previous section can be defined like this:
CREATE VIEW masked_customer AS SELECT id, first_name, last_name, mask_ssn(CONVERT(ssn USING binary)) AS masked_ssn FROM customer;
Then the query to look up a customer becomes simpler but still returns masked data:
SELECT id, masked_ssn FROM masked_customer WHERE first_name = 'Joanna' AND last_name = 'Bond';
The MySQL Enterprise Data Masking and De-Identification plugin library includes several user-defined functions (UDFs), which may be grouped into these categories:
As of MySQL 8.0.19, these UDFs support the single-byte latin1
character set for string arguments and return values. Prior to MySQL 8.0.19, the UDFs treat string arguments as binary strings (which means they do not distinguish lettercase), and string return values are binary strings. You can see the difference in return value character set as follows:
MySQL 8.0.19 and higher:
mysql> SELECT CHARSET(gen_rnd_email());
+--------------------------+
| CHARSET(gen_rnd_email()) |
+--------------------------+
| latin1 |
+--------------------------+
Prior to MySQL 8.0.19:
mysql> SELECT CHARSET(gen_rnd_email());
+--------------------------+
| CHARSET(gen_rnd_email()) |
+--------------------------+
| binary |
+--------------------------+
For any version, if a string return value should be in a different character set, convert it. The following example shows how to convert the result of gen_rnd_email()
to the utf8mb4
character set:
SET @email = CONVERT(gen_rnd_email() USING utf8mb4);
It may also be necessary to convert string arguments, as illustrated in Using Masked Data for Customer Identification.
Each function in this section performs a masking operation on its string argument and returns the masked result.
-
mask_inner(
str
,margin1
,margin2
[,mask_char
])Masks the interior part of a string, leaving the ends untouched, and returns the result. An optional masking character can be specified.
Arguments:
-
str
: The string to mask. -
margin1
: A nonnegative integer that specifies the number of characters on the left end of the string to remain unmasked. If the value is 0, no left end characters remain unmasked. -
margin2
: A nonnegative integer that specifies the number of characters on the right end of the string to remain unmasked. If the value is 0, no right end characters remain unmasked. -
mask_char
: (Optional) The single character to use for masking. The default is'X'
ifmask_char
is not given.The masking character must be a single-byte character. Attempts to use a multibyte character produce an error.
Return value:
The masked string, or
NULL
if either margin is negative.If the sum of the margin values is larger than the argument length, no masking occurs and the argument is returned unchanged.
Example:
SELECT mask_inner('abcdef', 1, 2), mask_inner('abcdef',0, 5); SELECT mask_inner('abcdef', 1, 2, '*'), mask_inner('abcdef',0, 5, '#'); -
-
mask_outer(
str
,margin1
,margin2
[,mask_char
])Masks the left and right ends of a string, leaving the interior unmasked, and returns the result. An optional masking character can be specified.
Arguments:
-
str
: The string to mask. -
margin1
: A nonnegative integer that specifies the number of characters on the left end of the string to mask. If the value is 0, no left end characters are masked. -
margin2
: A nonnegative integer that specifies the number of characters on the right end of the string to mask. If the value is 0, no right end characters are masked. -
mask_char
: (Optional) The single character to use for masking. The default is'X'
ifmask_char
is not given.The masking character must be a single-byte character. Attempts to use a multibyte character produce an error.
Return value:
The masked string, or
NULL
if either margin is negative.If the sum of the margin values is larger than the argument length, the entire argument is masked.
Example:
SELECT mask_outer('abcdef', 1, 2), mask_outer('abcdef',0, 5); SELECT mask_outer('abcdef', 1, 2, '*'), mask_outer('abcdef',0, 5, '#'); -
-
Masks a payment card Primary Account Number and returns the number with all but the last four digits replaced by
'X'
characters.Arguments:
-
str
: The string to mask. The string must be a suitable length for the Primary Account Number, but is not otherwise checked.
Return value:
The masked payment number as a string. If the argument is shorter than required, it is returned unchanged.
Example:
SELECT mask_pan(gen_rnd_pan()); SELECT mask_pan(gen_rnd_pan(19)); SELECT mask_pan('a*Z'); -
-
Masks a payment card Primary Account Number and returns the number with all but the first six and last four digits replaced by
'X'
characters. The first six digits indicate the payment card issuer.Arguments:
-
str
: The string to mask. The string must be a suitable length for the Primary Account Number, but is not otherwise checked.
Return value:
The masked payment number as a string. If the argument is shorter than required, it is returned unchanged.
Example:
SELECT mask_pan_relaxed(gen_rnd_pan()); SELECT mask_pan_relaxed(gen_rnd_pan(19)); SELECT mask_pan_relaxed('a*Z'); -
-
Masks a US Social Security number and returns the number with all but the last four digits replaced by
'X'
characters.Arguments:
-
str
: The string to mask. The string must be 11 characters long, but is not otherwise checked.
Return value:
The masked Social Security number as a string, or
NULL
if the argument is not the correct length.Example:
SELECT mask_ssn('909-63-6922'), mask_ssn('abcdefghijk'); SELECT mask_ssn('909'); -
The functions in this section generate random values for different types of data. When possible, generated values have characteristics reserved for demonstration or test values, to avoid having them mistaken for legitimate data. For example, gen_rnd_us_phone()
returns a US phone number that uses the 555 area code, which is not assigned to phone numbers in actual use. Individual function descriptions describe any exceptions to this principle.
-
Generates a random number chosen from a specified range.
Arguments:
-
lower
: An integer that specifies the lower boundary of the range. -
upper
: An integer that specifies the upper boundary of the range, which must not be less than the lower boundary.
Return value:
A random integer in the range from
lower
toupper
, inclusive, orNULL
if theupper
argument is less thanlower
.Example:
SELECT gen_range(100, 200), gen_range(-1000, -800); SELECT gen_range(1, 0); -
-
Generates a random email address in the
example.com
domain.Arguments:
None.
Return value:
A random email address as a string.
Example:
mysql>
SELECT gen_rnd_email();
+---------------------------+ | gen_rnd_email() | +---------------------------+ | ijocv.mwvhhuf@example.com | +---------------------------+ -
Generates a random payment card Primary Account Number. The number passes the Luhn check (an algorithm that performs a checksum verification against a check digit).
WarningValues returned from
gen_rnd_pan()
should be used only for test purposes, and are not suitable for publication. There is no way to guarantee that a given return value is not assigned to a legitimate payment account. Should it be necessary to publish agen_rnd_pan()
result, consider masking it withmask_pan()
ormask_pan_relaxed()
.Arguments:
-
size
: (Optional) An integer that specifies the size of the result. The default is 16 ifsize
is not given. If given,size
must be an integer in the range from 12 to 19.
Return value:
A random payment number as a string, or
NULL
if asize
argument outside the permitted range is given.Example:
SELECT mask_pan(gen_rnd_pan()); SELECT mask_pan(gen_rnd_pan(19)); SELECT mask_pan_relaxed(gen_rnd_pan()); SELECT mask_pan_relaxed(gen_rnd_pan(19)); SELECT gen_rnd_pan(11), gen_rnd_pan(20); -
-
Generates a random US Social Security number in
format. TheAAA
-BB
-CCCC
AAA
part is greater than 900 and theBB
part is less than 70, which are characteristics not used for legitimate Social Security numbers.Arguments:
None.
Return value:
A random Social Security number as a string.
Example:
mysql>
SELECT gen_rnd_ssn();
+---------------+ | gen_rnd_ssn() | +---------------+ | 951-26-0058 | +---------------+ -
Generates a random US phone number in
1-555-
format. The 555 area code is not used for legitimate phone numbers.AAA
-BBBB
Arguments:
None.
Return value:
A random US phone number as a string.
Example:
mysql>
SELECT gen_rnd_us_phone();
+--------------------+ | gen_rnd_us_phone() | +--------------------+ | 1-555-682-5423 | +--------------------+
The functions in this section manipulate dictionaries of terms and perform generation and masking operations based on them. Some of these functions require the SUPER
privilege.
When a dictionary is loaded, it becomes part of the dictionary registry and is assigned a name to be used by other dictionary functions. Dictionaries are loaded from plain text files containing one term per line. Empty lines are ignored. To be valid, a dictionary file must contain at least one nonempty line.
-
gen_blacklist(
str
,dictionary_name
,replacement_dictionary_name
)Replaces a term present in one dictionary with a term from a second dictionary and returns the replacement term. This masks the original term by substitution.
Arguments:
-
str
: A string that indicates the term to replace. -
dictionary_name
: A string that names the dictionary containing the term to replace. -
replacement_dictionary_name
: A string that names the dictionary from which to choose the replacement term.
Return value:
A string randomly chosen from
replacement_dictionary_name
as a replacement forstr
, orstr
if it does not appear indictionary_name
, orNULL
if either dictionary name is not in the dictionary registry.If the term to replace appears in both dictionaries, it is possible for the return value to be the same term.
Example:
mysql>
SELECT gen_blacklist('Berlin', 'DE_Cities', 'US_Cities');
+---------------------------------------------------+ | gen_blacklist('Berlin', 'DE_Cities', 'US_Cities') | +---------------------------------------------------+ | Phoenix | +---------------------------------------------------+ -
-
gen_dictionary(
dictionary_name
)Returns a random term from a dictionary.
Arguments:
-
dictionary_name
: A string that names the dictionary from which to choose the term.
Return value:
A random term from the dictionary as a string, or
NULL
if the dictionary name is not in the dictionary registry.Example:
SELECT gen_dictionary('mydict'); SELECT gen_dictionary('no-such-dict'); -
-
gen_dictionary_drop(
dictionary_name
)Removes a dictionary from the dictionary registry.
This function requires the
SUPER
privilege.Arguments:
-
dictionary_name
: A string that names the dictionary to remove from the dictionary registry.
Return value:
A string that indicates whether the drop operation succeeded.
Dictionary removed
indicates success.Dictionary removal error
indicates failure.Example:
SELECT gen_dictionary_drop('mydict'); SELECT gen_dictionary_drop('no-such-dict'); -
-
gen_dictionary_load(
dictionary_path
,dictionary_name
)Loads a file into the dictionary registry and assigns the dictionary a name to be used with other functions that require a dictionary name argument.
This function requires the
SUPER
privilege.ImportantDictionaries are not persistent. Any dictionary used by applications must be loaded for each server startup.
Once loaded into the registry, a dictionary is used as is, even if the underlying dictionary file changes. To reload a dictionary, first drop it with
gen_dictionary_drop()
, then load it again withgen_dictionary_load()
.Arguments:
-
dictionary_path
: A string that specifies the path name of the dictionary file. -
dictionary_name
: A string that provides a name for the dictionary.
Return value:
A string that indicates whether the load operation succeeded.
Dictionary load success
indicates success.Dictionary load error
indicates failure. Dictionary load failure can occur for several reasons, including:-
A dictionary with the given name is already loaded.
-
The dictionary file is not found.
-
The dictionary file contains no terms.
-
The
secure_file_priv
system variable is set and the dictionary file is not located in the directory named by the variable.
Example:
SELECT gen_dictionary_load('/usr/local/mysql/mysql-files/mydict','mydict'); SELECT gen_dictionary_load('/dev/null','null'); -
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
2017-03-13 windows server 2003R2\2008R2\2012\2016 安装【故障转移群集】cluster