consulのacl管理とconsul execの関係
consulのacl
consulは、aclによって実行制限を行うことができます。
ここでは、multi datacenterでacl管理を行うための、設定と効果を見てみます。
きっかけは、consulの設定の中にacl_datacenter
というものがあるのですが、ネット上のいろいろなページを見てもいまいち意味がわからなかったためです。
datacenter
と acl_datacenter
を同じ値にしていたり、では別の値だとどうなるのか?など…。
consul接続イメージ
今回構築しているのは以下のようなイメージです。(前回と同じイメージです)
- dc1,dc2の2つのデータセンタがあり、それぞれにconsulサーバ1台、consulクライアント1台が属する
- dc1とdc2間は接続されている
構築
前回の設定に加えて、aclの設定を入れてみます。
dc1 server
consul agent -config-file=/etc/consul/conf.d/dc1_server.json
/etc/consul/conf.d/dc1_server.json
{ "datacenter": "dc1", "data_dir": "/tmp/consul", "server": true, "bootstrap_expect": 1 "acl_datacenter": "dc1", "acl_default_policy": "deny", "acl_master_token": "master_token", "acl_token": "anonymous" }
acl_default_policy
をdeny
としています。
dc1 client
consul agent -config-file=/etc/consul/conf.d/dc1_client.json -join=dc1server
/etc/consul/conf.d/dc1_client.json
{ "datacenter": "dc1", "data_dir": "/tmp/consul", "server": false, "acl_token": "anonymous" }
dc2 server
consul agent -config-file=/etc/consul/conf.d/dc2_server.json -join-wan=dc1server
/etc/consul/conf.d/dc2_server.json
{ "datacenter": "dc2", "data_dir": "/tmp/consul", "server": true, "bootstrap_expect": 1, "acl_datacenter": "dc1", "acl_default_policy": "allow", "acl_master_token": "master_token", "acl_token": "anonymous" }
ここでは、datacenter
はdc2
ですが、acl_datacenter
はdc1
としています。
また、acl_default_policy
をallow
としています。
dc2 client
consul agent -config-file=/etc/consul/conf.d/dc2_client.json -join=dc2server
/etc/consul/conf.d/dc2_client.json
{ "datacenter": "dc2", "data_dir": "/tmp/consul", "server": false, "acl_token": "z" }
他のノードと異なり、acl_token
名を異なるものにしています。
(anonymous
ではなくsome_token
としています)
各設定の意味
acl_datacenter
:
自dcが従いたいdc名を指定します。ここで設定したdcでのacl設定の影響を受けます。
他dcを指定した場合、自dcでのacl設定は意味を成さなくなり、指定したdcのacl設定に従います。acl_default_policy
:
acl設定が、blacklistモードかwhitelistモードかを指定します。
allow
と指定した場合、基本的にあらゆる操作を許容し、別途拒否したい操作を追加で設定していきます。
deny
と指定した場合、逆に基本的にあらゆる操作を拒否し、別途許容したい操作を追加で設定していきます。acl_master_token
:
key/valueに対して、read/write(=あらゆる操作)が可能になるtoken名を指定します。acl_token
:
tokenを指定しない場合に、デフォルトで(暗黙的に)指定するtokenを記載します。
consul exec実行によるaclの影響確認
consul exec
コマンドも、暗黙的にk/vで_rexec
prefixを利用しているため、aclの影響を受けます。
上記設定の場合、どのような振る舞いになるのか確認してみます。
dc1 server
[root@dc1server /]# consul exec hostname Failed to create job file: Unexpected response code: 403 (Permission denied)
dc2 server
[root@dc2server /]# consul exec hostname Failed to create job file: Unexpected response code: 403 (Permission denied)
ポイントは、dc2 serverではconfigで"acl_default_policy": "allow"
と設定しているにも関わらず、実行に失敗している点です。
これは、acl_datacenter
がdc1
であるために、dc1
側の設定である"acl_default_policy": "deny"
が有効になっているためと思われます。
aclの設定
ここから、acl設定を追加することでどのような挙動になるのかを確認してみます。
最終的には、consul exec
が実行でき、結果が返ってくるようにします。
aclの登録
まずはpolicy設定を作成します。
公式(https://www.consul.io/docs/internals/acl.html)によるとjson形式で記述できるとあるのですが、少しだけ注意が必要です。
下記を見るとわかる通り、jsonはjsonなのですが、jsonの中にjsonを書くという、特殊な記載になります…。
(全体がjson形式で、さらにRules
の中が更にjsonになっていることがわかると思います)
{ "ID": "anonymous", "Type": "client", "Rules": "{ \"key\": { \"_rexec/\": { \"policy\":\"write\" } } }" }
このjsonファイルを登録します。登録時はacl_master_token
で指定したtokenを指定します。
[root@dc1server /]# curl -X PUT http://localhost:8500/v1/acl/update?token=master_token -d @/tmp/acl.json {"ID":"anonymous"}
効果の確認
先ほど、anonymous tokenの_rexec
prefixに対してwrite権を付与したので、consul exec
が実行できるはずです。
まずはdc1 serverから。
[root@dc1server /]# consul exec hostname dc1server: dc1server dc1server: ==> dc1server: finished with exit code 0 dc1client: dc1client dc1client: ==> dc1client: finished with exit code 0 2 / 2 node(s) completed / acknowledged [root@dc1server /]# consul exec -datacenter="dc2" hostname dc2server: dc2server dc2server: ==> dc2server: finished with exit code 0 1 / 1 node(s) completed / acknowledged [root@dc1server /]#
実行できています。ただし、dc2 clientの結果は返ってきていません。
次にdc2 serverから。
[root@dc2server /]# consul exec hostname dc2server: dc2server dc2server: ==> dc2server: finished with exit code 0 1 / 1 node(s) completed / acknowledged [root@dc2server /]# consul exec -datacenter="dc1" hostname dc1server: dc1server dc1server: ==> dc1server: finished with exit code 0 dc1client: dc1client dc1client: ==> dc1client: finished with exit code 0 2 / 2 node(s) completed / acknowledged
上記の通り、実行できました。ただし、こちらもdc2 clientだけ結果が返って来ません。
これは、dc2 clientのacl_token
をanonymous
ではなく別の名前(ここではsome_token
)にしているためです。
先ほどaclの設定でwrite権を設定した対象は、anonymousでした。
dc2 clientでも以下のログが出力されています。
2015/06/20 15:09:24 [ERR] agent: failed to get remote exec job: rpc error: ACL not found
aclの登録(2回目)
そこで、some_token
に対しても_rexec
に対してwrite権を付与してみます。
{ "ID": "some_token", "Type": "client", "Rules": "{ \"key\": { \"_rexec/\": { \"policy\":\"write\" } } }" }
登録します。
[root@dc1server /]# curl -X PUT http://localhost:8500/v1/acl/create?token=master_token -d @/tmp/acl_2.json {"ID":"some_token"}
最初と異なり、今回のhttp apiはupdate
ではなくcreate
を指定します。これは、anonymousはデフォルトで既存の設定が付与されているためです。
aclのcreate
は、通常はID
を指定せずに実行することで、ランダム文字列となるtokenが返ってきます。
通常、httpのapiを利用するときには、ここで返却されるID
を利用してtokenに指定することで権限を利用して操作を行いますが、
今回はacl_token
で既にtoken名を指定してしまっているので、決め打ちでaclを設定しています。
効果の確認(2回目)
これで、dc2 clientでもconsul exec
が実行できているはずです。
[root@dc1server /]# consul exec -datacenter="dc2" hostname dc2server: dc2server dc2server: ==> dc2server: finished with exit code 0 dc2client: dc2client dc2client: ==> dc2client: finished with exit code 0 2 / 2 node(s) completed / acknowledged
無事に実行できました。
これで、aclの効果と設定方法が少しだけ分かった気がします。