Serverspecでansible-vaultの情報を使う

  • 5
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

お久しぶりです。4月に就職して以来、約8ヶ月ぶりの投稿です。
今は田町でRuby、Ansible、Jenkins辺りと戯れつつクラウドを作っています。

学生時代は、研究室用にhico-horiuchi/ansible-playbooksを書いていました。
今見ると、roleで整理されていなかったり、tagやvarを使えていないなど、中々酷いものですね…。

そこで、5月の研修中に暇だったので、Ansible 2.0対応も兼ねて、自鯖用のPlaybookを書いてみました。
内容は「ConoHa + DokkuでプライベートPaaS構築」の環境を構築するものです。

今回は、ansible-vaultで暗号化した情報を、Serverspecで使うために工夫した内容を紹介します。
これにより、「設定ファイルにトークンが記述されているか」「パスワードを使ってログインできるか」などが確認できるようになります。

ansible_specの紹介

Ansible + Serverspecでテストをするために、volanja/ansible_specを使っています。
ansible_specの詳細は、開発した方が書かれている下記の記事をご覧下さい。

今回は、ansible_specが生成した spec/spec_helper.rb に改造を施していきます。

Rubyでansible-vaultの情報を読み込む

ansible-vaultは、Ansibleのvars(変数)を暗号化するためのツールです。
パスワードやトークンを記述したYAMLファイルを、暗号化・複合化することができます。

今回は、ansible-vaultの暗号化ファイルをRubyで読み込むために、tpickett66/ansible-vault-rbを使用します。
使い方は簡単で、下記のように暗号化ファイルのパスとパスワードを渡すだけで複合化してくれます。
ただし、 Ansible::Vault.read の返り値はStringなので、 YAML.load でハッシュ化する必要があります。

require 'ansible/vault'
require 'yaml'

contents = Ansible::Vault.read(path: '/path/to/file', password: 'foobar')
vars = YAML.load(contents)

Serverspecでansible-vaultの情報を使う

前置きが長くなりましたが、ここからが本題です。
Serverspecでansible-vault-rbを使うために、 spec/spec_helper.rb の末尾に下記の内容を追加します。
ソースコード全体は、hico-horiuchi/hiconyan-com-ansible/spec/spec_helper.rbをご覧下さい。

spec/spec_helper.rb
vars = AnsibleSpec.get_variables(host, group_idx, hosts)
property = AnsibleSpec.get_properties[group_idx]
ansible_cfg = File.expand_path('../ansible.cfg', File.dirname(__FILE__))
vault_password_file = ''
vault_password = ''

# ansible.cfgからvault_password_fileのパスを抽出
File.open(ansible_cfg, 'r') do |f|
  vault_password_file = f.read.match(/^vault_password_file = (.+)$/)[1]
end

# vault_password_fileからパスワードを読込
File.open(File.expand_path(vault_password_file), 'r') do |f|
  vault_password = f.read.chomp
end

# 必要なroles/*/vars/secret.ymlをハッシュとして読込
property['roles'].each do |role|
  secret = "roles/#{role}/vars/secret.yml"
  if File.exist?(secret)
    vars.merge! YAML.load(Ansible::Vault.read(path: secret, password: vault_password))
  end
end

set_property vars

コメントでも補足していますが、処理手順は下記のようになっています。

  1. ansible.cfgからvault_password_fileのパスを抽出
    • ansible-playbook時にパスワードを入力しなくて良いように、設定ファイルにパスを記述している。
    • 私の場合は ~/.vault_password にパスワードを書き出して保存している。
    • 詳細は「Configuration file — Ansible Documentation」をご覧下さい。
  2. vault_password_fileからパスワードを読込
    • 単純なRubyのファイル操作で、vault_password_fileの中身を読み込む。
    • ~ などを展開するために File.expand_path で絶対パスを取得する。
  3. 必要な roles/*/vars/secret.yml をハッシュとして読込
    • 今回は暗号化ファイル( secret.yml )をrole毎に分けて vars ディレクトリに格納した。
    • property['roles'] で対象ホストのroleが分かるので、 secret.yml が存在する場合は読み込む。

また、 set_property vars をすることで、Serverspecの中で property ハッシュで利用できるようになります。
実際のServerspecで利用している箇所は下記の2つです、参考にして下さい。

おわりに

実は、この方式は8月中旬には確立していたのですが、仕事でバタバタしていて記事にするのが遅くなりました…。
社会人になると、趣味もそうですが、技術的に遊べる時間が少なくなって、中々大変です。

今回は secret.ymlroles/*/vars に配置しました。
別の方法として、groupで分けるために group_vars/*/secret.yml に配置する方法もありますね。
両方を実現しようとすると、Ansibleの変数読み込み順序も考慮する必要があるので、大変そうです。