微服务之服务调用与安全控制

引言:

近年来,大多数企业IT软件均在向微服务架构转型,由于微服务架构采用了更细粒度的分布式拆分,对于服务调用安全方面的问题更复杂,更需要重视,需要整体的系统化解决方案。本文将分享普元EOS8.0版本的服务调用安全控制方案,希望能够对需要搭建微服务平台的企业和人员能够带来一些启发和帮助。

一、微服务平台架构简介

EOS8 微服务平台功能架构图

普元8月份发布了EOS8微服务平台,上图为功能架构图。平台提供了微服务开发测试、运行容器、公共服务以及管理监控等较为完善的工具套件,用以支撑企业级的It系统微服务架构落地。

微服务平台运行视图

这是微服务平台的一个简化版的运行视图,比照这张图,我们先一起理解并统一下概念术语,这里的术语解释不一定是业界共识,仅作为今天分享内容上下文中的一个定义对大家理解分享内容来说非常重要。

:从物理部署角度看,指微服务业务系统的基础运行环境,可以支持多个系统再域内运行监控和管理,即一个域部署一套微服务基础环境即可。从逻辑角度看,域常与业务或组织划分有所关联,可根据实际需求定义。

系统:即传统意义上的业务系统。微服务架构模式下,一个系统包含一个或者多个微服务。

应用:特指拆分后的 “微服务”。微服务架构模式下,系统按业务特点拆分成多个微服务,为避免“服务”这个词的使用混乱,我们这里将系统拆分后的微服务称作“应用”。

服务:特指API,即应用或网关发布和开放的对外接口。

网关:系统服务对外开放的服务门户。网关为客户端提供服务,作为服务出口屏蔽服务端实现。对于服务端来说,网关是所有外部请求的入口,提供安全认证、管理监控和服务编排等增强能力。

二、服务调用场景分析

服务调用场景的简单分解结果

运行视图

结合两图分析,我们推荐的服务调用模式:“跨系统调用走网关,系统内部直接调用”,优缺点分析如下:

跨系统调用走网关,网关作为请求的入口,可以为开发的服务提供很多增强的能力,如安全认证、流控、动态路由等等能力。网关作为系统服务的统一出口,可以屏蔽服务的实现。让客户端使用更简单。

如果跨系统不通过网关的话,类似服务安全控制、流控、降级这部分能力在网关、应用两端均需要重复建设。多种方式融合时,控制会非常混乱。

系统内部通常是一个项目团队,网关通常是不同的团队维护,系统开发期沟通交互多,应用间直接依赖SDK调用相比到网关发布再调用来说更方便。

系统内部调用的服务接口范围通常与给外部系统开放的服务接口范围不一致,如果都通过网关发布,工作量增多、安全控制方面的个性化需求多,管理复杂。

这张运行视图,注重标注出来了几个服务调用场景的关系。

①:表示用户通过系统前端UI访问后端应用的服务

②:表示系统内部,多个后端应用之间的服务调用

③:表示跨系统调用。由于空间有限,每个域只画了一个系统,所以图中所示的跨系统调用同时也跨了域。如果是域内跨系统服务调用,则需要调用本域网关发布的服务

④:表示与内部的网关,将外部请求路由到域内应用的服务调用

服务调用的过程中一定会存在服务提供者和消费者两个角色,划分如下:

应用”既提供服务又消费服务,所以兼有两个角色很好理解。

用户”通常是IT系统的使用者自然划入消费者角色。

网关”比较特殊,在服务调用过程中,主要任务是中介。由于系统必须通过网关才能向外提供服务,且此时网关在中介的基础上又会提供一些重要的增值能力如流控、路由、监控等,因此我们也把网关划入服务提供者角色。而对于真正的服务提供者“应用”来说,他会收到网关路由过来的服务调用请求,那么从这个角度,网关也可以算是带点消费者的特点,算半个消费者。

服务的调用过程即服务发布与消费的过程,一次调用通常也被称作“交易”,而信任是交易完成的前提,因此服务提供者和消费者之间需要建立信任。在我们的服务调用场景中,建立信任实际就是服务提供者对消费者的身份进行认证,认证通过后即成功建立信任,进一步需要进行鉴权,让交易在一个可信可控的范围内进行。

那么在上述这四个服务调用的场景中,均需要做服务安全认证与鉴权。

认证:目标是检查消费者是否可信,一般可以由提供者自己检查或委托第三方认证中心检查。

1、用户认证,使用“用户令牌”检查用户是否登录

2、系统内服务调用认证,使用“应用令牌”检查是否本系统应用

3、跨系统服务调用认证,使用“API令牌”检查是否已经订阅过服务

4、可信网关认证,使用“网关令牌”检查请求是否来自本域的网关

鉴权:目标是对可信任的消费者的权限范围进行检查和控制

1、网关检查应用可访问的API范围,并进行流控、路由等控制

2、应用检查用户功能权限,数据权限

其中①属于用户认证,用户认证在之前的统一认证中心中已经做过详细介绍,本文就不再讲解。后续内容我们主要对②③④几个部分的服务调用与安全控制方案进行说明。

三、服务发布过程介绍

面向系统内部发布服务:

  • 对系统内发布,指将服务开放给系统内其他应用访问
  • 基于Spring MVC能力发布RESTful服务接口映射
  • 基于Feign封装后的SDK提供给其他应用做服务调用依赖
  • 基于Swagger设计API Doc

面向系统外部发布服务:

  • 对系统外发布,指通过API Gateway 将已发布的RESTful API 向外部系统开放
  • 发布时支持API分组
  • 发布时支持API流控、路由等控制策略设置

介绍系统内部服务发布之前,先来看一下我们推荐的后端应用的设计方案

后端应用设计

对于系统内后端应用的设计,推荐以下几个设计原则:

1、服务设计与服务实现解耦

2、应用API设计先行,内部模块Lib化

3、系统内应用之间服务调用,采用SDK依赖RPC调用模式

基于上述原则,后端应用项目结构推荐如下:

系统内服务发布

基于后端应用的设计原则,服务规格均需要在API模块进行定义,平台支持向导或手工两种方式通过注解发布服务,使用到的组件和注解简要说明如下:

Spring MVC 注解:主要用来定义RESTFul 服务的URI映射关系。常用注解包含:@RequestMapping @GetMapping @PostMapping @PutMapping @DeleteMapping @PatchMapping @PathVariable @RequestParam @RequestBody等等

Tarest注解:此注解来自EOS平台的服务发布调用模块Tarest ,作用是对服务发布和消费SDK进行定义。结合Feign框架提供远程模拟本地调用的SDK,以及结合Coframe框架做用户访问权限控制。服务发布时使用的注解有两个@TarestService @TarestOperation。 服务发布成功后,可以通过管理平台应用查看应用已发布服务列表

Swagger注解:用来定义服务的规格并生成接口文档。常用注解包含:@Api @ApiOperation,基于Swagger规范的服务规格文件除了用来生成文档之外,一个更重要的作用就是可以在服务编排中使用,对于一个RESTFul 接口来说,规格文件就相当于 WebService接口的WSDL文件一样重要

系统内服务发布:示例代码

@RequestMapping("/say-hello")
@TarestService(group="group1",version="v1",name="SayHelloService")
@Api(value="com.eos.consumer.app.api.ISampleAppHello")
public interface ISampleAppHello { 
 
    @GetMapping
    @TarestOperation(name="sayHello")
    @ApiOperation(value="sayhello",nickname="Hello World !")
    String sayHello();  
  
    @GetMapping("/{user}")
    @TarestOperation(name="sayHelloToUser")
    @ApiOperation(value="sayHelloToUser", nickname="Hello {user} !")
    String sayHello(@PathVariable("user") String user);
    
}

(左右滑动可查阅全部)

上述接口设计代码示例中,使用了由Spring、Swagger以及EOS提供的三类注解,来自不同框架解决不同问题的三部分注解目前看上去比较繁琐且容易出错,因此EOS平台会提供接口设计的向导工具,用以生成上述的接口代码和服务规格Swagger文件,尽量避免纯手工编写,提升应用开发效率。

系统外服务发布:动态路由、精准路由两种发布模式

动态路由发布

  • 不指定具体的API,基于Base URL模糊匹配的方式发布服务
  • 优点是统一控制权限,可动态增加路由,操作简单方便
  • 缺点是无法获取明确的服务列表,控制策略影响范围大

精准路由发布

  • 精确到一个具体API的Method,逐个发布
  • 优点是可以精确控制权限,可提供明确的服务列表
  • 缺点是新增发布时,权限、分组、服务策略等均需定义

动态路由发布服务是绝大部分网关均需要支持的能力,通常适合批量服务穿透式向外发布的场景。

另外一些特殊的场景下比如,需要协议、报文转换或者权限特殊控制的服务来说,就需要更细粒度的服务发布能力。

我们在动态路由的基础之上,实现了API的更细粒度的控制和路由策略绑定。

系统外服务发布:精确发布示例

通过网关向系统外部发布接口,可配置请求、响应方式以及报文转换规则

四、服务消费与认证安全

服务消费的方案

系统内应用间服务直接调用

  • 采用SDK依赖,类RPC方式调用其他应用的服务, EOS平台采用了基于Feign的实现方式
  • 系统内应用间调用互信,采用对称加解密请求令牌方式实现

跨系统服务调用必须经过网关中转

  • 网关是系统向外提供服务的渠道,也是接收外部服务请求的入口。需要为系统提供认证、流控、路由、监控等相关服务治理能力
  • 消费者需要先订阅目标网关上开放的服务才能调用,网关需要对消费者进行身份认证。EOS 8 中API 网关自行颁发API令牌并自带认证能力
  • 服务提供者与当前域的网关之间也需要有身份识别,确保安全可靠。EOS 8 平台采用非对称加密证书请求令牌方式实现网关与系统的互信

系统内服务消费

1、依赖SDK

 <dependency>
            <groupId>com.eos.sample</groupId>
            <artifactId>sample-app-api</artifactId>
            <version>0.0.1-SNAPSHOT</version>
  </dependency>

2、声明服务消费

@TarestClient(name="sample-app",path="",fallback=SampleAppServiceClientFallback.class)
public interface ISampleAppServiceClient extends ISampleAppHello {}

(左右滑动可查阅全部)

3、类本地方式调用服务

@RestController
public class ServiceDemo implements ITestServiceDemo{
    @Autowired
    ISampleAppServiceClient client ;//自动注入TarestClient注解声明的消费服务
    @Override
    public String invokeDemo(String user) {
        return client.sayHello(user);
    }
}

(左右滑动可查阅全部)

服务消费声明的过程除了上述示例中的编写代码注解声明之外,还可以通过开发工具向导进行服务消费配置化声明。

系统内服务认证:如何识别本系统内部的其他应用?

系统内服务认证

应用端需配置本系统的内部认证秘钥,采用对称加解密的方式,发送和验证“应用令牌”

跨系统服务认证与消费:消费者订阅服务,网关识别消费者身份

  • 消费者从网关订阅服务,消费服务时需要带”API 令牌”:访问网关服务
  • 网关检查消费者请求的令牌是否合法以及API范围是否超限

消费网关发布的服务:HTTP头中带API令牌示例代码

public class GatewayServiceConsumeDemo {  
  
    public static void main(String[] args) {
        RestTemplate restTemplate = new RestTemplate();
        UserInfo user = new UserInfo();
        user.setUsername("tiger");
        user.setNickname("Tiger");
        RequestEntity<UserInfo> requestEntity;
        try {
            //网关服务地址,示例为模拟Post方法创建一个用户对象
            requestEntity = RequestEntity.post(new URI("http://gateway.com/api/users")) 
                    .header("access_token", "12b839e2-399e-4dfc-a50e-e00771184c79")   //设置api令牌头
                    .contentType(MediaType.APPLICATION_JSON)
                    .accept(MediaType.APPLICATION_JSON).body(user);
            ResponseEntity<UserInfo> responseEntity = restTemplate.exchange(requestEntity, UserInfo.class);           
           
            if (!responseEntity.getStatusCode().is2xxSuccessful()) {
                HttpErrorStatus.valueOf(responseEntity.getStatusCodeValue()).exception();
            }
        
            UserInfo createdUserInfo = responseEntity.getBody();
            System.out.println(createdUserInfo);
            
           } catch (URISyntaxException e) {
           e.printStackTrace();
        }
    }
}

(左右滑动可查阅全部)

网关与服务提供端认证:服务提供端如何识别网关身份?

1、网关安装启动前,通过工具生成公私钥

2、运行期网关进行服务路由转发时,利用私钥签名,生成网关令牌

3、应用从本域内的网关获取公钥,并将公钥配置到服务提供端配置文件中

4、运行期收到来自网关的服务请求时,使用公钥验证“网关令牌”是否合法

五、服务访问控制

网关对服务请求的控制

网关控制服务访问

  • 流控,流量、IP、并发数控制
  • 服务分组路由,升、降级等控制

网关负责对于来自外部的服务请求需要进行统一的控制与路由。如:流量控制、IP控制黑白名单、服务并发请求控制等等。还可以通过动态服务路由调整来达到服务请求的升降机,提升系统运行的可靠性。

应用对服务访问的控制

应用端控制用户服务权限范围

  • 功能权限,接口调用范围
  • 数据权限,数据访问范围

应用间服务调用时通常需要传递用户上下文,在某些场景中,即使应用认证通过,仍需控制应用的API访问权限和数据权限。

我们提供了应服务功能权限的控制,用以控制用户角色与API的访问关系。运行时,对这些服务方法进行拦截,检查用户权限。

对于数据权限控制,目前仍需要开发者自行扩展实现,比如利用AOP模式进行拦截某些方法控制数据访问。

回顾总结:


本文主要对服务的消费者和提供者之间的调用关系进行了梳理,以普元的EOS8平台已落地的方案实现为基础,从服务调用场景入手,着重讲后端服务调用,按系统内外分为两个部分,分别对服务发布、消费、认证方式以及控制方案进行了说明,希望能给大家进行微服务架构升级改造或者平台建设带来一些帮助。

精选提问:

问1:微服务平台都投入在哪些生产系统,想了解一下微服务网关实现,并发性能怎么样?

答:目前我知道的使用EOS8 平台的客户有邮储银行、邮政银行、太保、国电投、成飞等等企业,具体业务也是各式各样的。 网关底层也是基于Spring Cloud 结合Zuul、Ribbon等框架实现。并发性能不错,但我手头还没有具体数据。

问2:流量控制,服务路由具体是怎么实现的呢?有没有相关解决方案。

答:流量控制就是再网关层面做了流量计数,对服务API的访问次数进行控制,通常可以按照 天、小时、分钟等单位进行控制。服务路由,在网关上发布一个API服务的时候,需要绑定路由策略,比如不同分组或版本的API 路由到某几个服务提供者上。 内部路由实现集成了Zuul组件,并扩展了细粒度路由能力。

问3:请问服务发布有个注解targetservice是rpc模式吗?

答:TarestService是我们自定义的注解,主要用来统计服务提供和消费的。系统内部rpc模式指的是采用本地java代码的方式,调用远端的restful api调用。核心能力是SpringCloud Feign组件提供的,Tarest 是对Feign组件的封装,在Feign的基础上,增加了配置化声明服务消费、提供端拦截认证相关能力。

问4:请问网关如果要支持协议转换,有没有推荐的方案?

答:对于网关支持协议转换我觉得好的方案是需要在网关增加服务编排能力,通常服务编排需要提供服务的组装、协议转换、事务管理等。简单点做就是服务接入后可以配置消息处理拦截器,拦截器进行协议转换后,再路由到服务提供者。

原文发布于微信公众号 - EAWorld(eaworld)

原文发表时间:2018-11-02

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏腾讯移动品质中心TMQ的专栏

移动H5性能测试平台解决方案

1 平台的目的 说到H5性能测试,大家想到最多的是在PC端利用Firebug、Fiddle和HttpWatch等工具进行测试和性能指标的分析,但是如果我们测试的...

30150
来自专栏Java架构师学习

阿里首席架构师科普RPC框架

RPC概念及分类 RPC全称为Remote Procedure Call,翻译过来为“远程过程调用”。目前,主流的平台中都支持各种远程调用技术,以满足分布式系...

27520
来自专栏ChaMd5安全团队

【荐】Web Application Penetration Testing中文译作

(英文原版地址:https://www.exploit-db.com/docs/english/44319-web-application-security-t...

17240
来自专栏沃趣科技

Shell Limits设置问题导致用户不能登录

发生故障的环境为:RHEL 6.7,ORACLE 11gR2 RAC,其中集群节点1发生此故障,而节点2状态正常。

13120
来自专栏腾讯移动品质中心TMQ的专栏

常用流量测试方法及一些思考

App性能测试中流量测试是其中重要的一项,网络场景(wifi、非wifi)、用户使用场景(页面加载流量、场景使用流量、待机流量),这些都是需要考虑的测试点。

55950
来自专栏逸鹏说道

Web Api 入门实战 (快速入门+工具使用+不依赖IIS)

平台之大势何人能挡? 带着你的Net飞奔吧!:http://www.cnblogs.com/dunitian/p/4822808.html 屁话我也就不多说了,...

36650
来自专栏ThoughtWorks

登录工程:传统 Web 应用中的身份验证技术|洞见

标题中的 “传统Web应用” 这一说法并没有什么官方定义,只是为了与“现代化Web应用”做比较而自拟的一个概念。 所谓“现代化Web应用”指的是那些基于分布式架...

42450
来自专栏ImportSource

消费者驱动的微服务契约测试套件Spring Cloud Contract

在微服务架构下,你的服务可能由不同的团队提供和维护,在这种情况下,接口的开发和维护可能会带来一些问题,比如服务端调整架构或接口调整而对消费者不透明,导致接口调用...

426120
来自专栏CodingToDie

分布式事务解决方案

Spring Cloud 分布式事务管理 在微服务如火如荼的情况下,越来越多的项目开始尝试改造成微服务架构,微服务即带来了项目开发的方便性,又提高了运维难度以及...

67050
来自专栏做全栈攻城狮

Python教程:操作数据库,MySql的安装详解

本教程是基于Python语言的深入学习。本次主要介绍MySql数据库软件的安装。不限制语言语法,对MySql数据库安装有疑惑的各位同仁都可以查看一下。

13820

扫码关注云+社区

领取腾讯云代金券