CentOS
devops
serverspec
Ansible
WindowsServer

Windows Serverもansibleで自動構築してServerspecでテストしよう

More than 1 year has passed since last update.

はじめに

  • 2016/8/3 Serverspecでのテストを追記

  • ansibleも2.1になってWindows Serverのサポートも強化され、そろそろ手を出しても良さそうな感じになってきました。

  • ということで、ansibleを利用する前のWindowsServer側の設定とIISのインストール、Windowsグループ、ユーザの設定を自動構築し、serverspecでテストするところまでやってみたいと思います。

  • 記事中で使ったplaybookのサンプルはGithub uzresk/ansible-serverspec-windows-samplesからどうぞ。


前提となる環境

  • 以下の環境で動作確認をしています。
  • 尚、本文中ではansible自体のインストール手順は割愛しています。

ansible実行ホスト

  • CentOS6.7
  • ansible2.1.0
  • serverspec 2.36.0
  • IP:192.168.1.99

ansible適用ホスト

  • WindowsServer2012R2
  • opentableのイメージを使ってvagrantで起動しました。
  • IP:192.168.1.25

ansibleで環境構築

ansibleで環境構築する前準備

winrmを有効化する

  • Ansible で Windows の構成管理を行う場合には Windows Remote Management( WinRM)を有効化する必要があるようです。

winrmを有効化するスクリプトの取得

  • power shellを管理者権限で起動した後に以下のコマンドを使ってansibleが提供しているwinrmを有効化するスクリプトを取得します。
Invoke-WebRequest -Uri https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1 -OutFile ConfigureRemotingForAnsible.ps1

NetworkCategoryの変更

  • Windows System PrepによるとNetworkCategoryをprivateに変更しないといけない模様
Set-NetConnectionProfile -InterfaceAlias (Get-NetConnectionProfile -IPv4Connectivity Internet).InterfaceAlias -NetworkCategory Private
  • 確認するにはこのコマンド(NetworkCategoryがprivateになっていることを確認)
Get-NetConnectionProfile -IPv4Connectivity Internet

winrmを有効化

PS C:\Users\vagrant> powershell -ExecutionPolicy RemoteSigned .\ConfigureRemotingForAnsible.ps1


wxf                 : http://schemas.xmlsoap.org/ws/2004/09/transfer
a                   : http://schemas.xmlsoap.org/ws/2004/08/addressing
w                   : http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd
lang                : en-US
Address             : http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
ReferenceParameters : ReferenceParameters

Ok.

windows serverでwinrmのポートを確認する

  • Powershellを起動して以下のコマンドを実行
  • 5986と5985ポートが空いているのがわかりますね。ちなみに5986はhttps、5985はhttpです。
Get-Item WSMan:\localhost\Listener\*\Port


   WSManConfig: Microsoft.WSMan.Management\WSMan::localhost\Listener\Listener_1305953032

Type            Name                           SourceOfValue   Value
----            ----                           -------------   -----
System.String   Port                                           5986


   WSManConfig: Microsoft.WSMan.Management\WSMan::localhost\Listener\Listener_1084132640

Type            Name                           SourceOfValue   Value
----            ----                           -------------   -----
System.String   Port                                           5985

pipをインストール

get-pip.pyを取得

curl -x http://PROXY_HOST:PROXY_PORT -O https://bootstrap.pypa.io/get-pip.py

pipをインストール

  • プロキシを設定
export http_proxy=http://PROXY_HOST:PROXY_PORT
export https_proxy=http://PROXY_HOST:PROXY_PORT
  • インストール
python get-pip.py

winrmをインストール

pip install pywinrm

winrm経由でansibleが実行できるかを確認する

プロキシの除外設定

  • winrmはhttp/https通信であるため、プロキシの設定を行っている場合は、ansible対象ホストを除外設定する必要がある。
export no_proxy="192.168.1.25"

inventryファイル(hosts)の設定

  • 余談ですが、ansible2.0からはansible_ssh_userなどはdeprecatedになって、sshを取った変数名が推奨されます。
  • ansible windows inventory
[windows]
192.168.1.25

[windows:vars]
ansible_user=vagrant
ansible_password=vagrant
ansible_port=5985
ansible_connection=winrm
  • https(5986)で接続するには以下のように証明書の検証をしないようにinventoryファイルを構成すれば接続できます。(pythonの2.7.9から証明書の検証が行われるようになったそうです)
[windows]
192.168.1.25

[windows:vars]
ansible_user=vagrant
ansible_password=vagrant
ansible_port=5986
ansible_connection=winrm
ansible_winrm_server_cert_validation=ignore

win_pingを使って疎通確認

[root@52ae470c2708 scripts]# ansible -i hosts windows -m win_ping
192.168.1.25 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

WindowsServerの設定をansibleで!

  • ansibleでwindows serverを構成するためのモジュール群は以下に記載があります。
  • Windows Modules

IISをインストールしてみる

[root@52ae470c2708 ansible-scripts]# cat roles/iis/tasks/main.yml
- name: Install IIS
  win_feature:
    name: "Web-Server"
    state: present
    restart: yes
    include_sub_features: no
    include_management_tools: yes
[root@52ae470c2708 ansible-scripts]# ansible-playbook -i hosts site.yml

PLAY [windows] *****************************************************************

TASK [iis : Install IIS] *******************************************************
changed: [192.168.1.25]

PLAY RECAP *********************************************************************
192.168.1.25               : ok=1    changed=1    unreachable=0    failed=0
  • http://192.168.1.25/にアクセスすると無事IISのデフォルトページが表示されました。

グループとユーザをつくってみよう

グループを作成する

[root@52ae470c2708 ansible-scripts]# cat roles/group/tasks/main.yml
---
- name: create test-group
  win_group:
    name: test-group
    descriptsion: test group
    state: present

ユーザを作成する

[root@52ae470c2708 ansible-scripts]# cat roles/user/tasks/main.yml
---
- name: Add User
  win_user:
    name: test
    password: "@Password1"
    groups: ["test-group"]
  • パスワードポリシーに違反した場合はplaybook実行時に以下のようなエラーがでます
TASK [user : Add User] *********************************************************
fatal: [192.168.1.25]: FAILED! => {"changed": false, "failed": true, "msg": "Exception calling \"SetInfo\" with \"0\" argument(s): \"The password does not meet the password policy requirements. Check the minimum password length, password complexity and password history requirements.\r\n\""}
  • 実行後、サーバマネージャ - コンピュータの管理 - ローカルユーザとグループからユーザとグループが追加できていることが確認できると思います。

Serverspec

Serverspecを使ってwindowsをテストする為の前準備

  • Serverspecもansible同様winrmを使って接続します。Linuxをテストする時と比べて必要になるのはwinrmのモジュールのみです。

winrmをインストールする

gem install winrm

接続の仕方もwinrm経由に変更

  • ここでは、TARGET_HOST、USER、PASSWORDを環境変数から取得しwinrmの接続で利用しています。
[root@52ae470c2708 serverspec]# cat spec/spec_helper.rb
require 'serverspec'
require 'net/ssh'
require 'winrm'

set :backend, :winrm

RSpec.configure do |c|
  host = ENV['TARGET_HOST']
  user = ENV['USER'].dup
  pass = ENV['PASSWORD'].dup
  puts user
  puts pass
  endpoint = "http://" + host + ":5985/wsman"

  c.winrm = ::WinRM::WinRMWebService.new(endpoint, :ssl, :user => user, :pass => pass)
  c.winrm.set_timeout 300 # 5 minutes max timeout for any operation
end

テストしてみよう

IISがインストールされていることをテストする

  • ここではインストールされているか否かとポートがListenしているか否かをテストしてみたいと思います。
  • インストールされているか否かはServerspecのResourceTypeにwindows_featureがあるのでこれを利用します。ポートがListendしているか否かについてはLinux同様portを利用します。
iis_spec.rb
require 'spec_helper'

describe windows_feature('Web-Server') do
  it { should be_installed.by("powershell") }
end

describe port(80) do
  it { should be_listening.with('tcp') }
end

グループ、ユーザのテスト

  • グループが存在するか否か、ユーザが存在するか否か、ユーザがグループに存在するか否かのテストを行います。
  • こちらはLinux同様groupuserを利用します。
group_spec.rb
require 'spec_helper'

describe group('test-group') do
  it { should exist }
end
user_spec.rb
require 'spec_helper'

describe user('test') do
  it { should exist }
  it { should belong_to_group 'test-group' }
end

実行

  • 全部無事テストが通りましたね。
[root@52ae470c2708 windows]# rake spec
(in /scripts/ansible-serverspec-windows-samples/first-step/serverspec)
env TARGET_HOST=192.168.1.25 /root/.rbenv/versions/2.3.1/bin/ruby -I/root/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rspec-support-3.4.1/lib:/root/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rspec-core-3.4.4/lib /root/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/rspec-core-3.4.4/exe/rspec --pattern spec/\{windows\}/\*_spec.rb
vagrant
vagrant

Group "test-group"
 WARN  WinRM::WinRMWebService : WinRM::WinRMWebService#run_powershell_script is deprecated. Use WinRM::CommandExecutor#run_powershell_script instead
  should exist

Windows feature "Web-Server"
 WARN  WinRM::WinRMWebService : WinRM::WinRMWebService#run_powershell_script is deprecated. Use WinRM::CommandExecutor#run_powershell_script instead
  should be installed by "powershell"

Port "80"
 WARN  WinRM::WinRMWebService : WinRM::WinRMWebService#run_powershell_script is deprecated. Use WinRM::CommandExecutor#run_powershell_script instead
  should be listening with tcp

User "test"
 WARN  WinRM::WinRMWebService : WinRM::WinRMWebService#run_powershell_script is deprecated. Use WinRM::CommandExecutor#run_powershell_script instead
  should exist
 WARN  WinRM::WinRMWebService : WinRM::WinRMWebService#run_powershell_script is deprecated. Use WinRM::CommandExecutor#run_powershell_script instead
  should belong to group "test-group"

Finished in 2.35 seconds (files took 0.48295 seconds to load)
5 examples, 0 failures

おわりに

  • はじめる前はWinRMとか面倒だなーとか色々思いましたが拍子抜けするほど簡単にできましたので二の足を踏んでいる人はまずはやってみるとよさそうです。
  • ansibleは1.7でサポート開始されたころよりもwindows系のモジュールが増えたことでこれからますます活躍の場が増えていきそうですね。
  • ansibleはwindowsとlinuxでモジュールが別れていますが、serverspecは一つのResourceTypeで複数のOSをカバーできるようなので学習コストが少なく良い感じですね。