Serverspec で リモート サーバをテスト @ AWS EC2

## Serverspecとは
O'REILLY『Serverspec』P.5 によると以下の目的に使うサーバテストツールです。

1. テスト駆動によるインフラコード開発
2. サーバ構築後の確認作業の自動化
3. 稼働しているサーバの監視
4. サーバの再起動後の状態確認
5. サーバのあるべき状態の抽象化

Chef, Puppet, Ansibleと合わせて使うと、TDD（テスト駆動）なインフラコード開発が可能になります。
リモートマシンのテストは、SSH接続さえできれば可能です。テスト対象マシンは、rubyやServerspecのインストールは不要です。

## 対象読者
AWS EC2上でリモートサーバを*Serverspec*でテストしてみたい初心者を対象としています。

*Serverspec*のインストール方法、ローカルで*Serverspec*を実行してみる方法は、前回の記事を参照してください。
　　●　[Serverspec 最初の一歩 @ AWS EC2](http://qiita.com/olympic2020/items/12f9f10ff8e95dbe0999)



## 環境の準備
### ■ EC2インスタンスの準備

+ EC2 Amazon Linuxインスタンス作成
    Amazon Linux のEC2インスタンスを２つ作成します。

    | マシン名        | IPアドレス    | 用途                       |
    |:---------------|:--------------|:--------------------------|
    | ec2_serverspec | 172.31.24.21  | Serverspecを実行するマシン |
    | ec2_client     | 172.31.21.132 | テスト対象マシン           |
    
    Serverspecを実行するマシンは、前回の記事を参照してServerspecをセットアップしておきます。
　　●　[Serverspec 最初の一歩 @ AWS EC2](http://qiita.com/olympic2020/items/12f9f10ff8e95dbe0999)
    　  

### ■ SSH接続の準備
+ **OpenSSH形式のSSHプライベートキーを作成**  
    ec2_serverspec⇒ec2_clientにSSH接続できるようする準備をしていきます。
    　  
    PuTTYgenを使い、ec2_clientにPuTTYでアクセスするための\*.ppk ファイル（PuTTY Private Key File）をOpenSSH形式に変換します。
       
    PuTTY Key Generator ＞ Conversions ＞ Import key ＞ \*.ppk ファイルを選択 > 開く(O) > Conversions > Export OpenSSH key > （パスワードなしでよいかの質問）はい(Y) > ファイル名(N): serverspec-key ＞ 保存(S)
    　  
+ **SSH接続設定**  
    ① Macならscpコマンド、WindowsならWinSCPを使い、/home/ec2_userにserverspec-keyファイルをアップロードします。
    ② serverspec-keyをrootの.ssh/に配置し権限を設定ます。

    ```bash
    [root@ip-172-31-24-21 ~]# mv /home/ec2-user/serverspec-key ./.ssh/
    [root@ip-172-31-24-21 ~]# chown root:root ./.ssh/serverspec-key
    [root@ip-172-31-24-21 ~]# chmod 600 ./.ssh/serverspec-key
    ```

    ③ SSHのconfigファイルを作成します。

    ```bash
    [root@ip-172-31-24-21 ~]# vi  ./.ssh/config
    ```
    configファイル

    ```~/.ssh/config
    Host ec2_client
      HostName 172.31.21.132
      Port 22
      User ec2-user
      IdentityFile ~/.ssh/serverspec-key
    ```
       
    ④ SSHの通信チェックを行います。
    　初回は問い合わせがありyesを選択します。２回目以降はそのまま接続できます。

    ```bash
    [root@ip-172-31-24-21 ~]# ssh ec2_client
    The authenticity of host '172.31.21.132 (172.31.21.132)' can't be established.
    ECDSA key fingerprint is 51:68:55:50:15:8f:5e:9b:dc:0f:47:69:8b:65:d1:98.
    Are you sure you want to continue connecting (yes/no)? yes
    Warning: Permanently added '172.31.21.132' (ECDSA) to the list of known hosts.
    Last login: Sat Jun 18 06:33:08 2016 from 52.68.185.60
    
           __|  __|_  )
           _|  (     /   Amazon Linux AMI
          ___|\___|___|
    
    https://aws.amazon.com/amazon-linux-ami/2016.03-release-notes/
    [ec2-user@ip-172-31-21-132 ~]$ exit
    logout
    Connection to 172.31.21.132 closed.
    [root@ip-172-31-24-21 ~]# ssh ec2_client
    Last login: Sat Jun 18 07:08:23 2016 from ip-172-31-24-21.ap-northeast-1.compute.internal
    
           __|  __|_  )
           _|  (     /   Amazon Linux AMI
          ___|\___|___|
    
    https://aws.amazon.com/amazon-linux-ami/2016.03-release-notes/
    [ec2-user@ip-172-31-21-132 ~]$ 
    ```

## **テストの準備**
+ Serverspecファイルを作成
    <font color="#0000ff">**serverspec-init**</font> コマンドを実行します。

    ```bash
    [root@ip-172-31-24-21 ~]# mkdir serverspec
    [root@ip-172-31-24-21 ~]# cd serverspec/
    [root@ip-172-31-24-21 serverspec]# serverspec-init
    Select OS type:
    
      1) UN*X
      2) Windows
    
    Select number: 1
    
    Select a backend type:
    
      1) SSH
      2) Exec (local)
    
    Select number: 1
    
    Vagrant instance y/n: n
    Input target host name: ec2_client
     + spec/
     + spec/ec2_client/
     + spec/ec2_client/sample_spec.rb
     + spec/spec_helper.rb
     + Rakefile
     + .rspec
    ```

## **テストの実行**  
<font color="#0000ff">**rake spec**</font> コマンドを実行します。

+ **失敗テスト**
    ec2_clientの80番ポートを閉じている状態でテストを実行してみます。

    ```spec/ec2_client/sample_spec.rb
    describe port(80) do
      it { should be_listening }
    end
    ```
    ```bash
    [root@ip-172-31-24-21 ~]# cd serverspec/
    [root@ip-172-31-24-21 serverspec]# rspec spec
    /usr/bin/ruby2.0 -I/usr/local/share/ruby/gems/2.0/gems/rspec-support-3.4.1/lib:/usr/local/share/ruby/gems/2.0/gems/rspec-core-3.4.4/lib /usr/local/share/ruby/gems/2.0/gems/rspec-core-3.4.4/exe/rspec --pattern spec/ec2_client/\*_spec.rb
    
    Port "80"
      should be listening (FAILED - 1)
    
    Failures:
    
      1) Port "80" should be listening
         On host `ec2_client'
         Failure/Error: it { should be_listening }
           expected Port "80" to be listening
           sudo -p 'Password: ' /bin/sh -c netstat\ -tunl\ \|\ grep\ --\ :80\\\
    
         # ./spec/ec2_client/sample_spec.rb:27:in `block (2 levels) in <top (required)>'
    
    Finished in 0.0415 seconds (files took 0.54213 seconds to load)
    1 example, 1 failure
    
    Failed examples:
    
    rspec ./spec/ec2_client/sample_spec.rb:27 # Port "80" should be listening
    
    /usr/bin/ruby2.0 -I/usr/local/share/ruby/gems/2.0/gems/rspec-support-3.4.1/lib:/usr/local/share/ruby/gems/2.0/gems/rspec-core-3.4.4/lib /usr/local/share/ruby/gems/2.0/gems/rspec-core-3.4.4/exe/rspec --pattern spec/ec2_client/\*_spec.rb failed
    ```
    無事に失敗を検出しました。
    　  
+ **成功テスト**
    それでは、スペックファイル（spec/ec2_client/sample_spec.rb）を編集し、テストを成功させてみましょう。最後の３行を次のように変更します。
    
    ```sample_spec.rb
    describe port(22) do
      it { should be_listening }
    end
    
    describe service('ntpd') do
      it { should be_enabled }
      it { should be_running }
    end
    ```
   EC2のAmazon Linuxは、インスタンス生成直後は、以下の状態にあります。

    - 22番ポートが開いている
    - 「ntpd」サービスが利用可能
    - 「ntpd」サービスが稼働している

    この状態でテストを実行（<font color="#0000ff">**rake spec**</font>）すると、３つのテストが成功します。

    ```bash
    [root@ip-172-31-24-21 serverspec]# rake spec
    /usr/bin/ruby2.0 -I/usr/local/share/ruby/gems/2.0/gems/rspec-support-3.4.1/lib:/usr/local/share/ruby/gems/2.0/gems/rspec-core-3.4.4/lib /usr/local/share/ruby/gems/2.0/gems/rspec-core-3.4.4/exe/rspec --pattern spec/ec2_client/\*_spec.rb
    
    Port "22"
      should be listening
    
    Service "ntpd"
      should be enabled
      should be running
    
    Finished in 0.07869 seconds (files took 0.54404 seconds to load)
    3 examples, 0 failures
    
    ```

## **セキュリティ設定のテスト**  
+ **sshのテストを追加**
    
    テストのサンプルとして、セキュリティの設定をテストを追加してみます。
    ec2_serverspecサーバーにログインし、serverspecディレクトリに移動します。

    ```bash
    login as: ec2-user
    Authenticating with public key "imported-openssh-key" from agent
    Last login: Sat Jun 18 08:55:43 2016 from dcm1-133-204-45-4.tky.mesh.ad.jp
    
           __|  __|_  )
           _|  (     /   Amazon Linux AMI
          ___|\___|___|
    
    https://aws.amazon.com/amazon-linux-ami/2016.03-release-notes/
    [ec2-user@ip-172-31-24-21 ~]$ sudo su -
    Last login: Sat Jun 18 08:56:49 UTC 2016 on pts/3
    [root@ip-172-31-24-21 ~]# cd serverspec/
    ```
    　  
+ **スペック ファイル作成**
    
    ec2_clientサーバーのテスト項目をssh_spec.rbに定義します。
    設定ファイルの変更し忘れチェックは活用したいですね。

    ```spec/ec2_client/ssh_spec.rb
    describe package('openssh-server') do
      it { should be_installed }
    end
    
    describe service('sshd') do
      it { should be_enabled }
      it { should be_running }
    end
    
    describe file('/etc/ssh/sshd_config') do
      its(:content) { should match /^#Port 22/ }
      its(:content) { should_not match /^PasswordAuthentication yes/ }
    ```
    　  
    
+ **テスト実行**
    テストを実行（<font color="#0000ff">**rake spec**</font>）すると、specディレクトリの\*_spec.rbにマッチするスペックファイルがすべて実行されます。
    ここでは、もともとあった３つのテストに加えてsshの５つのテストが成功します。
    
    ```bash
    client/ssh_spec.rb
    [root@ip-172-31-24-21 serverspec]# rake spec
    /usr/bin/ruby2.0 -I/usr/local/share/ruby/gems/2.0/gems/rspec-support-3.4.1/lib:/usr/local/share/ruby/gems/2.0/gems/rspec-core-3.4.4/lib /usr/local/share/ruby/gems/2.0/gems/rspec-core-3.4.4/exe/rspec --pattern spec/ec2_client/\*_spec.rb
    
    Port "22"
      should be listening
    
    Service "ntpd"
      should be enabled
      should be running
    
    Package "openssh-server"
      should be installed
    
    Service "sshd"
      should be enabled
      should be running
    
    File "/etc/ssh/sshd_config"
      content
        should match /^#Port 22/
      content
        should not match /^PasswordAuthentication yes/
    
    Finished in 0.1879 seconds (files took 0.55769 seconds to load)
    8 examples, 0 failures
    ```


## Nextステップ
次は、Serverspecで複数のサーバのテストを行います。
　・[Serverspec で複数のサーバをテスト @ AWS EC2](http://qiita.com/olympic2020/items/956a8893aea6cb18a93f)