InSpec とは
InSpec は環境構築が正しく行われているかどうかをテストするためのフレームワークです。 Ruby で記述されており環境構築ツールで有名な Chef が開発しています。
serverspec との違い
InSpec と同系のツールに serverspec というフレームワークがあります。もともと InSpec は serverspec の拡張として作られていたため、テストコードの記述の仕方もよく似ています。しかし InSpec の方がセキュリティやコンプライアンスのテストなど serverspec よりも幅広いテストが可能となっています。
InSpec と serverspec の書き方の違いは マイグレーションガイド にまとまっていますので、 serverspec から InSpec に乗り換える際にはご活用下さい。
試した環境
- CentOS 7
- InSpec 3.0.52
インストール
$ gem install inspec
使い方
Apache がインストールされているかどうかをテストしたいときは次のようなコードを書きます。
httpd.rb
describe package('httpd') do
it { should be_installed }
end
テストを実行するにはターミナルで次のコマンドを叩きます。下記は httpd
が入っていない場合の結果です。
$ inspec exec httpd.rb
Profile: tests from tests (tests from tests)
Version: (not specified)
Target: local://
System Package httpd
× should be installed
expected that `System Package httpd` is installed
Test Summary: 0 successful, 1 failure, 0 skipped
テストを実行する対象はローカルマシンではなくリモートマシンを指定することもできます。リモートマシン上でテストを実行するには次のように ssh でログインするときのユーザ名とパスワードを指定して実行します。
$ inspec exec httpd.rb -t ssh://<user>:<pass>@<host>:<port>
httpd.rb 内の package()
というのはリソースといって各種情報源へアクセスするためのオブジェクトになります。リソースには次のようなものがあります。
リソース | 説明 |
---|---|
package | yum/apt などのパッケージの情報 |
file | ファイルの情報 |
http | HTTP に関する情報 |
port | ポートに関する情報 |
command | コマンドの実行に関する情報 |
公式サイトに リソース一覧 がまとまっていますのでご活用下さい。
ある観点でテストを作成するときには複数のリソースを使用するケースがあります。そのような場合には control
というブロックを使って複数のリソースをまとめることができます。
control 'command' do
title 'コマンドに関するテスト'
describe command('/bin/sh').exist? do
it { should eq true } # /bin/sh が存在するかの確認
end
describe command('echo hello') do
its('stdout') { shuld eq "hello\n" } # 標準出力の内容を確認
its('stderr') { should eq '' } # 標準エラー出力を確認
its('exits_status') { should eq 0 } # 終了コードが 0 であることの確認
end
end
リソースで提供されていない情報源を参照したい場合は command()
を使ってコマンドの実行結果をパースすることになりますが、場合によっては複数のコマンドを組み合わせる必要があったり複雑なパースが必要になることもあります。そのような場合には osquery というコマンドラインツールを使うと情報源の取得を SQL で記述し結果を JSON で受け取れるので記述がシンプルになります。
require 'json'
# osquery で httpd のプロセス情報を JSON で取得
result = command('osqueryi --json "SELECT * FROM processes WHERE name = \'httpd\';"')
JSON.parse(result.stdout).each do |item|
# httpd はポートをリッスンしているか?
describe port(item['port']) do
it { should be_listening }
end
end
まとめ
ナビタイムではデプロイ時のテストとして InSpec を活用しています。InSpec を使うことで安全なデプロイができるだけでなく、デプロイに対する心理的負担が下がる効果もあるのでぜひご活用下さい。