作者丨向荣(荣涵)
阿里云开放平台高级技术专家,主要负责阿里云OpenAPI访问密钥(AccessKey),专注于给阿里云用户提供高效,安全的访问密钥,身份验证服务。
名词解释
RAM(Resource Access Management)
访问控制是阿里云提供的一项管理用户身份与资源访问权限的服务。使用RAM,您可以创建、管理RAM用户(例如员工、系统或应用程序),并可以控制这些RAM用户对资源的操作权限。当您的企业存在多用户协同操作资源时,使用RAM可以让您避免与其他用户共享云账号密钥,按需为用户分配最小权限,从而降低企业信息安全风险。
STS(Security Token Service,STS)
阿里云临时安全令牌(Security Token Service,STS)是阿里云提供的一种临时访问权限管理服务。
摘要
就像登陆阿里云网站需要输入账号和密码一样,我们访问阿里云产品或者服务提供的OpenAPI时,也需要这样的密钥体系,这就是OpenAPI的访问密钥:AccessKey(AccessKey ID和AccessKey Secret)。所以,类似登陆的账号和密码泄露的安全问题,OpenAPI的访问密钥同样存在泄露的风险,本文介绍了一种不直接使用OpenAPI的访问密钥的身份认证方式,可以有效避免因为访问密钥的代码中硬编码或者存储到配置文件而引入的泄露风险。
前言
访问密钥
访问密钥是一个基本的2元组AccessKey(AccessKey ID和AccessKey Secret),AccessKey ID其实是做为一个索引来映射真实的密钥,AccessKey会在客户端和服务端共享,客户端使用AccessKey ID对应的密钥对请求的某些信息进行签名,然后把AccessKey ID和签名,以及相关信息都发给服务端,服务端做同样的事情,然后比对签名结果来标识身份认证合法与否。
身份认证流程
接下来我们看看一般OpenAPI的访问时身份认证的工作过程。
大致流程如下:
- 用户在阿里云上获取访问密钥
- 用户通过用户中心控制台申请和获取阿里云账号所拥有的的访问密钥,这个密钥是用户访问阿里云OpenAPI的密钥,具有该账户下任何资源的完全权限,权限最大。
- 用户通过RAM控制台申请和获取RAM子用户所拥有的的访问密钥,这个密钥同样是用户访问阿里云API的密钥,但只具有该子用户的权限,权限范围取决于用户给这个子用户配置了多少权限,一般在生产环境建议使用此类密钥,虽然子用户可以做到细粒度的权限控制,但是一旦泄露,对用户的资源也有很高的风险。
- 用户使用第一步获取的OpenAPI访问密钥把每次对云产品OpenAPI的访问或者调用进行身份的签名,并把签名结果附带在请求参数或者变量里发送给阿里云网关。
- 阿里云网关身份验证通过后,将请求发送给云产品的OpenAPI;
- 云产品将调用结果返给网关,并透传给真实调用方。
Signature = Base编码(签名算法(AccessKeySecret, UTF-8-Encoding-Of(StringToSign)))
阿里云实体身份
在介绍访问密钥时,我们需要了解访问密钥的类型和使用场景,然后看使用场景中的泄露风险。对于阿里云用户来说,我们先说一下阿里云提供的两种身份。
- 阿里云账户:云账户是阿里云的一种实体身份类型,也叫阿里云主账号/阿里云主用户,这个身份是用户在阿里云上的唯一标识,他是客户所有资源的实际拥有者,他有账号和密码用来登录阿里云官网,同样拥有阿里云OpenAPI访问密钥(数量有限),这些密钥时长期有效,除非用户自己禁用或者删除。
- 阿里云RAM子用户:RAM用户是RAM的一种实体身份类型,有确定的身份ID和身份凭证,它通常与某个确定的人或应用程序一一对应。类似于云账户,他也拥有账号密码以及OpenAPI访问密钥,这种访问密钥也是长期有效的,除非用户自己禁用或者删除。
• 一个云账号下可以创建多个RAM用户,对应企业内的员工、系统或应用程序。
• RAM用户不拥有资源,没有独立的计量计费,这些用户由所属云账号统一控制和付费。
• RAM用户归属于云账号,只能在所属云账号的空间下可见,而不是独立的云账号。
• RAM用户必须在获得云账号的授权后才能登录控制台或使用API操作云账号下的资源。
从阿里云提供两种身份描述和定义,我们可以看到他们具有相同的身份特性:
- 这些身份都是实体身份类型(用户身份)都有账号和密码来登录阿里云官网,
- 用于相同类型的OpenAPI访问凭证:访问密钥长期有效,且权限较大。
挑战
对于阿里云实体身份的访问密钥,如下泄露风险是显而易见的:
- 阿里云主账户对应的访问密钥具有该账户下任何资源的完全权限,权限最大,主账号的访问密钥泄露出去的话会带来极大的安全风险,获取者可以随意操作该账号下所有的资源,盗取重要信息等,所以在生产环境强烈不建议使用此类密钥;
- 通过分出不同权限的阿里云RAM子账号,将不同的权限分给不同的用户,这样一旦子账号泄露也不会造成全局的信息泄露。但是,由于子账号在一般情况下是长期有效的,因此,子用户的访问密钥也是不能泄露的。
既然风险比较大,那么一般的泄露途径会有哪些呢(客户侧泄露)?我们来看看了解到的一些客户的一般使用方式: - 硬编码在代码里:很多客户对访问密钥的安全意识不够或者没有意识到风险,为了使用方便,会直接把访问密钥的二元组写在代码里,供程序使用;在现在反编译和内存分析的技术已经很成熟的当下,硬编码的方式无异于明文存储密钥,有巨大的泄露风险。
- 第三方密钥存储:还有很多客户了解访问密钥的重要性,会使用第三方的密钥存储系统或者配置文件,将原始的密钥加密起来。这种方式的做法加延了密钥泄露的链路,但本质上只是原始密钥泄露的风险转移到另外一把密钥上,比如第三方密钥存储系统的访问key,或者是加密的密钥,归根结底还是会存在“最后一把密钥”的安全泄露风险。
无密钥访问方案-基础
针对访问密钥的泄露高风险,我们有没有一些方案既能克服“最后一把密钥”的风险,又能很方便的进行可控的身份认证呢?很自然,我们会想出来的第一个方案:既然长期的访问密钥权限大,我们能不能换一种短期且权限可控的访问密钥呢,这就要介绍阿里云的另外一种身份类型和与之相对应的访问密钥。
阿里云虚拟身份
RAM角色(RAM role)与RAM用户一样,都是RAM身份类型的一种,只不过RAM角色是一种虚拟用户,没有确定的身份认证密钥,需要被一个受信的实体用户扮演才能正常使用。简单说,可信实体扮演RAM角色,并使用角色令牌去访问RAM角色里规定的资源以及资源上的OpenAPI。
• RAM角色:RAM角色有确定的身份,可以被赋予一组权限策略,但没有确定的登录密码或访问密钥。RAM角色需要被一个受信的实体用户扮演,扮演成功后实体用户将获得RAM角色的安全令牌,使用这个安全令牌就能以角色身份访问被授权的资源。
• 可信实体(Trusted entity):角色的可信实体是指可以扮演角色的实体用户身份。创建角色时必须指定可信实体,角色只能被受信的实体扮演。可信实体可以是受信的阿里云账号、受信的阿里云服务或身份提供商。
• 角色令牌(Role token):角色令牌是角色身份的一种临时访问密钥。角色身份没有确定的访问密钥,当一个实体用户要使用角色时,必须通过扮演角色来获取对应的角色令牌,然后使用角色令牌来调用阿里云服务API。
对于虚拟身份类型(角色身份),对应的OpenAPI访问凭证就是上面说的角色令牌,是一种时效和权限可控的临时访问密钥。相对于阿里云实体身份的访问密钥的长效控制机制,STS提供的是一种临时访问授权。通过STS可以返回临时的访问密钥和令牌,这些信息可以直接发给临时用户用来访问阿里云服务。一般来说,从STS获取的权限会受到更加严格的限制,并且拥有时间限制,因此这些信息泄露之后对于系统的影响也很小。
阿里云用户在RAM中,定义一个角色,并授权了可以扮演此角色的可信实体,比如某主账户下的子用户账号A,然后授权账户可以访问RAM的接口获取临时访问密钥。账户A的访问流程就如下描述了。所以结合了STS访问密钥的方案一如下描述。
- 客户的应用使用阿里云颁发给账户A的访问密钥签名访问RAMOpenAPI的请求,发给网关;
- 阿里云网关在验证身份和API的权限校验通过后,将请求发送到RAM的OpenAPI,请求颁发STS临时访问密钥;
- 阿里云RAM的OpenAPI颁发STS临时访问密钥;
- 阿里云网关将申请的STS临时访问密钥返回给调用方-云客户应用;
- 云客户应用再将获取的STS临时访问密钥分发给其自己的终端或者别的应用系统;
- 9.步和我们在前言里介绍的一样,应用使用访问密钥正常访问阿里云服务的OpenAPI,只不过这里使用的是STS临时访问密钥了。
无密钥访问方案-进阶
无密钥访问方案-基础方案里,我们把权限较大的长期访问密钥,替换成了STS临时访问密钥,由于STS在时间等属性上有限制,这样可以把原来泄露长期访问密钥带来的风险降低到短时间都维度,做到了一定程度的安全风险减小,但细心的同学还会发现,要获取一个STS临时访问密钥,还是需要云账户或者其RAM子用户的长期访问密钥,也还是没有解决“最后一把密钥”的问题。
既然阿里云RAM提供了角色功能,并能把这个角色授权给实体,这个是实体是账户或者服务,那可不可以把这个角色和某些特定实体关联呢,比如某个IP,某个区域或者环境等。这种环境可以映射到什么实体呢?我们看现阶段客户的应用绝大部分会运行在机器,docker容器或者某个运行环境(Serverless)里,在这个特定的范围里,比如某个机上,是否可以实现免输入长期访问密钥而调用RAM的OpenAPI获取STS临时访问密钥呢。我们接下来引入阿里云ECS的一个特殊角色来举例。
实例RAM角色
ECS实例RAM(Resource Access Management)角色让ECS实例扮演具有某些权限的角色,从而赋予实例一定的访问权限。实例RAM角色允许用户将一个角色关联到ECS实例,在实例内部基于STS临时凭证(临时凭证将周期性更新)访问其他云产品的API。一方面可以保证AccessKey安全,另一方面也可以借助RAM实现权限的精细化控制和管理。关于角色的详细描述,请参见角色。
首先,我们定一个特殊的角色,这个角色就是ECS实例角色,然后把这个角色授予这个特定的ECS实例,在这个实例里的应用可以通过如下流程进行完整的阿里云OpenAPI访问。
- 在已经授予了实例RAM角色的机器上的应用,可以向ECS的元数据服务请求STS临时访问密钥;
- ECS元数据服务返回已经获取的STS临时访问密钥给客户的应用
- 客户的应用可以把获取的STS临时访问密钥分发给自己的其他应用;
- 客户的其他应用从而使用获得的STS临时访问密钥正常访问阿里云服务的OpenAPI。
除了ECS,阿里云的一些其他运行环境(ECI,ContainerService,FuntionCompute)都有类似的安全实现,在使用了此类安全实现后,用户不在需要直接把访问密钥AccessKey固化在实例中,如写在配置文件中,硬编码在代码中等不安全的存储访问密钥。
具体的配置和使用请参见实例RAM角色
结语
本文提供介绍了阿里云关于去除OpenAPI访问密钥本地存储的安全方案及实现,这种方式既满足了便捷调用OpenAPI的需求,又不需要直接把访问密钥AccessKey固化在实例中,如写在配置文件中,有效的解决了固化访问密钥这种方式权限过高,存在泄露信息和难以维护等问题。