翻译自Edge Authentication and Token-Agnostic Identity Propagation。经过本文能够了解到Netflix是如何经过将认证转移到边缘设备来下降系统内容内部的认证流程,以及如何使用统一的认证结构支持系统对身份信息的需求。java
正如大多数开发人员认为的那样,对安全协议和身份令牌,以及用户和设备身份验证的处理可能会充满挑战。假设有不少协议,令牌,200M+的用户,以及上千个设备,问题可能随时会在范围内爆发。几年前,咱们决定经过发起一个新的计划,组建一个新的团队来解决这种复杂性,将用户和设备身份验证以及各类安全协议和令牌的复杂处理移至(由一组集中式服务和一个团队管理的)边缘网络上。在这个过程当中,咱们更改了身份在服务之间的传播方式,转而使用支持加密验证且令牌无关的身份对象。后端
经过本文能够了解到:api
Netflix最初是一个容许会员管理其DVD队列的网站。该网站后来提供了流内容,流设备稍晚一些,可是这些初始设备的功能受到了限制。随着时间的推移,流设备的功能愈来愈强大,曾经只能经过网站访问的功能也拓展到了流设备上。Netflix服务的扩展很是快速,目前已经支持多达2000种设备类型。安全
支持这些功能的服务识别多种令牌以及安全协议(用于验证用户和设备,并受权访问这些功能)的负担也愈来愈重。整个系统变得至关复杂,开发也变得脆弱。加上边缘层的架构已经演化到PaaS模型,咱们须要肯定如何,以及在哪里处理身份令牌。服务器
为了展现流的复杂度,下面描述了在架构修改前,用户是如何登陆的:cookie
从最高层面看,此流程(大大简化)涉及的步骤以下:网络
该模型有一些问题,如:数据结构
本例展现了处理一个协议(HTTP/S)以及一个令牌类型(Cookies)的流程。在Netflix的流产品中使用了一些协议和令牌,归纳以下:架构
Netflix 的流生态系统会消费(有可能会更改)这些令牌,如:并发
更复杂的是,能够经过多种方法在系统之间传输这些令牌或令牌中包含的数据。在某些状况下会不断打开令牌,从中抽取身份数据元素,做为API调用使用的简单基元或字符串,或经过请求上下文首部或URL参数在系统间传递。整个过程当中并不会检查令牌或令牌中包含的数据的完整性。
同时,Netflix 的规模在以指数增加。如今,Netflix 已经有200M+的订阅,以及每个月上百万个活动的设备。咱们每秒要服务超过2.5百万个请求,至关大一部分用于某种格式的认证。在老的架构中,每个请求都会触发一个API调用,用来验证请求中声明的内容,以下所示:
后续业务的变更使得状况变得更复杂,边缘工程团队正在将老的API服务架构迁移到一个新的基于PaaS的方式。在咱们迁移到EdgePaaS的同时,先后端服务也从基于Java的API迁移到了BFF(backend for frontend),即NodeQuark:
该模型能够在不依赖核心API框架的前提下让先后端工程拥有和操做各自的服务。但这也引入了另外一层复杂性,即这些NodeQuark服务如何处理身份令牌?NodeQuark服务是用JavaScript编写的,废除了像MSL这样复杂又浪费的协议,这些协议会复制全部令牌管理的逻辑。
作个总结,在大规模场景下,发现咱们使用了一个复杂且低效的方案来处理认证和身份令牌。咱们有多种身份令牌类型和资源,每种身份令牌又须要不一样的处理,各个处理逻辑被复制到了多个系统中。关键身份数据以不一致的方式在整个服务器生态系统中传播。
咱们意识到,为了解决这个问题,须要一个统一的身份模型,在上游进一步处理身份验证令牌(和协议)。咱们经过将认证和协议终结转移到边缘网络,而后建立一个新的完整性保护的且令牌无关的对象,使该对象在整个服务器生态系统中传播。
注意,咱们的目标是提高安全性,并下降复杂度,进而提供更好的用户体验,咱们就如何将设备身份验证操做以及用户标识和身份验证令牌管理集中到服务边缘制定了相应的策略。
从上层看,Zuul(云网关)做为令牌检查和载荷加密/解密的终结点。这种状况下,Zuul能够处理这些操做(一小部分),例如,若是没有出现令牌,则须要更新,不然视为无效。Zuul会将这些操做委派给一组新的边缘身份验证服务,用来处理加密密钥交换以及令牌的建立或更新。
边缘认证服务(EAS)是一个架构理念,包含将设备和用户的认证和身份验证从栈转移到云边缘,以及用于处理令牌类型而开发的服务套件。
EAS是运行在Zuul中的一系列过滤器,可能会调用外部服务来支持域(domain),如调用一个服务来处理MSL 令牌或Cookies的其余令牌。EAS涵盖了为只读令牌建立"Passport"(稍后会涉及到)。
EAS处理请求的基本模式以下:
对于每一个进入Netflix 服务的请求,Zuul中的EAS入站过滤器会检查设备客户端提供的令牌,而后将请求转发到"Passport"检查过滤器(Passport Injection Filter),或某个认证服务进行处理。Passport Injection Filter会生成一个令牌无关的身份,而后使用该身份在剩余的服务生态系统中传播。在响应路径上,在边缘认证服务的协助下,EAS出站过滤器会生成须要发送到客户端设备的令牌。
如今系统架构的格式以下:
注意令牌永远不会越过边缘网关/EAS边界。MSL安全协议会在边缘网关上终结,且全部的令牌会在网关上打开,而后以一种令牌无关的方式在服务生态系统中传播身份数据。
在新的处理路径上,Zuul可以处理大量有效且未过时的令牌,边缘认证服务处理剩余的请求。
EAS服务具备容错性,例如在Zuul标识Cookies有效但已过时,且对EAS的续约调用失败或某些潜在的错误状况下:
这种失败场景下,Zuul中的EAS过滤器将会容忍这种错误,并容许解析后的身份继续传播,并在下一次请求时从新调度续约调用。
使用简单的可变身份结构是远远不够的,由于这样会致使服务到服务间传递的身份缺乏足够的信任。此时须要令牌无关的身份结构。
咱们引入了一个称为"Passport"的身份结构,它容许以统一的方式传播用户和设备身份信息。Passport也是一种令牌,但相比使用外部令牌,使用内部结构能带来不少好处。然而,下游系统仍然须要访问用户和设备身份。
Passport 是一种由边缘网关为每一个请求建立的短生命的身份结构,即它的生存时间取决于请求的生命周期,且仅在Netflix生态系统内部有效。Passport由Zuul经过一组身份过滤器生成。一个Passport包含用户&设备身份,格式为protobuf,其完整性由HMAC保证。
如上所述,Passport 模型为一个Protocol Buffer。从高层看,Passport 的定义以下:
message Passport { Header header = 1; UserInfo user_info = 2; DeviceInfo device_info = 3; Integrity user_integrity = 4; Integrity device_integrity = 5; }
Header元素传达了建立Passport的服务的名称。更有意义的是传播的与用户和设备有关的内容。
UserInfo 元素包含识别发起请求的用户所需的全部信息,DeviceInfo 元素包含用户访问Netflix的设备所需的全部信息:
message UserInfo { Source source = 1; int64 created = 2; int64 expires = 3; Int64Wrapper customer_id = 4; … (some internal stuff) … PassportAuthenticationLevel authentication_level = 11; repeated UserAction actions = 12; } message DeviceInfo { Source source = 1; int64 created = 2; int64 expires = 3; StringValue esn = 4; Int32Value device_type = 5; repeated DeviceAction actions = 7; PassportAuthenticationLevel authentication_level = 8; … (some more internal stuff) … }
UserInfo
和DeviceInfo
包含了请求的Source
和PassportAuthenticationLevel
。Source
是一个声明类型列表,为使用的协议以及用于验证声明的服务。PassportAuthenticationLevel
为放到认证声明中的信任的级别。
enum Source { NONE = 0; COOKIE = 1; COOKIE_INSECURE = 2; MSL = 3; PARTNER_TOKEN = 4; … } enum PassportAuthenticationLevel { LOW = 1; // untrusted transport HIGH = 2; // secure tokens over TLS HIGHEST = 3; // MSL or user credentials }
下游应用可使用这些值来进行受权或决定用户体验。
Passport 的完整性由HMAC保证(基于哈希的消息认证码),HMAC是一种特定类型的MAC,涉及密码哈希函数和密钥,能够同时用于校验数据完整性和消息的真实性。
用户和设备的完整性定义以下:
message Integrity { int32 version = 1; string key_name = 2; bytes hmac = 3; }
当Integrity的version为1表示为HMAC使用SHA-256,编码为ByteArray。将来Integrity的version可能使用一个不一样的哈希函数或编码。在version为1时,HMAC字段包含MacSpec.SHA_256中的256位。
完整性防御保证Passport 字段在Passport建立以后不会改变。客户端应用能够在使用其中包含的任何值以前,经过Passport Introspector检查Passport的完整性。
Passport对象自己是不透明的。客户端可使用Passport Introspector从首部抽取Passport,并检索其中的内容。Passport Introspector是Passport二进制数据的包装器。客户端能够经过一个工厂建立一个Introspector,而后就访问基本的访问器方法:
public interface PassportIntrospector { Long getCustomerId(); Long getAccountOwnerId(); String getEsn(); Integer getDeviceTypeId(); String getPassportAsString(); … }
下面定义了Passport 协议缓冲,以及Passport Actions 的定义:
message UserInfo { repeated UserAction actions = 12; … } message DeviceInfo { repeated DeviceAction actions = 7; … }
当对用户或设备身份进行更新时,下游服务会显示地发送一个Passport Actions。EAS 会使用该信号来建立或更新对应类型的令牌。
让咱们总结一下全部这些解决方案一块儿工做的例子。
在将认证和协议终结转移到边缘,并引入Passports做为身份以后,前面所述的登陆流程演变为了如下内容:
存在外部令牌流入下游系统的缘由是,受权决策常常会依赖令牌中的认证声明,且信任与各类令牌类型相关联。在咱们的Passport结构中为信任分配了不一样的级别,意味着,须要受权决策的系统能够围绕Passport编写合理的规则,而无需在不少服务的代码中重复信任规则。
具备规范身份的结构很是有用。传递身份原始数据的方式比较脆弱且难以调试。若是在一个调用声明中,用户的身份从服务A切换到了服务D,那么谁会发生改变?一旦身份结构经过全部关键系统,一种相对简单的方式是添加一个新的外部令牌类型,新的信任级别,以及新的方式来表示该身份。
拥有一个像Passport的结构,能够容许定义一个使用Passport定义的服务,而且能够被其余服务校验。当传播Passport且在日志中看到该Passport时,咱们能够打开、校验、了解其身分内容。也能够了解到Passport的来历,并跟踪到它是如何进入系统的。这使得调试异常身份问题变得更加容易。
传递一个统一的结构到下游系统,意味着这些系统可使用内省库查看设备和用户身份(因为使用了相同的结构,所以无需单独处理各个类型的外部令牌)
经过将令牌处理从这些系统卸载到中央边缘认证服务上,下游系统在CPU、请求延迟、垃圾回收指标当方面得到了可观的收益,全部这些均可以帮助下降集群占用空间以及云支出。下面例子中的受益都来源于主要的API服务。
在前面的实现中,每一个请求必须承担两次解密/终止开销,由于咱们须要在边缘具备路由的能力,且须要在下游服务中具备丰富的终止请求的能力。某些性能的提升归因于这些功能的合并-如今仅须要处理一次MSL请求。
卸载令牌的处理使得每一个请求的CPU开销下降了30%,并下降了40%的平均负载。下图展现了CPU的RPS比率,越低越好:
API服务的响应时间有了很大提高,下降了30%的平均延迟,并使99%的延迟下降20%:
显著下降了API服务的垃圾回收的压力,以及GC等待值时间,下图展现了垃圾回收的STW指标:
将微服务开发人员和身份验证和身份相关的问题剥离开来,意味着他们能够专一于其核心领域。如今仅在一组专门的服务中完成一次对身份认证的更改便可,而无需将变动散布到多个服务中。
咱们目前正在扩展边缘认证服务来经过一个新的服务"Resistor"支持多因子认证。基于机器学习模型选择性地为可疑的链接引入第二个因素。随着加入了新的流程,咱们引入了新的因素,例如使用一次性密码(OTP)来发送邮件或电话,给移动设备推送通知,以及使用第三方认证应用等。
咱们还可能为但愿在其账户上增长安全性的用户引入可选择的多重身份验证。
如今咱们已经有一个系统层面的身份验证流,在受权决策中咱们可使用该身份验证流做为一个信号。去年,咱们开始探索一个新的产品访问策列(PACS),如今正在将其引入Netflix流产品中。PACS最近为Streamfest( a weekend of free Netflix in India)的体验访问控制提供了支持。