Consul作为一款分布式、高可用的服务发现和配置的工具,提供了丰富的组件功能,被广泛应用于微服务架构中作为服务注册与配置中心。
本文从consul提供的ACL访问控制策略角度出发,详细介绍通过在应用层使用标签前缀的方式,分配访问控制权限,实现基于标签隔离的社区版consul多租户隔离,从而作为公共注册中心。
一、Consul产品介绍
Consul作为一款开源的组件工具,其使用GO语言开发,实现分布式系统的服务发现与配置,主要提供分布式服务注册和发现、健康检查、Key/Value数据存储、多数据中心的高可用性等能力。
【服务注册与发现】
consul client(客户端)使用HTTP或DNS的方式将服务注册到consul server(服务端)注册中心中。服务请求方通过consul server发现他所依赖的服务。
【健康检查】
consul client提供对应用程序健康检查机制,并将健康检查状态上报给consul server集群,用来监控集群节点的运行状况,并及时下线不健康的节点。
【Key/Value数据存储】
Consul提供K/V的存储功能,应用程序可以根据需要使用consul层级的Key/Value存储,比如用来保存动态配置,协调服务等等。
【多数据中心】
Consul支持多个数据中心,满足用户的多中心部署模式和灾备需求。
二、Consul基本架构
Consul是一个分布式,高可用的系统,在consul集群中的每个节点都运行一个agent,agent可以以客户端(client)模式或服务端(server)模式运行。
图1 Consul基本架构图
【数据中心(DataCenter)】
在consul数据中心中,集群中节点分为server节点和client节点,为了保证可用性和高性能,通常一个数据中心内为3-5个服务器。
【客户端模式(Client)】
客户端节点一般和应用部署在一起,负责注册服务、运行健康检查并将相关RPC转发给服务器。在微服务应用中,本地应用只访问client,由client和server进行通讯,实现集群的服务发现。
【服务器模式(Server)】
服务端节点维护consul集群的状态信息,并进行持久化,server节点存储公共信息,包括服务信息,K/V数据等。consul集群中的Server节点参与选举,响应RPC查询,转发信息给Leader(领导者),Leader除了包含server的功能外,还负责同步数据到各个server,每一个集群中只能有一个Leader,保证集群内数据一致。
三、Consul多租户隔离
在使用consul作为注册及配置中心的过程中,多个微服务架构系统需要每个系统分别部署一套consul集群,运维成本高且存在资源浪费,于是将consul服务作为PaaS能力提供,租户制使用便成为一种美好愿望。
社区版本不支持namespace隔离特性,多个系统共用一个注册和配置中心,需要防止出现写时配置相互覆盖,读时信息泄露等问题。因此,各系统在进行服务发现获取服务列表和配置信息修改等操作时,只能对本系统进行访问和操作,不能对其他系统的服务进行访问。
Consul在应用层唯一的鉴权能力是ACL机制,能否借此可以实现多租户访问权限的控制目的?
1.ACL机制
Consuls支持AccessControlList(ACL-即访问控制列表),用于保护对UI、API、CLI、服务和代理通信的访问。通过开启consul集群ACL机制,对consul执行任何的操作,需要得到对应的令牌,即ACLToken,以此来实现对consul集群agent、服务注册和发现、K/V数据的访问权限控制。
ACL的核心是以token作为身份认证,将一系列规则(rule)组成策略(policy),然后将一个或多个策略与令牌token进行相关联。在应用请求时,在其HTTP头中添加X-Consul-Token为分配的token,应用的服务注册、发现和配置更新等操作,server会根据token策略权限返回相应的服务内容以及校验是否有对应的配置资源读写权限。
图2 ACL机制运行核心
配置步骤:
(1)首先在consulserver集群的启动参数中添加配置,开启集群对ACL的校验。
{
...
acl= {
enabled= true,
default_policy= "deny",
enable_token_persistence= true }
}
(2)然后再创建policy,每个policy是由多个rule组成。policy格式为:
#rule:节点前缀为空,代表所有的节点都使用策略;
node_prefix""{
policy=’write/read/deny’
}
#rule:服务前缀为空,代表所有的服务都使用策略;
service_prefix""{
policy=’write/read/deny’’
}
#rule:key前缀为空,代表所有对所有key都使用策略;
key_prefix""{
policy=’write/read/deny’’
}
(3)最后创建token,并和policy绑定。
2.租户隔离
Rule是以关键字前缀作为过滤条件,这样可以统一分配权限。因此,可以每个租户的节点名称,服务名称,配置名称统一以租户名称为前置,然后每个租户分配一个token。在配置rule时,都只以租户名称作为前缀。这样就可以实现租户间资源隔离。
例如租户A的名称是:“SystemA”,租户A的相关资源命名都以SystemA为前缀:
- 节点名称:SystemA-ip,如SystemA-192.168.0.108
- 服务名称:SystemA-微服务名称,如SystemA-UserService
- 配置路径:config/SystemA-配置名称,如config/SystemA-public,config/SystemA-UserService
租户A的token绑定的policy策略为(默认策略为deny):
#代表SystemA前缀节点都使用该策略;
node_prefix"SystemA" {
policy="write"
}
#代表代表SystemA服务都使用该策略;
service_prefix"SystemA" {
policy="write"
}
#代表以config/SystemA开头的key都使用该策略;
key_prefix"config/SystemA" {
policy="write"
}
以此policy策略关联的token,其应用只能注册以“SystemA”开头的节点和服务,以及发现以“SystemA”标签为前缀的服务,并对“config/SystemA”为开头的key的配置信息进行编辑和修改。
四、总结
通过以统一租户名称为前置的资源命名管理+Consul产品ACL的方式,可以达到租户间资源访问隔离的效果。通过这种手段,可以将consul产品作为PaaS能力提供服务,丰富云原生生态。