Windowsのイベントログをsyslogに流すためのAnsible Playbook

サーバを数十台程度扱うようなお仕事も、Ansibleの力で複数台まとめて操作をおこなったり、Fluentdの力で全体の情報集約をできたりと、とても楽になってきました。

こういった自動化を考えていく中で少し手間がかかってくれるのがWindows Server。
Linuxで統一したいところではあるわけですが、どうしても用途によりWindows Serverで構築したほうが楽な場面があり、数台のWindows Serverがまぎれこんだりして非常に悩ましいところがあります。

そんなわけで今回は、Windows Serverのイベントログを集約するようなソフトウェアのインストール・設定を、Ansibleを使って実施することを試してみました。で、割と簡単にできそうだという感触が得られたのでそのメモ。

# 関連する技術

## AnsibleによるWindowsの操作

Ansibleは基本的には、対象サーバにSSHして、対象サーバのPython環境を使っていろいろな処理を実行してくれます。対して対象サーバがWindowsの場合には、対象サーバにWinRM (Windows Remote Management)で接続してPowerShellを使っていろいろ実行してくれるようになっています。

Windows環境にはPowerShell 3.0が必要だったりネットワーク設定が必要だったりしますが、以下にとてもわかりやすくまとめられています。

- [AnsibleでWindowsを操作する準備をする](http://qiita.com/yunano/items/f9d5652a296931a09a70)

今回はお試しとして、[Microsoft Azure](http://azure.microsoft.com/ja-jp/)上にWindows Server 2012 R2の仮想マシンを用意し、Ansibleから操作してみることにします。

##Windowsのイベントログを集める

WindowsのイベントログをFluentdに集める方法はいくつかありそうですが、以下を参考に[NXLog](http://nxlog.org/)を使ってsyslogで集めることにしました。

- [Collecting Log Data from Windows](http://docs.fluentd.org/articles/windows)
- [Windows のイベントログを fluentd で何とか出来ないか調べてみたら nxlog を組み合わせることで...](http://blog.cloudpack.jp/2014/08/21/windows-event-log-with-fluentd-nxlog/)

なお、今回は試さなかったのですが、 `fluent-plugin-winevtlog` というのもあるようで、非常に面白そう・・・！

- [Windowsイベントログをfluentdプラグインで集めてmongoDBに突っ込む](http://qiita.com/okahashi117/items/245d6cb68e6aa42c004a)


# 試してみる

試してみたPlaybookは https://github.com/yacchin1205/nxlog-ansible に置きました。

Playbookは割と単純で、 `roles/nxlog/tasks/main.yml`で、

```yaml:main.yml
- name: Download NXLog
  win_get_url: url=http://nxlog.org/system/files/products/files/1/nxlog-ce-2.9.1347.msi dest="C:\Users\{{ ansible_ssh_user }}\Downloads\nxlog-ce.msi"

- name: Install NXLog
  win_msi: path="C:\Users\{{ ansible_ssh_user }}\Downloads\nxlog-ce.msi"

- name: Copy configuration for NXLog
  win_template: src=nxlog.conf.j2 dest="C:\Program Files (x86)\nxlog\conf\nxlog.conf"
  notify: Restart NXLog

- name: Start NXLog
  win_service: name=nxlog start_mode=auto state=started
```

こんな感じで、 win_* モジュールを使うことでやりたいことがかなり素直に書ける印象。
NXLogの設定ファイルを変更する場合は `roles/nxlog/templates/nxlog.conf.j2` をいじればOK。

以下、試した構成と手順について、簡単に残しておきます。

## 構成

今回は失敗しても死なないように、Microsoft Azure上で仮想マシンを作成して試してみました。構成は以下のような感じ。

![2015-08-291.jpg](https://qiita-image-store.s3.amazonaws.com/0/28770/5ab733aa-1d6b-2ce7-e003-4b3e62e3cbcf.jpeg)

ここではAzureの1つの仮想ネットワーク内に2つの仮想マシンを用意しています。

- CoreOS Stable ... Ansibleを動かすコンテナ / Fluentdを動かすコンテナ
- Windows Server 2012 R2 ... イベントログの監視対象

CoreOS側にsyslogの受け口としてFluentdコンテナを用意しておいて、CoreOS上のAnsibleコンテナからWindows ServerにNXLogをインストールし、このFluentdにsyslog経由でイベントログを流させる、という格好です。

## 手順

### 仮想マシンの起動

今回は[Microsoft Azureのダッシュボード](https://manage.windowsazure.com/)から操作してみます。

1. Windows Server 2012 R2の仮想マシンを用意する。今回のパラメータは以下のような感じ
    - イメージ: Windows Server 2012 R2 Datacenter
    - バージョンのリリース日: 2015/07/26 (最新のものを選択)
    - 仮想マシン名: 適当につける
    - 階層: STANDARD
    - サイズ: D1 (1コア、3.5GBメモリ)
    - 新しいユーザ名: 適当につける
    - 新しいパスワード: 適切なものを設定

2. CoreOSの仮想マシンを用意する。パラメータは以下
    - イメージ: CoreOS Stable
    - バージョンのリリース日: 2015/08/04 (最新のものを選択)
    - 仮想マシン名: 適当につける
    - 階層: STANDARD
    - サイズ: A2 (2コア、3.5GBメモリ)
    - 新しいユーザ名: 適当につける
    - 認証: 適切なものを設定
        
今回はWindows ServerとAnsible環境を同じ仮想ネットワーク内に置いているのであまり気にしてはいないのですが、Windows Serverに対して仮想ネットワーク外のAnsible環境から操作する場合は、エンドポイントに PowerShell(5986ポート)が設定されていることを確認する必要があります。

### Fluentdの準備

今回はsyslogで受け取った内容をとりあえず標準出力で確認できればよかったので、syslog inputとstdout outputプラグインのみの単純な設定にしました。
イメージは https://github.com/fluent/fluentd-docker-image イメージを使わせてもらいます。

Azure上に作成したCoreOSの仮想マシンにSSHし、以下のように操作します。

1. 設定ファイルを記述する。今回は、 `/home/(user)/fluentd/test-syslog.conf` というファイルに、以下のような内容を記述

    ```
    <source>
      @type syslog
      port 5140
      bind 0.0.0.0
      tag system
    </source>
    
    <filter **>
      @type stdout
    </filter>
    ```

2. Fluentdコンテナを実行する。イメージは `fluent/fluentd` を指定すればOK

    ```
    $ sudo docker run -d -p 5140:5140/udp -v /home/(user)/fluentd:/fluentd/etc -e FLUENTD_CONF=test-syslog.conf fluent/fluentd
    ```

これでFluentdコンテナが起動され、syslog inputプラグインがホストのUDP 5140ポートからのパケットを受けつけてくれるようになります。
送られてきたsyslogの内容は標準出力に出力されるので、 `docker logs` コマンドで確認できます。

### Windows Serverの準備

Windows Serverが、AnsibleからのWinRM経由での要求を受けつけてくれるように設定変更をおこないます。
詳細は [AnsibleでWindowsを操作する準備をする#Windows側の準備](http://qiita.com/yunano/items/f9d5652a296931a09a70#windows%E5%81%B4%E3%81%AE%E6%BA%96%E5%82%99) を参照してください。

仮想マシンにRemote Desktopで接続し、以下のように操作します。


1. ログイン時にNetworkに関して、PCやデバイスの発見に関する問い合わせが表示されるので、[Yes]を選択する。
    もしくは、PowerShellから以下のコマンドを入力し、ネットワークをPrivateに変更する

    ```
    PS > Set-NetConnectionProfile -InterfaceAlias (Get-NetConnectionProfile -IPv4Connectivity Internet).InterfaceAlias -NetworkCategory Private
    ```

3. PowerShellを開き、以下のコマンドを入力する
       
    ```
    PS > cd Downloads
    PS > Invoke-WebRequest -Uri https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1 -OutFile ConfigureRemotingForAnsible.ps1
    PS > powershell -ExecutionPolicy RemoteSigned .\ConfigureRemotingForAnsible.ps1
    ```

これで `[Ok.]` と出力されれば、WinRM経由でAnsibleで操作可能な状態になったはずです。
続いてAnsible環境を作って、このWindows Serverを操作できるか確認してみます。


### Ansibleの準備

CoreOSのマシンにSSHし、以下のように作業していきます。

1. pipを使って `ansible` と `pywinrm` をインストールする。今回はubuntu:14.04のコンテナを使って準備したので以下のような感じ

    ```
    $ sudo docker run -it ubuntu:14.04
    # apt-get update && apt-get install -y python-pip python-dev git vim
    # pip install ansible pywinrm
    ```

2. インベントリファイルを作成する。適当なディレクトリに `test-hosts` というファイルを作成し、以下のようにWindows Serverの情報を記述する

    ```
    [windows]
    10.0.0.5    # Windows Serverホストの名前/アドレス
    
    [windows:vars]
    ansible_ssh_user=<Windows Serverのユーザ名>
    ansible_ssh_pass=<Windows Serverのパスワード>
    ansible_ssh_port=5986
    ansible_connection=winrm
    ```
 
3. 記述したインベントリを指定し、 `win_ping` モジュールを実行する

    ```
    # ansible -i test-hosts -m win_ping all
    ```

これで `"ping": "pong"` などと出力されればOK。エラーが発生した場合は `-vvv` などオプションをつけて処理を追っかけるなどして原因を突き止めます。

### AnsibleによりWindows ServerにNXLogをインストール・設定

Ansibleをインストールしたコンテナ内で、リポジトリ https://github.com/yacchin1205/nxlog-ansible をcloneして実行すればOK。

試したのは以下のような流れ。

1. お試しPlaybookをcloneする

    ```
    # git clone https://github.com/yacchin1205/nxlog-ansible.git
    ```

2. インベントリを作成する。`hosts.template` というファイルがリポジトリにあるので、これをベースに・・・

    ```
    # cd nxlog-ansible
    # cp hosts.template hosts
    # vim hosts
    ```

    `hosts` を以下のような内容に編集する。この例ではsyslog送信先の情報はインベントリに書いている。

    ```
    [windows]
    10.0.0.5    # Windows Serverホストの名前/アドレス
    
    [windows:vars]
    ansible_ssh_user=<Windows Serverのユーザ名>
    ansible_ssh_pass=<Windows Serverのパスワード>
    ansible_ssh_port=5986
    ansible_connection=winrm
    # syslogが動作しているホストとポート
    syslog_host=10.0.0.4
    syslog_port=5140
    ```

3. Playbookを実行する

    ```
    # ansible-playbook -i hosts nxlog.yml

    ...

    10.0.0.5                   : ok=6    changed=5    unreachable=0    failed=0
    ```

こんな感じでfailedなものなく処理が完了すればOK。

## 動作確認

あとは、Fluentdコンテナの標準出力の内容を見て、Windows Serverのイベントログらしきものが出力されていることを確認。
たとえば、Windows ServerにRDPしようとしたときなどは以下のような感じのログが出力されます。

```
$ sudo docker ps | grep fluentd
19140d80315a        fluent/fluentd:latest   "/bin/sh -c 'fluentd   3 minutes ago       Up 3 minutes        0.0.0.0:5140->5140/udp, 24224/tcp   serene_jang      

$ sudo docker logs 19140d80315a

...

2015-08-29 01:27:30 +0000 system.user.info: {"host":"yzwlab-win","ident":"MSWinEventLog","message":"27:29 2015\t131\tMicrosoft-Windows-RemoteDesktopServices-RdpCoreTS\tNETWORK SERVICE\tWell Known Group\tInformation\tyzwlab-win\tRemoteFX module\t\tThe server accepted a new TCP connection from client xxx.xxx.xxx.xxx:yyyy.\t53"}
2015-08-29 01:27:30 +0000 system.user.info: {"host":"yzwlab-win","ident":"MSWinEventLog","message":"27:29 2015\t65\tMicrosoft-Windows-RemoteDesktopServices-RdpCoreTS\tNETWORK SERVICE\tWell Known Group\tInformation\tyzwlab-win\tRemoteFX module\t\tConnection RDP-Tcp#2 created \t54"}
```

これでFluentd経由でWindows Serverで起きたイベントを追っかけられそう・・・！

実用にはPlaybookの`roles/nxlog/templates/nxlog.conf.j2`をいじる必要があるかもしれません。(文字セットとか・・・)
とはいえ、このような流れでWindows Serverのイベントログをsyslogで集約するようAnsibleからまとめて操作、みたいなことができそうでした。ということで。