001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.security;
019
020import java.io.File;
021import java.io.IOException;
022import java.net.InetAddress;
023
024import org.apache.hadoop.conf.Configuration;
025import org.apache.hadoop.fs.CommonConfigurationKeys;
026import org.apache.hadoop.hbase.AuthUtil;
027import org.apache.hadoop.hbase.HBaseConfiguration;
028import org.apache.hadoop.hbase.HBaseTestingUtility;
029import org.apache.hadoop.hbase.http.ssl.KeyStoreTestUtil;
030import org.apache.hadoop.hdfs.DFSConfigKeys;
031import org.apache.hadoop.http.HttpConfig;
032import org.apache.hadoop.yarn.conf.YarnConfiguration;
033import org.apache.yetus.audience.InterfaceAudience;
034import org.slf4j.Logger;
035import org.slf4j.LoggerFactory;
036import org.apache.hbase.thirdparty.com.google.common.base.Strings;
037import org.apache.hadoop.security.UserGroupInformation;
038
039@InterfaceAudience.Private
040public class HBaseKerberosUtils {
041  private static final Logger LOG = LoggerFactory.getLogger(HBaseKerberosUtils.class);
042
043  public static final String KRB_PRINCIPAL = SecurityConstants.REGIONSERVER_KRB_PRINCIPAL;
044  public static final String MASTER_KRB_PRINCIPAL = SecurityConstants.MASTER_KRB_PRINCIPAL;
045  public static final String KRB_KEYTAB_FILE = SecurityConstants.REGIONSERVER_KRB_KEYTAB_FILE;
046  public static final String CLIENT_PRINCIPAL = AuthUtil.HBASE_CLIENT_KERBEROS_PRINCIPAL;
047  public static final String CLIENT_KEYTAB = AuthUtil.HBASE_CLIENT_KEYTAB_FILE;
048
049  public static boolean isKerberosPropertySetted() {
050    String krbPrincipal = System.getProperty(KRB_PRINCIPAL);
051    String krbKeytab = System.getProperty(KRB_KEYTAB_FILE);
052    if (Strings.isNullOrEmpty(krbPrincipal) || Strings.isNullOrEmpty(krbKeytab)) {
053      return false;
054    }
055    return true;
056  }
057
058  public static void setPrincipalForTesting(String principal) {
059    setSystemProperty(KRB_PRINCIPAL, principal);
060  }
061
062  public static void setKeytabFileForTesting(String keytabFile) {
063    setSystemProperty(KRB_KEYTAB_FILE, keytabFile);
064  }
065
066  public static void setClientPrincipalForTesting(String clientPrincipal) {
067    setSystemProperty(CLIENT_PRINCIPAL, clientPrincipal);
068  }
069
070  public static void setClientKeytabForTesting(String clientKeytab) {
071    setSystemProperty(CLIENT_KEYTAB, clientKeytab);
072  }
073
074  public static void setSystemProperty(String propertyName, String propertyValue) {
075    System.setProperty(propertyName, propertyValue);
076  }
077
078  public static String getKeytabFileForTesting() {
079    return System.getProperty(KRB_KEYTAB_FILE);
080  }
081
082  public static String getPrincipalForTesting() {
083    return System.getProperty(KRB_PRINCIPAL);
084  }
085
086  public static String getClientPrincipalForTesting() {
087    return System.getProperty(CLIENT_PRINCIPAL);
088  }
089
090  public static String getClientKeytabForTesting() {
091    return System.getProperty(CLIENT_KEYTAB);
092  }
093
094  public static Configuration getConfigurationWoPrincipal() {
095    Configuration conf = HBaseConfiguration.create();
096    conf.set(CommonConfigurationKeys.HADOOP_SECURITY_AUTHENTICATION, "kerberos");
097    conf.set(User.HBASE_SECURITY_CONF_KEY, "kerberos");
098    conf.setBoolean(User.HBASE_SECURITY_AUTHORIZATION_CONF_KEY, true);
099    return conf;
100  }
101
102  public static Configuration getSecuredConfiguration() {
103    Configuration conf = HBaseConfiguration.create();
104    setSecuredConfiguration(conf);
105    return conf;
106  }
107
108  /**
109   * Set up configuration for a secure HDFS+HBase cluster.
110   * @param conf configuration object.
111   * @param servicePrincipal service principal used by NN, HM and RS.
112   * @param spnegoPrincipal SPNEGO principal used by NN web UI.
113   */
114  public static void setSecuredConfiguration(Configuration conf,
115      String servicePrincipal, String spnegoPrincipal) {
116    setPrincipalForTesting(servicePrincipal);
117    setSecuredConfiguration(conf);
118    setSecuredHadoopConfiguration(conf, spnegoPrincipal);
119  }
120
121  public static void setSecuredConfiguration(Configuration conf) {
122    conf.set(CommonConfigurationKeys.HADOOP_SECURITY_AUTHENTICATION, "kerberos");
123    conf.set(User.HBASE_SECURITY_CONF_KEY, "kerberos");
124    conf.setBoolean(User.HBASE_SECURITY_AUTHORIZATION_CONF_KEY, true);
125    conf.set(KRB_KEYTAB_FILE, System.getProperty(KRB_KEYTAB_FILE));
126    conf.set(KRB_PRINCIPAL, System.getProperty(KRB_PRINCIPAL));
127    conf.set(MASTER_KRB_PRINCIPAL, System.getProperty(KRB_PRINCIPAL));
128  }
129
130  private static void setSecuredHadoopConfiguration(Configuration conf,
131      String spnegoServerPrincipal) {
132    // if we drop support for hadoop-2.4.0 and hadoop-2.4.1,
133    // the following key should be changed.
134    // 1) DFS_NAMENODE_USER_NAME_KEY -> DFS_NAMENODE_KERBEROS_PRINCIPAL_KEY
135    // 2) DFS_DATANODE_USER_NAME_KEY -> DFS_DATANODE_KERBEROS_PRINCIPAL_KEY
136    String serverPrincipal = System.getProperty(KRB_PRINCIPAL);
137    String keytabFilePath = System.getProperty(KRB_KEYTAB_FILE);
138    // HDFS
139    conf.set(DFSConfigKeys.DFS_NAMENODE_USER_NAME_KEY, serverPrincipal);
140    conf.set(DFSConfigKeys.DFS_NAMENODE_KEYTAB_FILE_KEY, keytabFilePath);
141    conf.set(DFSConfigKeys.DFS_DATANODE_USER_NAME_KEY, serverPrincipal);
142    conf.set(DFSConfigKeys.DFS_DATANODE_KEYTAB_FILE_KEY, keytabFilePath);
143    conf.setBoolean(DFSConfigKeys.DFS_BLOCK_ACCESS_TOKEN_ENABLE_KEY, true);
144    // YARN
145    conf.set(YarnConfiguration.RM_PRINCIPAL, KRB_PRINCIPAL);
146    conf.set(YarnConfiguration.NM_PRINCIPAL, KRB_PRINCIPAL);
147
148    if (spnegoServerPrincipal != null) {
149      conf.set(DFSConfigKeys.DFS_WEB_AUTHENTICATION_KERBEROS_PRINCIPAL_KEY,
150          spnegoServerPrincipal);
151    }
152
153    conf.setBoolean("ignore.secure.ports.for.testing", true);
154
155    UserGroupInformation.setConfiguration(conf);
156  }
157
158  /**
159   * Set up SSL configuration for HDFS NameNode and DataNode.
160   * @param utility a HBaseTestingUtility object.
161   * @param clazz the caller test class.
162   * @throws Exception if unable to set up SSL configuration
163   */
164  public static void setSSLConfiguration(HBaseTestingUtility utility, Class clazz)
165      throws Exception {
166    Configuration conf = utility.getConfiguration();
167    conf.set(DFSConfigKeys.DFS_HTTP_POLICY_KEY, HttpConfig.Policy.HTTPS_ONLY.name());
168    conf.set(DFSConfigKeys.DFS_NAMENODE_HTTPS_ADDRESS_KEY, "localhost:0");
169    conf.set(DFSConfigKeys.DFS_DATANODE_HTTPS_ADDRESS_KEY, "localhost:0");
170
171    File keystoresDir = new File(utility.getDataTestDir("keystore").toUri().getPath());
172    keystoresDir.mkdirs();
173    String sslConfDir = KeyStoreTestUtil.getClasspathDir(clazz);
174    KeyStoreTestUtil.setupSSLConfig(keystoresDir.getAbsolutePath(), sslConfDir, conf, false);
175  }
176
177  public static UserGroupInformation loginAndReturnUGI(Configuration conf, String username)
178      throws IOException {
179    String hostname = InetAddress.getLocalHost().getHostName();
180    String keyTabFileConfKey = "hbase." + username + ".keytab.file";
181    String keyTabFileLocation = conf.get(keyTabFileConfKey);
182    String principalConfKey = "hbase." + username + ".kerberos.principal";
183    String principal = org.apache.hadoop.security.SecurityUtil
184        .getServerPrincipal(conf.get(principalConfKey), hostname);
185    if (keyTabFileLocation == null || principal == null) {
186      LOG.warn("Principal or key tab file null for : " + principalConfKey + ", "
187          + keyTabFileConfKey);
188    }
189    UserGroupInformation ugi =
190        UserGroupInformation.loginUserFromKeytabAndReturnUGI(principal, keyTabFileLocation);
191    return ugi;
192  }
193}