最新GA版 MySQL5.6 をセキュア・インストールするレシピ

#[SoftLayerクッキングLABO] (http://qiita.com/MahoTakara/items/464da29ccf932698b753)

# このレシピで出来ること
使い慣れたLinuxのバージョン(CentOS6/7,Ubuntu14)に最新版のMySQL5.6.27をインストールするレシピです。 このレシピの中では、ターゲットのサーバーからオラクルのダウンロードサイトにアクセスしてインストール用tarファイルを入手します。


# レシピの要約
この mysql01 レシピは、箇条書きの処理を実行します。

- 前提パッケージの導入
- MySQL tarファイルのダウンロードと展開
- MySQLのインストール
- MySQLの自動起動設定
- コンテナ領域を/data1に作成
- AppArmor(アプリアーマーの設定 Ubuntuのみ)
- 設定ファイルの置き場所作成 (CentOSのみ)
- MySQL設定ファイルの配置
- /usr/bin/mysql_install_db コンテナ領域作成
- セキュア・インストールのスクリプト実行
- アプリ用のデータベースの作成
- アプリ用のユーザー作成

# レシピの説明
このレシピを利用するにあたり必要な事として、minimal インストールの CentOS,Ubuntu を対象にしており、MySQLが導入されているケースを対象にしていません。


## レシピのファイル

クックブックの中で設定するのは、下記の３種類です。

```
chef@ChefWs:~/chef-repo/site-cookbooks$ tree mysql01/
mysql01/
├── CHANGELOG.md
├── README.md
├── attributes
│   └── default.rb    (1) アトリビュート設定 
├── definitions
├── files
├── libraries
├── metadata.rb
├── providers
├── recipes
│   └── default.rb   (2) レシピ本体
├── resources
└── templates
    └── default  (3) MySQL設定ファイル
        ├── character-set.cnf.erb
        ├── create_db.sql.erb
        ├── create_user.sql.erb
        ├── engine.cnf.erb
        ├── my.cnf.erb
        ├── mysqld_safe_syslog.cnf.erb
        ├── secure_install.sql.erb
        └── usr.sbin.mysqld.erb
```

## (1) アトリビュート設定
インストールするMySQLのルートパスワード、データベース、アプリユーザーとパスワードを設定します。
最後の５番目は、"service" とすれば、MySQLの設定を実行します。 stanby とするれば、インストールまでにして、MySQLのコンテナ領域の作成や設定を実施しません。これは、アクティブ・スタンバイの構成を組む場合のスタンバイ機をセットアップするために利用します。

```
default["mysql"]["root_password"] = 'passw0rd'    (1)ルートパスワード
default["mysql"]["db_name"] = 'testdb'  (2)データベース名
default["mysql"]["user"]["name"] = 'wordpress' (3)アプリユーザー
default["mysql"]["user"]["password"] = 'wordpress' (4)アプリユーザーのパスワード
default["mysql"]["node"] = 'service' (5) service または、それ以外で設定
```

## (2) レシピ本体

このレシピは、CentOS/RedHat 6と7, Ubuntu のケースで分岐を持たせ、それぞれの環境に合わせて対応する様にしています。 MySQLのバージョンは、アトリビュートに出すのではなく、このレシピの中にベタ書きしているので、利用したいバージョンに書き替えて対応する必要があります。

SoftLayerの CentOS の SELinux はでデフォルトで無効になっており、そのまま、利用します。しかし、Ubuntu の SELinux に相当する AppArmorは、有効化されており、MySQLのコンテナ領域を/data1に移動するだけでは、動作しません。 この為、AppArmor の aa コマンドを利用して、MySQLが /data1 を利用できる様に設定変更しています。

```
chef@ChefWs:~/chef-repo/site-cookbooks/mysql01/recipes$ cat default.rb 
# -*- coding: utf-8 -*-
#
# Cookbook Name:: mysql01
# Recipe:: default
# 
# MySQL 5.6 コミュニティ・エディションをダウンロード
# インストール＆セットアップするレシピ
#

work_dir = '/root/mysql'
conf_dir = '/etc/mysql'

#
# パッケージ導入 Ubuntu,CentOS/Redhat
#
case node['platform']

when 'ubuntu'
  execute 'apt-get update' do
    command 'apt-get update'
  end

  # 前提パッケージ
  package 'apparmor-utils'
  package 'libaio1'

  # https://dev.mysql.com/downloads/mysql/ のサイトからMySQLのtarファイルのURLを拾って指定
  tar_url = 'http://dev.mysql.com/get/Downloads/MySQL-5.6/mysql-server_5.6.27-1ubuntu14.04_amd64.deb-bundle.tar'

when 'centos','redhat'
  execute 'yum update' do
    command 'yum update -y'
    action :run
  end

  # 前提パッケージ
  package 'wget'
  package 'libaio'

  # https://dev.mysql.com/downloads/mysql/ のサイトからMySQLのtarファイルのURLを拾って指定
  case node['platform_version'].to_i
    when 6
      tar_url = 'http://dev.mysql.com/get/Downloads/MySQL-5.6/MySQL-5.6.27-1.el6.x86_64.rpm-bundle.tar'    
    when 7
      package 'net-tools'

      tar_url = 'http://dev.mysql.com/get/Downloads/MySQL-5.6/MySQL-5.6.27-1.el7.x86_64.rpm-bundle.tar'
  end
end

#
# MySQL tarファイルの取得と展開
#
script "install_mysql" do
  interpreter "bash"
  user        "root"
  code <<-EOL
     # rm -fr /etc/my.cnf /etc/my.cnf.d #{conf_dir}
     mkdir #{conf_dir}
     mkdir #{work_dir}
     wget -P #{work_dir} #{tar_url}
     cd #{work_dir}
     tar xvf `ls *.tar`
  EOL
  action :run
end


#
# MySQL Serverのインストール
#
case node['platform']
when 'ubuntu'
  dpkg_package "#{work_dir}/mysql-common_5.6.27-1ubuntu14.04_amd64.deb"
  dpkg_package "#{work_dir}/mysql-community-server_5.6.27-1ubuntu14.04_amd64.deb"
  dpkg_package "#{work_dir}/mysql-community-client_5.6.27-1ubuntu14.04_amd64.deb"
when 'centos','redhat'
  case node['platform_version'].to_i
    when 6
      # 依存関係のあるモジュール postfix以下のコマンドは実行できない。
      #rpm_package "mysql-libs-5.1.73-5.el6_6.x86_64" do
      #  action :remove
      #end
      execute "delete mysql-libs-5.1.73-5.el6_6.x86_64" do
        command "rpm -e --nodeps mysql-libs-5.1.73-5.el6_6.x86_64"
        action :run
        ignore_failure true
      end

      rpm_package "#{work_dir}/MySQL-shared-5.6.27-1.el6.x86_64.rpm" 
      rpm_package "#{work_dir}/MySQL-shared-compat-5.6.27-1.el6.x86_64.rpm" 
      rpm_package "#{work_dir}/MySQL-server-5.6.27-1.el6.x86_64.rpm"
      rpm_package "#{work_dir}/MySQL-client-5.6.27-1.el6.x86_64.rpm"

    when 7
      # 依存関係のあるモジュール postfix以下のコマンドは実行できない。
      #rpm_package "mariadb-libs-5.5.44-1.el7_1.x86_64" do
      #  action :remove
      #end
      execute "delete mariadb-libs-5.5.44-1.el7_1.x86_64" do
        command "rpm -e --nodeps mariadb-libs-5.5.44-1.el7_1.x86_64"
        action :run
        ignore_failure true
      end

      rpm_package "#{work_dir}/MySQL-shared-5.6.27-1.el7.x86_64.rpm" 
      rpm_package "#{work_dir}/MySQL-shared-compat-5.6.27-1.el7.x86_64.rpm"
      rpm_package "#{work_dir}/MySQL-server-5.6.27-1.el7.x86_64.rpm"
      rpm_package "#{work_dir}/MySQL-client-5.6.27-1.el7.x86_64.rpm"
  end
end


#
# MySQLの自動起動と停止を設定
#
service "mysql" do
  supports :start => true, :stop => true
  action [ :enable, :stop]
end


#
# コンテナ領域を新規作成
#  iSCSIと組み合わせて、外部共用ディスクのマウント・ポイントとして
#  利用できる様にする
#
directory "/data1" do
  owner 'mysql'
  group 'mysql'
  mode '0755'
  action :create
  notifies :stop, "service[mysql]", :immediately
end


case node['platform']
#
# Ubuntu の AppArmor アプリ アーマーの設定
#
when 'ubuntu','debian'
  execute "aa-disable_usr.bin.mysqld" do
    command "aa-disable usr.sbin.mysqld"
    ignore_failure true
    action :run
  end
  execute "aa-enforce_usr.bin.mysqld" do
    command "aa-enforce usr.sbin.mysqld"
    ignore_failure true
    action :nothing
  end
  template "/etc/apparmor.d/usr.sbin.mysqld" do
    source "usr.sbin.mysqld.erb"
    owner "root"
    group "root"
    mode 0644
    notifies :run, "execute[aa-enforce_usr.bin.mysqld]"
  end


#
# CentOS/RedHat は設定ファイルの置き場作成
#
when 'centos','redhat'
  directory "/etc/mysql" do
    owner "root"
    group "root"
    mode '0755'
    action :create
  end
  directory "/etc/mysql/conf.d" do
    owner "root"
    group "root"
    mode '0755'
    action :create
  end
  directory "/var/log/mysql" do
    owner "mysql"
    group "mysql"
    mode '0755'
    action :create
  end

end # case


#
# MySQL設定ファイルの配置
#
template "/etc/mysql/my.cnf" do
  source "my.cnf.erb"
  owner "root"
  group "root"
  mode 0644
end
template "/etc/mysql/conf.d/character-set.cnf" do
  source "character-set.cnf.erb"
  owner "root"
  group "root"
  mode 0644
end
template "/etc/mysql/conf.d/engine.cnf" do
  source "engine.cnf.erb"
  owner "root"
  group "root"
  mode 0644
end
template "/etc/mysql/conf.d/mysqld_safe_syslog.cnf" do
  source "mysqld_safe_syslog.cnf.erb"
  owner "root"
  group "root"
  mode 0644
end


#
# 先の設定ファイルが指すコンテナ領域に
# MySQLのコンテナ、ログ等を作成する
#
# 共有ディスクにセットアップする事を想定して
# この設定が動作するのは、service ノードの場合のみで
# standby ノードの場合には、実行しない。
# 
execute "mysqL_install_db" do
  command "/usr/bin/mysql_install_db"
  action :run
  only_if {node["mysql"]["node"] == 'service'}
  notifies :start, "service[mysql]", :immediately
end

#
# secure_install.sql を実行してパスワードを設定
#
root_password = node["mysql"]["root_password"]
template "#{Chef::Config[:file_cache_path]}/secure_install.sql" do
  owner "root"
  group "root"
  mode 0644
  source "secure_install.sql.erb"
  variables({
    :root_password => root_password,
  })
  only_if {node["mysql"]["node"] == 'service'}
  action :create
end


execute "secure_install" do
  command "/usr/bin/mysql -u root < #{Chef::Config[:file_cache_path]}/secure_install.sql"
  # 匿名ユーザーの削除で存在しないとエラーとなるので追加
  ignore_failure true
  only_if "/usr/bin/mysql -u root -e 'show databases;'"
  only_if {node["mysql"]["node"] == 'service'}
  action :run
end


#
# データベースを作成
# 
db_name = node["mysql"]["db_name"]
template "#{Chef::Config[:file_cache_path]}/create_db.sql" do
  owner "root"
  group "root"
  mode 0644
  source "create_db.sql.erb"
  variables({
    :db_name => db_name,
  })
  only_if {node["mysql"]["node"] == 'service'}
  action :create
end
execute "create_db" do
  command "/usr/bin/mysql -u root -p#{root_password} < #{Chef::Config[:file_cache_path]}/create_db.sql"
  not_if "/usr/bin/mysql -u root -p#{root_password} -D #{db_name}"
  only_if {node["mysql"]["node"] == 'service'}
  action :run
end


#
# ユーザーを追加
#
user_name     = node["mysql"]["user"]["name"]
user_password = node["mysql"]["user"]["password"]

template "#{Chef::Config[:file_cache_path]}/create_user.sql" do
  owner "root"
  group "root"
  mode 0644
  source "create_user.sql.erb"
  variables({
    :db_name => db_name,
    :username => user_name,
    :password => user_password,
  })
  only_if {node["mysql"]["node"] == 'service'}
  action :create
end
execute "create_user" do
  command "/usr/bin/mysql -u root -p#{root_password} < #{Chef::Config[:file_cache_path]}/create_user.sql"
  not_if "/usr/bin/mysql -u #{user_name} -p#{user_password} -D #{db_name}"
  only_if {node["mysql"]["node"] == 'service'}
  action :run
end
```

## (3) MySQL設定ファイル

MySQLのファイルは、ここで解説するよりも、GitHubに登録した現物をみるのが良いと思いますので、ここでは、それぞれのファイルの目的を記載しておきます。

 
- character-set.cnf.erb        utf-8 設定
- create_db.sql.erb            utf-8 でデータベース作成
- create_user.sql.erb          アプリユーザー登録 任意ホストから許可
- engine.cnf.erb               InnoDB指定
- my.cnf.erb                   MySQL設定本体 （ほとんどデフォルト）
- mysqld_safe_syslog.cnf.erb   Syslog サービス指定
- secure_install.sql.erb       匿名ユーザーの削除、root接続を許可するホスト設定
- usr.sbin.mysqld.erb          AppArmorの設定ファイル


#レシピの適用手順
起動してきた仮想サーバーや物理サーバーに対して、以下のコマンドを実行するだけです。 サーバーのOSによる違いは、レシピの中で切替えて動作するので、オプション等を変更する必要はありません。
既にCHEF Solo を利用している方はご存知と思いますが、リポジトリ chef-repo のディレクトリをカレントにする必要があります。

```
chef@ChefWs:~/chef-repo$ knife solo bootstrap 10.132.253.30 -x root -r 'recipe[mysql01]' -i ~/key/chefkey
```
既にchef-clientが導入されている場合は、bootstrap の部分を cook に変えて実行します。

## このレシピで作成したMySQLサーバーにログイン
以下は、アトリビュートに設定してある ユーザー名、パスワード、データベース名でログインしてみた結果です。

```
chef@ChefWs:~$ ssh root@10.132.253.30 -i ~/key/chefkey
Last login: Thu Oct 15 21:05:10 2015 from 10.132.253.38
[root@server3 ~]# mysql -u wordpress -pwordpress testdb
Warning: Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 7
Server version: 5.6.27 MySQL Community Server (GPL)

Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> \s
--------------
mysql  Ver 14.14 Distrib 5.6.27, for Linux (x86_64) using  EditLine wrapper

Connection id:		7
Current database:	testdb
Current user:		wordpress@localhost
SSL:			Not in use
Current pager:		stdout
Using outfile:		''
Using delimiter:	;
Server version:		5.6.27 MySQL Community Server (GPL)
Protocol version:	10
Connection:		Localhost via UNIX socket
Server characterset:	utf8
Db     characterset:	utf8
Client characterset:	utf8
Conn.  characterset:	utf8
UNIX socket:		/var/run/mysqld/mysqld.sock
Uptime:			2 hours 3 min 6 sec

Threads: 1  Questions: 26  Slow queries: 0  Opens: 68  Flush tables: 1  Open tables: 61  Queries per second avg: 0.003
--------------

mysql> 
```


# テスト済みのLinuxディストリビューション
SoftLayerでサーバーオーダー時に選択できるOSの中から、確認できたもののリストです。

- Ubuntu 14.04 64bit minimal install
- CentOS 7.1 64bit minimal install
- CentOS 6.7 64bit minimal install


# レシピの置き場所
最新版のレシピはGitHubにあります。
- GitHub takara9/chef-repo/ iscsiStorage01  https://github.com/takara9/chef-repo/tree/master/site-cookbooks/mysql01


# Chef 関連マニュアル
このレシピを作るにあたって参照したCHEFマニュアルのリンクです。
- script  (https://docs.chef.io/resource_script.html )
- execute (https://docs.chef.io/resource_execute.html )
- package (https://docs.chef.io/resource_package.html )
- template (https://docs.chef.io/resource_template.html)
- file (https://docs.chef.io/resource_file.html)
- directory (https://docs.chef.io/resource_directory.html)



# 参考資料
- https://dev.mysql.com/doc/refman/5.6/en/binary-installation.html