一:shell执行:
grant授权:
查看commands目录下grant.rb文件:
security_admin.grant(user, permissions, table_name, family, qualifier)
进入security.rb文件执行:
org.apache.hadoop.hbase.security.access.AccessControlClient.grant( @connection, tableName, user, fambytes, qualbytes, perm.getActions())
revoke解除权限:
commands目录下revoke.rb文件:
security_admin.revoke(user, table_name, family, qualifier)
紧接着进入security.rb文件执行:
org.apache.hadoop.hbase.security.access.AccessControlClient.revoke(@connection, tableName, user, fambytes, qualbytes)
二:hbase授权:
进入AccessController服务端处理请求类,(客户端类为AccessControllerClient类;)这个类执行hbase权限操作;找到授权代码:
public void grant(RpcController controller,
AccessControlProtos.GrantRequest request,
RpcCallback<AccessControlProtos.GrantResponse> done)
核心代码块:
User.runAsLoginUser(new PrivilegedExceptionAction<Void>() {
@Override
public Void run() throws Exception {
AccessControlLists.addUserPermission(regionEnv.getConfiguration(), perm,
regionEnv.getTable(AccessControlLists.ACL_TABLE_NAME), request.getMergeExistingPermissions());
return null;
}
});
执行添加用户权限到acl表一步,进入到addUserPermission方法,存储用户权限到表中:
看代码:
//获取权限行为
Permission.Action[] actions = userPerm.getActions();
//声明rowkey
//1.namespace存在,为namespace;2.表table与namespace不存在,为默认acl;3.否则为tableName
byte[] rowKey = userPermissionRowKey(userPerm);
//初始化put对象,为后面插入数据表准备
Put p = new Put(rowKey);
//插入权限行为对象的key
byte[] key = userPermissionKey(userPerm);
//action的判断
if ((actions == null) || (actions.length == 0)) {
...................中间处理,包含数据转byte等
p.addImmutable(ACL_LIST_FAMILY, key, value);
最后将权限数据插入acl表中:
t.put(p);
hbase授权结束。
三:hbase解除权限:
hbase解除权限与hbase授权一样;核心代码:
//扎到之前存储的匹配的权限移除
static void removeUserPermission(Configuration conf, UserPermission userPerm, Table t)
throws IOException {
Delete d = new Delete(userPermissionRowKey(userPerm));
byte[] key = userPermissionKey(userPerm);
if (LOG.isDebugEnabled()) {
LOG.debug("Removing permission "+ userPerm.toString());
}
d.addColumns(ACL_LIST_FAMILY, key);
try {
t.delete(d);
} finally {
t.close();
}
}
四:hbase权限判断:
回头看AccessController类,
public class AccessController implements MasterObserver, RegionObserver, RegionServerObserver,
AccessControlService.Interface, CoprocessorService, EndpointObserver, BulkLoadObserver
实现了CoprocessorService、AccessControlService.Interface等,会在scan,delete,merger,balance等操作前后触发操作:
例如:preScannerOpen,其他操作类似
内部调用permissionGranted(opType, user, env, families, Action.READ);检查当前user是否有privilege执行操作;
接着:
//meta表读权限所有用户都将允许
if (hri.isMetaRegion()) {
if (permRequest == Action.READ) {
return AuthResult.allow(request, "All users allowed", user,
permRequest, tableName, families);
}
}
/**如果获取不到用户,权限拒绝;
其中用户没指定情况下三种情况获取:
1.keberos中获取;
2.hadoop用户;
3.操作系统中的用户;
**/
if (user == null) {
return AuthResult.deny(request, "No user associated with request!", null,
permRequest, tableName, families);
}
检查是否有权限请求的表及列族;
如果列族存在且所有列族检查通过,则:
// all family checks passed
return AuthResult.allow(request, "All family checks passed", user, permRequest,
tableName, families);
否则:
// 4. no families to check and table level access failed
return AuthResult.deny(request, "No families to check and table permission failed",
user, permRequest, tableName, families);
中间权限检查通过TableAuthManager的authorize执行:
接着验证用户与验证用户组:
if (authorizeUser(user, table, family, qualifier, action)) {
return true;
}
String[] groups = user.getGroupNames();
if (groups != null) {
for (String group : groups) {
if (authorizeGroup(group, table, family, qualifier, action)) {
return true;
}
}
}
查看验证用户:
核心代码:
// Global and namespace authorizations supercede table level
if (authorize(user, table.getNamespaceAsString(), action)) {
return true;
}
// Check table permissions
return authorize(getTablePermissions(table).getUser(user.getShortName()), table, family,
qualifier, action);
其中检查namespace(namespace的来源就是zookeeper上注册监听的节点名nodename):权限:
从globalCache获取用户:
globalCache.getUser(user.getShortName()), action)
获取用户组:
globalCache.getGroup(group), action)
接着从nsCache获取namespace权限;
其中注册在ZooKeeperWatcher中节点数据变化(会将数据写到zookeeper中acl节点下,当然会解析acl表的数据成指定格式)的时候会refreshAuthManager,及会执行updateNsCache(namespace, perms);
/**
* Updates the internal permissions cache for a single table, splitting
* the permissions listed into separate caches for users and groups to optimize
* group lookups.
*/
private void updateNsCache(String namespace,
ListMultimap<String, TablePermission> tablePerms) {
PermissionCache<TablePermission> newTablePerms = new PermissionCache<>();
for (Map.Entry<String, TablePermission> entry : tablePerms.entries()) {
if (AuthUtil.isGroupPrincipal(entry.getKey())) {
newTablePerms.putGroup(AuthUtil.getGroupName(entry.getKey()), entry.getValue());
} else {
newTablePerms.putUser(entry.getKey(), entry.getValue());
}
}
nsCache.put(namespace, newTablePerms);
mtime.incrementAndGet();
}
上面是cache的基本流程;
接着会用从cache中获取的权限逐个检查:
for (Permission p : perms) {
if (p.implies(action)) {
return true;
}
}
结束;其中用户组的获取也是一样的道理。
这样就完成了用户操作钱权限的判断,具体请看源码。
五:hbase权限改进思路:
基于更严谨的hbase权限管理,可考虑:
1.HBASE中RWECA可以改善成更细粒度的权限,如增删改查权限;
2.连接hbase权限,用户名user+密码pwd认证;
3.grant授权与revoke解除权限,改进为user+pwd识别用户;
4.严谨的superuser用户定义及权限。
等等权限。
六:hbase权限其他方面:
1:Using Secure HTTP (HTTPS) for the Web UI
2:Using SPNEGO for Kerberos authentication with Web UIs
3:Thrift Gateway
4:REST Gateway
5:HDFS and ZooKeeper
6:Securing Access To Your Data
- Role-based Access Control (RBAC) controls
- Visibility Labels
- Transparent encryption of data at rest
- Secure Bulk Load
- Secure Enable