awspecを使って、AWSリソース(セキュリティグループ)のテストを自動化してみる
動機
前回に引き続き、AWS環境周りのテスト。 LocalStackで動作確認、motoでmockテストができるようになったところで、本番環境向けにテストしてみたいなと思ってた矢先、 プロが awspec
という、AWSリソースのテスト(assertion機能付き)フレームワークがあると教えてくれたので、早速使ってみた。
バージョン情報
Windows10
Vagrant2.0
VirtualBox 5.1.26
CentOS 7.2
ruby 2.4.2
ゴール
こんな感じのセキュリティグループを以下の観点でテストしてみたい。
1.Name タグが sampleであること
2.22番ポートはIPアドレス 10.10.10.10 からのみアクセス可能(のみ、が重要)
3.3389番ポートはどこからでもアクセス可能(!)
事前準備
公式手順に従って、ruby gem から awspecをインストールするだけなので省略。。。したいところだが、ただ実行するだけだと、公式ドキュメントの丸パクリ(というか劣化版)になってしまう。 ので、インフラエンジニアの端くれとして多少の差別化をはかり、(申し訳程度に)Vagrantfileを添付することにする。
Vagrant.configure(2) do |config| config.vm.provider "virtualbox" do |vb| vb.name = "awspec" vb.memory = "2048" end config.vm.box = "bento/centos-7.2" config.vm.hostname = 'awspec' config.vm.network "private_network", ip: "192.168.100.201" config.vm.provision :shell, inline: <<-SHELL for interface in $(grep 'NM_CONTROLLED=no' /etc/sysconfig/network-scripts/ifcfg-* -l) do sudo sed -i -e 's/NM_CONTROLLED=no/NM_CONTROLLED=yes/' $interface sudo ifdown $interface sudo ifup $interface done SHELL config.vm.provision :shell, inline: <<-SHELL sudo yum install -y git sudo git clone https://github.com/sstephenson/rbenv.git /usr/local/rbenv sudo git clone https://github.com/sstephenson/ruby-build.git /usr/local/rbenv/plugins/ruby-build sudo touch /etc/profile.d/rbenv.sh sudo chmod 777 /etc/profile.d/rbenv.sh echo 'export RBENV_ROOT="/usr/local/rbenv"' >> /etc/profile.d/rbenv.sh echo 'export PATH="${RBENV_ROOT}/bin:${PATH}"' >> /etc/profile.d/rbenv.sh echo 'eval "$(rbenv init -)"' >> /etc/profile.d/rbenv.sh sudo chmod -R 755 /usr/local/rbenv sudo yum install -y gcc openssl-devel readline-devel zlib-devel sudo -i rbenv install 2.4.2 sudo -i rbenv global 2.4.2 sudo -i gem install awspec sudo yum install -y epel-release sudo yum install -y python-pip sudo pip install pip --upgrade sudo pip install awscli SHELL end
、、、上記のVagrantfileで作った環境にSSHでログインしたら、aws configure
を実行して、credentialを登録。
そのあと、 awspec init
を実行し、spec/seacrets.yml を下記のように記述すれば準備完了。
region: ap-northeast-1 aws_access_key_id: XXXXXXXXXXXXXXXXXXXX aws_secret_access_key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
実行するコード
spec/security_group_spec.rb を下記のように記述する。
require 'spec_helper' describe security_group('セキュリティグループID') do it { should exist } it { should have_tag('Name').value('sample') } its(:inbound) { should be_opened_only(22).for('10.10.10.10/32')} its(:inbound) { should be_opened(3389).protocol('tcp').for('0.0.0.0/0')} end
結果
上記のコードを保存したら、Rakefileのあるディレクトリで、rake spec
を実行すればテスト完了。
下記のようにオールグリーンのコンソールが出ればO.K.
やってること
記述や実行方式は、serverspecやrspecと同じ。
1. have_tag
を用いて、タグのチェックを行っている。
2. be_opened_only
を用いて、22番ポートは、10.10.10.10/32から「のみ」アクセスを許可していることをチェックしている。
3. be_opened
を用いて、0.0.0.0/0 に対してアクセスを許可していることをチェックしている。
感想
serverspecに慣れ親しんでいる身としては、この方式(環境も)でテストが書けるのはうれしい。
作成した環境の内部の設定はserverspecで今までチェックできたが、セキュリティグループが「許可されている」ことは確認できても、 「余計なものが許可されていない」ことを確認するのは難しかった。 セキュリティグループに限らず、テストの範囲をEC2インスタンスの内部だけでなく、リソース全体に広げることができるので、テストの質が上がりそう。
また、前回、前々回の記事と併せて考えると、下記のような感じで環境構築作業、確認作業が自動化できそう。
(実装フェーズ)
1.LocalStackでCloudFormation や リソース作成の動作確認
2.motoでboto3スクリプトの自動テスト
(テストフェーズ)
3.awspecでリソース作成確認
4.serverspecでサービスの動作確認
どのツールがどの程度まで品質を担保できるものなのかは、もうちょっと使ってみてからまたブログに書きます。
蛇足 ~ be_opened_only のちょっと意地悪な例 ~
be_opened_only
の揚げ足を取るわけではないのだが、下記のような設定のセキュリティグループ(22番ポートにたいして、10.10.10.9/32と10.10.10.10/32 のIPアドレスを2つ列挙)に対して、10.10.10.8/30 からのみ許可しているかどうかテストすると、感覚的にはテスト成功しそうだが、実際はテスト失敗になる。(ブロードキャストアドレスと、ネットワークアドレスを入れても同様)
require 'spec_helper' describe security_group('sg-eb68a092') do it { should exist } it { should have_tag('Name').value('sample') } its(:inbound) { should be_opened_only(22).for('10.10.10.8/30')} its(:inbound) { should be_opened(3389).protocol('tcp').for('0.0.0.0/0')} end
。。。しかし、こんな「ポリシーがあるのかないのかよくわからないセキュリティポリシー(笑)」をテストするようなこともないだろうし、あったとしても、本来NGになるべきものがOKになっているわけではないので、無視していいでしょう。