Consule系列:Consul实现详解

Consul 的实现

Consul 使用 Consensus 协议提供一致性(Consistency)—— CAP 定义的一致性。Consensus 协议是基于 “Raft: In search of an Understandable Consensus Algorithm” 实现的。

Consul Protocol

Raft 算法

  • Raft 是基于 Paxos 的一致性算法。 与 Paxos 相比,Raft 被设计为具有更少的状态和更简单,更容易理解的算法。
  • Raft 算法是一种基于日志复制实现数据同步的高效算法,它在解决分布式系统中各个节点记录内容一致性问题的同时,也使得集群具备一定的容错能力。这种容错能 力体现在两个方面。

    • 当集群中出现网络故障或少于半数节点发生故障时,仍可以保证其余大多数节点正运行 。
    • 当集群中超过半数节点出现故障时 ,将导致集群不可用,但 Raft 算法依然可以保证节点中的数据不会出现错误的结果,从而为集群提供灾后备份和恢复的机会。

Raft 术语

  • Log:在 Raft 系统主要的工作单元为 Log entry。一致性的问题可以分解为复制日志。一个 log 是一个顺序的条目列表(entrylist)。如果所有成员都同意 log 的entry 和顺序,我们认为日志是一致的。
  • FSM:有限状态机。FSM 是有限个状态的集合以及在这些状态之间的转移和动作等行为的数学模型。当应用新日志时,允许 FSM 在状态之间转换。 相同的日志序列的应用必须导致相同的状态,这意味着行为必须是确定性的。
  • Peer set:Peer set 是参与日志复制的所有成员的集合。对于 Consul 而言,所有的 server 节点 均属于本地数据中心的 Peer set。
  • Quorum:法定票数,取决于 Peer set 大多数成员。对于大小为 n 的 set,quorum 需要至少(n / 2)+1 个成员。例如,Peer set 有 5 个 server 节点,就需要 至少 3 个节点才能形成 quorum。无论什么原因,只要 quorum 是无效的,那么 cluster 就会变为 unavailable,并且不会再有 log 提交。
  • Committed Entry:当条目永久存储在在法定数量的节点上,该条目才会被视为已提交(committed)。 一旦条目提交,它可以被应用。
  • Leader:在任何给定的时间,Peer set 选举一个节点作为 Leader。当 log commited 时,Leader 负责新 entry 处理、复制到 Followers,以及管理何时 entry 被视为已提交。

Raft 角色和状态机

Raft 集群中的每个节点都处于一种基于角色的状态机中。具体来说, Raft 定义了节点的三种角色:FollowerCandidata 和 Leader

  • Leader(领导者):Leader 节点在集群中有且仅能有一个,它负责向所有的 Follower 节点同步日志数据。
  • Follower(跟随者):Follower 节点从 Leader 节点获取日志,提供数据查询功能,并将所有修改请求转发给 Leader 节点。
  • Candidate(侯选者):当集群中的 Leader 节点不存在或失联后,其它 Follower 节点转换为 Candidata,然后开始新的 Leader 节点选举。

在节点初始启动时,所有节点的 Raft 状态机均处于 Follower 状态。当 Follower 在一定时间周期内没有收到来自 Leader 节点的心跳数据包时,节点会将自己的状态切换为 Candidate,并向集群中其它 Follower 节点发送投票请求,Follower 都会将自己的票投给收到的第一个投票请求节点。当 Candidate 收到来自集群超过半数节点的接收投 票后,即成为新的 Leader 节点。Leader 节点将接收并保存用户发送的数据,并向其它的 Follower 节点同步日志。

Leader 节点依靠定时向所有 Follower 发送心跳数据包来保持其地位。当集群中的 Leader 节点出现故障失联时,Follower 中又会重新选举出新的节点,从而确保整个集群 正常运作。

每成功选举一次,新 Leader 的 Team(任届)值都会比之前 Leader 的增加 1。当集群中由于网络或其它原因的故障出现分裂又重新合并时,集群中可能会出现多于一个的 Leader 节点,此时,Term 值更高的一个节点将成为真正的 Leader。

Raft in Consul

只有 Consul server 节点参与 Raft,并且组成 Peer set。 所有 clients 节点将请求转发到 server 节点。 此设计的部分原因是,随着更多成员被添加到 Peer set,法定票 数(quorum )的大小也随之增加。 这就引入了性能问题,因为您可能正在等待数百台机器同意一个 entry,而不是少数。

开始时,单个 Consul 服务器被置于 bootstarp(引导) 模式,且在``一个 Datacenter 中 只能有一个 server 节点 处于 bootstrap 模式(多 bootstrap 模式的 server 会 使群集处于不一致的状态),当一个 server 处于 bootstrap 模式时,可以选举自己为 raft leader。一旦 lender 被选举,其他 server 节点可以以保持一致性和安全性的方 式添加到集群中。最终,一旦添加了指定数目的(-bootstrap-expect`选项指定)server 节点后,那么就可以禁用第一个节点的 “bootstarp” 模式。

Consistency Modes

虽然对复制日志的所有写入都通过 Raft,读取更灵活。 为了支持开发人员可能需要的各种权衡,Consul 支持 3 种不同的一致性模式进行读取。

  • Default-Raft

    • 采用 Leader 租赁模式,提供了一个时间窗口,在该时间段内, Leader 角色是稳定的。但是,如果 Leader 从 Peers set 分裂出去,新的 Leader 就可能选举 出来,而旧 Leader 持有租赁。这意味着有 2 个 leader 节点。因为旧 Leader 不能提交新日志,就没有脑裂的风险。然而,如果旧 Leader 执行任何读取操 作,其读取到的结果就可能是过期的。Default 一致性模式只依赖于 Leader 租赁,Client 可能使用过期的数据。之所以这么权衡,因为读取是快速的,通常是 采用强一致性模式,只有在一个难以触发的情况下过期。并且时间窗口也是有界的,时间到了,leader 也会下台。
  • consistent

    • 这种模式是无条件一致性。它要求 leader 必须与 quorum 个 Peer 校验,虽然它仍然是 Leader。这将引入额外的节点轮询,增加了延迟。采用一致性读取,会导致额外的轮询开销。
  • stale

    • 这种模式允许在任何 Server 节点执行读取操作,无论它是不是 Leader。这意味着可能读取到旧的数据,但一般而言,速度与 leader 相比差距在 50 毫秒内。
    • 这种方式,读取速度是非常快的,但可能是旧的数据。这种模式下,即使没有 Leader,一样可以相应读取操作。

Bootstrapping a Datacenter

一个 agent 节点可以运行在 client 和 sever 模式。server 节点负责运行协商一致协议,并存储集群状态。client 节点大多是无状态的,并且严重依赖于 server 节点。 在 Consul 集群开始服务请求之前,必须有一个 server 节点被选举为 leader。 因此,被启动的第一节点必须是 server 节点。 Bootstrapping 是将这些初始 server 节点加入集群的过程。

推荐的 bootstrap 方式是使用 -bootstrap-expect 配置选项。 该选项表明:在一个 Datacenter 中期望提供的 server 节点数目,当该值提供的时候,consul 一直等到 server 节点达到指定数目时才会引导整个集群。这是为了防止不一致和裂脑情况(即多个服务器认为自己处于领导地位的集群),所有 server 节点应为 “-bootstrap- expect” 指定相同的值或完全不指定任何值。 只有指定值的 servers 将尝试引导集群。建议每个数据中心 3 或 5 个 server 节点。

创建集群

要触发 lender 选举,我们必须将这些 servers 节点一起加入并创建集群。 有两种选择加入:

  • 使用 HashiCorp 提供的 Atlas 自动加入,Atlas 是用于部署应用程序和管理基础架构的服务.
  • 手动添加 servers 节点至集群中.

Consul server 节点推荐至少在 3~5 个之间,这样可以最大限度地提高可用性,而不会大大牺牲性能。创建集群的方式,推荐的方法是一开始启动其中一台 server 节点, 并且配置到 bootstrap 模式(指定 -bootstrap 选项,指示以 bootstrap 模式启动 agent,常用于手动引导,consul 0.4 版本以前只能手动引导;该选项和 -bootstrap- expect 非 bootstrap 模式自动引导是冲突的),该模式下节点可以指定自己作为 leader,而不用进行选举。然后再依次启动其他 server 节点,配置为非 bootstrap 模 式。最后把第一个 server 的 bootstrap 模式停止,重新以非 bootstrap 模式启动,这样 server 之间就可以自动选举 leader。详见参见官方文档。

集群节点数目与容忍的故障节点数目:

Gossip in Consul

Consul 使用 gossip 协议管理成员关系、广播消息到整个集群。 所有这些都是通过使用 Serf 库提供的。Serf 使用的 gossip 协议是基于 “SWIM:可伸缩可传导的弱一致性 进程组成员资格协议”,它用来维护分布式系统中进程成员资格的协议”。

Consul 使用两个不同的 goosip pool,分别把他们称为 局域网池(LAN Pool) 或 广域网池(WAN Pool)

每个 Consul 数据中心都有一个包含所有成员(Server 和 Client)的 LAN gossip pool。

  • LAN Pool 有如下几个目的:首先,成员关系允许 Client 自动发现 Server 节点,减少所需的配置量。然后,分布式故障检测允许的故障检测的工作在某几个 Server 节点执行,而不是集中整个集群所有节点上。最后,gossip 允许可靠和快速的事件广播,比如,Leader 选举。
  • WAN Pool 是全局唯一的,无论属于哪一个数据中心,所有 Server 应该加入到 WAN Pool。由 WAN Pool 提供成员信息让 Server 节点可执行跨数据中心的请求。 集成中故障检测允许 Consul 妥善处理整个数据中心失去连接,或在远程数据中心只是单个的 Server 节点。

所有这些功能都是通过利用 Serf 提供。从用户角度来看,它是作为一个嵌入式库提供这些功能。但其被 Consul 屏蔽,用户无需关心。作为开发人员可以去了解这个库是如 何利用。

Network Coordinates

Consul 使用 network tomography(网络层析成像) 系统来计算集群中的节点的网络坐标。这些坐标允许使用非常简单的计算来估计任何两个节点之间的网络往返时间。 这允许许多有用的应用,例如找到最接近请求节点的 server 节点,或故障切换到下一个最接近的数据中心中的 servers 节点。

所有这些都是通过使用 Serf 库提供的。 Serf 的 network tomography 是基于 “Vivaldi:分布式网络坐标系统”,其基于其他研究一些增强。

Network Coordinates in Consul

  • consul rtt 令可用于查询任意两个节点之间的网络往返时间。
  • Catalog endpoints 和 Health endpoints 可以使用 “?near=” 参数,基于来自给定节点的网络往返时间对查询的结果进行排序。
  • Prepared queries 可以根据网络往返时间自动将 services 故障转移到其他 Consul 数据中心。
  • Coordinate endpoint 暴露原始网络坐标以用于其他应用程序。

Consul 使用 Serf 管理两个不同的 gossip pool,一个用于具有给定数据中心成员的 LAN(所有 client 和 server 节点),一个用于仅由所有数据中心的 Consul server 节 点组成的 WAN。 请注意,这两个 poll 之间的网络坐标不兼容。 LAN 坐标只有在与其他 LAN 坐标的计算中才有意义,WAN 坐标仅与其他 WAN 坐标有意义。

Sessions

Consul 提供了一个可用于 构建分布式锁 的会话(session)机制。 Session 充当节点、运行状况检查和键/值数据之间的绑定层。 它们旨在提供细粒度的锁定,并受到松 散耦合的分布式系统的分布式锁服务(The Chubby Lock Service for Loosely-Coupled Distributed Systems)的大量启发。

Consul 中的 session 表示具有非常特定语义的 contract 。 当构建会话时,可以提供节点名称、健康检查列表、行为、TTL 和 锁定延迟。 新构造的 session 具有可用于 识别它的命名 ID。 此 ID 可与 KV 存储一起使用以获取锁:用于互斥的咨询机制。

Consule 提供的 contract ,在下列任何情况下,会话将失效:

  • 节点已取消注册
  • 任何健康检查都被取消注册
  • 任何健康检查都进入临界状态
  • 会话被明确销毁
  • TTL 到期(如果适用)

当 session 无效时,会被销毁,不能再使用。 相关锁的操作取决于在创建时指定的行为。 Consul 支持 release 和 delete 行为。 如果未指定任何内容,则 release 行为是缺省值。

ACLs

参考

Consul 提供了可选的访问控制列表(ACL)系统,可用于控制对数据和 API 的访问。ACL 是 Capability-based 的,依赖于可以应用细粒度规则的 token。 它在很多方面与 AWS IAM 非常相似。

Anti-Entropy

Consule 使用一个高级的方式来维护 service 和 health 信息的方法。

Anti-Entropy(反熵 )

机制被用来保证在不同节点上的备份(replica)都持有最新版本。

这里有两个概念性地描述,可以让我们对 Anti-Entropy 更容易理解。

  • Agent

    • 每个 Consul agent 都维护自己的一套 service 和 check 注册以及健康信息。 Agent 负责执行自己的健康检查并更新其本地状态。
    • 在 agent 的上下文中的 serivice 和 check 具有丰富的可用配置选项。这是因为 agent 负责通过使用健康检查来生成有关其 serivce 及其健康的信息。
  • Catalog

    • Consul service 发现由 service catalog(服务目录)支持。 此 catalog 是通过聚合 agent 提交的信息形成的。 
    • Catalog 维护集群的 high-level view,包括哪些 service 可用,哪些 node 运行这些 service,运行状况信息等。 

Catalog 用于通过 Consul 提供的各种接口(包括 DNS 和 HTTP)公开此信息。

与 agnet 相比,Catalog 上下文中的 service 和 check 具有更有限的字段集。 这是因为 Catalog 仅负责记录和返回有关 service、node 和运行状况的信息。

Catalog 仅由 server 节点维护。 这是因为 Catalog 是通过 Raft 日志复制的,以提供集群的统一和一致的 view。

Anti-Entropy

Entropy(熵,物理意义是体系混乱程度的度量)是系统变得越来越无序的趋势。 Consul 的反熵(Anti-Entropy)机制被设计为抵抗这种趋势,即使通过其组件的故障来保 持群集的状态有序。

Consul 在全局 service catalog 和 agent 本地状态之间有明确的区分,如上所述。 反熵机制协调世界的这两个观点:反熵是本地 agent 状态和目录的同步。 例如,当用 户向 agent 注册新 service 或 check 时,agent 进而通知 catalog 该新 check 存在。 类似地,当从 agent 中删除 check 时,也会将其从 catalog 中删除。

反熵也用于更新可用性信息。 agent 程序运行其运行状况检查时,其状态可能会更改,在这种情况下,其新状态将同步到 catalog。 使用此信息,catalog 可以基于其可用 性智能地响应关于其节点和服务的查询。

在此同步期间,还会检查 catalog 的正确性。 如果 agent 不知道的 catalog 中存在任何 service 或 check,它们将被自动删除,以使 catalog 反映该 agent 的正确服务 集和健康信息集。 Consul 将 agent 的状态视为权威;如果 agent 和 catalog view 之间存在任何差异,则将始终使用 agent 本地 view。

Periodic Synchronization

除了在 agent 发生更改时运行,反熵也是一个长时间运行的进程,它会定期唤醒同步 service,并检查 catalog 的状态。 这确保 catalog 与 agent 的真实状态紧密匹配。 这也允许 Consul 重新填充 service catalog,即使在完全数据丢失的情况下。

为了避免饱和,周期性反熵运行之间的时间量将基于簇大小而变化。 下表定义了集群大小和同步间隔之间的关系:

上述间隔为近似值。 每个 Consul agent 将在间隔窗口内选择随机交错的开始时间,以避免一个惊群(thundering herd)。

Best-effort sync

在许多情况下,Anti-entropy 可能会失败,包括 agent 或其操作环境的配置错误,I/O 问题(整个磁盘,文件系统权限等),网络问题(agent 无法与 server 通信)等。 因此,agent 尝试以尽力而为的方式同步。

如果在 Anti-entropy 运行期间遇到错误,则会记录错误,并且 agent 继续运行。 Anti-entropy 机制周期性地运行以从这些类型的瞬态故障中自动恢复。

EnableTagOverride

可以部分修改服务注册的同步,以允许外部 agent 更改 services 的标记。 这在外部监视服务需要是标签信息的真实性的来源的情况下是有用的。 例如,Redis 数据库及其 监视服务 Redis Sentinel 有这种关系。 Redis 实例负责其大部分配置,但 Sentinels 确定 Redis 实例是主实例还是辅助实例。 使用 Consul 服务配置项 EnableTagOverride ,您可以指示运行 Redis 数据库的 Consul agent 在反熵同步期间不更新标记。 有关详细信息,请参阅 service 页面。

Security Model

Consul 依靠轻量级的 gossip 机制和 RPC 系统来提供各种功能。 这两个系统都有不同的安全机制,源于他们的设计。 然而,Consul 的安全机制有一个共同的目标:提供 保密性、完整性和认证。

Gossip 协议由 Serf 提供支持,Serf 使用对称密钥或共享密钥密码系统。 有更多的细节在这里的 Serf 的安全。 有关如何在 Consul 中启用 Serf 的 gossip 的详细信息,请 参阅 encryption doc here。

RPC 系统支持使用端到端 TLS 以及可选的客户端身份验证。 TLS 是一种广泛部署的非对称密钥系统,是 Web 安全的基础。

这意味着 Consule 通信被防止窃听、篡改和欺骗。 这使得可以在不受信任的网络(如 EC2 和其他共享托管提供商)上运行 Consul。

thread model

  • 非成员访问数据
  • 由于恶意消息导致的群集状态操作
  • 由于恶意消息造成的假数据生成
  • 篡改造成状态变化
  • 拒绝对节点的服务

此外,我们认识到,可以长时间观察网络流量的攻击者可以推断集群成员。 Consul 使用的 gossip 机制依赖于向随机成员发送消息,因此攻击者可以记录所有目的地并确定 集群的所有成员。

当在系统中设计安全性时,您可以将其设计为适合威胁模型。 我们的目标不是保护最高机密数据,而是提供一个 “合理” 的安全级别,这将需要攻击者提交大量的资源来击 败。

Network Ports

有关配置网络规则以支持 Consul,请参阅 Ports Used 于 Consul 使用的网络端口列表以及有关使用哪些功能的详细信息。

Consul ACLs

ACL System Overview

ACL 系统被设计为易于使用、快速执行和灵活地执行新策略,同时提供可管理的能力。 每个 token 都有一个 ID、Name、Type 和 rule set。 ID 是随机生成的 UUID,使其不可猜测。Name 对于 Consul 来说是不透明的,但对于人类来说是可读的。Type 区 分为两种类型:client(此 token 不能修改 ACL 规则),management(此 token 允许执行所有操作)。

Token ID 与 每个 RPC 请求一起传递到服务器。 Consul 的 HTTP endpont 可以通过 token query string parameter 或带 X-Consul-Token 请求头来接受 token。 Consul 的 CLI command 可以通过 token argument 或 CONSUL_HTTP_TOKEN 环境变量来接受 token。

ACL Rules and Scope

Token 绑定到一组控制 token 可以访问的 Consul 资源的规则集。根据 acl_default_policy 的配置,可以在 whitelist 或 blacklist 模式中定义策略。 如果默认策略是拒绝 所有操作,则可以将 token 规则设置为将特定操作列入 whitelist 。 反之,允许所有默认行为是 blacklist,其中规则用于禁止操作。默认情况下,Consul 将允许所有操 作。

下表汇总了可用于构建规则的 ACL 策略:

由于 Consul snapshot 实际上包含 ACL token,Snapshot API 需要一个用于 snapshot operations 的 management token,并且不使用特殊策略。 以下资源不会在 ACL 策略覆盖:

  • Status API 由服务器在 bootstrapping 和公开有关服务器的基本 IP 和端口信息时使用,并且不允许修改任何状态。
  • Catalog API 的数据中心 listing operation 同样公开了已知 Consu l数据中心的名称,并且不允许修改任何状态。

ACL Datacenter

所有节点(clinets 和 servers 端)都必须配置一个 acl_datacenter,这将启用 ACL 机制,但也指定了权威数据中心。Consul 凭据 RPC forwarding 来支持多数据中心配 置。但是,由于可以跨数据中心边界进行请求,因此 ACL token 必须全局有效。为了避免一致性问题,单个数据中心被认为是权威的,并存储了标准的 token sets。

当向非授权数据中心服务器中的 agent 发出请求时,必须将其解析为适当的策略。 这是通过从授权服务器读取 token 并将结果缓存到可配置的 acl_ttl 来完成的。缓存的含 义是缓存 TTL 是强制执行的策略的过期的上限。 可以设置 0 值 TTL,但是这会对性能产生不利影响,因为每个请求都需要通过 RPC 调用刷新策略。

Configuring ACLs

ACL 使用几种不同的配置选项进行配置。它们被标记为是否在服务器、客户端或两者中设置。

还有一些与 ACL replication 和 Version 8 ACL support 相关的其他配置项。这些在下面的相应部分中讨论。

还可以配置一些 special(特殊) tokens,允许 bootstrapping(引导) ACL system,或在特殊情况下访问 Consul:

In Consul 0.9.1 and later, the agent ACL tokens can be introduced or updated via the /v1/agent/token API.

Outages and ACL Replication

Consul ACL 系统设计有灵活的规则,以适应 acl_datacenter 的中断或网络问题阻止访问它。 在这种情况下,非授权数据中心中的 server 可能无法解析 token。 Consul 提供了多个可配置的 acl_down_policy 选项来调整行为。 可以拒绝或允许所有操作或忽略缓存 TTL 并进入故障安全模式。 默认值是忽略任何先前解析的 token 的缓存 TTL,并拒绝任何未缓存的 token。

Consul 0.7 添加了一个 ACL 复制功能,可以允许非授权数据中心 server 解决即使是未缓存的 token 。 这通过在非授权数据中心的 server 上的配置中设置 acl_replication_token 来启用。 启用复制后,server 将在非权威 server 上维护权威数据中心的完整 ACL 集副本。 ACL 复制 token 需要是具有管理权限的有效 ACL token,它也可以与主 ACL token 相同。

复制运行在后台进程,大约每 30 秒寻找新的 ACL。 复制的更改以每秒 100 次更新的速率写入,因此可能需要几分钟时间才能执行大量 ACL 的初始同步。

如果存在影响授权数据中心的分区或其他中断,并且 acl_down_policy 设置为 “extend-cache”,那么将使用复制的 ACL 集合在中断期间解析 token。 ACL replicationstatus 可用于监视复制进程的运行状况。

本地解析的 ACL 将使用非权威数据中心的 acl_ttl 设置进行缓存,因此这些条目可能会在高速缓存中保留到 TTL,即使权威数据中心恢复在线后也是如此。

ACL 复制还可以用于将 ACL 从一个数据中心迁移到另一个数据中心,方法如下:

  • 在所有数据中心中启用 ACL 复制,以允许在迁移期间继续服务,并填充目标数据中心。 验证复制是否健康,并使用 ACL replication status 捕获目标数据中心中的当 前 ACL 索引。
  • 关闭旧的权威数据中心 servers
  • 滚动重新启动目标数据中心中的 server,并将 acl_datacenter 配置更改为自身。 这将自动关闭复制,并将使数据中心能够使用之前的复制 ACL 启动作为权威数据中 心。
  • 滚动重新启动其他数据中心中的 server,并将其 acl_datacenter 配置更改为目标数据中心。

Bootstrapping ACLs

在新群集上引导 ACL 需要几个步骤,在本节中的示例中进行了概述。

Step 1:Enable ACLs on the Consul Servers

引导 ACL 的第一步是在 ACL 数据中心的 Consul servers 启用 ACL。

配置示例:

{

"acl_datacenter": "dc1",

"acl_master_token": "b1gs33cr3t",

"acl_default_policy": "deny",

"acl_down_policy": "extend-cache"

}
  • acl_datacenter:对数据中心启用 ACL system
  • acl_master_token:用于引导 ACL system,此 token 将自动创建为 “management” 类型的 token
  • acl_default_policy:启用 whitelist 模式
  • acl_down_policy:确定 ACL 数据中心 offline 要执行的操作

servers 需要重新启动以加载新配置。请注意一次启动一台 server,并确保每台 server 都已加入并正常运行,然后再启动另一台 server。acl_master_token 仅在 server 获得集群 lender 氏角色时才安装。如果您想要安装或更改 acl_master_token,请在所有 servers 的配置中为 acl_master_token 设置新值。一旦完成,重新启动当前 leader 以强制进行 leader 选举。

在 Consul 0.9.1 和更高版本中,您可以使用 /v1/acl/bootstrap API 来创建初始 master token,因此不需要将 token 放置到配置文件中。

一旦引导了 ACL system,就可以通过 ACL API 管理 ACL token。

Step 2:Create an Agent Token

透过 acl_master_token 可以创建拥有各种 ACL rule sets 的 token,将 token 应用于 agent client 端,就可以控制每个 agent 的对 API 的访问控制权限。

# cat acl.token

{

"ID": "e79622eb-5aae-4ce3-b5ad-a200b7107e35",

"Name": "Agent Token",

"Type": "client",

"Rules": "node "" { policy = "write" }nservice "" { policy = "write" }nkey "" { policy = "read" }"

}


[root@c7-Host sample]# curl -s -X PUT -H "X-Consul-Token: LgNnIeUcM0hyNiz/LiSEdA==" http://192.168.251.11:8500/v1/acl/create -d @a cl.token


## 命令返回创建的 token 的 ID

{"ID":"e79622eb-5aae-4ce3-b5ad-a200b7107e35"}

Step 3:Set Tokens for UI Use

启用 ACL 机制后,默认时访问 Consul WebUI 会看不到任何数据。需要在 WebUI 的 settings 设置页面,引入有权限的 Token 后方可查看有权限访问的数据。

Step 4:Enable ACLs on the Consul Clients

# cat /data/consul/config/acl.json

{

"acl_datacenter": "gd2a",

"acl_default_policy": "deny",

"acl_token": "e79622eb-5aae-4ce3-b5ad-a200b7107e35"

}

Rule Specification

ACL 系统的核心部分是用于描述必须实施的策略的规则语言。

  • Key

策略是通过将前缀与策略相耦合来定义。 使用最长前缀匹配策略强制执行规则:Consule 选择可能的最具体的策略。 策略是 “read”、”write” 或 “deny”。 “write” 策略意味着也有 “读”,并且没有办法指定只 write。 如果没有适用的规则,则应用 acl_default_policy。

  • Service

策略通过耦合服务名称和策略来定义。 使用最长前缀匹配策略(这是 0.5 中的完全匹配,但在 0.5.1中更改)强制执行规则。 应用于任何不具有匹配策略的 服务的默认规则是使用空字符串提供的。Service 为 “read”、”write” 或 “deny”。”write” 策略意味着也有 “read”,并且没有办法指定只 write。 如果没有 适用的规则,则应用 acl_default_policy。Service ACL 规则中的 “read” 策略允许限制对该 service 前缀的发现的访问。 有关服务发现和 ACL 的更多信息, 请参见下文。

  • consul" service

策略总是 “write”,因为它是由 Consul 内部管理。

  • Userevent

策略通过将事件名称前缀与策略相结合来定义。使用最长前缀匹配策略强制执行规则。 应用于没有匹配策略的任何用户事件的默认规则由空字符串提供。 事 件策略是 “read”、”write” 或 “deny” 中的一个。 目前,在事件触发期间只实施 “write” 级别。 可以随时读取事件。

  • Prepared query

策略控制对创建、更新和删除 prepared queries 的访问。 在执行 prepared queries 时使用 Service 策略。 有关详细信息,请参阅下文。

我们利用 HashiCorp 配置语言(HCL) 来指定策略。 这种语言是人类可读的,且可与 JSON 互操作,使其易于机器生成。

Specification in the HCL format looks like:

# Default all keys to read-only


key "" {

 policy = "read"

}

key "foo/" {

    policy = "write"

}

key "foo/private/" {

# Deny access to the dir "foo/private"

    policy = "deny"

}

#  Default all services to allow registration.

#  Also permits all services to be discovered. 


service "" {

    policy = "write"

}

#  Deny registration access to services prefixed "secure-".

#  Discovery of the service is still allowed in read mode. 

service "secure-" {

    policy = "read"

}

# Allow firing any user event by default.

event "" {

 policy = "write"

}

# Deny firing events prefixed with "destroy-".

event "destroy-" { 

    policy = "deny"

}

# Default prepared queries to read-only.

query "" {

 policy = "read"

}

# Read-only mode for the encryption keyring by default (list only)

keyring = "read"

# Read-only mode for Consul operator interfaces (list only) 

 operator = "read"

This is equivalent to the following JSON input:



{

"key": {

"": {

"policy": "read"

        },

"foo/": {

"policy": "write"

        },

"foo/private": {

"policy": "deny"

        }

    },

"service": {

"": {

"policy": "write"

        },

"secure-": {

"policy": "read"

        }

    },

"event": {

"": {

"policy": "write"

        },

"destroy-": {

"policy": "deny"

        }

    },

"query": {

"": {

"policy": "read"

        }

    },

"keyring": "read",

"operator": "read"

}

Building ACL Policies

Blacklist Mode and consul exec

如果将 acl_default_policy 设置为 deny,则 anonymous token 将无权读取缺省的 _rexec 前缀。因此,使用 anonymous token 的 consul agent 将无法执行 consul exec 操作。

原因如下:agnet 需要对 _rexec 前缀的读/写权限,以便 consul exec 正常工作。 他们使用该前缀作为大多数数据的传输。

您可以通过允许 anonymous token 访问该前缀,从未配置 token 的 agent 中启用 consul exec。 这可以通过将此规则赋予 anonymous token 来实现:

key "_rexec/" { 

    policy = "write"

}

或者,您当然可以向每个 agent 添加显式 acl_token,使其能够访问该前缀。

Blacklist Mode and Service Discovery

如果 acl_default_policy 设置为 deny,则 anonymous token 将无法读取任何 services 信息。 这将导致 REST API 和 DNS 接口中的 services 发现机制不返回任何 service 查询的结果。 这是因为内部 API 和 DNS 接口使用 RPC 接口,这将过滤 token 无法访问的 service 的结果。

您可以通过为 anonymous token 配置此 ACL 规则,允许发现所有 serivce,模拟 0.6.0 之前发布的行为:

service "" {

 policy = "read"

}

以上将允许仅读取 service 信息的访问。 这种访问级别允许发现系统中的其他 service,但不足以允许 agent 在 anti-entropy 期间同步其 service 和检查全局 catalog。 处理 service 注册和发现的最安全的方法是运行 Consul 0.6+,并发布对显式访问预期在每个 agent 上运行的 service 或 service 前缀的 token。

Blacklist mode and Events

与上述类似,如果您的 acl_default_policy 设置为 deny,那么 anonymous token 将无权访问触发用户事件。 这偏离了 0.6.0 之前的版本,用户事件完全不受限制。 事件在 ACL 语法中有自己的 first-class 表达式。 要从任意 agent 恢复对用户事件的访问,请为 anonymous token 配置如下所示的 ACL 规则:

event "" {

 policy = "write"

}

一如往常,处理用户事件的更安全的方法是根据应该能够触发的事件显式地授予每个 API token 的访问权限。

Blacklist Mode and Prepared Queries

在 consul 0.6.3 之后,对 prepared queries 的 ACL 进行了重大更改,包括新的查询 ACL 策略。 有关详细信息,请参阅下面的 prepared queries。

Blacklist Mode and Keyring Operations

Consul 0.6 及更高版本支持使用 ACL 保护 encryption keyring 操作。 Encryption 是 gossip 的一个可选组件。 有关 Consul 的 keyring operations 的更多信息,可以 在 keyring 命令 文档页面找到。

如果您的 acl_default_policy 设置为 deny,那么 anonymous token 将无法读取或写入 encryption keyring。 Keyring 策略是 ACL 语法中的另一个一等公民。 您可以将 anonymous token 配置为使用以下策略对 Keyring 进行自治管理:

keyring = "write"

Encryption keyring 操作是敏感的,应该妥善保护。 建议不要配置像上面那样的全开策略,而是应用每 token 策略以最大化安全性。

Blacklist Mode and Consul Operator Actions

Consul 0.7 添加了被新的 operator ACL 策略保护的特殊 consule actions。Operator actions 包括:

  • Operator HTTP endpoint
  • Operator CLI command

如果您的 acl_default_policy 设置为 deny,那么 anonymous token 将无权访问 Consul operator actions。 授予 read 访问权限允许读取信息用于诊断目的,而不对状态进行任何更改。 授予 write 访问权限允许读取信息和更改状态。 以下是一个示例策略:

operator = "write"

非常小心地授予对 operator actions 的 write 访问权限,因为不当使用可能导致 Consul 中断,甚至丢失数据。

Services and Checks with ACLs

Consul 允许配置可以控制对 serivce 的访问和 check 注册的 ACL 策略。 为了成功地注册具有这些类型的策略的 service 或 check,必须提供具有足够特权的 token 以执 行到全局目录的注册。 Consul 还执行周期性 anti-entropy 同步,这可能需要 ACL token 来完成。 为了适应这种情况,Consul 提供了两种配置 ACL token 以用于注册事 件的方法:

使用 acl_token 配置指令。 这允许全局配置单个 token,并在所有 service 和 check 注册操作期间使用。

在注册时提供具有 serivce 和 check 定义的 ACL token。 这允许更大的灵活性并且能够在同一 agnet 上使用多个 token。 这种情况的例子可用于 services 和 checks.还可以将 token 传递给 HTTP API 以用于需要它们的操作。

Restricting service discovery with ACLs

在 Consul 0.6 中,ACL 系统被扩展以支持限制对 service 注册的 read 访问。 这允许更严格的访问控制,并限制受损 token 发现群集中运行的其他服务的能力。 如果在请求期间使用的 token 具有 “read” 级别访问权限或更大权限,ACL 系统允许用户使用 REST API 或 UI 发现 service。 Consul 将过滤出所有 service,token 在所

有 API 查询中无法访问,使其看起来好像受限 service 不存在。

Consul 的 DNS 接口也受到 serivce 注册的限制的影响。 如果 agnet 使用的 token 无法访问给定的 service,则 DNS 接口在查询时将不返回任何记录。

Prepared Query ACLs

由于我们收到了 Consule 用户的反馈,我们已经演变了如何在 prepared queries 使用 ACL。

在本节中,我们首先介绍当前的实现,然后我们将详细了解具体的 Consul 版本之间的变化。

Managing Prepared Queries

管理 Prepared Queries 包括创建、读取、更新和删除查询。 有一些变化,其中每个都使用以下两种方式之一的 ACL:打开,受无法验证的 ID 保护或关闭,由 ACL 策略管 理。 这些变化在这里,例子:

  • 未定义 Name 的 Static queries 不受任何 ACL 策略控制。 这些类型的 queries 意味着是短暂的,并且不共享给不受信任的 clients,并且它们只有在 prepared query 的 ID 是已知的时才可到达。 由于这些 ID 是使用与 ACL token 相同的随机 ID 方案生成的,因此不可能猜测它们。 列出所有 prepared query,只有 management token才能看到这些类型,尽管 client 可以读取具有 ID 的实例。 此类型的示例用法是由启动脚本创建的 queries ,绑定到 session,并写入配置文 件以供通过 DNS 使用的进程。
  • 定义了 Name 的 Static queries 由 query ACL 策略控制。 客户端必须具有前缀足以涵盖其尝试管理的名称的 ACL token,其中最长的前缀匹配提供了定义更具体策 略的方法。 client 可以列出或读取基于其前缀具有 “read” 访问权限的 queries 。类似的,他们可以更新他们具有 “write” 访问权限的任何 queries 。 此类型的示例 使用是具有众所周知名称的 queries (例如,prod-master-customer-db),其被许多 client 使用和知晓以为数据库提供地理故障转移行为。
  • Template queries queries 的工作方式与定义了名称的 Static queries 类似,只是具有空名称的全部捕获模板需要可以写入任何查询前缀的 ACL token 。

Executing Pepared Queries

当 prepared queries 通过 DNS 查找或 HTTP 请求执行时,ACL 检查针对正在查询的 service 运行,类似于 ACL 如何与其他 service 查找一起工作。 有几种方式为此检 查选择 ACL token:

  • 如果在定义 prepared query 时捕获到 ACL token,则它将用于执行 service 查找。 这允许由具有较少或甚至没有 ACL token 的 client 执行 queries ,因此应该谨 慎使用。
  • 如果没有捕获 ACL token,则 client 的 ACL token 将用于执行 service 查找。
  • 如果没有捕获 ACL token,并且 cleint 没有ACL token ,则 anonymous token 将用于执行 serivice 查找。

在通常情况下,调用器的 ACL token 用于测试查找 service 的能力。 如果在创建 prepared query 时指定了 token,则行为会更改,现在由 query 的定义器设置的捕获的ACL token 在查找 service 时使用。

捕获 ACL token 类似于 PostgreSQL 的 SECURITY DEFINER 属性,它可以在函数上设置,并且使用 clinet 的 ACL token 类似于补充的 SECURITY INVOKER 属性。

ACL Implementation Changes for Prepared Queries

Prepared queries 最初在 Consul 0.6.0 中引入,ACL 行为一直到版本 0.6.3 保持不变,但随后更改为允许更好地管理 prepared query namespace。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>