diff --git a/README.md b/README.md index 20244c1bd..470a0c92e 100644 --- a/README.md +++ b/README.md @@ -11,11 +11,7 @@ This role focuses on security configuration of MySQL. Therefore you can add this ## Requirements * Ansible -* Python MySQL-DB Package - -## Usage - -Before you use this role make sure to have a valid login-configuration in `~/.my.cnf` so Ansible is able to login into your database. +* Set up `mysql_root_password` variable ### Example Playbook @@ -25,6 +21,7 @@ Before you use this role make sure to have a valid login-configuration in `~/.my This hardening role installs the hardening but expects an existing installation of MySQL, MariaDB or Percona. Please ensure that the following variables are set accordingly: +- `mysql_hardening_enabled: yes` role is enabled by default and can be disabled without removing it from a playbook. You can use conditional variable, for example: `mysql_hardening_enabled: "{{ true if mysql_enabled else false }}"` - `mysql_hardening_user: 'mysql'` The user that mysql runs as. - `mysql_datadir: '/var/lib/mysql'` The MySQL data directory - `mysql_hardening_hardening_conf: '/etc/mysql/conf.d/hardening.cnf'` The path to the configuration file where the hardening will be performed diff --git a/defaults/main.yml b/defaults/main.yml index 297a7360e..32b0ea007 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -1,10 +1,18 @@ +# switcher to enable/disable role +mysql_hardening_enabled: yes + # general configuration mysql_hardening_user: 'mysql' +mysql_hardening_group: 'root' mysql_datadir: '/var/lib/mysql' mysql_hardening_hardening_conf: '/etc/mysql/conf.d/hardening.cnf' +# You have to change this to your own strong enough mysql root password +mysql_root_password: '-----====>SetR00tPa$$wordH3r3!!!<====-----' +# There .my.cnf with mysql root credentials will be installed +mysql_user_home: "{{ ansible_env.HOME}}" # ensure the following parameters are set properly -mysql_allow_remote_root: false +mysql_remove_remote_root: true mysql_remove_anonymous_users: true mysql_remove_test_database: true diff --git a/files/mysql_grants.sql b/files/mysql_grants.sql deleted file mode 100644 index 5312c5acc..000000000 --- a/files/mysql_grants.sql +++ /dev/null @@ -1,4 +0,0 @@ -DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1'); -DELETE FROM mysql.user WHERE User=''; -DROP DATABASE IF EXISTS test; -DELETE FROM mysql.db WHERE Db='test' OR Db='test\_%'; diff --git a/files/mysql_remove_anonymous_users.sql b/files/mysql_remove_anonymous_users.sql new file mode 100644 index 000000000..916d83efd --- /dev/null +++ b/files/mysql_remove_anonymous_users.sql @@ -0,0 +1 @@ +DELETE FROM mysql.user WHERE User=''; diff --git a/files/mysql_remove_remote_root.sql b/files/mysql_remove_remote_root.sql new file mode 100644 index 000000000..a95b99016 --- /dev/null +++ b/files/mysql_remove_remote_root.sql @@ -0,0 +1 @@ +DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1'); diff --git a/tasks/configure.yml b/tasks/configure.yml new file mode 100644 index 000000000..6c3ec9401 --- /dev/null +++ b/tasks/configure.yml @@ -0,0 +1,18 @@ +--- + +- name: protect my.cnf + file: path='{{mysql_hardening_mysql_conf}}' mode=0600 owner=root group=root + +- name: ensure permissions on mysql-datadir are correct + file: path='{{mysql_datadir}}' state=directory owner='{{mysql_hardening_user}}' group='{{mysql_hardening_user}}' + +- name: check mysql configuration-directory exists and has right permissions + file: path='/etc/mysql/conf.d' state=directory owner='{{mysql_hardening_user}}' group='{{mysql_hardening_group}}' mode=0470 + +- name: check include-dir directive is present in my.cnf + lineinfile: dest='{{mysql_hardening_mysql_conf}}' line='!includedir /etc/mysql/conf.d/' insertafter='EOF' state=present backup=yes + notify: restart mysql + +- name: apply hardening configuration + template: src='hardening.cnf.j2' dest='{{mysql_hardening_hardening_conf}}' owner='{{mysql_hardening_user}}' group='{{mysql_hardening_group}}' mode=0460 + notify: restart mysql diff --git a/tasks/main.yml b/tasks/main.yml index fb69230c8..83659fb6e 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -4,25 +4,13 @@ include_vars: "{{ ansible_os_family }}.yml" tags: always -- name: protect my.cnf - file: path='{{mysql_hardening_mysql_conf}}' mode=0600 owner=root group=root - -- name: ensure permissions on mysql-datadir are correct - file: path='{{mysql_datadir}}' state=directory owner='{{mysql_hardening_user}}' group='{{mysql_hardening_user}}' - -- name: create mysql configuration-directory - file: path='/etc/mysql/conf.d' state=directory owner='{{mysql_hardening_user}}' mode=0600 - -- name: add include-dir directive to my.cnf - lineinfile: dest='{{mysql_hardening_mysql_conf}}' line='!includedir /etc/mysql/conf.d/' insertafter='^\[mysql\]' state=present backup=yes - -- name: apply hardening configuration - template: src='hardening.cnf.j2' dest='{{mysql_hardening_hardening_conf}}' owner='{{mysql_hardening_user}}' mode=0750 - notify: restart mysql - -# Copy database dump file to remote host and restore it to database 'my_db' -- name: copy the sql-script to the remote host - copy: src='mysql_grants.sql' dest='/tmp/' - -- name: run the mysql_grants.sql script - mysql_db: name='mysql' state=import target='/tmp/mysql_grants.sql' +- include: configure.yml + when: mysql_hardening_enabled + tags: + - mysql_hardening + +- include: mysql_secure_installation.yml + when: mysql_hardening_enabled + tags: + - mysql_hardening + - mysql_secure_installation diff --git a/tasks/mysql_secure_installation.yml b/tasks/mysql_secure_installation.yml new file mode 100644 index 000000000..d5f883449 --- /dev/null +++ b/tasks/mysql_secure_installation.yml @@ -0,0 +1,66 @@ +--- + +# supported for ansible ver => 2.0 +#- name: Install python-mysqldb for Ansible +# package: pkg=python-mysqldb state=present + + +- name: Install MySQL-python for Ansible + apt: name=python-mysqldb state=present + when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu' + +- name: Install python-mysqldb for Ansible + yum: name=MySQL-python state=present + when: ansible_os_family == 'RedHat' or ansible_os_family == 'Oracle Linux' + +- debug: msg="WARNING - you have to change default mysql_root_password" + when: mysql_root_password == '-----====>SetR00tPa$$wordH3r3!!!<====-----' + +- name: root password is present + mysql_user: name=root host={{item}} password={{mysql_root_password | mandatory}} state=present + with_items: + - '::1' + - '127.0.0.1' + - 'localhost' + +- name: install .my.cnf with credentials + template: src=my.cnf.j2 dest={{mysql_user_home}}/.my.cnf + mode=0400 + tags: my_cnf + +- name: test database is absent + mysql_db: name=test state=absent + when: mysql_remove_test_database + +# Can use only if ansible ver => 2.1 +#- name: anonymous users are absent +# mysql_user: name='' state=absent host_all=yes +# when: mysql_remove_anonymous_users + +- name: copy mysql_remove_anonymous_users + copy: src='{{item}}.sql' dest='/tmp/{{item}}.sql' + with_items: + - mysql_remove_anonymous_users + when: mysql_remove_anonymous_users + changed_when: false + +- name: apply mysql_remove_anonymous_users + mysql_db: name='mysql' state=import target='/tmp/{{item}}.sql' + with_items: + - mysql_remove_anonymous_users + when: mysql_remove_anonymous_users + changed_when: false + +- name: copy mysql_remove_remote_root + copy: src='{{item}}.sql' dest='/tmp/{{item}}.sql' + with_items: + - mysql_remove_remote_root + when: mysql_remove_remote_root + changed_when: false + +- name: apply mysql_remove_remote_root + mysql_db: name='mysql' state=import target='/tmp/{{item}}.sql' + with_items: + - mysql_remove_remote_root + when: mysql_remove_remote_root + changed_when: false diff --git a/templates/my.cnf.j2 b/templates/my.cnf.j2 new file mode 100644 index 000000000..ce66b13ed --- /dev/null +++ b/templates/my.cnf.j2 @@ -0,0 +1,4 @@ +[client] +user=root +password='{{ mysql_root_password | mandatory }}' +#ssl