Compnet

仕事とか遊びとか、日々折々

2016-04-30(土)

クライアント認証でログインできるようにしたら Zabbix API がエラーになるので無理矢理回避しました

Posted by Nakane, R. in technical   

Note

この記事は旧ブログから移行した記事です。 元記事は ここ にあります。

Zabbix には、外部プログラムから Zabbix が管理する情報を取り扱うための仕組みとして、Zabbix API が存在します。

Locked Zabbix

Zabbix API を使えば、Web UI を使わずにプログラムなどから Zabbix の各種情報、例えば登録されているホストの一覧や収集したホスト情報などを取得したり、新たな監視対象を登録したりできます。 筆者も Zabbix API を Python スクリプトから利用して、登録されている監視対象のホスト情報を取得して hogehoge して便利に活用しています。

さて、先の記事で Zabbix の Web UI にクライアント認証だけでログインできるようにしました。 これによって、Zabbix に対する不正アクセスを極端に減らせると喜んだのですが。 何というか、Zabbix API を使ったプログラムが軒並み動かなくなってしまいました。

クライアント認証で Zabbix Web UI にログインできるようにしたら Zabbix API がエラーに

もちろん Zabbix API のアクセス URL に対してはクライアント認証が不要になるように、Apache を設定してあります。

調べてみたところ、エラーになるのはどうやら user.login メソッドのようです。 試しに、Zabbix の認証方法を「HTTP」から「Zabbix のデータベース内のユーザー情報」に戻してみたところ、user.login メソッドのエラーがなくなりました。 もちろん、Zabbix API を使ったプログラムも正しく動くようになりました。

しかし、Web UI でクライアント認証だけでログインできるように、Zabbix の認証方法を「HTTP」にすると、やはり Zabbix API の user.login メソッドがエラーになります。

どうやら、Zabbix API のログインも Web UI のログインと同じ仕組みで処理しているため、Web UI のログインだけのつもりで変更した認証方法が、そのまま Zabbix API のログインにも使われるようです。 Zabbix の設定を色々と探してみましたが、特定のユーザーに対して認証方式を「HTTP」や「Zabbix のデータベース内のユーザー情報」にしする設定は存在しません。

つまり、Web サーバーの BASIC 認証で承認されたユーザー名を、そのまま引き継いでログインさせる Zabbix の認証方式である「HTTP」を設定をしたときは、たとえ Zabbix API であったとして Web サーバーで BASIC 認証されなくてはならないようです。 結果として、先の記事のように AuthBasicFake ディレクティブを使い、BASIC 認証に代えてクライアント認証だけを使うようにしたときは、Zabbix API でもクライアント認証が必要になるようです。

しかし、Zabbix API を使ったプログラムのために、クライアント証明書をわざわざ取得するのも手間ですし、クライアント証明書に記述するメール アドレスを、プログラムに割り当てるのも変な気がします。

Zabbix API にはクライアント認証を要求しないようにする

色々と検討した結果、Zabbix API を使ったプログラムからのアクセスのときにだけは、Web サーバーでクライアント認証をしないようにしました。 そのために、先の記事での Apache の設定に If ディレクティブを追加して、 Zabbix API を使ったプログラムを実行するホストの IP アドレスから Zabbix API へのアクセスのときは、クライアント認証をしないようにします。

<VirtualHost _default_:443>
      :
    SSLCACertificateFile certs/startssl.client1.ca.pem
      :
    <Directory /usr/share/zabbix>
          :
        <If "!(    %{SCRIPT_FILENAME} =~ m#/api_jsonrpc\.php# \
               and (%{REMOTE_ADDR} =~ m/^127\./ or %{REMOTE_ADDR} =~ m/^::1$/))">
            SSLVerifyDepth  2
            SSLVerifyClient require
            SSLRequire %{SSL_CLIENT_VERIFY} eq "SUCCESS"
            AuthBasicFake %{SSL_CLIENT_S_DN_CN}
        </If>
          :
    </Directory>
      :
</VirtualHost>

ここでは、Zabbix API を使ったプログラムを Web サーバー上で動かしているので 127.*.*.* や ::1 からのアクセスのときに、クライアント認証をしないようにしました。

なお、これだけではまだ Zabbix API のエラーは解消できません。 さらに、Web サーバーで BASIC 認証がなされたかたちにしなければなりません。 素直に、Zabbix API を使ったプログラムを実行するホストの IP アドレスから Zabbix API へのアクセスに対して、BASIC 認証をしてしまうのもひとつの方法です。

筆者の使い方では Zabbix API を使うユーザーは一つだけしかなく、その一つのユーザーのためだけに、BASIC 認証のパスワードファイルを用意するのもどうかという感じてしまいます。 そこで思い切って、AuthBasicFake ディレクティブを使って Zabbix API のユーザーで BASIC 認証したことにしてしまいます。

<VirtualHost _default_:443>
      :
    SSLCACertificateFile certs/startssl.client1.ca.pem
      :
    <Directory /usr/share/zabbix>
          :
        <If "!(    %{SCRIPT_FILENAME} =~ m#/api_jsonrpc\.php# \
               and (%{REMOTE_ADDR} =~ m/^127\./ or %{REMOTE_ADDR} =~ m/^::1$/))">
            SSLVerifyDepth  2
            SSLVerifyClient require
            SSLRequire %{SSL_CLIENT_VERIFY} eq "SUCCESS"
            AuthBasicFake %{SSL_CLIENT_S_DN_CN}
        </If>
        <Else>
            AuthBasicFake "API"
        </Else>
          :
    </Directory>
      :
</VirtualHost>

Zabbix API 用のユーザーは API なので、このように AuthBasicFake "API" として使い、BASIC 認証のユーザー名が API になるようにしました。 これで Web サーバー上で動す Zabbix API のプログラムが、正しく動作するようになりました。

ただ、Zabbix の認証方式を「HTTP」にすると Zabbix API もそれに引きずられる仕様には改善を期待します。

Comments