diff --git a/mariadb/CHANGELOG.md b/mariadb/CHANGELOG.md index 7718645..22803f0 100644 --- a/mariadb/CHANGELOG.md +++ b/mariadb/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## 2.0 + +- Pin add-on to Alpine Linux 3.11 +- Redirect MariaDB error log to add-on logs +- Remove grant & host options +- Add support for the mysql service +- Use a more secure default on install +- Skip DNS name resolving +- Improve integrity checks and recovery +- Tune MariaDB for lower memory usage +- Close port 3306 by default +- Ensure a proper collation set is used +- Adds database upgrade process during startup +- Change default configuration username from "hass" to "homeassistant" + ## 1.3 - Update from bash to bashio diff --git a/mariadb/Dockerfile b/mariadb/Dockerfile index 4ed0e17..dbd3964 100644 --- a/mariadb/Dockerfile +++ b/mariadb/Dockerfile @@ -5,7 +5,11 @@ FROM $BUILD_FROM ENV LANG C.UTF-8 # Setup base -RUN apk add --no-cache mariadb mariadb-client +RUN apk add --no-cache \ + mariadb \ + mariadb-client \ + mariadb-server-utils \ + pwgen # Copy data COPY data/run.sh / diff --git a/mariadb/README.md b/mariadb/README.md index d12c371..d0dd4ba 100644 --- a/mariadb/README.md +++ b/mariadb/README.md @@ -34,14 +34,11 @@ Example add-on configuration: databases: - homeassistant logins: - - username: hass - host: "%" - password: + - username: homeassistant + password: PASSWORD rights: - - username: hass - host: "%" + - username: homeassistant database: homeassistant - grant: ALL PRIVILEGES ON ``` ### Option: `databases` (required) @@ -54,11 +51,7 @@ This section defines a create user definition in MariaDB. [Create User][createus ### Option: `logins.username` (required) -Database user login, e.g., `hass`. [User Name][username] documentation. - -### Option: `logins.host` (required) - -Hostname allowed to connect to database. [Host Name][hostname] documentation. +Database user login, e.g., `homeassistant`. [User Name][username] documentation. ### Option: `logins.password` (required) @@ -72,18 +65,10 @@ This section grant privileges to users in MariaDB. [Grant][grant] documentation. This should be the same user name defined in `logins` -> `username`. -### Option: `rights.host` (required) - -This should be the same hostname defined in `logins` -> `host`. - ### Option: `rights.database` (required) This should be the same database defined in `databases`. -### Option: `rights.grant` (required) - -This is the grant statement giving your user access to the database. - ## Home Assistant Configuration MariaDB will be used by the `recorder` and `history` components within Home Assistant. For more information about setting this up, see the [MariaDB][mariadb-hass] documentation for Home Assistant. @@ -92,7 +77,7 @@ Example Home Assistant configuration: ```yaml recorder: - db_url: mysql://hass:password@core-mariadb/homeassistant?charset=utf8 + db_url: mysql://homeassistant:password@core-mariadb/homeassistant?charset=utf8 ``` ## Support diff --git a/mariadb/build.json b/mariadb/build.json new file mode 100644 index 0000000..460c6cd --- /dev/null +++ b/mariadb/build.json @@ -0,0 +1,9 @@ +{ + "build_from": { + "aarch64": "homeassistant/aarch64-base:3.11", + "amd64": "homeassistant/amd64-base:3.11", + "armhf": "homeassistant/armhf-base:3.11", + "armv7": "homeassistant/armv7-base:3.11", + "i386": "homeassistant/i386-base:3.11" + } +} diff --git a/mariadb/config.json b/mariadb/config.json index 2a9dc45..71ed23d 100644 --- a/mariadb/config.json +++ b/mariadb/config.json @@ -1,33 +1,30 @@ { "name": "MariaDB", - "version": "1.3", + "version": "2.0", "slug": "mariadb", "description": "An SQL database server", "url": "https://github.com/home-assistant/hassio-addons/tree/master/mariadb", "arch": ["armhf", "armv7", "aarch64", "amd64", "i386"], "startup": "system", "boot": "auto", + "services": ["mysql:provide"], "ports": { - "3306/tcp": 3306 + "3306/tcp": null }, "options": { "databases": ["homeassistant"], - "logins": [{ "username": "hass", "host": "%", "password": null }], + "logins": [{ "username": "homeassistant", "password": null }], "rights": [ { - "username": "hass", - "host": "%", - "database": "homeassistant", - "grant": "ALL PRIVILEGES ON" + "username": "homeassistant", + "database": "homeassistant" } ] }, "schema": { "databases": ["str"], - "logins": [{ "username": "str", "host": "str", "password": "str" }], - "rights": [ - { "username": "str", "host": "str", "database": "str", "grant": "str" } - ] + "logins": [{ "username": "str", "password": "str" }], + "rights": [{ "username": "str", "database": "str" }] }, "image": "homeassistant/{arch}-addon-mariadb", "timeout": 20 diff --git a/mariadb/data/mariadb-server.cnf b/mariadb/data/mariadb-server.cnf index 7e67d2d..4cc925a 100644 --- a/mariadb/data/mariadb-server.cnf +++ b/mariadb/data/mariadb-server.cnf @@ -1,10 +1,40 @@ - -[server] - [mysqld] +port=3306 +log_error=mariadb.err +# Persistent storage location datadir=/data/databases -[galera] +# Use a proper collation set +character-set-server = utf8mb4 +collation-server = utf8mb4_unicode_ci -[mariadb] +# Do not resolve DNS names +skip-name-resolve + +# Tune for low-end devices (Like a Raspberry Pi) +key_buffer_size = 16M +max_connections = 64 +myisam_recover_options = FORCE +myisam_sort_buffer_size = 8M +net_buffer_length = 16K +read_buffer_size = 256K +read_rnd_buffer_size = 512K +sort_buffer_size = 512K +join_buffer_size = 128K +table_open_cache = 64 +thread_cache_size = 8 +thread_stack = 192K +tmp_table_size = 16M + +# Disable query cache +query_cache_limit = 1M +query_cache_size = 0M +query_cache_type = 0 + +# InnoDB Tweaks +innodb_buffer_pool_instances = 1 +innodb_buffer_pool_size = 64M +innodb_log_buffer_size = 8M +innodb_log_file_size = 48M +max_binlog_size = 96M diff --git a/mariadb/data/run.sh b/mariadb/data/run.sh index f8f6709..593cd7c 100755 --- a/mariadb/data/run.sh +++ b/mariadb/data/run.sh @@ -2,18 +2,24 @@ set -e MARIADB_DATA=/data/databases +NEW_INSTALL=false # Init mariadb if ! bashio::fs.directory_exists "${MARIADB_DATA}"; then bashio::log.info "Create a new mariadb initial system" - mysql_install_db --user=root --datadir="$MARIADB_DATA" > /dev/null + mysql_install_db --user=root --datadir="${MARIADB_DATA}" --skip-name-resolve --skip-test-db > /dev/null + NEW_INSTALL=true else bashio::log.info "Using existing mariadb initial system" fi +# Redirect log output +rm -f /data/databases/mariadb.err +ln -s /proc/1/fd/1 /data/databases/mariadb.err + # Start mariadb bashio::log.info "Starting MariaDB" -mysqld_safe --datadir="$MARIADB_DATA" --user=root --skip-log-bin < /dev/null & +mysqld_safe --datadir="${MARIADB_DATA}" --user=root < /dev/null & MARIADB_PID=$! # Wait until DB is running @@ -22,29 +28,52 @@ while ! mysql -e "" 2> /dev/null; do done bashio::log.info "Check data integrity and fix corruptions" -mysqlcheck --no-defaults --check-upgrade --auto-repair --databases mysql --skip-write-binlog > /dev/null || true -mysqlcheck --no-defaults --all-databases --fix-db-names --fix-table-names --skip-write-binlog > /dev/null || true -mysqlcheck --no-defaults --check-upgrade --all-databases --auto-repair --skip-write-binlog > /dev/null || true +mysqlcheck --no-defaults --databases mysql --fix-db-names --fix-table-names || true +mysqlcheck --no-defaults --databases mysql --check --check-upgrade --auto-repair || true +mysqlcheck --no-defaults --all-databases --skip-database=mysql --fix-db-names --fix-table-names || true +mysqlcheck --no-defaults --all-databases --skip-database=mysql --check --check-upgrade --auto-repair || true + +bashio::log.info "Ensuring internal database upgrades are performed" +mysql_upgrade --silent + +# Set default secure values after inital setup +if bashio::var.true "${NEW_INSTALL}"; then + # Secure the installation. + mysql <<-EOSQL + SET @@SESSION.SQL_LOG_BIN=0; + DELETE FROM + mysql.user + WHERE + user NOT IN ('mysql.sys', 'mysqlxsys', 'root', 'mysql', 'proxies_priv') + OR host NOT IN ('localhost'); + DELETE FROM + mysql.proxies_priv + WHERE + user NOT IN ('mysql.sys', 'mysqlxsys', 'root', 'mysql', 'proxies_priv') + OR host NOT IN ('localhost'); + DROP DATABASE IF EXISTS test; + FLUSH PRIVILEGES; +EOSQL +fi # Init databases -bashio::log.info "Init custom database" -for line in $(bashio::config "databases"); do - bashio::log.info "Create database $line" - mysql -e "CREATE DATABASE $line;" 2> /dev/null || true +bashio::log.info "Ensure databases exists" +for database in $(bashio::config "databases"); do + bashio::log.info "Create database ${database}" + mysql -e "CREATE DATABASE ${database};" 2> /dev/null || true done # Init logins -bashio::log.info "Init/Update users" +bashio::log.info "Ensure users exists and are updated" for login in $(bashio::config "logins|keys"); do USERNAME=$(bashio::config "logins[${login}].username") PASSWORD=$(bashio::config "logins[${login}].password") - HOST=$(bashio::config "logins[${login}].host") - if mysql -e "SET PASSWORD FOR '$USERNAME'@'$HOST' = PASSWORD('$PASSWORD');" 2> /dev/null; then - bashio::log.info "Update user $USERNAME" + if mysql -e "SET PASSWORD FOR '${USERNAME}'@'%' = PASSWORD('${PASSWORD}');" 2> /dev/null; then + bashio::log.info "Update user ${USERNAME}" else - bashio::log.info "Create user $USERNAME" - mysql -e "CREATE USER '$USERNAME'@'$HOST' IDENTIFIED BY '$PASSWORD';" 2> /dev/null || true + bashio::log.info "Create user ${USERNAME}" + mysql -e "CREATE USER '${USERNAME}'@'%' IDENTIFIED BY '${PASSWORD}';" 2> /dev/null || true fi done @@ -52,18 +81,44 @@ done bashio::log.info "Init/Update rights" for right in $(bashio::config "rights|keys"); do USERNAME=$(bashio::config "rights[${right}].username") - HOST=$(bashio::config "rights[${right}].host") DATABASE=$(bashio::config "rights[${right}].database") - GRANT=$(bashio::config "rights[${right}].grant") - bashio::log.info "Alter rights for $USERNAME@$HOST - $DATABASE" - mysql -e "GRANT $GRANT $DATABASE.* TO '$USERNAME'@'$HOST';" 2> /dev/null || true + bashio::log.info "Alter rights for ${USERNAME} to ${DATABASE}" + mysql -e "GRANT ALL PRIVILEGES ON ${DATABASE}.* TO '${USERNAME}'@'%';" 2> /dev/null || true done +# Generate service user +if ! bashio::fs.file_exists "/data/secret"; then + pwgen 64 1 > /data/secret +fi +SECRET=$( /dev/null || true +mysql -e "CREATE USER 'service'@'172.30.33.%' IDENTIFIED BY '${SECRET}';" 2> /dev/null || true +mysql -e "GRANT ALL PRIVILEGES ON *.* TO 'service'@'172.30.32.%' WITH GRANT OPTION;" 2> /dev/null || true +mysql -e "GRANT ALL PRIVILEGES ON *.* TO 'service'@'172.30.33.%' WITH GRANT OPTION;" 2> /dev/null || true + +# Flush privileges +mysql -e "FLUSH PRIVILEGES;" 2> /dev/null || true + +# Send service information to the Supervisor +PAYLOAD=$(\ + bashio::var.json \ + host "$(hostname)" \ + port "^3306" \ + username "service" \ + password "${SECRET}" +) +if bashio::services.publish "mysql" "${PAYLOAD}"; then + bashio::log.info "Successfully send service information to Home Assistant." +else + bashio::log.warning "Service message to Home Assistant failed!" +fi + # Register stop function stop_mariadb() { + bashio::services.delete "mysql" mysqladmin shutdown } trap "stop_mariadb" SIGTERM SIGHUP -wait "$MARIADB_PID" +wait "${MARIADB_PID}"