Swift驱动程序中上传/下载过程中防止未经授权的错误¶
https://blueprints.launchpad.net/glance/+spec/prevention-of-401-in-swift-driver
此变更提案引入了一种新的机制,用于将分块文件上传/下载到Swift存储,以防止在图像上传/下载过程中用户令牌过期可能导致的401错误。它通过在过程中提供重新认证用户的能力来提高图像上传和下载的可靠性,从而增强整个系统的稳定性。
问题描述¶
当前Swift驱动程序实现存在一些缺点
1. 上传的情况。如果上传到Swift的文件超过用户设置的大小限制,则该文件将被拆分为块,并且每个块都将作为独立对象使用单个PUT请求上传。这些请求需要授权,不幸的是,可能会在中间块中发生用户令牌过期,这将导致未经授权的错误并导致上传失败。
2. 下载的情况。由于Swift驱动程序支持“重试”机制,因此在操作不成功的情况下,可能会有另一个尝试下载文件的操作。但是,如果令牌在之前的尝试之后过期,那么新的尝试也会因为未经授权的错误而失败。
这些问题同时存在于SingleTenant和MultiTenant实现中,尽管两种情况下的解决方案会有所不同。
提议的变更¶
建议以以下方式更改将文件上传和下载到Swift的工作流程
先决条件
为Swift后端在glance_store中添加了来自python_keystoneclient的新可选依赖项。将在swift存储和swiftclient连接之间添加一个额外的层(以后称为‘ConnectionManager’)。ConnectionManager将负责初始化keystone客户端并请求swift客户端连接(如果需要)。ConnectionManager在连接令牌即将过期并且已启用重新认证时执行重新认证。如果未启用重新认证,ConnectionManager始终返回相同的连接(不刷新连接)。如果启用了重新认证,ConnectionManager请求所有允许请求新令牌的先决条件
对于单租户存储:glance服务用户凭据(auth_url, domain, username, password, project)。所有必需的凭据都存储在传递给Store的StoreLocation对象中,因此不需要新的参数或配置选项。
对于多租户存储:trust id,glance服务用户凭据(username, project, password)。服务用户凭据将从swift_store_config_file或(swift_store_user, swift_store_key)配置选项中提取。因此,不需要新的配置选项。trust_id将通过以下步骤创建
使用用户令牌作用域初始化keystone客户端
使用keystone客户端从1)请求用户角色
使用用户名和密码创建Password auth插件,初始化keystone客户端,作用域限定为glance服务用户项目,并请求服务用户的user_id。
使用来自1)的客户端、来自2)的用户角色和来自3)的user_id创建trust。将trust_id存储在ConnectionManager中。
之后,ConnectionManager初始化并存储keystone客户端。Keystone客户端提供了一种从Identity服务请求新的有效令牌的方法。ConnectionManager可以使用该令牌构建新的Swift连接。
注意 如果由于某种原因无法创建客户端,则glance_store会引发异常(对于单租户)或使用用户上下文中的令牌(对于多租户)。
此外,需要将名为‘init_client’的方法添加到store中,它将负责初始化keystone客户端。
上传的情况。
注意 所有这些更改仅适用于分块上传。如果上传作为单个请求执行,它将使用旧的工作流程。
总的来说,建议的方案如下
1. 在上传之前,glance_store确定图像是否需要分块。如果是分块图像,glance_store初始化支持重新认证的ConnectionManager。
2. 在上传每个块之前,ConnectionManager检查是否启用了重新认证以及令牌是否即将过期(它使用authentication插件的‘will_expire_soon’方法和swift_store_expire_soon_interval值来定义何时需要请求令牌)。如果满足上述条件,则ConnectionManager请求新的令牌并创建新的swiftclient连接。该连接将用于上传该块。注意 使用‘will_expire_soon’是因为如果swiftclient请求因未经授权的错误而失败,glance_store可能会丢失数据。不幸的是,requests库在检查令牌之前开始读取数据,因此我们无法在失败后重试请求。更具体地说,requests库不支持100-continue。
下载的情况。
总的来说,建议的方案如下
1. 在下载之前,glance_store确定swift_retry_get_count是否为正数。如果选项值为正数,glance_store初始化允许重新认证并初始化新连接的ConnectionManager。否则,ConnectionManager始终返回相同的swift连接。
2. 在文件下载不成功的情况下,在重试之前,ConnectionManager检查是否启用了重新认证以及连接令牌是否即将过期。如果满足上述条件,ConnectionManager请求新的令牌并返回新的连接。
Glance正常执行下载重试。
备选方案¶
至少有一个针对整个功能的解决方法:延长令牌过期时间以允许Glance上传图像。此解决方案会影响所有服务,而且看起来不是长期的解决方案。
还有一些此问题的解决方法,但它们仅适用于SingleTenant实现,因为对于MultiTenant情况需要有效的用户令牌
1. 引入一个围绕图像数据的包装器,其形状称为BufferedReader类,该类支持‘seek’和‘tell’操作,它通过将图像数据tee到临时文件来缓冲图像段,因为正在将其上传到Swift。它被描述为一种可选的资源密集型解决方案,当Glance和Swift之间的连接不稳定时使用,因为它不仅可以帮助解决未经授权的错误。
2. 另一种选择是使用内存缓冲而不是磁盘缓冲。使用内存缓冲,内存占用将大幅增加,这可能会降低API性能。此外,磁盘比内存便宜,但并不一定更快。
数据模型影响¶
无
REST API 影响¶
无
安全影响¶
无
通知影响¶
无
其他最终用户影响¶
应支持Keystone V3才能正确使用trusts机制。
性能影响¶
如果图像文件太大,则glance_store需要为每次上传到多租户存储创建trust并初始化客户端。如果swift_retry_get_count为正数并且用户正在从swift存储下载图像,则需要执行相同的操作。
其他部署者影响¶
无
开发人员影响¶
以下蓝图定义了swift驱动程序的缓冲读取器:https://blueprints.launchpad.net/glance/+spec/buffered-reader-for-swift-driver。它描述了允许在上传失败时重试图像的缓冲读取器。这个蓝图似乎与此规范中的上传情况重叠,但它是不同的。此规范的目标是向用户提供具有有效令牌的swiftclient连接。缓冲读取器负责使用原始用户令牌重试上传。
实现¶
负责人¶
mfedosin kkushaev dshakhray
评审人员¶
flaper87 stuart-mclaren
工作项¶
实现ConnectionManager类
使用ConnectionManager在Swift存储的‘add’和‘get’方法中请求连接
依赖项¶
无。
测试¶
无。
文档影响¶
一个配置选项:需要在文档中描述‘will_expire_soon’间隔。它定义了ConnectionManager必须请求新令牌并初始化新连接的令牌过期前的时间段。
参考资料¶
Trusts蓝图:https://blueprints.launchpad.net/glance/+spec/trust-authentication
缓冲读取器蓝图:https://blueprints.launchpad.net/glance/+spec/buffered-reader-for-swift-driver