うさぎ好きエンジニアの備忘録

うさぎたちに日々癒されているエンジニアが業務で直面したもの & 個人的な学習メモを残していきます。

ZooKeeper の SASL 認証を有効にしてみる

巷では ZooKeeper のピア認証に脆弱性があると話題になっているので、ZooKeeper の 3.4.10 でピア認証を有効化してみようと思います。

tl;dr;

※ 今回は Kerberos でセキュア化した ZooKeeper を対象としています。

  • keytab を2種類発行しましょう
  • jaas に QuorumServer と QuorumLearner を追加しましょう
  • java.env を用意して jaas を読み込むようにしましょう

とりあえずドキュメントを読んでみる

Confluence に詳しい SASL 認証の有効化方法が載っているので読んでみました。

https://cwiki.apache.org/confluence/download/attachments/67634736/Kerberos-secured%20communication%20between%20servers.png?version=1&modificationDate=1481657396000&api=v2

どうやら

  • QuorumServer Principal の記載された keytab で認証
  • QuorumLearner Principal の記載された keytab で認証

を行う必要があるぽいことが何となくわかります。(気になる人は以下のドキュメントを読んでみましょう。)

Server-Server mutual authentication - Apache ZooKeeper - Apache Software Foundation

ちなみに ZooKeeper における Learner とは Follower と Observer を含めた呼び名となります。 (Client に対してサービスを行っている全ての ZooKeeper Server として理解していただけると何となく納得いただけるかなと…)

今回はそこまで深く追わないで keytab を発行して認証を有効にしていこうと思います。

keytab の発行

今回は自前で KDC サーバを立てて運用していたので、パパッと keytab を発行していきます。

# zkquorum の keytab 発行
kadmin.local -q "addprinc -randkey zkquorum/zk001.ponteru.hogehoge.co.jp"
kadmin.local -q "ktadd -k /etc/security/keytabs/zk001.zkquorum.keytab zkquorum/zk001.ponteru.hogehoge.co.jp"

kadmin.local -q "addprinc -randkey zkquorum/zk002.ponteru.hogehoge.co.jp"
kadmin.local -q "ktadd -k /etc/security/keytabs/zk002.zkquorum.keytab zkquorum/zk002.ponteru.hogehoge.co.jp"

kadmin.local -q "addprinc -randkey zkquorum/zk003.ponteru.hogehoge.co.jp"
kadmin.local -q "ktadd -k /etc/security/keytabs/zk003.zkquorum.keytab zkquorum/zk003.ponteru.hogehoge.co.jp"

# learner の keytab 発行

kadmin.local -q "addprinc -randkey learner/zk001.ponteru.hogehoge.co.jp"
kadmin.local -q "ktadd -k /etc/security/keytabs/zk001.learner.keytab learner/zk001.ponteru.hogehoge.co.jp"

kadmin.local -q "addprinc -randkey learner/zk002.ponteru.hogehoge.co.jp"
kadmin.local -q "ktadd -k /etc/security/keytabs/zk002.learner.keytab learner/zk002.ponteru.hogehoge.co.jp"

kadmin.local -q "addprinc -randkey learner/zk003.ponteru.hogehoge.co.jp"
kadmin.local -q "ktadd -k /etc/security/keytabs/zk003.learner.keytab learner/zk003.ponteru.hogehoge.co.jp"

zoo.cfg の修正

keytab が発行できたら jaas も作っておきましょう。

Configuration Changes There are a few important configuration parameters introduced as part of this new feature:

Feature flag: users can use this flag to turn the feature on or off. quorum.auth.enableSasl

Rolling upgrade: users can use these parameters to perform a rolling upgrade. quorum.auth.learnerRequireSasl

quorum.auth.serverRequireSasl

Service principal: configure service principal names. quorum.auth.kerberos.servicePrincipal

blog.cloudera.com

とのことなので /etc/zookeeper/conf/zoo.cfg に以下の行を追加しましょう。

# SASL を使ったクォーラムの認証を有効化
quorum.auth.enableSasl=true
 
# ピア認証の有効化
quorum.auth.learnerRequireSasl=true
quorum.auth.serverRequireSasl=true
 
# Kerberos 認証を使っている場合は Principal を記述
quorum.auth.kerberos.servicePrincipal=zkquorum/_HOST

jaas ファイルの準備

SASL 認証を有効にするため、以下のクライアントを追加して保存してください。

QuorumServer {
   com.sun.security.auth.module.Krb5LoginModule required
   useKeyTab=true
   storeKey=true
   useTicketCache=false
   keyTab="/etc/security/keytabs/zookeeper.zkquorum.keytab"
   principal="zkquorum//zk001.ponteru.hogehoge.co.jp@DEV";
};
 
QuorumLearner {
   com.sun.security.auth.module.Krb5LoginModule required
   useKeyTab=true
   storeKey=true
   useTicketCache=false
   keyTab="/etc/security/keytabs/zookeeper.learner.keytab"
   principal="learner//zk001.ponteru.hogehoge.co.jp@DEV";
};

ローリングアップグレード

ドキュメントを読んだ感じ、3つのステップを実施することでローリングアップグレードできる模様…

Rolling upgrade

This section describes the possible rolling upgrade to use ZOOKEEPER-1045 feature. The rolling upgrade in ZOOKEEPER-1045 is designed based on a key observation that a Quorum Peer can be configured such that a ZooKeeper ensemble can be composed of a mixed servers, both old and new. Rolling upgrade is achieved by a combination of configuration flags in zoo.cfg configuration file.

quorum.auth.enableSasl: If false, no authentication at all. If true, could be either in rolling upgrade, or finished rolling upgrade.

quorum.auth.learnerRequireSasl: Initially false. Sets to true in second step of rolling upgrade, this is to prepare each server ready to send authentication packet to other servers. This flag can’t be set to false if quorum.auth.serverRequireSasl is set to true.

quorum.auth.serverRequireSasl: Initially false. Sets to true in third step of rolling upgrade (quorum.auth.learnerRequireSasl should be true) to enable server-to-­server SASL authentication strictly.

めんどくさいですが試しにやってみようと思います。

(事前準備) ZooKeeper のバージョンアップ

ローリングアップグレード前に3.4.10を入れておきます。

# アプグレード
$ sudo yum upgrade zookeeper

# バージョン確認
$ rpm -qa | grep zookeeper
zookeeper-3.4.10-1.el7.centos.x86_64

# 今起動している ZooKeeper のバージョン確認
$ echo envi | nc localhost 2181 | grep zookeeper.version
zookeeper.version=3.4.6--1, built on 10/27/2018 11:59 GMT

Step-1

zoo.cfg に quorum.auth.enableSasl=true を追加して ZooKeeper を再起動します。

$ sudo grep quorum.auth.enableSasl /etc/zookeeper/conf/zoo.cfg
quorum.auth.enableSasl=true
$ sudo systemctl restart zookeeper.service
$ echo envi | nc localhost 2181 | grep zookeeper.version
zookeeper.version=3.4.10-678380eb9ad8d48b1360a52880aa8c106633331d, built on 10/27/2018 12:00 GMT

ZooKeeperのバージョンが上がりました。

Step-2

zoo.cfg に quorum.auth.learnerRequireSasl=true を追加して ZooKeeper を再起動します。

$ sudo grep quorum.auth.learnerRequireSasl /etc/zookeeper/conf/zoo.cfg
quorum.auth.learnerRequireSasl=true
$ sudo systemctl restart zookeeper.service

この時点でアップグレードを実施していた ZooKeeper クラスタを参照している Storm クラスタがダウン…。 ログを確認すると Kerberos 認証周りがうまくいっていない模様。

ERROR [QuorumConnectionThread-[myid=2]-3:SaslQuorumAuthLearner@223][] - An error: (java.security.PrivilegedActionException: javax.security.sasl.SaslException: GSS initiate failed [Caused by GSSException: No valid credentials provided (Mechanism level: Server not found in Kerberos database (7) - UNKNOWN_SERVER)]) occurred when evaluating Zookeeper Quorum Member's  received SASL token. This may be caused by Java's being unable to resolve the Zookeeper Quorum Member's hostname correctly. You may want to try to adding '-Dsun.net.spi.nameservice.provider.1=dns,sun' to your server's JVMFLAGS environment.

なので以下の設定を zoo.cfg に追加 & ZooKeeper を再起動して問題を解消しました。

quorum.auth.kerberos.servicePrincipal=zkquorum/_HOST

Step-3

zoo.cfg に quorum.auth.serverRequireSasl=true を追加して ZooKeeper を再起動。

$ sudo grep quorum.auth.serverRequireSasl /etc/zookeeper/conf/zoo.cfg
quorum.auth.serverRequireSasl=true
$ sudo systemctl restart zookeeper.service

以下のようなログが確認できたのでローリグアップグレードが問題なく完了したようです。

INFO  [QuorumConnectionThread-[myid=1]-1:SaslQuorumAuthServer@116][] - Successfully completed the authentication using SASL. learner addr: /172.17.155.252:43978

まとめ

ZooKeeper に脆弱性が報告されていたのでバージョンアップとピア間の SASL 認証を有効にしてみました。 同じように ZooKeeper のローリングアップグレードで困っている人の手助けになればと思います。