keycloak 中的资源、范围、权限和策略

Resources, scopes, permissions and policies in keycloak

我想使用 Keycloak 的授权系统创建一个相当简单的基于角色的访问控制系统。 Keycloak 正在替换的系统允许我们创建一个 "user",他是一个或多个 "groups" 的成员。在这个遗留系统中,一个用户被授予 "permission" 访问大约 250 个 "capabilities" 中的每一个,要么通过组成员资格(组被分配权限)要么直接授予用户权限。

我想将遗留系统映射到 keycloak 授权。

将现有系统中的每个 "capability" 映射到一个 keycloak 资源和一组 keycloak 范围对我来说应该很简单。例如,"viewAccount" 能力显然会映射到 "account" 资源和 "view" 范围;并且 "viewTransaction" 映射到 "transaction" 资源...但是最好的做法是只创建一个 "view" 范围,并在多个资源(帐户、交易等)中使用它吗?或者我应该创建一个 "viewAccount" 范围、一个 "viewTransaction" 范围等?

同样,我对权限有点困惑。对于资源和范围的每个实际组合,通常的做法是创建权限吗?如果有多个权限与给定的 resource/scope 相匹配,Keycloak 会做什么?我猜 Keycloak 的目的是允许我配置针对资源和范围的权限矩阵,例如,我可以有权访问 "accounts" 和 "view" 范围的权限,因此我将有权查看帐户?

我问是因为所有这一切的结果似乎是我的旧 "viewAccount" 能力最终创建了一个 "Account" 资源,具有 "View" 范围,并且 "viewAccount" 许可,这似乎让我回到了原来的位置。哪个好,如果它是正确的。

最后,显然我需要一组确定是否应应用 viewAccount 的策略。但我是否正确,这是否意味着我需要为用户可能属于的每个遗留组制定策略?例如,如果我有一个 "helpdesk" 角色,那么我需要一个 "helpdesk membership" 策略,然后我可以将其添加到 "viewAccount" 权限。这是正确的吗?

谢谢,

马克

我知道我迟到了 2 年多,但我想我会分享我所知道的,并希望能减轻未来读者的一些痛苦。完全透明 - 我绝不是 Keycloak/OAuth/OIDC 专家,我所知道的主要是阅读文档、书籍、优秀的 YouTube 和使用该工具。

这个post将由两部分组成:

  1. 我会尽力回答你所有的问题
  2. 我将向您展示如何在 Keycloak 中使用 policies/scopes/permissions,而无需部署单独的应用程序,以便更好地理解此线程中的一些核心概念。请注意,这主要是为了让你们都开始。我正在使用 Keycloak 8.0.0.

第一部分

开始之前的一些术语:

  • 在Keycloak中,您可以创建2种权限:Resource-Based and Scope-Based.
  • 简单地说,对于 Resource-Based 权限,您直接将其应用到您的资源
  • 对于 Scoped-Based 权限,您将其应用于您的范围或范围 资源。

is it best practice to create just one "view" scope, and use it across multiple resources (account, transaction, etc)? Or should I create a "viewAccount" scope, a "viewTransaction" scope, etc?

范围表示受保护资源的一组权限。在你的例子中,你有 2 个资源:accounttransaction,所以我倾向于第二种方法。

在长 运行 中,具有与所有资源关联的全局 view 范围(例如 accounttransactioncustomersettlement...) 使得授权难以管理和适应安全需求的变化。

这里有一些示例,您可以查看这些示例以感受设计

但请注意 - 我并不是说您不应该跨资源共享范围。事实上,Keycloak 允许对具有相同 type 的资源执行此操作。例如,您可能需要 viewAccountviewTransaction 范围来读取给定帐户下的交易(毕竟您可能需要访问该帐户才能查看交易)。您的要求和标准将严重影响您的设计。

For each practical combination of resource and scope, is it usual practice to create a permission?

抱歉,我没有完全理解这个问题,所以我会有点宽泛。为了 grant/deny 访问 resource,您需要:

  • 定义你的 policies
  • 定义你的permissions
  • 将您的策略​​应用于您的权限
  • 将您的权限关联到 scoperesource(或两者)

政策实施生效。参见 Authorization Process

如何设置这一切完全取决于您。例如,您可以:

  • 定义单独的策略,并将每个策略绑定到适当的权限下。

  • 更好的是,定义单独的策略,然后将所有相关策略分组在 aggregated 策略(策略的策略)下,然后将该聚合策略与 scope-based 相关联允许。您可以将 scoped-based 权限应用于资源及其所有关联范围。

  • 或者,您可以利用这两种不同的类型进一步分解您的权限。您可以通过 resource-based 权限类型仅为您的资源创建权限,并通过 scope-based 权限类型单独将其他权限仅与范围相关联。

你有选择。

If there are multiple permissions matching a given resource/scope, what does Keycloak do?

这取决于

  1. 资源服务器的Decision Strategy
  2. 每个权限的Decision Strategy
  3. 每个策略的 Logic 值。

Logic 值类似于 Java 的 ! 运算符。它可以是 PositiveNegative。当 LogicPositive 时,策略的最终评估保持不变。当其 Negative 时,最终结果被否定(例如,如果策略评估为 false 且其 LogicNegative,则它将为 true)。为简单起见,我们假设 Logic 始终设置为 Positive

Decision Strategy才是我们真正想要解决的问题。 Decision Strategy 可以是 UnanimousAffirmative。从文档中,

Decision Strategy

This configurations changes how the policy evaluation engine decides whether or not a resource or scope should be granted based on the outcome from all evaluated permissions. Affirmative means that at least one permission must evaluate to a positive decision in order grant access to a resource and its scopes. Unanimous means that all permissions must evaluate to a positive decision in order for the final decision to be also positive. As an example, if two permissions for a same resource or scope are in conflict (one of them is granting access and the other is denying access), the permission to the resource or scope will be granted if the chosen strategy is Affirmative. Otherwise, a single deny from any permission will also deny access to the resource or scope.

让我们用一个例子来更好地理解上面的内容。假设您有一个具有 2 个权限的资源并且有人试图访问该资源(请记住,Logic 是所有策略的 Positive)。现在:

  1. Permission One 有一个 Decision Strategy 设置为 Affirmative。它还有 3 个策略,它们各自评估为:
    • true
    • false
    • false

由于其中一个策略设置为 truePermission One 设置为 true(肯定 - 只有 1 个需要 true)。

  1. Permission Two 有一个 Decision Strategy 设置为 Unanimous,有 2 个策略:
    • true
    • false

在这种情况下,Permission Twofalse,因为一项政策是错误的(一致 - 它们都需要是 true)。

  1. 现在是最终评估。如果资源服务器'Decision Strategy 设置为 Affirmative,将授予对该资源的访问权限,因为 Permission Onetrue。另一方面,如果资源服务器的 Decision Strategy 设置为 Unanimous,访问将被拒绝。

参见:

我们会继续讨论这个问题。我在第二部分解释了如何设置资源服务器的 Decision Strategy

so for example I could have permission to access "accounts" and permission for "view" scope, so therefore I would have permission to view accounts?

简短的回答是肯定的。现在,让我们稍微展开一下:)

如果您遇到以下情况:

  1. 资源服务器的 Decision Strategy 设置为 UnanimousAffirmative
  2. 访问 account/{id} 资源的权限是 true
  3. 访问 view 范围的权限是 true

您将被授予查看帐户的权限。

  • true+true等于AffirmativeUnanimous下的trueDecision Strategy

现在如果你有这个

  1. 资源服务器的 Decision Strategy 设置为 Affirmative
  2. 访问 account/{id} 资源的权限是 true
  3. 访问 view 范围的权限是 false

您将被授予查看帐户的权限。

  • true + falseAffirmative策略下是true

这里的要点是,对给定资源的访问也取决于您的设置,因此请小心,因为您可能不希望出现第二种情况。

But am I right that this means I need a policy for each of the legacy groups that a user could belong to?

我不确定 Keycloak 在 2 年前的表现如何,但您可以指定 Group-Based policy 并根据该策略简单地添加您的所有组。您当然不需要为每个组创建一个策略。

For example, if I have a "helpdesk" role, then I need a "helpdesk membership" policy, which I could then add to the "viewAccount" permission. Is this correct?

差不多。您可以通过多种方式进行设置。例如,您可以:

  1. 创建您的资源(例如 /account/{id})并将其与 account:view 范围相关联。
  2. 创建一个 Role-Based Policy 并根据该策略添加 helpdesk 角色
  3. 创建一个名为 viewAccountScope-Based 权限并将其与 scoperesourcepolicy
  4. 绑定

我们将在第二部分中设置类似的内容。

第二部分

Keycloak 有一个简洁的小工具,可让您测试所有策略。更好的是,您实际上不需要启动另一个应用程序服务器并部署一个单独的应用程序来使其工作。

这是我们要设置的场景:

  1. 我们将创建一个名为 Whosebug-demo
  2. 的新领域
  3. 我们将在该领域下创建一个 bank-api 客户端
  4. 我们将为该客户端定义一个名为 /account/{id} 的资源
  5. account/{id} 将具有 account:view 范围
  6. 我们将在新领域
  7. 下创建一个名为 bob 的用户
  8. 我们还将创建三个角色:bank_telleraccount_owneruser
    • 我们不会将 bob 与任何角色相关联。现在不需要这个。
  9. 我们将设置以下两个 Role-Based 政策:
    • bank_telleraccount_owner 可以访问 /account/{id} 资源
    • account_owner 可以访问 account:view 范围
    • user 无权访问资源或范围
  10. 我们将尝试使用 Evaluate 工具来了解如何授予访问权限或 否认。

请原谅,这个例子不切实际,但我对银行业不熟悉:)

Keycloak 设置

下载并运行 Keycloak

cd tmp
wget https://downloads.jboss.org/keycloak/8.0.0/keycloak-8.0.0.zip 
unzip keycloak-8.0.0.zip
cd keycloak-8.0.0/bin
./standalone.sh 

创建初始管理员用户

  1. 转到http://localhost:8080/auth
  2. 点击Administration Consolelink
  3. 创建管理员用户并登录

访问Getting Started了解更多信息。就我们的目的而言,以上内容就足够了。

搭建舞台

创建一个新领域

  1. 将鼠标悬停在 master 领域上,然后单击 Add Realm 按钮。
  2. 输入 Whosebug-demo 作为名称。
  3. 点击 Create
  4. 左上角现在应该显示 Whosebug-demo 而不是 master 领域。

参见 Creating a New Realm

创建新用户

  1. 点击左边的Userslink
  2. 点击Add User按钮
  3. 输入username(例如bob
  4. 确保 User Enabled 已打开
  5. 点击Save

Creating a New User

创建新角色

  1. 点击Roleslink
  2. 点击Add Role
  3. 添加以下角色:bank_telleraccount_owneruser

同样,不要将您的用户与角色相关联。出于我们的目的,这不是必需的。

Roles

创建客户端

  1. 点击Clientslink
  2. 点击Create
  3. Client ID 输入 bank-api
  4. 对于 Root URL 输入 http://127.0.0.1:8080/bank-api
  5. 点击Save
  6. 确保Client Protocolopenid-connect
  7. Access Type 更改为 confidential
  8. Authorization Enabled改为On
  9. 向下滚动并点击 Save。一个新的 Authorization 标签应该出现在顶部。
  10. 单击 Authorization 选项卡,然后单击 Settings
  11. 确保 Decision Strategy 设置为 Unanimous
    • 这是资源服务器的Decision Strategy

参见:

创建自定义范围

  1. 单击 Authorization 选项卡
  2. 点击 Authorization Scopes > Create 调出 Add Scope 页面
  3. 在名称中输入 account:view 并按回车键。

创建"View Account Resource"

  1. 点击Authorization上方link
  2. 点击Resources
  3. 点击Create
  4. NameDisplay name 输入 View Account Resource
  5. URI 输入 account/{id}
  6. Scopes文本框中输入account:view
  7. 点击Save

Creating Resources

制定您的政策

  1. 再次在 Authorization 选项卡下,单击 Policies
  2. Select Role 来自 Create Policy 下拉列表
  3. Name 部分,输入 Only Bank Teller and Account Owner Policy
  4. Realm Roles select 下 bank_telleraccount_owner 角色
  5. 确保 Logic 设置为 Positive
  6. 点击Save
  7. 点击Policieslink
  8. Select Role 再次来自 Create Policy 下拉列表。
  9. 这次使用Only Account Owner PolicyName
  10. Realm Rolesselectaccount_owner
  11. 确保 Logic 设置为 Positive
  12. 点击Save
  13. 单击顶部的 Policies link,您现在应该会看到新创建的策略。

参见 Role-Based Policy

请注意,Keycloak 具有更强大的策略。参见 Managing Policies

创建Resource-Based权限

  1. 再次在 Authorization 选项卡下,单击 Permissions
  2. SelectResource-Based
  3. Name 输入 View Account Resource Permission
  4. Resources 下键入 View Account Resource Permission
  5. Apply PolicyselectOnly Bank Teller and Account Owner Policy
  6. 确保 Decision Strategy 设置为 Unanimous
  7. 点击Save

参见 Create Resource-Based Permissions

呼...

正在评估 Resource-Based 权限

  1. 再次在 Authorization 选项卡下,select Evaluate
  2. User下输入bob
  3. Rolesselectuser
    • 这是我们将用户与我们创建的角色相关联的地方。
  4. ResourcesselectView Account Resource下点击Add
  5. 点击评估。
  6. 展开 View Account Resource with scopes [account:view] 以查看结果,您应该会看到 DENY

  1. 这是有道理的,因为我们只允许两个角色通过 Only Bank Teller and Account Owner Policy 访问该资源。让我们测试一下以确保这是真的!
  2. 点击评价结果正上方的Backlink
  3. 将 bob 的角色更改为 account_owner 并单击 Evaluate。您现在应该看到结果为 PERMIT。如果您返回并将角色更改为 bank_teller
  4. ,则同样如此

Evaluating and Testing Policies

创建Scope-Based权限

  1. 返回Permissions部分
  2. Select Scope-Based 这次在 Create Permission 下拉菜单下。
  3. Name下输入View Account Scope Permission
  4. Scopes下输入account:view
  5. Apply Policy下输入Only Account Owner Policy
  6. 确保 Decision Strategy 设置为 Unanimous
  7. 点击Save

参见 Creating Scope-Based Permissions

第二次测试运行

评估我们的新变化

  1. 返回Authorization部分
  2. 点击Evaluate
  3. 用户应该是 bob
  4. 角色应该是 bank_teller
  5. 资源应该是View Account Resource然后点击Add
  6. 点击Evaluate,我们应该得到DENY
    • 同样,这应该不足为奇,因为 bank_teller 可以访问 resource 但不能访问 scope。这里一个权限评估为真,另一个为假。鉴于资源服务器的Decision Strategy设置为Unanimous,最终决定为DENY
  7. 点击 Authorization 选项卡下的 Settings,将 Decision Strategy 更改为 Affirmative 并再次返回步骤 1-6。这一次,最终结果应该是PERMIT(一个权限为真,所以最终决定为真)。
  8. 为了完整起见,将资源服务器的Decision Strategy转回Unanimous。再次返回步骤 1 到 6,但这一次,将角色设置为 account_owner。这一次,最终结果又是 PERMIT,这是有道理的,因为 account_owner 可以访问 resourcescope

整洁 :) 希望这对您有所帮助。

我希望通过纯 HTTP 方法强制执行授权,而不使用适配器,因为 Lua 没有适配器。希望这个答案可以帮助人们寻找非基于适配器的方法。

如果您正在寻找适配器 quick start guide is the best place to start. Especially the spring boot authz example

对于纯基于 HTTP 的实现:

第 1 步:

Keycloak Admin UI

中定义策略和权限

步骤 2

对哪些 HTTP 路径属于哪些资源以及每个路径所需的范围进行内部映射。这也可以保存在configuration file中。调用特定路由时,调用 Keycloak 令牌端点以验证访问令牌的声明。

{
  "policy-enforcer": {
    "user-managed-access" : {},
    "enforcement-mode" : "ENFORCING"
    "paths": [
      {
        "path" : "/someUri/*",
        "methods" : [
          {
            "method": "GET",
            "scopes" : ["urn:app.com:scopes:view"]
          },
          {
            "method": "POST",
            "scopes" : ["urn:app.com:scopes:create"]
          }
        ]
      }
    ]
  }
}

如果您使用适配器且未指定路径或资源,适配器将在内部搜索路径和资源from Keycloak

第 3 步:

使用令牌端点 get or evaluate 权限。您可以使用 response_mode 参数来获得最终决定(是否提供访问权限)或检索全部权限。

curl -X POST \
  http://${host}:${port}/auth/realms/${realm}/protocol/openid-connect/token \
  -H "Authorization: Bearer ${access_token}" \
  --data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket" \
  --data "permission=Resource A#Scope A"

如果授权请求未映射到任何权限,则会返回 403 HTTP 状态代码。

我知道我来晚了,但让我尽可能多地解释一下。

在 keycloak 中,我们有这样的术语:

资源:用户将访问或执行操作的对象

授权范围:用户可以对特定对象执行的操作

政策:政策

Permission : 映射实际发生在这里

如果您不想遵循手动方式,您可以导出此 JSON 并且所有用户、资源、权限将自动设置 bu keycloak

JSON configuration file

现在让我们看一个场景:

现在我们几乎没有像这样的资源:

  1. 账户
  2. 机器人
  3. 举报

我们想要实现只有特定用户才能执行特定操作的场景。

设置 Keycloak

创建新领域

  1. 单击 添加领域 按钮。

  1. 输入 test-v1 作为名称。
  2. 点击创建。

创建新角色

  1. 单击角色
  2. 单击添加角色
  3. 创建角色“admin”、“agent”和“super_admin”

创建客户

  • 单击客户端 选项卡
  • 在客户端 ID 文本框中输入 app-client
  • 点击保存
  • Select 并再次选择客户端配置其他设置
  • 验证客户端协议是 openid-connect
  • 将访问类型设置为机密
  • 将授权启用设置为开
  • 最后点击保存按钮。
  • 新的授权 选项卡将出现在顶部。
  • Select 在授权选项卡上,然后是设置

检查决策策略是否设置为一致。这是资源服务器策略

创建自定义授权范围

转到授权 选项卡 Select 授权范围 > 然后单击 创建 在文本中输入 scopes:create & scopes:view 并保存值。

创建资源

  • 现在转到 资源 选项卡 > 然后单击 创建
  • 一一进入,创建如下资源res:account & res:bot & res :报告
  • 对于范围文本中的所有资源 select 我们早期创建的两个范围 scopes:create & scopes:view
  • 点击保存

创建策略

  • 再次在“授权”选项卡中,策略
  • 上的select
  • 单击 创建策略 下拉菜单和 select 角色
  • 在名称文本框中,Admin
  • 领域角色 select 角色 Admin
  • 检查逻辑设置为正
  • 单击保存,对“代理”和“Super_admin”执行相同操作

  • 再次在“授权”选项卡中,策略
  • 上的select
  • 单击 创建策略 下拉菜单和 select 聚合
  • 在名称文本框中,Admin 或 Super_admin 或 Agent
  • 在领域角色 select 角色 Admin & Super_admin & Agent
  • 检查逻辑设置为肯定
  • 点击保存

创建权限

  • 再次在“授权”选项卡中,select 权限
  • 单击 创建权限 下拉菜单和 select 基于范围的
  • 在名称文本框中,创建帐户
  • 在资源箱中,select“资源res:account”
  • 在范围 select、scopes:create
  • 应用策略管理员
  • 我们必须根据要求为所有资源设置相同的权限

创建用户

  • 在用户选项卡中创建一个 test 用户 我们不会为其分配任何角色、范围或组以进行测试

让我们评估一下

  • 再次在“授权”选项卡中,select 在 评估
  • Select我们创建的客户端,app-client
  • 在user select创建的用户,test
  • 在角色select中创建的用户,admin
  • 资源值,res:account
  • 单击添加 按钮
  • 单击评估按钮

您会看到授权是 permitted 因为 Admin 角色有权执行操作 create 查看资源帐户

让我们再评估一下

  • 再次在“授权”选项卡中,select 在 评估
  • Select我们创建的客户端,app-client
  • 在user select创建的用户,test
  • 在角色select中创建的用户,admin
  • 资源值,res:report
  • 范围值,范围:创建
  • 单击添加 按钮
  • 单击评估按钮

您会看到授予是 拒绝 因为只有 Super_Admin 角色有权执行操作 创建 资源 报告.

可以在此处找到具有资源、范围和权限的工作解决方案 keycloak-nodejs-example

只是 运行 已经使用 docker 配置了 Keycloak - 使用 Quick Start guide.

编写

项目中的其他有用示例

  • 不使用 Keycloak 登录页面的自定义登录。
  • 无状态 Node.js 服务器,不使用会话。 Keycloak 令牌使用 cookie 存储。
  • 一个用于检查权限的集中式中间件。没有明确描述的路线无法访问。
  • 没有 keycloak.json 的配置。它可用于为多个环境进行配置。例如 — DEV、QA。
  • 使用 Keycloak REST API 创建用户、角色和自定义属性的示例。