From c21479f1f0b350d445042d87edd7dfde54a45c3f Mon Sep 17 00:00:00 2001 From: thiruvel Date: Wed, 30 Oct 2013 16:50:25 -0700 Subject: [PATCH] Enable audit logs for HiveServer2 --- .../apache/hive/service/auth/HiveAuthFactory.java | 9 ++ .../hive/service/cli/thrift/ThriftCLIService.java | 150 +++++++++++++++++++++ 2 files changed, 159 insertions(+) diff --git a/service/src/java/org/apache/hive/service/auth/HiveAuthFactory.java b/service/src/java/org/apache/hive/service/auth/HiveAuthFactory.java index 5a66a6c..92fc957 100644 --- a/service/src/java/org/apache/hive/service/auth/HiveAuthFactory.java +++ b/service/src/java/org/apache/hive/service/auth/HiveAuthFactory.java @@ -33,6 +33,7 @@ import org.apache.thrift.transport.TTransportFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.net.InetAddress; import java.text.MessageFormat; import java.util.HashMap; import java.util.Map; @@ -139,6 +140,14 @@ public class HiveAuthFactory { } } + public InetAddress getRemoteHost() { + if (saslServer != null) { + return saslServer.getRemoteAddress(); + } else { + return null; + } + } + /* perform kerberos login using the hadoop shim API if the configuration is available */ public static void loginFromKeytab(HiveConf hiveConf) throws IOException { String principal = hiveConf.getVar(ConfVars.HIVE_SERVER2_KERBEROS_PRINCIPAL); diff --git a/service/src/java/org/apache/hive/service/cli/thrift/ThriftCLIService.java b/service/src/java/org/apache/hive/service/cli/thrift/ThriftCLIService.java index 857e627..9b78fd1 100644 --- a/service/src/java/org/apache/hive/service/cli/thrift/ThriftCLIService.java +++ b/service/src/java/org/apache/hive/service/cli/thrift/ThriftCLIService.java @@ -20,6 +20,7 @@ package org.apache.hive.service.cli.thrift; import java.io.IOException; import java.net.InetSocketAddress; +import java.util.Formatter; import java.util.HashMap; import java.util.Map; @@ -27,8 +28,12 @@ import javax.security.auth.login.LoginException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.hive.common.metrics.Metrics; import org.apache.hadoop.hive.conf.HiveConf; import org.apache.hadoop.hive.conf.HiveConf.ConfVars; +import org.apache.hadoop.hive.metastore.MetaStoreUtils; +import org.apache.hadoop.hive.shims.ShimLoader; +import org.apache.hadoop.security.UserGroupInformation; import org.apache.hive.service.AbstractService; import org.apache.hive.service.auth.HiveAuthFactory; import org.apache.hive.service.cli.CLIService; @@ -71,6 +76,27 @@ public abstract class ThriftCLIService extends AbstractService implements TCLISe protected static HiveAuthFactory hiveAuthFactory; + public enum ThriftCliFunctions { + OpenSession, + CloseSession, + GetInfo, + GetTypeInfo, + GetCatalogs, + GetTableTypes, + GetOperationStatus, + CancelOperation, + CloseOperation, + GetResultSetMetadata, + FetchResults, + ExecuteStatement, + GetSchemas, + GetTables, + GetColumns, + GetFunctions + } + public ThriftCLIService(CLIService cliService, String serviceName) { super(serviceName); this.cliService = cliService; @@ -111,11 +137,85 @@ public abstract class ThriftCLIService extends AbstractService implements TCLISe super.stop(); } + public static final String AUDIT_FORMAT = + "ugi=%s\t" + // ugi + "ip=%s\t" + // remote IP + "cmd=%s"; // command + public static final Log auditLog = LogFactory.getLog(ThriftCLIService.class.getName() + ".audit"); + + private static final ThreadLocal auditFormatter = + new ThreadLocal() { + @Override + protected Formatter initialValue() { + return new Formatter(new StringBuilder(AUDIT_FORMAT.length() * 4)); + } + }; + + private final void logAuditEvent(String cmd) { + if (cmd == null) { + return; + } + + final Formatter fmt = auditFormatter.get(); + ((StringBuilder) fmt.out()).setLength(0); + + UserGroupInformation ugi; + try { + ugi = ShimLoader.getHadoopShims().getUGIForConf(hiveConf); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + + String address = null; + if (getRemoteHost() != null) { + address = getRemoteHost(); + } //TODO: Un-secure Setup implementation + /* else { + address = getIpAddress(); + } */ + if (address == null) { + address = "unknown-ip-addr"; + } + auditLog.info(fmt.format(AUDIT_FORMAT, ugi.getUserName(), address, cmd).toString()); + } + + public void startFunction(ThriftCliFunctions function, String extraLogInfo) { + logAuditEvent(function + extraLogInfo); + try { + Metrics.startScope(function.name()); + } catch (IOException e) { + LOG.debug("Exception when starting metrics scope" + + e.getClass().getName() + " " + e.getMessage()); + MetaStoreUtils.printStackTrace(e); + } + } + + public void startFunction(ThriftCliFunctions function) { + startFunction(function, ""); + } + + public void endFunction(ThriftCliFunctions function) { + try { + Metrics.endScope(function.name()); + } catch (IOException e) { + LOG.debug("Exception when closing metrics scope" + e); + } + } + + private String getRemoteHost() { + if (hiveAuthFactory != null + && hiveAuthFactory.getRemoteHost() != null) { + return hiveAuthFactory.getRemoteHost().toString(); + } else { + return null; + } + } @Override public TOpenSessionResp OpenSession(TOpenSessionReq req) throws TException { TOpenSessionResp resp = new TOpenSessionResp(); try { + startFunction(ThriftCliFunctions.OpenSession); SessionHandle sessionHandle = getSessionHandle(req); resp.setSessionHandle(sessionHandle.toTSessionHandle()); // TODO: set real configuration map @@ -124,6 +224,8 @@ public abstract class ThriftCLIService extends AbstractService implements TCLISe } catch (Exception e) { LOG.warn("Error opening session: ", e); resp.setStatus(HiveSQLException.toTStatus(e)); + } finally { + endFunction(ThriftCliFunctions.OpenSession); } return resp; } @@ -170,12 +272,15 @@ public abstract class ThriftCLIService extends AbstractService implements TCLISe public TCloseSessionResp CloseSession(TCloseSessionReq req) throws TException { TCloseSessionResp resp = new TCloseSessionResp(); try { + startFunction(ThriftCliFunctions.CloseSession); SessionHandle sessionHandle = new SessionHandle(req.getSessionHandle()); cliService.closeSession(sessionHandle); resp.setStatus(OK_STATUS); } catch (Exception e) { LOG.warn("Error closing session: ", e); resp.setStatus(HiveSQLException.toTStatus(e)); + } finally { + endFunction(ThriftCliFunctions.CloseSession); } return resp; } @@ -184,6 +289,7 @@ public abstract class ThriftCLIService extends AbstractService implements TCLISe public TGetInfoResp GetInfo(TGetInfoReq req) throws TException { TGetInfoResp resp = new TGetInfoResp(); try { + startFunction(ThriftCliFunctions.GetInfo); GetInfoValue getInfoValue = cliService.getInfo(new SessionHandle(req.getSessionHandle()), GetInfoType.getGetInfoType(req.getInfoType())); @@ -192,6 +298,8 @@ public abstract class ThriftCLIService extends AbstractService implements TCLISe } catch (Exception e) { LOG.warn("Error getting info: ", e); resp.setStatus(HiveSQLException.toTStatus(e)); + } finally { + endFunction(ThriftCliFunctions.GetInfo); } return resp; } @@ -202,6 +310,7 @@ public abstract class ThriftCLIService extends AbstractService implements TCLISe try { SessionHandle sessionHandle = new SessionHandle(req.getSessionHandle()); String statement = req.getStatement(); + startFunction(ThriftCliFunctions.ExecuteStatement, "\tstmt={" + statement.replaceAll("[\\n\\t]", "") + "}"); Map confOverlay = req.getConfOverlay(); Boolean runAsync = req.isRunAsync(); OperationHandle operationHandle = runAsync ? @@ -212,6 +321,8 @@ public abstract class ThriftCLIService extends AbstractService implements TCLISe } catch (Exception e) { LOG.warn("Error fetching results: ", e); resp.setStatus(HiveSQLException.toTStatus(e)); + } finally { + endFunction(ThriftCliFunctions.ExecuteStatement); } return resp; } @@ -220,12 +331,15 @@ public abstract class ThriftCLIService extends AbstractService implements TCLISe public TGetTypeInfoResp GetTypeInfo(TGetTypeInfoReq req) throws TException { TGetTypeInfoResp resp = new TGetTypeInfoResp(); try { + startFunction(ThriftCliFunctions.GetTypeInfo); OperationHandle operationHandle = cliService.getTypeInfo(new SessionHandle(req.getSessionHandle())); resp.setOperationHandle(operationHandle.toTOperationHandle()); resp.setStatus(OK_STATUS); } catch (Exception e) { LOG.warn("Error executing statement: ", e); resp.setStatus(HiveSQLException.toTStatus(e)); + } finally { + endFunction(ThriftCliFunctions.GetTypeInfo); } return resp; } @@ -234,12 +348,15 @@ public abstract class ThriftCLIService extends AbstractService implements TCLISe public TGetCatalogsResp GetCatalogs(TGetCatalogsReq req) throws TException { TGetCatalogsResp resp = new TGetCatalogsResp(); try { + startFunction(ThriftCliFunctions.GetCatalogs); OperationHandle opHandle = cliService.getCatalogs(new SessionHandle(req.getSessionHandle())); resp.setOperationHandle(opHandle.toTOperationHandle()); resp.setStatus(OK_STATUS); } catch (Exception e) { LOG.warn("Error getting type info: ", e); resp.setStatus(HiveSQLException.toTStatus(e)); + } finally { + endFunction(ThriftCliFunctions.GetCatalogs); } return resp; } @@ -248,6 +365,7 @@ public abstract class ThriftCLIService extends AbstractService implements TCLISe public TGetSchemasResp GetSchemas(TGetSchemasReq req) throws TException { TGetSchemasResp resp = new TGetSchemasResp(); try { + startFunction(ThriftCliFunctions.GetSchemas, "\tcatalog=" + req.getCatalogName() + "\tschema=" + req.getSchemaName()); OperationHandle opHandle = cliService.getSchemas( new SessionHandle(req.getSessionHandle()), req.getCatalogName(), req.getSchemaName()); resp.setOperationHandle(opHandle.toTOperationHandle()); @@ -255,6 +373,8 @@ public abstract class ThriftCLIService extends AbstractService implements TCLISe } catch (Exception e) { LOG.warn("Error getting catalogs: ", e); resp.setStatus(HiveSQLException.toTStatus(e)); + } finally { + endFunction(ThriftCliFunctions.GetSchemas); } return resp; } @@ -263,6 +383,8 @@ public abstract class ThriftCLIService extends AbstractService implements TCLISe public TGetTablesResp GetTables(TGetTablesReq req) throws TException { TGetTablesResp resp = new TGetTablesResp(); try { + startFunction(ThriftCliFunctions.GetTables, "\tcatalog=" + req.getCatalogName() + "\tschema=" + req.getSchemaName() + + "\ttable=" + req.getTableName()); OperationHandle opHandle = cliService .getTables(new SessionHandle(req.getSessionHandle()), req.getCatalogName(), req.getSchemaName(), req.getTableName(), req.getTableTypes()); @@ -271,6 +393,8 @@ public abstract class ThriftCLIService extends AbstractService implements TCLISe } catch (Exception e) { LOG.warn("Error getting schemas: ", e); resp.setStatus(HiveSQLException.toTStatus(e)); + } finally { + endFunction(ThriftCliFunctions.GetTables); } return resp; } @@ -279,12 +403,15 @@ public abstract class ThriftCLIService extends AbstractService implements TCLISe public TGetTableTypesResp GetTableTypes(TGetTableTypesReq req) throws TException { TGetTableTypesResp resp = new TGetTableTypesResp(); try { + startFunction(ThriftCliFunctions.GetTableTypes); OperationHandle opHandle = cliService.getTableTypes(new SessionHandle(req.getSessionHandle())); resp.setOperationHandle(opHandle.toTOperationHandle()); resp.setStatus(OK_STATUS); } catch (Exception e) { LOG.warn("Error getting tables: ", e); resp.setStatus(HiveSQLException.toTStatus(e)); + } finally { + endFunction(ThriftCliFunctions.GetTableTypes); } return resp; } @@ -293,6 +420,8 @@ public abstract class ThriftCLIService extends AbstractService implements TCLISe public TGetColumnsResp GetColumns(TGetColumnsReq req) throws TException { TGetColumnsResp resp = new TGetColumnsResp(); try { + startFunction(ThriftCliFunctions.GetColumns, "\tcatalog=" + req.getCatalogName() + "\tschema=" + req.getSchemaName() + + "\ttable=" + req.getTableName() + "\tcolumn=" + req.getColumnName()); OperationHandle opHandle = cliService.getColumns( new SessionHandle(req.getSessionHandle()), req.getCatalogName(), @@ -304,6 +433,8 @@ public abstract class ThriftCLIService extends AbstractService implements TCLISe } catch (Exception e) { LOG.warn("Error getting table types: ", e); resp.setStatus(HiveSQLException.toTStatus(e)); + } finally { + endFunction(ThriftCliFunctions.GetColumns); } return resp; } @@ -312,6 +443,8 @@ public abstract class ThriftCLIService extends AbstractService implements TCLISe public TGetFunctionsResp GetFunctions(TGetFunctionsReq req) throws TException { TGetFunctionsResp resp = new TGetFunctionsResp(); try { + startFunction(ThriftCliFunctions.GetFunctions, "\tcatalog=" + req.getCatalogName() + + "\tschema=" + req.getSchemaName() + "\tfunction=" + req.getFunctionName()); OperationHandle opHandle = cliService.getFunctions( new SessionHandle(req.getSessionHandle()), req.getCatalogName(), req.getSchemaName(), req.getFunctionName()); @@ -320,6 +453,8 @@ public abstract class ThriftCLIService extends AbstractService implements TCLISe } catch (Exception e) { LOG.warn("Error getting columns: ", e); resp.setStatus(HiveSQLException.toTStatus(e)); + } finally { + endFunction(ThriftCliFunctions.GetFunctions); } return resp; } @@ -328,12 +463,15 @@ public abstract class ThriftCLIService extends AbstractService implements TCLISe public TGetOperationStatusResp GetOperationStatus(TGetOperationStatusReq req) throws TException { TGetOperationStatusResp resp = new TGetOperationStatusResp(); try { + startFunction(ThriftCliFunctions.GetOperationStatus); OperationState operationState = cliService.getOperationStatus(new OperationHandle(req.getOperationHandle())); resp.setOperationState(operationState.toTOperationState()); resp.setStatus(OK_STATUS); } catch (Exception e) { LOG.warn("Error getting functions: ", e); resp.setStatus(HiveSQLException.toTStatus(e)); + } finally { + endFunction(ThriftCliFunctions.GetOperationStatus); } return resp; } @@ -342,11 +480,14 @@ public abstract class ThriftCLIService extends AbstractService implements TCLISe public TCancelOperationResp CancelOperation(TCancelOperationReq req) throws TException { TCancelOperationResp resp = new TCancelOperationResp(); try { + startFunction(ThriftCliFunctions.CancelOperation); cliService.cancelOperation(new OperationHandle(req.getOperationHandle())); resp.setStatus(OK_STATUS); } catch (Exception e) { LOG.warn("Error getting operation status: ", e); resp.setStatus(HiveSQLException.toTStatus(e)); + } finally { + endFunction(ThriftCliFunctions.CancelOperation); } return resp; } @@ -355,11 +496,14 @@ public abstract class ThriftCLIService extends AbstractService implements TCLISe public TCloseOperationResp CloseOperation(TCloseOperationReq req) throws TException { TCloseOperationResp resp = new TCloseOperationResp(); try { + startFunction(ThriftCliFunctions.CloseOperation); cliService.closeOperation(new OperationHandle(req.getOperationHandle())); resp.setStatus(OK_STATUS); } catch (Exception e) { LOG.warn("Error canceling operation: ", e); resp.setStatus(HiveSQLException.toTStatus(e)); + } finally { + endFunction(ThriftCliFunctions.CloseOperation); } return resp; } @@ -369,12 +513,15 @@ public abstract class ThriftCLIService extends AbstractService implements TCLISe throws TException { TGetResultSetMetadataResp resp = new TGetResultSetMetadataResp(); try { + startFunction(ThriftCliFunctions.GetResultSetMetadata); TableSchema schema = cliService.getResultSetMetadata(new OperationHandle(req.getOperationHandle())); resp.setSchema(schema.toTTableSchema()); resp.setStatus(OK_STATUS); } catch (Exception e) { LOG.warn("Error closing operation: ", e); resp.setStatus(HiveSQLException.toTStatus(e)); + } finally { + endFunction(ThriftCliFunctions.GetResultSetMetadata); } return resp; } @@ -383,6 +530,7 @@ public abstract class ThriftCLIService extends AbstractService implements TCLISe public TFetchResultsResp FetchResults(TFetchResultsReq req) throws TException { TFetchResultsResp resp = new TFetchResultsResp(); try { + startFunction(ThriftCliFunctions.FetchResults); RowSet rowSet = cliService.fetchResults( new OperationHandle(req.getOperationHandle()), FetchOrientation.getFetchOrientation(req.getOrientation()), @@ -393,6 +541,8 @@ public abstract class ThriftCLIService extends AbstractService implements TCLISe } catch (Exception e) { LOG.warn("Error getting result set metadata: ", e); resp.setStatus(HiveSQLException.toTStatus(e)); + } finally { + endFunction(ThriftCliFunctions.FetchResults); } return resp; } -- 1.8.5-rc3