読者です 読者をやめる 読者になる 読者になる

knife-solo_data_bagを使ってEncrypted Data Bagで暗号化したファイルを配布する

knife-solo環境でリモート側のサーバーに暗号化したファイルを配布する方法についてメモ。

対象となるケース

  • knife-soloを使ってchef-soloを実行している
  • リモート側にローカルで暗号化したファイルを転送したい

実行環境

ローカル側(knife-solo実行環境)

  • OS: MacOS X 10.7.5
  • chef: 11.4.0
  • knife-solo: 0.3.0.pre2

リモート側(chef-solo実行環境)

  • OS: Amazon Linux
  • chef: 11.4.0

Data Bag

chefにはdata bagというものがあってリポジトリ全体にわたって定義する必要のある情報を格納しておく仕組みがあります。大抵はユーザのアカウント情報を管理したりしているのではないでしょうか。

Encrypt a Data Bag

ユーザ名や公開鍵などはリポジトリにcommitしておいてもいいですが、パスワードや秘密鍵など平文ではリポジトリに保存したくない情報を格納しておくために暗号化して保存しておく仕組みがEncrypted Data Bagです。Encrypted Data Bag を使うために必要なのはencrepted_data_bag_secretと呼ばれる共通鍵のみです。

Encrypted Data Bagを使うにはChef-Serverが使うことが前提となっているので、Chef-solo環境で単純にknife data bagは上手く動きません。chef-solo環境でEncrypted Data Bagを使うためには以下のドキュメントの通りに行えばよいです。

http://ed.victavision.co.uk/blog/post/4-8-2012-chef-solo-encrypted-data-bags

しかしながら、このドキュメントはknife-soloの環境では動きません。今回は、knife-solo_data_bagというプラグインをみつけたのででこれを使ってEncrypted Data Bagにデータを格納する方法を示します。

Knife Solo Data Bag

https://github.com/thbishop/knife-solo_data_bag

インストール

※ 2013.05.15現在 knife-solo_data_bag-0.3.2

$ gem install knife-solo_data_bag

使い方

  • knifeの設定に以下を追加
data_bag_path './data_bags' # Data Bagの格納パス
encrypted_data_bag_secret "./data_bag_key/secret_key" # 共通鍵のパス(作り方は後述)
  • 共通鍵が必要なので作成する

knife-soloのひな形でつくったディレクトリ構成に"data_bag_key"というディレクトリを作りその中に鍵を作ります。

$ ls
cookbooks/      data_bags/      nodes/          roles/          site-cookbooks/
$ mkdir data_bag_key
$ cd data_bag_key
$ openssl rand -base64 512 > secret_key
  • Encrypted Data Bagを作成

エディタが立ち上がるので、json形式で入力を行います。

$ knife solo data bag create apps app_1

## エディタが開くので、以下のように入力して保存。id":"app_1"が必須項目でdata bagのIDになるのでここは触らない(暗号化もされない)

{
   "id": "app_1",
   "user": "root",
   "pass": "password"
}
  • 暗号化されているか確認してみます
$ cat data_bags/apps/app_1.json
{"name":"data_bag_item_apps_app_1","json_class":"Chef::DataBagItem","chef_type":"data_bag_item","data_bag":"apps","raw_data":{"id":"app_1","user":{"encrypted_data":"Hhkl06zX1LqKPMVQudpuUo/jPnWdPjZsGhgk7GaTl9g=\n","iv":"/b5HKsYjPDfZoOPKohqptA==\n","version":1,"cipher":"aes-256-cbc"},"pass":{"encrypted_data":"BIqXd28qwukQlXwf0ev5wKu8RUBe7SLWwEwNbPxs2Ug=\n","iv":"IoZPgn960mpHh9W2WI8O8g==\n","version":1,"cipher":"aes-256-cbc"}}}


$ knife solo data bag show apps
app_1:
  id:   app_1
  pass:
    cipher:         aes-256-cbc
    encrypted_data: BIqXd28qwukQlXwf0ev5wKu8RUBe7SLWwEwNbPxs2Ug=

    iv:             IoZPgn960mpHh9W2WI8O8g==

    version:        1
  user:
    cipher:         aes-256-cbc
    encrypted_data: Hhkl06zX1LqKPMVQudpuUo/jPnWdPjZsGhgk7GaTl9g=

    iv:             /b5HKsYjPDfZoOPKohqptA==

    version:        1

さきほどエディタで入力した値が暗号化されているのを確認できました。

  • 復号化できるか確認
$ knife solo data bag show apps app_1 --secret-file ./data_bag_key/secret_key -F json
{
  "id": "app_1",
  "user": "root",
  "pass": "password"
}

RecipeからEncrypted Data Bagの取り出し方

data = Chef::EncryptedDataBagItem.load("apps", "app_1")
user = data["user"]
password = data["pass"]

※ 共通鍵ファイルがchef-soloの設定のデフォルトの /etc/chef/encrypted_data_bag_secret に配置されている場合はsecretを指定しなくてもOKらしい

例:gitの秘密鍵を配るレシピ

  • リモート側のサーバーで秘密鍵でgitのcloneをする必要があったので以下のようなchefのレシピを書いて、checkoutするユーザの.sshの配下に秘密鍵を配布してみました。
$ knife solo data bag create apps git --secret-file ./data_bag_key/secret_key

## エディタでid_rsaの値の部分に秘密鍵の内容を一行になるようにコピペ

{
  "id":"git",
  "id_rsa": "<PRIVATE KEY 改行は\nに変換しておくこと>"
}
  • 'www'というユーザの.ssh配下にgit用の秘密鍵を作る
secret = Chef::EncryptedDataBagItem.load_secret("/tmp/chef-solo/data_bag_key/secret_key")
git = Chef::EncryptedDataBagItem.load("apps", "git", secret)
id_rsa = git["id_rsa"]

file "/home/www/.ssh/id_rsa" do
    content id_rsa
    action :create
    mode 0400
    owner "www"
    group "www"
end

ポイントは、load_secretの読み込み先をknife-soloの転送先パスの配下のキーを指定しています。以下のように設定をしておけば問題ないかと思います。

knife[:solo_path] = '/tmp/chef-solo'
data_bag_path './data_bags'
encrypted_data_bag_secret "./data_bag_key/secret_key"

まとめ

knife-solo_data_bagを使ってknife-soloでリモート側のサーバーに暗号化したファイルを配布する方法について書きました。これでリポジトリにパスワードや秘密鍵などの平文では保存したくない情報をcommitできるかと思います。