SSHでZabbixの途中経路を暗号化(zabbix1.8系)

以前からVPSのようなグローバルIPで直接監視をするようなサーバに対してZabbixを使うときには、Stoneで暗号化をしてきた。

Stoneでzabbix途中経路を暗号化
でも、長期運用をしていると必ずと言って・・・とある問題があった。

stoneを通しての通信が停止したり、到達できないというエラーで監視ができなくなってしまう。

これは、Server側のstoneとAgent側を再起動すると解決はするのだが、一回では再起動が完了せず、落とすまでにも時間がかかるし、立ち上げるのもひどいときには5,6回起動コマンドが必要になる。もしかしたら、メモリ解放ができていなくて、このような現象になっているのかもしれないけれど。(pgpool-IIでも同様の現象があったので、マッチングテーブルが解放できないとかなのかなぁ)

というわけで、Zabbix Agentの通信経路暗号化に他のプロダクトを使うことにした記録。1年ぐらい前に実装して今のところ運用実績は1年程度。


プロダクト候補


■1.stuunel


技ブロ stunnelを使った通信経路の暗号化

参考にしたのは上記のサイト。以前から安定性とかも問題なさそうだったので、採用してみたいと思っていた。

■2.SSH のポートフォワード


切断、接続が手動しかないのでは再起動するまでのデータ抜けが発生したり、運用手順が煩雑になったりするので敬遠される。

でも、今回試したのはSSHのポートフォワード。なぜ?と思われるかもしれないけれど、iptablesでポートを開ける必要が無いっていうのとスクリプトで何とかなるんじゃないか?と思ったから。stuunelのほうが実装例が多いみたいなので、挑戦するならこっちのほうかなと思ってのこと。

■参考サイト・フォーラムのURL
ZABBIX-JPフォーラム:トンネリングのポートを使用しての監視
いわずもがなと思いますが、日本のZABBIXコミュニティのフォーラム。エージェントアクティブを使った監視には2つのポートをトンネリングしないとだめっていう事が書いてある。


ZABBIXをSSH越しで使う。の巻
autosshっていうのは知らなかった。機会あったら使いたいかも。

お名前.com の VPS を Zabbix でリモート監視
iptablesのnatテーブルにルールを書いて、相手先への接続を自分自身のポートに変更している。LVSでも勉強したけれど、iptablesの応用力には驚かされる。



■作ってみたSSHトンネルを作成するスクリプト

・引数にサーバ名、ログインユーザー、相手のポート、自分のポートを渡すことでトンネリングできる。
・stopで該当する接続だけを停止できる。restartで切断、再接続ができる。

準備するもの

・トンネル専用ユーザーと公開鍵が仕込んである監視対象サーバ。
・監視対象サーバ上のZabbixエージェントの設定ではlocalhostの10050portでListenして、localhostの10051portにサーバがある設定。
・監視対象サーバ上のSSHポートは22から12022等に変更済み。

#!/bin/sh
KEY=/usr/local/zabbix/bin/for_tunnel_dsa
KNOWN_HOSTS=/usr/local/zabbix/bin/for_tunnel_known_hosts
 
SSH_OPTIONS="-t -t -i ${KEY} -o UserKnownHostsFile=${KNOWN_HOSTS}"
 
# debug
echo $@
 
# 接続
function start() {
  /usr/bin/ssh ${SSH_OPTIONS} ${AGENT_USER}@${AGENT_HOST} -n -p ${SSH_PORT} -L ${TUNNEL_PORT}:127.0.0.1:10050 &
  /usr/bin/ssh ${SSH_OPTIONS} ${AGENT_USER}@${AGENT_HOST} -n -p ${SSH_PORT} -R 10051:127.0.0.1:10051 &
}
 
# 切断
function stop() {
  pgrep -l -f "${AGENT_USER}@${AGENT_HOST} -n -p ${SSH_PORT} "
  pkill -f "${AGENT_USER}@${AGENT_HOST} -n -p ${SSH_PORT} "
  echo "${AGENT_USER}@${AGENT_HOST} -n -p ${SSH_PORT} "
  echo 'stop ssh for tunnel'
}
 
if [ $# -ne 5 ];then
  echo $"Usage: $0 {start|stop|restart} Destination_server Login_user Localport Destination_ssh_port"
  exit 1
fi
 
AGENT_HOST=${2}
AGENT_USER=${3}
TUNNEL_PORT=${4}
SSH_PORT=${5}
 
case "$1" in
  start)
    start
    ;;
  stop)
    stop
    ;;
  restart)
    stop
    sleep 1
    start
    ;;
  *)
    echo $"Usage: $0 {start|stop|restart}"
    exit 1
esac



スクリプトをキックするためのZabbix設定

またこれが厄介な話なのだが、引数に接続ユーザーやZabbixサーバからエージェントを指定するときのポートをスクリプトに渡さなくてはならないのに、Zabbix1.8のリモートコマンドに引き渡せる情報は、HOSTNAMEだけだった。そこで、苦肉の策としてプロファイルに書き込んだ情報を引き渡している。

リモートコマンドに記述した内容


「ZABBIXサーバの名前」:/usr/local/zabbix/bin/zabbix_ssh_tunnel.sh start {HOSTNAME} {PROFILE.TAG1} >> /tmp/zabbix_ssh_tunnel.log 2>&1



画面の例
2014-05-25_062856


ホストのプロファイルのタグに書き込んだ内容


zabbix_tunnel 20054 12022



画面の例
2014-05-25_055901

今後、Zabbix2.2に移行するにあたって拡張したいことや修正必要箇所

https://www.zabbix.com/documentation/2.2/manual/appendix/macros/supported_by_location

これを見ると、PORTが「Trigger-based notifications and commands」でサポートされたので、引数には{HOST.NAME} {HOST.PORT} {PROFILE.TAG1}(=zabbix_tunnel 12022)となりそう。※{PROFILE.TAG1}は{INVENTORY.TAG<1-9>}と名前が変わった模様

あと、「DB monitoring additional parameters, SSH and Telnet scripts」が{$MACRO}を使えるらしいので、どんなものなのか?を確かめてみたい。
これは、SSHの接続をチェックするタイプだった。

https://www.zabbix.com/documentation/2.2/manual/config/items/itemtypes/ssh_checks

そういえば、これも合わせてテンプレートに入れておいて、回復したことをトリガーにトンネルスクリプトを流しても良いかもしれない。