data_bagsの用途について

こんにちは。小宮です。 data_bagsについて内部的に解説する必要が生じたのでこちらにも書いておきます。

最近のdata_bagsの活用方法は以下のとおり

1.LDAPで管理していないシステム用途のOSユーザ情報をロードしてレシピで追加 2.SSL証明書の格納とレシピからロードしてtemplateで設定 3.ntpサーバの情報のロードとtemplateで設定 4.awsのクレデンシャル情報を管理して各種スクリプトへ埋め込み 5.mysqlやldapなどのパスワードなどアカウント情報の管理 6.roleとenvironmentに収まりきらないnginxやapacheのvhostやupstream等の情報の管理 7.gangliaのhead_nodeやcluster_nameの情報の管理


0.下準備的な解説

※前提条件としてchef-soloの場合"knife-solo_data_bag"というgemが必要なので入れる。 (gem listでなければgem installかbundlerで入れてください)

格納方法と確認方法

暗号化しない場合、viなど任意のエディタで編集OK chef-repository/data_bags/任意のディレクトリ名/任意のファイル名.json をつくる。 中身はjsonの規則にのっとっている必要があるので、シンタックスをjson_verifyでCHK。

cat data_bags/dirname/filename.json |json_verify で、JSON is valid と出るのを確認する

暗号化する場合、 まずEDITORの環境変数を~/.bashrcなりに設定しておく必要があるのと暗号化用の鍵を作って設定しておく必要がある。 (※鍵は案件ごとに異なるイメージで、.gitignoreに書いとく必要があります。  流出厳禁かつ無くすとデータが見えなくなります。)

export EDITOR=vi
vi .chef/knife.rb
------コメントを外す---------------------
encrypted_data_bag_secret "data_bag_key"
-----------------------------------------

※コメント外すと鍵指定しなくてもknifeコマンドでcreateした場合常に暗号化される  ゆえに暗号化せず扱いたいデータファイルはviで作るかコメントインしてから作る必要有

鍵が必要なら作る (※.chef/knife.rbの相対パスはchefリポジトリ直下を意味します)

openssl rand -base64 512 > data_bag_key

knife solo data bag create dirname filename # 作成(※既存は上書きされる)
knife solo data bag edit dirname filename   # ファイルをエディタで編集
knife solo data bag show dirname filename   # jsonの中身を表示
knife solo data bag list            # ディレクトリ一覧表示

・注意するべきこと →bashやexecuteリソースは極力使うべきではない。templateリソースつかってください。  bashでsedるとdata_bagsから変数に入れた特殊文字が展開されて意図しない値が入ったりします  もうひとつ、sedると毎度毎度同じsedをする必要が生じるなど冪等にならないです。


1.LDAPで管理していないシステム用途のOSユーザ情報をロードしてレシピで追加

これは大したことしてないのでポインタで失礼します Chefで既存手順のレシピを書く2(ユーザ作成) | DEVLAB 暗号化はしていないパターン。(パスワードはあらかじめ暗号化した文字列を入れる) 個人ユーザはLDAP管理でchefでは扱うのはldapのclient設定ファイル配布等です


2.SSL証明書の格納とレシピからロードしてtemplateで設定

apacheとnginxでやっておりますがnginxの場合についてを記載します。

ssl証明書の格納方法についてですが、改行コードを以下のように文字列に変換したものを貼ります。 証明書と鍵なのでもちろん暗号化で入れてロードしております。

cat cert.pem|perl -pe 's/n/n/g'

knife solo data bag create ssl jenkins
knife solo data bag edit ssl jenkins
knife solo data bag show ssl jenkins
{
  "id": "jenkins",
  "crt": "-----BEGIN CERTIFICATE-----nMIIDd~略~",
  "key": "~略~",
  "passkey": "~略~",
  "passphrase": "hogehoge"
}

レシピ側でロードする方法について(一部抜粋)

 # cat site-cookbooks/nginx/recipes/nginx_ssl_client.rb
---
 # data_type(≒role)名と環境名を変数に入れてdataファイルの名前にしてます
#role = ("#{node.roles}"[/[w_-]+/])
environment = ("#{node.environment}"[/w+/])
data_type = node['nginx']['data_type']
sslclientconf_type = node['nginx']['sslclientconf_type']
datafile = "#{data_type}_#{environment}"

 # 鍵の名前などを変数に定義(これはrole等のアトリビュートからロードされます
sslkeyfile = node['nginx']['sslkey1']
sslcrtfile = node['nginx']['sslcrt1']
clientcrtfile = node['nginx']['clientcrt']
clientcrlfile = node['nginx']['clientcrl']
sslkeydir = '/etc/nginx'

 # data_bagsの暗号化されたデータをロードして変数に定義してます
ssl = Chef::EncryptedDataBagItem.load("ssl", "#{datafile}")
sslcrtdata = ssl["crt"]
sslkeydata = ssl["key"]
clientcrtdata = ssl["clientcrt"]
#clientcrldata = ssl["clientcrl"]

 # data_typeでif分岐してるレシピです
if "#{data_type}" == ""
  #~略~
else
 # templateリソースを使うことで冪等性を保つことができます
 template "#{sslkeydir}/#{sslcrtfile}" do
   notifies :restart, 'service[nginx]'
   source "sslcrtfile.erb"
   variables({
     :sslcrtdata => sslcrtdata
   })
 end
 template "#{sslkeydir}/#{sslkeyfile}" do
   notifies :restart, 'service[nginx]'
   source "sslkeyfile.erb"
   variables({
     :sslkeydata => sslkeydata
   })
 end
 template "#{sslkeydir}/#{clientcrtfile}" do
   notifies :restart, 'service[nginx]'
   source "clientcrtfile.erb"
   variables({
     :clientcrtdata => clientcrtdata
   })
 end
---
templateファイルがどうなっているかといいますと
 # cat site-cookbooks/nginx/templates/default/sslcrtfile.erb
<%= @sslcrtdata %>
 # cat site-cookbooks/nginx/templates/default/sslkeyfile.erb
<%= @sslkeydata %>
 # cat site-cookbooks/nginx/templates/default/clientcrtfile.erb
<%= @clientcrtdata %>

variablesで@になってる箇所にdata_bagsからロードして変数に入ってる値をセットできます。


3.ntpサーバの情報のロードとtemplateで設定
5.mysqlやldapなどのパスワードなどアカウント情報の管理

これもポインタで失礼をば。 chef-soloのレシピのカスタマイズの記録 | DEVLAB ご参考まで。


4.awsのクレデンシャル情報を管理して各種スクリプトへ埋め込み

もちろん暗号化して入れます。 ssl証明書の場合とロード方法も埋め込む方法もあまり変わらないので省略します。

作成・編集・確認は以下のように。

 # knife solo data bag create awskeys deploy
 # knife solo data bag edit awskeys deploy
 # knife solo data bag show awskeys deploy

{
  "id": "deploy",
  "aws_access_key_id": "Axxxxxxxxxxxxxxxxxx",
  "aws_secret_access_key": "oxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "region": "us-xxxx-2"
}

こんなかんじでいれて、ロードする方法はたとえば以下のようにしています。(設置せずにスクリプトに変数渡してます)

cookbook_file "/usr/local/sbin/renamehost" do
  source "renamehost"
  owner 'root'
  group 'root'
  mode 0750
end

ohai "reload" do
  plugin "hostname"
end

# 環境から対応するAWSアカウントを取得する
env_rank = data_bag_item("master_data", "env_rank")
rank_awsaccount = data_bag_item("master_data", "rank_awsaccount")
environment = node.chef_environment
rank = env_rank[environment]
awsaccount = rank_awsaccount[rank]

# アカウントに対応する認証情報を取得する
awscredential = Chef::EncryptedDataBagItem.load("awskeys", "deploy_#{awsaccount}")
aws_access_key_id = awscredential["aws_access_key_id"]
aws_secret_access_key = awscredential["aws_secret_access_key"]
aws_region = awscredential["region"] 

role = ("#{node.roles}"[/[\w_-]+/])
bash "exec-renamehost" do
  not_if { node[:hostname] =~ /^#{role}/ }
  notifies :reload, "ohai[reload]", :immediately
  notifies :restart, "service[rsyslog]", :immediately
  code <<-EOC
    /usr/local/sbin/renamehost `echo #{aws_access_key_id} #{aws_secret_access_key} #{aws_region}`
  EOC
end

include_recipe "base_setting::hosts"

6.roleとenvironmentに収まりきらないnginxやapacheのvhostやupstream等の情報の管理

レシピ的には以下のとおりです

ngxdata = data_bag_item('nginx',"#{datafile}")
servername = ngxdata['servername1']
upstream = ngxdata['upstream1']
upstreamport = ngxdata['upstreamport']

 template "/etc/nginx/conf.d/ssl.conf" do
  source "#{role}/ssl.conf.erb"
  path '/etc/nginx/conf.d/ssl.conf'
  backup 5
  owner 'root'
  group 'root'
  mode '0644'
  action :create
  notifies :restart, 'service[nginx]'
  variables({
        :servername1 => servername,
        :upstream1 => upstream,
        :upstreamport => upstreamport
  })
 end

jsonファイルは特に暗号化していません(gitで確認しづらいですし)

# cat data_bags/nginx/nginx-hoge_test1.json
----
{
  "id": "nginx-hoge_test1",
  "servername1": "exsample.hoge.net",
  "upstream1": "internal-ELB-int-hoge-test1-xxxxxxx.us-xxxx-2.elb.amazonaws.com",
  "upstreamport": "80"
}
----

**roleもenvironmentも多数あって、どっちかに収まりきらないという時にはdata_bagsに入れるしかなさげです。


7.gangliaのhead_nodeやcluster_nameの情報の管理

これは6とあんまり変わらないので省略します

参考:

databags を使ってみた一部始終(1) - ようへいの日々精進 [chef] data bag活用法 | ITインフラ雑記帳 Chefで公開したくないJSONデータを暗号化するためにDataBagsを利用してみた記録 - さよならインターネット ご参考まで。読んでいただいてありがとうございました。**