はちびる日記

Chef Solo + knife-soloでData Bag Itemを暗号化する

Chef Server/Client構成の環境であればknifeコマンドを使用して、knife data bag create DATA_BAG_NAME DATA_BAG_ITEM --secret-file FILEで Data Bag Itemを暗号化することができますが、Chef Solo環境ではこれが使えません。

代替策としてChefのencrypted_data_bag_itemライブラリをロードしてencrypt_data_bag_itemメソッドを直接呼び出す方法がありますが、 knife-solo_data_bagを使うとこれが簡単に出来る、ということで、 Linuxユーザのユーザ名とパスワードをData Bagに格納しレシピからそれらを使用するところまでをやってみました。

環境

  • ワーク端末 : Mac OSX 10.9
  • Chef : 11.14.0.alpha.1
  • knife-solo : 0.4.1
  • リモートサーバ : CentOS 6.4

knife-solo_data_bagインストール

gemでインストールします。

$ gem install knife-solo_data_bag

bundlerを使ってインストールする場合は、Gemfilegem knife-solo_data_bagを追加してbundle installを実行します。

共通鍵生成

暗号化で使用する共通鍵を作成します。

今回はopensslコマンドを使ってChefレポジトリの.chefディレクトリ下にdata_bag_keyという名称で鍵を作成しました。

$ cd <Chef Repository Name>
$ openssl rand -base64 512 | tr -d '\r\n' > .chef/data_bag_key

knife.rb設定

.chef/knife.rbで、Data Bagディレクトリ(jsonファイルを格納するディレクトリ)のパス(data_bag_path)と共通鍵のファイルパス(encrypted_data_bag_secret)を指定します。

data_bag_path    "data_bags"
encrypted_data_bag_secret ".chef/data_bag_key"

共通鍵のファイルパスはData Bagの作成時にknife soloのコマンドラインオプションで指定することができます。ただし、 knife solo cook実行時にはknife.rbの設定が参照されるので上記のようにknife.rbでの設定が必要です。 (encrypted_data_bag_secretで指定した共通鍵がリモートサーバにアップロードされます。)

EDITOR環境変数設定

knife soloコマンドでData bagを作成すると、環境変数EDITORで指定されたエディタが自動的に起動しData Bagのjsonファイルがオープンされます。 使用したいエディタを予め.bash_profileなどで定義しておくと便利です。

# vimを使う場合
export EDITOR='vim'
# atomを使う場合
export EDITOR='atom -w'
# sublime textを使う場合
export EDITOR='subl -w'

AtomSublime Textを使う場合は予めそれぞれのシェルコマンドを作成しておいて、 それらを-w付き(wait mode)で起動するように環境変数を設定します。

knife-solo_data_bagでは、knife solo data bag createコマンドでData bagの作成と暗号化を行います。

Data bagの作成と暗号化は、

  1. tempディレクトリ($TMPDIRで指定されたディレクトリ)にテンポラリのjsonファイルが作成される
  2. jsonファイルを編集する(この時点ではData Bag Itemは暗号化されていない)
  3. 編集後、エディタを閉じたタイミングでData BagディレクトリにData Bag Itemが暗号化されたjsonファイルが作成される

という3ステップで行わるので、エディタを-w付きで起動する設定にしておかないと1.の時点(エディタの起動が完了した時点)でknife soloコマンドが終了してしまい、 Data Bagディレクトリに“id"キーだけのjsonファイルが作成される一方でtempファイルを虚しく編集する結果となってしまいます。

Data Bag作成

knife soloコマンドを実行しData Bagを作成します。 以下はusersという名前のData Bagとyuyawataという名前のData Bag Itemを作成する例です。 (Data Bagディレクトリ下にusersディレクトリが作成され、その下にyuyawata.jsonが作成されます。)

$ knife solo data bag create users yuyawata --secret-file .chef/data_bag_key

EDITOR環境変数で指定したエディタが起動するので、jsonファイルを編集&保存し、エディタを閉じます。

以下はLinuxユーザのユーザ名とそのパスワードを定義する例です。

{
  "id": "yuyawata",
  "username": "yuyawata",
  "password": "$6$MySalt$OLjTmmVn..5nCbb7sgph9B0QlLklMrC/gs8PiCAfyuJLqO2wkOdvsmXkmdN/i5lY8me8zcZfvF4BZAK3Qw93F/"
}

Linuxユーザのパスワードはshadow passwordの形式で指定する必要があります。

MD5でパスワードを指定する

opensslコマンドを使うとMD5でshadow passwordを生成することができます。パスワードSALTをMySalt、パスワードをdatabagtestとする場合は以下のようにコマンドを実行します。

openssl password -1 -salt "MySalt" "databagtest"

SHA512でパスワードを指定する

opensslコマンドはMD5にしか対応していません。SHA256やSHA512でshadow passwordを生成する方法はいくつかあるようですが、 今回はRuby製のunix-cryptを使ってSHA512でshadow passwordを生成する方法を書いておきます。

unix-cryptはgemでインストールします。unix-cryptをインストールするとmkunixcryptというコマンドも同時にインストールされるので、これを使います。

# unix-cryptインストール
$ gem install unix-crypt

# shadow password生成
# -sでパスワードSALTを指定。パスワードは対話式で指定する。
$ mkunixcrypt -s MySalt
Enter password:
Verify password:

Data Bagの確認

作成されたjsonファイルを開くと、Data Bag Itemが暗号化されていることが確認できます。 "id"は暗号化の対象外で、それ以外のキーの値(今回の例ではusernamepassword)が暗号化されます。

{
  "id": "yuyawata",
  "username": {
    "encrypted_data": "6SDEzXiMjwumOr3cxxFlTQUxQ0jDKESKV37/2lq8Z1A=\n",
    "iv": "dlFVfjO94+qfdENJOdIg6g==\n",
    "version": 1,
    "cipher": "aes-256-cbc"
  },
  "password": {
    "encrypted_data":"3k4YbyRfUY0ri67gZYaRTe74oTZznpYz5M0Ssu7R4DxXjlwTanWDDx4Fte+S\nNvt75/TIgzDK0dAUwaxxeTM3Ff2G59uoN/diuW9GwB0UeyR7F/sy59UR+38p\nCdM0iCrmgu6XKQsNlYyE7Y0PgDf3Au1D1qUZ7VXFl1kRVdjHM7o=\n",
    "iv": "HV8/ilxMRkRTpvTpxvQOMw==\n",
    "version": 1,
    "cipher": "aes-256-cbc"
  }
}

Data Bagの編集

暗号化されたData Bag Itemはknife solo data bag editで編集できます。createと同様に自動でエディタが起動し、Data Bag Itemが復号化された状態でjsonファイルが開きます。

$ knife solo data bag edit users yuyawata --secret-file .chef/data_bag_key

暗号化されたData Bag Itemの取得

暗号化されたData Bag Itemは、Chef::EncryptedDataBagItem.load('DATA_BAG_NAME', 'DATA_BAG_ITEMID', 'SECRET_KEY')で取得します。 'SECRET_KEY'には共通鍵を文字列で指定します。今回はknife.rbに共通鍵のパスを指定しているので、'SECRET_KEY'の指定は省略可能です。

以下はLinuxユーザを作成する場合のレシピの例です。

user_data = Chef::EncryptedDataBagItem.load('users', 'yuyawata')

user user_data['username'] do
  comment 'data_bag_test_user'
  home '/home/yuyawata'
  shell '/bin/bash'
  password user_data['password']
  supports manage_home: true
  action :create
end

参考サイト/書籍

comments powered by Disqus

© Yutaka Yawata 2014-2015. All right reserved.