consul 配置/KV/ACL

作者: Liberalman | 来源:发表于2017-10-24 12:07 被阅读560次

    [TOCM]

    Consul版本 v0.9.2

    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是规则权限。

    例如,往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上报的信息了。

    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 北京

    该文章在以下平台同步

    相关文章

      网友评论

      • 5ffea1b71c75::flushed:client addr可以配置成localhist吗? 这样会影响节点加入集群吗
        Liberalman:@Amoy_Sun 可以独立成单独节点的,“让每个应用都去连接consul client”这个表述不对,而应该是“让consul client去访问每个应用的的心跳地址”,所以,client不需要做harproxy,是它去访问应用,不是应用访问它。另外client还需要连接到consul server,而这个server本身就是多个节点对等访问的cluster,访问任何一个server节点都行,也不用haproxy。
        5ffea1b71c75:@Liberalman 请问下 consul client可以独立出来吗? 让每个应用都直接去连接consul client? 当然为了解决client的单点问题,我考虑用haproxy代理client cluster。 请问这样可以吗? 主要是不想每个应用里面都安装一个client,
        Liberalman:@Amoy_Sun 要指名ip地址,localhost是不行的,到时候上报到服务器上做记录的,需要一个明确的客户端ip地址,以便别人能根据这个地址访问到你的客户端上,否则,服务器一看是localhost,还以为是自己本地的ip呢。
      • 陶好达:厉害了我的超哥:smile:
        Liberalman:@超级无敌大猩猩 同厉同厉:smile:
      • 724071ba206f:挺有帮助的,谢谢! 有个问题请教下,我想限制一个客户端consul获取memberlist,但是我又想当前token可以控制多个客户端consul。 也就是说我想要a,b,c这三个consul客户端使用同一个token,来使得这三个consul都不能执行 consul members命令(只能看到自己),a,b,c三个客户端的node名没有规律
        Liberalman:@dev_chenl 啊,你这个既要看自己,又不能看别人,还大家都一致的token,目前办不到啊。
        Liberalman:@dev_chenl 没有这样的字段
        724071ba206f:有没有一个字段xxx可以标识是自己? agent "xxx" {"policy":"read"}
      • Liberalman:自己的文章,再烂也要看完!:eyes:

      本文标题:consul 配置/KV/ACL

      本文链接:https://www.haomeiwen.com/subject/xyptpxtx.html