HADOOP-10982

This commit is contained in:
Alejandro Abdelnur 2014-09-16 23:07:01 -07:00
parent 0a495bef5c
commit d9a86031a0
3 changed files with 72 additions and 11 deletions

View File

@ -45,6 +45,7 @@
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.lang.reflect.UndeclaredThrowableException;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URI;
@ -400,6 +401,8 @@ public HttpURLConnection run() throws Exception {
});
} catch (IOException ex) {
throw ex;
} catch (UndeclaredThrowableException ex) {
throw new IOException(ex.getUndeclaredThrowable());
} catch (Exception ex) {
throw new IOException(ex);
}

View File

@ -602,7 +602,31 @@ $ keytool -genkey -alias tomcat -keyalg RSA
*** HTTP Kerberos Principals Configuration
TBD
When KMS instances are behind a load-balancer or VIP, clients will use the
hostname of the VIP. For Kerberos SPNEGO authentication, the hostname of the
URL is used to construct the Kerberos service name of the server,
<<<HTTP/#HOSTNAME#>>>. This means that all KMS instances must have have a
Kerberos service name with the load-balancer or VIP hostname.
In order to be able to access directly a specific KMS instance, the KMS
instance must also have Kebero service name with its own hostname. This is
require for monitoring and admin purposes.
Both Kerberos service principal credentials (for the load-balancer/VIP
hostname and for the actual KMS instance hostname) must be in the keytab file
configured for authentication. And the principal name specified in the
configuration must be '*'. For example:
+---+
<property>
<name>hadoop.kms.authentication.kerberos.principal</name>
<value>*</value>
</property>
+---+
<<NOTE:>> If using HTTPS, the SSL certificate used by the KMS instance must
be configured to support multiple hostnames (see Java 7
<<<keytool>> SAN extension support for details on how to do this).
*** HTTP Authentication Signature

View File

@ -32,6 +32,7 @@
import org.apache.hadoop.security.Credentials;
import org.apache.hadoop.security.SecurityUtil;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.security.authentication.client.AuthenticationException;
import org.apache.hadoop.security.authorize.AuthorizationException;
import org.apache.hadoop.security.ssl.KeyStoreTestUtil;
import org.junit.AfterClass;
@ -209,6 +210,7 @@ public static void setUpMiniKdc() throws Exception {
keytab = new File(kdcDir, "keytab");
List<String> principals = new ArrayList<String>();
principals.add("HTTP/localhost");
principals.add("HTTP/127.0.0.1");
principals.add("client");
principals.add("hdfs");
principals.add("otheradmin");
@ -251,8 +253,8 @@ private <T> T doAs(String user, final PrivilegedExceptionAction<T> action)
}
}
public void testStartStop(final boolean ssl, final boolean kerberos)
throws Exception {
public void testStartStop(final boolean ssl, final boolean kerberos,
final boolean multipleServerPrincipals) throws Exception {
Configuration conf = new Configuration();
if (kerberos) {
conf.set("hadoop.security.authentication", "kerberos");
@ -278,7 +280,12 @@ public void testStartStop(final boolean ssl, final boolean kerberos)
conf.set("hadoop.kms.authentication.type", "kerberos");
conf.set("hadoop.kms.authentication.kerberos.keytab",
keytab.getAbsolutePath());
conf.set("hadoop.kms.authentication.kerberos.principal", "HTTP/localhost");
if (multipleServerPrincipals) {
conf.set("hadoop.kms.authentication.kerberos.principal", "*");
} else {
conf.set("hadoop.kms.authentication.kerberos.principal",
"HTTP/localhost");
}
conf.set("hadoop.kms.authentication.kerberos.name.rules", "DEFAULT");
}
@ -291,21 +298,42 @@ public Void call() throws Exception {
URL url = getKMSUrl();
Assert.assertEquals(keystore != null,
url.getProtocol().equals("https"));
final URI uri = createKMSUri(getKMSUrl());
if (kerberos) {
for (String user : new String[]{"client", "client/host"}) {
doAs(user, new PrivilegedExceptionAction<Void>() {
@Override
public Void run() throws Exception {
final KeyProvider kp = new KMSClientProvider(uri, conf);
URI uri = createKMSUri(getKMSUrl());
KeyProvider kp = new KMSClientProvider(uri, conf);
// getKeys() empty
Assert.assertTrue(kp.getKeys().isEmpty());
if (!ssl) {
String url = getKMSUrl().toString();
url = url.replace("localhost", "127.0.0.1");
uri = createKMSUri(new URL(url));
if (multipleServerPrincipals) {
kp = new KMSClientProvider(uri, conf);
// getKeys() empty
Assert.assertTrue(kp.getKeys().isEmpty());
} else {
kp = new KMSClientProvider(uri, conf);
try {
kp.getKeys().isEmpty();
Assert.fail();
} catch (IOException ex) {
Assert.assertEquals(AuthenticationException.class,
ex.getCause().getClass());
}
}
}
return null;
}
});
}
} else {
URI uri = createKMSUri(getKMSUrl());
KeyProvider kp = new KMSClientProvider(uri, conf);
// getKeys() empty
Assert.assertTrue(kp.getKeys().isEmpty());
@ -317,22 +345,27 @@ public Void run() throws Exception {
@Test
public void testStartStopHttpPseudo() throws Exception {
testStartStop(false, false);
testStartStop(false, false, false);
}
@Test
public void testStartStopHttpsPseudo() throws Exception {
testStartStop(true, false);
testStartStop(true, false, false);
}
@Test
public void testStartStopHttpKerberos() throws Exception {
testStartStop(false, true);
testStartStop(false, true, false);
}
@Test
public void testStartStopHttpsKerberos() throws Exception {
testStartStop(true, true);
testStartStop(true, true, false);
}
@Test
public void testStartStopHttpsKerberosMultiplePrincipals() throws Exception {
testStartStop(false, true, true);
}
@Test
@ -1340,7 +1373,8 @@ public Void call() throws Exception {
KeyProvider kp = new KMSClientProvider(uri, conf);
kp.createKey("kA", new KeyProvider.Options(conf));
} catch (IOException ex) {
System.out.println(ex.getMessage());
Assert.assertEquals(AuthenticationException.class,
ex.getCause().getClass());
}
doAs("client", new PrivilegedExceptionAction<Void>() {