MinIO 的 OpenID Connect 集成详解

MinIO 提供了一个灵活的身份和访问管理系统,可以与流行的外部身份提供商集成。 MinIO IAM 以 AWS IAM 兼容性为核心构建 - 访问由镜像 AWS IAM 策略的策略控制。虽然 AWS 支持多种控制访问的方式,包括 ACL、存储桶策略等,但为了简化起见,MinIO 的访问控制基于与用户或用户组关联的策略。
在此上下文中,策略是 JSON 文档的标识符,该文档遵循与 AWS 的访问策略文档相同的语法,并包含有关允许(和禁止)的 API、资源和访问条件的语句。实体对对象存储的访问由其身份和应用于此身份的访问策略控制。
MinIO 服务器具有内置的内部身份提供程序,支持创建用户和用户组,将一个或多个策略附加到这些用户或组,以及创建具有可选过期时间和范围缩减策略的访问密钥对。
为了与外部身份验证和授权系统集成,MinIO 为安全令牌服务 (STS) API 提供了扩展,以与基于 OpenID Connect 的系统、基于 Active Directory/LDAP 的系统、基于客户端 TLS 证书的系统一起工作,并且还包括对插入任意外部授权和身份验证系统的支持。在这篇文章中,我们将重点关注对广泛流行的基于 OpenID Connect (OIDC) 标准的外部身份提供商 (IDP) 的功能支持。
插入组织的基于 OpenID Connect 的单点登录系统
OIDC 与 MinIO 最简单的用法是与您组织的 IDP 集成。在这种情况下,MinIO 将身份验证委托给与 OIDC 兼容的服务。身份验证成功后,IDP 会生成一个id_token
- 这是一个 JSON Web Token (JWT),包含身份验证的加密证明。MinIO 使用 JWT 中的加密签名和 IDP 的公钥来验证 IDP 完成的身份验证。
任何客户端应用程序都可以为组织用户执行 OIDC 服务器的身份验证,然后调用 MinIO 的 AssumeRoleWithWebIdentity STS API,并向其提供从 OIDC 服务接收到的id_token
,以生成访问对象存储的临时凭证。
最常见的此类客户端应用程序是 MinIO 服务器的 Web 控制台。控制台使用OpenID Connect 的授权代码流实现身份验证,并在后续的 STS API 调用中使用接收到的id_token
令牌来生成对象存储访问的临时凭证。登录控制台时,用户会被重定向到组织的 IDP 以输入其凭据并完成身份验证(可能包括基于 MFA 的身份验证步骤),然后他们会被转到 MinIO 控制台界面以与对象存储交互。
访问对象存储的授权呢?MinIO 在这里支持两种我们称为自定义id_token
声明和角色策略的方法。
自定义id_token
声明
第一种(也是较旧的)方法使用从外部 IDP 接收到的id_token
中提供的声明中的信息。组织可以在 IDP 中配置自定义声明以列出要应用于用户的策略名称。例如,以下解码的id_token
(来自开发环境)显示了名为“groups”的自定义声明的值。使用在 MinIO 服务器中配置的此自定义声明,该值会被解释为要应用于用户的策略名称列表。
{
"alg": "RS256",
"kid": "4d7a8d4a74c6f1443890ddba7c3b500efd06e8c4"
}.{
"iss": "http://127.0.0.1:5556/dex",
"sub": "Cit1aWQ9ZGlsbG9uLG91PXBlb3BsZSxvdT1zd2VuZ2csZGM9bWluLGRjPWlvEgRsZGFw",
"aud": "minio-client-app",
"exp": 1697571883,
"iat": 1697485483,
"at_hash": "cITlbF83_r4rU-fLWWWJeA",
"c_hash": "EYUT2tpGQh4gB_AXIHH6Pw",
"email": "johndoe@example.io",
"groups": [
"projecta",
"projectb"
]
}.[Signature]
这两个策略projecta
和projectb
定义了此用户(以及他们生成的任何访问密钥)可能具有的最大访问范围。这些策略的 JSON 策略文档可以通过策略变量利用id_token
中的其他属性来进一步自定义策略,并使用各种条件(在本帖的后面部分描述),如OpenID Connect 访问管理 - MinIO 对象存储 Kubernetes中所述。
虽然简单,但这种方法的主要限制在于管理此系统涉及使用自定义声明配置组织的 IDP,并为不同的项目和用户设置它。我们发现,对于许多组织来说,管理 MinIO 部署的团队和管理 IDP 的团队是不同的,并且此过程涉及大量来回设置和配置每个用例的此自定义声明。
角色策略
第二种更灵活的方法来管理对对象存储的授权允许在 MinIO 服务器本身中配置 IDP 的所有访问策略。这消除了使用自定义声明配置外部 IDP 的需要,并支持其他用例,尤其是在组织不想或无法修改 IDP 返回的声明时。
在这种方法中,外部 IDP 定义了一个“角色” - 即一组应用于此 IDP 身份验证的任何用户的策略。配置外部 IDP 时,管理员将列出应应用于此外部 IDP 的策略作为role_policy
。MinIO 服务器为此配置分配一个唯一的称为 RoleARN 的值。客户端在 AssumeRoleWithWebIdentity STS API 调用中向 MinIO 服务器提供此值以生成临时凭据。
使用角色策略,所有用户都会获得相同的策略列表。那么我们如何为用户或用户组分配不同的访问策略呢?答案是策略变量。id_token
包含用户的属性,例如他们的电子邮件地址、唯一 ID 和组织内部组等属性。我们可以利用此信息来限制访问。让我们来看一个例子。
考虑上一节中解码的id_token
。它表示一个电子邮件地址为johndoe@example.io
的用户 - 此用户也是几个组的成员。要为组projecta
和projectb
的成员分配特定策略,我们可以创建如下内容的策略
策略“projecta”
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:*"
],
"Resource": [
"arn:aws:s3:::projecta/",
"arn:aws:s3:::projecta/*"
],
"Condition": {
"ForAnyValue:StringEquals": {"jwt:groups": "projecta"}
}
}
]
}
策略“projectb”
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:*"
],
"Resource": [
"arn:aws:s3:::projectb/",
"arn:aws:s3:::projectb/*"
],
"Condition": {
"ForAnyValue:StringEquals": {"jwt:groups": "projectb"}
}
}
]
}
这些策略中的每一个都允许对特定存储桶(也称为projecta
和projectb
)执行所有 S3 操作。它们还在jwt:groups
属性上包含一个条件,指定语句仅适用于由其组列表包含给定组名称的用户发出的请求。由于jwt:groups
属性是多值(即用户可能是多个组的成员),因此使用ForAnyValue:
限定符来指示StringEquals
函数应该匹配列表中的任何组。
作为最后一个示例,如果我们想让某些用户访问所有 S3 存储桶,假设通过他们的电子邮件地址识别,我们可以创建如下单独的策略
策略“allbuckets”
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:*"
],
"Resource": [
"arn:aws:s3:::*"
],
"Condition": {
"StringEquals": {
"jwt:email": [
"johndoe@example.io",
"janedoe@example.io"
]
}
}
}
]
}
在这种情况下,jwt:email
是一个单值属性,它与策略中给定的每个电子邮件地址(使用 OR 逻辑)匹配。
配置 MinIO 时,以上所有三个策略都将列在 IDP 的role_policy
参数中。只有id_token
信息与策略条件匹配的用户才会应用该策略,从而获得对对象存储的访问权限。
使用多个 OIDC 身份提供商
MinIO 允许配置多个 IDP 并配置角色策略 - 由于对 STS API 的每个请求都需要指定 RoleARN - 因此 MinIO 服务器在针对相应提供商验证id_tokens
和处理请求方面不存在歧义。
这支持新的特定于应用程序的用例。假设我们要开发一个具有以下(并非不常见)需求的移动应用程序
- 特定于用户的应用程序数据(例如照片、视频和文档)需要存储在对象存储中
- 每个用户的数据需要存储在对象存储中的唯一路径下
- 我们不希望在应用程序二进制文件或用户设备上保存对象存储凭据
- 用户应该能够使用某些常见的 OpenID 提供商(例如 Google、Facebook 和 GitHub)进行身份验证
众所周知,可以使用 AssumeRoleWithWebIdentity STS API 生成对象存储的动态临时凭证。MinIO 可以使用这三个提到的 OpenID 提供程序通过角色策略进行配置,以便用户可以通过其id_tokens
进行身份验证。访问策略基于策略变量,并根据唯一标识符为每个用户提供唯一的路径。
{
"Version": "2012-10-17",
"Statement": [
{
"Action": ["s3:ListBucket"],
"Effect": "Allow",
"Resource": ["arn:aws:s3:::mybucket"],
"Condition": {"StringLike": {"s3:prefix": ["github/${jwt:upn}/*"]}}
},
{
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Effect": "Allow",
"Resource": ["arn:aws:s3:::mybucket/github/${jwt:upn}/*"]
}
]
}
上面显示了一个可以与 GitHub 作为外部 IDP 一起使用的示例策略。jwt:upn
是id_token
中的“用户主体名称”声明,对于每个用户来说都是唯一的 - 此处可以使用 IDP 提供的任何此类唯一标识符。请注意,路径以提供程序名称为前缀以确保唯一性。
MinIO 的 OIDC 集成 - 一种灵活且无妥协的解决方案
通过利用 OIDC 标准,MinIO 与外部 IDP 无缝集成,简化了身份验证过程并确保了强大的加密验证。组织可以使用自定义id_token
声明或角色策略,从而能够执行微调的访问控制,根据用户属性和组关联对其进行定制。能够以最少的配置配置多个 IDP 突显了 MinIO 的适应性,使各种应用程序能够创建动态存储解决方案,而不会影响安全性。它证明了该平台致力于用户在管理对象存储方面的便利性和安全性。