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

This commit is contained in:
Wangda Tan 2016-07-06 16:42:35 -07:00
parent c3d9ac82af
commit e246cf74c9
8 changed files with 67 additions and 18 deletions

View File

@ -18,8 +18,12 @@
package org.apache.hadoop.yarn.security; 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 org.apache.hadoop.security.UserGroupInformation;
import java.util.List;
/** /**
* This request object contains all the context information to determine whether * This request object contains all the context information to determine whether
* a user has permission to access the target entity. * a user has permission to access the target entity.
@ -30,7 +34,14 @@ import org.apache.hadoop.security.UserGroupInformation;
* if no app is associated. * if no app is associated.
* appName : the associated app name for current access. This could be null if * appName : the associated app name for current access. This could be null if
* no app is associated. * 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 { public class AccessRequest {
private PrivilegedEntity entity; private PrivilegedEntity entity;
@ -38,14 +49,19 @@ public class AccessRequest {
private AccessType accessType; private AccessType accessType;
private String appId; private String appId;
private String appName; private String appName;
private String remoteAddress;
private List<String> forwardedAddresses;
public AccessRequest(PrivilegedEntity entity, UserGroupInformation user, 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.entity = entity;
this.user = user; this.user = user;
this.accessType = accessType; this.accessType = accessType;
this.appId = appId; this.appId = appId;
this.appName = appName; this.appName = appName;
this.remoteAddress = remoteAddress;
this.forwardedAddresses = forwardedAddresses;
} }
public UserGroupInformation getUser() { public UserGroupInformation getUser() {
@ -67,4 +83,13 @@ public class AccessRequest {
public PrivilegedEntity getEntity() { public PrivilegedEntity getEntity() {
return entity; return entity;
} }
public List<String> getForwardedAddresses() {
return forwardedAddresses;
}
public String getRemoteAddress() {
return remoteAddress;
}
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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