hive任务提交的相关权限认证详析

WBOY
풀어 주다: 2016-06-07 16:57:53
원래의
1231명이 탐색했습니다.

最近在研究Hue,遇到一个问题,在HiveEditor写一个HQL,提交后会报权限错误,类似这样的Authorizationfailed:NoprivilegeSelectfoundforinputs&n..

    最近在研究Hue,遇到一个问题,在Hive Editor写一个HQL,提交后会报权限错误,类似这样的

Authorization failed:No privilege 'Select' found for inputs {database:xxx, table:xxx, columnName:xxx}. Use show grant to get more details.

    Hue的登录用户是hadoop,使用cli方式查询的时候,是没问题的,但是使用Hue连接HiveServer2的方式,就查询不了对应的表了,排除Hue的干扰,使用Beeline来连接HiveServer2,同样报权限的错误,堆栈信息如下图



wKiom1O1KT_jKAZdAAyGT2bPY6U498.jpg


    根据堆栈信息大概梳理了下源码(只列出比较重要的代码),Hive提交SQL的权限验证流程如下

    Driver.compile(String command, boolean resetTaskIds){       if (HiveConf.getBoolVar(conf,           HiveConf.ConfVars.HIVE_AUTHORIZATION_ENABLED)) {         try {           perfLogger.PerfLogBegin(LOG, PerfLogger.DO_AUTHORIZATION);           //进行权限校验           doAuthorization(sem);         }      }      Driver.doAuthorization(BaseSemanticAnalyzer sem){         //判断op的操作类型为QUERY         if (op.equals(HiveOperation.CREATETABLE_AS_SELECT)               || op.equals(HiveOperation.QUERY)) {             if (cols != null && cols.size() > 0) {                 //进行更具体的验证                 ss.getAuthorizer().authorize(tbl, null, cols,                     op.getInputRequiredPrivileges(), null);             }          }      }      BitSetCheckedAuthorizationProvider.authorize(Table table, Partition part, List columns,Privilege[] inputRequiredPriv, Privilege[] outputRequiredPriv){             //验证用户对DB和Table的权限             authorizeUserDBAndTable(table, inputRequiredPriv, outputRequiredPriv,inputCheck,outputCheck)             //验证用户对Table中column的权限             for (String col : columns) {                 PrincipalPrivilegeSet partColumnPrivileges = hive_db                       .get_privilege_set(HiveObjectType.COLUMN, table.getDbName(),table.getTableName(),partValues, col,this.getAuthenticator().getUserName(), this.getAuthenticator().getGroupNames());                 authorizePrivileges(partColumnPrivileges, inputRequiredPriv, inputCheck2,                        outputRequiredPriv, outputCheck2);             }      }

    Hive的权限验证首先会调用authorizeUserDBAndTable验证用户是否对访问的DB和Table有访问权限,对应到MetaStore的DB_PRIVS和TBL_PRIVS表,在进行验证的时候,会通过thrift与HiveMetaStore进程进行交互来获取MetaStore库中对应表的相关信息。如果用户对更大粒度的资源有访问权限,则会直接返回,不会再继续进行更细粒度的验证,也就是说如果用户对DB有相关的权限,则不会继续验证对Table和Column的访问权限。

    查看了下DB_PRIVS表,hadoop用户对访问的数据库是有Select权限的,所以再传统CLI模式下访问是没有问题的。看上述代码也都是在预料之中,因为实际上CLI模式和HiveServer模式的权限验证是一套代码。决定remote debug下,进而发现this.getAuthenticator().getUserName()的值为hive,也即是启动HiveServer2的用户,而不是提交SQL的用户hadoop,顺藤摸瓜,找到了设置authenticator相关属性的代码

    SessionState.start(SessionState startSs) {         //实例化默认的HadoopDefaultAuthenticator,方法内部,,使用ReflectionUtils反射加载类的时候,进而调用了HadoopDefaultAuthenticator.setConf方法         startSs.authenticator=HiveUtils.getAuthenticator(startSs.getConf(),HiveConf.ConfVars.HIVE_AUTHENTICATOR_MANAGER);     }     HadoopDefaultAuthenticator.setConf(Configuration conf){         ugi = ShimLoader.getHadoopShims().getUGIForConf(conf);     }     HadoopShimsSecure.getUGIForConf(Configuration conf) throws IOException {         return UserGroupInformation.getCurrentUser();     }      UserGroupInformation.getCurrentUser() throws IOException {     AccessControlContext context = AccessController.getContext();     Subject subject = Subject.getSubject(context);     //HiveServer刚启动的时候,subject为空,调用getLoginUser     if (subject == null || subject.getPrincipals(User.class).isEmpty()) {       return getLoginUser();     } else {       return new UserGroupInformation(subject);     }   } UserGroupInformation.getLoginUser() {     if (loginUser == null) {       try {         Subject subject = new Subject();         LoginContext login;         if (isSecurityEnabled()) {           login = newLoginContext(HadoopConfiguration.USER_KERBEROS_CONFIG_NAME,               subject, new HadoopConfiguration());         } else {           login = newLoginContext(HadoopConfiguration.SIMPLE_CONFIG_NAME,                subject, new HadoopConfiguration());         }         login.login();         loginUser = new UserGroupInformation(subject);         loginUser.setLogin(login);         loginUser.setAuthenticationMethod(isSecurityEnabled() ?                                           AuthenticationMethod.KERBEROS :                                           AuthenticationMethod.SIMPLE);         loginUser = new UserGroupInformation(login.getSubject());         String fileLocation = System.getenv(HADOOP_TOKEN_FILE_LOCATION);         if (fileLocation != null) {           Credentials cred = Credentials.readTokenStorageFile(               new File(fileLocation), conf);           loginUser.addCredentials(cred);         }         loginUser.spawnAutoRenewalThreadForUserCreds();       } catch (LoginException le) {         LOG.debug("failure to login", le);         throw new IOException("failure to login", le);       }       if (LOG.isDebugEnabled()) {         LOG.debug("UGI loginUser:"+loginUser);       }     }     return loginUser;   }

    

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
최신 이슈
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿