diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/YarnAuthorizationProvider.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/YarnAuthorizationProvider.java index dd81ebd..104b62d 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/YarnAuthorizationProvider.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/YarnAuthorizationProvider.java @@ -60,6 +60,16 @@ public static YarnAuthorizationProvider getInstance(Configuration conf) { return authorizer; } + // for test + public static void destory() { + synchronized (YarnAuthorizationProvider.class) { + if (authorizer != null) { + LOG.debug(authorizer.getClass().getName() + " is destoryed."); + authorizer = null; + } + } + } + /** * Initialize the provider. Invoked on daemon startup. DefaultYarnAuthorizer is * initialized based on configurations. diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/AllocationConfiguration.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/AllocationConfiguration.java index f984fef..f85df32 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/AllocationConfiguration.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/AllocationConfiguration.java @@ -23,13 +23,14 @@ import java.util.Set; import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.security.authorize.AccessControlList; import org.apache.hadoop.yarn.api.records.QueueACL; import org.apache.hadoop.yarn.api.records.ReservationACL; import org.apache.hadoop.yarn.api.records.Resource; +import org.apache.hadoop.yarn.security.AccessType; import org.apache.hadoop.yarn.server.resourcemanager.reservation.ReservationSchedulerConfiguration; import org.apache.hadoop.yarn.server.resourcemanager.resource.ResourceWeights; +import org.apache.hadoop.yarn.server.resourcemanager.scheduler.SchedulerUtils; import org.apache.hadoop.yarn.util.resource.DefaultResourceCalculator; import org.apache.hadoop.yarn.util.resource.ResourceCalculator; import org.apache.hadoop.yarn.util.resource.Resources; @@ -64,7 +65,7 @@ private final float queueMaxAMShareDefault; // ACL's for each queue. Only specifies non-default ACL's from configuration. - private final Map> queueAcls; + private final Map> queueAcls; // Reservation ACL's for each queue. Only specifies non-default ACL's from // configuration. @@ -117,7 +118,7 @@ public AllocationConfiguration(Map minQueueResources, Map minSharePreemptionTimeouts, Map fairSharePreemptionTimeouts, Map fairSharePreemptionThresholds, - Map> queueAcls, + Map> queueAcls, Map> resAcls, QueuePlacementPolicy placementPolicy, Map> configuredQueues, @@ -159,7 +160,7 @@ public AllocationConfiguration(Configuration conf) { queueMaxAppsDefault = Integer.MAX_VALUE; queueMaxResourcesDefault = Resources.unbounded(); queueMaxAMShareDefault = 0.5f; - queueAcls = new HashMap>(); + queueAcls = new HashMap>(); resAcls = new HashMap>(); minSharePreemptionTimeouts = new HashMap(); fairSharePreemptionTimeouts = new HashMap(); @@ -183,9 +184,10 @@ public AllocationConfiguration(Configuration conf) { * nobody ("") */ public AccessControlList getQueueAcl(String queue, QueueACL operation) { - Map queueAcls = this.queueAcls.get(queue); - if (queueAcls != null) { - AccessControlList operationAcl = queueAcls.get(operation); + Map acls = this.queueAcls.get(queue); + if (acls != null) { + AccessControlList operationAcl = + acls.get(SchedulerUtils.toAccessType(operation)); if (operationAcl != null) { return operationAcl; } @@ -193,6 +195,13 @@ public AccessControlList getQueueAcl(String queue, QueueACL operation) { return (queue.equals("root")) ? EVERYBODY_ACL : NOBODY_ACL; } + /** + * Get the map of ACLs of all queues + */ + public Map> getQueueAcls() { + return this.queueAcls; + } + @Override /** * Get the map of reservation ACLs to {@link AccessControlList} for the @@ -291,21 +300,6 @@ public Resource getMaxResources(String queueName) { } } - public boolean hasAccess(String queueName, QueueACL acl, - UserGroupInformation user) { - int lastPeriodIndex = queueName.length(); - while (lastPeriodIndex != -1) { - String queue = queueName.substring(0, lastPeriodIndex); - if (getQueueAcl(queue, acl).isUserAllowed(user)) { - return true; - } - - lastPeriodIndex = queueName.lastIndexOf('.', lastPeriodIndex - 1); - } - - return false; - } - public SchedulingPolicy getSchedulingPolicy(String queueName) { SchedulingPolicy policy = schedulingPolicies.get(queueName); return (policy == null) ? defaultSchedulingPolicy : policy; diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/AllocationFileLoaderService.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/AllocationFileLoaderService.java index fab536d..894365d 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/AllocationFileLoaderService.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/AllocationFileLoaderService.java @@ -41,7 +41,12 @@ import org.apache.hadoop.yarn.api.records.QueueACL; import org.apache.hadoop.yarn.api.records.ReservationACL; import org.apache.hadoop.yarn.api.records.Resource; +import org.apache.hadoop.yarn.security.AccessType; +import org.apache.hadoop.yarn.security.Permission; +import org.apache.hadoop.yarn.security.PrivilegedEntity; +import org.apache.hadoop.yarn.security.PrivilegedEntity.EntityType; import org.apache.hadoop.yarn.server.resourcemanager.resource.ResourceWeights; +import org.apache.hadoop.yarn.server.resourcemanager.scheduler.SchedulerUtils; import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.policies.FifoPolicy; import org.apache.hadoop.yarn.util.Clock; import org.apache.hadoop.yarn.util.SystemClock; @@ -74,6 +79,12 @@ public static final long THREAD_JOIN_TIMEOUT_MS = 1000; + private static final String ROOT = "root"; + private static final AccessControlList EVERYBODY_ACL = + new AccessControlList("*"); + private static final AccessControlList NOBODY_ACL = + new AccessControlList(" "); + private final Clock clock; private long lastSuccessfulReload; // Last time we successfully reloaded queues @@ -81,7 +92,7 @@ // Path to XML file containing allocations. private File allocFile; - + private Listener reloadListener; @VisibleForTesting @@ -90,6 +101,8 @@ private Thread reloadThread; private volatile boolean running = true; + private List defaultPermissions; + public AllocationFileLoaderService() { this(SystemClock.getInstance()); } @@ -208,6 +221,7 @@ public synchronized void reloadAllocations() throws IOException, ParserConfigurationException, SAXException, AllocationConfigurationException { if (allocFile == null) { + reloadListener.onReload(null); return; } LOG.info("Loading allocation file " + allocFile); @@ -224,8 +238,8 @@ public synchronized void reloadAllocations() throws IOException, Map fairSharePreemptionTimeouts = new HashMap(); Map fairSharePreemptionThresholds = new HashMap(); - Map> queueAcls = - new HashMap>(); + Map> queueAcls = + new HashMap>(); Map> reservationAcls = new HashMap>(); Set reservableQueues = new HashSet(); @@ -440,7 +454,7 @@ private void loadQueue(String parentName, Element element, Map minSharePreemptionTimeouts, Map fairSharePreemptionTimeouts, Map fairSharePreemptionThresholds, - Map> queueAcls, + Map> queueAcls, Map> resAcls, Map> configuredQueues, Set reservableQueues, @@ -463,8 +477,8 @@ private void loadQueue(String parentName, Element element, if (parentName != null) { queueName = parentName + "." + queueName; } - Map acls = - new HashMap(); + Map acls = + new HashMap(); Map racls = new HashMap<>(); NodeList fields = element.getChildNodes(); boolean isLeaf = true; @@ -515,10 +529,10 @@ private void loadQueue(String parentName, Element element, queuePolicies.put(queueName, policy); } else if ("aclSubmitApps".equals(field.getTagName())) { String text = ((Text)field.getFirstChild()).getData(); - acls.put(QueueACL.SUBMIT_APPLICATIONS, new AccessControlList(text)); + acls.put(AccessType.SUBMIT_APP, new AccessControlList(text)); } else if ("aclAdministerApps".equals(field.getTagName())) { String text = ((Text)field.getFirstChild()).getData(); - acls.put(QueueACL.ADMINISTER_QUEUE, new AccessControlList(text)); + acls.put(AccessType.ADMINISTER_QUEUE, new AccessControlList(text)); } else if ("aclAdministerReservations".equals(field.getTagName())) { String text = ((Text)field.getFirstChild()).getData(); racls.put(ReservationACL.ADMINISTER_RESERVATIONS, @@ -567,6 +581,18 @@ private void loadQueue(String parentName, Element element, } configuredQueues.get(FSQueueType.PARENT).add(queueName); } + + // Set default acls if not defined + // The root queue defaults to all access + for (QueueACL acl : QueueACL.values()) { + AccessType accessType = SchedulerUtils.toAccessType(acl); + if (acls.get(accessType) == null){ + AccessControlList defaultAcl = queueName.equals(ROOT) ? + EVERYBODY_ACL : NOBODY_ACL; + acls.put(accessType, defaultAcl); + } + } + queueAcls.put(queueName, acls); resAcls.put(queueName, racls); if (maxQueueResources.containsKey(queueName) && @@ -580,8 +606,30 @@ private void loadQueue(String parentName, Element element, minQueueResources.get(queueName))); } } - + + + /** + * The default permission for the root queue is everybody ("*") + * and the default permission for all other queues is nobody ("") + * The default permission list would be loaded before the permissions + * from allocation file. + */ + protected List getDefaultPermissions() { + if (defaultPermissions == null) { + List permissions = new ArrayList(); + Map acls = + new HashMap(); + for (QueueACL acl : QueueACL.values()) { + acls.put(SchedulerUtils.toAccessType(acl), EVERYBODY_ACL); + } + permissions.add(new Permission( + new PrivilegedEntity(EntityType.QUEUE, ROOT), acls)); + defaultPermissions = permissions; + } + return defaultPermissions; + } + public interface Listener { - public void onReload(AllocationConfiguration info); + void onReload(AllocationConfiguration info) throws IOException; } } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/FSQueue.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/FSQueue.java index 25554dd..66d269b 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/FSQueue.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/FSQueue.java @@ -27,6 +27,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.hadoop.classification.InterfaceAudience.Private; import org.apache.hadoop.classification.InterfaceStability.Unstable; +import org.apache.hadoop.ipc.Server; import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.yarn.api.records.ApplicationAttemptId; import org.apache.hadoop.yarn.api.records.Priority; @@ -37,8 +38,13 @@ import org.apache.hadoop.yarn.api.records.Resource; import org.apache.hadoop.yarn.factories.RecordFactory; import org.apache.hadoop.yarn.factory.providers.RecordFactoryProvider; +import org.apache.hadoop.yarn.security.AccessRequest; +import org.apache.hadoop.yarn.security.PrivilegedEntity; +import org.apache.hadoop.yarn.security.YarnAuthorizationProvider; +import org.apache.hadoop.yarn.security.PrivilegedEntity.EntityType; import org.apache.hadoop.yarn.server.resourcemanager.resource.ResourceWeights; import org.apache.hadoop.yarn.server.resourcemanager.scheduler.Queue; +import org.apache.hadoop.yarn.server.resourcemanager.scheduler.SchedulerUtils; import org.apache.hadoop.yarn.util.resource.Resources; @Private @@ -51,6 +57,8 @@ private Resource steadyFairShare = Resources.createResource(0, 0); private final String name; protected final FairScheduler scheduler; + private final YarnAuthorizationProvider authorizer; + private final PrivilegedEntity queueEntity; private final FSQueueMetrics metrics; protected final FSParentQueue parent; @@ -67,6 +75,9 @@ public FSQueue(String name, FairScheduler scheduler, FSParentQueue parent) { this.name = name; this.scheduler = scheduler; + this.authorizer = + YarnAuthorizationProvider.getInstance(scheduler.getConf()); + this.queueEntity = new PrivilegedEntity(EntityType.QUEUE, name); this.metrics = FSQueueMetrics.forQueue(getName(), parent, true, scheduler.getConf()); metrics.setMinShare(getMinShare()); metrics.setMaxShare(getMaxShare()); @@ -85,7 +96,11 @@ public String getName() { public String getQueueName() { return name; } - + + public PrivilegedEntity getPrivilegedEntity() { + return queueEntity; + } + public SchedulingPolicy getPolicy() { return policy; } @@ -213,7 +228,10 @@ public void setSteadyFairShare(Resource steadyFairShare) { } public boolean hasAccess(QueueACL acl, UserGroupInformation user) { - return scheduler.getAllocationConfiguration().hasAccess(name, acl, user); + return authorizer.checkPermission( + new AccessRequest(getPrivilegedEntity(), user, + SchedulerUtils.toAccessType(acl), null, null, + Server.getRemoteAddress(), null)); } public long getFairSharePreemptionTimeout() { diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/FairScheduler.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/FairScheduler.java index ac384a1..7c7a6fd 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/FairScheduler.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/FairScheduler.java @@ -25,7 +25,9 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.logging.Log; @@ -34,6 +36,7 @@ import org.apache.hadoop.classification.InterfaceStability.Unstable; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.security.UserGroupInformation; +import org.apache.hadoop.security.authorize.AccessControlList; import org.apache.hadoop.yarn.api.records.ApplicationAttemptId; import org.apache.hadoop.yarn.api.records.ApplicationId; import org.apache.hadoop.yarn.api.records.Container; @@ -53,6 +56,11 @@ import org.apache.hadoop.yarn.exceptions.YarnException; import org.apache.hadoop.yarn.exceptions.YarnRuntimeException; import org.apache.hadoop.yarn.proto.YarnServiceProtos.SchedulerResourceTypes; +import org.apache.hadoop.yarn.security.AccessType; +import org.apache.hadoop.yarn.security.Permission; +import org.apache.hadoop.yarn.security.PrivilegedEntity; +import org.apache.hadoop.yarn.security.YarnAuthorizationProvider; +import org.apache.hadoop.yarn.security.PrivilegedEntity.EntityType; import org.apache.hadoop.yarn.server.api.protocolrecords.NMContainerStatus; import org.apache.hadoop.yarn.server.resourcemanager.RMContext; import org.apache.hadoop.yarn.server.resourcemanager.recovery.RMStateStore.RMState; @@ -127,6 +135,7 @@ AbstractYarnScheduler { private FairSchedulerConfiguration conf; + private YarnAuthorizationProvider authorizer; private Resource incrAllocation; private QueueManager queueMgr; private volatile Clock clock; @@ -1383,6 +1392,8 @@ private void initScheduler(Configuration conf) throws IOException { synchronized (this) { this.conf = new FairSchedulerConfiguration(conf); validateConf(this.conf); + + authorizer = YarnAuthorizationProvider.getInstance(conf); minimumAllocation = this.conf.getMinimumAllocation(); initMaximumResourceCapability(this.conf.getMaximumAllocation()); incrAllocation = this.conf.getIncrementAllocation(); @@ -1566,18 +1577,40 @@ public AllocationConfiguration getAllocationConfiguration() { AllocationFileLoaderService.Listener { @Override - public void onReload(AllocationConfiguration queueInfo) { + public void onReload(AllocationConfiguration queueInfo) + throws IOException { // Commit the reload; also create any queue defined in the alloc file // if it does not already exist, so it can be displayed on the web UI. synchronized (FairScheduler.this) { - allocConf = queueInfo; - allocConf.getDefaultSchedulingPolicy().initialize(getClusterResource()); - queueMgr.updateAllocationConfiguration(allocConf); - maxRunningEnforcer.updateRunnabilityOnReload(); + if (queueInfo == null) { + authorizer.setPermission(allocsLoader.getDefaultPermissions(), + UserGroupInformation.getCurrentUser()); + } else { + allocConf = queueInfo; + setQueueAcls(allocConf.getQueueAcls()); + allocConf.getDefaultSchedulingPolicy().initialize(getClusterResource()); + queueMgr.updateAllocationConfiguration(allocConf); + maxRunningEnforcer.updateRunnabilityOnReload(); + } } } } + private void setQueueAcls( + Map> queueAcls) + throws IOException { + authorizer.setPermission(allocsLoader.getDefaultPermissions(), + UserGroupInformation.getCurrentUser()); + List permissions = new ArrayList<>(); + for (Entry> queueAcl : + queueAcls.entrySet()) { + permissions.add(new Permission(new PrivilegedEntity(EntityType.QUEUE, + queueAcl.getKey()), queueAcl.getValue())); + } + authorizer.setPermission(permissions, + UserGroupInformation.getCurrentUser()); + } + @Override public List getAppsInQueue(String queueName) { FSQueue queue = queueMgr.getQueue(queueName); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/TestFairScheduler.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/TestFairScheduler.java index 87670c4..9650983 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/TestFairScheduler.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/TestFairScheduler.java @@ -74,6 +74,7 @@ import org.apache.hadoop.yarn.event.EventHandler; import org.apache.hadoop.yarn.exceptions.YarnException; import org.apache.hadoop.yarn.exceptions.YarnRuntimeException; +import org.apache.hadoop.yarn.security.YarnAuthorizationProvider; import org.apache.hadoop.yarn.server.resourcemanager.ApplicationMasterService; import org.apache.hadoop.yarn.server.resourcemanager.MockAM; import org.apache.hadoop.yarn.server.resourcemanager.MockNM; @@ -98,11 +99,9 @@ import org.apache.hadoop.yarn.server.resourcemanager.scheduler.AbstractYarnScheduler; import org.apache.hadoop.yarn.server.resourcemanager.scheduler.QueueMetrics; import org.apache.hadoop.yarn.server.resourcemanager.scheduler.SchedulerApplicationAttempt; - import org.apache.hadoop.yarn.server.resourcemanager.scheduler.SchedulerRequestKey; import org.apache.hadoop.yarn.server.resourcemanager.scheduler.SchedulerNode; import org.apache.hadoop.yarn.server.resourcemanager.scheduler.TestSchedulerUtils; - import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity .TestUtils; import org.apache.hadoop.yarn.server.resourcemanager.scheduler.event.AppAddedSchedulerEvent; @@ -162,6 +161,7 @@ public void tearDown() { } QueueMetrics.clearQueueMetrics(); DefaultMetricsSystem.shutdown(); + YarnAuthorizationProvider.destory(); }