Ranger HDFS Plugin Details

The main entrance is specified in hdfs-site.xml .

 <property>
        <name>dfs.namenode.inode.attributes.provider.class</name>
        <value>org.apache.ranger.authorization.hadoop.RangerHdfsAuthorizer</value>
    </property>

RangerHdfsAuthorizer extends INodeAttributeProvider and implements the abstract methods.

INodeAttributeProvider

public abstract class INodeAttributeProvider {
/**
   * Initialize the provider. This method is called at NameNode startup
   * time.
   */
  public abstract void start();

  /**
   * Shutdown the provider. This method is called at NameNode shutdown time.
   */
  public abstract void stop();

  public abstract INodeAttributes getAttributes(String[] pathElements,
      INodeAttributes inode);

  /**
   * Can be over-ridden by implementations to provide a custom Access Control
   * Enforcer that can provide an alternate implementation of the
   * default permission checking logic.
   * @param defaultEnforcer The Default AccessControlEnforcer
   * @return The AccessControlEnforcer to use
   */
  public AccessControlEnforcer getExternalAccessControlEnforcer(
      AccessControlEnforcer defaultEnforcer) {
    return defaultEnforcer;
  }

The most import methods include start and getExternalAccessControlEnforcer”.

Method start is used to initialize the plugin and getExternalAccessControlEnforcer is used to enforce permission check.

RangerHdfsAuthorizer.start

Method start is used to initialize the plugin.

     public void start() {
        if(LOG.isDebugEnabled()) {
            LOG.debug("==> RangerHdfsAuthorizer.start()");
        }

        RangerHdfsPlugin plugin = new RangerHdfsPlugin();
        plugin.init();
        }

class RangerHdfsPlugin

RangerHdfsPlugin extends RangerBasePlugin.

RangerBasePlugin

RangerBasePlugin implemented the common method of various plugin. It includes PolicyRefresher, RangerPolicyEngine, RangerAccessResultProcessor.

RangerBasePlugin.PolicyRefresher

RangerAdminClient admin = createAdminClient(serviceName, appId, propertyPrefix);

        refresher = new PolicyRefresher(this, serviceType, appId, serviceName, admin, pollingIntervalMs, cacheDir);
        refresher.setDaemon(true);
        refresher.startRefresher();

PolicyRefresher.run load policy regularly.

public void run() {
        while(true) {
            loadPolicy();
            try {
                Thread.sleep(pollingIntervalMs);
            } catch(InterruptedException excp) {
                LOG.info("PolicyRefresher(serviceName=" + serviceName + ").run(): interrupted! Exiting thread", excp);
                break;
            }
        }


    }

PolicyRefresher.loadPolicy
Firstly, it loads policy from PolicyAdmin, if success then saveToCache, else load from cache.

private void loadPolicy() {
        try {
            //load policy from PolicyAdmin
            ServicePolicies svcPolicies = loadPolicyfromPolicyAdmin();

            if (svcPolicies == null) {
                //if Policy fetch from Policy Admin Fails, load from cache
                if (!policiesSetInPlugin) {
                    svcPolicies = loadFromCache();
                }
            } else {
                saveToCache(svcPolicies);
            }


            if (svcPolicies != null) {
                plugIn.setPolicies(svcPolicies);
                policiesSetInPlugin = true;
                setLastActivationTimeInMillis(System.currentTimeMillis());
                lastKnownVersion = svcPolicies.getPolicyVersion();
            } else {
                if (!policiesSetInPlugin && !serviceDefSetInPlugin) {
                    plugIn.setPolicies(null);
                    serviceDefSetInPlugin = true;
                }
            }
        } catch (RangerServiceNotFoundException snfe) {

        } catch (Exception excp) {

        }


    }

The admin used to fech policy is created using createAdminClient.
RangerAdminClient admin = createAdminClient(serviceName, appId, propertyPrefix);

Using the setting ranger.plugin.hdfs.policy.source.impl in conf/ranger-hdfs-security.xml to create admin.

<property>
                <name>ranger.plugin.hdfs.service.name</name>
                <value>hadoopdev</value>
                <description>
                        Name of the Ranger service containing policies for this YARN instance
                </description>
        </property>

        <property>
                <name>ranger.plugin.hdfs.policy.source.impl</name>
                <value>org.apache.ranger.admin.client.RangerAdminRESTClient</value>
                <description>
                        Class to retrieve policies from the source
                </description>
        </property>

        <property>
                <name>ranger.plugin.hdfs.policy.rest.url</name>
                <value>http://localhost:8098</value>
                <description>
                        URL to Ranger Admin
                </description>
        </property>

org.apache.ranger.admin.client.RangerAdminRESTClient

public ServicePolicies getServicePoliciesIfUpdated(final long lastKnownVersion, final long lastActivationTimeInMillis) throws Exception {
// RangerRESTUtils.REST_URL_POLICY_GET_FOR_SERVICE_IF_UPDATED ="/service/plugins/secure/policies/download/"
    WebResource webResource = createWebResource(RangerRESTUtils.REST_URL_POLICY_GET_FOR_SERVICE_IF_UPDATED + serviceName)
                        .queryParam(RangerRESTUtils.REST_PARAM_LAST_KNOWN_POLICY_VERSION, Long.toString(lastKnownVersion))
                        .queryParam(RangerRESTUtils.REST_PARAM_LAST_ACTIVATION_TIME, Long.toString(lastActivationTimeInMillis))
                        .queryParam(RangerRESTUtils.REST_PARAM_PLUGIN_ID, pluginId)
                        .queryParam(RangerRESTUtils.REST_PARAM_CLUSTER_NAME, clusterName);
                response = webResource.accept(RangerRESTUtils.REST_MIME_TYPE_JSON).get(ClientResponse.class);

FSPermissionChecker.checkPermission

FSPermissionChecker in package org.apache.hadoop.hdfs.server.namenode.
When checkPermission is called, it will call external access control enforcer. By default, it returns defaultEnforcer – FSPermissionChecker

public AccessControlEnforcer getExternalAccessControlEnforcer(
      AccessControlEnforcer defaultEnforcer) {
    return defaultEnforcer;
  }

FSPermissionChecker.checkPermission

void checkPermission(INodesInPath inodesInPath, boolean doCheckOwner,
      FsAction ancestorAccess, FsAction parentAccess, FsAction access,
      FsAction subAccess, boolean ignoreEmptyDir)
      throws AccessControlException {
      ...
      AccessControlEnforcer enforcer =
        getAttributesProvider().getExternalAccessControlEnforcer(this);
    enforcer.checkPermission(fsOwner, supergroup, callerUgi, inodeAttrs, inodes,
        pathByNameArr, snapshotId, path, ancestorIndex, doCheckOwner,
        ancestorAccess, parentAccess, access, subAccess, ignoreEmptyDir);
  }

Default checkPermission in FSPermissionChecker

/**
     * Checks permission on a file system object. Has to throw an Exception
     * if the filesystem object is not accessessible by the calling Ugi.
     * @param fsOwner Filesystem owner (The Namenode user)
     * @param supergroup super user geoup
     * @param callerUgi UserGroupInformation of the caller
     * @param inodeAttrs Array of INode attributes for each path element in the
     *                   the path
     * @param inodes Array of INodes for each path element in the path
     * @param pathByNameArr Array of byte arrays of the LocalName
     * @param snapshotId the snapshotId of the requested path
     * @param path Path String
     * @param ancestorIndex Index of ancestor
     * @param doCheckOwner perform ownership check
     * @param ancestorAccess The access required by the ancestor of the path.
     * @param parentAccess The access required by the parent of the path.
     * @param access The access required by the path.
     * @param subAccess If path is a directory, It is the access required of
     *                  the path and all the sub-directories. If path is not a
     *                  directory, there should ideally be no effect.
     * @param ignoreEmptyDir Ignore permission checking for empty directory?
     * @throws AccessControlException
     */
     @Override
  public void checkPermission(String fsOwner, String supergroup,
      UserGroupInformation callerUgi, INodeAttributes[] inodeAttrs,
      INode[] inodes, byte[][] pathByNameArr, int snapshotId, String path,
      int ancestorIndex, boolean doCheckOwner, FsAction ancestorAccess,
      FsAction parentAccess, FsAction access, FsAction subAccess,
      boolean ignoreEmptyDir)
      throws AccessControlException {
    for(; ancestorIndex >= 0 && inodes[ancestorIndex] == null;
        ancestorIndex--);
    checkTraverse(inodeAttrs, path, ancestorIndex);

    final INodeAttributes last = inodeAttrs[inodeAttrs.length - 1];
    if (parentAccess != null && parentAccess.implies(FsAction.WRITE)
        && inodeAttrs.length > 1 && last != null) {
      checkStickyBit(inodeAttrs[inodeAttrs.length - 2], last);
    }
    if (ancestorAccess != null && inodeAttrs.length > 1) {
      check(inodeAttrs, path, ancestorIndex, ancestorAccess);
    }
    if (parentAccess != null && inodeAttrs.length > 1) {
      check(inodeAttrs, path, inodeAttrs.length - 2, parentAccess);
    }
    if (access != null) {
      check(last, path, access);
    }
    if (subAccess != null) {
      INode rawLast = inodes[inodeAttrs.length - 1];
      checkSubAccess(pathByNameArr, inodeAttrs.length - 1, rawLast,
          snapshotId, subAccess, ignoreEmptyDir);
    }
    if (doCheckOwner) {
      checkOwner(last);
    }
  }

RangerHdfsAuthorizer.getExternalAccessControlEnforcer

@Override
    public AccessControlEnforcer getExternalAccessControlEnforcer(AccessControlEnforcer defaultEnforcer) {
        RangerAccessControlEnforcer rangerAce = new RangerAccessControlEnforcer(defaultEnforcer);
        return rangerAce;
    }

The constructor of RangerAccessControlEnforcer saves defaultEnforcer first.

public RangerAccessControlEnforcer(AccessControlEnforcer defaultEnforcer) {
            this.defaultEnforcer = defaultEnforcer;
        }

RangerAccessControlEnforcer.checkPermission

RangerAccessControlEnforcer.checkPermission using plugin.isAccessAllowed(request, auditHandler) at first. If the plugin returns not determined, then it using the default check.

        @Override
        public void checkPermission(String fsOwner, String superGroup, UserGroupInformation ugi,
                                    INodeAttributes[] inodeAttrs, INode[] inodes, byte[][] pathByNameArr,
                                    int snapshotId, String path, int ancestorIndex, boolean doCheckOwner,
                                    FsAction ancestorAccess, FsAction parentAccess, FsAction access,
                                    FsAction subAccess, boolean ignoreEmptyDir) throws AccessControlException {
            AuthzStatus            authzStatus = AuthzStatus.NOT_DETERMINED;

...
    // checkINodeAccess
                    if(authzStatus == AuthzStatus.ALLOW && access != null && inode != null) {
                        INodeAttributes inodeAttribs = inodeAttrs.length > 0 ? inodeAttrs[inodeAttrs.length - 1] : null;

                        authzStatus = isAccessAllowed(inode, inodeAttribs, access, user, groups, plugin, auditHandler);
                        if (authzStatus == AuthzStatus.NOT_DETERMINED) {
                            authzStatus = checkDefaultEnforcer(fsOwner, superGroup, ugi, inodeAttrs, inodes,
                                            pathByNameArr, snapshotId, path, ancestorIndex, doCheckOwner,
                                            null, null, access, null, ignoreEmptyDir,
                                            isTraverseOnlyCheck, ancestor, parent, inode, auditHandler);
                        }
                    }
private AuthzStatus isAccessAllowed(INode inode, INodeAttributes inodeAttribs, FsAction access, String user, Set<String> groups, RangerHdfsPlugin plugin, RangerHdfsAuditHandler auditHandler) {
            AuthzStatus ret       = null;
            String      path      = inode != null ? inode.getFullPathName() : null;
            String      pathOwner = inodeAttribs != null ? inodeAttribs.getUserName() : null;
            String      clusterName = plugin.getClusterName();

            if(pathOwner == null && inode != null) {
                pathOwner = inode.getUserName();
            }

            if (RangerHadoopConstants.HDFS_ROOT_FOLDER_PATH_ALT.equals(path)) {
                path = RangerHadoopConstants.HDFS_ROOT_FOLDER_PATH;
            }


            Set<String> accessTypes = access2ActionListMapper.get(access);

            if(accessTypes == null) {
                LOG.warn("RangerAccessControlEnforcer.isAccessAllowed(" + path + ", " + access + ", " + user + "): no Ranger accessType found for " + access);

                accessTypes = access2ActionListMapper.get(FsAction.NONE);
            }

            for(String accessType : accessTypes) {
                RangerHdfsAccessRequest request = new RangerHdfsAccessRequest(inode, path, pathOwner, access, accessType, user, groups, clusterName);

                RangerAccessResult result = plugin.isAccessAllowed(request, auditHandler);

                if (result == null || !result.getIsAccessDetermined()) {
                    ret = AuthzStatus.NOT_DETERMINED;
                    // don't break yet; subsequent accessType could be denied
                } else if(! result.getIsAllowed()) { // explicit deny
                    ret = AuthzStatus.DENY;
                    break;
                } else { // allowed
                    if(!AuthzStatus.NOT_DETERMINED.equals(ret)) { // set to ALLOW only if there was no NOT_DETERMINED earlier
                        ret = AuthzStatus.ALLOW;
                    }
                }
            }

            if(ret == null) {
                ret = AuthzStatus.NOT_DETERMINED;
            }

            if(LOG.isDebugEnabled()) {
                LOG.debug("<== RangerAccessControlEnforcer.isAccessAllowed(" + path + ", " + access + ", " + user + "): " + ret);
            }

            return ret;
        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值