发布于: Jul 29, 2022

Amazon IAM 是 Amazon 云服务的身份和访问权限管理的基石,任何对 Amazon Web Services 服务的 API 调用,都会涉及到 IAM 身份和权限的验证过程

 

Amazon IAM 是 Amazon Web Services 云服务的身份和访问权限管理的基石,任何对 Amazon Web Services 服务的 API 调用,都会涉及到 IAM 身份和权限的验证过程。

对于 S3 的访问来说,对于通常访问控制的场景,详细剖析如下,

  • 使用某个 IAM 实体(通常是 IAM user)的 Access Key 和 Secret Key (AK/SK) 直接访问某个存储桶/某个文件。

最基础的场景是,无论您使用 Amazon Web Services 控制台,Amazon Web Services 命令行工具或者利用 Amazon Web Services SDK 编程来访问 S3 存储(如读取某个文件),您的客户端底层都实现了利用您当前的 IAM user 对应的 AK/SK 来签发您的此次 S3 API 请求(如 GetObject API),使得云上的 IAM 服务接到该请求后可以对您进行身份验证和授权。在身份验证过程中,IAM 服务将通过验证签名来确认该请求发起的主体是您所宣称的主体(如 IAM user bob),授权的过程则会通过仔细考察您的请求携带的上下文信息(访问主体,客体,源 IP,请求协议,tag 信息等等),结合您发起请求的 IAM user 所带有的 IAM policy(一组 Amazon Web Services API 权限的集合)信息,以及可能涉及到的资源端 policy(如 S3 bucket policy),最终确定您是否有权限发起该请求。

关于利用 AK/SK 进行请求签名的详细过程可参考以下 SigV4 的实现机制,您也可以参考此机制自己来做 Amazon Web Services 请求的底层实现

  • 使用与 Amazon Web Services 服务集成的 IAM role 来访问。

由于您的 AK/SK 就像用户名密码一样可以完全代表您的身份,对他们的保护显得尤为重要。例如在一段需要读写 S3 文件的程序实现中,最佳实践是不要将 AK/SK 明文地写入到您的代码中。基于您的代码所运行的计算服务的不同场景,有不同的方案来帮助您避免在代码中明文写入 AK/SK。

如果您的程序部署在 EC2 上,可采用 Instance profile 功能来将某个 IAM role 绑定到该 EC2 实例上,IAM role 的 policy 对应您希望程序拥有的 IAM 权限(如读写某个 S3 存储桶的某个 prefix)。

如果您的程序部署在 EKS 容器集群,可利用 EKS built-in 的 IRSA 机制,通过在部署 yaml 文件中指定 service account 的方式来指定您希望程序拥有的 IAM 权限。

如果您的程序部署在 Lambda 函数中,可利用 Lambda Execution Role 来对应您希望程序拥有的 IAM 权限。

在 Amazon Web Services 的很多托管服务中也和 Lambda 类似,可通过为该服务设置某个 IAM role 来赋予该服务访问您的 S3 存储桶或者其他 Amazon Web Services 服务的权限。在此不做赘述。

值得注意的是,通过 IAM role 方式为应用赋权的做法,其底层仍然是基于 AK/SK 签发 API 请求的做法,只不过不再需要用户来处理明文 AK/SK,而是隐式地由 Amazon Web Services SDK 底层去调用 STS 服务来获取临时 AK/SK 并完成请求签名的过程。用户和应用代码本身则不再需要接触到永久性的、明文的 AK/SK,减少了密钥泄露的风险。

  • 使用您现有的身份和访问管理系统与 IAM 服务集成从而访问 S3。

很多客户在自建应用系统为最终用户提供服务时,希望通过 AD 域或者现有的 SSO 系统来提供最终用户登录,并能够让最终用户获取到定制化的 IAM 权限,比如仅允许应用用户 bob 读写 ’S3://some-application-bucket/bob/*’ 存储桶资源等等。一种推荐的实现思路是,应用系统的登录服务将负责处理与 SSO 系统的集成,在确认用户成功登录后查询该用户的预设权限范围(一套权限集合对应一个 IAM role),并负责调用 Amazon Web Services STS 相关 API 来生成临时的 IAM 权限,并返回临时 AK/SK 给客户端,同时在客户端后续的访问中负责维护和更新该临时权限。通过这种设计,使得最终用户可以使用熟悉的登录模块来完成登录,并可以通过客户端程序使用 IAM 临时权限来直接请求 S3 等 Amazon Web Services 资源来完成业务操作,这里的数据交互过程无需经过应用服务器,在减小应用服务器性能压力的同时,实现了扩展性、性能、安全性兼顾的云原生架构。

  • 与 Amazon Web Services 提供的其他企业级 IAM 权限管理功能集成。

Amazon Web Services 提供诸如 Amazon Organizations SCP, Permissions Boundary 等企业级 IAM 权限管理功能,使得一个复杂的组织能够更灵活地集中管控企业多账号环境的权限边界,实现多层级的安全管控。对于即将或者正在探索这些功能的企业来说,理解这些功能之间的关系是规划设计的前提。对于扁平化、暂无集中化权限管理需求的企业来说,可暂时忽略这部分内容。

下图展示了从 IAM 主体角度的权限决策链,

一个 IAM 主体最终拥有的 IAM permission,会经过图中不同权限管理功能的层层规范。举例来说,决定一个 IAM user 的最终权限,可以从该 user 的 IAM policy 所定义的权限出发,去掉 Organizations SCP 未赋予该 user 所在的 Amazon Web Services 账号的那部分权限,去掉不在 Permissions Boundary 赋予该 user 的权限范围的权限,最终得到的即是该 user 真正拥有的 IAM 权限。在此图中,‘Session Principal’ 指的是由该 user 调用 STS API(如 assumerole)获取到另一个 IAM role 的临时权限,则 assumed role(被调用的角色)的权限也会纳入最终考量。在此不做展开。

  • 利用 Bucket Policy 实现资源角度的权限管控。

在上述四种场景中描述的是不同场景下发起 API 请求的 IAM 实体,以及如何判断其最终所具有的 IAM 权限。而决定一个发往 S3 的 API 请求是否最终得到授权,IAM 服务除了会检查 IAM 实体所拥有的权限,还会检查 Bucket Policy 所允许的权限。Bucket Policy 与 IAM Policy 的区别在于,IAM Policy 从主体的角度规定了某个 IAM 实体(user, role)所拥有的权限,而 Bucket Policy 则从客体的角度规范某个 S3 存储桶所允许和/或禁止的来自某些主体的访问权限。换言之,IAM Policy 是跟着 IAM 实体走,是访问方账号的权限管控意志的体现,而 Bucket Policy 则是跟着资源(S3 存储桶)走的,是资源方账号的权限管控意志的体现。

IAM 服务决定某一个针对 S3 的 API 请求最终是否成功时,会同时考察 IAM Policy 和 Bucket Policy。这里的考察机制看似复杂,可能也让许多用户感到困惑。总体来说可以参考下图:

在本图中,User context 对应的是发起请求的 IAM user 所在的 Amazon Web Services 账号层面;Bucket context 对应的是所请求的存储桶层面;Object context 对应的是所请求的文件层面。对于某个文件的访问请求,将在这三个层面来考察该请求是否被允许。

为方便读者理解,也为了更贴近多数现实场景,这里做一下场景的简化,假设 Bucket owner 和 Object owner 是同一 Amazon Web Services 账号,根据该 Amazon Web Services 账号与 IAM 实体所在的 Amazon Web Services 账号的异同,这里分几种情况做场景展开:

  1. 在 IAM 实体和 S3 存储桶同账号的场景下,Bucket Policy 与 IAM Policy 中只要有一方允许某权限,结果即为允许。比如:IAM user bob 的 IAM policy 具有访问 s3://bucket-abc/prefix1/* 的 read 权限,而 bucket-abc 存储桶的 bucket policy 中未含有 allow IAM user bob 的任何权限,甚至 bucket policy 为空。此时 bob 发起的针对 s3://bucket-abc/prefix1/file1 的读取请求将被允许。反之,如果 bob 的 IAM policy 中无 S3 权限,而他访问的存储桶的 bucket policy 允许了 IAM user bob 具有访问 s3://bucket-abc/prefix1/* 的 read 权限,则 bob 针对该 prefix 下的文件读取请求也将被允许。
  2. 在 IAM 实体和 S3 存储桶不同账号的场景下,Bucket Policy 与 IAM Policy 均需要显式允许该操作,结果才为允许。所以在上一场景中提到的两种情况,Bucket Policy 与 IAM Policy 都只有一方显式的允许,那么在这一场景中的访问结果都将是拒绝访问。
  3. 在任何情况下(无论该访问是来自同账号还是跨账号),Bucket Policy 与 IAM Policy 中只要有一方显式的 deny 某实体具有该 object 访问的权限,则最终结果即为 deny(拒绝访问)。
 

相关文章