大数据安全之hdfs与hive的Authentication与Authorization
我们经常听到以下口号:城市发展什么最重要?人才!家庭生活什么最重要?孩子!企业生产什么最重要?数据!在当今时代,数据在企业中作为具有战略意义的重要资产,其安全性受到了越来越高的重视,任何形式的误删除,误修改,越权使用,不慎泄露等,都是重大的安全事件。为了保护数据安全,各企业都实施了严格的数据使用规范和准则,也应用了各种数据安全技术,确保数据的安全使用。本文我们就来看下大数据安全领域的话题。
在安全领域,有个3A的概念,即Authentication认证,Authorization鉴权,和Audit审计。其中Authentication解决的是身份认证的问题,通俗的来说就是验明真身,证明用户确实是他声称的身份而不是由由其它身份伪装而来;Authorization解决的是权限验证问题,即执行某个具体操作前,确认该用户确实有执行该操作的权限,而不是越权行事;Audit解决的是审计问题,是在事后定期查看安全相关操作记录,从而进一步调整安全策略的基础。(当然数据加密Encryption也是确保安全常见的措施。)
针对某一个用户的某一次数据操作来看,Authentication是事前的安全措施,Authorization是事中的安全措施,Audit是事后的安全措施。三者联动,才能确保真正的安全。这三者之中,Authentication是基础,因为如果不能证明用户身份,一切都无从谈起;而Authorization是核心和主题,也是具体业务系统实现时大家更关注的地方。
笔者在这里尝试浅析下大数据安全领域中authentication和authorization方面话题。在大数据安全领域,Authentication层面,常见的有simple, ldap, 和kerberos三种;Authorization层面,很多是由业务系统自己实现的,而底层大数据组件可以借助于成熟的开源框架,目前常见的有Sentry和Ranger两种(其中CDP中不再支持Sentry,只支持Ranger)。由于篇幅有限,笔者在这里聚焦于数据存储层面的hdfs和hive框架,不会讨论spark,flink等计算框架中的实现。
先来看hadoop的Authentication. hadoop框架(包含hdfs)的Authentication,通过参数hadoop.security.authentication 来配置,目前支持的值只有两种,即simple 和kerbero。其中前者是不做任何验证,用户说他是谁hadoop框架就认为是谁,参见源码org.apache.hadoop.security.UserGroupInformation可知,hadoop会使用环境变量HADOOP_USER_NAME的值来获得当前用户,没有获取到则会使用系统参数HADOOP_USER_NAME的值来获得当前用户,仍然没有获取到则则会使用系统参数user.name的值来确定当前用户。所以我们经常在没有启用kerberos的环境中,在执行代码前,通过设置环境变量的方式来灵活切换用户身份,如:export HADOOP_USER_NAME= xyz;而配置了使用kerberos认证身份时,用户身份的验证工作是由kerberos来是实现的,在使用上,用户一般通过kinit principal_name -kt key_tab_location的方式来认证用户身份,代码中则一般通过org.apache.hadoop.security.UserGroupInformation.loginUserFromKeytab(String user, String path)的方式来认证用户身份。
接下来看下hive的Authentication. Hive的authentication通过参数hive.server2.authentication来配置,可配置的值有多种,常见的有NONE:即不做身份校验,LDAP: 使用基于LDAP/AD的用户身份校验,以及 KERBEROS: 使用Kerberos/GSSAPI 做身份校验。针对None, 其含义是不对用户身份进行校验,事实上此时用户通过beeline登录时,可以不配置用户名和密码 (Hive会认为是匿名用户anonymous),也可以配置为任意用户名(甚至是不存在的用户),如:beeline -u jdbc:hive2://xx.xx.xx.xx:10000/default 或beeline -u jdbc:hive2://xx.xx.xx.xx:10000/default -n xyz;针对ldap方式,会到ldap中验证用户名和密码,只有验证通过后才能正常登录,此时登录方式跟none类似,但需要提供正确的用户名和密码:beeline -u jdbc:hive2://xx.xx.xx.xx:10000/default -n xyz -p xyz; 如果是kerberos认证方式,则在执行登录前需要首先获取a valid Kerberos ticket in the ticket cache before connecting,这点用户一般通过kinit principal_name -kt key_tab_location的方式来获取ticket,程序代码中则一般通过org.apache.hadoop.security.UserGroupInformation.loginUserFromKeytab(String user, String path)的方式来获取ticket;获取ticket成功后,才可以通过jdbc连接登录到hiveserver,注意此时需要在url中指定登录用户的principla, 此时url格式如下:url = jdbc:hive2://xx.xx.xx.xx:10000/default;principal=hive/[email protected]";
再来看看hdfs的authorization. HDFS对目录和文件实现了类似linux操作系统上的POSIX的安全模型,其核心是对owner,group和other可以分别配置读写和执行权限,在次不在赘述这点,不清楚的同学请自行查阅。为了支持更细粒度的更灵活的对用户或用户组的权限配置,hdfs也支持类似 POSIX ACLs (Access Control Lists) 的访问控制列表, 用户可以通过命令查看和设置任意用户或用户组对特定目录的读写或执行权限,这点是对owner-group-other权限模型之外的有力补充,由于其灵活性和细粒度行,使用十分广泛。查看acl命令格式如下:hdfs dfs -getfacl [-R] <path>,设置acl命令格式如下:hdfs dfs -setfacl [-R] [-b |-k -m |-x <acl_spec> <path>] |[--set <acl_spec> <path>],更多信息请自行参阅官方文档。出了以上两点,还有个stickybit的概念,也是大家要掌握的,其含义是: 通过对特定目录设置sticky bit,可以有效阻止除超级用户和该目录owner之外的任意其它用户对该目录下文件的删除或移动操作。
最后来看下hive的Authorization. Hive的authorization所支持的模式在不断演化中,目前来看主要有以下四大类:1. Old default Hive Authorization (Legacy Mode) (Hive 2.0.0前该选项是默认值); 2. Metastore server 中的Storage Based Authorization;3. hiveserver2 中的 SQL Standards Based Authorization; 4. 使用权限框架如 Apache Ranger 或 Sentry. 用户可以根据自己使用Hive的模式的不同,单独使用或组合搭配使用以上支持的authorization机制。如果是仅仅将hive作为表存储层使用,比如通过presto, spark, impala等计算引擎访问hive中的数据,此时会直接访问hive metastore中的元数据,也会直接访问hdfs上的数据,这种使用场景比较适合启用storage based authorization,其底层机制是通过hdfs permissions来验证用户访问hdfs中数据的权限,而对应的hive metastore中元数据的访问权限是由hive从对应的hdfs 目录的权限同步而来的,这样就可以做到对元数据和数据权限的全面校验;如果使用场景是将hive作为sql执行引擎使用,即通过hiveserver2的api来访问hiveserver2进而提交执行hive sql查询数据,比如代码中的jdbc/odbc连接或beeline的jdbc连接,此时就可以启用 SQL Standards Based Authorization,该模式可以做到更细粒度的权限控制,比如column字段或view试图级别的权限控制;以上三种方式都是hive社区官方推出的方案,而目前在大数据业界实践中,似乎使用sentry和ranger这类成熟框架的相对更多些,其原因应该是因为这些框架的底层原理整合的还是以上hive官方的三种authorization机制,但是在自身的安装部署和易用性上,以及大数据生态整合上做的更好,尤其是在CDH中。
Sentry和Ranger这两个框架非常类似,都是基于角色的访问控制模型(role-based access control,RBAC),基于角色的访问控制在需要对大量用户进行授权时能大大减轻所需的ACL配置工作。Sentry最初是由Cloudera公司内部开发而来的,初衷是为了让用户能够细粒度的控制Hadoop系统中的数据(主要指HDFS,Hive的数据),所以Sentry对HDFS,Hive以及同样由Cloudera开发的Impala有着很好的支持性;而Ranger最初是由另一家公司Hortonworks(已经被Cloudera收购)主导开发的,它同样是做细粒度的权限控制,但相比较于Sentry而言,ranger有着更加丰富的策略控制,以及更加通用性的大数据组件支持,包括于HDFS, Hive, HBase, Yarn, Storm, Knox, Kafka, Solr 和 NiFi等。在Cloudera公司新推出的大数据平台cdp中,不在提供对sentry的支持而是统一使用了Ranger.
以下详细分享下sentry相关知识。Sentry 支持对hiveserver2的基于角色的细粒度的授权,当然 sentry只会控制hive和impala的访问,如果是通过hdfs的api或者 hdfs的shell直接操作hdfs文件,还是会通过hdfs 的权限控制机制 验证hdfs文件权限。有一点需要注意,由于sentry的授权是按照角色和组来授权的,不支持直接对用户进行授权,所以还需要解决用户和组的映射问题,具体使用哪种映射方式是由hadoop的hadoop.security.group.mapping参数决定的,该参数默认值是org.apache.hadoop.security.ShellBasedUnixGroupsMapping,即基于namenode节点的操作系统的用户和组的映射规则来确定实际使用的用户组,生产环境一般会配置为org.apache.hadoop.security.LdapGroupsMapping,即使用ldap来确定用户对应的用户组。
sentry 授权的一般操作步骤是,通过sentry管理员账户登录beeline后,创建角色,执行grant授权语句对角色授予服务,数据库,表,URI的权限,然后执行grant语句将角色赋予目标用户组。其中sentry管理员用户组,是通过配置项sentry.service.admin.group来指定的,该用户组下所有用户都是sentry管理员;而server是通过配置项hive.sentry.server指定的。赋权示例:
创建角色:create role xx;
给角色赋权:服务级赋权:GRANT xx ON SERVER xx TO ROLE xx WITH GRANT OPTION; 数据库赋权:GRANT xx ON DATABASE xx TO ROLE xx WITH GRANT OPTION; 表赋权:GRANT xx ON table xx TO ROLE xx WITH GRANT OPTION; URI赋权:GRANT ALL ON URI 'hdfs://namenode:XXX/path/to/table' TO ROLE xx WITH GRANT OPTION;
将用户组加入到角色中:GRANT ROLE xx TO GROUP xx;
查看权限:SHOW ROLES; SHOW CURRENT ROLES;SHOW GRANT ROLE role_name;
一些关键配置项:
需要关闭Hive的用户模拟功能: hive.server2.enable.impersonation/hive.server2.nable.doAs=false;
需要开启hdfs的访问控制列表功能acl: dfs.namenode.acl.enabled=true;
需要在HDFS中确保已开启sentry插件,并启用ACL同步(enable sentry synchronization);
需要在hdfs中配置sentry需要同步的hive库的路径: sentry synchronization path prefix/sentry.hdfs.integration.path.prefix (默认是/user/hive/warehouse,根据需要添加其它路径) ;
如果没有配置好sentry和hdfs的acl同步,可以通过hdfs dfs -setfacl配置acl,如:hdfs dfs -setfacl -R -m group:xyz:rwx /user/hundsun/
参考链接:
https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Authorization
https://cwiki.apache.org/confluence/display/SENTRY/Documentation