APIの認証について

pemっていうファイルで認証しているのはなんとなくわかる。
このなんとなくを解消したいと思う。
本エントリはWikiの誤訳だと思ってほしいです。

API Clients

nodeデータはChef serverからの認証リクエストによって別々に管理されており、それはすなわちAPI Clientごとに管理されているということです。どのAPI Clientも公開/非公開キーを所持しています。
公開キーはChef server側で所持され、非公開キーはAPI Clientのほうで所持しています。nodeを実行したとき、非公開キーが自動的に/etc/chef/client.pem上に生成されます。knifeコマンドを利用するのが管理者の場合~/.chef/USERNAME.pemに非公開キーは生成されます。
全てのChef serverへのリクエストはHTTP headerに認証情報が入っています。署名はClient側のリクエストにClientの非公開キーを用いて暗号化したものを利用します。

The Validation Client

Chef Clientの初回アクセスはAPI Clientのキーをまだ生成できておらずChef serverへ認証リクエストを作る事ができません。
そこでデフォルトで"validation-client"という特殊なClientを使います。Chef clientが実行されて、最初にキーがなかったときChef serverに自分自身を登録するためvalidation-clientを一時的に借りるようにします。それをするために、validation clientの非公開キーをChef clientホストの/etc/chef/validation.pemにおくようにしてください。
一度Chef server側に登録できればこの特殊なClientは必要なくなります。一度validation clientを利用してChef serverに登録したらそのホストにおいてあるキーを削除する事をおすすめします。

Signed Header Authentication

APIの認証は基本的にリクエストごとに実施します。そしてそのリクエスト自体はClientがキーを利用して作成しています。つまるところ、結局HTTP headerに毎回ユニークな認証キーを作成しているだけです。リクエストは以下の項目を所持しています。

  • The HTTP Method (GET/PUT/POST/DELETE)
  • The Request Body in Base64
  • A Timestamp
  • Your Client ID

リクエストはClient側の非公開キーによって暗号化され、HTTP headerにセットされ、Chef server側でそれを解釈します。さらに受け取ったリクエストが本当にChef client側から送られてきたものなのかどうかをbodyがかわっていないかHTTP methodに変わりはないか必要な回数以内のリクエストなのかということから判断します。
全てのリクエストはHTTPS経由で行う事をお勧めします。
Chef Clientにはclient keyが発行されることになります。

Under the hood

新しいAPI Clientが作成されたとき、Chefは新しい公開/非公開キーを作成します。公開キーはChef serverで保持され、非公開キーはAPI Client側で保持されます。リクエストがきたときChef server側では以下のように検証を行います。(公開キーを利用します)
この検証は以下のメリットをもっています。

  • 全てのリクエストで認証が必要
  • Sessionを持たなくてよい
  • リクエストを改ざんされても問題ありません
  • end-to-endの認証なのでいかなるトランスポート層を通る事ができます

Chef Clientの認証の仕組みは以下の通りです。

  • 最初にChef clientがclient keyを持っているか確認します
    • もし持っていたら認証リクエストの発行を開始します
  • もし持っていなかった場合validation keyをもっているか確認します
    • もし持っていたらAPIを利用するためのリクエストを作成します
    • もし持っていなかったら、失敗です。。。
  • もしClient keyを作成できた場合、それを使って再度リクエストを作成します

The Web UI key

Chef web UIはChef APIのようなものです。違いはインストール時にキーが発行されることです。(同時にvalidation keyも発行されます)

Creating new API Client Keys with Knife

もしChef-server上にデフォルトのユーザでリクエストを送りたくなければ絶対に自分自身のキーを作った方がいいですよ。
API clientを生成する際は、まず以下のknifeコマンドを発行しましょう。

$ knife client create monkey
INFO: Created (or updated) client[monkey]

これから利用する非公開キーが発行されます。さらに以下のコマンドを発行しましょう。

knife client create monkey -f /tmp/monkey.pem

この例でいえば/tmp/monkey.pemに非公開キーができるはずです。

まとめ

  • Chef-serverは公開キー持ってればいい
  • Chef-Clientは非公開キーが必要
  • 上記のAPI Clientの作り方だと失敗したよ(僕の環境)
    • でもChef-webuiから発行できるよ
    • 発行したものをChef-clientサーバのpemファイルに保存すれば問題なく動きます
追記

API Clientの作り方失敗しませんでした

  • Client上に/etc/chefディレクトリ作成
  • /etc/chef/client.rbに最低限以下のものを設定したファイルをおく
    • client_key
    • chef_server_url
  • /etc/chef/validation.pemに非公開キーをおく
  • chef-clientを実行
    • chef-validatorが新しいclient_keyを作成してくれる
  • ~/.chef/knife.rbにclient.rbにnode_nameあたりを追加したものをコピー
    • knife node listで出力確認

なんかApacheインストールするためだけのレシピ

%w(#{node[:apache][:work_dir]} #{node[:apache][:install_dir]}).each do |dir|
  directory dir do
    owner "root"
    group "root"
    mode 0644
    action :create
    recirsive true
  end
end

cookbook_file File.join(node[:apache][:work_dir], "httpd.tar.gz") do
  source "httpd-2.2.17.tar.gz"
  action :create
  owner "root"
  group "root"
  mode 0644  
end

script "install apache" do
  interpreter 'bash'
  user 'root'
  cwd node[:apache][:work_dir]
  code <<-EOC
    tar -zxvf httpd.tar.gz
    cd httpd-2.2.17
    ./configure #{node[:apahe][:install_options]}
    make
    make install
  EOC
end