概要
ConsulにはACL(Access Control List)といって、AWSのIAMに似たアクセスコントロールの仕組みがあります。
今回はそれの設定方法を説明します。
環境
- Consul v1.4.0
Consul ACL
ACL System
大きく分けて
というコンポーネントがあります。
ACL Policies
各リソースの対する権限のポリシーです。以下の権限設定ができます。
設定 | 説明 |
---|---|
read | read権限 |
write | read/write権限 |
deny | readもwriteも不可 |
各リソースはこちらに載っています。
これを次のACL Tokensと紐づけて利用します。
またGlobal Management
という管理者権限のPolicyが最初は用意されています。
IDは00000000-0000-0000-0000-000000000001
です。
この管理者権限から細かいリソース毎のPolicyを作成していきます。
1.4.0より前はToken毎にPolicyを設定していく形でPolicyとTokenの分離ができておらず、Policyの再利用ができませんでした。
今は再利用ができるため、あらかじめPolicyを定義しておいてTokenにアタッチしていくことが可能です。
またTokenにアタッチしたPolicyを更新した場合、Tokenを再作成したりしなくてもPolicyの更新は反映されます。
ACL Tokens
ACL Tokenには大きく4種類あって
種類 | 役割 |
---|---|
Master Token | Global Management に紐づく管理者権限のToken。configで明示的に acl.tokens.master を設定しなかった場合、Bootstrap時に自動生成される |
Anonymous Token | CLI などでリクエストする際、Tokenを明示的に指定しなかった場合に使われるToken。00000000-0000-0000-0000-000000000002 というアクセスID。後からPolicyを追加可能 |
Agent token | Consul agentの内部オペレーション(ノード情報の更新など)で利用されるToken。 configでは acl.tokens.agent にセットする |
通常のToken | Anonymous Token では権限が足りない時に自前で生成し、適切なPolicyをアタッチする。configでは acl.tokens.default にセットする |
このうちMater Token
とAnonymous Token
はACLを有効にしたタイミングで自動で用意されます。
Agent Token
と通常のToken
は自前で生成します。
ハンズオン
こちらのリポジトリを利用してください。
中身の説明
サーバ
{ "primary_datacenter": "dc1", "acl": { "enabled": true, "default_policy": "deny", "down_policy": "extend-cache", "tokens": { "master": "b1gs33cr3t" } } }
acl.enabled: true
にすることでACLが有効化されます。
"default_policy": "deny"
のようにデフォルトで全リソースのアクセス禁止にしてwhitelist形式で扱っていきます。
tokens.master
は書かずにあとでbootstrapingで生成しても大丈夫です。
注意としてMaster tokenが漏れるとどんな操作も可能なので、必ず漏洩しないようにしてください
今回は明記した方が説明しやすいのでこうしています。
クライアント
{ "primary_datacenter": "dc1", "acl": { "enabled": true, "down_policy": "extend-cache" } }
サーバからdefault_policy
とtokens.master
を抜いただけです。
起動
起動してみます。
$ docker-compose up
デフォルトPolicyをdenyにしたので、agent間の通信もできず以下のエラーがでます。
consul-agent-1_1 | 2018/12/06 18:54:35 [ERR] consul: "Coordinate.Update" RPC failed to server 172.21.0.3:8300: rpc error making call: rpc error making call: Permission denied consul-agent-1_1 | 2018/12/06 18:54:35 [WARN] agent: Coordinate update blocked by ACLs consul-agent-2_1 | 2018/12/06 18:54:38 [ERR] consul: "Coordinate.Update" RPC failed to server 172.21.0.6:8300: rpc error making call: rpc error making call: Permission denied consul-agent-2_1 | 2018/12/06 18:54:38 [WARN] agent: Coordinate update blocked by ACLs
下の「Agent間通信の許可」にてこのエラーを解消します。
Bootstraping
※この操作はMaster Tokenをconfigで設定していない場合で必要です。設定してあればスキップしてください
あるサーバのコンテナに入って操作します。
$ docker exec -it acl_consul-server-bootstrap_1 /bin/ash
bootstrapします。これは1度きりです。
/ # consul acl bootstrap AccessorID: ad22630f-a10d-fad0-3231-26dbb3595d7d SecretID: 4e98466f-59d3-84e6-5277-4c6fb03bcad0 Description: Bootstrap Token (Global Management) Local: false Create Time: 2018-12-06 19:04:58.1592181 +0000 UTC Policies: 00000000-0000-0000-0000-000000000001 - global-management
このSecretID:4e98466f-59d3-84e6-5277-4c6fb03bcad0
はMaster Tokenです。
管理者権限のPolicyである00000000-0000-0000-0000-000000000001 - global-management
と紐付いていますね。
この管理者権限のTokenがないと自前のPolicyの定義ができないため、configで明示していない場合は必ず保存しておいてください。
Agent間通信の許可
簡単のため、環境変数CONSUL_HTTP_TOKEN
にMaster Tokenを設定しておきます。
/ # export CONSUL_HTTP_TOKEN=b1gs33cr3t
※各CLI操作で-token=b1gs33cr3t
をつけるのと同じです
Agent Policyの作成
まずはConsul Agent間で疎通できないとクラスタ構築がされないので、agent間の内部オペレーションを許可するPolicyを定義します。
内部オペレーションで必要な権限は以下なので、agent.hcl
と定義して、
node_prefix "" { policy = "write" } service_prefix "" { policy = "read" }
Policyを作成します。
/ # consul acl policy create \ -name "agent-policy" \ -description "Agent Token Policy" \ -rules @/consul/policies/agent.hcl ID: 6807479a-eb6e-d50c-db10-6a83afc08cba Name: agent-policy Description: Agent Token Policy Datacenters: Rules: node_prefix "" { policy = "write" } service_prefix "" { policy = "read" }
Agent Tokenの生成
↑で作ったPolicyをアタッチしてTokenを生成します。
/ # consul acl token create \ -description "Agent Token" \ -policy-name "agent-policy" AccessorID: 24fe3b36-30d9-f01f-1eed-16d0e8c2dbc2 SecretID: 271970dd-8498-8361-599b-fc90fb65257b Description: Agent Token Local: false Create Time: 2018-12-06 19:25:20.0921606 +0000 UTC Policies: 6807479a-eb6e-d50c-db10-6a83afc08cba - agent-policy
271970dd-8498-8361-599b-fc90fb65257b
がagent tokenです。
Agent Tokenの反映
agent tokenを用意できたので、各configにtokens.agent
をつける修正してコンテナを再起動させます。
サーバ
{ "primary_datacenter": "dc1", "acl": { "enabled": true, "default_policy": "deny", "down_policy": "extend-cache", "tokens": { "master": "b1gs33cr3t", "agent": "271970dd-8498-8361-599b-fc90fb65257b" } } }
クライアント
{ "primary_datacenter": "dc1", "acl": { "enabled": true, "down_policy": "extend-cache", "tokens": { "agent": "271970dd-8498-8361-599b-fc90fb65257b" } } }
再起動
$ docker-compose restart
しばらくすると内部の通信ができるようになり、クラスタが構築されます。
/ # consul members Node Address Status Type Build Protocol DC Segment 1d561da489ed 172.25.0.4:8301 alive server 1.4.0 2 dc1 <all> dccab8780f64 172.25.0.6:8301 alive server 1.4.0 2 dc1 <all> e03b703d4345 172.25.0.7:8301 alive server 1.4.0 2 dc1 <all> 091e7c809fb1 172.25.0.3:8301 alive client 1.4.0 2 dc1 <default> e98cc8322113 172.25.0.5:8301 alive client 1.4.0 2 dc1 <default> fa3d5ff86fdc 172.25.0.2:8301 alive client 1.4.0 2 dc1 <default>
Anonymous Tokenに最低限の権限を付与
これまではMaster Tokenを使っていたので何でも操作できましたが、Anonymous Tokenの権限ではconsul info
、consul members
やDNS lookupすらできません。
agentのコンテナでは
/ # consul members / #
何も表示されませんし、
$ dig @127.0.0.1 -p 8600 consul.service.consul ; <<>> DiG 9.10.6 <<>> @127.0.0.1 -p 8600 consul.service.consul ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 18336 ;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1 ;; WARNING: recursion requested but not available ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;consul.service.consul. IN A ;; AUTHORITY SECTION: consul. 0 IN SOA ns.consul. hostmaster.consul. 1544125928 3600 600 86400 0 ;; Query time: 11 msec ;; SERVER: 127.0.0.1#8600(127.0.0.1) ;; WHEN: Fri Dec 07 04:52:08 JST 2018 ;; MSG SIZE rcvd: 100
このように;; WARNING: recursion requested but not available
と怒られます。
なので、Anonymous Token
に権限を追加します。
Policy作成
以下を参考にconsul members
やDNS lookup
ができる権限を定義します。
https://www.consul.io/docs/guides/acl.html#configure-the-anonymous-token-optional-
agent_prefix "" { policy = "read" } node_prefix "" { policy = "read" } service "consul" { policy = "read" }
Policyを作成します。
/ # consul acl policy create \ -name "anonymous-policy" \ -description "Anonymous Token Policy" \ -rules @/consul/policies/anonymous.hcl ID: b4898e08-b19f-ea0d-20d0-f9cc2bcfaabd Name: anonymous-policy Description: Anonymous Token Policy Datacenters: Rules: agent_prefix "" { policy = "read" } node_prefix "" { policy = "read" } service "consul" { policy = "read" }
Anonymous TokenへPolicyのアタッチ
/ # consul acl token update \ -id 00000000-0000-0000-0000-000000000002 \ -policy-name "anonymous-policy" \ -description "Anonymous Token" Token updated successfully. AccessorID: 00000000-0000-0000-0000-000000000002 SecretID: anonymous Description: Anonymous Token Local: false Create Time: 2018-12-06 19:23:40.4129681 +0000 UTC Policies: b4898e08-b19f-ea0d-20d0-f9cc2bcfaabd - anonymous-policy
動作確認
agentにログインしてみて
$ docker exec -it acl_consul-agent-1_1 /bin/ash
consul members
ができることを確認できますし、
/ # consul members Node Address Status Type Build Protocol DC Segment 1d561da489ed 172.25.0.4:8301 alive server 1.4.0 2 dc1 <all> dccab8780f64 172.25.0.6:8301 alive server 1.4.0 2 dc1 <all> e03b703d4345 172.25.0.7:8301 alive server 1.4.0 2 dc1 <all> 091e7c809fb1 172.25.0.3:8301 alive client 1.4.0 2 dc1 <default> e98cc8322113 172.25.0.5:8301 alive client 1.4.0 2 dc1 <default> fa3d5ff86fdc 172.25.0.2:8301 alive client 1.4.0 2 dc1 <default>
ローカルにポートマップしたagent経由でDNS lookupもできます。
$ dig @127.0.0.1 -p 8600 consul.service.consul ; <<>> DiG 9.10.6 <<>> @127.0.0.1 -p 8600 consul.service.consul ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 45022 ;; flags: qr aa rd; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 4 ;; WARNING: recursion requested but not available ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;consul.service.consul. IN A ;; ANSWER SECTION: consul.service.consul. 0 IN A 172.25.0.6 consul.service.consul. 0 IN A 172.25.0.7 consul.service.consul. 0 IN A 172.25.0.4 ;; ADDITIONAL SECTION: consul.service.consul. 0 IN TXT "consul-network-segment=" consul.service.consul. 0 IN TXT "consul-network-segment=" consul.service.consul. 0 IN TXT "consul-network-segment=" ;; Query time: 5 msec ;; SERVER: 127.0.0.1#8600(127.0.0.1) ;; WHEN: Fri Dec 07 05:06:12 JST 2018 ;; MSG SIZE rcvd: 206
UIリソースの許可
最後の例で、Web UIの機能が使えるためのACL Policyを設定します。
現状だと権限がないので、一部のページで以下のようにエラーがでます。
Policyの作成
https://www.consul.io/docs/guides/acl.html#create-tokens-for-ui-use-optional-
を参考に以下の権限を付与します。
xxx_prefix
という形式の場合そのリソース全てが対象になります。
key_prefix "" { policy = "write" } node_prefix "" { policy = "read" } service_prefix "" { policy = "read" }
Policyを作成します。
/ # consul acl policy create \ -name "ui-policy" \ -description "UI Token Policy" \ -rules @/consul/policies/ui.hcl ID: 83a7b2cc-6996-fb0e-0d23-11ea1d86b3a7 Name: ui-policy Description: UI Token Policy Datacenters: Rules: key_prefix "" { policy = "write" } node_prefix "" { policy = "read" } service_prefix "" { policy = "read" }
Tokenの生成
/ # consul acl token create \ -description "UI Token" \ -policy-name "ui-policy" AccessorID: 2ea57bc4-5793-eb44-d050-323d107a5993 SecretID: 0689d5fa-f4f0-cf60-eed5-1e1346c7c346 Description: UI Token Local: false Create Time: 2018-12-06 20:15:36.7292146 +0000 UTC Policies: 83a7b2cc-6996-fb0e-0d23-11ea1d86b3a7 - ui-policy
0689d5fa-f4f0-cf60-eed5-1e1346c7c346
がtokenです。
UIのACLページ設定
こちらでトークンをセットします。
ちなみにここでセットしたトークンはlocalStorageに保存されるだけなので、他のブラウザではトークンは反映されません。
全体的に反映したい場合は以下のようにconsul configのdefault tokenとして設定してください。
{ "primary_datacenter": "dc1", "acl": { "enabled": true, "down_policy": "extend-cache", "tokens": { "agent": "271970dd-8498-8361-599b-fc90fb65257b", "default": "0689d5fa-f4f0-cf60-eed5-1e1346c7c346" } } }
動作確認
先程のようにkey/valueを登録してみると
ちゃんと成功しました。
まとめ
ConsulはVaultなど秘密情報のバックエンドに利用したり、設定ファイルのリアルタイム更新などに使うため適切にアクセス制御する必要があります。
AWSで完全にPrivate Subnetに閉じている場合はまだいいですが、Public SubnetにConsul agentがいたり、すべてPublicに置かれるGCPで使う場合は必ずACLでアクセス制御を行ってください。