Skip to content

Commit

Permalink
HADOOP-10651. Add ability to restrict service access using IP address…
Browse files Browse the repository at this point in the history
…es and hostnames. (Benoy Antony)
  • Loading branch information
Benoy Antony committed Jan 8, 2015
1 parent dc2eaa2 commit 20625c8
Show file tree
Hide file tree
Showing 4 changed files with 259 additions and 16 deletions.
Expand Up @@ -33,6 +33,7 @@
import org.apache.hadoop.security.KerberosInfo;
import org.apache.hadoop.security.SecurityUtil;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.util.MachineList;

import com.google.common.annotations.VisibleForTesting;

Expand All @@ -44,13 +45,18 @@
@InterfaceStability.Evolving
public class ServiceAuthorizationManager {
static final String BLOCKED = ".blocked";
static final String HOSTS = ".hosts";

private static final String HADOOP_POLICY_FILE = "hadoop-policy.xml";

// For each class, first ACL in the array specifies the allowed entries
// and second ACL specifies blocked entries.
private volatile Map<Class<?>, AccessControlList[]> protocolToAcls =
new IdentityHashMap<Class<?>, AccessControlList[]>();
// For each class, first MachineList in the array specifies the allowed entries
// and second MachineList specifies blocked entries.
private volatile Map<Class<?>, MachineList[]> protocolToMachineLists =
new IdentityHashMap<Class<?>, MachineList[]>();

/**
* Configuration key for controlling service-level authorization for Hadoop.
Expand Down Expand Up @@ -85,7 +91,8 @@ public void authorize(UserGroupInformation user,
InetAddress addr
) throws AuthorizationException {
AccessControlList[] acls = protocolToAcls.get(protocol);
if (acls == null) {
MachineList[] hosts = protocolToMachineLists.get(protocol);
if (acls == null || hosts == null) {
throw new AuthorizationException("Protocol " + protocol +
" is not known.");
}
Expand Down Expand Up @@ -115,6 +122,16 @@ public void authorize(UserGroupInformation user,
" is not authorized for protocol " + protocol +
", expected client Kerberos principal is " + clientPrincipal);
}
if (addr != null) {
String hostAddress = addr.getHostAddress();
if (hosts.length != 2 || !hosts[0].includes(hostAddress) ||
hosts[1].includes(hostAddress)) {
AUDITLOG.warn(AUTHZ_FAILED_FOR + " for protocol=" + protocol
+ " from host = " + hostAddress);
throw new AuthorizationException("Host " + hostAddress +
" is not authorized for protocol " + protocol) ;
}
}
AUDITLOG.info(AUTHZ_SUCCESSFUL_FOR + user + " for protocol="+protocol);
}

Expand All @@ -135,6 +152,8 @@ public void refreshWithLoadedConfiguration(Configuration conf,
PolicyProvider provider) {
final Map<Class<?>, AccessControlList[]> newAcls =
new IdentityHashMap<Class<?>, AccessControlList[]>();
final Map<Class<?>, MachineList[]> newMachineLists =
new IdentityHashMap<Class<?>, MachineList[]>();

String defaultAcl = conf.get(
CommonConfigurationKeys.HADOOP_SECURITY_SERVICE_AUTHORIZATION_DEFAULT_ACL,
Expand All @@ -143,6 +162,13 @@ public void refreshWithLoadedConfiguration(Configuration conf,
String defaultBlockedAcl = conf.get(
CommonConfigurationKeys.HADOOP_SECURITY_SERVICE_AUTHORIZATION_DEFAULT_BLOCKED_ACL, "");

String defaultServiceHostsKey = getHostKey(
CommonConfigurationKeys.HADOOP_SECURITY_SERVICE_AUTHORIZATION_DEFAULT_ACL);
String defaultMachineList = conf.get(defaultServiceHostsKey,
MachineList.WILDCARD_VALUE);
String defaultBlockedMachineList= conf.get(
defaultServiceHostsKey+ BLOCKED, "");

// Parse the config file
Service[] services = provider.getServices();
if (services != null) {
Expand All @@ -157,11 +183,26 @@ public void refreshWithLoadedConfiguration(Configuration conf,
conf.get(service.getServiceKey() + BLOCKED,
defaultBlockedAcl));
newAcls.put(service.getProtocol(), new AccessControlList[] {acl, blockedAcl});
String serviceHostsKey = getHostKey(service.getServiceKey());
MachineList machineList = new MachineList (conf.get(serviceHostsKey, defaultMachineList));
MachineList blockedMachineList = new MachineList(
conf.get(serviceHostsKey + BLOCKED, defaultBlockedMachineList));
newMachineLists.put(service.getProtocol(),
new MachineList[] {machineList, blockedMachineList});
}
}

// Flip to the newly parsed permissions
protocolToAcls = newAcls;
protocolToMachineLists = newMachineLists;
}

private String getHostKey(String serviceKey) {
int endIndex = serviceKey.lastIndexOf(".");
if (endIndex != -1) {
return serviceKey.substring(0, endIndex)+ HOSTS;
}
return serviceKey;
}

@VisibleForTesting
Expand All @@ -178,4 +219,19 @@ public AccessControlList getProtocolsAcls(Class<?> className) {
public AccessControlList getProtocolsBlockedAcls(Class<?> className) {
return protocolToAcls.get(className)[1];
}

@VisibleForTesting
public Set<Class<?>> getProtocolsWithMachineLists() {
return protocolToMachineLists.keySet();
}

@VisibleForTesting
public MachineList getProtocolsMachineList(Class<?> className) {
return protocolToMachineLists.get(className)[0];
}

@VisibleForTesting
public MachineList getProtocolsBlockedMachineList(Class<?> className) {
return protocolToMachineLists.get(className)[1];
}
}
Expand Up @@ -45,6 +45,7 @@
public class MachineList {

public static final Log LOG = LogFactory.getLog(MachineList.class);
public static final String WILDCARD_VALUE = "*";

/**
* InetAddressFactory is used to obtain InetAddress from host.
Expand Down Expand Up @@ -91,7 +92,7 @@ public MachineList(Collection<String> hostEntries) {
public MachineList(Collection<String> hostEntries, InetAddressFactory addressFactory) {
this.addressFactory = addressFactory;
if (hostEntries != null) {
if ((hostEntries.size() == 1) && (hostEntries.contains("*"))) {
if ((hostEntries.size() == 1) && (hostEntries.contains(WILDCARD_VALUE))) {
all = true;
ipAddresses = null;
hostNames = null;
Expand Down
Expand Up @@ -159,6 +159,31 @@ security.ha.service.protocol.acl | ACL for HAService protocol used by HAAdm
the ability to refresh the service-level authorization configuration to
certain users/groups.

** Access Control using list of ip addresses, host names and ip ranges

Access to a service can be controlled based on the ip address of the client accessing
the service. It is possible to restrict access to a service from a set of machines by
specifying a list of ip addresses, host names and ip ranges. The property name for each service
is derived from the corresponding acl's property name. If the property name of acl is
security.client.protocol.acl, property name for the hosts list will be
security.client.protocol.hosts.

If hosts list is not defined for a service, the value of
<<<security.service.authorization.default.hosts>>> is applied. If
<<<security.service.authorization.default.hosts>>> is not defined, <<<*>>> is applied.

It is possible to specify a blocked list of hosts. Only those machines which are in the
hosts list, but not in the blocked hosts list will be granted access to the service. The property
name is derived by suffixing with ".blocked".

Example: The property name of blocked hosts list for <<<security.client.protocol.hosts>>
will be <<<security.client.protocol.hosts.blocked>>>

If blocked hosts list is not defined for a service, the value of
<<<security.service.authorization.default.hosts.blocked>>> is applied. If
<<<security.service.authorization.default.hosts.blocked>>> is not defined,
empty blocked hosts list is applied.

** Examples

Allow only users <<<alice>>>, <<<bob>>> and users in the <<<mapreduce>>> group to submit
Expand Down

0 comments on commit 20625c8

Please sign in to comment.