From 6e5621cdc9d45503ec64ab43db8dbf2faa9036fb Mon Sep 17 00:00:00 2001 From: schurzi Date: Wed, 1 Mar 2023 14:19:50 +0100 Subject: [PATCH] simplify MySQL queries for user deletion (#641) * use rowcount to determine mysql results Signed-off-by: Martin Schurz * use correct list level Signed-off-by: Martin Schurz * remove json_query Signed-off-by: Martin Schurz * remove intermediate vars Signed-off-by: Martin Schurz * add check for count Signed-off-by: Martin Schurz * drop condition, since one result must exist Signed-off-by: Martin Schurz * move rowcount in condition Signed-off-by: Martin Schurz * do loop in ansible to report each deleted user Signed-off-by: Martin Schurz * add idempotency check Signed-off-by: Martin Schurz * additional tests to verify user deletion Signed-off-by: Martin Schurz * actually iterate the whole user list when deleting Signed-off-by: Martin Schurz * fix tests for SuSE Signed-off-by: Martin Schurz * adopt suggestions Signed-off-by: Martin Schurz --------- Signed-off-by: Martin Schurz --- molecule/mysql_hardening/molecule.yml | 2 +- molecule/mysql_hardening/prepare.yml | 7 ++--- .../prepare_tasks/mysql_users.yml | 15 +++++++++++ molecule/mysql_hardening/verify.yml | 9 +++++++ .../verify_tasks/mysql_users.yml | 25 +++++++++++++++++ .../tasks/mysql_secure_installation.yml | 27 +++++-------------- 6 files changed, 58 insertions(+), 27 deletions(-) create mode 100644 molecule/mysql_hardening/prepare_tasks/mysql_users.yml create mode 100644 molecule/mysql_hardening/verify_tasks/mysql_users.yml diff --git a/molecule/mysql_hardening/molecule.yml b/molecule/mysql_hardening/molecule.yml index a9c5a0b7..0eef4be0 100644 --- a/molecule/mysql_hardening/molecule.yml +++ b/molecule/mysql_hardening/molecule.yml @@ -53,6 +53,6 @@ scenario: - create - prepare - converge - # - idempotence # not idempotent + - idempotence - verify - destroy diff --git a/molecule/mysql_hardening/prepare.yml b/molecule/mysql_hardening/prepare.yml index a8d6a681..53a3a190 100644 --- a/molecule/mysql_hardening/prepare.yml +++ b/molecule/mysql_hardening/prepare.yml @@ -70,11 +70,8 @@ - include_role: name: dev-sec.mysql - - name: create a user with an empty password - community.mysql.mysql_query: - query: - - "CREATE USER foo@bar;" - login_unix_socket: "{{ login_unix_socket | default(omit) }}" + - name: include MySQL user prepare tasks + include_tasks: prepare_tasks/mysql_users.yml vars: overwrite_global_mycnf: false mysql_root_password: iloverandompasswordsbutthiswilldo diff --git a/molecule/mysql_hardening/prepare_tasks/mysql_users.yml b/molecule/mysql_hardening/prepare_tasks/mysql_users.yml new file mode 100644 index 00000000..1c3b368e --- /dev/null +++ b/molecule/mysql_hardening/prepare_tasks/mysql_users.yml @@ -0,0 +1,15 @@ +--- +- name: create users for test + community.mysql.mysql_query: + query: + - "CREATE USER 'user'@'delete';" + - "CREATE USER 'user'@'127.0.0.1';" + - "CREATE USER 'user'@'::1';" + - "CREATE USER 'user'@'%';" + - "CREATE USER 'user'@'192.168.0.%';" + - "CREATE USER 'user'@'192.168.0.1';" + - "CREATE USER '%'@'192.168.0.1';" + - "CREATE USER 'user'@'192.168.0.2' IDENTIFIED BY 'keep';" + - "CREATE USER 'user'@'keep' IDENTIFIED BY 'keep';" + - "CREATE USER 'user'@'192.168.%' IDENTIFIED BY 'keep';" + login_unix_socket: "{{ login_unix_socket | default(omit) }}" diff --git a/molecule/mysql_hardening/verify.yml b/molecule/mysql_hardening/verify.yml index 9e2472e5..74fa9db2 100644 --- a/molecule/mysql_hardening/verify.yml +++ b/molecule/mysql_hardening/verify.yml @@ -34,9 +34,18 @@ update_cache: true when: ansible_distribution == 'Debian' + - name: Use Python 3 on Suse + set_fact: + ansible_python_interpreter: /usr/bin/python3 + when: + - ansible_os_family == 'Suse' + - name: include tests for the service include_tasks: verify_tasks/service.yml + - name: include tests for MySQL user + include_tasks: verify_tasks/mysql_users.yml + - name: download cinc-auditor get_url: url: https://omnitruck.cinc.sh/install.sh diff --git a/molecule/mysql_hardening/verify_tasks/mysql_users.yml b/molecule/mysql_hardening/verify_tasks/mysql_users.yml new file mode 100644 index 00000000..7f10686c --- /dev/null +++ b/molecule/mysql_hardening/verify_tasks/mysql_users.yml @@ -0,0 +1,25 @@ +--- +- name: Get all users from MySQL server + community.mysql.mysql_query: + query: > + SELECT CONCAT(USER, '@', HOST) AS users FROM mysql.user; + login_unix_socket: "{{ login_unix_socket | default(omit) }}" + register: mysql_users + +- name: create list of users from mysql query + set_fact: + mysql_users_list: "{{ mysql_users.query_result.0 | json_query('[*].users') | list }}" + +- name: assert that only accounts with password remain + ansible.builtin.assert: + that: + - '"user@delete" not in mysql_users_list' + - '"user@127.0.0.1" not in mysql_users_list' + - '"user@::1" not in mysql_users_list' + - '"user@%" not in mysql_users_list' + - '"user@192.168.0.%" not in mysql_users_list' + - '"user@192.168.0.1" not in mysql_users_list' + - '"%@192.168.0.1" not in mysql_users_list' + - '"user@192.168.0.2" in mysql_users_list' + - '"user@keep" in mysql_users_list' + - '"user@192.168.%" in mysql_users_list' diff --git a/roles/mysql_hardening/tasks/mysql_secure_installation.yml b/roles/mysql_hardening/tasks/mysql_secure_installation.yml index 493b274d..915980a2 100644 --- a/roles/mysql_hardening/tasks/mysql_secure_installation.yml +++ b/roles/mysql_hardening/tasks/mysql_secure_installation.yml @@ -49,14 +49,13 @@ - name: Get all users that have no authentication_string on MySQL version >= 5.7.6 or Mariadb version >= 10.4.0 community.mysql.mysql_query: query: > - SELECT GROUP_CONCAT(QUOTE(USER), '@', QUOTE(HOST) SEPARATOR ', ') AS users + SELECT CONCAT(QUOTE(USER), '@', QUOTE(HOST)) AS user FROM mysql.user WHERE (length(authentication_string)=0 OR authentication_string="") AND USER NOT IN ('mysql.sys', 'mysqlxsys', 'mariadb.sys'); - login_unix_socket: "{{ login_unix_socket | default(omit) }}" register: mysql_users_wo_passwords_or_auth_string when: > @@ -67,7 +66,7 @@ - name: Get all users that have no password or authentication_string on MySQL version < 5.7.6 or Mariadb version < 10.4.0 community.mysql.mysql_query: query: > - SELECT GROUP_CONCAT(QUOTE(USER), '@', QUOTE(HOST) SEPARATOR ', ') AS users + SELECT CONCAT(QUOTE(USER), '@', QUOTE(HOST)) AS user FROM mysql.user WHERE (length(password)=0 OR password="") @@ -83,25 +82,11 @@ (mysql_distribution == "mariadb" and mysql_version.version.full is version('10.4.0', '<')) -- name: Create a fact for users without password or authentication_string - ansible.builtin.set_fact: - users_wo_auth: "{{ mysql_users_wo_passwords_or_auth_string.query_result.0.0 | community.general.json_query('users') }}" - when: - - mysql_users_wo_passwords_or_auth_string.query_result is defined - - mysql_users_wo_passwords_or_auth_string.query_result != "" # noqa empty-string-compare - -- name: Create a fact for users without password - ansible.builtin.set_fact: - users_wo_auth: "{{ mysql_users_wo_passwords.query_result.0.0 | community.general.json_query('users') }}" - when: - - mysql_users_wo_passwords.query_result is defined - - mysql_users_wo_passwords.query_result != "" # noqa empty-string-compare - - name: Ensure that there are no users without password or authentication_string community.mysql.mysql_query: query: - - DROP USER {{ users_wo_auth }} + - DROP USER {{ item.user }} login_unix_socket: "{{ login_unix_socket | default(omit) }}" - when: - - users_wo_auth is defined - - users_wo_auth != "" # noqa empty-string-compare + with_community.general.flattened: + - "{{ mysql_users_wo_passwords.query_result | default([]) }}" + - "{{ mysql_users_wo_passwords_or_auth_string.query_result | default([]) }}"