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..f16067c 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,14 @@ public static YarnAuthorizationProvider getInstance(Configuration conf) { return authorizer; } + // for test + public static void destory() { + if (authorizer != null) { + LOG.info(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..476f0fc 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); + Map queueAcls = this.queueAcls.get(queue); if (queueAcls != null) { - AccessControlList operationAcl = queueAcls.get(operation); + AccessControlList operationAcl = queueAcls.get( + SchedulerUtils.toAccessType(operation)); if (operationAcl != null) { return operationAcl; } @@ -193,6 +195,10 @@ public AccessControlList getQueueAcl(String queue, QueueACL operation) { return (queue.equals("root")) ? EVERYBODY_ACL : NOBODY_ACL; } + public Map> getQueueAcls() { + return this.queueAcls; + } + @Override /** * Get the map of reservation ACLs to {@link AccessControlList} for the @@ -291,21 +297,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 661caa7..1d07a8c 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; @@ -73,6 +78,10 @@ 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 @@ -80,7 +89,7 @@ // Path to XML file containing allocations. private File allocFile; - + private Listener reloadListener; @VisibleForTesting @@ -89,6 +98,8 @@ private Thread reloadThread; private volatile boolean running = true; + private List defaultPermissions; + public AllocationFileLoaderService() { this(SystemClock.getInstance()); } @@ -207,6 +218,7 @@ public synchronized void reloadAllocations() throws IOException, ParserConfigurationException, SAXException, AllocationConfigurationException { if (allocFile == null) { + reloadListener.onReload(null); return; } LOG.info("Loading allocation file " + allocFile); @@ -223,8 +235,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(); @@ -439,7 +451,7 @@ private void loadQueue(String parentName, Element element, Map minSharePreemptionTimeouts, Map fairSharePreemptionTimeouts, Map fairSharePreemptionThresholds, - Map> queueAcls, + Map> queueAcls, Map> resAcls, Map> configuredQueues, Set reservableQueues, @@ -461,8 +473,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; @@ -513,10 +525,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, @@ -565,6 +577,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) && @@ -578,8 +602,23 @@ private void loadQueue(String parentName, Element element, minQueueResources.get(queueName))); } } - + + 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); + public 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..497e0b7 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; + protected final YarnAuthorizationProvider authorizer; + protected final PrivilegedEntity queueEntity; private final FSQueueMetrics metrics; protected final FSParentQueue parent; @@ -67,6 +75,8 @@ 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 +95,11 @@ public String getName() { public String getQueueName() { return name; } - + + public PrivilegedEntity getPrivilegedEntity() { + return queueEntity; + } + public SchedulingPolicy getPolicy() { return policy; } @@ -213,7 +227,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 bc953ba..d7a792c 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,11 +1577,18 @@ 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) { + if (queueInfo == null) { + authorizer.setPermission(allocsLoader.getDefaultPermissions(), + UserGroupInformation.getCurrentUser()); + return; + } allocConf = queueInfo; + setQueueAcls(allocConf.getQueueAcls()); allocConf.getDefaultSchedulingPolicy().initialize(getClusterResource()); queueMgr.updateAllocationConfiguration(allocConf); maxRunningEnforcer.updateRunnabilityOnReload(); @@ -1578,6 +1596,19 @@ public void onReload(AllocationConfiguration queueInfo) { } } + private void setQueueAcls( + Map> queueAcls) + throws IOException { + 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 43ebe53..2f516e3 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 @@ -73,6 +73,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.MockNodes; import org.apache.hadoop.yarn.server.resourcemanager.MockRM; @@ -151,6 +152,7 @@ public void tearDown() { } QueueMetrics.clearQueueMetrics(); DefaultMetricsSystem.shutdown(); + YarnAuthorizationProvider.destory(); }