使用Ansible mysql_user模块设置的root @ localhost密码不起作用

时间:2016-10-14 18:54:57

标签: mysql ubuntu ansible

我有以下剧本:

- hosts: myserver
  vars:
    mysql_root_password: foobarbaz

[...]

tasks:

  [...]

  - name: update mysql root password for all root accounts
      mysql_user: name=root host={{ item }} password={{ mysql_root_password }} priv=*.*:ALL,GRANT
      with_items:
        - "{{ ansible_hostname }}"
        - 127.0.0.1
        - ::1
        - "localhost"
      become: true
      tags: mysql

  [...]

  # I've ommitted the tasks to install the mysql packages, 
  # store the password in /root/.my.cnf and restart the server)

问题是所需的密码正确保存在mysql.user中127.0.0.1,:: 1和主机名但不是 for localhost,即

mysql> select host,user,authentication_string from user;
+-----------+------------------+-------------------------------------------+
| host      | user             | authentication_string                     |
+-----------+------------------+-------------------------------------------+
| localhost | root             |                                           |
| localhost | mysql.sys        | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE |
| localhost | debian-sys-maint | *DA57FEBA9C5C5119186DB8834C7B83216E450117 |
| ubuntu    | root             | *8C5206E23A3B76002AA6E152691F5C5D7ABC31F9 |
| 127.0.0.1 | root             | *8C5206E23A3B76002AA6E152691F5C5D7ABC31F9 |
| ::1       | root             | *8C5206E23A3B76002AA6E152691F5C5D7ABC31F9 |
+-----------+------------------+-------------------------------------------+

其中* 8C52 ...是加密密码:

mysql> select password('foobarbaz');
+-------------------------------------------+
| password('foobarbaz')                     |
+-------------------------------------------+
| *8C5206E23A3B76002AA6E152691F5C5D7ABC31F9 |
+-------------------------------------------+

因此,这失败了:

william@ubuntu:/etc/mysql$ mysql -u root --password=foobarbaz
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1698 (28000): Access denied for user 'root'@'localhost'

如果我使用sudo,我可以使用任何密码或无连接以root身份连接到mysql。

换句话说,这个ansible命令没有做任何事情,但是如果我使用任何其他用户或主机它可以工作。

ansible myserver -m mysql_user -a "name=root host=localhost password=foobarbaz priv=*.*:ALL,GRANT" -b
myserver | SUCCESS => {
    "changed": true,
    "user": "root"
}

MySQL:Ver 14.14 Distrib 5.7.15
Ubuntu 16.04.1 LTS
Ansible 2.1.2.0

3 个答案:

答案 0 :(得分:5)

由于Ansible现在支持用于本地连接的Unix域套接字,因此存在一种非常优雅的方法(无需初始root用户设置和任何文件配置):

tasks:
  # assume that pymysql and mysql-server (with default config) are installed before this task

  - name: add user to mysql server
    mysql_user:
      # you can get socket path from /etc/mysql/mysql.conf.d/mysqld.cnf
      login_unix_socket: /var/run/mysqld/mysqld.sock  # default path
      name: username
      password: user_password
      priv: "database.*:ALL"    # not sure about dot, colon and asterisk, so I used quotes here
    become: yes

login_unix_socket参数可用于所有Ansible mysql modules

答案 1 :(得分:3)

原因是Ansible mysql_user module

的这种限制
  

目前,只支持mysql_native_password   加密密码哈希模块。

您可以在指定或未指定root密码的情况下安装MySQL软件包。

使用root密码安装

使用密码,root @ localhost登录使用mysql_native_passwordpassword hashing method introduced in MySQL 4.1.1,其中密码长度为41个字节,以单个星号开头,password()函数生成哈希值。

mysql> select host,user,authentication_string,plugin from mysql.user;
+-----------+------------------+-------------------------------------------+-----------------------+
| host      | user             | authentication_string                     | plugin                |
+-----------+------------------+-------------------------------------------+-----------------------+
| localhost | root             | *9B500343BC52E2911172EB52AE5CF4847604C6E5 | mysql_native_password |
| localhost | mysql.sys        | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE | mysql_native_password |
| localhost | debian-sys-maint | *DA57FEBA9C5C5119186DB8834C7B83216E450117 | mysql_native_password |
+-----------+------------------+-------------------------------------------+-----------------------+

没有root密码的安装

没有密码,root @ localhost使用auth_socket插件:

mysql> select host,user,authentication_string,plugin from mysql.user;
+-----------+------------------+-------------------------------------------+-----------------------+
| host      | user             | authentication_string                     | plugin                |
+-----------+------------------+-------------------------------------------+-----------------------+
| localhost | root             |                                           | auth_socket           |
| localhost | mysql.sys        | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE | mysql_native_password |
| localhost | debian-sys-maint | *DA57FEBA9C5C5119186DB8834C7B83216E450117 | mysql_native_password |
+-----------+------------------+-------------------------------------------+-----------------------+

auth_socket仅在您从localhost通过unix_socket连接时才有效。它只会检查连接的用户名是否与“用户”字段中的用户名匹配,没有密码

这就是为什么你可以sudo mysql使用你喜欢的任何密码,或者不使用任何密码,但无论你输入什么密码,以mysql -u root -p作为无特权用户都无法工作。

Ansible模块目前无法设置密码,除非插件是mysql_native_password,因此您需要先正确设置插件值。

已经有feature request来修复此问题。

<强>解决方案

使用密码安装MySQL ,使用debconf module提前提供(您必须设置两次,一次用于确认屏幕)。然后安装MySQL,将密码保存到/root/.my.cnf,以便root用户可以自动连接,并使用mysql_user设置您需要的其他任何登录。

- hosts: myserver
  vars:
    mysql_root_password: foobarbaz

  tasks:
    - name: Specify MySQL root password before installing
      # without this, auth_socket will be used for root@localhost, and we won't be able to set the password
      debconf: name='mysql-server' question='mysql-server/root_password' value='{{mysql_root_password | quote}}' vtype='password'
      become: true

    - name: Confirm MySQL root password before installing
      debconf: name='mysql-server' question='mysql-server/root_password_again' value='{{mysql_root_password | quote}}' vtype='password'
      become: true

    - name: Install MySQL server
      apt: name={{ item }} state=present
      with_items:
        - mysql-server
        - python-mysqldb
      become: true

    - name: Start MySQL
      service: name=mysql state=started
      become: true

    - name: create /root/.my.cnf (from template) with password credentials
      template: src=/etc/ansible/templates/root/.my.cnf dest=/root/.my.cnf owner=root mode=0600
      become: true

    - name: update mysql root password for all root accounts
      mysql_user: name=root host={{ item }} password={{ mysql_root_password }} sql_log_bin=yes priv=*.*:ALL,GRANT
      with_items:
        - "{{ ansible_hostname }}"
        - 127.0.0.1
        - ::1
        - "localhost"
      become: true

答案 2 :(得分:2)

替代解决方案:

sudo mysql -u root -p{{ mysql_root_password }} -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '{{ mysql_root_password }}'; FLUSH PRIVILEGES;"

它首次运行,因为root仍然使用auth_socket身份验证插件并忽略密码,并且后续运行因为密码是正确的。

找到解决方案,并在此解释如何调试:https://www.percona.com/blog/2016/03/16/change-user-password-in-mysql-5-7-with-plugin-auth_socket/