Ich möchte einen MySQL-Server unter AWS einrichten und Ansible für die Konfigurationsverwaltung verwenden. __ Ich verwende die Standard-AMI von Amazon ( AMI-3275ee5b ), die yum
für die Paketverwaltung verwendet.
Wenn das untenstehende Playbook ausgeführt wird, ist alles gut. Wenn ich es jedoch ein zweites Mal starte, schlägt die Aufgabe Configure the root credentials
fehl, da das alte Passwort von MySQL nicht mehr übereinstimmt, da es beim letzten Ausführen dieses Playbooks aktualisiert wurde.
Dies macht das Playbook nicht idempotent, was ich nicht mag. Ich möchte das Playbook beliebig oft ausführen können.
- hosts: staging_mysql
user: ec2-user
Sudo: yes
tasks:
- name: Install MySQL
action: yum name=$item
with_items:
- MySQL-python
- mysql
- mysql-server
- name: Start the MySQL service
action: service name=mysqld state=started
- name: Configure the root credentials
action: command mysqladmin -u root -p $mysql_root_password
Was wäre der beste Weg, das zu lösen, was das Playbook idempotent macht? Danke im Voraus!
- hosts: staging_mysql
user: ec2-user
Sudo: yes
tasks:
- name: Install MySQL
action: yum name={{ item }}
with_items:
- MySQL-python
- mysql
- mysql-server
- name: Start the MySQL service
action: service name=mysqld 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: name=root Host={{ item }} password={{ mysql_root_password }}
with_items:
- "{{ ansible_hostname }}"
- 127.0.0.1
- ::1
- localhost
- name: copy .my.cnf file with root password credentials
template: src=templates/root/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
[client]
user=root
password={{ mysql_root_password }}
Ich habe dies auf coderwall gepostet, aber ich werde die Verbesserung von dennisjac in den Kommentaren meines ursprünglichen Posts wiedergeben.
Der Trick, es idempotent zu tun, ist zu wissen, dass das Modul mysql_user eine ~/.my.cnf -Datei lädt, wenn es eine findet.
Ich ändere zunächst das Passwort und kopiere dann eine .my.cnf-Datei mit den Passwort-Zugangsdaten. Wenn Sie versuchen, es ein zweites Mal auszuführen, findet das ansible-Modul myqsl_user die Datei .my.cnf und verwendet das neue Kennwort.
- hosts: staging_mysql
user: ec2-user
Sudo: yes
tasks:
- name: Install MySQL
action: yum name={{ item }}
with_items:
- MySQL-python
- mysql
- mysql-server
- name: Start the MySQL service
action: service name=mysqld 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: name=root Host={{ item }} password={{ mysql_root_password }} priv=*.*:ALL,GRANT
with_items:
- "{{ ansible_hostname }}"
- 127.0.0.1
- ::1
- localhost
- name: copy .my.cnf file with root password credentials
template: src=templates/root/.my.cnf dest=/root/.my.cnf owner=root mode=0600
Die .my.cnf-Vorlage sieht folgendermaßen aus:
[client]
user=root
password={{ mysql_root_password }}
Bearbeiten: In den Kommentaren wurden die von Dhananjay Nene empfohlenen Berechtigungen hinzugefügt und die Interpolation der Variablen so geändert, dass Klammern anstelle von Dollarzeichen verwendet werden.
Dies ist eine alternative Lösung zu der von @LorinHochStein vorgeschlagenen
Eine meiner Einschränkungen bestand darin, sicherzustellen, dass keine Passwörter in Klartextdateien auf dem Server gespeichert werden. Somit war .my.cnf kein praktischer Vorschlag
Lösung:
- name: update mysql root password for all root accounts from local servers
mysql_user: login_user=root
login_password={{ current_password }}
name=root
Host=$item
password={{ new_password }}
priv=*.*:ALL,GRANT
with_items:
- $ansible_hostname
- 127.0.0.1
- ::1
- localhost
Und in der VAR-Datei
current_password: foobar
new_password: "{{ current_password }}"
Wenn Sie das MySQL-Kennwort nicht ändern, führen Sie das Ansible Playbook wie üblich in der Befehlszeile aus.
Wenn Sie das mysql-Kennwort ändern, fügen Sie der Befehlszeile Folgendes hinzu. Durch die Angabe in der Befehlszeile kann der Parametersatz in der Befehlszeile Vorrang vor demjenigen haben, der standardmäßig in der VARS-Datei verwendet wird.
$ ansible-playbook ........ --extra-vars "new_password=buzzz"
Nachdem Sie den Befehl ausgeführt haben, ändern Sie die vars-Datei wie folgt
current_password=buzzz
new_password={{ current_password }}
Zusätzlich zu den vorherigen Antworten wollte ich vor dem Ausführen des Befehls keinen manuellen Schritt, dh ich möchte einen neuen Server hochfahren und das Playbook ausführen, ohne das Root-Passwort zuerst manuell ändern zu müssen. Ich glaube nicht, dass {{mysql_password}} das erste Mal funktioniert, wenn das root-Passwort null ist, da mysql_password noch irgendwo definiert werden muss (es sei denn, Sie möchten es mit -e überschreiben).
Also habe ich eine Regel dazu hinzugefügt, die ignoriert wird, wenn sie fehlschlägt. Dies ist zusätzlich zu den anderen Befehlen hier und wird auch vorher angezeigt.
- name: Change root user password on first run
mysql_user: login_user=root
login_password=''
name=root
password={{ mysql_root_password }}
priv=*.*:ALL,GRANT
Host={{ item }}
with_items:
- $ansible_hostname
- 127.0.0.1
- ::1
- localhost
ignore_errors: true
Für ansible 1.3+:
- name: ensure mysql local root password is zwx123
mysql_user: check_implicit_admin=True login_user=root login_password="zwx123" name=root password="zwx123" state=present
Nun, das war etwas kompliziert. Ich habe einen ganzen Tag damit verbracht und die unten aufgelistete Lösung gefunden. Der Schlüsselpunkt ist, wie Ansible den MySQL-Server installiert. Aus den Dokumenten von mysql_user module (letzter Hinweis auf Seite):
MySQL server installs with default login_user of ‘root’ and no password. To secure this user as part of an idempotent playbook, you must create at least two tasks: the first must change the root user’s password, without providing any login_user/login_password details. The second must drop a ~/.my.cnf file containing the new root credentials. Subsequent runs of the playbook will then succeed by reading the new credentials from the file.
Dieses Problem mit einem leeren oder leeren Passwort war eine große Überraschung.
Rolle:
---
- name: Install MySQL packages
Sudo: yes
yum: name={{ item }} state=present
with_items:
- mysql
- mysql-server
- MySQL-python
- name: Start MySQL service
Sudo: yes
service: name=mysqld state=started enabled=true
- name: Update MySQL root password for root account
Sudo: yes
mysql_user: name=root password={{ db_root_password }} priv=*.*:ALL,GRANT
- name: Create .my.cnf file with root password credentials
Sudo: yes
template: src=.my.cnf.j2 dest=/root/.my.cnf owner=root group=root mode=0600
notify:
- restart mysql
- name: Create a database
Sudo: yes
mysql_db: name={{ db_name }}
collation=utf8_general_ci
encoding=utf8
state=present
- name: Create a database user
Sudo: yes
mysql_user: name={{ db_user }}
password={{ db_user_password }}
priv="{{ db_name }}.*:ALL"
Host=localhost
state=present
Handler:
---
- name: restart mysql
service: name=mysqld state=restarted
.my.cnf.j2:
[client]
user=root
password={{ db_root_password }}
Folgendes wird funktionieren (my.cnf zwischen 2 Aufrufen von mysql_user einfügen)
- name: 'Install MySQL'
yum: name={{ item }} state=present
with_items:
- MySQL-python
- mysql
- mysql-server
notify:
- restart-mysql
- name: 'Start Mysql Service'
action: service name=mysqld state=started enabled=yes
- name: 'Update Mysql Root Password'
mysql_user: name=root Host=localhost password={{ mysql_root_password }} state=present
- name: 'Copy Conf file with root password credentials'
template: src=../templates/my.cnf.j2 dest=/root/.my.cnf owner=root mode=0600
- name: 'Update Rest-Mysql Root Password'
mysql_user: name=root Host={{ item }} password={{ mysql_root_password }} state=present
with_items:
- "{{ ansible_hostname }}"
- "{{ ansible_eth0.ipv4.address }}"
- 127.0.0.1
- ::1
- name: 'Delete anonymous MySQL server user from server'
mysql_user: name="" Host={{ ansible_hostname }} state="absent"
Es ist wichtig, den mysql-Server vor dem Festlegen des root-Passworts neu zu starten. Ich hatte auch alles ausprobiert, was bis zu diesem Beitrag [Datum] gepostet wurde, und stellte fest, dass es unbedingt erforderlich ist, login_password
und login_user
zu übergeben.
(d. h.) Bei jeder Wiedergabe, nachdem Sie mysql_user
user:root
und password= {{ SOMEPASSWORD }}
eingestellt haben, müssen Sie sich für die nachfolgende Wiedergabe mit login_password
und login_user
verbinden.
Hinweis: Der with_items
basiert auf den von Ansible &/MariaDB erstellten Standardhosts.
Beispiel für das Sichern eines MariaDB-Servers:
---
# 'secure_mariadb.yml'
- name: 'Ensure MariaDB server is started and enabled on boot'
service: name={{ mariadb_service_name }} state=started enabled=yes
# localhost needs to be the last item for idempotency, see
# http://ansible.cc/docs/modules.html#mysql-user
- name: 'Update Mysql Root Password'
mysql_user: name=root
Host={{ item }}
password={{ root_db_password }}
priv=*.*:ALL,GRANT
state=present
with_items:
- 127.0.0.1
- ::1
- instance-1 # Created by MariaDB to prevent conflicts between port and sockets if multi-instances running on the same computer.
- localhost
- name: 'Create MariaDB main configuration file'
template: >
src=my.cnf.j2
dest=/etc/mysql/my.cnf
owner=root
group=root
mode=0600
- name: 'Ensure anonymous users are not in the database'
mysql_user: login_user=root
login_password={{ root_db_password }}
name=''
Host={{ item }}
state=absent
with_items:
- 127.0.0.1
- localhost
- name: 'Remove the test database'
mysql_db: login_user=root
login_password={{ root_db_password }}
name=test
state=absent
- name: 'Reload privilege tables'
command: 'mysql -ne "{{ item }}"'
with_items:
- FLUSH PRIVILEGES
changed_when: False
- name: 'Ensure MariaDB server is started and enabled on boot'
service: name={{ mariadb_service_name }} state=started enabled=yes
# 'End Of File'
Wir haben viel Zeit mit diesem Thema verbracht. Für MySQL 5.7 und höher schlussfolgerten wir, dass es einfacher ist, das root-Konto einfach zu ignorieren und Berechtigungen für einen normalen MySQL-Benutzer festzulegen.
unix_socket
auth plugin steht in Konflikt mit dem standard auth pluginunix_socket
-Plugins ist nahezu unmöglichWenn Sie Idempotenz aufgeben, können Sie es gut funktionieren lassen. Da jedoch der mögliche Wert des Ideals lautet, dass Idempotenz möglich ist, stellen wir fest, dass Entwickler Zeit mit der falschen Annahme verschwenden.
Die bloße Existenz einer Hack-Option wie check_implicit_admin
weist darauf hin, dass deterministisches MySQL-Setup nicht so einfach ist. Wenn es tatsächlich deterministisch ist, sollte es keine "Prüfung" geben, es sollte nur "tun" geben.
Ich weiß, das ist eine alte Frage, aber ich teile mein Arbeitsbuch für diejenigen, die es suchen:
---
- 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: Copy the configuration file (my.cnf)
template: src=my.cnf.j2 dest=/etc/mysql/my.cnf
notify:
- Restart MySQL
- 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
---
mysql_port: 3306 #Default is 3306, please change it if you are using non-standard
mysql_bind_address: "127.0.0.1" #Change it to "0.0.0.0",if you want to listen everywhere
mysql_root_pass: mypassword #MySQL Root Password
[client]
port = 3306
socket = /var/run/mysqld/mysqld.sock
[mysqld_safe]
socket = /var/run/mysqld/mysqld.sock
Nice = 0
[mysqld]
user = mysql
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
port = {{ mysql_port }}
basedir = /usr
datadir = /var/lib/mysql
tmpdir = /tmp
lc-messages-dir = /usr/share/mysql
skip-external-locking
bind-address = {{ mysql_bind_address }}
key_buffer = 16M
max_allowed_packet = 64M
thread_stack = 192K
thread_cache_size = 8
myisam-recover = BACKUP
query_cache_limit = 1M
query_cache_size = 16M
log_error = /var/log/mysql/error.log
expire_logs_days = 10
max_binlog_size = 100M
[mysqldump]
quick
quote-names
max_allowed_packet = 64M
[mysql]
[isamchk]
key_buffer = 16M
!includedir /etc/mysql/conf.d/
[client]
user=root
password={{ mysql_root_pass }}
Ich füge meine eigenen Ansichten zu den verschiedenen Ansätzen hinzu (Centos 7).
Die Variable mysql_root_password sollte in einem Ansible-Vault (besser) gespeichert oder in der Befehlszeile (schlechter) übergeben werden.
- name: "Ensure mariadb packages are installed"
yum: name={{ item }} state="present"
with_items:
- mariadb
- mariadb-server
- name: "Ensure mariadb is running and configured to start at boot"
service: name=mariadb state=started enabled=yes
# idempotently ensure secure mariadb installation --
# - attempts to connect as root user with no password and then set the [email protected] mysql password for each mysql root user mode.
# - ignore_errors is true because this task will always fail on subsequent runs (as the root user password has been changed from "")
- name: Change root user password on first run, this will only succeed (and only needs to succeed) on first playbook run
mysql_user: login_user=root
login_password=''
name=root
password={{ mysql_root_password }}
priv=*.*:ALL,GRANT
Host={{ item }}
with_items:
- "{{ ansible_hostname }}"
- 127.0.0.1
- ::1
- localhost
ignore_errors: true
- name: Ensure the anonymous mysql user ""@{{ansible_hostname}} is deleted
action: mysql_user user="" Host="{{ ansible_hostname }}" state="absent" login_user=root login_password={{ mysql_root_password }}
- name: Ensure the anonymous mysql user ""@localhost is deleted
action: mysql_user user="" state="absent" login_user=root login_password={{ sts_ad_password }}
- name: Ensure the mysql test database is deleted
action: mysql_db db=test state=absent login_user=root login_password={{ mysql_root_password }}