consul 配置/KV/ACL

[TOCM]

Consul版本 v0.9.3

1. 配置

1.1 CLI配置

Consul Agent有各种各样的配置项可以在命令行或者配置文件进行定义,所有的配置项都是可选择的,当加载配置文件的时候,Consul从配置文件或者配置目录加载配置。后面定义的配置会合并前面定义的配置,但是大多数情况下,合并的意思是后面定义的配置会覆盖前面定义的配置,但是有些情况,例如event句柄,合并仅仅是添加到前面定义的句柄后面。Consul重新加载配置文件也支持以信号的方式接收update信号。
- -advertise:通知展现地址用来改变我们给集群中的其他节点展现的地址,一般情况下-bind地址就是展现地址
- -bootstrap:用来控制一个server是否在bootstrap模式,在一个datacenter中只能有一个server处于bootstrap模式,当一个server处于bootstrap模式时,可以自己选举为raft leader。
- -bootstrap-expect:在一个datacenter中期望提供的server节点数目,当该值提供的时候,consul一直等到达到指定sever数目的时候才会引导整个集群,该标记不能和bootstrap公用
- -bind:该地址用来在集群内部的通讯,集群内的所有节点到地址都必须是可达的,默认是0.0.0.0
- -client:consul绑定在哪个client地址上,这个地址提供HTTP、DNS、RPC等服务,默认是127.0.0.1
- -config-file:明确的指定要加载哪个配置文件
- -config-dir:配置文件目录,里面所有以.json结尾的文件都会被加载
- -data-dir:提供一个目录用来存放agent的状态,所有的agent允许都需要该目录,该目录必须是稳定的,系统重启后都继续存在
- -dc:该标记控制agent允许的datacenter的名称,默认是dc1
- -encrypt:指定secret key,开启gossip加密,使consul在通讯时进行加密,同一个集群中的节点必须使用相同的key。
key必须是16bytes长度的base64加密,也可以通过consul keygen直接产生一个。生成secret key的方法

root@server1:~# consul keygen
WAFhifMUpMk0IISXSOQnhw==
  • -join:加入一个已经启动的agent的ip地址,可以多次指定多个agent的地址。如果consul不能加入任何指定的地址中,则agent会启动失败,默认agent启动时不会加入任何节点。
  • -retry-join:和join类似,但是允许你在第一次失败后进行尝试。
  • -retry-interval:两次join之间的时间间隔,默认是30s
  • -retry-max:尝试重复join的次数,默认是0,也就是无限次尝试
  • -log-level:consul agent启动后显示的日志信息级别。默认是info,可选:trace、debug、info、warn、err。
  • -node:节点在集群中的名称,在一个集群中必须是唯一的,默认是该节点的主机名
  • -protocol:consul使用的协议版本
  • -rejoin:使consul忽略先前的离开,在再次启动后仍旧尝试加入集群中。
  • -server:定义agent运行在server模式,每个集群至少有一个server,建议每个集群的server不要超过5个
  • -syslog:开启系统日志功能,只在linux/osx上生效
  • -ui-dir:提供存放web ui资源的路径,该目录必须是可读的
  • -pid-file:提供一个路径来存放pid文件,可以使用该文件进行SIGINT/SIGHUP(关闭/更新)agent

1.2 FILE配置

除了命令行参数外,配置也可以写入文件中,启动时候使用-config-file参数。
在某些情况下配置文件会更简单一些,例如:Consul被用来管理系统。配置文件是json格式的,很容易编写。配置文件不仅被用来设置Agent的启动,也可以用来提供健康检测和服务发现的定义。配置文件的一般格式如下:

{
  "datacenter": "consul",
  "data_dir": "/opt/consul",
  "ui": true,
  "log_level": "INFO",
  "node_name": "consul",
  "server": true,
  "watches": [
    {
        "type": "checks",
        "handler": "/usr/bin/health-check-handler.sh"
    }
  ]
}

详细的配置文件参数:

  • acl_datacenter:只用于server,指定的datacenter的权威ACL信息,所有的servers和datacenter必须同意ACL datacenter
  • acl_default_policy:默认是allow
  • acl_down_policy:
  • acl_master_token:
  • acl_token:agent会使用这个token和consul server进行请求
  • acl_ttl:控制TTL的cache,默认是30s
  • addresses:一个嵌套对象,可以设置以下key:dns、http、rpc
  • advertise_addr:等同于-advertise
  • bootstrap:等同于-bootstrap
  • bootstrap_expect:等同于-bootstrap-expect
  • bind_addr:等同于-bind
  • ca_file:提供CA文件路径,用来检查客户端或者服务端的链接
  • cert_file:必须和key_file一起
  • check_update_interval:
  • client_addr:等同于-client
  • datacenter:等同于-dc
  • data_dir:等同于-data-dir
  • disable_anonymous_signature:在进行更新检查时禁止匿名签名
  • disable_remote_exec:禁止支持远程执行,设置为true,agent会忽视所有进入的远程执行请求
  • disable_update_check:禁止自动检查安全公告和新版本信息
  • dns_config:是一个嵌套对象,可以设置以下参数:allow_stale、max_stale、node_ttl 、service_ttl、enable_truncate
  • domain:默认情况下consul在进行DNS查询时,查询的是consul域,可以通过该参数进行修改
  • enable_debug:开启debug模式
  • enable_syslog:等同于-syslog
  • encrypt:等同于-encrypt
  • key_file:提供私钥的路径
  • leave_on_terminate:默认是false,如果为true,当agent收到一个TERM信号的时候,它会发送leave信息到集群中的其他节点上。
  • log_level:等同于-log-level
  • node_name:等同于-node
  • ports:这是一个嵌套对象,可以设置以下key:dns(dns地址:8600)、http(http api地址:8500)、rpc(rpc:8400)、serf_lan(lan port:8301)、serf_wan(wan port:8302)、server(server rpc:8300)
  • protocol:等同于-protocol
  • recursor:Address of an upstream DNS server. Can be specified multiple times.
  • rejoin_after_leave:等同于-rejoin
  • retry_join:等同于-retry-join
  • retry_interval:等同于-retry-interval
  • server:等同于-server
  • server_name:会覆盖TLS CA的node_name,可以用来确认CA name和hostname相匹配
  • skip_leave_on_interrupt:和leave_on_terminate比较类似,不过只影响当前句柄
  • start_join:一个字符数组提供的节点地址会在启动时被加入
  • statsd_addr:
  • statsite_addr:
  • syslog_facility:当enable_syslog被提供后,该参数控制哪个级别的信息被发送,默认Local0
  • ui: 是否启用web ui,不能和底下的ui_dir同时启用,会报错。
  • ui_dir:等同于-ui-dir
  • verify_incoming:默认false,如果为true,则所有进入链接都需要使用TLS,需要客户端使用ca_file提供ca文件,只用于consul server端,因为client从来没有进入的链接
  • verify_outgoing:默认false,如果为true,则所有出去链接都需要使用TLS,需要服务端使用ca_file提供ca文件,consul server和client都需要使用,因为两者都有出去的链接
  • watches:watch一个详细名单

Consul Agent支持所有的网络通讯进行加密,关于加密的具体信息可以参考 官方描述 ,有两个分开的系统,一个是gossip流量,一个是RPC。
使用TLS为RPC加密,主要是上面介绍的verify_incoming和verify_outgoing参数来设置。

2. K/V 存储

除了提供服务发现和综合健康检查,Consul还提供了一个易于使用的键/值存储。这可以用来保存动态配置,协助服务协调,建立领导人选举,并启用其他开发人员可以想构建的任何其他内容。

有两种方法可以使用:通过HTTP API和通过CLI API。下面的例子显示使用CLI API

root@server1:~# consul kv get redis/config/minconns
Error! No key exists at: redis/config/minconns

你将看到没有结果返回,由于KV存储中没有该键返回了一个错误,接下来我们将插入或”put”一个值到KV存储中。

root@server1:~# consul kv put redis/config/minconns 1
Success! Data written to: redis/config/minconns

现在再次查询该键你将看到如下结果:

root@server1:~# consul kv get redis/config/minconns
1

Consul保留额外的元数据在该字段,你可以使用-detailed标志检索详细信息:

root@server1:~# consul kv get -detailed redis/config/minconns
CreateIndex      1049
Flags            0
Key              redis/config/minconns
LockIndex        0
ModifyIndex      1049
Session          -
Value            1

设置值的时候,还可以使用-flags标志
- -flags=<uint>
Unsigned integer value to assign to this key-value pair. This value is not read by Consul, so clients can use this value however makes sense for their use case. The default value is 0 (no flags).

flags用来做客户端自定义标志,consul并不使用它,你可以在你自己的程序中随便定义

root@server1:~# consul kv put -flags=42 redis/config/users/admin abcd1234
Success! Data written to: redis/config/users/admin

设置flag值为42,想设置成什么就设置成什么.所有的键都支持设置一个64位的整型值。

使用-recurse选项可以列出KV存储中所有keys,返回的结果将按照字母排序。

root@server1:~# consul kv get -recurse
redis/config/minconns:1
redis/config/users/admin:abcd1234

使用delete命令删除KV存储中指定的key。

root@server1:~# consul kv delete redis/config/minconns
Success! Deleted key: redis/config/minconns

还可以使用recurse选项递归选项删除含某个前缀的所有keys:

root@server1:~# consul kv delete -recurse redis
Success! Deleted keys with prefix: redis

如果要更新一个存在键的值,可以put一个新值在同样的路径上。

root@server1:~# consul kv put foo bar
Success! Data written to: foo
root@server1:~# consul kv get foo
bar
root@server1:~# consul kv put foo zip
Success! Data written to: foo
root@server1:~# consul kv get foo
zip

Consul可以使用Check_And_Set提供原子键更新操作。执行CAS操作时需指定-cas标志。至于什么是CAS,请自行百度吧
- -modify-index=<uint>
Unsigned integer representing the ModifyIndex of the key. This is used in combination with the -cas flag.

首先查询foo这个key的详细信息

root@server1:~# consul kv get -detailed foo
CreateIndex      1065
Flags            0
Key              foo
LockIndex        0
ModifyIndex      1067
Session          -
Value            zip

看到foo的索引编号ModifyIndex是1067。然后使用CAS操作的方式来修改它

root@server1:~# consul kv put -cas -modify-index=1067 foo bar
Success! Data written to: foo

修改成功,再查询

root@server1:~# consul kv get -detailed foo
CreateIndex      1065
Flags            0
Key              foo
LockIndex        0
ModifyIndex      1091
Session          -
Value            bar

ModifyIndex变成1091了。依然使用上面那个修改命令试试

root@server1:~# consul kv put -cas -modify-index=1067 foo bar
Error! Did not write to foo: CAS failed

失败了。原因是第一次CAS操作成功,因为ModifyIndex的值是1067,我们输入的也是-modify-index=1067。
第二次操作失败,ModifyIndex已经变成1091了,我们还用-modify-index=1067,Check_And_SetS中的Check这步就失败了,不会再Set了。

3. ACL

Access Control List,有没有发现consul web ui是可以直接访问做各种操作的,传说中的登录这种屏障都没有啊。so,需要一个ACL来限制操作权限,就像“登录”了一样。
官方文档:https://www.consul.io/docs/guides/acl.html

3.1 服务端ACL

1.启动consul的all模式时,我的核心配置文件:

{
    "acl_datacenter": "dc1",
    "acl_master_token": "xxxhelloworldxxx",
    "acl_default_policy": "deny" //开启acl
    ......
}

这三个配置是使用ACL的必须选项
- acl_datacenter:数据中心名称。可填all表示所有的数据中心都启用acl。
- acl_master_token:服务端选举的令牌。这个是自己指定的,随便来一串字符串就可以了。当然如果正式上线则不能随便,可以使用uuidgen | awk '{print tolower($0)}'生成,每台主机都不相同。需要在每个server上配置,有management级别的权限,相当于一个种子token用来生成其余token。
- acl_default_policy:默认策略
不配置rule规则的情况下默认值是allow,即能够执行任何操作。(可配置为allow,deny)
当acl_default_policy为deny是,默认的api(写)行为都会被阻止,我们可以配置其子项,让比如配置key可写,这样在全部deny的情况下,出现了一个默认可写的行为,这就是白名单
黑名单反之,当acl_default_policy为allow时,默认行为都是允许的,我们可以配置子项使它某些行为为deny,这就是黑名单的概念
若要开启all,acl_default_policy需要设置成deny
- acl_ttl:控制TTL的cache,默认是30s

按这个配置启动带web ui的consul server后,访问 http://10.111.152.242:8500/ui/#/dc1/services ,发现页面是空的,什么都没有,一片空白啊,连个字都没有。同时sever打印日志

2017/09/08 16:04:51 [ERR] http: Request GET /v1/internal/ui/nodes?dc=dc1&token=<hidden>, error: ACL not found from=10.111.152.150:61226

这下连web ui都不让我访问了,报403 forbidden。其实这是个bug,要清理浏览器缓存,然后才能访问web ui。

清理缓存后,可以进入web ui中,但是没法看到service、nodes、kv等信息了,点击ACL,提示

Access Denied

Your ACL token does not have the appropriate permissions to perform the expected action.

同时在server端日志显示

2017/09/08 18:31:10 [ERR] http: Request GET /v1/acl/list?dc=dc1&token=<hidden>, error: Permission denied from=10.111.152.150:57776

说明ACL已经生效了,目前阻止了我们的访问。

2.创建子token
要访问那些被阻止的信息,就要申请token

root@server1:~# curl -H "X-Consul-Token: secret" -X PUT -d '{"Name": "dc1", "Type": "management"}' http://10.111.152.242:8500/v1/acl/create?token=xxxhelloworldxxx
{"ID":"fc6cad19-4323-9a93-4e5a-9d2e00d91360"}
  • Name:token的name
  • Type:token的类型,有client跟management
  • token:我们上面说到的master token

返回这个ID就是我们需要的子token,将这个management权限的token配置在web ui节点的server上,便于管理ACL、k/v、service等

{
    "acl_datacenter": "dc1",
    "acl_master_token": "xxxhelloworldxxx",
    "acl_default_policy": "deny", //开启acl
    "acl_token" : "dae1911a-a81f-136b-7ad2-20a65fe98d9d"
    ......
}

这次重启就可以访问acl了,浏览器缓存别忘了先清理下。这次再访问web ui,就能看到services和nodes都给访问了,点击ACL也能看到列表了。

当然也可以用命令行访问,要加上token

root@server1:~# curl "http://10.111.152.242:8500/v1/internal/ui/nodes?dc=dc1&token=fc6cad19-4323-9a93-4e5a-9d2e00d91360"
[{"ID":"27b5e48b-08f5-9605-434b-dfbfcb7acdb9","Node":"server1","Address":"10.111.152.242","TaggedAddresses":{"lan":"10.111.152.242","wan":"10.111.152.242"},"Meta":{},"Services":[{"ID":"consul","Service":"consul","Tags":null,"Address":"","Port":8300,"EnableTagOverride":false,"CreateIndex":5,"ModifyIndex":5}],"Checks":[{"Node":"server1","CheckID":"serfHealth","Name":"Serf Health Status","Status":"passing","Notes":"","Output":"Agent alive and reachable","ServiceID":"","ServiceName":"","ServiceTags":null,"CreateIndex":5,"ModifyIndex":5}]},{"ID":"ce41eb68-411b-a80f-4e8f-557fb838edb0","Node":"server3","Address":"10.111.152.246","TaggedAddresses":{"lan":"10.111.152.246","wan":"10.111.152.246"},"Meta":{},"Services":[{"ID":"registrator-3:root_web_1:80","Service":"my-web-server","Tags":["backend-3"],"Address":"10.111.152.246","Port":32768,"EnableTagOverride":false,"CreateIndex":9,"ModifyIndex":9}],"Checks":[{"Node":"server3","CheckID":"serfHealth","Name":"Serf Health Status","Status":"passing","Notes":"","Output":"Agent alive and reachable","ServiceID":"","ServiceName":"","ServiceTags":null,"CreateIndex":7,"ModifyIndex":7}]}]

后来我发现,直接把acl_master_token的值复制给acl_token也是可以访问的,哈哈,不用中间生成token那一步了,生了不少事啊。

3.2 客户端ACL

上面我们配置了server端的acl,客户端均链接不上去,日志报

[ERR] consul: RPC failed to server 192.168.56.101:8300: rpc error: Permission denied

这样的错误,显然被server给拒绝了,现在我们要在client节点上配置acl_token,以通过server的验证。

server ACL页面
先回到server的ACL页面。默认ACL有anonymous token,type是client;master token, type是management。现在我们添加一个自定义ACL,命名为client-1,type选择client,然后往rules里面写规则。

rules语法:

规则对象 "" { policy = "read" }

规则对象有:agent、event、key、keyring、node、operator、query、service、session。
read、write、deny是规则权限。
这只是其中一种语法,还支持json格式的语法。

例子,往rules中填入

agent "" { policy = "read" }

这个意思是所有agent的请求都有读的权限。

如果要指定过滤某些特定的节点有写权限,类似白名单,可以这样

规则对象 "节点名称" { policy = "write" }

例如,对-node=host-2的节点

agent "host-2" { policy = "write" }

多个规则,可以换行排列,例如我的配置

agent "" { policy = "read" }
agent "host-2" { policy = "write" }
service "" {  policy = "read"  } #
service "" {  policy = "write"  } #这个可以把client的Service上报到server上去。
node "" {  policy = "write"  }
event "" {  policy = "write"  }
query "" { policy = "write"  }

看看效果
https://offical.b0.upaiyun.com/static/article/1508904606718228503.png

添加成功的时候,会生成一个token,我这里是a724b77f-1ad6-57e4-c553-127a51d6beda,把它给客户端,准备接入吧。

client节点
到客户端机器上,修改配置文件。acl_master_token只有server端可以配置,客户端只要配置这两个重启下,就可以通过认证了

{
    "acl_datacenter": "dc1",
    "acl_token": "a724b77f-1ad6-57e4-c553-127a51d6beda"
    ......
}

在server端的ui上就能看到重新链接上的client上报的信息了。

3.3 ACL API

上面创建acl的操作,使用json格式的api来创建

root@host-1:~# curl --request PUT --data '{"Name": "client1","Type": "client","Rules": "{\"agent\":{\"\":{\"policy\":\"read\"}},\"service\":{\"\":{\"policy\":\"read\"}},\"node\":{\"\":{\"policy\":\"write\"}},\"service\":{\"\":{\"policy\":\"write\"}},\"event\":{\"\":{\"policy\":\"write\"}},\"query\":{\"\":{\"policy\":\"write\"}}}"}' http://localhost:8500/v1/acl/create?token=xxxhelloworldxxx
{"ID":"1b64d3ea-db7e-5cdf-5089-ba6e9a26f7ea"}

创建名为client1的acl成功,并且返回生成的允许client端访问的token。这个Name是可以重复的,大家起名字的时候尽量不要重复。

更新acl

$ curl --request PUT --header "X-Consul-Token: b1gs33cr3t" --data '{"ID":"anonymous","Type": "client","Rules": "node \"\" { policy = \"read\" }"}' http://127.0.0.1:8500/v1/acl/update

另外我这里的访问地址使用了localhost,不管在server端,还是client,都可以这样用,最终消息都会发到server端的。经过测试,server端都不用token字段了,client端一定要把acl_master_token的值赋值给token才行。

多数据中心ACL复制

在多数据中心Consul配置中,新的ACL复制特性允许用户将整套的ACL从ACL数据中心同步到非授权的数据中心,防止网络分区。在0.7版本之前,非授权数据中心的ACL只是一份缓存,在WAN故障时可能会导致ACL不完整。

4. 常见问题

4.1 Failed to get advertise address

Error starting agent: Failed to get advertise address: Multiple private IPs found.
启动的时候加-bind参数绑定ip

consul agent -dev -bind 192.168.231.18
4.2 8500端口没开

检查一下是不是直接连这个端口就会拒绝呢?

ncat -v localhost 8500

或者

nc -v localhost 8500

如果这样连还是『connection refused』说明Consul服务有问题。

参考:
http://bbotte.com/server-config/consul-acl-rule-usage/


创建于 2017-09-08 北京,更新于 2017-10-25 北京

该文章在以下平台同步
- HICOOL.TOP: https://www.hicool.top/article/143
- CSDN:
- 简书: http://www.jianshu.com/p/05741685af33

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页