概要
Consulではserviceを登録することでService Discovery機能を活用することができます。
例えば
"service": { "name": "payment", "port": 9090, "tags": ["development"] }
のように設定をすると、
$ dig @localhost -p 8600 payment.service.consul
でpayment
サービスとして登録したノードのIP群を取得できます。
詳細を知りたい方は以下を参考にしてください。
今回はこのサービス登録でACLを設定しているとうまく行かずハマってしまった話です。
環境
- Consul v1.4.0
原因調査
以前使ったハンズオン用のリポジトリに
"service": { "name": "consul-ui", "port": 8500, "tags": ["ui"] }
を追加して検証してみました。ui用ノードには以下のエラーが表示されました。
[ERR] consul: "Catalog.Register" RPC failed to server 172.26.0.4:8300: rpc error making call: rpc error making call: Permission denied [WARN] agent: Service "consul-ui" registration blocked by ACLs
この時のPolicyは以下です。
agent policy
node_prefix "" { policy = "write" } service_prefix "" { policy = "read" }
agent tokenに使用します。
ui policy
key_prefix "" { policy = "write" } node_prefix "" { policy = "read" } service_prefix "" { policy = "read" }
default tokenに使用します。
似たエラー
ググってよく見るエラーは以下です。
[ERR] consul: "Coordinate.Update" RPC failed to server 172.26.0.3:8300: rpc error making call: rpc error making call: Permission denied [WARN] agent: Coordinate update blocked by ACLs
これはagent間通信でNodeの登録が必要なので、agent tokenには以下のnode:write
の権限が必要になります。
node_prefix "" { policy = "write" }
元々これはドキュメントにも明記されているもので、今回も
node_prefix "" { policy = "write" } service_prefix "" { policy = "read" }
のpolicyでagent tokenを用意していたので別の問題ということになります。
Service registration だから write権限が必要?
次に
[WARN] agent: Service "consul-ui" registration blocked by ACLs
に注目してみると、registration
とあるのでwrite
権限が必要なのでは?と推測しました。
ドキュメントのServiceAPIを確認してみると、
Service - Agent - HTTP API - Consul by HashiCorp
にはservice:write
とあるのでやはり権限が違ったようです。
そこでagent-policyを
node_prefix "" { policy = "write" } service_prefix "" { policy = "write" }
にしてみました。
しかしこれでもエラーは直りませんでした。
Policyの変更はtokenに反映されない?
「前述のpolicy変更がもしかしたらtokenに反映されてないのでは?」と考えて
- policy_ttlが過ぎるのを待つ
- policy変更後にtokenもupdate
- tokenの再生成
と色々試してみましたがエラーは直りませんでした。
※あとで分かりましたがpolicyの変更はちゃんと既存tokenに反映されます
結論
Serviceの登録はagent tokenを使用しない
のissueを読んでみると、どうやらService登録はagent tokenによって行われるものではない事が分かりました。
つまりdefault token側の権限が足りていなかったのです。
そこでdefault tokenに使っているui policyを以下のようにservice:write
にしてみると
key_prefix "" { policy = "write" } node_prefix "" { policy = "read" } service_prefix "" { policy = "write" }
無事Service登録されることがログ&UIで確認できました。
[INFO] agent: Synced node info [INFO] agent: Synced service "consul-ui"
まとめ
Consul ACLは柔軟な権限管理ができる一方で
- ドキュメントに明記されてない使い方
- ドキュメント自体の誤植
がちょこちょこあるので本番導入時にはしっかり検証を行いましょう。