Develop with pleasure!

福岡でCloudとかBlockchainとか。

knife ec2 を使ってインスタンスを起動した際の鍵の配布

opscode/knife-ec2 · GitHubを使って、EC2のインスタンスを起動すると、インスタンスがChef Serverに接続し、インスタンスに対し登録されているレシピの適用を始める。その際にどうやってChef Serverとインスタンス間で認証が行われているのか気になったので調べてみた。

knife ec2 server create では、起動したインスタンスに対して、knifeのbootstrapが実行され↓の処理を行う。

  • chef clientのインストール
  • validation_keyの配備
    /etc/chef/validation.pemに配置される。
  • /etc/chef/client.rbを配備
  • encrypted_data_bag_secretの配備
    /etc/chef/encrypted_data_bag_secretに配置される。
  • /etc/chef/first-boot.jsonの配備
  • chef-clientの実行

このデフォのbootstrapの定義内容は↓

bash -c '
<%= "export http_proxy=\"#{knife_config[:bootstrap_proxy]}\"" if knife_config[:bootstrap_proxy] -%>

exists() {
  if command -v $1 &>/dev/null
  then
    return 0
  else
    return 1
  fi
}

install_sh="http://opscode.com/chef/install.sh"
version_string="-v <%= chef_version %>"

if ! exists /usr/bin/chef-client; then
  if exists wget; then
    bash <(wget <%= "--proxy=on " if knife_config[:bootstrap_proxy] %> ${install_sh} -O -) ${version_string}
  else
    if exists curl; then
      bash <(curl -L <%= "--proxy=on " if knife_config[:bootstrap_proxy] %> ${install_sh}) ${version_string}
    fi
  fi
fi

mkdir -p /etc/chef

(
cat <<'EOP'
<%= validation_key %>
EOP
) > /tmp/validation.pem
awk NF /tmp/validation.pem > /etc/chef/validation.pem
rm /tmp/validation.pem


<% if @chef_config[:encrypted_data_bag_secret] -%>
(
cat <<'EOP'
<%= encrypted_data_bag_secret %>
EOP
) > /tmp/encrypted_data_bag_secret
awk NF /tmp/encrypted_data_bag_secret > /etc/chef/encrypted_data_bag_secret
rm /tmp/encrypted_data_bag_secret
<% end -%>

(
cat <<'EOP'
<%= config_content %>
EOP
) > /etc/chef/client.rb

(
cat <<'EOP'
<%= first_boot.to_json %>
EOP
) > /etc/chef/first-boot.json

<%= start_chef %>'

(ちなみにbootstrap自体はchefのgem内のchef/knife/直下に各ディストリビューション毎に定義されてるけど、オプションで独自のbootstrapファイルを指定することも可能)

インスタンス(chef-client)とChef Server間の認証に必要な鍵は、この段階でvalidation.pemとして配備されてる。このvalidation.pemはknifeコマンドを実行した端末のknife.rbに定義されているvalidation_keyの内容を読み込んでvalidation.pemとして配備しており、このvalidation.pemを用いてインスタンスがChef Serverと接続している模様。
※尚、一度このvalidation.pemを使用して接続した後は、/etc/chef/client.pemというファイルが配置され、以降のChef Serverへの接続はこのclient.rbが使用されるため、validation.pemは不要となる。Secret Training of Opscode Chef - jedipunkz' blogあたりを見ると、このvalidation.pemは削除しておいた方が良さそうね。


あとそれとは別に、DBやアプリケーションのパスワードなんかをattributesに定義してたらChef Server上で丸見えになって危険じゃ?と思ってたけど、そういったケースに対応するのがencrypted_data_bag_secretなのね。encrypted_data_bag_secretという鍵を生成し、data bag作成時にこの鍵を使ってパラメータの暗号化を行うことで、Chef Server上でも暗号化後の値しか見れないという仕組みになるみたい。各chef client上では、↑のbootstrap処理でencrypted_data_bag_secretの鍵が配布されるので、その鍵を使って復号化すると。
参考:ChefでのMySQLパスワードの扱い - matetsuだもんで