LogstashのHttp_poller inputがOAuth2.0未対応だった件

## はじめに
Logstashを使って、Google Reports APIからGoogle Driveの監査ログの取得を試みましたが
うまくいかなかった失敗事例として記事投稿します。m(_ _)m

**【参考】**
・ [Google Reports APIとは][00]

## 利用環境
・Logstash 7.0.0

## 実施したこと
Logstashで以下の設定を行いました。

- **input**: `http_poller`でHTTP APIを叩く
- **filter**: `json`パーサーでResponseを正規化する
- **output**: reportsapiという名前で`file`に出力する

```ruby:logstash.conf
input {
  http_poller {
    urls => {
      gdrive => {
        method => get
        user => "XXXXXXXXXXX-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.apps.googleusercontent.com"
        password => "*******************"
        url => "https://www.googleapis.com/admin/reports/v1/activity/users/all/applications/drive"
        headers => {
          Accept => "application/json"
        }
     }
    }
    request_timeout => 60
    schedule => {every => "1h"}
    codec => "json"
    metadata_target => "http_poller_metadata"
  }
}

filter {
  json {
    source => "message"
  }
}

output {
  file {
    path => "/tmp/reportsapi"
    codec => json
  }
}
```

## Http_poller Input Pluginとは
指定したURLに対して、HTTP APIを呼び出し、その出力結果(Response)をイベントにデコードします。
上記機能を実現するのが[Http_poller Input Plugin][01]になります。

※Http_poller Input固有の設定項目は以下の通りです。

| 設定項目 | デフォルト値 | 説明 |
|---------|-------------|------|
| user | - (任意)  | HTTP認証で使用するユーザ名を指定します。 |
| password | - (任意)  | HTTP認証用のユーザー名と一緒に使用されるパスワードを指定します。 |
| automatic_retries | 1 (任意)  | 失敗したURLに対するクライアント再試行回数を指定します。 |
| cacert | - (任意)  | カスタムのX.509CAのパスを指定します。 |
| client_cert | - (任意)  | クライアント証明書のパスを指定します。 |
| client_key | - (任意)  | クライアント証明書の暗号キーを指定します。 |
| connect_timeout | 10 (任意)  | 接続確立されるまでのタイムアウト値(秒)を指定します。 |
| cookies | true (任意)  | Cookieのサポート有無を指定します。 |
| follow_redirects | true (任意)  | URLのリダイレクト処理を許可するか指定します。 |
| keepalive | true (任意)  | HTTPキープアライブの有効化の有無を指定します。 |
| keystore | - (任意)  | カスタムキーストア(.jks)を指定します。 |
| keystore_password | - (任意)  | キーストアのパスワードを指定します。 |
| keystore_type | "JKS" (任意)  | キーストアの種類を指定します。 |
| metadata_target | "@metadata" (任意)  | メタデータの情報を格納するFieldを指定します。 |
| pool_max | 50 (任意)  | 最大同時接続数を指定します。 |
| pool_max_per_route | 25 (任意)  | 単一ホストへの最大同時接続数を指定します。 |
| proxy | - (任意)  | HTTPプロキシのURLを指定します。 |
| request_timeout | 60 (任意)  | リクエスト全体のタイムアウト値(秒)を指定します。 |
| retry_non_idempotent | false (任意)  | automatic_retriesが有効な場合のPOST等の冪等ではないHTTPリクエストメソッドの再試行有無を指定します。 |
| schedule | - (必須)  | URLに対するAPIの定期ポーリング間隔を指定します。 |
| socket_timeout | 10 (任意)  | ソケット上のデータを待機するタイムアウト値(秒)を指定します。 |
| target | - (任意)  | 取得したイベントの格納するFieldを指定します。 |
| truststore | - (任意)  | カスタムのトラストストア(.jks)を指定します。 |
| truststore_password | - (任意)  | トラストストアのパスワードを指定します。 |
| truststore_type | "JKS" (任意)  | トラストストアの種類を指定します。 |
| urls | - (必須)  | 接続先のURLを指定します。(複数指定可) |
| validate_after_inactivity | 200 (任意)  | キープアライブ要求が必要かどうかを判断するために失効した接続をチェックする前に待機する時間(秒)を指定します。 |

※keystoreはクライアント認証、truststoreはサーバ認証に利用する証明書や秘密鍵等のこと。

## 実施結果
LogstashのloggingをDebugモードにして、`/var/log/logstash-plain.log`に以下のログが
出ていることを確認しました。うまくHTTP APIアクセスできるように見えます。

```console
[2019-05-23T16:34:26,307][DEBUG][logstash.inputs.http_poller] Fetching URL {:name=>"gdrive", :url=>[:get, "https://w
ww.googleapis.com/admin/reports/v1/activity/users/all/applications/drive", {:headers=>{"Accept"
=>"application/json"}, :auth=>{:user=>"XXXXXXXXXXX-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.apps.googleusercontent.com", :pa
ss=>"*******************", :eager=>true}}]}
```

output句に指定した`/tmp/reportsapi`のファイルを開いてみたところ
以下のようなデータが記録されていました。むむむっ

```console
{"http_poller_metadata":{"response_message":"Unauthorized","request":{"headers":{"Accept":"application/json"},"method":"get","url":"https://www.googleapis.com/admin/reports/v1/activity/users/all/applications/drive","auth":{"pass":"*******************","eager":true,"user":"XXXXXXXXXXX-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.apps.googleusercontent.com"}},"times_retried":0,"host":"instance-1","runtime_seconds":1.704896,"code":401,"name":"gdrive","response_headers":{"expires":"Sun, 19 May 2019 17:24:24 GMT","transfer-encoding":"chunked","www-authenticate":"basic realm=\"Google APIs\"","vary":["Origin","X-Origin"],"date":"Sun, 19 May 2019 17:24:24 GMT","x-frame-options":"SAMEORIGIN","x-content-type-options":"nosniff","server":"GSE","cache-control":"private, max-age=0","x-xss-protection":"1; mode=block","content-type":"application/json; charset=UTF-8"}},"error":{"message":"HTTP Basic Authentication is not supported for this API","code":401,"errors":[{"location":"Authorization","reason":"authError","message":"HTTP Basic Authentication is not supported for this API","locationType":"header","domain":"global"}]},"@version":"1","@timestamp":"2019-05-19T17:24:24.462Z"}{"@version":"1","error":{"code":401,"errors":[{"reason":"authError","locationType":"header","location":"Authorization","domain":"global","message":"HTTP Basic Authentication is not supported for this API"}],"message":"HTTP Basic Authentication is not supported for this API"},"http_poller_metadata":{"runtime_seconds":1.7114010000000002,"response_headers":{"cache-control":"private, max-age=0","www-authenticate":"basic realm=\"Google APIs\"","vary":["Origin","X-Origin"],"server":"GSE","content-type":"application/json; charset=UTF-8","date":"Sun, 19 May 2019 17:26:45 GMT","x-content-type-options":"nosniff","expires":"Sun, 19 May 2019 17:26:45 GMT","x-xss-protection":"1; mode=block","x-frame-options":"SAMEORIGIN","transfer-encoding":"chunked"},"code":401,"request":{"method":"get","headers":{"Accept":"application/json"},"url":"https://www.googleapis.com/admin/reports/v1/activity/users/all/applications/drive","auth":{"user":"XXXXXXXXXXX-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.apps.googleusercontent.com","pass":"*******************","eager":true}},"response_message":"Unauthorized","times_retried":0,"host":"instance-1","name":"gdrive"},"@time
```

`reason":"authError"`
`"message":"HTTP Basic Authentication is not supported for this API`
ということでHttp_polling input pluginではHTTP Basic認証しか対応していないようですね。

ちなみに、Google Reports APIの認証は**OAuth2.0**になります。

**【参考】**
・ [Authorizing requests with OAuth 2.0][02]

## まとめ
今回、Http_polling input pluginを試してみました。
使ってみるまでHTTP認証の方式まであまり気にしていませんでしたが
最近のパブリックなサービスはOAuth2.0による認証が多いので
Logstashでも対応してもらえると嬉しいところです。

ちなみに以下のようなDiscussが上がっており、一応アドバイス的なことは書かれていました。

>You might be better off doing the authenticated REST call externally to logstash, using /bin/sh and curl (and maybe cron) and then POST it into an HTTP input in logstash.

**【参考】**
・[How to generate OAUTH2 token and use REST API to pull logs from cloud"][03]

[00]:https://developers.google.com/admin-sdk/reports/v1/guides/manage-audit-drive "Reports API"
[01]:https://www.elastic.co/guide/en/logstash/7.0/plugins-inputs-http_poller.html "Http_poller input plugin"
[02]:https://developers.google.com/admin-sdk/reports/v1/guides/authorizing "Authorizing requests with OAuth 2.0"
[03]:https://discuss.elastic.co/t/how-to-generate-oauth2-token-and-use-rest-api-to-pull-logs-from-cloud/166624 "How to generate OAUTH2 token and use REST API to pull logs from cloud"