Skip to content

[Feat] Cluster Authorization By Env 支持按环境给用户授权集群管理权限 #5301

Description

@spaceluke

需求:

#4372

新用户按环境授权,无法直接作用于集群,只能作用于集群的namespace。

支持按环境给用户授权集群管理权限,如查看、更改和发布。

** 实际上集群就是跟着环境走的,集群 = App 在某个 Env 下的一种划分 **

现状

实际上,从Permission这张表里面可以看得到,对于一个应用(App)的对应权限有如下权限的划分

image

  • App 管理员

    应用管理员具有以下权限: 1. 创建 Namespace 2. 创建Cluster 3. 管理App、Namespace 权限

  • App-Namespace 维度的Namespace管理员(分为两种权限)

    • 更改(Modify)
    • 发布(Release)
  • App-Namespace-Env 维度的Namespace管理员 (分为两种权限)

    • 更改(Modify)
    • 发布(Release)

方案:

  • Permission 侧:

    新增两种PermissionType,ModifyCluster 和 ReleaseCluster。代表在Cluster维度的修改和发布的权利,即可以修改和发布Env-Cluster下所有Namespace。

    对应的TargetId格式为 AppId + Env + ClusterName

  • Role 侧:

    新增RoleNameModifyCluster+TargetIdReleaseCluster+TargetId

image (1)

Management/Subjective

在Portal新增三个接口,获取、赋予、移除Cluster相关的权限Permission。

OpenApi处暂时没有支持相关管理能力。

Management/Passive

需要在Cluster被创建的时候进行RoleInitialize,Cluster在下面几个场景会被创建:

  1. 创建App时,默认在每个Env下创建一个default集群
  2. 指定给某个Env创建App时,默认创建default集群
  3. 在portal端指定App-Env创建Cluster
image (2)

第一种创建默认的Cluster的场景,Portal是完全不感知的,只知道自己向对应Env发送了创建App的请求,创建Cluster的逻辑完全在AdminService端,只能在创建完远端App之后,默认Cluster也创建成功。

由于权限系统只存在于Portal,三条创建Cluster的链路在Portal端是没有交集的,完全不同,因此需要在三个地方都加上initializeClusterRole的逻辑。(以后或许是可以优化的点)

Usage/Anno&Api

目前来说,Namespace的权限校验相关功能,现有的系统的调用链路还是比较统一的,比如说ModifyNamespace权限校验基本都是调用的hasModifyNamespacePermission 这个接口。

这对于要新加入的ModifyCluster权限就不太合适了,首先方法的语义就不相同,ModifyNamespace是ModifyCluster的子集。如果要在这个接口里面再做对Cluster权限的校验也不合适,因为参数列表里面没有传递ClusterName。

所以可以得到结论:要实现Cluster级别权限的需求,必定要在原有的代码上进行修改了,也就是这个注解:

@PreAuthorize(value = "@permissionValidator.hasModifyNamespacePermission(#appId, #namespaceName, #env)")

目前来说有两种实现方式:

  1. 修改参数列表,接收四个String
@PreAuthorize(value = "@permissionValidator.hasModifyNamespacePermission(#appId, #env, #clusterNam, #namespaceName)")
  1. 多加一个方法hasModifyClusterPermission,在注解表达式中用 or 加进去。
@PreAuthorize(value = "@permissionValidator.hasModifyNamespacePermission(#appId, #namespaceName, #env) " 
      + "or @permissionValidator.hasModifyClusterPermission(#appId, #env, #clusterName)")

两种方法其实都对原本代码是破坏性的,所以还是打算先选择第二种方法,**对原本的功能的影响尽可能的少。**如有需要,后续再对权限校验进行重构。

测试报告

后端集成测试

主要写了两个集成测试,从Usage和Management两个方面入手

ItemControllerAuthIntegrationTest:测试是否有权限时,对需鉴权接口的访问情况

  /**
   * Test cluster permission denied.
   */
  @Test
  public void testCreateItemPermissionDenied() {
    setUserId("xxx");
    try {
      HttpHeaders headers = new HttpHeaders();
      headers.set("Content-Type", "application/json");

      HttpEntity<String> entity = new HttpEntity<>(GSON.toJson(itemDTO), headers);

      restTemplate.postForEntity(
          url("/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/item"),
          entity, String.class, appId, env, clusterName, namespaceName);

      fail("should throw");
    } catch (final HttpClientErrorException e) {
      assertEquals(HttpStatus.FORBIDDEN, e.getStatusCode());
    }
  }

PermissionControllerTest:测试Cluster Role的管理端整个生命周期(初始化,assign,get,remove)

  @Test
  @Sql(scripts = "/sql/cleanup.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
  public void testClusterRoleLifeCycle() {

    HttpHeaders headers = new HttpHeaders();
    headers.set("Content-Type", "application/json");
    HttpEntity<String> entity = new HttpEntity<>(user, headers);

    // check role not assigned
    ResponseEntity<ClusterRolesAssignedUsers> beforeAssign = restTemplate.getForEntity(
        url("/apps/{appId}/envs/{env}/clusters/{clusterName}/role_users"),
        ClusterRolesAssignedUsers.class, appId, env, clusterName);
    assertEquals(200, beforeAssign.getStatusCodeValue());
    ClusterRolesAssignedUsers body = beforeAssign.getBody();
    assertNotNull(body);
    assertEquals(appId, body.getAppId());
    assertEquals(env, body.getEnv());
    assertEquals(clusterName, body.getCluster());
    assertTrue(body.getModifyRoleUsers() == null || body.getModifyRoleUsers().isEmpty());

    // assign role to user
    restTemplate.postForEntity(
        url("/apps/{appId}/envs/{env}/clusters/{clusterName}/roles/{roleType}"), entity, Void.class,
        appId, env, clusterName, roleType);

    // check role assigned
    ...
    // remove role from user
    ...
    // check role removed
    ...
  }

整体Portal端验收测试

  1. 创建好测试环境和集群
image (3)
  1. 给开发账号luke授予boe_feat_123的Modify和Release权限
image (5) image (4)
  1. 登录luke账号,查看集群Namespace,在boe_feat_123有权限,在default没有权限
image (6) image (7)
  1. 正常测试创建配置、修改、发布等功能
image (8) image (9) image (10)

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/portalapollo-portalfeature requestCategorizes issue as related to a new feature.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions