HTTPSでnginx_statusが取れない

MuninでHTTPSのnginx_status取得が失敗して、グラフが描画されない時の対処方法を書く。
Munin version 2.0.25
CentOS 6

事象

nginx.confが80ポートのHTTPの時は問題なくグラグが描画された。

server {
        listen       80;
        listen       localhost:80;
略
        location /nginx_status {
                stub_status on;
                access_log   off;
                allow 127.0.0.1;
                deny all;
        }
    }

これを443ポートのHTTPSに変更すると、グラフが描画されなくなった。

server {
        listen       443;
        listen       localhost;443;
略
        location /nginx_status {
                stub_status on;
                access_log   off;
                allow 127.0.0.1;
                deny all;
        }
    }

調査

このサーバでmunin-runを実行してmuninの挙動を確かめてみる。

$ sudo munin-run nginx_status
total.value U
reading.value U
writing.value U
waiting.value U

$ sudo munin-run nginx_request
request.value U

nginx_statusプラグインもnginx_requestプラグインも取得した値が数値ではなくUという文字列になってしまった。これらのプラグインのコードを確認してみると、URLがHTTPを前提として動いているため、HTTPSにアクセスできていないことがわかる。

$ grep URL /usr/share/munin/plugins/nginx_status
my $URL = exists $ENV{'url'} ? $ENV{'url'} : "http://localhost/nginx_status";
    my $response = $ua->request(HTTP::Request->new('GET',$URL));
        print "no (no nginx status on $URL)\n";
my $response = $ua->request(HTTP::Request->new('GET',$URL));

対処

環境変数urlをhttps://localhost/nginx_statusに変えてみるとうまく動く。

$ url=https://localhost/nginx_status
$ export url
$ sudo munin-run nginx_request
total.value 1
reading.value 0
writing.value 1
waiting.value 0
$ sudo munin-run nginx_request
request.value 10

環境変数urlだけでなく、環境変数 portも変えた方がいい。Nginx requestsグラフの表記がrequests port 80になっているので、443に修正するために環境変数portも指定してあげる。

$ grep port /usr/share/munin/plugins/nginx_request
my $port = exists $ENV{'port'} ? $ENV{'port'} : "80";
        print "request.label requests port $port\n";

先ほどはコマンドを打って環境変数を設定したが、環境変数をMunin上で設定するには/etc/munin/plugin-conf.d/munin-nodeenv.変数 値で記載する。

[nginx*]
env.url https://localhost/nginx_status
env.port 443

記載が終わったらmunin-nodeを再起動する。

$ sudo service munin-node restart

確認

munin-nodeでmunin-runで実行して確認できたら、munin本体からもtelnetやncを使って4949ポートにつなぎ、fetchを発行して確認してみる。
ちなみに、munin-node側ではmunin-node再起動しなくてもmunin-runで環境変数が適用された正しい値が取れることが確認できるが、munin本体から確認するときは、munin-node側でmunin-node再起動していないとfetchで環境変数が適用された正しい値を取れない。もし環境変数も設定ファイルに正しく書いて、munin-runで値が取れることを確認しているのに、グラフ描画が行われない場合は、service munin-node restartを実行しておらず、munin本体から値が取れていない状況かもしれない。

$ telnet munin-nodeのIP 4949
fetch nginx_status
total.value 1
reading.value 0
writing.value 1
waiting.value 0
.
request.value 26
.
quit

確認しているうちに、munin本体のcronが動き、グラフ描写も始まる。

CentOS 7とMunin 2.0.33で構築したら他にも対処が必要だった

どこが直接の原因かは調べていないが、CentOS 7.5で構築していたところ、上記対策を行ってもMuninの値が取れなかった。

調査

munin-run nginx_request --debug, munin-run nginx_status --debugをして確認したところ、環境変数が正しく設定されていることは確認できたが、それ以上の情報は得られなかった。pluginのソースを編集して、Responseの情報を表示できるようにした。

## response取得後に以下を追加
$ sudo vim /usr/share/munin/plugins/nginx_request
print $response->message;

$ sudo munin-run nginx_request
Protocol scheme 'https' is not supported (LWP::Protocol::https not installed)request.value U

HTTPSをサポートしていないといわれてしまった。

http://please-sleep.cou929.nu/lwp-useragent-ssl-warn.htmlによると「LWP::UserAgent は昔は LWP::Protocol::https をバンドルしていたが、次のコミットからは分離するようになった。LWP::UserAgent で SSL 接続する場合は LWP::Protocol::https も別途入れてあげる必要がある」とのこと。

対処

yumでperl-LWP-Protocol-httpsをinstallする。

$ sudo yum install perl-LWP-Protocol-https

調査その2

再度munin-runしたところ、今度は別のエラーがでた。

$ sudo munin-run nginx_request
Can't connect to localhost:443request.value U

自己証明書を入れていたため、証明書の検査を省く必要がありそう。curlでも--insecureをつけないとつなげない。

$ curl https://localhost:443/nginx_status
curl: (60) Peer's certificate issuer has been marked as not trusted by the user.
More details here: http://curl.haxx.se/docs/sslcerts.html

curl performs SSL certificate verification by default, using a "bundle"
 of Certificate Authority (CA) public keys (CA certs). If the default
 bundle file isn't adequate, you can specify an alternate file
 using the --cacert option.
If this HTTPS server uses a certificate signed by a CA represented in
 the bundle, the certificate verification probably failed due to a
 problem with the certificate (it might be expired, or the name might
 not match the domain name in the URL).
If you'd like to turn off curl's verification of the certificate, use
 the -k (or --insecure) option.

$ curl --insecure https://localhost/nginx_status
Active connections: 1 
server accepts handled requests
 34 34 27 
Reading: 0 Writing: 1 Waiting: 0 

SSL証明書の対処

Perlでcurlの--insecureと同じように対応するため、/usr/share/munin/plugins/nginx_requestと/usr/share/munin/plugins/nginx_statusを編集した。以下のコードをLWP::UserAgent->newの後に入れた。

$ua->ssl_opts( verify_hostname => 0 ,SSL_verify_mode => 0x00);

munin-runで正しく値が取れたため、エラーメッセージを確認するために追加したprint $response->message;を消したうえでsystemctl restart munin-nodeすると、グラフに描画された。