10月25日,阿里云课堂第二期在上海开课,“云安全架构设计与实践”主题分享在众多朋友的期待下精彩上演,现场观众再次爆满。本次活动中,李雪峰(花名:虚舟)和杨孟哲(花名:孟哲)两位安全专家为大家献上了精彩演讲,并在OpenSpace环节与观众展开讨论,积极互动。应广大用户要求,我们将云课堂讲师现场分享内容全文整理出来,供大家参考。阿里云课堂会继续在全国各地陆续开课,欢迎大家继续支持!
以下为讲师杨孟哲的分享内容:
访问控制,是一个很古老的话题。大家平时都有接触,但又不是真正的、非常深入的去了解它。我今天想讲的方式,是用一种比较轻松的方式让大家了解一下阿里云的飞天和云平台大概是怎样设计的。
一、简单介绍一下访问控制的概念。
首先,访问控制要有主体,一个人也好,一个进程也好,或者是什么,要有发起访问的人。然后有客体和真正的操作,同样的道理,我们可能有很多的客体和它们的操作,这样的简单表格就完成了访问控制的设计。这张表格里面,我们可以看到Alice对file有读写的权限,主流的访问控制实现,有两个思路。第一个思路,大家耳熟能详,就是ACL。ACL可以给大家举一个很简单的例子,大家在实现各种各样系统的时候,到后期会有一个PM告诉你我要加一个feature,那个时候大家就想,我都实现完了你才和我说?但是一听访问控制的需求又非常的简单,就随便动手改一些,加一个白名单或者黑名单就搞定了。大家做这件事的时候,就实现了基于ACL理念的访问控制。ACL的访问控制,就是把前面的表进行了变化。
ACL是以客体作为出发点,我们有文件和表的两样东西,我们在这个客体上面可以附上一个列表,上面写某个客体有什么权限。我们可以定义出这样的列表,当Alice访问file的时候,有权限我们就放过,bob没有权限我们就不放过。
capability这个概念可能大家听少比较少的,这个可能大家没有注意到,但平时非常常用。比如,我从杭州坐高铁过来,高铁的这件事上,或者说火车票机制上,本质上就是基于capability的访问控制。可以抽象成“持票人”的概念。刚才我们按列做划分,现在我们换一下,按行做划分。这个可以看到,我们可以给Alice这个人发一张票,上面写着对文件、对表有读的权限,Alice要访问的时候出示票,我们检查,有权限我们就放过。我们坐火车,你买了票,到时候凭票上车。凭票上车的过程,可以理解为是capability的访问控制。实际上这个访问控制理念,在计算机里面有接触,大家会知道Linux系统里面就有一个capability的访问控制。大家用过Linux应该都知道,Linux很残忍的把用户分成两级,一级叫root,什么事情都可以做,还有一些普通用户,只有很少的权限。大家用多了就会发现,普通用户做很多事情需要变成root的身份,你做完这件事,可能就不小心留下一个后门,被黑客利用。后来Linux系统通过这个capability访问控制机制,把root的权限打散成28个不同的权限,你可以把这些小的权限分配给你的进程。比如一个进程,具有读取任何文件的权限,但是却没有网络访问的一些特权。
ACL和capability,这两个理念在不同的场景下有不同的应用,我们给大家做一个对比,方便大家应用。
首先认证这块,作为ACL来说,认证是必须的。访问控制列表,上面写着Alice有读写权限,但是你不知道访问你的人是Alice还是bob,你就根本无法使用。capability,认证是可选的。你坐火车,以前不需要实名制,你拿着票上车就是了,现在火车站为了更安全,防止*活动,搞成实名制,但实际上这个认证不一定是必须的,可能是可选项。
授权操作,ACL里面授权必须在客体进行,也就是说,完成这个授权操作就是在客体,也就是文件的访问列表上加一项。完成授权,我必须操作客体。对capability来是,授权操作是独立的,没有必要进火车站的那一刻做授权,只需要提前或者是在我有时间的时候去买票就可以了。
安全保障的意思,如果这两个机制足够安全,分别要保护哪些东西?对ACL来说,必须要保护好ACL的数据安全,如果黑客可以篡改那就是不安全的。对capability来说,签发和验证的密钥必须是安全的,大家可以这么想,大家坐火车、买火车票或者是找*开各种各样的证明,都会在上面盖章,那个章实际上就是实现了capability的密钥安全功能,使你没有能力或者说比较困难、难以伪造这样的一个权限。
委派,这也是访问控制经常有的概念。比如说我能访问一个文件,现在我想让我的朋友也访问这个文件,怎么做?在ACL的访问控制列表里面,基本是走的授权流程。我能访问这个文件,意味着我可以在上面加一项,授权给我的朋友访问。或者我需要向管理员发起申请,由管理员申请这个ACL的格子,让我的某个朋友也可以访问。在capability的机制里面,委派是很简单的事情,主体可以直接委派,如果是没有强制要求的话。比如我可以把火车票给其他人,他拿这个票上车就可以了,没有其他繁琐的流程。
撤销授权,在ACL里面非常容易,管理员把某个人的格子删掉就可以了,但是在capability是非常大的难题,我的车票卖出去,要撤销很难。在计算机的设计里面,凭据发出去之后,这个凭据撤销的难得非常大,我无法从别人的计算机或者是别人的手里删除,我也没有办法知道别人是不是把这个数据拷贝了无数次。
为了给大家讲得生动一些,我们从一个比较特殊的角度来看一下阿里云的产品包括下面的飞天系统是怎么做的,这是一个Query的故事。
ODPS这个产品,大部分的云产品都是这样的结构,有一个客户端,会开发出REST API、SDK、CLT、IDE等。接入层有HTTP Srver,如果你是阿里云的用户,在HTTP Srver层面会完成整个的认证过程。ODPS,是一个处理海量数据离线服务,可以处理数以TB甚至PB计的表的计算。必须要把这个Query进行解析,解析成底层可以理解的任务,发送到存储、计算层去执行。
给大家看一个简单的sql,这条语句,在整个过程中到底发生了什么。为什么这里要有一个count*,count*是一个系统的内建的函数,但对我们来说一样,可以换成任何一个用户自定义的聚合函数。用户需要通过上传处理函数,数据会放在雪峰的沙箱里面进行计算,虽然我们知道,大部分用户是没有恶意的,,但这个(沙箱)是非常有必要的。
前面已经说过了,前面的一层整个是做身份认证的功能。过了这一层我们就知道,这个Query是谁提交的,假设是张三提交。下一层,在ODPS逻辑层,我们做了所谓的ACL访问控制。在这个地方,是一个数据存储中心,比如每张表的创建时间、创建人是谁等等。在这些数据上有ACL的存储,比如张三能不能存储,能不能访问等。下面这一层,我们设置了capability的访问理念。上层提交给下层的作业,你必须要给下层的作业一张票据,样,下层的作业就会凭票访问数据,因为是分布式的系统,表面上你看着好像是提交了一个作业,后台可能是数以百计、千计的进程在计算。每个计算的节点都会访问底层的存储系统,这个存储系统会验证你这个进程有没有权限访问你想访问的表或者是具体的文件。大家可以看到中间这块,本来都有像上面的模块描述,公司做安全审核的,安全控制学的比较好,逼我把中间的内容擦掉了。
我们看一下最关键的地方在于ODPS的中间这块逻辑层,用户提交了一个Query进来,第一步,肯定要解析Query。光是Query,不解析的话没有办法理解它说的是什么,肯定需要解析这个Query,把Query里面的整个逻辑抓出来,这个Query到底做了哪些事情。这对我们做访问控制来说,最重要的一点是什么?我们要看它访问了哪些客体。其他的像where条件等我们不关心,只关心它访问了哪些客体。当我们知道了它访问哪些客体,我们首先要检查这些客体是否存在。比如客体访问的project prj和user这张表是否存在。第三步是ACL的访问控制检查,我们这边需要做确认,它访问的客体的访问控制列表里面有没有记张三是否可以访问,如果有就可以执行,如果没有张三就无法执行。我们在做的时候,还不是这么简单,我们除了检查表上的单元,会检查没有一个大的规则,检查张三是否可以访问表,不管怎么样都是一个基于ACL的访问控制,只不过对象有了层次。从传统文件的系统理解,对象有目录和文件,某个目录下有某个文件,允许在目录上设置一些规则,用户可以访问目录下的所有文件,这样我们不需要检查它对文件的ACL,读到目录就知道张三具有目录的所有文件,我让你通过就好了。第四步是生成执行计划,里面很复杂,对访问控制来说并不复杂。生成执行计划,需要分好。还要把这个表和底层文件系统做映射。因为飞天里面看到的都是文件和目录,所以我们可以做假设。刚才提交的query对应这个目录,执行计划的时候,也都不会有表的概念,这个执行计划会说读目录,然后做一个where的条件过滤,然后做group by,把结果输出。通过这个原数据中心,可以把上层的访问控制抽象映射到下层的访问控制抽象上。第五步,打通了上层的ACL访问和下层capability控制的核心一步。这时候我们会生成一个票据,这个表对应的目录,具有读的权限过期时间3天。当然我们可以给更多的运行时间,我们不希望产生这样的作业。一方面作业运行时间越长,对用户来说会收费,而且大部分情况下,要在巨大的集群上跑三天还跑不完,可能是作业写错了或者有什么问题。所以我们会有一个过期的时间,以后我们可以通过机器学习之类的方法预测作业运行时间。这样就能够实现最小权限原则,保护权限泄露。有了Ticket,接下来就可以执行,拿着这个火车票或者是这个Ticket,去做他所要做的事情了。
接下来我们做Job执行,这一层上没有任何的ACL也不会记录任何的状态,你每一个请求过来的时候,你把票带上,把票里面描述的权限和你当前请求访问路径做一个对应。比如我要读这个目录,这是允许的。真实的场景下,肯定会有一堆的Worker要读目录。比如Job Worker的开发者code写错了,或者说像李雪峰讲的没有绝对的安全,我们的沙箱可能会被突破,突破完了会怎么样?用户可以自己构造一个API的请求,比如正常情况下API请求是我要访问User这个目录,黑客突破了沙箱,修改了请求,变成我要访问Item的表,但你只有访问user表的权限,所以你会被拒绝。也就是说,它能够做到权限的细分。在这个角度上来说,因为这张票据赋予你最小的权限,所以你想干某些坏事,你除了突破沙箱,你要用某种方式搞到权限更大的票才行,但相对来说这个比较困难。
回到这张图上,我们看一下为什么上面一层需要用ACL,下面一层要用capability因为不同的场景适合不同的情况。大家可以看一下,上面是面向最终用户,如果用capability,访问会非常难用。大家登录某个网站不需要注册,但是你在网站上每一个请求都要带一个“票据”,传输协议上要保证这个票据是安全的,不能被坏人窃听,否则他和你拥有同样的权限,这时候的访问控制非常难做。用户管理一堆的票据,他会觉得很难受,另外给别人授权,每授权一次多出一张票,他也会感到非常困惑、很难使用。还有一点,因为capability没有办法做到及时授权撤销,为了保证安全经常使用的方式就是有一个过期时间,长的话是1到3天,短是几个小时。上面做成capability的控制,你每次做API请求,你要先搞到票,你才可以请求API,这对用户肯定不友好,撤销授权也有很多的困难。ACL系统的撤销很好做,只要提供撤销的接口,他就可以很好的使用整套的系统。
再看下面的一层,为什么不能使用ACL的访问控制?第一,下面这层做认证很困难。下面看到的不是最终用户,而是上层各种各样的服务。要做用户认证,我们要假设ODPS服务是一个人,给用户名和密码,每次提交作业包括作业运行的时候,都持有ODPS这个人的身份,这时候违反了“最小权限原则”,ODPS是多租户系统,无数用户使用。如果张三提交的作业在底层跑的时候是用ODPS跑,非常不安全。ODPS这个权限非常大,不仅有张三存在里面的数据还有李四的数据,这时候沙箱被突破,用户可以轻易访问李四的数据了。这一层有一个难题就是认证,如果我们不能以ODPS的大单位做认证,我们要实现最小权限原则必须把认证力度也分得很细,对于上面提交下来的每一个Job,需要给他一个身份,也就是用户名和密码,同时还要授权你只能访问这些数据,用户跑完之后我们要把这个授权撤掉,还要把零时创建的用户删除,这样繁琐的操作实现起来基本上是不能忍的。即使我们这样做了,其实用户也感知不到,还有一个很重要的,我们要把用户名和密码分配给无数的工作进程。这也是相对来说比较麻烦的事情,底层不适合用ACL去做访问控制的。
如果大家有了这样的一个概念,相信大家在用某些云产品系统的访问控制,或者是自己设计自己的产品访问控制时,大家就会有一个很好的技术判断,我到底应该用这个还是那个?就像我们阿里云的场景,都用了。上一层我们用的是ACL,下一层我们用的是capability的访问控制。
前面说了这么多,我们都是站在正的看的角度解决问题。我们选择某一项技术,因为这项技术比较适合我们的场景。访问控制里面,可以讲一些比较有趣的话题。我们可以从反方向的角度来看,访问控制体系能不能保护系统的安全。访问控制领域,有一个叫confused deputy。当一个“坏人”去访问某一个东西就会说bob你能不能帮我做这件事?只要是个访问控制体系,肯定会说“不行,因为你没有这个权限”,这个很容易理解。但这个时候,Attacker会换一种方式,和Don这样一个比较有地位的人说,你去和bob说,让他做这件事,bob会说“好的”,然后就把事情做了。实际上这个事情就是由Attacker发起的。这是在访问控制上的confused deputy问题,这个问题特别容易出现在,当你一个架构设计里面,有代理层或者是代理的情况下,比如说,大家可能知道sql注入的攻击方式,从访问控制的角度理解实际上问题就是存在于这里。大家可以想像,我搭了一个网站,后台有一个数据库。我写程序的时候,我的网站要访问数据库,里面有访问控制。写程序的时候会在网站代码或者是配置里面,配置一个用户名和密码,然后去读数据库,用户的一些输入,你没有做足够多的检查。比如说用户的输入直接你拼到你的sql里。不是以用户的身份去的,而是以服务器的用户名和密码执行的,那自然可以执行成功,这时候你服务器变成了一个“被愚弄的代理人”。
怎么解决这个问题?我们举个生活中很常见的例子。几年前,我们去超市的时候,刚进去的时候都有一些储物的地方。几年前,超市都是“人肉储物柜”。这时候,这个“人”就可能成为愚弄的代理,如果他的记忆里不够好,那么张三存在那里的包可以就被长的很像的“李四”拿走了。解决问题的方案很简单,现在的储物柜都是机器,你进去之后按一个存包的按纽,吐出来一个ticket,实质上,储物柜就从原来的ACL访问控制,变成了capability访问控制。等你拿东西的时候,你刷一下票,然后箱子的门就打开了。所以说,要解决这个问题,有两种解决方案。第一种解决方案,像前面PPT里面,ODPS的控制层就是一个代理,持有了所有用户底层数据权限,代理做得不够聪明,很可能成为黑客供给的点。所以我们要做得足够聪明,以此避免。第二,capability访问控制机制天然避免了confused deputy的问题。所以说,在底层的Job Worker也是一个代理,但是就不存在这个问题。
我主要是给大家介绍访问控制的东西,包括我们自己的一些实现上的设计理念,包括我们为什么这样的场景下要用这样的访问控制,那样的场景下用那样的访问控制,这样的访问控制可以带给我们怎样的安全特性。接下来是提问环节。