Revert "HADOOP-15996. Improved Kerberos username mapping strategy in Hadoop."

This reverts commit af589262c8.
This commit is contained in:
Sunil G 2019-01-08 07:38:51 +05:30
parent c968568c58
commit 4b457f0f43
13 changed files with 31 additions and 298 deletions

View File

@ -88,12 +88,6 @@ public class KerberosAuthenticationHandler implements AuthenticationHandler {
*/ */
public static final String NAME_RULES = TYPE + ".name.rules"; public static final String NAME_RULES = TYPE + ".name.rules";
/**
* Constant for the configuration property that indicates how auth_to_local
* rules are evaluated.
*/
public static final String RULE_MECHANISM = TYPE + ".name.rules.mechanism";
private String type; private String type;
private String keytab; private String keytab;
private GSSManager gssManager; private GSSManager gssManager;
@ -169,10 +163,7 @@ public class KerberosAuthenticationHandler implements AuthenticationHandler {
if (nameRules != null) { if (nameRules != null) {
KerberosName.setRules(nameRules); KerberosName.setRules(nameRules);
} }
String ruleMechanism = config.getProperty(RULE_MECHANISM, null);
if (ruleMechanism != null) {
KerberosName.setRuleMechanism(ruleMechanism);
}
try { try {
gssManager = Subject.doAs(serverSubject, gssManager = Subject.doAs(serverSubject,
new PrivilegedExceptionAction<GSSManager>() { new PrivilegedExceptionAction<GSSManager>() {

View File

@ -44,19 +44,6 @@ import org.slf4j.LoggerFactory;
public class KerberosName { public class KerberosName {
private static final Logger LOG = LoggerFactory.getLogger(KerberosName.class); private static final Logger LOG = LoggerFactory.getLogger(KerberosName.class);
/**
* Constant that defines auth_to_local legacy hadoop evaluation
*/
public static final String MECHANISM_HADOOP = "hadoop";
/**
* Constant that defines auth_to_local MIT evaluation
*/
public static final String MECHANISM_MIT = "mit";
/** Constant that defines the default behavior of the rule mechanism */
public static final String DEFAULT_MECHANISM = MECHANISM_HADOOP;
/** The first component of the name */ /** The first component of the name */
private final String serviceName; private final String serviceName;
/** The second component of the name. It may be null. */ /** The second component of the name. It may be null. */
@ -94,11 +81,6 @@ public class KerberosName {
*/ */
private static List<Rule> rules; private static List<Rule> rules;
/**
* How to evaluate auth_to_local rules
*/
private static String ruleMechanism = null;
private static String defaultRealm = null; private static String defaultRealm = null;
@VisibleForTesting @VisibleForTesting
@ -322,11 +304,10 @@ public class KerberosName {
* array. * array.
* @param params first element is the realm, second and later elements are * @param params first element is the realm, second and later elements are
* are the components of the name "a/b@FOO" -> {"FOO", "a", "b"} * are the components of the name "a/b@FOO" -> {"FOO", "a", "b"}
* @param ruleMechanism defines the rule evaluation mechanism
* @return the short name if this rule applies or null * @return the short name if this rule applies or null
* @throws IOException throws if something is wrong with the rules * @throws IOException throws if something is wrong with the rules
*/ */
String apply(String[] params, String ruleMechanism) throws IOException { String apply(String[] params) throws IOException {
String result = null; String result = null;
if (isDefault) { if (isDefault) {
if (getDefaultRealm().equals(params[0])) { if (getDefaultRealm().equals(params[0])) {
@ -342,9 +323,7 @@ public class KerberosName {
} }
} }
} }
if (result != null if (result != null && nonSimplePattern.matcher(result).find()) {
&& nonSimplePattern.matcher(result).find()
&& ruleMechanism.equalsIgnoreCase(MECHANISM_HADOOP)) {
throw new NoMatchingRule("Non-simple name " + result + throw new NoMatchingRule("Non-simple name " + result +
" after auth_to_local rule " + this); " after auth_to_local rule " + this);
} }
@ -413,22 +392,21 @@ public class KerberosName {
} else { } else {
params = new String[]{realm, serviceName, hostName}; params = new String[]{realm, serviceName, hostName};
} }
String ruleMechanism = this.ruleMechanism;
if (ruleMechanism == null && rules != null) {
LOG.warn("auth_to_local rule mechanism not set."
+ "Using default of " + DEFAULT_MECHANISM);
ruleMechanism = DEFAULT_MECHANISM;
}
for(Rule r: rules) { for(Rule r: rules) {
String result = r.apply(params, ruleMechanism); String result = r.apply(params);
if (result != null) { if (result != null) {
return result; return result;
} }
} }
if (ruleMechanism.equalsIgnoreCase(MECHANISM_HADOOP)) { throw new NoMatchingRule("No rules applied to " + toString());
throw new NoMatchingRule("No rules applied to " + toString()); }
}
return toString(); /**
* Set the rules.
* @param ruleString the rules string.
*/
public static void setRules(String ruleString) {
rules = (ruleString != null) ? parseRules(ruleString) : null;
} }
/** /**
@ -456,47 +434,6 @@ public class KerberosName {
return rules != null; return rules != null;
} }
/**
* Indicates of the rule mechanism has been set
*
* @return if the rule mechanism has been set.
*/
public static boolean hasRuleMechanismBeenSet() {
return ruleMechanism != null;
}
/**
* Set the rules.
* @param ruleString the rules string.
*/
public static void setRules(String ruleString) {
rules = (ruleString != null) ? parseRules(ruleString) : null;
}
/**
*
* @param ruleMech the evaluation type: hadoop, mit
* 'hadoop' indicates '@' or '/' are not allowed the result
* evaluation. 'MIT' indicates that auth_to_local
* rules follow MIT Kerberos evaluation.
*/
public static void setRuleMechanism(String ruleMech) {
if (ruleMech != null
&& (!ruleMech.equalsIgnoreCase(MECHANISM_HADOOP)
&& !ruleMech.equalsIgnoreCase(MECHANISM_MIT))) {
throw new IllegalArgumentException("Invalid rule mechanism: " + ruleMech);
}
ruleMechanism = ruleMech;
}
/**
* Get the rule evaluation mechanism
* @return the rule evaluation mechanism
*/
public static String getRuleMechanism() {
return ruleMechanism;
}
static void printRules() throws IOException { static void printRules() throws IOException {
int i = 0; int i = 0;
for(Rule r: rules) { for(Rule r: rules) {

View File

@ -65,7 +65,6 @@ public class TestKerberosAuthenticator extends KerberosSecurityTestcase {
props.setProperty(KerberosAuthenticationHandler.KEYTAB, KerberosTestUtils.getKeytabFile()); props.setProperty(KerberosAuthenticationHandler.KEYTAB, KerberosTestUtils.getKeytabFile());
props.setProperty(KerberosAuthenticationHandler.NAME_RULES, props.setProperty(KerberosAuthenticationHandler.NAME_RULES,
"RULE:[1:$1@$0](.*@" + KerberosTestUtils.getRealm()+")s/@.*//\n"); "RULE:[1:$1@$0](.*@" + KerberosTestUtils.getRealm()+")s/@.*//\n");
props.setProperty(KerberosAuthenticationHandler.RULE_MECHANISM, "hadoop");
return props; return props;
} }

View File

@ -65,8 +65,6 @@ public class TestKerberosAuthenticationHandler
KerberosTestUtils.getKeytabFile()); KerberosTestUtils.getKeytabFile());
props.setProperty(KerberosAuthenticationHandler.NAME_RULES, props.setProperty(KerberosAuthenticationHandler.NAME_RULES,
"RULE:[1:$1@$0](.*@" + KerberosTestUtils.getRealm()+")s/@.*//\n"); "RULE:[1:$1@$0](.*@" + KerberosTestUtils.getRealm()+")s/@.*//\n");
props.setProperty(KerberosAuthenticationHandler.RULE_MECHANISM,
KerberosName.MECHANISM_HADOOP);
return props; return props;
} }
@ -91,18 +89,18 @@ public class TestKerberosAuthenticationHandler
} }
@Test(timeout=60000) @Test(timeout=60000)
public void testNameRulesHadoop() throws Exception { public void testNameRules() throws Exception {
KerberosName kn = new KerberosName(KerberosTestUtils.getServerPrincipal()); KerberosName kn = new KerberosName(KerberosTestUtils.getServerPrincipal());
Assert.assertEquals(KerberosTestUtils.getRealm(), kn.getRealm()); Assert.assertEquals(KerberosTestUtils.getRealm(), kn.getRealm());
//destroy handler created in setUp() //destroy handler created in setUp()
handler.destroy(); handler.destroy();
KerberosName.setRules("RULE:[1:$1@$0](.*@FOO)s/@.*//\nDEFAULT");
handler = getNewAuthenticationHandler(); handler = getNewAuthenticationHandler();
Properties props = getDefaultProperties(); Properties props = getDefaultProperties();
props.setProperty(KerberosAuthenticationHandler.NAME_RULES, props.setProperty(KerberosAuthenticationHandler.NAME_RULES, "RULE:[1:$1@$0](.*@BAR)s/@.*//\nDEFAULT");
"RULE:[1:$1@$0](.*@BAR)s/@.*//\nDEFAULT");
try { try {
handler.init(props); handler.init(props);
} catch (Exception ex) { } catch (Exception ex) {
@ -118,55 +116,7 @@ public class TestKerberosAuthenticationHandler
} }
} }
@Test @Test(timeout=60000)
public void testNameRulesCompat() throws Exception {
KerberosName kn = new KerberosName(KerberosTestUtils.getServerPrincipal());
Assert.assertEquals(KerberosTestUtils.getRealm(), kn.getRealm());
//destroy handler created in setUp()
handler.destroy();
handler = getNewAuthenticationHandler();
Properties props = getDefaultProperties();
props.setProperty(KerberosAuthenticationHandler.NAME_RULES, "RULE:[1:$1@$0](.*@BAR)s/@.*//\nDEFAULT");
props.setProperty(KerberosAuthenticationHandler.RULE_MECHANISM, KerberosName.MECHANISM_MIT);
try {
handler.init(props);
} catch (Exception ex) {
}
kn = new KerberosName("bar@BAR");
Assert.assertEquals("bar", kn.getShortName());
kn = new KerberosName("bar@FOO");
Assert.assertEquals("bar@FOO", kn.getShortName());
}
@Test
public void testNullProperties() throws Exception {
KerberosName kn = new KerberosName(KerberosTestUtils.getServerPrincipal());
Assert.assertEquals(KerberosTestUtils.getRealm(), kn.getRealm());
KerberosName.setRuleMechanism("MIT");
KerberosName.setRules("DEFAULT");
//destroy handler created in setUp()
handler.destroy();
handler = getNewAuthenticationHandler();
Properties props = getDefaultProperties();
props.remove(KerberosAuthenticationHandler.NAME_RULES);
props.remove(KerberosAuthenticationHandler.RULE_MECHANISM);
try {
handler.init(props);
} catch (Exception ex) {
}
Assert.assertEquals("MIT", KerberosName.getRuleMechanism());
Assert.assertEquals("DEFAULT", KerberosName.getRules());
}
@Test
public void testInit() throws Exception { public void testInit() throws Exception {
Assert.assertEquals(KerberosTestUtils.getKeytabFile(), handler.getKeytab()); Assert.assertEquals(KerberosTestUtils.getKeytabFile(), handler.getKeytab());
Set<KerberosPrincipal> principals = handler.getPrincipals(); Set<KerberosPrincipal> principals = handler.getPrincipals();

View File

@ -40,7 +40,6 @@ public class TestKerberosName {
"RULE:[2:$1;$2](^.*;admin$)s/;admin$//\n" + "RULE:[2:$1;$2](^.*;admin$)s/;admin$//\n" +
"RULE:[2:$2](root)\n" + "RULE:[2:$2](root)\n" +
"DEFAULT"; "DEFAULT";
KerberosName.setRuleMechanism(KerberosName.MECHANISM_HADOOP);
KerberosName.setRules(rules); KerberosName.setRules(rules);
KerberosName.printRules(); KerberosName.printRules();
} }
@ -86,16 +85,10 @@ public class TestKerberosName {
@Test @Test
public void testAntiPatterns() throws Exception { public void testAntiPatterns() throws Exception {
KerberosName.setRuleMechanism(KerberosName.MECHANISM_HADOOP);
checkBadName("owen/owen/owen@FOO.COM"); checkBadName("owen/owen/owen@FOO.COM");
checkBadName("owen@foo/bar.com"); checkBadName("owen@foo/bar.com");
checkBadTranslation("foo@ACME.COM"); checkBadTranslation("foo@ACME.COM");
checkBadTranslation("root/joe@FOO.COM"); checkBadTranslation("root/joe@FOO.COM");
KerberosName.setRuleMechanism(KerberosName.MECHANISM_MIT);
checkTranslation("foo@ACME.COM", "foo@ACME.COM");
checkTranslation("root/joe@FOO.COM", "root/joe@FOO.COM");
} }
@Test @Test
@ -136,11 +129,6 @@ public class TestKerberosName {
checkTranslation("Joe/guestguest@FOO.COM", "joe"); checkTranslation("Joe/guestguest@FOO.COM", "joe");
} }
@Test(expected = IllegalArgumentException.class)
public void testInvalidRuleMechanism() throws Exception {
KerberosName.setRuleMechanism("INVALID_MECHANISM");
}
@After @After
public void clear() { public void clear() {
System.clearProperty("java.security.krb5.realm"); System.clearProperty("java.security.krb5.realm");

View File

@ -607,13 +607,6 @@ public class CommonConfigurationKeysPublic {
* <a href="{@docRoot}/../hadoop-project-dist/hadoop-common/core-default.xml"> * <a href="{@docRoot}/../hadoop-project-dist/hadoop-common/core-default.xml">
* core-default.xml</a> * core-default.xml</a>
*/ */
public static final String HADOOP_SECURITY_AUTH_TO_LOCAL_MECHANISM =
"hadoop.security.auth_to_local.mechanism";
/**
* @see
* <a href="{@docRoot}/../hadoop-project-dist/hadoop-common/core-default.xml">
* core-default.xml</a>
*/
public static final String HADOOP_SECURITY_DNS_INTERFACE_KEY = public static final String HADOOP_SECURITY_DNS_INTERFACE_KEY =
"hadoop.security.dns.interface"; "hadoop.security.dns.interface";
/** /**

View File

@ -1126,6 +1126,7 @@ public final class HttpServer2 implements FilterContainer {
params.put("kerberos.keytab", httpKeytab); params.put("kerberos.keytab", httpKeytab);
} }
params.put(AuthenticationFilter.AUTH_TYPE, "kerberos"); params.put(AuthenticationFilter.AUTH_TYPE, "kerberos");
defineFilter(webAppContext, SPNEGO_FILTER, defineFilter(webAppContext, SPNEGO_FILTER,
AuthenticationFilter.class.getName(), params, null); AuthenticationFilter.class.getName(), params, null);
} }

View File

@ -19,7 +19,6 @@
package org.apache.hadoop.security; package org.apache.hadoop.security;
import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTH_TO_LOCAL; import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTH_TO_LOCAL;
import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTH_TO_LOCAL_MECHANISM;
import java.io.IOException; import java.io.IOException;
@ -28,9 +27,6 @@ import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.security.authentication.util.KerberosName; import org.apache.hadoop.security.authentication.util.KerberosName;
import org.apache.hadoop.security.authentication.util.KerberosUtil; import org.apache.hadoop.security.authentication.util.KerberosUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** /**
* This class implements parsing and handling of Kerberos principal names. In * This class implements parsing and handling of Kerberos principal names. In
* particular, it splits them apart and translates them down into local * particular, it splits them apart and translates them down into local
@ -40,8 +36,6 @@ import org.slf4j.LoggerFactory;
@InterfaceAudience.LimitedPrivate({"HDFS", "MapReduce"}) @InterfaceAudience.LimitedPrivate({"HDFS", "MapReduce"})
@InterfaceStability.Evolving @InterfaceStability.Evolving
public class HadoopKerberosName extends KerberosName { public class HadoopKerberosName extends KerberosName {
private static final Logger LOG =
LoggerFactory.getLogger(HadoopKerberosName.class);
/** /**
* Create a name from the full Kerberos principal name. * Create a name from the full Kerberos principal name.
@ -51,8 +45,8 @@ public class HadoopKerberosName extends KerberosName {
super(name); super(name);
} }
/** /**
* Set the static configuration to get and evaluate the rules. * Set the static configuration to get the rules.
* <p> * <p/>
* IMPORTANT: This method does a NOP if the rules have been set already. * IMPORTANT: This method does a NOP if the rules have been set already.
* If there is a need to reset the rules, the {@link KerberosName#setRules(String)} * If there is a need to reset the rules, the {@link KerberosName#setRules(String)}
* method should be invoked directly. * method should be invoked directly.
@ -79,9 +73,6 @@ public class HadoopKerberosName extends KerberosName {
} }
String ruleString = conf.get(HADOOP_SECURITY_AUTH_TO_LOCAL, defaultRule); String ruleString = conf.get(HADOOP_SECURITY_AUTH_TO_LOCAL, defaultRule);
setRules(ruleString); setRules(ruleString);
String ruleMechanism = conf.get(HADOOP_SECURITY_AUTH_TO_LOCAL_MECHANISM, DEFAULT_MECHANISM);
setRuleMechanism(ruleMechanism);
} }
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {

View File

@ -22,7 +22,6 @@ import org.apache.commons.io.IOUtils;
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured; import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.io.Text; import org.apache.hadoop.io.Text;
import org.apache.hadoop.security.authentication.util.KerberosName;
import org.apache.hadoop.security.token.Token; import org.apache.hadoop.security.token.Token;
import org.apache.hadoop.security.token.TokenIdentifier; import org.apache.hadoop.security.token.TokenIdentifier;
import org.apache.hadoop.util.ExitUtil; import org.apache.hadoop.util.ExitUtil;
@ -55,7 +54,6 @@ import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.regex.Pattern;
import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.*; import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.*;
import static org.apache.hadoop.security.UserGroupInformation.*; import static org.apache.hadoop.security.UserGroupInformation.*;
@ -131,12 +129,6 @@ public class KDiag extends Configured implements Tool, Closeable {
private boolean nofail = false; private boolean nofail = false;
private boolean nologin = false; private boolean nologin = false;
private boolean jaas = false; private boolean jaas = false;
private boolean checkShortName = false;
/**
* A pattern that recognizes simple/non-simple names. Per KerberosName
*/
private static final Pattern nonSimplePattern = Pattern.compile("[/@]");
/** /**
* Flag set to true if a {@link #verify(boolean, String, String, Object...)} * Flag set to true if a {@link #verify(boolean, String, String, Object...)}
@ -165,8 +157,6 @@ public class KDiag extends Configured implements Tool, Closeable {
public static final String ARG_SECURE = "--secure"; public static final String ARG_SECURE = "--secure";
public static final String ARG_VERIFYSHORTNAME = "--verifyshortname";
@SuppressWarnings("IOResourceOpenedButNotSafelyClosed") @SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
public KDiag(Configuration conf, public KDiag(Configuration conf,
PrintWriter out, PrintWriter out,
@ -210,7 +200,6 @@ public class KDiag extends Configured implements Tool, Closeable {
nofail = popOption(ARG_NOFAIL, args); nofail = popOption(ARG_NOFAIL, args);
jaas = popOption(ARG_JAAS, args); jaas = popOption(ARG_JAAS, args);
nologin = popOption(ARG_NOLOGIN, args); nologin = popOption(ARG_NOLOGIN, args);
checkShortName = popOption(ARG_VERIFYSHORTNAME, args);
// look for list of resources // look for list of resources
String resource; String resource;
@ -256,9 +245,7 @@ public class KDiag extends Configured implements Tool, Closeable {
+ arg(ARG_NOLOGIN, "", "Do not attempt to log in") + arg(ARG_NOLOGIN, "", "Do not attempt to log in")
+ arg(ARG_OUTPUT, "<file>", "Write output to a file") + arg(ARG_OUTPUT, "<file>", "Write output to a file")
+ arg(ARG_RESOURCE, "<resource>", "Load an XML configuration resource") + arg(ARG_RESOURCE, "<resource>", "Load an XML configuration resource")
+ arg(ARG_SECURE, "", "Require the hadoop configuration to be secure") + arg(ARG_SECURE, "", "Require the hadoop configuration to be secure");
+ arg(ARG_VERIFYSHORTNAME, ARG_PRINCIPAL + " <principal>",
"Verify the short name of the specific principal does not contain '@' or '/'");
} }
private String arg(String name, String params, String meaning) { private String arg(String name, String params, String meaning) {
@ -291,7 +278,6 @@ public class KDiag extends Configured implements Tool, Closeable {
println("%s = %d", ARG_KEYLEN, minKeyLength); println("%s = %d", ARG_KEYLEN, minKeyLength);
println("%s = %s", ARG_KEYTAB, keytab); println("%s = %s", ARG_KEYTAB, keytab);
println("%s = %s", ARG_PRINCIPAL, principal); println("%s = %s", ARG_PRINCIPAL, principal);
println("%s = %s", ARG_VERIFYSHORTNAME, checkShortName);
// Fail fast on a JVM without JCE installed. // Fail fast on a JVM without JCE installed.
validateKeyLength(); validateKeyLength();
@ -390,9 +376,6 @@ public class KDiag extends Configured implements Tool, Closeable {
validateKinitExecutable(); validateKinitExecutable();
validateJAAS(jaas); validateJAAS(jaas);
validateNTPConf(); validateNTPConf();
if (checkShortName) {
validateShortName();
}
if (!nologin) { if (!nologin) {
title("Logging in"); title("Logging in");
@ -447,32 +430,6 @@ public class KDiag extends Configured implements Tool, Closeable {
aesLen, minKeyLength); aesLen, minKeyLength);
} }
/**
* Verify whether auth_to_local rules transform a principal name
* <p>
* Having a local user name "bar@foo.com" may be harmless, so it is noted at
* info. However if what was intended is a transformation to "bar"
* it can be difficult to debug, hence this check.
*/
protected void validateShortName() {
failif(principal == null, CAT_KERBEROS, "No principal defined");
try {
KerberosName kn = new KerberosName(principal);
String result = kn.getShortName();
if (nonSimplePattern.matcher(result).find()) {
warn(CAT_KERBEROS, principal + " short name: " + result +
" still contains @ or /");
}
} catch (IOException e) {
throw new KerberosDiagsFailure(CAT_KERBEROS, e,
"Failed to get short name for " + principal, e);
} catch (IllegalArgumentException e) {
error(CAT_KERBEROS, "KerberosName(" + principal + ") failed: %s\n%s",
e, StringUtils.stringifyException(e));
}
}
/** /**
* Get the default realm. * Get the default realm.
* <p> * <p>

View File

@ -662,15 +662,6 @@
<description>Maps kerberos principals to local user names</description> <description>Maps kerberos principals to local user names</description>
</property> </property>
<property>
<name>hadoop.security.auth_to_local.mechanism</name>
<value>hadoop</value>
<description>The mechanism by which auth_to_local rules are evaluated.
If set to 'hadoop' it will not allow resulting local user names to have
either '@' or '/'. If set to 'MIT' it will follow MIT evaluation rules
and the restrictions of 'hadoop' do not apply.</description>
</property>
<property> <property>
<name>hadoop.token.files</name> <name>hadoop.token.files</name>
<value></value> <value></value>

View File

@ -133,35 +133,22 @@ The MapReduce JobHistory Server keytab file, on that host, should look like the
### Mapping from Kerberos principals to OS user accounts ### Mapping from Kerberos principals to OS user accounts
Hadoop maps Kerberos principals to OS user (system) accounts using rules specified by `hadoop.security.auth_to_local`. How Hadoop evaluates these rules is determined by the setting of `hadoop.security.auth_to_local.mechanism`. Hadoop maps Kerberos principals to OS user (system) accounts using rules specified by `hadoop.security.auth_to_local`. These rules work in the same way as the `auth_to_local` in [Kerberos configuration file (krb5.conf)](http://web.mit.edu/Kerberos/krb5-latest/doc/admin/conf_files/krb5_conf.html). In addition, Hadoop `auth_to_local` mapping supports the **/L** flag that lowercases the returned name.
In the default `hadoop` mode a Kerberos principal *must* be matched against a rule that transforms the principal to a simple form, i.e. a user account name without '@' or '/', otherwise a principal will not be authorized and a error will be logged. In case of the `MIT` mode the rules work in the same way as the `auth_to_local` in [Kerberos configuration file (krb5.conf)](http://web.mit.edu/Kerberos/krb5-latest/doc/admin/conf_files/krb5_conf.html) and the restrictions of `hadoop` mode do *not* apply. If you use `MIT` mode it is suggested to use the same `auth_to_local` rules that are specified in your /etc/krb5.conf as part of your default realm and keep them in sync. In both `hadoop` and `MIT` mode the rules are being applied (with the exception of `DEFAULT`) to *all* principals regardless of their specified realm. Also, note you should *not* rely on the `auth_to_local` rules as an ACL and use proper (OS) mechanisms. The default is to pick the first component of the principal name as the system user name if the realm matches the `default_realm` (usually defined in /etc/krb5.conf). e.g. The default rule maps the principal `host/full.qualified.domain.name@REALM.TLD` to system user `host`. The default rule will *not be appropriate* for most clusters.
Possible values for `auth_to_local` are:
* `RULE:exp` The local name will be formulated from exp. The format for exp is `[n:string](regexp)s/pattern/replacement/g`. The integer n indicates how many components the target principal should have. If this matches, then a string will be formed from string, substituting the realm of the principal for `$0` and the nth component of the principal for `$n` (e.g., if the principal was johndoe/admin then `[2:$2$1foo]` would result in the string `adminjohndoefoo`). If this string matches regexp, then the `s//[g]` substitution command will be run over the string. The optional g will cause the substitution to be global over the string, instead of replacing only the first match in the string. As an extension to MIT, Hadoop `auth_to_local` mapping supports the **/L** flag that lowercases the returned name.
* `DEFAULT` Picks the first component of the principal name as the system user name if and only if the realm matches the `default_realm` (usually defined in /etc/krb5.conf). e.g. The default rule maps the principal `host/full.qualified.domain.name@MYREALM.TLD` to system user `host` if the default realm is `MYREALM.TLD`.
In case no rules are specified Hadoop defaults to using `DEFAULT`, which is probably *not suitable* to most of the clusters.
Please note that Hadoop does not support multiple default realms (e.g like Heimdal does). Also, Hadoop does not do a verification on mapping whether a local system account exists.
### Example rules
In a typical cluster HDFS and YARN services will be launched as the system `hdfs` and `yarn` users respectively. `hadoop.security.auth_to_local` can be configured as follows: In a typical cluster HDFS and YARN services will be launched as the system `hdfs` and `yarn` users respectively. `hadoop.security.auth_to_local` can be configured as follows:
<property> <property>
<name>hadoop.security.auth_to_local</name> <name>hadoop.security.auth_to_local</name>
<value> <value>
RULE:[2:$1/$2@$0]([ndj]n/.*@REALM.\TLD)s/.*/hdfs/ RULE:[2:$1/$2@$0]([ndj]n/.*@REALM.TLD)s/.*/hdfs/
RULE:[2:$1/$2@$0]([rn]m/.*@REALM\.TLD)s/.*/yarn/ RULE:[2:$1/$2@$0]([rn]m/.*@REALM.TLD)s/.*/yarn/
RULE:[2:$1/$2@$0](jhs/.*@REALM\.TLD)s/.*/mapred/ RULE:[2:$1/$2@$0](jhs/.*@REALM.TLD)s/.*/mapred/
DEFAULT DEFAULT
</value> </value>
</property> </property>
This would map any principal `nn, dn, jn` on any `host` from realm `REALM.TLD` to the local system account `hdfs`. Secondly it would map any principal `rm, nm` on any `host` from `REALM.TLD` to the local system account `yarn`. Thirdly, it would map the principal `jhs` on any `host` from realm `REALM.TLD` to the local system account `mapred`. Finally, any principal on any host from the default realm will be mapped to the user component of that principal.
Custom rules can be tested using the `hadoop kerbname` command. This command allows one to specify a principal and apply Hadoop's current `auth_to_local` ruleset. Custom rules can be tested using the `hadoop kerbname` command. This command allows one to specify a principal and apply Hadoop's current `auth_to_local` ruleset.
### Mapping from user to group ### Mapping from user to group
@ -483,7 +470,6 @@ KDiag: Diagnose Kerberos Problems
[--out <file>] : Write output to a file. [--out <file>] : Write output to a file.
[--resource <resource>] : Load an XML configuration resource. [--resource <resource>] : Load an XML configuration resource.
[--secure] : Require the hadoop configuration to be secure. [--secure] : Require the hadoop configuration to be secure.
[--verifyshortname <principal>]: Verify the short name of the specific principal does not contain '@' or '/'
``` ```
#### `--jaas`: Require a JAAS file to be defined in `java.security.auth.login.config`. #### `--jaas`: Require a JAAS file to be defined in `java.security.auth.login.config`.
@ -579,11 +565,6 @@ or implicitly set to "simple":
Needless to say, an application so configured cannot talk to a secure Hadoop cluster. Needless to say, an application so configured cannot talk to a secure Hadoop cluster.
#### `--verifyshortname <principal>`: validate the short name of a principal
This verifies that the short name of a principal contains neither the `"@"`
nor `"/"` characters.
### Example ### Example
``` ```

View File

@ -164,22 +164,6 @@ public class TestKDiag extends Assert {
ARG_PRINCIPAL, "foo@EXAMPLE.COM"); ARG_PRINCIPAL, "foo@EXAMPLE.COM");
} }
@Test
public void testKerberosName() throws Throwable {
kdiagFailure(ARG_KEYLEN, KEYLEN,
ARG_VERIFYSHORTNAME,
ARG_PRINCIPAL, "foo/foo/foo@BAR.COM");
}
@Test
public void testShortName() throws Throwable {
kdiag(ARG_KEYLEN, KEYLEN,
ARG_KEYTAB, keytab.getAbsolutePath(),
ARG_PRINCIPAL,
ARG_VERIFYSHORTNAME,
ARG_PRINCIPAL, "foo@EXAMPLE.COM");
}
@Test @Test
public void testFileOutput() throws Throwable { public void testFileOutput() throws Throwable {
File f = new File("target/kdiag.txt"); File f = new File("target/kdiag.txt");

View File

@ -74,7 +74,6 @@ import java.util.concurrent.TimeUnit;
import static org.apache.hadoop.fs.CommonConfigurationKeys.HADOOP_USER_GROUP_METRICS_PERCENTILES_INTERVALS; import static org.apache.hadoop.fs.CommonConfigurationKeys.HADOOP_USER_GROUP_METRICS_PERCENTILES_INTERVALS;
import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.HADOOP_KERBEROS_MIN_SECONDS_BEFORE_RELOGIN; import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.HADOOP_KERBEROS_MIN_SECONDS_BEFORE_RELOGIN;
import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTH_TO_LOCAL; import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTH_TO_LOCAL;
import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTH_TO_LOCAL_MECHANISM;
import static org.apache.hadoop.test.MetricsAsserts.assertCounter; import static org.apache.hadoop.test.MetricsAsserts.assertCounter;
import static org.apache.hadoop.test.MetricsAsserts.assertCounterGt; import static org.apache.hadoop.test.MetricsAsserts.assertCounterGt;
import static org.apache.hadoop.test.MetricsAsserts.assertGaugeGt; import static org.apache.hadoop.test.MetricsAsserts.assertGaugeGt;
@ -330,7 +329,6 @@ public class TestUserGroupInformation {
// security off, but use rules if explicitly set // security off, but use rules if explicitly set
conf.set(HADOOP_SECURITY_AUTH_TO_LOCAL, conf.set(HADOOP_SECURITY_AUTH_TO_LOCAL,
"RULE:[1:$1@$0](.*@OTHER.REALM)s/(.*)@.*/other-$1/"); "RULE:[1:$1@$0](.*@OTHER.REALM)s/(.*)@.*/other-$1/");
conf.set(HADOOP_SECURITY_AUTH_TO_LOCAL_MECHANISM, "hadoop");
UserGroupInformation.setConfiguration(conf); UserGroupInformation.setConfiguration(conf);
testConstructorSuccess("user1", "user1"); testConstructorSuccess("user1", "user1");
testConstructorSuccess("user4@OTHER.REALM", "other-user4"); testConstructorSuccess("user4@OTHER.REALM", "other-user4");
@ -338,52 +336,25 @@ public class TestUserGroupInformation {
testConstructorFailures("user2@DEFAULT.REALM"); testConstructorFailures("user2@DEFAULT.REALM");
testConstructorFailures("user3/cron@DEFAULT.REALM"); testConstructorFailures("user3/cron@DEFAULT.REALM");
testConstructorFailures("user5/cron@OTHER.REALM"); testConstructorFailures("user5/cron@OTHER.REALM");
// with MIT
conf.set(HADOOP_SECURITY_AUTH_TO_LOCAL_MECHANISM, "mit");
UserGroupInformation.setConfiguration(conf);
testConstructorSuccess("user2@DEFAULT.REALM", "user2@DEFAULT.REALM");
testConstructorSuccess("user3/cron@DEFAULT.REALM", "user3/cron@DEFAULT.REALM");
testConstructorSuccess("user5/cron@OTHER.REALM", "user5/cron@OTHER.REALM");
// failures
testConstructorFailures("user6@example.com@OTHER.REALM");
testConstructorFailures("user7@example.com@DEFAULT.REALM");
testConstructorFailures(null); testConstructorFailures(null);
testConstructorFailures(""); testConstructorFailures("");
conf.set(HADOOP_SECURITY_AUTH_TO_LOCAL_MECHANISM, "hadoop");
} }
/** test constructor */ /** test constructor */
@Test (timeout = 30000) @Test (timeout = 30000)
public void testConstructorWithKerberos() throws Exception { public void testConstructorWithKerberos() throws Exception {
// security on, default is remove default realm // security on, default is remove default realm
conf.set(HADOOP_SECURITY_AUTH_TO_LOCAL_MECHANISM, "hadoop");
SecurityUtil.setAuthenticationMethod(AuthenticationMethod.KERBEROS, conf); SecurityUtil.setAuthenticationMethod(AuthenticationMethod.KERBEROS, conf);
UserGroupInformation.setConfiguration(conf); UserGroupInformation.setConfiguration(conf);
testConstructorSuccess("user1", "user1"); testConstructorSuccess("user1", "user1");
testConstructorSuccess("user2@DEFAULT.REALM", "user2"); testConstructorSuccess("user2@DEFAULT.REALM", "user2");
testConstructorSuccess("user3/cron@DEFAULT.REALM", "user3"); testConstructorSuccess("user3/cron@DEFAULT.REALM", "user3");
// failure test // failure test
testConstructorFailures("user4@OTHER.REALM"); testConstructorFailures("user4@OTHER.REALM");
testConstructorFailures("user5/cron@OTHER.REALM"); testConstructorFailures("user5/cron@OTHER.REALM");
// with MIT
conf.set(HADOOP_SECURITY_AUTH_TO_LOCAL_MECHANISM, "mit");
UserGroupInformation.setConfiguration(conf);
testConstructorSuccess("user4@OTHER.REALM", "user4@OTHER.REALM");
testConstructorSuccess("user5/cron@OTHER.REALM", "user5/cron@OTHER.REALM");
// failures
testConstructorFailures(null); testConstructorFailures(null);
testConstructorFailures(""); testConstructorFailures("");
conf.set(HADOOP_SECURITY_AUTH_TO_LOCAL_MECHANISM, "hadoop");
} }
/** test constructor */ /** test constructor */
@ -422,9 +393,8 @@ public class TestUserGroupInformation {
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
String expect = (userName == null || userName.isEmpty()) String expect = (userName == null || userName.isEmpty())
? "Null user" : "Illegal principal name "+userName; ? "Null user" : "Illegal principal name "+userName;
String expect2 = "Malformed Kerberos name: "+userName; assertTrue("Did not find "+ expect + " in " + e,
assertTrue("Did not find "+ expect + " or " + expect2 + " in " + e, e.toString().contains(expect));
e.toString().contains(expect) || e.toString().contains(expect2));
} }
} }