Browse Source

YARN-5294. Pass remote ip address down to YarnAuthorizationProvider. (Jian He via wangda)

Wangda Tan 9 years ago
parent
commit
e246cf74c9

+ 26 - 1
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/security/AccessRequest.java

@@ -18,8 +18,12 @@
 
 package org.apache.hadoop.yarn.security;
 
+import org.apache.hadoop.classification.InterfaceAudience.Public;
+import org.apache.hadoop.classification.InterfaceStability.Unstable;
 import org.apache.hadoop.security.UserGroupInformation;
 
+import java.util.List;
+
 /**
  * This request object contains all the context information to determine whether
  * a user has permission to access the target entity.
@@ -30,7 +34,14 @@ import org.apache.hadoop.security.UserGroupInformation;
  *              if no app is associated.
  * appName    : the associated app name for current access. This could be null if
  *              no app is associated.
+ * remoteAddress : The caller's remote ip address.
+ * forwardedAddresses : In case this is an http request, this contains the
+ *                    originating IP address of a client connecting to a web
+ *                    server through an HTTP proxy or load balancer. This
+ *                    parameter is null, if it's a RPC request.
  */
+@Public
+@Unstable
 public class AccessRequest {
 
   private PrivilegedEntity entity;
@@ -38,14 +49,19 @@ public class AccessRequest {
   private AccessType accessType;
   private String appId;
   private String appName;
+  private String remoteAddress;
+  private List<String> forwardedAddresses;
 
   public AccessRequest(PrivilegedEntity entity, UserGroupInformation user,
-      AccessType accessType, String appId, String appName) {
+      AccessType accessType, String appId, String appName, String remoteAddress,
+      List<String> forwardedAddresses) {
     this.entity = entity;
     this.user = user;
     this.accessType = accessType;
     this.appId = appId;
     this.appName = appName;
+    this.remoteAddress = remoteAddress;
+    this.forwardedAddresses = forwardedAddresses;
   }
 
   public UserGroupInformation getUser() {
@@ -67,4 +83,13 @@ public class AccessRequest {
   public PrivilegedEntity getEntity() {
     return entity;
   }
+
+
+  public List<String> getForwardedAddresses() {
+    return forwardedAddresses;
+  }
+
+  public String getRemoteAddress() {
+    return remoteAddress;
+  }
 }

+ 2 - 1
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/ClientRMService.java

@@ -306,7 +306,8 @@ public class ClientRMService extends AbstractService implements
     return applicationsACLsManager
         .checkAccess(callerUGI, operationPerformed, owner,
             application.getApplicationId()) || queueACLsManager
-        .checkAccess(callerUGI, QueueACL.ADMINISTER_QUEUE, application);
+        .checkAccess(callerUGI, QueueACL.ADMINISTER_QUEUE, application,
+            Server.getRemoteAddress(), null);
   }
 
   ApplicationId getNewApplicationId() {

+ 5 - 2
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/RMAppManager.java

@@ -26,6 +26,7 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.io.DataInputByteBuffer;
+import org.apache.hadoop.ipc.Server;
 import org.apache.hadoop.security.AccessControlException;
 import org.apache.hadoop.security.Credentials;
 import org.apache.hadoop.security.UserGroupInformation;
@@ -370,11 +371,13 @@ public class RMAppManager implements EventHandler<RMAppManagerEvent>,
           && !authorizer.checkPermission(
               new AccessRequest(csqueue.getPrivilegedEntity(), userUgi,
                   SchedulerUtils.toAccessType(QueueACL.SUBMIT_APPLICATIONS),
-                  applicationId.toString(), appName))
+                  applicationId.toString(), appName, Server.getRemoteAddress(),
+                  null))
           && !authorizer.checkPermission(
               new AccessRequest(csqueue.getPrivilegedEntity(), userUgi,
                   SchedulerUtils.toAccessType(QueueACL.ADMINISTER_QUEUE),
-                  applicationId.toString(), appName))) {
+                  applicationId.toString(), appName, Server.getRemoteAddress(),
+                  null))) {
         throw new AccessControlException(
             "User " + user + " does not have permission to submit "
                 + applicationId + " to queue " + submissionContext.getQueue());

+ 2 - 1
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/AbstractCSQueue.java

@@ -29,6 +29,7 @@ import org.apache.commons.lang.StringUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.classification.InterfaceAudience.Private;
+import org.apache.hadoop.ipc.Server;
 import org.apache.hadoop.security.UserGroupInformation;
 import org.apache.hadoop.security.authorize.AccessControlList;
 import org.apache.hadoop.yarn.api.records.Priority;
@@ -199,7 +200,7 @@ public abstract class AbstractCSQueue implements CSQueue {
   public boolean hasAccess(QueueACL acl, UserGroupInformation user) {
     return authorizer.checkPermission(
         new AccessRequest(queueEntity, user, SchedulerUtils.toAccessType(acl),
-            null, null));
+            null, null, Server.getRemoteAddress(), null));
   }
 
   @Override

+ 6 - 6
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/security/QueueACLsManager.java

@@ -18,6 +18,7 @@
 
 package org.apache.hadoop.yarn.server.resourcemanager.security;
 
+import com.google.common.annotations.VisibleForTesting;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.conf.Configuration;
@@ -26,15 +27,14 @@ import org.apache.hadoop.yarn.api.records.QueueACL;
 import org.apache.hadoop.yarn.conf.YarnConfiguration;
 import org.apache.hadoop.yarn.security.AccessRequest;
 import org.apache.hadoop.yarn.security.YarnAuthorizationProvider;
-import org.apache.hadoop.yarn.server.resourcemanager.ResourceTrackerService;
 import org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMApp;
 import org.apache.hadoop.yarn.server.resourcemanager.scheduler.ResourceScheduler;
-
-import com.google.common.annotations.VisibleForTesting;
 import org.apache.hadoop.yarn.server.resourcemanager.scheduler.SchedulerUtils;
 import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CSQueue;
 import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler;
 
+import java.util.List;
+
 public class QueueACLsManager {
 
   private static final Log LOG = LogFactory.getLog(QueueACLsManager.class);
@@ -56,7 +56,7 @@ public class QueueACLsManager {
   }
 
   public boolean checkAccess(UserGroupInformation callerUGI, QueueACL acl,
-      RMApp app) {
+      RMApp app, String remoteAddress, List<String> forwardedAddresses) {
     if (!isACLsEnable) {
       return true;
     }
@@ -71,11 +71,11 @@ public class QueueACLsManager {
             .getApplicationId());
         return true;
       }
-
       return authorizer.checkPermission(
           new AccessRequest(queue.getPrivilegedEntity(), callerUGI,
               SchedulerUtils.toAccessType(acl),
-              app.getApplicationId().toString(), app.getName()));
+              app.getApplicationId().toString(), app.getName(),
+              remoteAddress, forwardedAddresses));
     } else {
       return scheduler.checkAccess(callerUGI, acl, app.getQueue());
     }

+ 8 - 1
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java

@@ -25,6 +25,7 @@ import java.security.AccessControlException;
 import java.security.Principal;
 import java.security.PrivilegedExceptionAction;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.EnumSet;
 import java.util.HashMap;
@@ -228,12 +229,18 @@ public class RMWebServices extends WebServices {
   protected Boolean hasAccess(RMApp app, HttpServletRequest hsr) {
     // Check for the authorization.
     UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true);
+    List<String> forwardedAddresses = null;
+    String forwardedFor = hsr.getHeader("X-Forwarded-For");
+    if (forwardedFor != null) {
+      forwardedAddresses = Arrays.asList(forwardedFor.split(","));
+    }
     if (callerUGI != null
         && !(this.rm.getApplicationACLsManager().checkAccess(callerUGI,
               ApplicationAccessType.VIEW_APP, app.getUser(),
               app.getApplicationId()) ||
             this.rm.getQueueACLsManager().checkAccess(callerUGI,
-                QueueACL.ADMINISTER_QUEUE, app))) {
+                QueueACL.ADMINISTER_QUEUE, app, hsr.getRemoteAddr(),
+                forwardedAddresses))) {
       return false;
     }
     return true;

+ 3 - 1
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/TestApplicationACLs.java

@@ -66,6 +66,7 @@ import org.apache.hadoop.yarn.server.utils.BuilderUtils;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.mockito.Matchers;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 
@@ -112,7 +113,8 @@ public class TestApplicationACLs {
           Configuration conf) {
         QueueACLsManager mockQueueACLsManager = mock(QueueACLsManager.class);
         when(mockQueueACLsManager.checkAccess(any(UserGroupInformation.class),
-            any(QueueACL.class), any(RMApp.class))).thenAnswer(new Answer() {
+            any(QueueACL.class), any(RMApp.class), any(String.class),
+            Matchers.<List<String>>any())).thenAnswer(new Answer() {
           public Object answer(InvocationOnMock invocation) {
             return isQueueUser;
           }

+ 15 - 5
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/TestClientRMService.java

@@ -151,6 +151,7 @@ import org.junit.Test;
 
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Sets;
+import org.mockito.Matchers;
 
 public class TestClientRMService {
 
@@ -474,7 +475,8 @@ public class TestClientRMService {
     QueueACLsManager mockQueueACLsManager = mock(QueueACLsManager.class);
     when(
         mockQueueACLsManager.checkAccess(any(UserGroupInformation.class),
-            any(QueueACL.class), any(RMApp.class))).thenReturn(true);
+            any(QueueACL.class), any(RMApp.class), any(String.class),
+            Matchers.<List<String>>any())).thenReturn(true);
     return new ClientRMService(rmContext, yarnScheduler, appManager,
         mockAclsManager, mockQueueACLsManager, null);
   }
@@ -575,7 +577,9 @@ public class TestClientRMService {
     ApplicationACLsManager mockAclsManager = mock(ApplicationACLsManager.class);
     QueueACLsManager mockQueueACLsManager = mock(QueueACLsManager.class);
     when(mockQueueACLsManager.checkAccess(any(UserGroupInformation.class),
-        any(QueueACL.class), any(RMApp.class))).thenReturn(true);
+        any(QueueACL.class), any(RMApp.class), any(String.class),
+        Matchers.<List<String>>any()))
+        .thenReturn(true);
     when(mockAclsManager.checkAccess(any(UserGroupInformation.class),
         any(ApplicationAccessType.class), anyString(),
         any(ApplicationId.class))).thenReturn(true);
@@ -601,7 +605,9 @@ public class TestClientRMService {
     QueueACLsManager mockQueueACLsManager1 =
         mock(QueueACLsManager.class);
     when(mockQueueACLsManager1.checkAccess(any(UserGroupInformation.class),
-        any(QueueACL.class), any(RMApp.class))).thenReturn(false);
+        any(QueueACL.class), any(RMApp.class), any(String.class),
+        Matchers.<List<String>>any()))
+        .thenReturn(false);
     when(mockAclsManager1.checkAccess(any(UserGroupInformation.class),
         any(ApplicationAccessType.class), anyString(),
         any(ApplicationId.class))).thenReturn(false);
@@ -640,7 +646,9 @@ public class TestClientRMService {
 
     QueueACLsManager mockQueueACLsManager = mock(QueueACLsManager.class);
     when(mockQueueACLsManager.checkAccess(any(UserGroupInformation.class),
-        any(QueueACL.class), any(RMApp.class))).thenReturn(true);
+        any(QueueACL.class), any(RMApp.class), any(String.class),
+        Matchers.<List<String>>any()))
+        .thenReturn(true);
     ClientRMService rmService =
         new ClientRMService(rmContext, yarnScheduler, appManager,
             mockAclsManager, mockQueueACLsManager, null);
@@ -728,7 +736,9 @@ public class TestClientRMService {
     ApplicationACLsManager mockAclsManager = mock(ApplicationACLsManager.class);
     QueueACLsManager mockQueueACLsManager = mock(QueueACLsManager.class);
     when(mockQueueACLsManager.checkAccess(any(UserGroupInformation.class),
-        any(QueueACL.class), any(RMApp.class))).thenReturn(true);
+        any(QueueACL.class), any(RMApp.class), any(String.class),
+        Matchers.<List<String>>any()))
+        .thenReturn(true);
     ClientRMService rmService =
         new ClientRMService(rmContext, yarnScheduler, appManager,
             mockAclsManager, mockQueueACLsManager, null);