web-dev-qa-db-ja.com

Ansibleべき等MySQLインストールプレイブック

Ansibleを構成管理に使用して、AWSにMySQLサーバーをセットアップしたい。 AmazonのデフォルトAMI(AMI-3275ee5b)を使用しています。これは、パッケージ管理にyumを使用します。

以下のプレイブックを実行すると、すべてうまくいきます。しかし、2回目に実行すると、タスクConfigure the root credentialsは失敗します。これは、このPlaybookを前回実行したときに更新されていたため、MySQLの古いパスワードが一致しなくなったためです。

これにより、Playbookはide等ではなくなりますが、これは好ましくありません。プレイブックを何度でも実行できるようにしたい。

- 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

これを解決する最良の方法は何ですか?つまり、Playbookをi等にすることです?前もって感謝します!

41
ndequeker

安全なMySQLインストール用のAnsibleバージョン。

mysql_secure_installation.yml

- 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

templates/root/my.cnf.j2

[client]
user=root
password={{ mysql_root_password }}

参照資料

29
ndequeker

これについて coderwall に投稿しましたが、元の投稿のコメントでdennisjacの改善を再現します。

それをdem等に行う秘trickは、mysql_userモジュールが見つかった場合に〜/ .my.cnfファイルをロードすることを知ることです。

最初にパスワードを変更してから、パスワード資格情報を使用して.my.cnfファイルをコピーします。もう一度実行しようとすると、myqsl_user ansibleモジュールは.my.cnfを見つけて新しいパスワードを使用します。

- 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

.my.cnfテンプレートは次のようになります。

[client]
user=root
password={{ mysql_root_password }}

編集:Dhananjay Neneの推奨するコメントに特権を追加し、変数補間を変更してドル記号の代わりに中括弧を使用しました

35
Lorin Hochstein

これは、@ LorinHochSteinが提案するソリューションの代替ソリューションです

私の制約の1つは、パスワードがサーバー上のどこにでもプレーンテキストファイルに保存されないようにすることでした。したがって、.my.cnfは実用的な命題ではありませんでした

解決策:

- 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

そして、varsファイルで

current_password: foobar
new_password: "{{ current_password }}"

Mysqlのパスワードを変更しない場合は、通常どおりコマンドラインでansible Playbookを実行します。

Mysqlのパスワードを変更する場合、コマンドラインに次を追加します。コマンドラインで指定すると、コマンドラインで設定されたパラメーターが、varsファイルでデフォルト設定されているパラメーターよりも優先されます。

$ ansible-playbook ........ --extra-vars "new_password=buzzz"

コマンドを実行した後、次のようにvarsファイルを変更します

current_password=buzzz
new_password={{ current_password }}
5
Dhananjay Nene

前の回答に加えて、コマンドを実行する前に手動の手順が必要ではありませんでした。つまり、新しいサーバーを起動し、最初にルートパスワードを手動で変更せずにプレイブックを実行するだけです。ルートパスワードがnullの場合、{{mysql_password}}が最初に機能するとは思われません。mysql_passwordはまだ(-eでオーバーライドしたい場合を除き)どこかで定義する必要があるためです。

そこで、それを行うルールを追加しましたが、失敗した場合は無視されます。これは、ここにある他のコマンドに追加され、その前に表示されます。

- 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
5
mahemoff

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
4
anneb

まあ、これは少し複雑になりました。私はこれに丸一日を費やし、以下にリストされたソリューションを思いつきました。重要な点は、AnsibleがMySQLサーバーをインストールする方法です。 mysql_user モジュールのドキュメントから(ページの最後のメモ):

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.

空白またはヌルのパスワードに関するこの問題は、大きな驚きでした。

ロール

---

- 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

ハンドラー

---

- name: restart mysql
  service: name=mysqld state=restarted

。my.cnf.j2

[client]
user=root
password={{ db_root_password }}
3
oblalex

以下が機能します(2つのmysql_user呼び出しの間にmy.cnfを挿入します)


- 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"
1
smuniyappa

ルートパスワードを設定する前に、mysqlサーバーを起動/再起動することが重要です。また、この投稿[日付]までに投稿されたすべてを試してみましたが、login_passwordlogin_userを渡すことが不可欠であることがわかりました。

(つまり)mysql_useruser:rootおよびpassword= {{ SOMEPASSWORD }}を設定した後のすべての再生、その後の再生にはlogin_passwordおよびlogin_userを使用して接続する必要があります。

注:以下のwith_itemsは、Ansible&/ MariaDBのデフォルトホストが作成したものに基づいています

MariaDBサーバーの保護の例:

---
# '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'
0
user742030

私たちはこの問題に多くの時間を費やしました。 MySQL 5.7以降では、ルートアカウントを単純に無視し、通常のMySQLユーザーにアクセス許可を設定する方が簡単だと結論付けました。

理由

  1. ルートパスワードの設定は難しい
  2. unix_socket認証プラグインが標準認証プラグインと競合しています
  3. unix_socketプラグインを無効にした後にルートパスワードを確実に変更することはほとんど不可能です
  4. Ansibleは、ルートパスワードを1ステップでアトミックに変更するのにはあまり適していません
  5. 通常のアカウントを使用するとうまく機能します

べき等性を放棄すると、正常に機能するようになります。しかし、無理のない価値提案はi等性が可能であるということなので、開発者は間違った仮定で時間を浪費することがわかります。

check_implicit_adminのようなハックオプションが存在するだけで、決定論的なMySQLセットアップはそれほど簡単ではないことが示唆され始めます。それが実際に決定論的である場合、「チェック」はなく、「実行」のみが行われるべきです。

0
Ryan

私はこれが古い質問であることを知っていますが、それを探している人たちのために私の作業プレイブックを共有しています:

mysql.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: 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

vars.yml

---
 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

my.cnf.j2

[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/

root.cnf.j2

[client]
user=root
password={{ mysql_root_pass }}
0
Arbab Nazar

さまざまなアプローチについて独自の見解を追加しています(centos 7)。

変数mysql_root_passwordは、ansible-vaultに保存する(より良い)か、コマンドラインで渡す(より悪い)必要があります

- 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 root@ 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 }}
0
Ben