前言
Sentry是Hadoop生态中的一员,扮演着“守门人”的角色,看守着大数据平台的数据安全的访问。它以Plugin的形式运行于组件中,通过关系型数据库(PostgreSQL、MySQL)或本地文件来存取访问策略,对数据使用者提供细粒度的访问控制。本文试图在源码层剖析Sentry的鉴权过程,以帮助更好的理解权限的鉴定过程。博客地址Sentry源码之HiveServer2鉴权过程
Sentry架构简述
Sentry的设计目标是作为一层独立的访问控制层来对Hadoop组件(目前支持HDFS,Hive,Impala,solr,kafka,sqoop)进行授权/鉴权操作,因此它的耦合度很低,以插件的形式工作于组件之上。可以把它看作Java web中的filter,当用户请求过来的时候,sentry截获了用户的信息,对用户的权限进行验证,如果成功,则让该请求通过;否则,抛出异常,阻断该请求。
Sentry是一个分层的结构,如下图所示
- Binding层 负责将用户对Hadoop组件的访问请求截获,并解析出其中的用户信息,以便进行鉴权
- Provider层 是一个较通用的权限策略验证层,在这里抽象了权限对象,并对用户所具备的权限对象进行验证
- Policy Metadata Store 负责与策略的存储和读取,目前支持文件存储和关系型数据库存储方式。
由上图结合源码分析,Sentry的大致工作流程为:
1. Binding层拦截用户的访问,并将用户信息解析出来,暂存到一个subject对象中
2. Policy Metadata Store层根据用户访问的资源对象(表名)和用户信息(subject)从底层存储(文件或关系型数据库)中读取两个权限对象列表:requireList(需要有的权限)和obtainList(用户当前的权限)
3. Policy Engine根据读取到的两个权限对象列表,逐一进行权限的比对,缺少任何一个权限都要抛出异常,只有当完全满足时,将此访问请求通过
源码分析
下面以HiveServer2为例,分析Sentry是如何进行鉴权工作的,以此为切入点,剖析Sentry的通用鉴权模型。上面提到,Sentry的鉴权过程中主要分为了Binding、Policy Engine和Policy MetadataStore三层的协作,下面逐一进行分析。
Binding
上面谈到Binding的主要工作是解析用户信息,那么Sentry是如何截获用户对Hadoop组件的请求的呢?拿HiveServer2为例,用户在连接的时候,会由HiveServer2创建一个session,该session中保存了用户的用户名等信息,该session在该用户的整个TCP连接中都会保留,因此如果可以获得该session,便可以获得用户名。
HiveServer2中提供了一个方便的接口叫作HiveSessionHook,其中只有一个run方法,在session manager创建一个session的时候,会进行调用。这是一个Hive提供的hook机制,方便进行自定义的hook动作,Sentry使用了这个Hook,定义了一个HiveAuthzBindingSessionHookV2类实现了HiveSessionHook接口,重写了其中的run方法。代码如下:
@Override
public void run(HiveSessionHookContext sessionHookContext) throws HiveSQLException {
// Add sentry hooks to the session configuration
HiveConf sessionConf = sessionHookContext.getSessionConf();
appendConfVar(sessionConf, ConfVars.SEMANTIC_ANALYZER_HOOK.varname, SEMANTIC_HOOK);
// enable sentry authorization V2
sessionConf.setBoolean(HiveConf.ConfVars.HIVE_AUTHORIZATION_ENABLED.varname, true);
sessionConf.setBoolean(HiveConf.ConfVars.HIVE_SERVER2_ENABLE_DOAS.varname, false);
sessionConf.set(HiveConf.ConfVars.HIVE_AUTHENTICATOR_MANAGER.varname,
"org.apache.hadoop.hive.ql.security.SessionStateUserAuthenticator");
// grant all privileges for table to its owner
sessionConf.setVar(ConfVars.HIVE_AUTHORIZATION_TABLE_OWNER_GRANTS, "");
// Enable compiler to capture transform URI referred in the query
sessionConf.setBoolVar(ConfVars.HIVE_CAPTURE_TRANSFORM_ENTITY, true);
// set security command list
HiveAuthzConf authzConf = HiveAuthzBindingHookBaseV2.loadAuthzConf(sessionConf);
String commandWhitelist =
authzConf.get(HiveAuthzConf.HIVE_SENTRY_SECURITY_COMMAND_WHITELIST,
HiveAuthzConf.HIVE_SENTRY_SECURITY_COMMAND_WHITELIST_DEFAULT);
sessionConf.setVar(ConfVars.HIVE_SECURITY_COMMAND_WHITELIST, commandWhitelist);
// set additional configuration properties required for auth
sessionConf.setVar(ConfVars.SCRATCHDIRPERMISSION, SCRATCH_DIR_PERMISSIONS);
// setup restrict list
sessionConf.addToRestrictList(ACCESS_RESTRICT_LIST);
// set user name
sessionConf.set(HiveAuthzConf.HIVE_ACCESS_SUBJECT_NAME, sessionHookContext.getSessionUser());
sessionConf.set(HiveAuthzConf.HIVE_S