CloudFront でホストされたサイトを Nagios check_http で監視するときのハマリポイント

株式会社オズビジョンのユッコ (@terra_yucco) です。
オズビジョンでは主に Nagios を使って監視をしているのですが、プロダクトの他に、自社の[コーポレートサイト](https://www.oz-vision.co.jp)も監視をしています。
今日は、この監視が最近頻繁にタイムアウトをするようになったので、調査したときのメモを残しています。

~~なお未解決です。こうしたら？というのがあればぜひコメントでいただきたいです。~~
この記事書くのに調べまくってたら解消しました。

# アラート発砲

最近よくこんなのが来るように。

```text
nagiosAPP [6:51 PM]
oz-vision/httpはCRITICALです:
CRITICAL - Socket timeout after 20 seconds

nagiosAPP [6:56 PM]
oz-vision/httpはOKです
```

ただし、実際にブラウザを立ち上げてサイトを見に行っても、特に遅いこともなく普通に見えています。

## 前提

- Nagios Core 3.5.1
- check_http v1.4.16 (nagios-plugins 1.4.16)

## 監視設定

詳細は省きますが、Web UI の System > Configuration > Services から参照できる定義は、引数をひらくと以下のようになっています。

```
/usr/lib64/nagios/plugins/check_http -H $HOSTADDRESS$ -t 20 -f follow
```

`$HOSTADDRESS` には `www.oz-vision.co.jp` を入れています。

### 手動で実行
#### タイムアウトするケース

Nagios Core からの監視と同じようにタイムアウトする場合。

```terminal
$ sudo -u nagios /usr/lib64/nagios/plugins/check_http -H www.oz-vision.co.jp -t 20 -f follow
CRITICAL - Socket timeout after 20 seconds
```

#### 301 で止まるケース

場合によっては、以下のようになることもあります。`-f` が機能していないように見えます。

```
$ sudo -u nagios /usr/lib64/nagios/plugins/check_http -H www.oz-vision.co.jp -t 20 -f follow
CRITICAL - Cannot make SSL connection.
139944962140016:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:769:
HTTP OK: HTTP/1.1 301 Moved Permanently - 580 bytes in 0.199 second response time |time=0.199023s;;;0.000000 size=580B;;;0
```

おそらく (想定している状態ではないのですが) タイムアウトしないときは 301 で終わっているので、アラートは出るときと出ないときがあるのだと予想できます。


### 他の手順で確認

wget を使うと http から https のリダイレクトも含め問題なく取得ができました。

```terminal
$  wget http://www.oz-vision.co.jp
--2019-06-11 19:53:06--  http://www.oz-vision.co.jp/
Resolving www.oz-vision.co.jp (www.oz-vision.co.jp)... 13.33.0.130, 13.33.0.154, 13.33.0.217, ...
Connecting to www.oz-vision.co.jp (www.oz-vision.co.jp)|13.33.0.130|:80... connected.
HTTP request sent, awaiting response... 301 Moved Permanently
Location: https://www.oz-vision.co.jp/ [following]
--2019-06-11 19:53:06--  https://www.oz-vision.co.jp/
Connecting to www.oz-vision.co.jp (www.oz-vision.co.jp)|13.33.0.130|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: ‘index.html’

index.html                                             [ <=>                                                                                                             ]  13.79K  --.-KB/s   in 0.05s

2019-06-11 19:53:06 (274 KB/s) - ‘index.html’ saved [14122]
```

### check_http をもう少し調べてみる

check_http には Nagios で使うには適しませんが `-v` で verbose が指定できるので、指定してみました。
毎回 20s 待つのはつらいので、タイムアウトを 5s に下げています。

#### タイムアウトするケース

リダイレクトしようとしてそのままタイムアウト。

```
$ sudo -u nagios /usr/lib64/nagios/plugins/check_http -H www.oz-vision.co.jp -t 5 -f follow -v
GET / HTTP/1.1
User-Agent: check_http/v1.4.16 (nagios-plugins 1.4.16)
Connection: close
Host: www.oz-vision.co.jp


http://www.oz-vision.co.jp:80/ is 580 characters
STATUS: HTTP/1.1 301 Moved Permanently
**** HEADER ****
Server: CloudFront
Date: Tue, 11 Jun 2019 10:59:02 GMT
Content-Type: text/html
Content-Length: 183
Connection: close
Location: https://www.oz-vision.co.jp/
X-Cache: Redirect from cloudfront
Via: 1.1 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.cloudfront.net (CloudFront)
X-Amz-Cf-Pop: xxxxx-xx
X-Amz-Cf-Id: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
**** CONTENT ****
<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>CloudFront</center>
</body>
</html>

Redirection to https://www.oz-vision.co.jp:443/
CRITICAL - Socket timeout after 5 seconds
```

#### 301 で止まるケース

SSL handshake に失敗していることで、その先のリダイレクトが処理できていないように見えます。

```
$ sudo -u nagios /usr/lib64/nagios/plugins/check_http -H www.oz-vision.co.jp -t 5 -f follow -v
GET / HTTP/1.1
User-Agent: check_http/v1.4.16 (nagios-plugins 1.4.16)
Connection: close
Host: www.oz-vision.co.jp


http://www.oz-vision.co.jp:80/ is 556 characters
STATUS: HTTP/1.1 301 Moved Permanently
**** HEADER ****
Server: CloudFront
Date: Tue, 11 Jun 2019 10:58:21 GMT
Content-Type: text/html
Content-Length: 183
Connection: close
Location: https://www.oz-vision.co.jp/
X-Cache: Redirect from cloudfront
Via: 1.1 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.cloudfront.net (CloudFront)
X-Amz-Cf-Id: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
**** CONTENT ****
<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>CloudFront</center>
</body>
</html>

Redirection to https://www.oz-vision.co.jp:443/
CRITICAL - Cannot make SSL connection.
139923145283440:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:769:
HTTP OK: HTTP/1.1 301 Moved Permanently - 556 bytes in 0.042 second response time |time=0.042349s;;;0.000000 size=556B;;;0
```

#### https に直接向けてみる

別のエラーに…。
これに対応するには CloudFront 側の対応が必要そうでした。

- [Amazon CloudFront の"The request could not be satisfied. Bad Request. (リクエストに失敗しました。無効なリクエストです。)" というエラーを解決するにはどうしたらよいですか?](https://aws.amazon.com/jp/premiumsupport/knowledge-center/resolve-cloudfront-bad-request-error/)

ただ、急に発生するようになりましたが、CloudFront の設定は変更していないので、これは最終手段にしたい。

```
sudo -u nagios /usr/lib64/nagios/plugins/check_http -H www.oz-vision.co.jp -p 443 -t 5 -f follow -v
GET / HTTP/1.1
User-Agent: check_http/v1.4.16 (nagios-plugins 1.4.16)
Connection: close
Host: www.oz-vision.co.jp:443


http://www.oz-vision.co.jp:443/ is 904 characters
STATUS: HTTP/1.1 400 Bad Request
**** HEADER ****
Server: CloudFront
Date: Tue, 11 Jun 2019 11:09:31 GMT
Content-Type: text/html
Content-Length: 556
Connection: close
X-Cache: Error from cloudfront
Via: 1.1 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.cloudfront.net (CloudFront)
X-Amz-Cf-Pop: xxxxxxxx
X-Amz-Cf-Id: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
**** CONTENT ****
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<TITLE>ERROR: The request could not be satisfied</TITLE>
</HEAD><BODY>
<H1>400 ERROR</H1>
<H2>The request could not be satisfied.</H2>
<HR noshade size="1px">
Bad request.

<BR clear="all">
<HR noshade size="1px">
<PRE>
Generated by cloudfront (CloudFront)
Request ID: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
</PRE>
<ADDRESS>
</ADDRESS>
</BODY></HTML>
HTTP WARNING: HTTP/1.1 400 Bad Request - 904 bytes in 0.135 second response time |time=0.134521s;;;0.000000 size=904B;;;0
```

### handshake に失敗する原因を掘り下げる

>error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure

#### SNI 対応サーバ

- [OpenSSL APIメモ（handshake failure）](http://work-in-progress.hatenablog.com/entry/2017/12/03/113552)
- [SSL接続時にHandshakeに失敗する場合はSNIが原因かもしれない](http://www.todesking.com/blog/2017-02-11-openssl-alert-handshake-failure/)

エラーメッセージで検索して 1 つ目の記事にたどりつき、そこからリンク先をたどって 2 つ目の記事にたどりつきました。

諸事情あってコーポレートサイトの AWS アカウントの中身は確認できないのですが、https 対応を行っていることから、これに該当するのかと予想。

- [CloudFront で HTTPS リクエストを供給する方法の選択](https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/cnames-https-dedicated-ip-or-sni.html)

#### 監視の修正方法

かなり試行しましたが、100% 200 が返却されるようになりました！

```
$ sudo -u nagios /usr/lib64/nagios/plugins/check_http -H www.oz-vision.co.jp -t 20 -f follow --sni
HTTP OK: HTTP/1.1 200 OK - 14834 bytes in 0.971 second response time |time=0.970905s;;;0.000000 size=14834B;;;0
```

## Conclusion

Nagios の check_http を使い、CloudFront 上でホストされている https 対応サイトを監視する場合には `--sni` オプションが必要そうです。