From 30c8bbc545c158b95c1ca5f4774a87baa96526d7 Mon Sep 17 00:00:00 2001 From: Josh Elser Date: Tue, 3 May 2016 20:57:43 -0400 Subject: [PATCH] HBASE-5291 SPNEGO authentication for web UIs --- .../org/apache/hadoop/hbase/http/HttpServer.java | 77 ++++++++++++++++++++++ src/main/asciidoc/_chapters/security.adoc | 37 +++++++++++ 2 files changed, 114 insertions(+) diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java index 667e597..b19cb8c 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java @@ -27,6 +27,7 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; @@ -107,6 +108,13 @@ public class HttpServer implements FilterContainer { = "hbase.http.filter.initializers"; static final String HTTP_MAX_THREADS = "hbase.http.max.threads"; + static final String HTTP_UI_AUTHENTICATION = "hbase.security.authentication.ui"; + static final String HTTP_SPNEGO_AUTHENTICATION = "hbase.security.authentication.spnego"; + static final String HTTP_SPNEGO_AUTHENTICATION_PRINCIPAL = "kerberos.principal"; + static final List REQUIRED_SPNEGO_CONFIG_KEYS = Arrays.asList(HTTP_SPNEGO_AUTHENTICATION_PRINCIPAL, + "kerberos.keytab"); + static final List OPTIONAL_SPNEGO_CONFIG_KEYS = Arrays.asList("kerberos.name.rules", "signature.secret.file"); + // The ServletContext attribute where the daemon Configuration // gets stored. public static final String CONF_CONTEXT_ATTRIBUTE = "hbase.conf"; @@ -532,6 +540,16 @@ public class HttpServer implements FilterContainer { addDefaultApps(contexts, appDir, conf); + // Optionally enable SPNEGO authentication + if (shouldUseSpnegoAuthentication(conf)) { + LOG.info("Adding SPNEGO authentication filter to web UI's server"); + final Map filterConfig = getSpnegoFilterConfiguration(conf, hostName); + + // It's a bummer, but AuthenticationFilter is still marked as Private (2016/05/03). It's + // still better to reuse this than maintain yet another implementation. + addGlobalFilter("spnego", AuthenticationFilter.class.getName(), filterConfig); + } + addGlobalFilter("safety", QuotingInputFilter.class.getName(), null); Map params = new HashMap(); params.put("xframeoptions", conf.get("hbase.http.filter.xframeoptions.mode", "DENY")); @@ -564,6 +582,65 @@ public class HttpServer implements FilterContainer { listeners.add(new ListenerInfo(true, connector)); } + /** + * Computes, given the conf, if SPNEGO authentication should be enabled for this + * HttpServer. SPNEGO authentication requires Kerberos authentication to be enabled. + * + * @param conf The HBase configuration + * @return True if SPNEGO auth should be used, false otherwise + */ + private boolean shouldUseSpnegoAuthentication(Configuration conf) { + return "kerberos".equalsIgnoreCase(conf.get("hbase.security.authentication")) + && "spnego".equalsIgnoreCase(conf.get(HTTP_UI_AUTHENTICATION)); + } + + /** + * Builds the configuration map for the AuthenticationFilter for SPNEGO + * authentication from the HBase configuration. + * + * @param conf The HBase configuration + * @param hostname The hostname for the HTTP server + * @return A Map of configuration entries for the AuthenticationFilter + */ + private Map getSpnegoFilterConfiguration(Configuration conf, String hostname) + throws IOException { + Map filterConfig = new HashMap<>(); + + // Configure the AuthenticationFilter to do Kerberos/SPNEGO authentication + filterConfig.put(AuthenticationFilter.AUTH_TYPE, "kerberos"); + + // Required configuration + for (String keySuffix : REQUIRED_SPNEGO_CONFIG_KEYS) { + final String key = HTTP_SPNEGO_AUTHENTICATION + "." + keySuffix; + String value = conf.get(key, null); + if (null == value) { + throw new RuntimeException(key + " is not defined in the configuration"); + } else if (HTTP_SPNEGO_AUTHENTICATION_PRINCIPAL.equals(keySuffix)) { + // Make sure _HOST gets substituted in the Kerberos principal + String origPrinc = value; + value = SecurityUtil.getServerPrincipal(value, hostname); + if (!origPrinc.equals(value)) { + LOG.info("Qualified Kerberos principal with hostname as " + value); + } + } + + // The `keySuffix` is the key which KerberosAuthenticationHandler/AuthenticationFilter + // are expecting. + filterConfig.put(keySuffix, value); + } + + // Optional configuration + for (String keySuffix : OPTIONAL_SPNEGO_CONFIG_KEYS) { + final String key = HTTP_SPNEGO_AUTHENTICATION + "." + keySuffix; + String value = conf.get(key, null); + if (null != value) { + filterConfig.put(keySuffix, value); + } + } + + return filterConfig; + } + private static WebAppContext createWebAppContext(String name, Configuration conf, AccessControlList adminsAcl, final String appDir) { WebAppContext ctx = new WebAppContext(); diff --git a/src/main/asciidoc/_chapters/security.adoc b/src/main/asciidoc/_chapters/security.adoc index 0d1407a..ad333df 100644 --- a/src/main/asciidoc/_chapters/security.adoc +++ b/src/main/asciidoc/_chapters/security.adoc @@ -69,6 +69,43 @@ See Nick Dimiduk's contribution on this link:http://stackoverflow.com/questions/ If you know how to fix this without opening a second port for HTTPS, patches are appreciated. ==== +[[hbase.secure.spnego.ui]] +== Using SPNEGO for Kerberos authentication with Web UIs + +Kerberos-authentication to HBase Web UIs can be enabled via configuring SPNEGO with the `hbase.security.authentication.ui` +property in _hbase-site.xml_. Enabling this authentication requires that HBase is also configured to use Kerberos authentication +for RPCs (e.g `hbase.security.authentication` = `kerberos`). + +A number of properties exist to configure SPNEGO authentication for the web server: + +[source,xml] +---- + + hbase.security.authentication.spnego.kerberos.principal + HTTP/_HOST@EXAMPLE.COM + The Kerberos principal to use for SPNEGO authentication by the web server. The _HOST keyword + will be automatically substituted with the node's hostname. + + + hbase.security.authentication.spnego.kerberos.keytab + /etc/security/keytabs/spnego.service.keytab + The Kerberos keytab file to use for SPNEGO authentication by the web server. + + + hbase.security.authentication.spnego.kerberos.name.rules + + Optional, Hadoop-style `auth_to_local` rules which will be parsed and used in the + handling of Kerberos principals + + + hbase.security.authentication.spnego.signature.secret.file + privacy + Optional, a file whose contents will be used as a secret to sign the HTTP cookies + as a part of the SPNEGO authentication handshake. If this is not provided, Java's `Random` library + will be used for the secret. + +---- + [[hbase.secure.configuration]] == Secure Client Access to Apache HBase -- 2.1.2