You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dolphinscheduler.apache.org by ca...@apache.org on 2022/04/20 10:23:34 UTC

[dolphinscheduler] branch dev updated: [Feature][Task] K8s namespace auth manager (#9303)

This is an automated email from the ASF dual-hosted git repository.

caishunfeng pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/dolphinscheduler.git


The following commit(s) were added to refs/heads/dev by this push:
     new 165d7aa51f [Feature][Task] K8s namespace auth manager (#9303)
165d7aa51f is described below

commit 165d7aa51f1be5aba86752b27067ec9888582acf
Author: qianli2022 <97...@users.noreply.github.com>
AuthorDate: Wed Apr 20 18:23:23 2022 +0800

    [Feature][Task] K8s namespace auth manager (#9303)
    
    * k8s auth
    
    * remove log
    
    * fix test
    
    * use constants
    
    * use constants K8S_LOCAL_TEST_CLUSTER
    
    * simple auth get
    
    * change test
    
    * add namespace authorize in user page
    
    * prettier code
    
    * change test data
    
    Co-authored-by: qianl4 <qi...@cicso.com>
    Co-authored-by: William Tong <we...@cisco.com>
---
 .../api/controller/K8sNamespaceController.java     |  91 +++++++++---
 .../api/controller/UsersController.java            |  26 ++++
 .../apache/dolphinscheduler/api/enums/Status.java  |   6 +-
 ...eSpaceService.java => K8sNamespaceService.java} |  39 ++++-
 .../dolphinscheduler/api/service/UsersService.java |  11 ++
 ...rviceImpl.java => K8SNamespaceServiceImpl.java} | 155 +++++++++++++++----
 .../api/service/impl/UsersServiceImpl.java         |  53 +++++++
 .../api/controller/K8sNamespaceControllerTest.java |  45 +++++-
 ...rviceTest.java => K8SNamespaceServiceTest.java} |  80 +++++++---
 .../api/service/UsersServiceTest.java              |  21 +++
 .../apache/dolphinscheduler/common/Constants.java  |   1 +
 .../dolphinscheduler/dao/entity/K8sNamespace.java  |  92 +++++++++---
 .../dao/entity/K8sNamespaceUser.java               | 164 +++++++++++++++++++++
 .../dao/mapper/K8sNamespaceMapper.java             |  26 ++++
 ...paceMapper.java => K8sNamespaceUserMapper.java} |  99 +++++++------
 .../dao/mapper/K8sNamespaceMapper.xml              |  33 ++++-
 ...espaceMapper.xml => K8sNamespaceUserMapper.xml} |  88 +++++------
 .../src/main/resources/sql/dolphinscheduler_h2.sql |  31 +++-
 .../main/resources/sql/dolphinscheduler_mysql.sql  |  17 ++-
 .../resources/sql/dolphinscheduler_postgresql.sql  |  19 ++-
 .../2.1.0_schema/mysql/dolphinscheduler_ddl.sql    |  19 ++-
 .../postgresql/dolphinscheduler_ddl.sql            |  16 +-
 .../src/locales/modules/en_US.ts                   |   2 +
 .../src/locales/modules/zh_CN.ts                   |   2 +
 .../src/service/modules/k8s-namespace/index.ts     |  17 +++
 .../src/service/modules/users/index.ts             |   9 ++
 .../src/service/modules/users/types.ts             |   5 +
 .../user-manage/components/authorize-modal.tsx     |   9 ++
 .../user-manage/components/use-authorize.ts        |  37 ++++-
 .../src/views/security/user-manage/types.ts        |   1 +
 .../src/views/security/user-manage/use-columns.ts  |   6 +-
 .../pages/namespace/_source/createNamespace.vue    |  23 +--
 .../security/pages/namespace/_source/list.vue      |   2 -
 .../pages/security/pages/users/_source/list.vue    |  52 ++++++-
 .../src/js/module/components/transfer/transfer.vue |   2 +
 .../src/js/module/i18n/locale/en_US.js             |   7 +-
 .../src/js/module/i18n/locale/zh_CN.js             |   3 +-
 37 files changed, 1074 insertions(+), 235 deletions(-)

diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/K8sNamespaceController.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/K8sNamespaceController.java
index ddae560d67..ac2e29534d 100644
--- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/K8sNamespaceController.java
+++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/K8sNamespaceController.java
@@ -19,18 +19,23 @@ package org.apache.dolphinscheduler.api.controller;
 
 import static org.apache.dolphinscheduler.api.enums.Status.CREATE_K8S_NAMESPACE_ERROR;
 import static org.apache.dolphinscheduler.api.enums.Status.DELETE_K8S_NAMESPACE_BY_ID_ERROR;
+import static org.apache.dolphinscheduler.api.enums.Status.QUERY_AUTHORIZED_NAMESPACE_ERROR;
+import static org.apache.dolphinscheduler.api.enums.Status.QUERY_CAN_USE_K8S_CLUSTER_ERROR;
 import static org.apache.dolphinscheduler.api.enums.Status.QUERY_K8S_NAMESPACE_LIST_PAGING_ERROR;
+import static org.apache.dolphinscheduler.api.enums.Status.QUERY_UNAUTHORIZED_NAMESPACE_ERROR;
 import static org.apache.dolphinscheduler.api.enums.Status.UPDATE_K8S_NAMESPACE_ERROR;
 import static org.apache.dolphinscheduler.api.enums.Status.VERIFY_K8S_NAMESPACE_ERROR;
 
 import org.apache.dolphinscheduler.api.aspect.AccessLogAnnotation;
 import org.apache.dolphinscheduler.api.exceptions.ApiException;
-import org.apache.dolphinscheduler.api.service.K8sNameSpaceService;
+import org.apache.dolphinscheduler.api.service.K8sNamespaceService;
 import org.apache.dolphinscheduler.api.utils.Result;
 import org.apache.dolphinscheduler.common.Constants;
 import org.apache.dolphinscheduler.common.utils.ParameterUtils;
+import org.apache.dolphinscheduler.dao.entity.K8sNamespace;
 import org.apache.dolphinscheduler.dao.entity.User;
 
+import java.util.List;
 import java.util.Map;
 
 import org.springframework.beans.factory.annotation.Autowired;
@@ -60,7 +65,7 @@ import springfox.documentation.annotations.ApiIgnore;
 public class K8sNamespaceController extends BaseController {
 
     @Autowired
-    private K8sNameSpaceService k8sNameSpaceService;
+    private K8sNamespaceService k8sNamespaceService;
 
     /**
      * query namespace list paging
@@ -92,7 +97,7 @@ public class K8sNamespaceController extends BaseController {
             return result;
         }
         searchVal = ParameterUtils.handleEscapes(searchVal);
-        result = k8sNameSpaceService.queryListPaging(loginUser, searchVal, pageNo, pageSize);
+        result = k8sNamespaceService.queryListPaging(loginUser, searchVal, pageNo, pageSize);
         return result;
     }
 
@@ -102,8 +107,6 @@ public class K8sNamespaceController extends BaseController {
      *
      * @param loginUser
      * @param namespace    k8s namespace
-     * @param owner        owner
-     * @param tag          Which type of job is available, can be empty, all available
      * @param k8s          k8s name
      * @param limitsCpu    max cpu
      * @param limitsMemory max memory
@@ -112,8 +115,6 @@ public class K8sNamespaceController extends BaseController {
     @ApiOperation(value = "createK8sNamespace", notes = "CREATE_NAMESPACE_NOTES")
     @ApiImplicitParams({
             @ApiImplicitParam(name = "namespace", value = "NAMESPACE", required = true, dataType = "String"),
-            @ApiImplicitParam(name = "owner", value = "OWNER", required = false, dataType = "String"),
-            @ApiImplicitParam(name = "tag", value = "TAG", required = false, dataType = "String"),
             @ApiImplicitParam(name = "k8s", value = "K8S", required = true, dataType = "String"),
             @ApiImplicitParam(name = "limits_cpu", value = "LIMITS_CPU", required = false, dataType = "Double"),
             @ApiImplicitParam(name = "limits_memory", value = "LIMITS_MEMORY", required = false, dataType = "Integer")
@@ -125,12 +126,10 @@ public class K8sNamespaceController extends BaseController {
     public Result createNamespace(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
                                   @RequestParam(value = "namespace") String namespace,
                                   @RequestParam(value = "k8s") String k8s,
-                                  @RequestParam(value = "owner", required = false) String owner,
-                                  @RequestParam(value = "tag", required = false) String tag,
                                   @RequestParam(value = "limitsCpu", required = false) Double limitsCpu,
                                   @RequestParam(value = "limitsMemory", required = false) Integer limitsMemory
     ) {
-        Map<String, Object> result =  k8sNameSpaceService.createK8sNamespace(loginUser, namespace, k8s, owner, tag, limitsCpu, limitsMemory);
+        Map<String, Object> result =  k8sNamespaceService.createK8sNamespace(loginUser, namespace, k8s, limitsCpu, limitsMemory);
         return returnDataList(result);
     }
 
@@ -138,8 +137,7 @@ public class K8sNamespaceController extends BaseController {
      * update namespace,namespace and k8s not allowed update, because may create on k8s,can delete and create new instead
      *
      * @param loginUser
-     * @param owner        owner
-     * @param tag          Which type of job is available,such as flink,means only flink job can use, can be empty, all available
+     * @param userName        owner
      * @param limitsCpu    max cpu
      * @param limitsMemory max memory
      * @return
@@ -147,8 +145,7 @@ public class K8sNamespaceController extends BaseController {
     @ApiOperation(value = "updateK8sNamespace", notes = "UPDATE_NAMESPACE_NOTES")
     @ApiImplicitParams({
             @ApiImplicitParam(name = "id", value = "K8S_NAMESPACE_ID", required = true, dataType = "Int", example = "100"),
-            @ApiImplicitParam(name = "owner", value = "OWNER", required = false, dataType = "String"),
-            @ApiImplicitParam(name = "tag", value = "TAG", required = false, dataType = "String"),
+            @ApiImplicitParam(name = "userName", value = "OWNER", required = false, dataType = "String"),
             @ApiImplicitParam(name = "limitsCpu", value = "LIMITS_CPU", required = false, dataType = "Double"),
             @ApiImplicitParam(name = "limitsMemory", value = "LIMITS_MEMORY", required = false, dataType = "Integer")})
     @PutMapping(value = "/{id}")
@@ -157,11 +154,11 @@ public class K8sNamespaceController extends BaseController {
     @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
     public Result updateNamespace(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
                                   @PathVariable(value = "id") int id,
-                                  @RequestParam(value = "owner", required = false) String owner,
+                                  @RequestParam(value = "userName", required = false) String userName,
                                   @RequestParam(value = "tag", required = false) String tag,
                                   @RequestParam(value = "limitsCpu", required = false) Double limitsCpu,
                                   @RequestParam(value = "limitsMemory", required = false) Integer limitsMemory) {
-        Map<String, Object> result = k8sNameSpaceService.updateK8sNamespace(loginUser, id, owner, tag, limitsCpu, limitsMemory);
+        Map<String, Object> result = k8sNamespaceService.updateK8sNamespace(loginUser, id, userName, limitsCpu, limitsMemory);
         return returnDataList(result);
     }
 
@@ -187,7 +184,7 @@ public class K8sNamespaceController extends BaseController {
                                   @RequestParam(value = "k8s") String k8s
     ) {
 
-        return k8sNameSpaceService.verifyNamespaceK8s(namespace, k8s);
+        return k8sNamespaceService.verifyNamespaceK8s(namespace, k8s);
     }
 
 
@@ -208,7 +205,65 @@ public class K8sNamespaceController extends BaseController {
     @AccessLogAnnotation
     public Result delNamespaceById(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
                                    @RequestParam(value = "id") int id) {
-        Map<String, Object> result = k8sNameSpaceService.deleteNamespaceById(loginUser, id);
+        Map<String, Object> result = k8sNamespaceService.deleteNamespaceById(loginUser, id);
+        return returnDataList(result);
+    }
+
+    /**
+     * query unauthorized namespace
+     *
+     * @param loginUser login user
+     * @param userId user id
+     * @return the namespaces which user have not permission to see
+     */
+    @ApiOperation(value = "queryUnauthorizedNamespace", notes = "QUERY_UNAUTHORIZED_NAMESPACE_NOTES")
+    @ApiImplicitParams({
+        @ApiImplicitParam(name = "userId", value = "USER_ID", dataType = "Int", example = "100")
+    })
+    @GetMapping(value = "/unauth-namespace")
+    @ResponseStatus(HttpStatus.OK)
+    @ApiException(QUERY_UNAUTHORIZED_NAMESPACE_ERROR)
+    @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
+    public Result queryUnauthorizedNamespace(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
+                                             @RequestParam("userId") Integer userId) {
+        Map<String, Object> result = k8sNamespaceService.queryUnauthorizedNamespace(loginUser, userId);
         return returnDataList(result);
     }
+
+    /**
+     * query unauthorized namespace
+     *
+     * @param loginUser login user
+     * @param userId user id
+     * @return namespaces which the user have permission to see
+     */
+    @ApiOperation(value = "queryAuthorizedNamespace", notes = "QUERY_AUTHORIZED_NAMESPACE_NOTES")
+    @ApiImplicitParams({
+        @ApiImplicitParam(name = "userId", value = "USER_ID", dataType = "Int", example = "100")
+    })
+    @GetMapping(value = "/authed-namespace")
+    @ResponseStatus(HttpStatus.OK)
+    @ApiException(QUERY_AUTHORIZED_NAMESPACE_ERROR)
+    @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
+    public Result queryAuthorizedNamespace(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
+                                           @RequestParam("userId") Integer userId) {
+        Map<String, Object> result = k8sNamespaceService.queryAuthorizedNamespace(loginUser, userId);
+        return returnDataList(result);
+    }
+
+    /**
+     * query namespace available
+     *
+     * @param loginUser login user
+     * @return namespace list
+     */
+    @ApiOperation(value = "queryAvailableNamespaceList", notes = "QUERY_AVAILABLE_NAMESPACE_LIST_NOTES")
+    @GetMapping(value = "/available-list")
+    @ResponseStatus(HttpStatus.OK)
+    @ApiException(QUERY_CAN_USE_K8S_CLUSTER_ERROR)
+    @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
+    public Result queryAvailableNamespaceList(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser) {
+        List<K8sNamespace> result = k8sNamespaceService.queryNamespaceAvailable(loginUser);
+        return success(result);
+    }
 }
diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/UsersController.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/UsersController.java
index 313958b22b..81f0041db0 100644
--- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/UsersController.java
+++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/UsersController.java
@@ -22,6 +22,7 @@ import static org.apache.dolphinscheduler.api.enums.Status.CREATE_USER_ERROR;
 import static org.apache.dolphinscheduler.api.enums.Status.DELETE_USER_BY_ID_ERROR;
 import static org.apache.dolphinscheduler.api.enums.Status.GET_USER_INFO_ERROR;
 import static org.apache.dolphinscheduler.api.enums.Status.GRANT_DATASOURCE_ERROR;
+import static org.apache.dolphinscheduler.api.enums.Status.GRANT_K8S_NAMESPACE_ERROR;
 import static org.apache.dolphinscheduler.api.enums.Status.GRANT_PROJECT_ERROR;
 import static org.apache.dolphinscheduler.api.enums.Status.GRANT_RESOURCE_ERROR;
 import static org.apache.dolphinscheduler.api.enums.Status.GRANT_UDF_FUNCTION_ERROR;
@@ -334,6 +335,31 @@ public class UsersController extends BaseController {
     }
 
 
+    /**
+     * grant namespace
+     *
+     * @param loginUser login user
+     * @param userId user id
+     * @param namespaceIds namespace id array
+     * @return grant result code
+     */
+    @ApiOperation(value = "grantNamespace", notes = "GRANT_NAMESPACE_NOTES")
+    @ApiImplicitParams({
+        @ApiImplicitParam(name = "userId", value = "USER_ID", required = true, dataType = "Int", example = "100"),
+        @ApiImplicitParam(name = "namespaceIds", value = "NAMESPACE_IDS", required = true, type = "String")
+    })
+    @PostMapping(value = "/grant-namespace")
+    @ResponseStatus(HttpStatus.OK)
+    @ApiException(GRANT_K8S_NAMESPACE_ERROR)
+    @AccessLogAnnotation
+    public Result grantNamespace(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
+                                 @RequestParam(value = "userId") int userId,
+                                 @RequestParam(value = "namespaceIds") String namespaceIds) {
+        Map<String, Object> result = usersService.grantNamespaces(loginUser, userId, namespaceIds);
+        return returnDataList(result);
+    }
+
+
     /**
      * grant datasource
      *
diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java
index 4954adf431..ff844ad96d 100644
--- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java
+++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java
@@ -394,7 +394,11 @@ public enum Status {
     VERIFY_K8S_NAMESPACE_ERROR(1300007, "verify k8s and namespace error", "验证k8s命名空间信息错误"),
     DELETE_K8S_NAMESPACE_BY_ID_ERROR(1300008, "delete k8s namespace by id error", "删除命名空间错误"),
     VERIFY_PARAMETER_NAME_FAILED(1300009, "The file name verify  failed", "文件命名校验失败"),
-    STORE_OPERATE_CREATE_ERROR(1300010, "create the resource failed", "存储操作失败");
+    STORE_OPERATE_CREATE_ERROR(1300010, "create the resource failed", "存储操作失败"),
+    GRANT_K8S_NAMESPACE_ERROR(1300011, "grant namespace error", "授权资源错误"),
+    QUERY_UNAUTHORIZED_NAMESPACE_ERROR(1300012, "query unauthorized namespace error", "查询未授权命名空间错误"),
+    QUERY_AUTHORIZED_NAMESPACE_ERROR(1300013, "query authorized namespace error", "查询授权命名空间错误"),
+    QUERY_CAN_USE_K8S_CLUSTER_ERROR(1300014, "login user query can used k8s cluster list error", "查询可用k8s集群错误");
 
     private final int code;
     private final String enMsg;
diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/K8sNameSpaceService.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/K8sNamespaceService.java
similarity index 71%
rename from dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/K8sNameSpaceService.java
rename to dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/K8sNamespaceService.java
index c9156a38f3..d56c8ab537 100644
--- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/K8sNameSpaceService.java
+++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/K8sNamespaceService.java
@@ -18,14 +18,16 @@
 package org.apache.dolphinscheduler.api.service;
 
 import org.apache.dolphinscheduler.api.utils.Result;
+import org.apache.dolphinscheduler.dao.entity.K8sNamespace;
 import org.apache.dolphinscheduler.dao.entity.User;
 
+import java.util.List;
 import java.util.Map;
 
 /**
  * k8s namespace service impl
  */
-public interface K8sNameSpaceService {
+public interface K8sNamespaceService {
     /**
      * query namespace list paging
      *
@@ -44,26 +46,23 @@ public interface K8sNameSpaceService {
      * @param loginUser    login user
      * @param namespace    namespace
      * @param k8s          k8s not null
-     * @param owner        owner can null
-     * @param tag          can null,if set means just used for one type job,such as flink,spark
      * @param limitsCpu    limits cpu, can null means not limit
      * @param limitsMemory limits memory, can null means not limit
      * @return
      */
-    Map<String, Object> createK8sNamespace(User loginUser, String namespace, String k8s, String owner, String tag, Double limitsCpu, Integer limitsMemory);
+    Map<String, Object> createK8sNamespace(User loginUser, String namespace, String k8s, Double limitsCpu, Integer limitsMemory);
 
 
     /**
      * update K8s Namespace tag and resource limit
      *
      * @param loginUser    login user
-     * @param owner        owner
-     * @param tag          Which type of job is available,such as flink,means only flink job can use, can be empty, all available
+     * @param userName     owner
      * @param limitsCpu    max cpu
      * @param limitsMemory max memory
      * @return
      */
-    Map<String, Object> updateK8sNamespace(User loginUser, int id, String owner, String tag, Double limitsCpu, Integer limitsMemory);
+    Map<String, Object> updateK8sNamespace(User loginUser, int id, String userName, Double limitsCpu, Integer limitsMemory);
 
     /**
      * verify namespace and k8s
@@ -82,4 +81,30 @@ public interface K8sNameSpaceService {
      * @return
      */
     Map<String, Object> deleteNamespaceById(User loginUser, int id);
+
+    /**
+     * query unauthorized namespace
+     *
+     * @param loginUser login user
+     * @param userId    user id
+     * @return the namespaces which user have not permission to see
+     */
+    Map<String, Object> queryUnauthorizedNamespace(User loginUser, Integer userId);
+
+    /**
+     * query unauthorized namespace
+     *
+     * @param loginUser login user
+     * @param userId    user id
+     * @return namespaces which the user have permission to see
+     */
+    Map<String, Object> queryAuthorizedNamespace(User loginUser, Integer userId);
+
+    /**
+     * query namespace can use
+     *
+     * @param loginUser login user
+     * @return namespace list
+     */
+    List<K8sNamespace> queryNamespaceAvailable(User loginUser);
 }
diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/UsersService.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/UsersService.java
index 3ae4c689b1..4a2afe547f 100644
--- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/UsersService.java
+++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/UsersService.java
@@ -194,6 +194,17 @@ public interface UsersService {
     Map<String, Object> grantUDFFunction(User loginUser, int userId, String udfIds);
 
 
+    /**
+     * grant namespace
+     *
+     * @param loginUser login user
+     * @param userId user id
+     * @param namespaceIds namespace id array
+     * @return grant result code
+     */
+    Map<String, Object> grantNamespaces(User loginUser, int userId, String namespaceIds);
+
+
     /**
      * grant datasource
      *
diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/K8sNameSpaceServiceImpl.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/K8SNamespaceServiceImpl.java
similarity index 66%
rename from dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/K8sNameSpaceServiceImpl.java
rename to dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/K8SNamespaceServiceImpl.java
index faa8a24cb3..f6e393f6ab 100644
--- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/K8sNameSpaceServiceImpl.java
+++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/K8SNamespaceServiceImpl.java
@@ -18,7 +18,7 @@
 package org.apache.dolphinscheduler.api.service.impl;
 
 import org.apache.dolphinscheduler.api.enums.Status;
-import org.apache.dolphinscheduler.api.service.K8sNameSpaceService;
+import org.apache.dolphinscheduler.api.service.K8sNamespaceService;
 import org.apache.dolphinscheduler.api.utils.PageInfo;
 import org.apache.dolphinscheduler.api.utils.Result;
 import org.apache.dolphinscheduler.common.Constants;
@@ -29,15 +29,20 @@ import org.apache.dolphinscheduler.service.k8s.K8sClientService;
 
 import org.apache.commons.lang.StringUtils;
 
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 
@@ -45,9 +50,9 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
  * k8s namespace service impl
  */
 @Service
-public class K8sNameSpaceServiceImpl extends BaseServiceImpl implements K8sNameSpaceService {
+public class K8SNamespaceServiceImpl extends BaseServiceImpl implements K8sNamespaceService {
 
-    private static final Logger logger = LoggerFactory.getLogger(K8sNameSpaceServiceImpl.class);
+    private static final Logger logger = LoggerFactory.getLogger(K8SNamespaceServiceImpl.class);
 
     private static String resourceYaml = "apiVersion: v1\n"
         + "kind: ResourceQuota\n"
@@ -100,14 +105,12 @@ public class K8sNameSpaceServiceImpl extends BaseServiceImpl implements K8sNameS
      * @param loginUser    login user
      * @param namespace    namespace
      * @param k8s          k8s not null
-     * @param owner        owner can null
-     * @param tag          can null,if set means just used for one type job,such as flink,spark
      * @param limitsCpu    limits cpu, can null means not limit
      * @param limitsMemory limits memory, can null means not limit
      * @return
      */
     @Override
-    public Map<String, Object> createK8sNamespace(User loginUser, String namespace, String k8s, String owner, String tag, Double limitsCpu, Integer limitsMemory) {
+    public Map<String, Object> createK8sNamespace(User loginUser, String namespace, String k8s, Double limitsCpu, Integer limitsMemory) {
         Map<String, Object> result = new HashMap<>();
         if (isNotAdmin(loginUser, result)) {
             return result;
@@ -143,8 +146,7 @@ public class K8sNameSpaceServiceImpl extends BaseServiceImpl implements K8sNameS
 
         k8sNamespaceObj.setNamespace(namespace);
         k8sNamespaceObj.setK8s(k8s);
-        k8sNamespaceObj.setOwner(owner);
-        k8sNamespaceObj.setTag(tag);
+        k8sNamespaceObj.setUserId(loginUser.getId());
         k8sNamespaceObj.setLimitsCpu(limitsCpu);
         k8sNamespaceObj.setLimitsMemory(limitsMemory);
         k8sNamespaceObj.setOnlineJobNum(0);
@@ -154,13 +156,15 @@ public class K8sNameSpaceServiceImpl extends BaseServiceImpl implements K8sNameS
         k8sNamespaceObj.setCreateTime(now);
         k8sNamespaceObj.setUpdateTime(now);
 
-        try {
-            String yamlStr = genDefaultResourceYaml(k8sNamespaceObj);
-            k8sClientService.upsertNamespaceAndResourceToK8s(k8sNamespaceObj, yamlStr);
-        } catch (Exception e) {
-            logger.error("namespace create to k8s error", e);
-            putMsg(result, Status.K8S_CLIENT_OPS_ERROR, e.getMessage());
-            return result;
+        if (!Constants.K8S_LOCAL_TEST_CLUSTER.equals(k8sNamespaceObj.getK8s())) {
+            try {
+                String yamlStr = genDefaultResourceYaml(k8sNamespaceObj);
+                k8sClientService.upsertNamespaceAndResourceToK8s(k8sNamespaceObj, yamlStr);
+            } catch (Exception e) {
+                logger.error("namespace create to k8s error", e);
+                putMsg(result, Status.K8S_CLIENT_OPS_ERROR, e.getMessage());
+                return result;
+            }
         }
 
         k8sNamespaceMapper.insert(k8sNamespaceObj);
@@ -173,14 +177,13 @@ public class K8sNameSpaceServiceImpl extends BaseServiceImpl implements K8sNameS
      * update K8s Namespace tag and resource limit
      *
      * @param loginUser    login user
-     * @param owner        owner
-     * @param tag          Which type of job is available,such as flink,means only flink job can use, can be empty, all available
+     * @param userName     owner
      * @param limitsCpu    max cpu
      * @param limitsMemory max memory
      * @return
      */
     @Override
-    public Map<String, Object> updateK8sNamespace(User loginUser, int id, String owner, String tag, Double limitsCpu, Integer limitsMemory) {
+    public Map<String, Object> updateK8sNamespace(User loginUser, int id, String userName, Double limitsCpu, Integer limitsMemory) {
         Map<String, Object> result = new HashMap<>();
         if (isNotAdmin(loginUser, result)) {
             return result;
@@ -203,18 +206,19 @@ public class K8sNameSpaceServiceImpl extends BaseServiceImpl implements K8sNameS
         }
 
         Date now = new Date();
-        k8sNamespaceObj.setTag(tag);
         k8sNamespaceObj.setLimitsCpu(limitsCpu);
         k8sNamespaceObj.setLimitsMemory(limitsMemory);
         k8sNamespaceObj.setUpdateTime(now);
-        k8sNamespaceObj.setOwner(owner);
-        try {
-            String yamlStr = genDefaultResourceYaml(k8sNamespaceObj);
-            k8sClientService.upsertNamespaceAndResourceToK8s(k8sNamespaceObj, yamlStr);
-        } catch (Exception e) {
-            logger.error("namespace update to k8s error", e);
-            putMsg(result, Status.K8S_CLIENT_OPS_ERROR, e.getMessage());
-            return result;
+
+        if (!Constants.K8S_LOCAL_TEST_CLUSTER.equals(k8sNamespaceObj.getK8s())) {
+            try {
+                String yamlStr = genDefaultResourceYaml(k8sNamespaceObj);
+                k8sClientService.upsertNamespaceAndResourceToK8s(k8sNamespaceObj, yamlStr);
+            } catch (Exception e) {
+                logger.error("namespace update to k8s error", e);
+                putMsg(result, Status.K8S_CLIENT_OPS_ERROR, e.getMessage());
+                return result;
+            }
         }
         // update to db
         k8sNamespaceMapper.updateById(k8sNamespaceObj);
@@ -271,8 +275,9 @@ public class K8sNameSpaceServiceImpl extends BaseServiceImpl implements K8sNameS
             putMsg(result, Status.K8S_NAMESPACE_NOT_EXIST, id);
             return result;
         }
-
-        k8sClientService.deleteNamespaceToK8s(k8sNamespaceObj.getNamespace(), k8sNamespaceObj.getK8s());
+        if (!Constants.K8S_LOCAL_TEST_CLUSTER.equals(k8sNamespaceObj.getK8s())) {
+            k8sClientService.deleteNamespaceToK8s(k8sNamespaceObj.getNamespace(), k8sNamespaceObj.getK8s());
+        }
         k8sNamespaceMapper.deleteById(id);
         putMsg(result, Status.SUCCESS);
         return result;
@@ -323,4 +328,96 @@ public class K8sNameSpaceServiceImpl extends BaseServiceImpl implements K8sNameS
         }
         return result;
     }
+
+
+    /**
+     * query unauthorized namespace
+     *
+     * @param loginUser login user
+     * @param userId    user id
+     * @return the namespaces which user have not permission to see
+     */
+    @Override
+    public Map<String, Object> queryUnauthorizedNamespace(User loginUser, Integer userId) {
+        Map<String, Object> result = new HashMap<>();
+        if (loginUser.getId() != userId && isNotAdmin(loginUser, result)) {
+            return result;
+        }
+        // query all namespace list,this auth does not like project
+        List<K8sNamespace> namespaceList = k8sNamespaceMapper.selectList(null);
+        List<K8sNamespace> resultList = new ArrayList<>();
+        Set<K8sNamespace> namespaceSet;
+        if (namespaceList != null && !namespaceList.isEmpty()) {
+            namespaceSet = new HashSet<>(namespaceList);
+            List<K8sNamespace> authedProjectList = k8sNamespaceMapper.queryAuthedNamespaceListByUserId(userId);
+            resultList = getUnauthorizedNamespaces(namespaceSet, authedProjectList);
+        }
+        result.put(Constants.DATA_LIST, resultList);
+        putMsg(result, Status.SUCCESS);
+        return result;
+    }
+
+    /**
+     * query authorized namespace
+     *
+     * @param loginUser login user
+     * @param userId    user id
+     * @return namespaces which the user have permission to see
+     */
+    @Override
+    public Map<String, Object> queryAuthorizedNamespace(User loginUser, Integer userId) {
+        Map<String, Object> result = new HashMap<>();
+
+        if (loginUser.getId() != userId && isNotAdmin(loginUser, result)) {
+            return result;
+        }
+
+        List<K8sNamespace> namespaces = k8sNamespaceMapper.queryAuthedNamespaceListByUserId(userId);
+        result.put(Constants.DATA_LIST, namespaces);
+        putMsg(result, Status.SUCCESS);
+
+        return result;
+    }
+
+    /**
+     * query namespace can use
+     *
+     * @param loginUser login user
+     * @return namespace list
+     */
+    @Override
+    public List<K8sNamespace> queryNamespaceAvailable(User loginUser) {
+        if (isAdmin(loginUser)) {
+            return k8sNamespaceMapper.selectList(null);
+        } else {
+            return k8sNamespaceMapper.queryNamespaceAvailable(loginUser.getId());
+        }
+    }
+
+    /**
+     * get unauthorized namespace
+     *
+     * @param namespaceSet        namespace set
+     * @param authedNamespaceList authed namespace list
+     * @return namespace list that authorization
+     */
+    private List<K8sNamespace> getUnauthorizedNamespaces(Set<K8sNamespace> namespaceSet, List<K8sNamespace> authedNamespaceList) {
+        List<K8sNamespace> resultList = new ArrayList<>();
+        for (K8sNamespace k8sNamespace : namespaceSet) {
+            boolean existAuth = false;
+            if (authedNamespaceList != null && !authedNamespaceList.isEmpty()) {
+                for (K8sNamespace k8sNamespaceAuth : authedNamespaceList) {
+                    if (k8sNamespace.equals(k8sNamespaceAuth)) {
+                        existAuth = true;
+                    }
+                }
+            }
+
+            if (!existAuth) {
+                resultList.add(k8sNamespace);
+            }
+        }
+        return resultList;
+    }
+
 }
diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/UsersServiceImpl.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/UsersServiceImpl.java
index f83ffbfba7..ac6b38adcc 100644
--- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/UsersServiceImpl.java
+++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/UsersServiceImpl.java
@@ -36,6 +36,7 @@ import org.apache.dolphinscheduler.common.utils.EncryptionUtils;
 import org.apache.dolphinscheduler.common.utils.PropertyUtils;
 import org.apache.dolphinscheduler.dao.entity.AlertGroup;
 import org.apache.dolphinscheduler.dao.entity.DatasourceUser;
+import org.apache.dolphinscheduler.dao.entity.K8sNamespaceUser;
 import org.apache.dolphinscheduler.dao.entity.Project;
 import org.apache.dolphinscheduler.dao.entity.ProjectUser;
 import org.apache.dolphinscheduler.dao.entity.Resource;
@@ -46,6 +47,7 @@ import org.apache.dolphinscheduler.dao.entity.User;
 import org.apache.dolphinscheduler.dao.mapper.AccessTokenMapper;
 import org.apache.dolphinscheduler.dao.mapper.AlertGroupMapper;
 import org.apache.dolphinscheduler.dao.mapper.DataSourceUserMapper;
+import org.apache.dolphinscheduler.dao.mapper.K8sNamespaceUserMapper;
 import org.apache.dolphinscheduler.dao.mapper.ProcessDefinitionMapper;
 import org.apache.dolphinscheduler.dao.mapper.ProjectMapper;
 import org.apache.dolphinscheduler.dao.mapper.ProjectUserMapper;
@@ -117,6 +119,9 @@ public class UsersServiceImpl extends BaseServiceImpl implements UsersService {
     @Autowired(required = false)
     private StorageOperate storageOperate;
 
+    @Autowired
+    private K8sNamespaceUserMapper k8sNamespaceUserMapper;
+
     /**
      * create user, only system admin have permission
      *
@@ -798,6 +803,54 @@ public class UsersServiceImpl extends BaseServiceImpl implements UsersService {
         return result;
     }
 
+
+    /**
+     * grant namespace
+     *
+     * @param loginUser    login user
+     * @param userId       user id
+     * @param namespaceIds namespace id array
+     * @return grant result code
+     */
+    @Override
+    @Transactional(rollbackFor = RuntimeException.class)
+    public Map<String, Object> grantNamespaces(User loginUser, int userId, String namespaceIds) {
+        Map<String, Object> result = new HashMap<>();
+        result.put(Constants.STATUS, false);
+
+        //only admin can operate
+        if (check(result, !isAdmin(loginUser), Status.USER_NO_OPERATION_PERM)) {
+            return result;
+        }
+
+        //check exist
+        User tempUser = userMapper.selectById(userId);
+        if (tempUser == null) {
+            putMsg(result, Status.USER_NOT_EXIST, userId);
+            return result;
+        }
+
+        k8sNamespaceUserMapper.deleteNamespaceRelation(0, userId);
+        if (StringUtils.isNotEmpty(namespaceIds)) {
+            String[] namespaceIdArr = namespaceIds.split(",");
+            for (String namespaceId : namespaceIdArr) {
+                Date now = new Date();
+                K8sNamespaceUser namespaceUser = new K8sNamespaceUser();
+                namespaceUser.setUserId(userId);
+                namespaceUser.setNamespaceId(Integer.parseInt(namespaceId));
+                namespaceUser.setPerm(7);
+                namespaceUser.setCreateTime(now);
+                namespaceUser.setUpdateTime(now);
+                k8sNamespaceUserMapper.insert(namespaceUser);
+            }
+        }
+
+        putMsg(result, Status.SUCCESS);
+
+        return result;
+    }
+
+
     /**
      * grant datasource
      *
diff --git a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/K8sNamespaceControllerTest.java b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/K8sNamespaceControllerTest.java
index 830943ba0d..d265ebb118 100644
--- a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/K8sNamespaceControllerTest.java
+++ b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/K8sNamespaceControllerTest.java
@@ -28,8 +28,12 @@ import org.apache.dolphinscheduler.api.utils.Result;
 import org.apache.dolphinscheduler.common.utils.JSONUtils;
 import org.apache.dolphinscheduler.dao.entity.User;
 
+import java.util.HashMap;
+import java.util.Map;
+
 import org.junit.Assert;
 import org.junit.Test;
+import org.mockito.Mockito;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.http.MediaType;
@@ -96,7 +100,7 @@ public class K8sNamespaceControllerTest extends AbstractControllerTest {
             .andExpect(content().contentType(MediaType.APPLICATION_JSON))
             .andReturn();
         Result result = JSONUtils.parseObject(mvcResult.getResponse().getContentAsString(), Result.class);
-        Assert.assertEquals(Status.K8S_CLIENT_OPS_ERROR.getCode(), result.getCode().intValue());
+        Assert.assertEquals(Status.SUCCESS.getCode(), result.getCode().intValue());
         logger.info("update queue return result:{}", mvcResult.getResponse().getContentAsString());
     }
 
@@ -137,7 +141,7 @@ public class K8sNamespaceControllerTest extends AbstractControllerTest {
     }
 
     @Test
-    public void delNamespaceById() throws Exception {
+    public void deleteNamespaceById() throws Exception {
         MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>();
         paramsMap.add("id", "1");
 
@@ -149,7 +153,42 @@ public class K8sNamespaceControllerTest extends AbstractControllerTest {
             .andReturn();
 
         Result result = JSONUtils.parseObject(mvcResult.getResponse().getContentAsString(), Result.class);
-        Assert.assertEquals(Status.DELETE_K8S_NAMESPACE_BY_ID_ERROR.getCode(), result.getCode().intValue());//there is no k8s cluster in test env
+        Assert.assertEquals(Status.SUCCESS.getCode(), result.getCode().intValue());//there is no k8s cluster in test env
+        logger.info(mvcResult.getResponse().getContentAsString());
+    }
+
+    @Test
+    public void testQueryUnauthorizedNamespace() throws Exception {
+
+        MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>();
+        paramsMap.add("userId", "1");
+
+        MvcResult mvcResult = mockMvc.perform(get("/k8s-namespace/unauth-namespace")
+            .header(SESSION_ID, sessionId)
+            .params(paramsMap))
+            .andExpect(status().isOk())
+            .andExpect(content().contentType(MediaType.APPLICATION_JSON))
+            .andReturn();
+
+        Result result = JSONUtils.parseObject(mvcResult.getResponse().getContentAsString(), Result.class);
+        Assert.assertEquals(Status.SUCCESS.getCode(), result.getCode().intValue());
+        logger.info(mvcResult.getResponse().getContentAsString());
+    }
+
+    @Test
+    public void testQueryAuthorizedNamespace() throws Exception {
+        MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>();
+        paramsMap.add("userId", "1");
+
+        MvcResult mvcResult = mockMvc.perform(get("/k8s-namespace/authed-namespace")
+            .header(SESSION_ID, sessionId)
+            .params(paramsMap))
+            .andExpect(status().isOk())
+            .andExpect(content().contentType(MediaType.APPLICATION_JSON))
+            .andReturn();
+
+        Result result = JSONUtils.parseObject(mvcResult.getResponse().getContentAsString(), Result.class);
+        Assert.assertEquals(Status.SUCCESS.getCode(), result.getCode().intValue());
         logger.info(mvcResult.getResponse().getContentAsString());
     }
 }
\ No newline at end of file
diff --git a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/K8sNameSpaceServiceTest.java b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/K8SNamespaceServiceTest.java
similarity index 64%
rename from dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/K8sNameSpaceServiceTest.java
rename to dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/K8SNamespaceServiceTest.java
index 26735565d1..3ab626c5a0 100644
--- a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/K8sNameSpaceServiceTest.java
+++ b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/K8SNamespaceServiceTest.java
@@ -18,7 +18,7 @@
 package org.apache.dolphinscheduler.api.service;
 
 import org.apache.dolphinscheduler.api.enums.Status;
-import org.apache.dolphinscheduler.api.service.impl.K8sNameSpaceServiceImpl;
+import org.apache.dolphinscheduler.api.service.impl.K8SNamespaceServiceImpl;
 import org.apache.dolphinscheduler.api.utils.PageInfo;
 import org.apache.dolphinscheduler.api.utils.Result;
 import org.apache.dolphinscheduler.common.Constants;
@@ -51,12 +51,12 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 
 @RunWith(MockitoJUnitRunner.class)
-public class K8sNameSpaceServiceTest {
+public class K8SNamespaceServiceTest {
 
-    private static final Logger logger = LoggerFactory.getLogger(K8sNameSpaceServiceTest.class);
+    private static final Logger logger = LoggerFactory.getLogger(K8SNamespaceServiceTest.class);
 
     @InjectMocks
-    private K8sNameSpaceServiceImpl k8sNameSpaceService;
+    private K8SNamespaceServiceImpl k8sNamespaceService;
 
     @Mock
     private K8sNamespaceMapper k8sNamespaceMapper;
@@ -86,7 +86,7 @@ public class K8sNameSpaceServiceTest {
         page.setTotal(1L);
         page.setRecords(getNamespaceList());
         Mockito.when(k8sNamespaceMapper.queryK8sNamespacePaging(Mockito.any(Page.class), Mockito.eq(namespace))).thenReturn(page);
-        Result result = k8sNameSpaceService.queryListPaging(getLoginUser(), namespace, 1, 10);
+        Result result = k8sNamespaceService.queryListPaging(getLoginUser(), namespace, 1, 10);
         logger.info(result.toString());
         PageInfo<K8sNamespace> pageInfo = (PageInfo<K8sNamespace>) result.getData();
         Assert.assertTrue(CollectionUtils.isNotEmpty(pageInfo.getTotalList()));
@@ -95,19 +95,19 @@ public class K8sNameSpaceServiceTest {
     @Test
     public void createK8sNamespace() {
         // namespace is null
-        Map<String, Object> result = k8sNameSpaceService.createK8sNamespace(getLoginUser(), null, k8s, null, "tag", 10.0, 100);
+        Map<String, Object> result = k8sNamespaceService.createK8sNamespace(getLoginUser(), null, k8s, 10.0, 100);
         logger.info(result.toString());
         Assert.assertEquals(Status.REQUEST_PARAMS_NOT_VALID_ERROR, result.get(Constants.STATUS));
         // k8s is null
-        result = k8sNameSpaceService.createK8sNamespace(getLoginUser(), namespace, null, null, "tag", 10.0, 100);
+        result = k8sNamespaceService.createK8sNamespace(getLoginUser(), namespace, null, 10.0, 100);
         logger.info(result.toString());
         Assert.assertEquals(Status.REQUEST_PARAMS_NOT_VALID_ERROR, result.get(Constants.STATUS));
         // correct
-        result = k8sNameSpaceService.createK8sNamespace(getLoginUser(), namespace, k8s, null, "tag", 10.0, 100);
+        result = k8sNamespaceService.createK8sNamespace(getLoginUser(), namespace, k8s, 10.0, 100);
         logger.info(result.toString());
         Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS));
         //null limit cpu and mem
-        result = k8sNameSpaceService.createK8sNamespace(getLoginUser(), namespace, k8s, null, "tag", null, null);
+        result = k8sNamespaceService.createK8sNamespace(getLoginUser(), namespace, k8s, null, null);
         logger.info(result.toString());
         Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS));
     }
@@ -116,15 +116,15 @@ public class K8sNameSpaceServiceTest {
     public void updateK8sNamespace() {
         Mockito.when(k8sNamespaceMapper.selectById(1)).thenReturn(getNamespace());
 
-        Map<String, Object> result = k8sNameSpaceService.updateK8sNamespace(getLoginUser(), 1, null, "tag", null, null);
+        Map<String, Object> result = k8sNamespaceService.updateK8sNamespace(getLoginUser(), 1, null, null, null);
         logger.info(result.toString());
         Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS));
 
-        result = k8sNameSpaceService.updateK8sNamespace(getLoginUser(), 1, null, "tag", -1.0, 100);
+        result = k8sNamespaceService.updateK8sNamespace(getLoginUser(), 1, null, -1.0, 100);
         logger.info(result.toString());
         Assert.assertEquals(Status.REQUEST_PARAMS_NOT_VALID_ERROR, result.get(Constants.STATUS));
 
-        result = k8sNameSpaceService.updateK8sNamespace(getLoginUser(), 1, null, "tag", 1.0, 100);
+        result = k8sNamespaceService.updateK8sNamespace(getLoginUser(), 1, null, 1.0, 100);
         logger.info(result.toString());
         Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS));
     }
@@ -135,22 +135,22 @@ public class K8sNameSpaceServiceTest {
         Mockito.when(k8sNamespaceMapper.existNamespace(namespace, k8s)).thenReturn(true);
 
         //namespace null
-        Result result = k8sNameSpaceService.verifyNamespaceK8s(null, k8s);
+        Result result = k8sNamespaceService.verifyNamespaceK8s(null, k8s);
         logger.info(result.toString());
         Assert.assertEquals(result.getCode().intValue(), Status.REQUEST_PARAMS_NOT_VALID_ERROR.getCode());
 
         //k8s null
-        result = k8sNameSpaceService.verifyNamespaceK8s(namespace, null);
+        result = k8sNamespaceService.verifyNamespaceK8s(namespace, null);
         logger.info(result.toString());
         Assert.assertEquals(result.getCode().intValue(), Status.REQUEST_PARAMS_NOT_VALID_ERROR.getCode());
 
         //exist
-        result = k8sNameSpaceService.verifyNamespaceK8s(namespace, k8s);
+        result = k8sNamespaceService.verifyNamespaceK8s(namespace, k8s);
         logger.info(result.toString());
         Assert.assertEquals(result.getCode().intValue(), Status.K8S_NAMESPACE_EXIST.getCode());
 
         //not exist
-        result = k8sNameSpaceService.verifyNamespaceK8s(namespace, "other k8s");
+        result = k8sNamespaceService.verifyNamespaceK8s(namespace, "other k8s");
         logger.info(result.toString());
         Assert.assertEquals(result.getCode().intValue(), Status.SUCCESS.getCode());
     }
@@ -160,11 +160,57 @@ public class K8sNameSpaceServiceTest {
         Mockito.when(k8sNamespaceMapper.deleteById(Mockito.any())).thenReturn(1);
         Mockito.when(k8sNamespaceMapper.selectById(1)).thenReturn(getNamespace());
 
-        Map<String, Object> result = k8sNameSpaceService.deleteNamespaceById(getLoginUser(), 1);
+        Map<String, Object> result = k8sNamespaceService.deleteNamespaceById(getLoginUser(), 1);
         logger.info(result.toString());
         Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS));
     }
 
+    @Test
+    public void testQueryAuthorizedNamespace() {
+        Mockito.when(k8sNamespaceMapper.queryAuthedNamespaceListByUserId(2)).thenReturn(getNamespaceList());
+
+        User loginUser = getLoginUser();
+
+        // test admin user
+        loginUser.setUserType(UserType.ADMIN_USER);
+        Map<String, Object> result = k8sNamespaceService.queryAuthorizedNamespace(loginUser, 2);
+        logger.info(result.toString());
+        List<K8sNamespace> namespaces = (List<K8sNamespace>) result.get(Constants.DATA_LIST);
+        Assert.assertTrue(CollectionUtils.isNotEmpty(namespaces));
+
+        // test non-admin user
+        loginUser.setUserType(UserType.GENERAL_USER);
+        loginUser.setId(3);
+        result = k8sNamespaceService.queryAuthorizedNamespace(loginUser, 2);
+        Assert.assertEquals(Status.USER_NO_OPERATION_PERM, result.get(Constants.STATUS));
+        namespaces = (List<K8sNamespace>) result.get(Constants.DATA_LIST);
+        Assert.assertTrue(CollectionUtils.isEmpty(namespaces));
+    }
+
+    @Test
+    public void testQueryUnAuthorizedNamespace() {
+        Mockito.when(k8sNamespaceMapper.queryAuthedNamespaceListByUserId(2)).thenReturn(new ArrayList<>());
+        Mockito.when(k8sNamespaceMapper.selectList(Mockito.any())).thenReturn(getNamespaceList());
+
+        // test admin user
+        User loginUser = new User();
+        loginUser.setUserType(UserType.ADMIN_USER);
+        Map<String, Object> result = k8sNamespaceService.queryUnauthorizedNamespace(loginUser, 2);
+        logger.info(result.toString());
+        List<K8sNamespace> namespaces = (List<K8sNamespace>) result.get(Constants.DATA_LIST);
+        Assert.assertTrue(CollectionUtils.isNotEmpty(namespaces));
+
+        // test non-admin user
+        loginUser.setId(2);
+        loginUser.setUserType(UserType.GENERAL_USER);
+        result = k8sNamespaceService.queryUnauthorizedNamespace(loginUser, 3);
+        logger.info(result.toString());
+        Assert.assertEquals(Status.USER_NO_OPERATION_PERM, result.get(Constants.STATUS));
+        namespaces = (List<K8sNamespace>) result.get(Constants.DATA_LIST);
+        Assert.assertTrue(CollectionUtils.isEmpty(namespaces));
+    }
+
+
     private User getLoginUser() {
 
         User loginUser = new User();
diff --git a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/UsersServiceTest.java b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/UsersServiceTest.java
index 596eba4d75..8eaba04c60 100644
--- a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/UsersServiceTest.java
+++ b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/UsersServiceTest.java
@@ -90,6 +90,9 @@ public class UsersServiceTest {
     @Mock
     private UDFUserMapper udfUserMapper;
 
+    @Mock
+    private K8sNamespaceUserMapper k8sNamespaceUserMapper;
+
     @Mock
     private ProjectMapper projectMapper;
 
@@ -434,6 +437,24 @@ public class UsersServiceTest {
         Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS));
     }
 
+    @Test
+    public void testGrantNamespaces() {
+        String namespaceIds = "100000,120000";
+        when(userMapper.selectById(1)).thenReturn(getUser());
+        User loginUser = new User();
+
+        //user not exist
+        loginUser.setUserType(UserType.ADMIN_USER);
+        Map<String, Object> result = usersService.grantNamespaces(loginUser, 2, namespaceIds);
+        logger.info(result.toString());
+        Assert.assertEquals(Status.USER_NOT_EXIST, result.get(Constants.STATUS));
+        //success
+        when(k8sNamespaceUserMapper.deleteNamespaceRelation(0,1)).thenReturn(1);
+        result = usersService.grantNamespaces(loginUser, 1, namespaceIds);
+        logger.info(result.toString());
+        Assert.assertEquals(Status.SUCCESS, result.get(Constants.STATUS));
+    }
+
     @Test
     public void testGrantDataSource() {
         String datasourceIds = "100000,120000";
diff --git a/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/Constants.java b/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/Constants.java
index 4199627f71..3d87af5ea8 100644
--- a/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/Constants.java
+++ b/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/Constants.java
@@ -816,4 +816,5 @@ public final class Constants {
     public static final String K8S = "k8s";
     public static final String LIMITS_CPU = "limitsCpu";
     public static final String LIMITS_MEMORY = "limitsMemory";
+    public static final String K8S_LOCAL_TEST_CLUSTER = "ds_null_k8s";
 }
diff --git a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/K8sNamespace.java b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/K8sNamespace.java
index d22e7bd520..e6864a58bd 100644
--- a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/K8sNamespace.java
+++ b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/K8sNamespace.java
@@ -37,54 +37,66 @@ public class K8sNamespace {
      */
     @TableField(value = "namespace")
     private String namespace;
+
     /**
      * total cpu limit
      */
     @TableField(value = "limits_cpu")
     private Double limitsCpu;
+
     /**
      * total memory limit,mi
      */
     private Integer limitsMemory;
+
     /**
      * owner
      */
-    @TableField(value = "owner")
-    private String owner;
+    @TableField(value = "user_id")
+    private int userId;
+
+    /**
+     * user name
+     */
+    @TableField(exist = false)
+    private String userName;
 
     /**
      * create_time
      */
     @TableField("create_time")
     private Date createTime;
+
     /**
      * update_time
      */
     @TableField("update_time")
     private Date updateTime;
+
     /**
-     * tag use for set this namespace allow run which type
+     * 1.00 = 1 cpu
      */
-    @TableField("tag")
-    private String tag;
-
     @TableField("pod_request_cpu")
     private Double podRequestCpu = 0.0;
+
     /**
      * Mi
      */
     @TableField("pod_request_memory")
     private Integer podRequestMemory = 0;
+
     /**
-     *
+     * replicas
      */
     @TableField("pod_replicas")
     private Integer podReplicas = 0;
+
     /**
      * online job
      */
     @TableField("online_job_num")
     private Integer onlineJobNum = 0;
+
     /**
      * k8s name
      */
@@ -123,12 +135,12 @@ public class K8sNamespace {
         this.limitsMemory = limitsMemory;
     }
 
-    public String getOwner() {
-        return owner;
+    public int getUserId() {
+        return userId;
     }
 
-    public void setOwner(String owner) {
-        this.owner = owner;
+    public void setUserId(int userId) {
+        this.userId = userId;
     }
 
     public Date getCreateTime() {
@@ -147,14 +159,6 @@ public class K8sNamespace {
         this.updateTime = updateTime;
     }
 
-    public String getTag() {
-        return tag;
-    }
-
-    public void setTag(String tag) {
-        this.tag = tag;
-    }
-
     public Integer getPodRequestMemory() {
         return podRequestMemory;
     }
@@ -194,4 +198,54 @@ public class K8sNamespace {
     public void setPodRequestCpu(Double podRequestCpu) {
         this.podRequestCpu = podRequestCpu;
     }
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    @Override
+    public String toString() {
+        return "K8sNamespace{" +
+            "id=" + id +
+            ", namespace=" + namespace +
+            ", limitsCpu=" + limitsCpu +
+            ", limitsMemory=" + limitsMemory +
+            ", userId=" + userId +
+            ", podRequestCpu=" + podRequestCpu +
+            ", podRequestMemory=" + podRequestMemory +
+            ", podReplicas=" + podReplicas +
+            ", k8s=" + k8s +
+            ", createTime=" + createTime +
+            ", updateTime=" + updateTime +
+            '}';
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        K8sNamespace k8sNamespace = (K8sNamespace) o;
+
+        if (id.equals(k8sNamespace.id)) {
+            return true;
+        }
+
+        return namespace.equals(k8sNamespace.namespace) && k8s.equals(k8sNamespace.k8s);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = id;
+        result = 31 * result + (k8s+namespace).hashCode();
+        return result;
+    }
 }
diff --git a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/K8sNamespaceUser.java b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/K8sNamespaceUser.java
new file mode 100644
index 0000000000..87a7a3ecc4
--- /dev/null
+++ b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/entity/K8sNamespaceUser.java
@@ -0,0 +1,164 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dolphinscheduler.dao.entity;
+
+import java.util.Date;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+
+/**
+ * k8s namespace and user relation
+ */
+@TableName("t_ds_relation_namespace_user")
+public class K8sNamespaceUser {
+    /**
+     * id
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private int id;
+
+    /**
+     * user id
+     */
+    @TableField("user_id")
+    private int userId;
+
+    /**
+     * namespace id
+     */
+    @TableField("namespace_id")
+    private int namespaceId;
+
+    /**
+     * k8s cluster
+     */
+    @TableField(exist = false)
+    private String k8s;
+
+    /**
+     * namespace name
+     */
+    @TableField(exist = false)
+    private String namespaceName;
+
+    /**
+     * user name
+     */
+    @TableField(exist = false)
+    private String userName;
+
+    /**
+     * permission
+     */
+    private int perm;
+
+    @TableField("create_time")
+    private Date createTime;
+
+    @TableField("update_time")
+    private Date updateTime;
+
+    public int getId() {
+        return id;
+    }
+
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    public int getUserId() {
+        return userId;
+    }
+
+    public void setUserId(int userId) {
+        this.userId = userId;
+    }
+
+    public int getNamespaceId() {
+        return namespaceId;
+    }
+
+    public void setNamespaceId(int namespaceId) {
+        this.namespaceId = namespaceId;
+    }
+
+    public String getK8s() {
+        return k8s;
+    }
+
+    public void setK8s(String k8s) {
+        this.k8s = k8s;
+    }
+
+    public String getNamespaceName() {
+        return namespaceName;
+    }
+
+    public void setNamespaceName(String namespaceName) {
+        this.namespaceName = namespaceName;
+    }
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    public int getPerm() {
+        return perm;
+    }
+
+    public void setPerm(int perm) {
+        this.perm = perm;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    public Date getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    @Override
+    public String toString() {
+        return "K8sNamespaceUser{" +
+            "id=" + id +
+            ", userId=" + userId +
+            ", namespaceId=" + namespaceId +
+            ", k8s=" + k8s +
+            ", namespaceName=" + namespaceName +
+            ", perm=" + perm +
+            ", createTime=" + createTime +
+            ", updateTime=" + updateTime +
+            '}';
+    }
+}
diff --git a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceMapper.java b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceMapper.java
index e804d55402..e8f80ebf3f 100644
--- a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceMapper.java
+++ b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceMapper.java
@@ -21,6 +21,8 @@ import org.apache.dolphinscheduler.dao.entity.K8sNamespace;
 
 import org.apache.ibatis.annotations.Param;
 
+import java.util.List;
+
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 
@@ -46,4 +48,28 @@ public interface K8sNamespaceMapper extends BaseMapper<K8sNamespace> {
      * @return true if exist else return null
      */
     Boolean existNamespace(@Param("namespace") String namespace, @Param("k8s") String k8s);
+
+    /**
+     * query namespace except userId
+     *
+     * @param userId userId
+     * @return namespace list
+     */
+    List<K8sNamespace> queryNamespaceExceptUserId(@Param("userId") int userId);
+
+    /**
+     * query authed namespace list by userId
+     *
+     * @param userId userId
+     * @return namespace list
+     */
+    List<K8sNamespace> queryAuthedNamespaceListByUserId(@Param("userId") int userId);
+
+    /**
+     * query namespace can use
+     *
+     * @param userId userId
+     * @return namespace list
+     */
+    List<K8sNamespace> queryNamespaceAvailable(@Param("userId") Integer userId);
 }
diff --git a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceMapper.java b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceUserMapper.java
similarity index 56%
copy from dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceMapper.java
copy to dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceUserMapper.java
index e804d55402..46723cc41d 100644
--- a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceMapper.java
+++ b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceUserMapper.java
@@ -1,49 +1,50 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.dolphinscheduler.dao.mapper;
-
-import org.apache.dolphinscheduler.dao.entity.K8sNamespace;
-
-import org.apache.ibatis.annotations.Param;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-
-/**
- * namespace interface
- */
-public interface K8sNamespaceMapper extends BaseMapper<K8sNamespace> {
-    /**
-     * k8s namespace page
-     *
-     * @param page      page
-     * @param searchVal searchVal
-     * @return k8s namespace IPage
-     */
-    IPage<K8sNamespace> queryK8sNamespacePaging(IPage<K8sNamespace> page,
-                                                @Param("searchVal") String searchVal);
-
-    /**
-     * check the target namespace exist
-     *
-     * @param namespace namespace
-     * @param k8s       k8s name
-     * @return true if exist else return null
-     */
-    Boolean existNamespace(@Param("namespace") String namespace, @Param("k8s") String k8s);
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dolphinscheduler.dao.mapper;
+
+import org.apache.dolphinscheduler.dao.entity.K8sNamespaceUser;
+
+import org.apache.ibatis.annotations.Param;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * namespace user mapper interface
+ */
+public interface K8sNamespaceUserMapper extends BaseMapper<K8sNamespaceUser> {
+
+    /**
+     * delete namespace user relation
+     *
+     * @param namespaceId namespaceId
+     * @param userId      userId
+     * @return delete result
+     */
+    int deleteNamespaceRelation(@Param("namespaceId") int namespaceId,
+                                @Param("userId") int userId);
+
+    /**
+     * query namespace relation
+     *
+     * @param namespaceId namespaceId
+     * @param userId      userId
+     * @return namespace user relation
+     */
+    K8sNamespaceUser queryNamespaceRelation(@Param("namespaceId") int namespaceId,
+                                            @Param("userId") int userId);
+}
diff --git a/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceMapper.xml b/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceMapper.xml
index 9099e0c411..ba32fc2b12 100644
--- a/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceMapper.xml
+++ b/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceMapper.xml
@@ -20,8 +20,13 @@
 <mapper namespace="org.apache.dolphinscheduler.dao.mapper.K8sNamespaceMapper">
 
     <sql id="baseSql">
-        id, namespace, k8s, owner, tag, limits_memory, limits_cpu, online_job_num, pod_replicas, pod_request_cpu, pod_request_memory, create_time, update_time
+        id, namespace, k8s, user_id, limits_memory, limits_cpu, online_job_num, pod_replicas, pod_request_cpu, pod_request_memory, create_time, update_time
     </sql>
+
+    <sql id="baseSqlV2">
+        ${alias}.id, ${alias}.namespace, ${alias}.k8s, ${alias}.user_id, ${alias}.limits_memory, ${alias}.limits_cpu, ${alias}.online_job_num, ${alias}.pod_replicas, ${alias}.pod_request_cpu, ${alias}.pod_request_memory, ${alias}.create_time, ${alias}.update_time
+    </sql>
+
     <select id="queryK8sNamespacePaging" resultType="org.apache.dolphinscheduler.dao.entity.K8sNamespace">
         select
         <include refid="baseSql"/>
@@ -45,4 +50,30 @@
         </if>
     </select>
 
+    <select id="queryNamespaceExceptUserId" resultType="org.apache.dolphinscheduler.dao.entity.K8sNamespace">
+        select
+        <include refid="baseSql"/>
+        from t_ds_k8s_namespace
+        where user_id <![CDATA[ <> ]]> #{userId}
+    </select>
+
+    <select id="queryAuthedNamespaceListByUserId" resultType="org.apache.dolphinscheduler.dao.entity.K8sNamespace">
+        select
+        <include refid="baseSqlV2">
+            <property name="alias" value="p"/>
+        </include>
+        from t_ds_k8s_namespace p,t_ds_relation_namespace_user rel
+        where p.id = rel.namespace_id and rel.user_id= #{userId}
+    </select>
+
+    <select id="queryNamespaceAvailable" resultType="org.apache.dolphinscheduler.dao.entity.K8sNamespace">
+        select
+        <include refid="baseSqlV2">
+            <property name="alias" value="b"/>
+        </include>
+        from ( select namespace_id  from t_ds_relation_namespace_user where user_id= #{userId} ) a
+        left join  t_ds_k8s_namespace b
+        on b.id = a.namespace_id
+        where b.id is not null
+    </select>
 </mapper>
diff --git a/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceMapper.xml b/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceUserMapper.xml
similarity index 51%
copy from dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceMapper.xml
copy to dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceUserMapper.xml
index 9099e0c411..7e26039b99 100644
--- a/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceMapper.xml
+++ b/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/K8sNamespaceUserMapper.xml
@@ -1,48 +1,40 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~ Licensed to the Apache Software Foundation (ASF) under one or more
-  ~ contributor license agreements.  See the NOTICE file distributed with
-  ~ this work for additional information regarding copyright ownership.
-  ~ The ASF licenses this file to You under the Apache License, Version 2.0
-  ~ (the "License"); you may not use this file except in compliance with
-  ~ the License.  You may obtain a copy of the License at
-  ~
-  ~     http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="org.apache.dolphinscheduler.dao.mapper.K8sNamespaceMapper">
-
-    <sql id="baseSql">
-        id, namespace, k8s, owner, tag, limits_memory, limits_cpu, online_job_num, pod_replicas, pod_request_cpu, pod_request_memory, create_time, update_time
-    </sql>
-    <select id="queryK8sNamespacePaging" resultType="org.apache.dolphinscheduler.dao.entity.K8sNamespace">
-        select
-        <include refid="baseSql"/>
-        from t_ds_k8s_namespace
-        where 1= 1
-        <if test="searchVal != null and searchVal != ''">
-            and namespace like concat('%', #{searchVal}, '%')
-        </if>
-        order by update_time desc
-    </select>
-
-    <select id="existNamespace" resultType="java.lang.Boolean">
-        select 1 = 1
-        from t_ds_k8s_namespace
-        where 1 = 1
-        <if test="namespace != null and namespace != ''">
-            and namespace = #{namespace}
-        </if>
-        <if test="k8s != null and k8s != ''">
-            and k8s =#{k8s}
-        </if>
-    </select>
-
-</mapper>
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+<mapper namespace="org.apache.dolphinscheduler.dao.mapper.K8sNamespaceUserMapper">
+    <sql id="baseSql">
+        id, user_id, namespace_id, perm, create_time, update_time
+    </sql>
+    <delete id="deleteNamespaceRelation">
+        delete from t_ds_relation_namespace_user
+        where 1=1
+        and user_id = #{userId}
+        <if test="namespaceId != 0 ">
+            and namespace_id = #{namespaceId}
+        </if>
+    </delete>
+    <select id="queryNamespaceRelation" resultType="org.apache.dolphinscheduler.dao.entity.K8sNamespaceUser">
+        select
+        <include refid="baseSql"/>
+        from t_ds_relation_namespace_user
+        where namespace_id = #{namespaceId}
+        and user_id = #{userId}
+        limit 1
+    </select>
+</mapper>
\ No newline at end of file
diff --git a/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_h2.sql b/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_h2.sql
index 7fd9dc8256..f6cfae00e0 100644
--- a/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_h2.sql
+++ b/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_h2.sql
@@ -1898,11 +1898,10 @@ CREATE TABLE t_ds_k8s_namespace (
     limits_memory      int(11) DEFAULT NULL,
     namespace          varchar(100) DEFAULT NULL,
     online_job_num     int(11) DEFAULT NULL,
-    owner              varchar(100) DEFAULT NULL,
+    user_id            int(11) DEFAULT NULL,
     pod_replicas       int(11) DEFAULT NULL,
     pod_request_cpu    decimal(14,3) DEFAULT NULL,
     pod_request_memory int(11) DEFAULT NULL,
-    tag                varchar(100) DEFAULT NULL,
     limits_cpu         decimal(14,3) DEFAULT NULL,
     k8s                varchar(100) DEFAULT NULL,
     create_time        datetime DEFAULT NULL ,
@@ -1914,8 +1913,32 @@ CREATE TABLE t_ds_k8s_namespace (
 -- ----------------------------
 -- Records of t_ds_k8s_namespace
 -- ----------------------------
-INSERT INTO t_ds_k8s_namespace
-VALUES (1, 10000, 'default', 99, 'owner',1,NULL,1,'test',NULL,'default',null,null);
+INSERT INTO `t_ds_k8s_namespace`
+(`id`,`limits_memory`,`namespace`,`online_job_num`,`user_id`,`pod_replicas`,`pod_request_cpu`,`pod_request_memory`,`limits_cpu`,`k8s`,`create_time`,`update_time`)
+VALUES (1, 1000, 'flink_test', 99, 1, 1, 0.1, 1, NULL, 'ds_null_k8s',  '2022-03-03 11:31:24.0', '2022-03-03 11:31:24.0');
+
+INSERT INTO `t_ds_k8s_namespace`
+(`id`,`limits_memory`,`namespace`,`online_job_num`,`user_id`,`pod_replicas`,`pod_request_cpu`,`pod_request_memory`,`limits_cpu`,`k8s`,`create_time`,`update_time`)
+VALUES (2, 500, 'spark_test', 90, 2,1,10000,1, NULL, 'ds_null_k8s', '2021-03-03 11:31:24.0', '2021-03-03 11:31:24.0');
+
+INSERT INTO `t_ds_k8s_namespace`
+(`id`,`limits_memory`,`namespace`,`online_job_num`,`user_id`,`pod_replicas`,`pod_request_cpu`,`pod_request_memory`,`limits_cpu`,`k8s`,`create_time`,`update_time`)
+VALUES (3, 200, 'auth_test', 68, 3,1,100,1, 10000, 'ds_null_k8s', '2020-03-03 11:31:24.0', '2020-03-03 11:31:24.0');
+
+-- ----------------------------
+-- Table structure for t_ds_relation_namespace_user
+-- ----------------------------
+DROP TABLE IF EXISTS t_ds_relation_namespace_user;
+CREATE TABLE t_ds_relation_namespace_user (
+    id                int(11) NOT NULL AUTO_INCREMENT ,
+    user_id           int(11) NOT NULL ,
+    namespace_id      int(11) NOT NULL ,
+    perm              int(11) DEFAULT '1' ,
+    create_time       datetime DEFAULT NULL ,
+    update_time       datetime DEFAULT NULL ,
+    PRIMARY KEY (id) ,
+    UNIQUE KEY namespace_user_unique (user_id,namespace_id)
+);
 
 -- ----------------------------
 -- Table structure for t_ds_alert_send_status
diff --git a/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_mysql.sql b/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_mysql.sql
index 051ea1d006..197173a1b8 100644
--- a/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_mysql.sql
+++ b/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_mysql.sql
@@ -1891,11 +1891,10 @@ CREATE TABLE `t_ds_k8s_namespace` (
   `limits_memory` int(11) DEFAULT NULL,
   `namespace` varchar(100) DEFAULT NULL,
   `online_job_num` int(11) DEFAULT NULL,
-  `owner` varchar(100) DEFAULT NULL,
+  `user_id` int(11) DEFAULT NULL,
   `pod_replicas` int(11) DEFAULT NULL,
   `pod_request_cpu` decimal(14,3) DEFAULT NULL,
   `pod_request_memory` int(11) DEFAULT NULL,
-  `tag` varchar(100) DEFAULT NULL,
   `limits_cpu` decimal(14,3) DEFAULT NULL,
   `k8s` varchar(100) DEFAULT NULL,
   `create_time` datetime DEFAULT NULL COMMENT 'create time',
@@ -1904,6 +1903,20 @@ CREATE TABLE `t_ds_k8s_namespace` (
   UNIQUE KEY `k8s_namespace_unique` (`namespace`,`k8s`)
 ) ENGINE= INNODB AUTO_INCREMENT= 1 DEFAULT CHARSET= utf8;
 
+-- ----------------------------
+-- Table structure for t_ds_relation_namespace_user
+-- ----------------------------
+DROP TABLE IF EXISTS `t_ds_relation_namespace_user`;
+CREATE TABLE `t_ds_relation_namespace_user` (
+  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'key',
+  `user_id` int(11) NOT NULL COMMENT 'user id',
+  `namespace_id` int(11) DEFAULT NULL COMMENT 'namespace id',
+  `perm` int(11) DEFAULT '1' COMMENT 'limits of authority',
+  `create_time` datetime DEFAULT NULL COMMENT 'create time',
+  `update_time` datetime DEFAULT NULL COMMENT 'update time',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `namespace_user_unique` (`user_id`,`namespace_id`)
+) ENGINE=InnoDB AUTO_INCREMENT= 1 DEFAULT CHARSET= utf8;
 
 -- ----------------------------
 -- Table structure for t_ds_alert_send_status
diff --git a/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_postgresql.sql b/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_postgresql.sql
index 9e9c64d089..7e5526976f 100644
--- a/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_postgresql.sql
+++ b/dolphinscheduler-dao/src/main/resources/sql/dolphinscheduler_postgresql.sql
@@ -1889,11 +1889,10 @@ CREATE TABLE t_ds_k8s_namespace (
    limits_memory      int DEFAULT NULL ,
    namespace          varchar(100) DEFAULT NULL ,
    online_job_num     int DEFAULT '0' ,
-   owner              varchar(100) DEFAULT NULL,
+   user_id            int DEFAULT NULL,
    pod_replicas       int DEFAULT NULL,
    pod_request_cpu    NUMERIC(13,4) NULL,
    pod_request_memory int DEFAULT NULL,
-   tag                varchar(100) DEFAULT NULL,
    limits_cpu         NUMERIC(13,4) NULL,
    k8s                varchar(100) DEFAULT NULL,
    create_time        timestamp DEFAULT NULL ,
@@ -1902,6 +1901,22 @@ CREATE TABLE t_ds_k8s_namespace (
    CONSTRAINT k8s_namespace_unique UNIQUE (namespace,k8s)
 );
 
+--
+-- Table structure for table t_ds_relation_namespace_user
+--
+
+DROP TABLE IF EXISTS t_ds_relation_namespace_user;
+CREATE TABLE t_ds_relation_namespace_user (
+    id serial NOT NULL,
+    user_id           int DEFAULT NULL ,
+    namespace_id      int DEFAULT NULL ,
+    perm              int DEFAULT NULL ,
+    create_time       timestamp DEFAULT NULL ,
+    update_time       timestamp DEFAULT NULL ,
+    PRIMARY KEY (id) ,
+    CONSTRAINT namespace_user_unique UNIQUE (user_id,namespace_id)
+);
+
 -- ----------------------------
 -- Table structure for t_ds_alert_send_status
 -- ----------------------------
diff --git a/dolphinscheduler-dao/src/main/resources/sql/upgrade/2.1.0_schema/mysql/dolphinscheduler_ddl.sql b/dolphinscheduler-dao/src/main/resources/sql/upgrade/2.1.0_schema/mysql/dolphinscheduler_ddl.sql
index ac08027dd6..4f0dacaf9d 100644
--- a/dolphinscheduler-dao/src/main/resources/sql/upgrade/2.1.0_schema/mysql/dolphinscheduler_ddl.sql
+++ b/dolphinscheduler-dao/src/main/resources/sql/upgrade/2.1.0_schema/mysql/dolphinscheduler_ddl.sql
@@ -199,11 +199,10 @@ CREATE TABLE `t_ds_k8s_namespace` (
   `limits_memory` int(11) DEFAULT NULL,
   `namespace` varchar(100) DEFAULT NULL,
   `online_job_num` int(11) DEFAULT NULL,
-  `owner` varchar(100) DEFAULT NULL,
+  `user_id` int(11) DEFAULT NULL,
   `pod_replicas` int(11) DEFAULT NULL,
   `pod_request_cpu` decimal(14,3) DEFAULT NULL,
   `pod_request_memory` int(11) DEFAULT NULL,
-  `tag` varchar(100) DEFAULT NULL,
   `limits_cpu` decimal(14,3) DEFAULT NULL,
   `k8s` varchar(100) DEFAULT NULL,
   `create_time` datetime DEFAULT NULL COMMENT 'create time',
@@ -211,3 +210,19 @@ CREATE TABLE `t_ds_k8s_namespace` (
   PRIMARY KEY (`id`),
   UNIQUE KEY `k8s_namespace_unique` (`namespace`,`k8s`)
 ) ENGINE= INNODB AUTO_INCREMENT= 1 DEFAULT CHARSET= utf8;
+
+-- ----------------------------
+-- Table structure for t_ds_relation_namespace_user
+-- ----------------------------
+DROP TABLE IF EXISTS `t_ds_relation_namespace_user`;
+CREATE TABLE `t_ds_relation_namespace_user` (
+  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'key',
+  `user_id` int(11) NOT NULL COMMENT 'user id',
+  `namespace_id` int(11) DEFAULT NULL COMMENT 'namespace id',
+  `perm` int(11) DEFAULT '1' COMMENT 'limits of authority',
+  `create_time` datetime DEFAULT NULL COMMENT 'create time',
+  `update_time` datetime DEFAULT NULL COMMENT 'update time',
+  PRIMARY KEY (`id`),
+  KEY `user_id_index` (`user_id`),
+  UNIQUE KEY `namespace_user_unique` (`user_id`,`namespace_id`)
+) ENGINE=InnoDB AUTO_INCREMENT= 1 DEFAULT CHARSET= utf8;
\ No newline at end of file
diff --git a/dolphinscheduler-dao/src/main/resources/sql/upgrade/2.1.0_schema/postgresql/dolphinscheduler_ddl.sql b/dolphinscheduler-dao/src/main/resources/sql/upgrade/2.1.0_schema/postgresql/dolphinscheduler_ddl.sql
index 9e2459f82d..e3d7b8c568 100644
--- a/dolphinscheduler-dao/src/main/resources/sql/upgrade/2.1.0_schema/postgresql/dolphinscheduler_ddl.sql
+++ b/dolphinscheduler-dao/src/main/resources/sql/upgrade/2.1.0_schema/postgresql/dolphinscheduler_ddl.sql
@@ -180,12 +180,11 @@ EXECUTE 'CREATE TABLE IF NOT EXISTS '|| quote_ident(v_schema) ||'."t_ds_k8s_name
    id serial NOT NULL,
    limits_memory      int DEFAULT NULL ,
    namespace          varchar(100) DEFAULT NULL ,
-   online_job_num     int DEFAULT ''0'' ,
-   owner              varchar(100) DEFAULT NULL,
+   online_job_num     int DEFAULT NULL,
+   user_id            int DEFAULT NULL,
    pod_replicas       int DEFAULT NULL,
    pod_request_cpu    NUMERIC(13,4) NULL,
    pod_request_memory int DEFAULT NULL,
-   tag                varchar(100) DEFAULT NULL,
    limits_cpu         NUMERIC(13,4) NULL,
    k8s                varchar(100) DEFAULT NULL,
    create_time        timestamp DEFAULT NULL ,
@@ -194,6 +193,17 @@ EXECUTE 'CREATE TABLE IF NOT EXISTS '|| quote_ident(v_schema) ||'."t_ds_k8s_name
    CONSTRAINT k8s_namespace_unique UNIQUE (namespace,k8s)
 )';
 
+EXECUTE 'CREATE TABLE IF NOT EXISTS '|| quote_ident(v_schema) ||'."t_ds_relation_namespace_user" (
+    id serial NOT NULL,
+    user_id           int DEFAULT NULL ,
+    namespace_id      int DEFAULT NULL ,
+    perm              int DEFAULT NULL ,
+    create_time       timestamp DEFAULT NULL ,
+    update_time       timestamp DEFAULT NULL ,
+    PRIMARY KEY (id) ,
+    CONSTRAINT namespace_user_unique UNIQUE (user_id,namespace_id)
+)';
+
 return 'Success!';
 exception when others then
 		---Raise EXCEPTION '(%)',SQLERRM;
diff --git a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts b/dolphinscheduler-ui-next/src/locales/modules/en_US.ts
index 1f00751a79..c785a70170 100644
--- a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts
+++ b/dolphinscheduler-ui-next/src/locales/modules/en_US.ts
@@ -1045,8 +1045,10 @@ const security = {
     udf_resource: 'UDF Resource',
     datasource: 'Datasource',
     udf: 'UDF Function',
+    namespace: 'Namespace',
     authorize_project: 'Project Authorize',
     authorize_resource: 'Resource Authorize',
+    authorize_namespace: 'Namespace Authorize',
     authorize_datasource: 'Datasource Authorize',
     authorize_udf: 'UDF Function Authorize',
     username: 'Username',
diff --git a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts b/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
index e590d67524..c8a3d47aa7 100644
--- a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
+++ b/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
@@ -1032,8 +1032,10 @@ const security = {
     udf_resource: 'UDF资源',
     datasource: '数据源',
     udf: 'UDF函数',
+    namespace: '命名空间',
     authorize_project: '项目授权',
     authorize_resource: '资源授权',
+    authorize_namespace: '命名空间授权',
     authorize_datasource: '数据源授权',
     authorize_udf: 'UDF函数授权',
     username: '用户名',
diff --git a/dolphinscheduler-ui-next/src/service/modules/k8s-namespace/index.ts b/dolphinscheduler-ui-next/src/service/modules/k8s-namespace/index.ts
index 69aaae9684..2df1d5f703 100644
--- a/dolphinscheduler-ui-next/src/service/modules/k8s-namespace/index.ts
+++ b/dolphinscheduler-ui-next/src/service/modules/k8s-namespace/index.ts
@@ -17,6 +17,7 @@
 
 import { axios } from '@/service/service'
 import { ListReq, K8SReq } from './types'
+import { UserIdReq } from '@/service/modules/resources/types'
 
 export function queryNamespaceListPaging(params: ListReq): any {
   return axios({
@@ -60,3 +61,19 @@ export function delNamespaceById(id: number): any {
     params: { id }
   })
 }
+
+export function authNamespaceFunc(params: UserIdReq): any {
+  return axios({
+    url: '/k8s-namespace/authed-namespace',
+    method: 'get',
+    params
+  })
+}
+
+export function unAuthNamespaceFunc(params: UserIdReq): any {
+  return axios({
+    url: '/k8s-namespace/unauth-namespace',
+    method: 'get',
+    params
+  })
+}
diff --git a/dolphinscheduler-ui-next/src/service/modules/users/index.ts b/dolphinscheduler-ui-next/src/service/modules/users/index.ts
index bd42f40a65..9a1313cbfb 100644
--- a/dolphinscheduler-ui-next/src/service/modules/users/index.ts
+++ b/dolphinscheduler-ui-next/src/service/modules/users/index.ts
@@ -28,6 +28,7 @@ import {
   GrantProject,
   ProjectCodeReq,
   GrantUDFReq,
+  GrantNamespaceReq,
   ListAllReq,
   ListReq,
   RegisterUserReq
@@ -120,6 +121,14 @@ export function grantUDFFunc(data: GrantUDFReq & UserIdReq) {
   })
 }
 
+export function grantNamespaceFunc(data: GrantNamespaceReq & UserIdReq) {
+  return axios({
+    url: '/users/grant-namespace',
+    method: 'post',
+    data
+  })
+}
+
 export function listUser(): any {
   return axios({
     url: '/users/list',
diff --git a/dolphinscheduler-ui-next/src/service/modules/users/types.ts b/dolphinscheduler-ui-next/src/service/modules/users/types.ts
index 3768d22b14..a49370560c 100644
--- a/dolphinscheduler-ui-next/src/service/modules/users/types.ts
+++ b/dolphinscheduler-ui-next/src/service/modules/users/types.ts
@@ -66,6 +66,10 @@ interface GrantUDFReq {
   udfIds: string
 }
 
+interface GrantNamespaceReq {
+  namespaceIds: string
+}
+
 interface ListAllReq extends UserReq {
   alertGroup?: string
   createTime?: string
@@ -127,6 +131,7 @@ export {
   GrantProject,
   ProjectCodeReq,
   GrantUDFReq,
+  GrantNamespaceReq,
   ListAllReq,
   ListReq,
   RegisterUserReq,
diff --git a/dolphinscheduler-ui-next/src/views/security/user-manage/components/authorize-modal.tsx b/dolphinscheduler-ui-next/src/views/security/user-manage/components/authorize-modal.tsx
index 0118299f40..bce9c567c6 100644
--- a/dolphinscheduler-ui-next/src/views/security/user-manage/components/authorize-modal.tsx
+++ b/dolphinscheduler-ui-next/src/views/security/user-manage/components/authorize-modal.tsx
@@ -151,6 +151,15 @@ export const AuthorizeModal = defineComponent({
             />
           </NSpace>
         )}
+        {type === 'authorize_namespace' && (
+          <NTransfer
+            virtualScroll
+            options={this.unauthorizedNamespaces}
+            filterable
+            v-model:value={this.authorizedNamespaces}
+            class={styles.transfer}
+          />
+        )}
       </Modal>
     )
   }
diff --git a/dolphinscheduler-ui-next/src/views/security/user-manage/components/use-authorize.ts b/dolphinscheduler-ui-next/src/views/security/user-manage/components/use-authorize.ts
index f12b6a3219..819a7a444f 100644
--- a/dolphinscheduler-ui-next/src/views/security/user-manage/components/use-authorize.ts
+++ b/dolphinscheduler-ui-next/src/views/security/user-manage/components/use-authorize.ts
@@ -29,11 +29,16 @@ import {
   authUDFFunc,
   unAuthUDFFunc
 } from '@/service/modules/resources'
+import {
+  authNamespaceFunc,
+  unAuthNamespaceFunc
+} from '@/service/modules/k8s-namespace'
 import {
   grantProject,
   grantResource,
   grantDataSource,
-  grantUDFFunc
+  grantUDFFunc,
+  grantNamespaceFunc
 } from '@/service/modules/users'
 import { removeUselessChildren } from '@/utils/tree-format'
 import type { TAuthType, IResourceOption, IOption } from '../types'
@@ -48,6 +53,8 @@ export function useAuthorize() {
     unauthorizedDatasources: [] as IOption[],
     authorizedUdfs: [] as number[],
     unauthorizedUdfs: [] as IOption[],
+    authorizedNamespaces: [] as number[],
+    unauthorizedNamespaces: [] as IOption[],
     resourceType: 'file',
     fileResources: [] as IResourceOption[],
     udfResources: [] as IResourceOption[],
@@ -139,6 +146,25 @@ export function useAuthorize() {
     state.authorizedUdfResources = udfTargets
   }
 
+  const getNamespaces = async (userId: number) => {
+    if (state.loading) return
+    state.loading = true
+    const namespaces = await Promise.all([
+      authNamespaceFunc({ userId }),
+      unAuthNamespaceFunc({ userId })
+    ])
+    state.loading = false
+    state.authorizedNamespaces = namespaces[0].map(
+      (item: { id: number }) => item.id
+    )
+    state.unauthorizedNamespaces = [...namespaces[0], ...namespaces[1]].map(
+      (item: { namespace: string; id: number }) => ({
+        label: item.namespace,
+        value: item.id
+      })
+    )
+  }
+
   const onInit = (type: TAuthType, userId: number) => {
     if (type === 'authorize_project') {
       getProjects(userId)
@@ -152,6 +178,9 @@ export function useAuthorize() {
     if (type === 'authorize_resource') {
       getResources(userId)
     }
+    if (type === 'authorize_namespace') {
+      getNamespaces(userId)
+    }
   }
 
   /*
@@ -242,6 +271,12 @@ export function useAuthorize() {
         resourceIds: allPathId.join(',')
       })
     }
+    if (type === 'authorize_namespace') {
+      await grantNamespaceFunc({
+        userId,
+        namespaceIds: state.authorizedNamespaces.join(',')
+      })
+    }
     state.saving = false
     return true
   }
diff --git a/dolphinscheduler-ui-next/src/views/security/user-manage/types.ts b/dolphinscheduler-ui-next/src/views/security/user-manage/types.ts
index ac8c1fc8a6..8c98d222fa 100644
--- a/dolphinscheduler-ui-next/src/views/security/user-manage/types.ts
+++ b/dolphinscheduler-ui-next/src/views/security/user-manage/types.ts
@@ -27,6 +27,7 @@ type TAuthType =
   | 'authorize_resource'
   | 'authorize_datasource'
   | 'authorize_udf'
+  | 'authorize_namespace'
 
 interface IRecord {
   id: number
diff --git a/dolphinscheduler-ui-next/src/views/security/user-manage/use-columns.ts b/dolphinscheduler-ui-next/src/views/security/user-manage/use-columns.ts
index 288b2b6343..f0af7aec9c 100644
--- a/dolphinscheduler-ui-next/src/views/security/user-manage/use-columns.ts
+++ b/dolphinscheduler-ui-next/src/views/security/user-manage/use-columns.ts
@@ -137,7 +137,11 @@ export function useColumns(onCallback: Function) {
                       label: t('security.user.datasource'),
                       key: 'authorize_datasource'
                     },
-                    { label: t('security.user.udf'), key: 'authorize_udf' }
+                    { label: t('security.user.udf'), key: 'authorize_udf' },
+                    {
+                      label: t('security.user.namespace'),
+                      key: 'authorize_namespace'
+                    }
                   ],
                   onSelect: (key) =>
                     void onCallback({ rowData, key }, 'authorize')
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/namespace/_source/createNamespace.vue b/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/namespace/_source/createNamespace.vue
index 3d0903e85d..42e2459307 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/namespace/_source/createNamespace.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/namespace/_source/createNamespace.vue
@@ -48,18 +48,6 @@
             </el-input>
           </template>
         </m-list-box-f>
-        <m-list-box-f>
-          <template slot="name">{{$t('K8s Tag')}}</template>
-          <template slot="content">
-            <el-input
-              type="input"
-              v-model="tag"
-              maxlength="60"
-              size="mini"
-              :placeholder="$t('Please enter k8s cluster')">
-            </el-input>
-          </template>
-        </m-list-box-f>
 
         <m-list-box-f>
           <template slot="name">{{$t('Limits Cpu')}}</template>
@@ -90,7 +78,7 @@
           <template slot="content">
             <el-input
               type="input"
-              v-model="owner"
+              v-model="userName"
               maxlength="60"
               size="mini"
               :placeholder="$t('Please enter owner')">
@@ -116,8 +104,7 @@
         store,
         namespace: '',
         k8s: '',
-        owner: '',
-        tag: '',
+        userName: '',
         limitsCpu: '',
         limitsMemory: ''
       }
@@ -134,8 +121,7 @@
         let param = {
           namespace: _.trim(this.namespace),
           k8s: _.trim(this.k8s),
-          owner: _.trim(this.owner),
-          tag: _.trim(this.tag),
+          userName: _.trim(this.userName),
           limitsCpu: _.trim(this.limitsCpu),
           limitsMemory: _.trim(this.limitsMemory)
         }
@@ -205,8 +191,7 @@
       if (this.item) {
         this.namespace = this.item.namespace
         this.k8s = this.item.k8s
-        this.owner = this.item.owner
-        this.tag = this.item.tag
+        this.userName = this.item.userName
         this.limitsCpu = this.item.limitsCpu
         this.limitsMemory = this.item.limitsMemory
       }
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/namespace/_source/list.vue b/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/namespace/_source/list.vue
index 73153b8851..ee4e571b7c 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/namespace/_source/list.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/namespace/_source/list.vue
@@ -21,8 +21,6 @@
         <el-table-column type="index" :label="$t('#')" width="50"></el-table-column>
         <el-table-column prop="namespace" :label="$t('K8s Namespace')"></el-table-column>
         <el-table-column prop="k8s" :label="$t('K8s Cluster')"></el-table-column>
-        <el-table-column prop="owner" :label="$t('Namespace Owner')"></el-table-column>
-        <el-table-column prop="tag" :label="$t('K8s Tag')"></el-table-column>
         <el-table-column prop="limitsCpu" :label="$t('Limits Cpu')"></el-table-column>
         <el-table-column prop="limitsMemory" :label="$t('Limits Memory')"></el-table-column>
 
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/users/_source/list.vue b/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/users/_source/list.vue
index 212060bb7b..4978a27289 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/users/_source/list.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/users/_source/list.vue
@@ -58,6 +58,7 @@
                   <el-dropdown-item @click.native="_authFile(scope.row,scope.$index)">{{$t('Resources')}}</el-dropdown-item>
                   <el-dropdown-item @click.native="_authDataSource(scope.row,scope.$index)">{{$t('Datasource')}}</el-dropdown-item>
                   <el-dropdown-item @click.native="_authUdfFunc(scope.row,scope.$index)">{{$t('UDF Function')}}</el-dropdown-item>
+                  <el-dropdown-item @click.native="_authNamespace(scope.row,scope.$index)">{{$t('K8s Namespace')}}</el-dropdown-item>
                 </el-dropdown-menu>
               </el-dropdown>
             </el-tooltip>
@@ -107,6 +108,13 @@
       width="auto">
       <m-resource :resourceData="resourceData" @onUpdateAuthResource="onUpdateAuthResource" @closeAuthResource="closeAuthResource"></m-resource>
     </el-dialog>
+
+    <el-dialog
+      v-if="authNamespaceDialog"
+      :visible.sync="authNamespaceDialog"
+      width="auto">
+      <m-transfer :transferData="transferData" @onUpdateAuthNamespace="onUpdateAuthNamespace" @closeAuthNamespace="closeAuthNamespace"></m-transfer>
+    </el-dialog>
   </div>
 </template>
 <script>
@@ -141,7 +149,8 @@
             name: ''
           }
         },
-        resourceDialog: false
+        resourceDialog: false,
+        authNamespaceDialog: false
       }
     },
     props: {
@@ -348,6 +357,35 @@
           this.$message.error(e.msg || '')
         })
       },
+
+      _authNamespace (item, i) {
+        this.getAuthList({
+          id: item.id,
+          type: 'namespace',
+          category: 'k8s-namespace'
+        }).then(data => {
+          let sourceListPrs = _.map(data[0], v => {
+            return {
+              id: v.id,
+              name: v.namespace
+            }
+          })
+          let targetListPrs = _.map(data[1], v => {
+            return {
+              id: v.id,
+              name: v.namespace
+            }
+          })
+          this.item = item
+          this.transferData.sourceListPrs = sourceListPrs
+          this.transferData.targetListPrs = targetListPrs
+          this.transferData.type.name = i18n.$t('K8s Namespace')
+          this.authNamespaceDialog = true
+        }).catch(e => {
+          this.$message.error(e.msg || '')
+        })
+      },
+
       onUpdateAuthUdfFunc (udfIds) {
         this._grantAuthorization('users/grant-udf-func', {
           userId: this.item.id,
@@ -360,6 +398,18 @@
         this.authUdfFuncDialog = false
       },
 
+      onUpdateAuthNamespace (namespaceIds) {
+        this._grantAuthorization('users/grant-namespace', {
+          userId: this.item.id,
+          namespaceIds: namespaceIds
+        })
+        this.authNamespaceDialog = false
+      },
+
+      closeAuthNamespace () {
+        this.authNamespaceDialog = false
+      },
+
       _grantAuthorization (api, param) {
         this.grantAuthorization({
           api: api,
diff --git a/dolphinscheduler-ui/src/js/module/components/transfer/transfer.vue b/dolphinscheduler-ui/src/js/module/components/transfer/transfer.vue
index 3cb29f77ac..b671b6c5b6 100644
--- a/dolphinscheduler-ui/src/js/module/components/transfer/transfer.vue
+++ b/dolphinscheduler-ui/src/js/module/components/transfer/transfer.vue
@@ -81,6 +81,8 @@
             this.$emit('onUpdateAuthDataSource', _.map(this.targetList, v => v.id).join(','))
           } else if (this.transferData.type.name === `${i18n.$t('UDF Function')}`) {
             this.$emit('onUpdateAuthUdfFunc', _.map(this.targetList, v => v.id).join(','))
+          } else if (this.transferData.type.name === `${i18n.$t('K8s Namespace')}`) {
+            this.$emit('onUpdateAuthNamespace', _.map(this.targetList, v => v.id).join(','))
           }
         }, 800)
       },
diff --git a/dolphinscheduler-ui/src/js/module/i18n/locale/en_US.js b/dolphinscheduler-ui/src/js/module/i18n/locale/en_US.js
index 515d16be07..4c330f6d7f 100755
--- a/dolphinscheduler-ui/src/js/module/i18n/locale/en_US.js
+++ b/dolphinscheduler-ui/src/js/module/i18n/locale/en_US.js
@@ -906,14 +906,13 @@ export default {
   'Create namespace': 'Create namespace',
   'Edit namespace': 'Edit namespace',
   'Namespace manage': 'K8s namespace manage',
-  'K8s Namespace': 'k8s Namespace',
+  'K8s Namespace': 'K8s Namespace',
   'Limits Cpu': 'Limit Cpu',
   'Limits Memory': 'Limit Memory',
-  'K8s Cluster': 'k8s',
+  'K8s Cluster': 'k8s Cluster',
   'Namespace Owner': 'Owner',
   'Please enter k8s cluster': 'Please enter k8s cluster',
   'Please enter namespace': 'Please enter namespace',
   'Please enter namespace tag': 'Please enter namespace tag can null',
-  'Please enter owner': 'Please enter owner can null',
-  'K8s Tag': 'tag'
+  'Please enter owner': 'Please enter owner can null'
 }
diff --git a/dolphinscheduler-ui/src/js/module/i18n/locale/zh_CN.js b/dolphinscheduler-ui/src/js/module/i18n/locale/zh_CN.js
index fe1fba85db..8fd53fc298 100755
--- a/dolphinscheduler-ui/src/js/module/i18n/locale/zh_CN.js
+++ b/dolphinscheduler-ui/src/js/module/i18n/locale/zh_CN.js
@@ -914,6 +914,5 @@ export default {
   'Please enter k8s cluster': '请输入k8s集群值',
   'Please enter namespace': '请输入命名空间',
   'Please enter namespace tag': '请输入命名空间标签可空',
-  'Please enter owner': '请输入owner可空',
-  'K8s Tag': '标签'
+  'Please enter owner': '请输入owner可空'
 }