论微服务安全

每一个人都在讨论微服务,每一个人也都但愿可以实现微服务架构,而微服务安全也日渐成为你们关注的重要问题。今天小数与你们分享的文章,就从应用层面深刻探讨了应对微服务安全挑战的方案,为微服务安全提供了新的思路。缓存

面向服务架构(简称SOA)引入了一类设计规范,其核心思路在于采用高度解耦式服务部署,其中各项服务可经过一套标准信息格式经由网络实现彼此通讯。这套方案与具体技术无关,即不考虑各项服务具体是如何实现的。每项服务都拥有一个明肯定义,用于发布服务描述或者服务接口。在实践当中,这类信息格式经过SOAP实现标准化——即由W3C于2000年初推出的一项标准——同时亦基于XML——其中服务描述由WSDL(另外一项W3C标准)进行标准化,而服务发现标准由UDDI(一样为W3C标准)实现。这一切正是基于SOAP的Web服务的实现基础,甚至使得Web服务在必定程度上成了SOA的代名词。不过这种实现方式在架构模式层面也有着本身的缺陷。SOA的基本原则正被时代所逐步淘汰,现在由OASIS提供的WS-*堆栈(包括WS-Security, WS-Policy, WS-Security Policy,WS-Trust, WS-Federation, WS-Secure Conversation, WS-Reliable Messaging, WS-Atomic Transactions, WS-BPEL等等)令SOA的复杂性不断提升,这也直接致使不少普通开发者发现本身很难对其加以驾驭。安全

多年以后,现在咱们得以再次开启这段通往SOA基本原则的旅途——但这一次它有了新的名号,即微服务。微服务可以为应用程序设计提供一种更具针对性、范围性与模块性的实现方案。服务器

微服务可谓当下一大热门词汇之一,与之并驾齐驱的则包括物联网、容器化与区块链。“微服务”一词最初于2011年5月亮相于威尼斯软件架构师研讨会。这个词汇用于解释一类常见的架构类型。网络

你们已经意识到微服务并不只仅是作对了的SOA,它也不仅是一种架构模式——而是一种围绕架构模式展开的全新文化。其由主要目标做为驱动力,旨在实现快速部署与快速生产。架构

在保护微服务安全时,须要从如下几个角度入手:框架

  • 保护开发生命周期与测试自动化机制:微服务背后的核心驱动力在于提高投付生产的速度。咱们须要向服务当中引入变动,加以测试然后当即将成果部署至生产环境。为了确保在代码层面中不存在安全漏洞,咱们须要制定规划以进行静态代码分析与动态测试——更重要的是,这些测试应当成为持续交付流程的组成部分。任何安全漏洞都须要在早期开发周期内被发现,另外反馈周期也必须尽量获得缩短。分布式

  • DevOps安全:微服务部署模式可谓多种多样——但其中使用最为普遍的当数每主机服务模式。其中的主机指定的并不必定是物理设备——也极可能属于容器(Docker)。咱们须要对容器层面的安全进行关注。咱们该如何确保各容器之间获得有效隔离,又该在容器与主机操做系统之间采起怎样的隔离水平?ide

  • 应用级别安全:咱们该如何验证用户身份并对其微服务访问操做进行控制,又要怎样保障不一样微服务之间的通讯安全?微服务

在今天的文章中,咱们将提供一整套安全模式,旨在解决应用层级所面临的各种微服务安全保护挑战。性能

单体应用VS微服务

在总体型应用程序中,全部服务都被部署在同一应用服务器当中,而该应用服务器自己则提供会话管理功能。其中不一样服务间的接口为本地调用,且所有服务皆可共享用户的逻辑状态。每项服务(或者组件)不须要对用户进行验证。验证工做集中由拦截器处理,其拦截全部服务调用并审查其是否能够放行。验证完成以后,其会在不一样平台上的不一样服务(或者组件)间发送用户登陆凭证。如下示意图解释了总体应用程序中各不一样组件间的交互方式。

图片描述

在Java EE环境下,拦截器能够由servlet过滤器充当。该servlet过滤器会拦截所有来自其已注册上下文的请求,并强制进行验证。该服务调用要么携带有效的凭证,要么拥有可以映射至某个用户的会话令牌。一旦servlet过滤器找到该用户,则会建立登陆上下文,并将其传递给下游组件。每一个下游组件都可以从该登陆上下文内识别出用户以完成受权。

在微服务环境下,安全性每每成为最大的挑战。在微服务架构当中,各服务分布及部署在分布式设置当中的多套容器以内。各服务接口再也不存在于本地,而是经过HTTP进行远程接入。如下示意图显示了不一样微服务之间的交互方式。

图片描述

这里的挑战在于,咱们要如何验证用户并在不一样微服务之间以对称方式完成登陆上下文传递,随后还要想办法让微服务完成对用户的受权。

保护服务到服务通讯

在今天的文章中,咱们将探讨两套方案,旨在保护服务到服务通讯。其一基于JWT,其二则基于TLS相互验证。

JSON Web令牌(简称JWT)

图片描述

JWT(即JSON Web令牌)负责定义一套容器,旨在完成各方之间的数据传输。其可用于:

  • 在各方之间传播其中一方的身份。

  • 在各方之间传播用户权利。

  • 经过非安全通道在各方之间安全实现数据传输。

  • 根据JWT受信指标判断用户身份。

已签名JWT被称为JWS(即JSON Web签名),而加密JWT则被称为JWE(即JSON Web加密)。事实上,JWT并不会以自身原始方式存在——其要么做为JWS,要么做为JWE,它像是一种抽象类——JWS与JWE为其具体实现方式。

来自某一微服务并将被传递至另外一微服务的用户上下文可伴随JWS一同传递。因为JWS由上游微服务的某一已知密钥进行签名,所以JWS会同时包含有最终用户身份(在JWT中声明)以及上游微服务身份(经过签名实现)。为了接收JWS,下游微服务首先须要根据JWS自己中的嵌入公钥对JWS的签名进行验证。这还不够,咱们还须要检查该密钥是否受信。不一样微服务之间可经过多种方式创建受信关系。其一为由服务为各服务配置受信证书。很明显,这种方式在规模化微服务部署环境中并不可行。所以我建议你们创建一套专有证书中心(简称CA),同时能够为不一样微服务组设置中介证书中心。如今,相较于互相信任及各自分配不一样的证书,下游微服务将只须要信任根证书受权或者中介机制便可。这可以显著下降证书配置所带来的管理负担。

JWT验证的成本

每项微服务都须要承担JWT验证成本,其中还包含用于验证令牌签名的加密操做。微服务层级中的JWT会进行缓存,而非每次进行数据提取,这就下降了重复令牌验证形成的性能影响。缓存过时时间必须与JWT的到期时间相匹配。正是因为利用这种机制,所以若是JWT的过时时间设定得过短,则会给缓存性能形成严重影响。

验证用户

JWT在其声明集中包含一项参数,名为sub,其表明拥有该JWT的主体或者用户。JWT自己也能够包含各种用户属性,例如first_name、last_name、email等等。若是任何微服务须要在其操做过程当中识别此用户,则须要查看对应的属性。Sub属性的值对于给定发行者而言是唯一的。若是你们拥有一项微服务,其可以从多个发行者处接收令牌,那么该用户的唯一性应被认定为该发行者与sub属性的结合体。

而aud参数一样存在于JWT声明集内,负责指定令牌的目标受众。其能够是单个接收者或者是一组接收者。在执行任何验证检查以前,该令牌接收者都必须首先查看是否发布了特定JWT供其使用,若是没有则当即拒绝。令牌发送方须要在发出令牌以前,肯定该令牌实际接收者的身份,同时aud参数值必须属于令牌发送方与接收方间预先约定的值。在微服务环境中,咱们能够利用正规表达式来验证令牌受众。举例来讲,令牌中的aud值能够为*.facilelogin.com,意味着facilelogin.com域名下的每一个接收方(例如foo.facilelogin.com,bar.facilelogin.com等)都可以拥有本身的aud值。

TLS相互身份验证

在TLS相互验证与JWT方法当中,每项微服务都须要拥有本身的证书。这两种方法的区别在于,JWT验证机制中JWS可同时携带最终用户身份以及上游服务身份。而TLS相互验证则只在应用层传输最终用户身份。

证书吊销

在以上提到的两种方案当中,证书吊销都是项棘手的任务。证书吊销尽管难以实现,但仍然存在多种选项供咱们选择:

  • CRL (证书吊销列表 / RFC 2459)

  • OCSP (在线证书状态协议 / RFC 2560)

  • OCSP Stapling (RFC 6066)

  • OCSP Stapling Required (尚处于草案阶段)

CRL的使用频率并不高。客户端在发起TLS握手时,必须从对应的证书颁发中心处获取一份长长的吊销证书列表,然后检查服务器证书是否被列入该列表。相较于每一次进行列表获取,客户端能够在本地对CRL进行缓存。在此以后,你们还须要考虑如何避免以陈旧数据为基础作出判断的问题。当TLS相互验证机制被使用时,服务器也须要针对客户端进行一样的证书验证。最终,人们发现CRL的实际效果其实并不理想,所以新的解决方案也应运而生——这就是OCSP。

在OCSP当中,一切元素的实际效果都要比CRL好上那么一点。TLS客户端可以检查特定证书的状态,且无需从证书中心处下载完整的吊销证书列表。换句话来讲,当客户端每次与新的下游微服务进行通讯时,其都必须同对应的OCSP响应方沟通以验证当前服务器(或者服务)的证书状态——而服务器则必须面向客户端证书执行一样的操做。如此一来,OCSP响应方一样面临着巨大的流量压力。基于一样的考虑,客户端仍然能够对OCSP决策进行缓存,但这无疑继续带来一样的、基于陈旧数据进行决策的可能性。

而OCSP stapling的出现令客户端再也不须要每次同下游微服务进行通讯时,都与OCSP响应方“打招呼”。该下游微服务将从对应的OCSP响应方处获取OCSP响应,以及staple,或者将响应附加到证书自己当中。因为OCSP响应获得了对应证书中心的签名,所以该客户端可以验证经过其签名并接收此响应。这种方法令事情有了起色,事实上现在是由服务而非客户端与OCSP响应方进行通讯。不过在TLS相互验证模式下,OCSP stapling相较于原始OCSP没法带来任何额外优点。

因为OCPS必须配合stapling,该服务(即下游服务)须要向客户端(即上游服务)提供保证,证实OCSP响应被附加到了该服务在TLS握手时接收到的证书中。若是OCSP响应未被附加至该证书中,那么结果并不是出现软错误,而是客户端必须当即拒绝该链接。

临时证书

从最终用户的角度来看,临时证书的效果与目前的常规证书并没有区别,只不过暂时证书的过时时间很是之短。TLS客户端并不须要针对临时证书进行CRL或者OCSP验证,而是坚持设定好的过时时间,并对证书自己进行时间戳加盖。

Netflix与临时证书

图片描述

临时证书带来的最大挑战在于其部署与维护工做。自动则正是解决这些难题的灵丹妙药。Netflix公司建议使用分层方案以构建临时证书部署机制。你们能够在TPM(即受信平台模块)或者SGX(软件保护扩展)当中得到系统身份或者长期证书,从而显著提高安全性。在此以后,再使用这些凭证做为临时证书。最后,在微服务中使用临时证书——这些证书亦可由其它微服务使用。每项微服务都可以利用自身长期证书对临时证书进行按期刷新。固然,仅仅拥有临时证书还不够——托管该服务(或者TLS终止器)的主机应当支持对服务器证书的动态更新。目前存在大量可以运行服务器证书动态重载的TLS终止器,但其中大多数可能会致使短暂的服务停机。

边界安全

微服务集与外部世界的连通通常经由API网关模式实现。利用API网关模式,须要进行声明的微服务可以在该网关内得到对应的API。固然,并非全部微服务都须要立足于API网关实现声明。

图片描述

最终用户对微服务的访问(经过API实现)应当在边界或者API网关处进行验证。目前最为常见的API安全保护模式为OAuth 2.0。

OAuth 2.0

OAuth 2.0是一套做为访问表明的框架。它容许某方对另外一方进行某种操做。OAuth 2.0引入了一系列grant types。其中之一用于解释协议,客户端可利用此协议获取资源拥有方的许可,从而表明拥有方进行资源访问。另外,还有部分grant types可解释用于获取令牌的协议,且整个操做彻底等同于由资源拥有方执行——换言之,该客户在这种状况下即至关于资源拥有方。如下示意图解释了OAuth 2.0协议的宏观实现流程。其中描述了OAuth客户端、资源拥有方、验证服务器以及资源服务器之间的交互方式。

图片描述

要想经过API网关访问某项微服务,请求发起方必须首先得到有效的OAuth令牌。系统可以以自身角色访问微服务,也能够做为其余用户实现访问。对于后一种状况,假设用户登陆至某Web应用,那么此后该Web应用便可以所登陆用户的身份进行微服务访问。

图片描述

下面来看端到端通讯的具体实现方式,如上图所显示:

  • 用户经过Identity Provider登陆至Web应用/移动应用,而Web应用/移动应用则经过OpenID Connect(也能够是SAML 2.0)信任该Provider。

  • 该Web应用获取一条OAuth 2.0 access_token与一条id_token。其中id_token将验证访问该Web应用的最终用户。若是使用SAML 2.0,则该Web应用须要与其信任的OAuth验证服务器的token端点进行通讯,同时将SAML令牌交换为一条OAuth acess_token,随后交换OAuth 2.0的SAML 2.0 grant type。

  • 该Web应用会做为最终用户调用一个API——并随同API请求发送access_token。

  • API网关会拦截来自该Web应用的请求,提取access_token,与令牌交换端点(或者STS)进行通讯,并由后者验证该acess_token,然后向该API网关提供JWT(由其签名)。此JWT还携带有用户上下文。在STS对acess_token进行验证时,其还将经过introspection API与对应的OAuth受权服务器进行通讯。

  • API网关向下游微服务将同时发出请求与JWT。

  • 每项微服务都会验证其接收到的JWT,然后做为下游服务调用,其可以建立新的自签名JWT并将其与该请求一同发送。在其它方案中,亦会用到嵌套JWT——即由新的JWT携带上一JWT。

在上述流程当中,来自外部客户端的API请求将经由该API网关。当某项微服务与其它微服务通讯时,其将再也不须要通过该网关。另外,从特定微服务的角度来看,不管你们是从外部客户端仍是其它微服务处获取请求,得到的都是JWT——也就是说,这是一种对称安全模式。

访问控制

受权属于一项业务功能。每项微服务能够决定使用何种标准以容许各项访问操做。从简单的受权角度来说,咱们能够检查特定用户是否向特定资源执行了特定操做。将操做与资源加以结合,也就构成了权限。受权检查会评估特定用户是否具有访问特定资源的最低必要权限集合。该资源可以定义谁能够进行访问,可在访问中具体执行哪些操做。为特定资源声明必要权限可经过多种方式实现。

XACML (可扩展访问控制标记语言)

XACML已经成为细粒度访问控制领域的客观标准。其引入的方式可以表明访问某种资源所须要的权限集,且具体方法采用基于XML的特定域语言(简称DSL)编写而成。

图片描述

上图所示为XACML组件架构。首先,策略管理员须要经过PAP(即策略管理点)定义XACML策略,而这些策略将被保存在策略存储内。要检查特定实体是否拥有访问某种资源的权限,PEP(即策略执行点)须要拦截该访问请求、建立一条XACML请求并将其发送至XACML PDP(即策略决策点)。该XACML请求可以携带任何有助于在PDP上执行决策流程的属性。举例来讲,其可以包含拒绝标识符、资源标识符以及特定对象将对目标资源执行的操做。须要进行用户受权的微服务则须要与该PDP通讯并从JWT中提取相关属性,从而创建XACML请求。PIP(即策略信息点)会在PDP发现XACML请求中不存在策略评估所要求的特定属性时介入。在此以后,PDP会与PIP通讯以找到缺失的对应属性。PIP可以接入相关数据存储,找到该属性然后将其返回至PDP。

图片描述

嵌入式PDP

远程PDP模式存在几大弊端,其可能与微服务的基本原则发生冲突:

  • 性能成本:每一次被要求执行访问控制检查时,对应微服务都须要经过线缆与PDP进行通讯。当该决策被缓存在客户端时,此类传输成本与策略评估成本将获得有效下降。不过在使用缓存机制时,咱们亦有可能根据陈旧数据进行安全决策。

  • 策略信息点(简称PIP)的全部权:每项微服务都应当拥有本身的PIP,其了解要从哪里引入实现访问控制所必需的数据。在以上方案中,咱们创建起的一套“总体式”PDP,其中包含所有PIP——对应所有微服务。

图片描述

如上图所示,嵌入式PDP将遵循一类事件模式,其中每项微服务都会订阅其感兴趣的主题以从PAP处获取合适的访问控制策略,然后更新其内嵌PDP。你们能够经过微服务组或者全局多租户模型获取PAP。当出现新策略或者策略存在更新时,该PAP会向对应的主题发布事件。

这套方案不会违反微服务中的“服务器不变”原则。“服务器不变”意味着当你们在持续交付流程结尾处,直接利用加载自库的配置构建服务器或者容器时,整个建立流程应该可以基于一样的配置进行不断重复。所以,咱们不但愿任何用户登入服务器并对配置作出变动。在内嵌PDP模式下,尽管服务器会加载对应的策略,但其仍同时处于运行当中。这意味着当咱们启动新容器时,其仍然立足于一样的策略集。

在结束本篇文章以前,咱们还有另外一个重要的问题须要回答,即API网关在受权上下文中到底扮演着怎样的角色。咱们能够设置全局可访问的访问控制策略——其可用于最终用户,并由网关进行强制执行——但没法设置服务层级的策略。由于顾名思义,服务层策略必须在服务层上执行。

相关文章
相关标签/搜索