Ansible playbook to install and configure MySQL on Ubuntu - mysql

I am trying to set up MySQL reasonably secured,
on Ubuntu 22.04, using Ansible. This is my playbook (from a post by Lorin Hochstein) See Ansible idempotent MySQL installation Playbook This is my playbook (converted for apt and Ubuntu)
- hosts: carme.hcs
become: yes
gather_facts: false
vars:
new_mysql_root_password: <redacted>
mysqlsoftware:
- python3-pymysql
- mysql-client
- mysql-server
tasks:
- name: Install MySQL
action: apt install {{ item }}
with_items: "{{ mysqlsoftware }}"
- name: Start the MySQL service
action: service name=mysql state=started
# 'localhost' needs to be the last item for idempotency, see
# http://ansible.cc/docs/modules.html#mysql-user
- name: update mysql root password for all root accounts
mysql_user:
check_implicit_admin: true
login_user: root
name: root
priv: '*.*:ALL,GRANT'
host: "{{ item }}"
password: "{{ new_mysql_root_password }}"
with_items:
- 127.0.0.1
- ::1
- localhost
- name: copy .my.cnf file with root password credentials
template: src=./shared/my.cnf.j2 dest=/root/.my.cnf owner=root mode=0600
- name: delete anonymous MySQL server user for $server_hostname
action: mysql_user user="" host="{{ server_hostname }}" state="absent"
- name: delete anonymous MySQL server user for localhost
action: mysql_user user="" state="absent"
- name: remove the MySQL test database
action: mysql_db db=test state=absent`
Steps 1 and 2 work just fine.
Step 3 always fails with
TASK [update mysql root password for all root accounts] ********************************************************************************************************* failed: [carme.hcs] (item=127.0.0.1) => {"ansible_loop_var": "item", "changed": false, "item": "127.0.0.1", "msg": "unable to connect to database, check login_user and login_password are correct or /root/.my.cnf has the credentials. Exception message: (1698, \"Access denied for user 'root'#'localhost'\")"} failed: [carme.hcs] (item=::1) => {"ansible_loop_var": "item", "changed": false, "item": "::1", "msg": "unable to connect to database, check login_user and login_password are correct or /root/.my.cnf has the credentials. Exception message: (1698, \"Access denied for user 'root'#'localhost'\")"} failed: [carme.hcs] (item=localhost) => {"ansible_loop_var": "item", "changed": false, "item": "localhost", "msg": "unable to connect to database, check login_user and login_password are correct or /root/.my.cnf has the credentials. Exception message: (1698, \"Access denied for user 'root'#'localhost'\")"}
I have checked on carme.hcs, and /root/.my.cnf does not exist.
I can log in to mysql with "sudo mysql" but not with
"mysql -u root" nor with "mysql -u root -p". Is this not
the default set up of a fresh MySQL install, that I wish to change?
I also ran 'select user, host, plugin, authentication_string from user where user = "root";' on carme, and the result is garbled beyond belief.
In short, plugin = "mysql_native_password" and authentication_string is blank for root#localhost.
I do not understand what is going wrong. Some enlightenment please!

There are so many things wrong with the playbook I'm embarrassed.
I misunderstood about installing pip and what should be installed with apt and what with pip.
apt will hang, and needs a -y param.
It leaves /root/.my.cnf so root can still log in with no password.
When that is fixed, when it is run twice it will fail the second time because it can't log in with no password.
127.0.0.1 and ::1 do not exist in mysql.user table, so they do not need to have their root access removed.
OK, Lets post the updated playbook.
- hosts: carme.hcs
become: yes
gather_facts: false
vars:
new_mysql_root_password: redacted
mysqlsoftware:
- mysql-server
- mysql-client
tasks:
- name: install python, pip etc
shell: apt-get -y install "{{ item }}"
with_items:
- pip
- python3-dev
- default-libmysqlclient-dev
- build-essential
- name: Install MySQL server
shell: apt-get -y install mysql-server
- name: Install MySQL client
shell: apt-get -y install mysql-client
- name: pip install mysqlclient
shell: pip install mysqlclient
- name: Start the MySQL service
action: service name=mysql state=started
- name: copy .my.cnf file with root password credentials
template: src=/home/ian/Ansible/playbooks/shared/my.cnf.j2 dest=/root/.my.cnf owner=root mode=0600
- name: update mysql root password for all root accounts
mysql_user:
name: root
host: localhost
password: "{{ new_mysql_root_password }}"
- name: delete anonymous MySQL server user for localhost
action: mysql_user user="" state="absent"
- name: remove the MySQL test database
action: mysql_db db=test state=absent
- name: Remove /root/.my.cnf
ansible.builtin.file:
path: /root/.my.cnf
state: absent

Related

How to login to MySQL / MariaDB using Ansible?

I am using Ansible to replicate a given shopware installation guide with an Ansible project. Therefore I need to create a database and edit privileges.
I added my credentials to local my.cnf file and copy it to the server via
- name: Create Database
become: yes
community.mysql.mysql_db:
name: shopware
state: present
config_file: /etc/mysql/my.cnf
[client-server]
# Import all .cnf files from configuration directory
!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/mariadb.conf.d/
[client]
user="root"
password=""
The next step
- name: Create Database
become: yes
community.mysql.mysql_db:
name: shopware
state: present
config_file: /etc/mysql/my.cnf
- name: Create user with password, all database privileges and 'WITH GRANT OPTION' shopware database
become: yes
community.mysql.mysql_user:
state: present
name: "{{shopware_db_username}}"
password: "{{shopware_db_pass}}"
priv:
'shopware.*': 'ALL,GRANT'
is throwing the error:
TASK [Create Database] ******************************************************************************************************************************************************************************************************
fatal: [swserver]: FAILED! => {"changed": false, "msg": "unable to connect to database, check login_user and login_password are correct or /etc/mysql/my.cnf has the credentials. Exception message: (1698, \"Access denied for user 'root'#'localhost'\")"}
Additional info
login via mysql -u root -p with empty password does not work
Server
OS: Ubuntu 20.04.3 LTS x86_64
Kernel: 5.4.0-94-generic
Host
OS: Ubuntu 20.04.3 LTS on Windows 10 x86_64
Ansible 2.9.6
Kernel: 5.10.16.3-microsoft-standard-WSL2
Source:
https://git.rosibert.de/rpolito/ansible-shopware
Since I had a similar question in the past I like to share my solution approach here.
After MySQL/MariaDB server installation
- name: Install from EPEL-7 and/or IUS-7 repositories
yum:
name: ['mariadb103-server', 'mariadb103', 'python2-PyMySQL']
state: latest
and copying the config to /etc/my.cnf.d/my.cnf
[server]
[mysqld]
datadir=/var/data
socket=/var/lib/mysql/mysql.sock
log-error=/var/log/mariadb/mariadb.log
pid-file=/run/mariadb/mariadb.pid
it was possible to start the service
- name: Make sure service is started and enabled
systemd:
name: mariadb
state: started
enabled: yes
and connect to via socket to perform the next steps
# mysql_secure_installation
- name: Delete all anonymous SQL user accounts
mysql_user:
user: ""
host_all: yes
state: absent
- name: Remove the SQL test database
mysql_db:
db: "test"
state: absent
- name: Change root user password on first run
mysql_user:
login_user: root
login_password: ''
name: root
password: "{{ SQL_ROOT_PASSWORD }}"
priv: "*.*:ALL,GRANT"
host: "{{ item }}"
with_items:
- "{{ ansible_hostname }}"
- "127.0.0.1"
- "::1"
- "localhost"
After that, tasks like
- name: Make sure user exists
shell:
cmd: "mysql -uroot -p{{ SQL_ROOT_PASSWORD }} -e\"CREATE USER IF NOT EXISTS '{{ SQL_USER }}'#'{{ SQL_IP }}' IDENTIFIED BY '{{ SQL_USER_PASSWORD }}' REQUIRE SSL;\" -N -B"
register: result
were be possible.

Ansible access denied for 'root#localhost' error

I am trying to create a mysql database through Ansible playbook. After reading several threads & questions over here, I have created my playbook like this -
---
- name: "Install Packages"
hosts: localhost
connection: local
become: yes
vars:
mysql_root_password: Test#1123
tasks:
- name: Install basic packages
apt:
name:
- vim
- curl
- python3-pip
- mysql-server
- libmysqlclient-dev
- python-pymysql
state: latest
cache_valid_time: 3600
- name: start & enable mysql Server
service:
name=mysql
state=started
enabled=yes
- name: checking RabbitMQ & mysql Server status
command: systemctl status "{{ item }}"
with_items:
- mysql
register: result
ignore_errors: yes
- name: showing mysql Server status
debug:
var: result
- name: Install pip modules
pip:
name:
- pymysql
- virtualenv
state: present
executable: /usr/bin/pip3
- name: create /root/.my.cnf with password credentials
blockinfile:
path: /root/.my.cnf
block: |
[client]
user=root
password={{ mysql_root_password }}
[mysql]
user=root
password={{ mysql_root_password }}
[mysqldump]
user=root
password={{ mysql_root_password }}
[mysqldiff]
user=root
password={{ mysql_root_password }}
create: yes
- name: "Mysql Configuration - Resetting RootPassword"
mysql_user:
login_user: root
login_password: ''
name: root
host_all: yes
password: "{{mysql_root_password}}"
- name: Create a new database with name 'test'
mysql_db:
login_user: root
login_password: "{{mysql_root_password}}"
login_unix_socket: /run/mysqld/mysqld.sock
name: test
state: present
- name: Create database user with name 'test' and password 'Test#1123' with all database privileges
mysql_user:
name: test
password: Test#1123
priv: '*.test:ALL'
state: present
While running this playbook, I am getting below error -
TASK [Mysql Configuration - Resetting RootPassword] *****************************************************************************************************************************************
[WARNING]: Module did not set no_log for update_password
fatal: [localhost]: FAILED! => {"changed": false, "msg": "unable to connect to database, check login_user and login_password are correct or /root/.my.cnf has the credentials. Exception message: (1698, u\"Access denied for user 'root'#'localhost'\")"}
I have checked /root/.my.cnf file has been updated with correct username & password.
I tried to run mysql -u root -p. This has been successful without any password. But while trying to run mysql -u 'root'#'localhost' -p, it is not allowing to get into mysql with or without password.
I know this can be fixed several ways manually. But how to fix this issue with Ansible. May be I am doing some silly mistake. But unable to figure it out. I have also tried without /root/.my.cnf file and without socket file also. But facing same issue.
UPDATE:
I fixed the issue by following this
please take a look at the https://docs.ansible.com/ansible/latest/modules/mysql_user_module.html#examples mysql_user_module documentation.
Here's probably what you want to achieve:
- name: "Mysql Configuration - Resetting RootPassword"
mysql_user:
login_user: root
login_password: actual_root_mysql_password
host: ''
name: root
password: "{{mysql_root_password}}"

Ansible Install MySql 5.7 - Set Root User Password

I've recently upgraded my vagrant from ubuntu/trusty-64 to bento/ubuntu-16.04. With that MySQL was updated to 5.7. I've made several updates to my playbook, but I keep getting stuck when setting the root user's password.
In the past (before 5.7) the following was sufficient:
- name: MySQL | Set the root password.
mysql_user:
name=root
host=localhost
password={{ mysql_root_password }}
become: true
In my playbook this is tested by attempting to delete an anonymous user.
- name: MySQL | Delete anonymous MySQL server user for {{ server_hostname }}
mysql_user:
name=""
host="{{ server_hostname }}"
state="absent"
login_user=root
login_password={{ mysql_root_password }}
However, now my playbook fails at this step, returning:
"Access denied for user 'root'#'localhost'"
TASK [mysql : MySQL | Delete anonymous MySQL server user for vagrant] **********
task path: /Users/jonrobinson/vagrant/survey/playbooks/roles/mysql/tasks/mysql.yml:51
fatal: [vagrant]: FAILED! => {"changed": false, "failed": true, "msg": "unable to connect to database, check login_user and login_password are correct or /home/vagrant/.my.cnf has the credentials. Exception message: (1698, \"Access denied for user 'root'#'localhost'\")"}
I've tried several things:
Setting the password blank for root user mysql_root_password=""
Attempting to delete the root user then recreate it with Ansible. I get same error probably because it's trying to act at the root user.
Manually updating the root password in mysql. - This also doesn't appear to work (password isn't recognized) unless I delete the root user and recreate it with all the permissions. Just updating the root user password appears to have no change.
My Full MySQL YAML:
---
- name: MySQL | install mysql packages
apt: pkg={{ item }} state=installed
become: true
with_items:
- mysql-client
- mysql-common
- mysql-server
- python-mysqldb
- name: MySQL | create MySQL configuration file
template:
src=my.cnf.j2
dest=/etc/mysql/my.cnf
backup=yes
owner=root
group=root
mode=0644
become: true
- name: MySQL | create MySQLD configuration file
template:
src=mysqld.cnf.j2
dest=/etc/mysql/conf.d/mysqld.cnf
backup=yes
owner=root
group=root
mode=0644
become: true
- name: MySQL | restart mysql
service: name=mysql state=restarted
become: true
- name: MySQL | Set the root password.
mysql_user:
name=root
host=localhost
password={{ mysql_root_password }}
become: true
- name: MySQL | Config for easy access as root user
template: src=mysql_root.my.cnf.j2 dest=/root/.my.cnf
become: true
- name: MySQL | Config for easy access as root user
template: src=mysql_root.my.cnf.j2 dest={{ home_dir }}/.my.cnf
when: "'{{ user }}' != 'root'"
- name: MySQL | Delete anonymous MySQL server user for {{ server_hostname }}
mysql_user: name="" host="{{ server_hostname }}" state="absent" login_user=root login_password={{ mysql_root_password }}
- name: MySQL | Delete anonymous MySQL server user for localhost
mysql_user: name="" state="absent" host=localhost login_user=root login_password={{ mysql_root_password }}
- name: MySQL | Secure the MySQL root user for IPV6 localhost (::1)
mysql_user: name="root" password="{{ mysql_root_password }}" host="::1" login_user=root login_password={{ mysql_root_password }}
- name: MySQL | Secure the MySQL root user for IPV4 localhost (127.0.0.1)
mysql_user: name="root" password="{{ mysql_root_password }}" host="127.0.0.1" login_user=root login_password={{ mysql_root_password }}
- name: MySQL | Secure the MySQL root user for localhost domain (localhost)
mysql_user: name="root" password="{{ mysql_root_password }}" host="localhost" login_user=root login_password={{ mysql_root_password }}
- name: MySQL | Secure the MySQL root user for {{ server_hostname }} domain
mysql_user: name="root" password="{{ mysql_root_password }}" host="{{ server_hostname }}" login_user=root login_password={{ mysql_root_password }}
- name: MySQL | Remove the MySQL test database
mysql_db: db=test state=absent login_user=root login_password={{ mysql_root_password }}
- name: MySQL | create application database user
mysql_user: name={{ dbuser }} password={{ dbpass }} priv=*.*:ALL host='%' state=present login_password={{ mysql_root_password }} login_user=root
- name: MySQL | restart mysql
service: name=mysql state=restarted
become: true
I was able to figure it out. The gist of the problem had to do with mysql 5.7 using auth_socket for the root user when no password is provided. See the following: "That plugin doesn’t care and doesn’t need a password. It just checks if the user is connecting using a UNIX socket and then compares the username. "
When this is the case you cannot update the password using:
SET PASSWORD FOR 'root'#'localhost' = PASSWORD('test');
And instead must use:
ALTER USER 'root'#'localhost' IDENTIFIED WITH mysql_native_password='test';
Solution 1: However, Ansible, as of version 2.0.2 didn't account for this. I was able to get around this by setting the password before MySql is installed
- name: Specify MySQL root password before installing
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: MySQL | install mysql packages
apt: pkg={{ item }} state=installed
become: true
with_items:
- mysql-client
- mysql-common
- mysql-server
- python-mysqldb
...
However, this has also since been addressed by Ansible
Solution 2: The easiest solution is just to upgrade Ansible to 2.2.1
From what I understand, in MySQL, changing the root password needs to be done for localhost, the server's hostname and 127.0.0.1 and also needs full privileges. Something along the these lines may help (Note: I've only tested this on MariaDB, and not MySQL):
tasks:
- name: Set a new root password
mysql_user: check_implicit_admin=yes
login_user=root
login_password={{ mysql_root_password }}
user=root
password={{ NEW_mysql_root_password }}
host={{ item }}
priv='*.*:ALL,GRANT'
with_items:
- localhost
- 127.0.0.1
- {{ server_hostname }}
notify:
- restart_mariadb
handlers:
- name: restart_mariadb
service: name=mariadb
state=restarted

ansible mysql configuration in one file for ubuntu 14.04

I'm trying to write a single page ansible script for mysql installation and setup a new user and create a empty DB. what I've tried so far -
hosts file
[mysql]
webapp ansible_ssh_host=xxx.xxx.xxx.xxx
mysql.yml (The single file for all tasks/vars/handelers) (both hosts and mysql.yml in same directory) and I can login in remote system using ssh
---
- hosts: mysql
vars:
- system_packages:
- build-essential
- python-dev
- python-pip
- libmysqlclient-dev
- mysql-server
- python-mysqldb
- root_password: root
tasks:
- name: Install MySQL
apt: pkg={{ item }} state=installed update-cache=yes
with_items: system_packages
tags:
- setup
- name: Start MySQL service
action: service name=mysql state=started enabled=yes
- name: Update mysql password for root account
mysql_user: name=root host={{ item }} password={{root_password}}
with_items:
- 127.0.0.1 #In case of distributed system how should I place Ip addr of this system
- localhost
- name: create db 'mydb'
action: mysql_db db=mydb state=present
- name: Creates database user 'eric' with password 'eric' for 'mydb' and grant all priveleges
action: mysql_user state=present name=eric password=eric priv=mydb.*:ALL
handlers:
- name: start mysql
service: name=mysql state=started
when I run this script I get this output(+error)
failed: [webapp] => (item=127.0.0.1) => {"failed": true, "item": "127.0.0.1"}
msg: unable to connect to database, check login_user and login_password are correct or ~/.my.cnf has the credentials
You can't connect to mysql server before you will set root password. To do this use the following:
- name: Set password for root user
shell:
mysqladmin password "{{ root_password }}" -u root
After a default installation on ubuntu, you only can login to your mysql as root with password "root". So to change your password you will have to set your mysql login user to root (as you did in the next task)
- name: Update mysql password for root account
mysql_user:
name=root host={{ item }}
password={{root_password}}
login_user=root
login_password="root"
sudo: yes
sudo_user: root
There is also a ready-to-go solution in ansible galaxy
Please add this task inside your task/main.yml
- name: Copy the root credentials as .my.cnf file
template: src=root.cnf.j2 dest=~/.my.cnf mode=0600
and this will be your root.cnf.j2
[client]
user=root
password={{ root_password }}
What it will do is, to connect the mysql from the root user without password and perform these task. You can remove it after running all the task or leave it like this because it is under root and have tight permission.

Install MySQL with ansible on ubuntu

I have a problem installing MySQL with ansible on a vagrant ubuntu,
This is my MySQL part
---
- name: Install MySQL
apt:
name: "{{ item }}"
with_items:
- python-mysqldb
- mysql-server
- name: copy .my.cnf file with root password credentials
template:
src: templates/root/.my.cnf
dest: ~/.my.cnf
owner: root
mode: 0600
- name: Start the MySQL service
service:
name: mysql
state: started
enabled: true
# 'localhost' needs to be the last item for idempotency, see
# http://ansible.cc/docs/modules.html#mysql-user
- 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
And I have this error
failed: [default] => (item=vagrant-ubuntu-trusty-64) => {"failed": true, "item": "vagrant-ubuntu-trusty-64"}
msg: unable to connect to database, check login_user and login_password are correct or ~/.my.cnf has the credentials
failed: [default] => (item=127.0.0.1) => {"failed": true, "item": "127.0.0.1"}
msg: unable to connect to database, check login_user and login_password are correct or ~/.my.cnf has the credentials
failed: [default] => (item=::1) => {"failed": true, "item": "::1"}
msg: unable to connect to database, check login_user and login_password are correct or ~/.my.cnf has the credentials
failed: [default] => (item=localhost) => {"failed": true, "item": "localhost"}
msg: unable to connect to database, check login_user and login_password are correct or ~/.my.cnf has the credentials
my .my.cnf is
[client]
user=root
password={{ mysql_root_password }}
and when copied on the server
[client]
user=root
password=root
I don't understand why, ~/.my.cnf is created
Project Github
Thanks
When mysql-server is installed headlessly, there's no password. Therefore to make .my.cnf work, it should have a blank password line. Here's what I tested with for a .my.cnf:
[client]
user=root
password=
It's also slightly strange to put .my.cnf in your vagrant user directory as owned by root and only readable as root.
After ensuring the password was blank in .my.cnf, I was able to properly set the password for root in those four contexts. Note that it fails to run after that, since .my.cnf would need to be updated, so it fails the idempotency test.
There's a note on the ansible mysql_user module page that suggests writing the password and then writing the .my.cnf file. If you do that, you need a where clause to the mysql_user action (probably with a file stat before that).
Even more elegant is to use check_implicit_admin along with login_user and login_password. That's beautifully idempotent.
As a third way, perhaps check_implicit_admin makes it even easier.
Here's my successful playbook showing the above, tested with a few fresh servers. Kinda proud of this. Note .my.cnf is unnecessary for all of this.
---
- hosts: mysql
vars:
mysql_root_password: fart
tasks:
- name: Install MySQL
apt: name={{ item }} update_cache=yes cache_valid_time=3600 state=present
sudo: yes
with_items:
- python-mysqldb
- mysql-server
#- name: copy cnf
# copy: src=.my.cnf dest=~/.my.cnf owner=ubuntu mode=0644
# sudo: yes
- name: Start the MySQL service
sudo: yes
service:
name: mysql
state: started
enabled: true
- name: update mysql root password for all root accounts
sudo: yes
mysql_user:
name: root
host: "{{ item }}"
password: "{{ mysql_root_password }}"
login_user: root
login_password: "{{ mysql_root_password }}"
check_implicit_admin: yes
priv: "*.*:ALL,GRANT"
with_items:
- "{{ ansible_hostname }}"
- 127.0.0.1
- ::1
- localhost
(edit- removed my.cnf)
Here is my complete working MySQL role, that might help you.
vars/main.yml :
mysql_root_pass: mypassword #MySQL Root Password
asks/main.yml :
---
- name: Install the MySQL packages
apt: name={{ item }} state=installed update_cache=yes
with_items:
- mysql-server-5.6
- mysql-client-5.6
- python-mysqldb
- libmysqlclient-dev
- name: Update MySQL root password for all root accounts
mysql_user: name=root host={{ item }} password={{ mysql_root_pass }} state=present
with_items:
- "{{ ansible_hostname }}"
- 127.0.0.1
- ::1
- localhost
- name: Copy the root credentials as .my.cnf file
template: src=root.cnf.j2 dest=~/.my.cnf mode=0600
- name: Ensure Anonymous user(s) are not in the database
mysql_user: name='' host={{ item }} state=absent
with_items:
- localhost
- "{{ ansible_hostname }}"
- name: Remove the test database
mysql_db: name=test state=absent
notify:
- Restart MySQL
templates/root.cnf.j2
[client]
user=root
password={{ mysql_root_pass }}
handlers/main.yml
---
- name: Restart MySQL
service: name=mysql state=restarted
site.yml
---
- hosts: all
become: yes
gather_facts: yes
roles:
- mysql
If you need any help, please check this github link. Thanks
On ubuntu 20.04, it requires login_unix_socket now:
- name: setting default root password
mysql_user:
name: root
password: "{{ mysql_root_password }}"
check_implicit_admin: true
login_unix_socket: /var/run/mysqld/mysqld.sock
Cheers