ACCUMULO-4070 Backport server-side fix Kerberos renewal from ACCUMULO-4069
Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/4d952ac0 Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/4d952ac0 Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/4d952ac0 Branch: refs/heads/master Commit: 4d952ac070c399cd16688eefd5d8a5c3f80e753c Parents: bd8cf5e Author: Josh Elser <els...@apache.org> Authored: Thu Dec 3 01:53:27 2015 -0500 Committer: Josh Elser <els...@apache.org> Committed: Thu Dec 3 16:20:56 2015 -0500 ---------------------------------------------------------------------- .../org/apache/accumulo/core/conf/Property.java | 2 + .../accumulo/server/security/SecurityUtil.java | 47 ++++++++++++++++++-- 2 files changed, 45 insertions(+), 4 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/accumulo/blob/4d952ac0/core/src/main/java/org/apache/accumulo/core/conf/Property.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/conf/Property.java b/core/src/main/java/org/apache/accumulo/core/conf/Property.java index 6d1f043..632bb59 100644 --- a/core/src/main/java/org/apache/accumulo/core/conf/Property.java +++ b/core/src/main/java/org/apache/accumulo/core/conf/Property.java @@ -160,6 +160,8 @@ public enum Property { GENERAL_KERBEROS_KEYTAB("general.kerberos.keytab", "", PropertyType.PATH, "Path to the kerberos keytab to use. Leave blank if not using kerberoized hdfs"), GENERAL_KERBEROS_PRINCIPAL("general.kerberos.principal", "", PropertyType.STRING, "Name of the kerberos principal to use. _HOST will automatically be " + "replaced by the machines hostname in the hostname portion of the principal. Leave blank if not using kerberoized hdfs"), + GENERAL_KERBEROS_RENEWAL_PERIOD("general.kerberos.renewal.period", "30s", PropertyType.TIMEDURATION, "The amount of time between attempts to perform " + + "Kerberos ticket renewals. This does not equate to how often tickets are actually renewed (which is performed at 80% of the ticket lifetime)."), GENERAL_MAX_MESSAGE_SIZE("general.server.message.size.max", "1G", PropertyType.MEMORY, "The maximum size of a message that can be sent to a server."), @Experimental GENERAL_VOLUME_CHOOSER("general.volume.chooser", "org.apache.accumulo.server.fs.RandomVolumeChooser", PropertyType.CLASSNAME, http://git-wip-us.apache.org/repos/asf/accumulo/blob/4d952ac0/server/base/src/main/java/org/apache/accumulo/server/security/SecurityUtil.java ---------------------------------------------------------------------- diff --git a/server/base/src/main/java/org/apache/accumulo/server/security/SecurityUtil.java b/server/base/src/main/java/org/apache/accumulo/server/security/SecurityUtil.java index 42d1313..9e0eb04 100644 --- a/server/base/src/main/java/org/apache/accumulo/server/security/SecurityUtil.java +++ b/server/base/src/main/java/org/apache/accumulo/server/security/SecurityUtil.java @@ -21,6 +21,8 @@ import java.net.InetAddress; import org.apache.accumulo.core.conf.AccumuloConfiguration; import org.apache.accumulo.core.conf.Property; +import org.apache.accumulo.core.util.Daemon; +import org.apache.accumulo.fate.util.LoggingRunnable; import org.apache.hadoop.security.UserGroupInformation; import org.apache.log4j.Logger; @@ -29,6 +31,7 @@ import org.apache.log4j.Logger; */ public class SecurityUtil { private static final Logger log = Logger.getLogger(SecurityUtil.class); + private static final Logger renewalLog = Logger.getLogger("KerberosTicketRenewal"); public static boolean usingKerberos = false; /** @@ -48,11 +51,10 @@ public class SecurityUtil { if (login(principalConfig, keyTab)) { try { - // This spawns a thread to periodically renew the logged in (accumulo) user - UserGroupInformation.getLoginUser(); + startTicketRenewalThread(UserGroupInformation.getCurrentUser(), acuConf.getTimeInMillis(Property.GENERAL_KERBEROS_RENEWAL_PERIOD)); return; - } catch (IOException io) { - log.error("Error starting up renewal thread. This shouldn't be happenining.", io); + } catch (IOException e) { + log.error("Failed to obtain Kerberos user after successfully logging in", e); } } @@ -80,4 +82,41 @@ public class SecurityUtil { } return false; } + + /** + * Start a thread that periodically attempts to renew the current Kerberos user's ticket. + * + * @param ugi + * The current Kerberos user. + * @param renewalPeriod + * The amount of time between attempting renewals. + */ + static void startTicketRenewalThread(final UserGroupInformation ugi, final long renewalPeriod) { + Thread t = new Daemon(new LoggingRunnable(renewalLog, new Runnable() { + @Override + public void run() { + while (true) { + try { + renewalLog.debug("Invoking renewal attempt for Kerberos ticket"); + // While we run this "frequently", the Hadoop implementation will only perform the login at 80% of ticket lifetime. + ugi.checkTGTAndReloginFromKeytab(); + } catch (IOException e) { + // Should failures to renew the ticket be retried more quickly? + renewalLog.error("Failed to renew Kerberos ticket", e); + } + + // Wait for a bit before checking again. + try { + Thread.sleep(renewalPeriod); + } catch (InterruptedException e) { + renewalLog.error("Renewal thread interrupted", e); + Thread.currentThread().interrupt(); + return; + } + } + } + })); + t.setName("Kerberos Ticket Renewal"); + t.start(); + } }