You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by pe...@apache.org on 2018/12/29 08:56:44 UTC

[ranger] branch master updated: RANGER-2170:Ranger supports plugin to enable, monitor and manage Elasticsearch

This is an automated email from the ASF dual-hosted git repository.

pengjianhua pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ranger.git


The following commit(s) were added to refs/heads/master by this push:
     new 39a53b6  RANGER-2170:Ranger supports plugin to enable, monitor and manage Elasticsearch
39a53b6 is described below

commit 39a53b6c448145c2a68839233281671f754e519b
Author: zhangqiang2 <zh...@zte.com.cn>
AuthorDate: Thu Dec 13 14:46:14 2018 +0800

    RANGER-2170:Ranger supports plugin to enable, monitor and manage Elasticsearch
    
    Signed-off-by: peng.jianhua <pe...@zte.com.cn>
---
 agents-common/scripts/enable-agent.sh              |  12 +-
 .../apache/ranger/plugin/client/BaseClient.java    |   2 +-
 .../plugin/store/EmbeddedServiceDefsUtil.java      |   8 +-
 .../ranger-servicedef-elasticsearch.json           | 196 ++++++++++++++
 plugin-elasticsearch/.gitignore                    |   1 +
 .../conf/ranger-elasticsearch-audit-changes.cfg    |  65 +++++
 .../conf/ranger-elasticsearch-audit.xml            | 271 ++++++++++++++++++++
 .../conf/ranger-elasticsearch-security-changes.cfg |  28 ++
 .../conf/ranger-elasticsearch-security.xml         |  83 ++++++
 .../conf/ranger-policymgr-ssl-changes.cfg          |  21 ++
 plugin-elasticsearch/conf/ranger-policymgr-ssl.xml |  49 ++++
 plugin-elasticsearch/pom.xml                       |  69 +++++
 plugin-elasticsearch/scripts/install.properties    | 140 ++++++++++
 .../authorizer/RangerElasticsearchAuthorizer.java  | 148 +++++++++++
 .../elasticsearch/RangerServiceElasticsearch.java  |  88 +++++++
 .../elasticsearch/client/ElasticsearchClient.java  | 282 +++++++++++++++++++++
 .../client/ElasticsearchResourceMgr.java           | 102 ++++++++
 .../elasticsearch/privilege/IndexPrivilege.java    |  55 ++++
 .../privilege/IndexPrivilegeUtils.java             | 102 ++++++++
 pom.xml                                            |  34 +++
 ranger-elasticsearch-plugin-shim/.gitignore        |   1 +
 .../conf/plugin-descriptor.properties              |  65 +++++
 .../conf/plugin-security.policy                    |  39 +++
 ranger-elasticsearch-plugin-shim/pom.xml           |  66 +++++
 .../RangerElasticsearchAccessControl.java          |  35 +++
 .../authorizer/RangerElasticsearchAuthorizer.java  | 119 +++++++++
 .../plugin/RangerElasticsearchPlugin.java          | 122 +++++++++
 .../action/filter/RangerSecurityActionFilter.java  |  82 ++++++
 .../plugin/authc/user/UsernamePasswordToken.java   | 103 ++++++++
 .../rest/filter/RangerSecurityRestFilter.java      |  73 ++++++
 .../elasticsearch/plugin/utils/RequestUtils.java   | 126 +++++++++
 src/main/assembly/admin-web.xml                    |  12 +
 src/main/assembly/plugin-elasticsearch.xml         | 197 ++++++++++++++
 33 files changed, 2793 insertions(+), 3 deletions(-)

diff --git a/agents-common/scripts/enable-agent.sh b/agents-common/scripts/enable-agent.sh
index ce0dc8c..b4194a7 100755
--- a/agents-common/scripts/enable-agent.sh
+++ b/agents-common/scripts/enable-agent.sh
@@ -210,6 +210,8 @@ elif [ "${HCOMPONENT_NAME}" = "sqoop" ]; then
     HCOMPONENT_LIB_DIR=${HCOMPONENT_INSTALL_DIR}/server/lib
 elif [ "${HCOMPONENT_NAME}" = "kylin" ]; then
     HCOMPONENT_LIB_DIR=${HCOMPONENT_INSTALL_DIR}/tomcat/webapps/kylin/WEB-INF/lib
+elif [ "${HCOMPONENT_NAME}" = "elasticsearch" ]; then
+    HCOMPONENT_LIB_DIR=${HCOMPONENT_INSTALL_DIR}/plugins
 fi
 
 HCOMPONENT_CONF_DIR=${HCOMPONENT_INSTALL_DIR}/conf
@@ -219,7 +221,7 @@ if [ "${HCOMPONENT_NAME}" = "solr" ]; then
 	install_owner=`ls -ld | cut -f 3 -d " "`
 	echo "INFO: Creating $HCOMPONENT_CONF_DIR" 
 	mkdir -p $HCOMPONENT_CONF_DIR
-	echo "INFO: Changing ownership of  $HCOMPONENT_CONF_DIR to $install_owner" 
+	echo "INFO: Changing ownership of $HCOMPONENT_CONF_DIR to $install_owner"
 	chown $install_owner:$install_owner $HCOMPONENT_CONF_DIR
     fi    
 elif [ "${HCOMPONENT_NAME}" = "kafka" ]; then
@@ -230,6 +232,14 @@ elif [ "${HCOMPONENT_NAME}" = "yarn" ]; then
     HCOMPONENT_CONF_DIR=${HCOMPONENT_INSTALL_DIR}/etc/hadoop
 elif [ "${HCOMPONENT_NAME}" = "sqoop" ]; then
     HCOMPONENT_CONF_DIR=${HCOMPONENT_INSTALL_DIR}/conf
+elif [ "${HCOMPONENT_NAME}" = "elasticsearch" ]; then
+    HCOMPONENT_CONF_DIR=${HCOMPONENT_INSTALL_DIR}/config/ranger-elasticsearch-plugin
+	if [ ! -d $HCOMPONENT_CONF_DIR ]; then
+	echo "INFO: Creating $HCOMPONENT_CONF_DIR"
+	mkdir -p $HCOMPONENT_CONF_DIR
+	echo "INFO: Changing ownership of $HCOMPONENT_CONF_DIR to $CFG_OWNER_INF"
+	chown $CFG_OWNER_INF $HCOMPONENT_CONF_DIR
+    fi
 fi
 
 HCOMPONENT_ARCHIVE_CONF_DIR=${HCOMPONENT_CONF_DIR}/.archive
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/client/BaseClient.java b/agents-common/src/main/java/org/apache/ranger/plugin/client/BaseClient.java
index e654f2b..ed002ef 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/client/BaseClient.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/client/BaseClient.java
@@ -37,7 +37,7 @@ public abstract class BaseClient {
 
 
 	private static final String DEFAULT_NAME_RULE = "DEFAULT";
-	private static final String DEFAULT_ERROR_MESSAGE = " You can still save the repository and start creating "
+	protected static final String DEFAULT_ERROR_MESSAGE = " You can still save the repository and start creating "
 				+ "policies, but you would not be able to use autocomplete for "
 				+ "resource names. Check ranger_admin.log for more info.";
 
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/store/EmbeddedServiceDefsUtil.java b/agents-common/src/main/java/org/apache/ranger/plugin/store/EmbeddedServiceDefsUtil.java
index 118af1f..110f763 100755
--- a/agents-common/src/main/java/org/apache/ranger/plugin/store/EmbeddedServiceDefsUtil.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/store/EmbeddedServiceDefsUtil.java
@@ -48,7 +48,7 @@ public class EmbeddedServiceDefsUtil {
 
 
 	// following servicedef list should be reviewed/updated whenever a new embedded service-def is added
-	private static final String DEFAULT_BOOTSTRAP_SERVICEDEF_LIST = "tag,hdfs,hbase,hive,kms,knox,storm,yarn,kafka,solr,atlas,nifi,nifi-registry,sqoop,kylin";
+	private static final String DEFAULT_BOOTSTRAP_SERVICEDEF_LIST = "tag,hdfs,hbase,hive,kms,knox,storm,yarn,kafka,solr,atlas,nifi,nifi-registry,sqoop,kylin,elasticsearch";
 	private static final String PROPERTY_SUPPORTED_SERVICE_DEFS = "ranger.supportedcomponents";
 	private Set<String> supportedServiceDefs;
 	public static final String EMBEDDED_SERVICEDEF_TAG_NAME  = "tag";
@@ -68,6 +68,7 @@ public class EmbeddedServiceDefsUtil {
 	public static final String EMBEDDED_SERVICEDEF_SQOOP_NAME = "sqoop";
 	public static final String EMBEDDED_SERVICEDEF_KYLIN_NAME  = "kylin";
 	public static final String EMBEDDED_SERVICEDEF_ABFS_NAME  = "abfs";
+	public static final String EMBEDDED_SERVICEDEF_ELASTICSEARCH_NAME = "elasticsearch";
 
 	public static final String PROPERTY_CREATE_EMBEDDED_SERVICE_DEFS = "ranger.service.store.create.embedded.service-defs";
 
@@ -102,6 +103,7 @@ public class EmbeddedServiceDefsUtil {
 	private RangerServiceDef sqoopServiceDef;
 	private RangerServiceDef kylinServiceDef;
 	private RangerServiceDef abfsServiceDef;
+	private RangerServiceDef elasticsearchServiceDef;
 
 	private RangerServiceDef tagServiceDef;
 
@@ -145,6 +147,7 @@ public class EmbeddedServiceDefsUtil {
 			sqoopServiceDef = getOrCreateServiceDef(store, EMBEDDED_SERVICEDEF_SQOOP_NAME);
 			kylinServiceDef = getOrCreateServiceDef(store, EMBEDDED_SERVICEDEF_KYLIN_NAME);
 			abfsServiceDef = getOrCreateServiceDef(store, EMBEDDED_SERVICEDEF_ABFS_NAME);
+			elasticsearchServiceDef = getOrCreateServiceDef(store, EMBEDDED_SERVICEDEF_ELASTICSEARCH_NAME);
 
 			// Ensure that tag service def is updated with access types of all service defs
 			store.updateTagServiceDefForAccessTypes();
@@ -211,6 +214,9 @@ public class EmbeddedServiceDefsUtil {
 		return getId(kylinServiceDef);
 	}
 
+	public long getElasticsearchServiceDefId() {
+		return getId(elasticsearchServiceDef);
+	}
 	public long getTagServiceDefId() { return getId(tagServiceDef); }
 
 	public long getWasbServiceDefId() { return getId(wasbServiceDef); }
diff --git a/agents-common/src/main/resources/service-defs/ranger-servicedef-elasticsearch.json b/agents-common/src/main/resources/service-defs/ranger-servicedef-elasticsearch.json
new file mode 100644
index 0000000..b055bf8
--- /dev/null
+++ b/agents-common/src/main/resources/service-defs/ranger-servicedef-elasticsearch.json
@@ -0,0 +1,196 @@
+{
+	"id":16,
+	"name": "elasticsearch",
+	"implClass": "org.apache.ranger.services.elasticsearch.RangerServiceElasticsearch",
+	"label": "ELASTICSEARCH",
+	"description": "ELASTICSEARCH",
+	"guid": "c0682ba7-7052-4c9c-a30e-84ccd5d98457",
+	"resources":
+	[
+		{
+			"itemId": 1,
+			"name": "index",
+			"type": "string",
+			"level": 10,
+			"parent": "",
+			"mandatory": true,
+			"lookupSupported": true,
+			"recursiveSupported": false,
+			"excludesSupported": false,
+			"matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher",
+			"matcherOptions": { "wildCard":true, "ignoreCase":true},
+			"validationRegEx":"",
+			"validationMessage": "",
+			"uiHint":"",
+			"label": "Index",
+			"description": "Elasticsearch Index"
+		}
+	],
+
+	"accessTypes":
+	[
+		{
+			"itemId": 1,
+			"name": "all",
+			"label": "all",
+			"impliedGrants":
+			[
+				"monitor",
+				"manage",
+				"view_index_metadata",
+				"read",
+				"read_cross_cluster",
+				"index",
+				"create",
+				"delete",
+				"write",
+				"delete_index",
+				"create_index",
+				"indices_put",
+				"indices_search_shards",
+				"indices_bulk",
+				"indices_index"
+			]
+		},
+
+		{
+			"itemId": 2,
+			"name": "monitor",
+			"label": "monitor"
+		},
+
+		{
+			"itemId": 3,
+			"name": "manage",
+			"label": "manage",
+			"impliedGrants":
+			[
+				"monitor"
+			]
+		},
+
+		{
+			"itemId": 4,
+			"name": "view_index_metadata",
+			"label": "view_index_metadata",
+			"impliedGrants":
+			[
+				"indices_search_shards"
+			]
+		},
+
+		{
+			"itemId": 5,
+			"name": "read",
+			"label": "read"
+		},
+
+		{
+			"itemId": 6,
+			"name": "read_cross_cluster",
+			"label": "read_cross_cluster",
+			"impliedGrants":
+			[
+				"indices_search_shards"
+			]
+		},
+
+		{
+			"itemId": 7,
+			"name": "index",
+			"label": "index",
+			"impliedGrants":
+			[
+				"indices_put",
+				"indices_bulk",
+				"indices_index"
+			]
+		},
+
+		{
+			"itemId": 8,
+			"name": "create",
+			"label": "create",
+			"impliedGrants":
+			[
+				"indices_put",
+				"indices_bulk",
+				"indices_index"
+			]
+		},
+
+		{
+			"itemId": 9,
+			"name": "delete",
+			"label": "delete",
+			"impliedGrants":
+			[
+				"indices_bulk"
+			]
+		},
+
+		{
+			"itemId": 10,
+			"name": "write",
+			"label": "write",
+			"impliedGrants":
+			[
+				"indices_put"
+			]
+		},
+
+		{
+			"itemId": 11,
+			"name": "delete_index",
+			"label": "delete_index"
+		},
+
+		{
+			"itemId": 12,
+			"name": "create_index",
+			"label": "create_index"
+		}
+	],
+
+	"configs":
+	[
+		{
+			"itemId": 1,
+			"name": "username",
+			"type": "string",
+			"mandatory": true,
+			"validationRegEx":"",
+			"validationMessage": "",
+			"uiHint":"",
+			"label": "Username"
+		},
+
+		{
+			"itemId": 2,
+			"name": "elasticsearch.url",
+			"type": "string",
+			"mandatory": true,
+			"defaultValue": "",
+			"validationRegEx":"",
+			"validationMessage": "",
+			"uiHint":"{\"TextFieldWithIcon\":true, \"info\": \"eg. 'http://&lt;ipaddr&gt;:9200'\"}",
+			"label": "Elasticsearch URL"
+		}
+	],
+	"options": { "enableDenyAndExceptionsInPolicies": "false" },
+
+	"enums":
+	[
+
+	],
+
+	"contextEnrichers":
+	[
+
+	],
+
+	"policyConditions":
+	[
+
+	]
+}
diff --git a/plugin-elasticsearch/.gitignore b/plugin-elasticsearch/.gitignore
new file mode 100644
index 0000000..b83d222
--- /dev/null
+++ b/plugin-elasticsearch/.gitignore
@@ -0,0 +1 @@
+/target/
diff --git a/plugin-elasticsearch/conf/ranger-elasticsearch-audit-changes.cfg b/plugin-elasticsearch/conf/ranger-elasticsearch-audit-changes.cfg
new file mode 100644
index 0000000..8071e7b
--- /dev/null
+++ b/plugin-elasticsearch/conf/ranger-elasticsearch-audit-changes.cfg
@@ -0,0 +1,65 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#xasecure.audit.db.is.enabled                        %XAAUDIT.DB.IS_ENABLED%                                         mod create-if-not-exists
+#xasecure.audit.jpa.javax.persistence.jdbc.url		%XAAUDIT_DB_JDBC_URL%											mod create-if-not-exists
+#xasecure.audit.jpa.javax.persistence.jdbc.user		%XAAUDIT.DB.USER_NAME% 											mod create-if-not-exists
+#xasecure.audit.jpa.javax.persistence.jdbc.password	crypted	 														mod create-if-not-exists
+#xasecure.audit.credential.provider.file     		jceks://file%CREDENTIAL_PROVIDER_FILE% 							mod create-if-not-exists
+#xasecure.audit.jpa.javax.persistence.jdbc.driver	%XAAUDIT_DB_JDBC_DRIVER% 										mod create-if-not-exists
+
+xasecure.audit.hdfs.is.enabled                                     %XAAUDIT.HDFS.IS_ENABLED%                               mod create-if-not-exists
+xasecure.audit.hdfs.config.destination.directory                   %XAAUDIT.HDFS.DESTINATION_DIRECTORY%                    mod create-if-not-exists
+xasecure.audit.hdfs.config.destination.file                        %XAAUDIT.HDFS.DESTINTATION_FILE%                        mod create-if-not-exists
+xasecure.audit.hdfs.config.destination.flush.interval.seconds      %XAAUDIT.HDFS.DESTINTATION_FLUSH_INTERVAL_SECONDS%      mod create-if-not-exists
+xasecure.audit.hdfs.config.destination.rollover.interval.seconds   %XAAUDIT.HDFS.DESTINTATION_ROLLOVER_INTERVAL_SECONDS%   mod create-if-not-exists
+xasecure.audit.hdfs.config.destination.open.retry.interval.seconds %XAAUDIT.HDFS.DESTINTATION_OPEN_RETRY_INTERVAL_SECONDS% mod create-if-not-exists
+xasecure.audit.hdfs.config.local.buffer.directory                  %XAAUDIT.HDFS.LOCAL_BUFFER_DIRECTORY%                   mod create-if-not-exists
+xasecure.audit.hdfs.config.local.buffer.file                       %XAAUDIT.HDFS.LOCAL_BUFFER_FILE%                        mod create-if-not-exists
+xasecure.audit.hdfs.config.local.buffer.flush.interval.seconds     %XAAUDIT.HDFS.LOCAL_BUFFER_FLUSH_INTERVAL_SECONDS%      mod create-if-not-exists
+xasecure.audit.hdfs.config.local.buffer.rollover.interval.seconds  %XAAUDIT.HDFS.LOCAL_BUFFER_ROLLOVER_INTERVAL_SECONDS%   mod create-if-not-exists
+xasecure.audit.hdfs.config.local.archive.directory                 %XAAUDIT.HDFS.LOCAL_ARCHIVE_DIRECTORY%                  mod create-if-not-exists
+xasecure.audit.hdfs.config.local.archive.max.file.count            %XAAUDIT.HDFS.LOCAL_ARCHIVE_MAX_FILE_COUNT%             mod create-if-not-exists
+
+#xasecure.audit.kafka.is.enabled                                    %XAAUDIT.KAFKA.IS_ENABLED%                             mod create-if-not-exists
+#xasecure.audit.kafka.is.async                                      %XAAUDIT.KAFKA.IS_ASYNC%                               mod create-if-not-exists
+#xasecure.audit.kafka.async.max.queue.size                          %XAAUDIT.KAFKA.MAX_QUEUE_SIZE%                         mod create-if-not-exists
+#xasecure.audit.kafka.async.max.flush.interval.ms                   %XAAUDIT.KAFKA.MAX_FLUSH_INTERVAL_MS%                  mod create-if-not-exists
+#xasecure.audit.kafka.broker_list                                   %XAAUDIT.KAFKA.BROKER_LIST%                            mod create-if-not-exists
+#xasecure.audit.kafka.topic_name                                    %XAAUDIT.KAFKA.TOPIC_NAME%                             mod create-if-not-exists
+
+xasecure.audit.solr.is.enabled                                    %XAAUDIT.SOLR.IS_ENABLED%                               mod create-if-not-exists
+xasecure.audit.solr.async.max.queue.size                          %XAAUDIT.SOLR.MAX_QUEUE_SIZE%                           mod create-if-not-exists
+xasecure.audit.solr.async.max.flush.interval.ms                   %XAAUDIT.SOLR.MAX_FLUSH_INTERVAL_MS%                    mod create-if-not-exists
+xasecure.audit.solr.solr_url                                      %XAAUDIT.SOLR.SOLR_URL%                                 mod create-if-not-exists
+
+#V3 configuration
+xasecure.audit.destination.solr                                    %XAAUDIT.SOLR.ENABLE%                               mod create-if-not-exists
+xasecure.audit.destination.solr.urls                               %XAAUDIT.SOLR.URL%                                 mod create-if-not-exists
+xasecure.audit.destination.solr.user %XAAUDIT.SOLR.USER% mod create-if-not-exists
+xasecure.audit.destination.solr.password %XAAUDIT.SOLR.PASSWORD% mod create-if-not-exists
+xasecure.audit.destination.solr.zookeepers                         %XAAUDIT.SOLR.ZOOKEEPER%                           mod create-if-not-exists
+xasecure.audit.destination.solr.batch.filespool.dir                %XAAUDIT.SOLR.FILE_SPOOL_DIR%                      mod create-if-not-exists
+
+xasecure.audit.destination.hdfs					   %XAAUDIT.HDFS.ENABLE%                      mod create-if-not-exists
+xasecure.audit.destination.hdfs.batch.filespool.dir                %XAAUDIT.HDFS.FILE_SPOOL_DIR%                      mod create-if-not-exists
+xasecure.audit.destination.hdfs.dir                		   %XAAUDIT.HDFS.HDFS_DIR%                      mod create-if-not-exists
+
+AZURE.ACCOUNTNAME                                                                                                 %XAAUDIT.HDFS.AZURE_ACCOUNTNAME%            var
+xasecure.audit.destination.hdfs.config.fs.azure.shellkeyprovider.script                                           %XAAUDIT.HDFS.AZURE_SHELL_KEY_PROVIDER%     mod         create-if-not-exists
+xasecure.audit.destination.hdfs.config.fs.azure.account.key.%AZURE.ACCOUNTNAME%.blob.core.windows.net             %XAAUDIT.HDFS.AZURE_ACCOUNTKEY%             mod         create-if-not-exists
+xasecure.audit.destination.hdfs.config.fs.azure.account.keyprovider.%AZURE.ACCOUNTNAME%.blob.core.windows.net     %XAAUDIT.HDFS.AZURE_ACCOUNTKEY_PROVIDER%    mod         create-if-not-exists
+
+#xasecure.audit.destination.file					   %XAAUDIT.FILE.ENABLE%                      mod create-if-not-exists
+#xasecure.audit.destination.file.dir                		   %XAAUDIT.FILE.DIR%                      mod create-if-not-exists
diff --git a/plugin-elasticsearch/conf/ranger-elasticsearch-audit.xml b/plugin-elasticsearch/conf/ranger-elasticsearch-audit.xml
new file mode 100644
index 0000000..b9bdde5
--- /dev/null
+++ b/plugin-elasticsearch/conf/ranger-elasticsearch-audit.xml
@@ -0,0 +1,271 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
+<configuration xmlns:xi="http://www.w3.org/2001/XInclude">
+	<property>
+		<name>xasecure.audit.is.enabled</name>
+		<value>true</value>
+	</property>
+
+
+	<!-- DB audit provider configuration -->
+	<property>
+		<name>xasecure.audit.db.is.enabled</name>
+		<value>false</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.db.is.async</name>
+		<value>true</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.db.async.max.queue.size</name>
+		<value>10240</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.db.async.max.flush.interval.ms</name>
+		<value>30000</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.db.batch.size</name>
+		<value>100</value>
+	</property>
+
+	<!--  Properties whose name begin with "xasecure.audit.jpa." are used to configure JPA -->
+	<property>
+		<name>xasecure.audit.jpa.javax.persistence.jdbc.url</name>
+		<value>jdbc:mysql://localhost:3306/ranger_audit</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.jpa.javax.persistence.jdbc.user</name>
+		<value>rangerlogger</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.jpa.javax.persistence.jdbc.password</name>
+		<value>none</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.jpa.javax.persistence.jdbc.driver</name>
+		<value>com.mysql.jdbc.Driver</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.credential.provider.file</name>
+		<value>jceks://file/etc/ranger/elasticsearchdev/auditcred.jceks</value>
+	</property>
+
+
+
+	<!-- HDFS audit provider configuration -->
+	<property>
+		<name>xasecure.audit.hdfs.is.enabled</name>
+		<value>false</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.hdfs.is.async</name>
+		<value>true</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.hdfs.async.max.queue.size</name>
+		<value>1048576</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.hdfs.async.max.flush.interval.ms</name>
+		<value>30000</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.hdfs.config.encoding</name>
+		<value></value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.hdfs.config.destination.directory</name>
+		<value>hdfs://NAMENODE_HOST:8020/ranger/audit/%app-type%/%time:yyyyMMdd%</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.hdfs.config.destination.file</name>
+		<value>%hostname%-audit.log</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.hdfs.config.destination.flush.interval.seconds</name>
+		<value>900</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.hdfs.config.destination.rollover.interval.seconds</name>
+		<value>86400</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.hdfs.config.destination.open.retry.interval.seconds</name>
+		<value>60</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.hdfs.config.local.buffer.directory</name>
+		<value>/var/log/elasticsearch/audit</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.hdfs.config.local.buffer.file</name>
+		<value>%time:yyyyMMdd-HHmm.ss%.log</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.hdfs.config.local.buffer.file.buffer.size.bytes</name>
+		<value>8192</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.hdfs.config.local.buffer.flush.interval.seconds</name>
+		<value>60</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.hdfs.config.local.buffer.rollover.interval.seconds</name>
+		<value>600</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.hdfs.config.local.archive.directory</name>
+		<value>/var/log/elasticsearch/audit/archive</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.hdfs.config.local.archive.max.file.count</name>
+		<value>10</value>
+	</property>
+
+	<!-- Audit to HDFS on Azure Datastore (WASB) requires v3 style settings.  Comment the above and uncomment only the
+	following to audit to Azure Blob Datastore via hdfs' WASB schema.
+
+	NOTE: If you specify one audit destination in v3 style then other destinations, if any, must also be specified in v3 style
+	====
+
+	<property>
+		<name>xasecure.audit.destination.hdfs</name>
+		<value>enabled</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.destination.hdfs.dir</name>
+		<value>wasb://ranger-audit1@youraccount.blob.core.windows.net</value>
+	</property>
+
+	the following 3 correspond to the properties with similar name in core-site.xml, i.e.
+	- fs.azure.account.key.youraccount.blob.core.windows.net => xasecure.audit.destination.hdfs.config.fs.azure.account.key.youraccount.blob.core.windows.net and
+	- fs.azure.account.keyprovider.youraccount.blob.core.windows.net => xasecure.audit.destination.hdfs.config.fs.azure.account.keyprovider.youraccount.blob.core.windows.net,
+	- fs.azure.shellkeyprovider.script => xasecure.audit.destination.hdfs.config.fs.azure.shellkeyprovider.script,
+
+	<property>
+		<name>xasecure.audit.destination.hdfs.config.fs.azure.account.key.youraccount.blob.core.windows.net</name>
+		<value>YOUR ENCRYPTED ACCESS KEY</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.destination.hdfs.config.fs.azure.account.keyprovider.youraccount.blob.core.windows.net</name>
+		<value>org.apache.hadoop.fs.azure.ShellDecryptionKeyProvider</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.destination.hdfs.config.fs.azure.shellkeyprovider.script</name>
+		<value>/usr/lib/python2.7/dist-packages/hdinsight_common/decrypt.sh</value>
+	</property>
+	-->
+
+	<!-- Log4j audit provider configuration -->
+	<property>
+		<name>xasecure.audit.log4j.is.enabled</name>
+		<value>false</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.log4j.is.async</name>
+		<value>false</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.log4j.async.max.queue.size</name>
+		<value>10240</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.log4j.async.max.flush.interval.ms</name>
+		<value>30000</value>
+	</property>
+
+	<!-- Kafka audit provider configuration -->
+	<property>
+		<name>xasecure.audit.kafka.is.enabled</name>
+		<value>false</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.kafka.async.max.queue.size</name>
+		<value>1</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.kafka.async.max.flush.interval.ms</name>
+		<value>1000</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.kafka.broker_list</name>
+		<value>localhost:9092</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.kafka.topic_name</name>
+		<value>ranger_audits</value>
+	</property>
+
+	<!-- Ranger audit provider configuration -->
+	<property>
+		<name>xasecure.audit.solr.is.enabled</name>
+		<value>false</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.solr.async.max.queue.size</name>
+		<value>1</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.solr.async.max.flush.interval.ms</name>
+		<value>1000</value>
+	</property>
+
+	<property>
+		<name>xasecure.audit.solr.solr_url</name>
+		<value>http://localhost:6083/solr/ranger_audits</value>
+	</property>
+
+</configuration>
diff --git a/plugin-elasticsearch/conf/ranger-elasticsearch-security-changes.cfg b/plugin-elasticsearch/conf/ranger-elasticsearch-security-changes.cfg
new file mode 100644
index 0000000..5b0deae
--- /dev/null
+++ b/plugin-elasticsearch/conf/ranger-elasticsearch-security-changes.cfg
@@ -0,0 +1,28 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Change the original policy parameter to work with policy manager based.
+#
+#
+ranger.plugin.elasticsearch.service.name %REPOSITORY_NAME% mod create-if-not-exists
+
+ranger.plugin.elasticsearch.policy.source.impl org.apache.ranger.admin.client.RangerAdminRESTClient mod create-if-not-exists
+
+ranger.plugin.elasticsearch.policy.rest.url                %POLICY_MGR_URL%                          mod create-if-not-exists
+ranger.plugin.elasticsearch.policy.rest.ssl.config.file    /etc/hadoop/conf/ranger-policymgr-ssl.xml mod create-if-not-exists
+ranger.plugin.elasticsearch.policy.pollIntervalMs          30000                                     mod create-if-not-exists
+ranger.plugin.elasticsearch.policy.cache.dir               %POLICY_CACHE_FILE_PATH%                  mod create-if-not-exists
+ranger.plugin.elasticsearch.policy.rest.client.connection.timeoutMs 	  120000					    mod create-if-not-exists
+ranger.plugin.elasticsearch.policy.rest.client.read.timeoutMs	   	  30000					        mod create-if-not-exists
\ No newline at end of file
diff --git a/plugin-elasticsearch/conf/ranger-elasticsearch-security.xml b/plugin-elasticsearch/conf/ranger-elasticsearch-security.xml
new file mode 100644
index 0000000..802e573
--- /dev/null
+++ b/plugin-elasticsearch/conf/ranger-elasticsearch-security.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
+<configuration xmlns:xi="http://www.w3.org/2001/XInclude">
+	<property>
+		<name>ranger.plugin.elasticsearch.service.name</name>
+		<value>elasticsearchdev</value>
+		<description>
+			Name of the Ranger service containing policies for this elasticsearch instance
+		</description>
+	</property>
+
+	<property>
+		<name>ranger.plugin.elasticsearch.policy.source.impl</name>
+		<value>org.apache.ranger.admin.client.RangerAdminRESTClient</value>
+		<description>
+			Class to retrieve policies from the source
+		</description>
+	</property>
+
+	<property>
+		<name>ranger.plugin.elasticsearch.policy.rest.url</name>
+		<value>http://policymanagerhost:port</value>
+		<description>
+			URL to Ranger Admin
+		</description>
+	</property>
+
+	<property>
+		<name>ranger.plugin.elasticsearch.policy.rest.ssl.config.file</name>
+		<value>/etc/hadoop/conf/ranger-policymgr-ssl.xml</value>
+		<description>
+			Path to the file containing SSL details to contact Ranger Admin
+		</description>
+	</property>
+
+	<property>
+		<name>ranger.plugin.elasticsearch.policy.pollIntervalMs</name>
+		<value>30000</value>
+		<description>
+			How often to poll for changes in policies?
+		</description>
+	</property>
+
+	<property>
+		<name>ranger.plugin.elasticsearch.policy.cache.dir</name>
+		<value>/etc/ranger/hadoopdev/policycache</value>
+		<description>
+			Directory where Ranger policies are cached after successful retrieval from the source
+		</description>
+	</property>
+
+	<property>
+		<name>ranger.plugin.elasticsearch.policy.rest.client.connection.timeoutMs</name>
+		<value>120000</value>
+		<description>
+			RangerRestClient Connection Timeout in Milli Seconds
+		</description>
+	</property>
+
+	<property>
+		<name>ranger.plugin.elasticsearch.policy.rest.client.read.timeoutMs</name>
+		<value>30000</value>
+		<description>
+			RangerRestClient read Timeout in Milli Seconds
+		</description>
+	</property>
+</configuration>
diff --git a/plugin-elasticsearch/conf/ranger-policymgr-ssl-changes.cfg b/plugin-elasticsearch/conf/ranger-policymgr-ssl-changes.cfg
new file mode 100644
index 0000000..ae347e8
--- /dev/null
+++ b/plugin-elasticsearch/conf/ranger-policymgr-ssl-changes.cfg
@@ -0,0 +1,21 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SSL Params
+#
+xasecure.policymgr.clientssl.keystore					 %SSL_KEYSTORE_FILE_PATH%						mod create-if-not-exists
+xasecure.policymgr.clientssl.keystore.credential.file	 jceks://file%CREDENTIAL_PROVIDER_FILE%			mod create-if-not-exists
+xasecure.policymgr.clientssl.truststore				     %SSL_TRUSTSTORE_FILE_PATH%						mod create-if-not-exists
+xasecure.policymgr.clientssl.truststore.credential.file  jceks://file%CREDENTIAL_PROVIDER_FILE%         mod create-if-not-exists
diff --git a/plugin-elasticsearch/conf/ranger-policymgr-ssl.xml b/plugin-elasticsearch/conf/ranger-policymgr-ssl.xml
new file mode 100644
index 0000000..dcb0de0
--- /dev/null
+++ b/plugin-elasticsearch/conf/ranger-policymgr-ssl.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
+<configuration xmlns:xi="http://www.w3.org/2001/XInclude">
+	<!-- The following properties are used for 2-way SSL client server validation -->
+	<property>
+		<name>xasecure.policymgr.clientssl.keystore</name>
+		<value>elasticsearchdev-clientcert.jks</value>
+		<description>
+			Java Keystore files
+		</description>
+	</property>
+	<property>
+		<name>xasecure.policymgr.clientssl.truststore</name>
+		<value>cacerts-xasecure.jks</value>
+		<description>
+			java truststore file
+		</description>
+	</property>
+	<property>
+		<name>xasecure.policymgr.clientssl.keystore.credential.file</name>
+		<value>jceks://file/tmp/keystore-elasticsearchdev-ssl.jceks</value>
+		<description>
+			java keystore credential file
+		</description>
+	</property>
+	<property>
+		<name>xasecure.policymgr.clientssl.truststore.credential.file</name>
+		<value>jceks://file/tmp/truststore-elasticsearchdev-ssl.jceks</value>
+		<description>
+			java truststore credential file
+		</description>
+	</property>
+</configuration>
diff --git a/plugin-elasticsearch/pom.xml b/plugin-elasticsearch/pom.xml
new file mode 100644
index 0000000..b997310
--- /dev/null
+++ b/plugin-elasticsearch/pom.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<artifactId>ranger-elasticsearch-plugin</artifactId>
+	<name>Elasticsearch Security Plugin</name>
+	<description>Elasticsearch Security Plugin</description>
+	<packaging>jar</packaging>
+	<properties>
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+	</properties>
+	<parent>
+		<groupId>org.apache.ranger</groupId>
+		<artifactId>ranger</artifactId>
+		<version>2.0.0-SNAPSHOT</version>
+		<relativePath>..</relativePath>
+	</parent>
+	<dependencies>
+		<dependency>
+			<groupId>org.elasticsearch</groupId>
+			<artifactId>elasticsearch</artifactId>
+			<version>${elasticsearch.version}</version>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.ranger</groupId>
+			<artifactId>ranger-elasticsearch-plugin-shim</artifactId>
+			<version>${project.version}</version>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.ranger</groupId>
+			<artifactId>ranger-plugins-common</artifactId>
+			<version>${project.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.ranger</groupId>
+			<artifactId>ranger-plugins-audit</artifactId>
+			<version>${project.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.ranger</groupId>
+			<artifactId>credentialbuilder</artifactId>
+			<version>${project.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.httpcomponents</groupId>
+			<artifactId>httpcore</artifactId>
+			<version>${httpcomponents.httpcore.version}</version>
+		</dependency>
+	</dependencies>
+</project>
diff --git a/plugin-elasticsearch/scripts/install.properties b/plugin-elasticsearch/scripts/install.properties
new file mode 100644
index 0000000..3a5b213
--- /dev/null
+++ b/plugin-elasticsearch/scripts/install.properties
@@ -0,0 +1,140 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Location of Policy Manager URL
+#
+# Example:
+# POLICY_MGR_URL=http://policymanager.xasecure.net:6080
+#
+POLICY_MGR_URL=
+
+#
+# This is the repository name created within policy manager
+#
+# Example:
+# REPOSITORY_NAME=elasticsearchdev
+#
+REPOSITORY_NAME=
+
+#
+# Name of the directory where the component's lib and conf directory exist.
+# This location should be relative to the parent of the directory containing
+# the plugin installation files.
+#
+COMPONENT_INSTALL_DIR_NAME=../elasticsearch
+
+# Enable audit logs to Solr
+#Example
+#XAAUDIT.SOLR.ENABLE=true
+#XAAUDIT.SOLR.URL=http://localhost:6083/solr/ranger_audits
+#XAAUDIT.SOLR.ZOOKEEPER=
+#XAAUDIT.SOLR.FILE_SPOOL_DIR=/var/log/elasticsearch/audit/solr/spool
+
+XAAUDIT.SOLR.ENABLE=false
+XAAUDIT.SOLR.URL=NONE
+XAAUDIT.SOLR.USER=NONE
+XAAUDIT.SOLR.PASSWORD=NONE
+XAAUDIT.SOLR.ZOOKEEPER=NONE
+XAAUDIT.SOLR.FILE_SPOOL_DIR=/var/log/elasticsearch/audit/solr/spool
+
+# Enable audit logs to HDFS
+#Example
+#XAAUDIT.HDFS.ENABLE=true
+#XAAUDIT.HDFS.HDFS_DIR=hdfs://node-1.example.com:8020/ranger/audit
+#  If using Azure Blob Storage
+#XAAUDIT.HDFS.HDFS_DIR=wasb[s]://<containername>@<accountname>.blob.core.windows.net/<path>
+#XAAUDIT.HDFS.HDFS_DIR=wasb://ranger_audit_container@my-azure-account.blob.core.windows.net/ranger/audit
+#XAAUDIT.HDFS.FILE_SPOOL_DIR=/var/log/elasticsearch/audit/hdfs/spool
+
+XAAUDIT.HDFS.ENABLE=false
+XAAUDIT.HDFS.HDFS_DIR=hdfs://__REPLACE__NAME_NODE_HOST:8020/ranger/audit
+XAAUDIT.HDFS.FILE_SPOOL_DIR=/var/log/elasticsearch/audit/hdfs/spool
+
+# Following additional propertis are needed When auditing to Azure Blob Storage via HDFS
+# Get these values from your /etc/hadoop/conf/core-site.xml
+#XAAUDIT.HDFS.HDFS_DIR=wasb[s]://<containername>@<accountname>.blob.core.windows.net/<path>
+XAAUDIT.HDFS.AZURE_ACCOUNTNAME=__REPLACE_AZURE_ACCOUNT_NAME
+XAAUDIT.HDFS.AZURE_ACCOUNTKEY=__REPLACE_AZURE_ACCOUNT_KEY
+XAAUDIT.HDFS.AZURE_SHELL_KEY_PROVIDER=__REPLACE_AZURE_SHELL_KEY_PROVIDER
+XAAUDIT.HDFS.AZURE_ACCOUNTKEY_PROVIDER=__REPLACE_AZURE_ACCOUNT_KEY_PROVIDER
+
+# End of V3 properties
+
+
+#
+#  Audit to HDFS Configuration
+#
+# If XAAUDIT.HDFS.IS_ENABLED is set to true, please replace tokens
+# that start with __REPLACE__ with appropriate values
+#  XAAUDIT.HDFS.IS_ENABLED=true
+#  XAAUDIT.HDFS.DESTINATION_DIRECTORY=hdfs://__REPLACE__NAME_NODE_HOST:8020/ranger/audit/%app-type%/%time:yyyyMMdd%
+#  XAAUDIT.HDFS.LOCAL_BUFFER_DIRECTORY=__REPLACE__LOG_DIR/elasticsearch/audit
+#  XAAUDIT.HDFS.LOCAL_ARCHIVE_DIRECTORY=__REPLACE__LOG_DIR/elasticsearch/audit/archive
+#
+# Example:
+#  XAAUDIT.HDFS.IS_ENABLED=true
+#  XAAUDIT.HDFS.DESTINATION_DIRECTORY=hdfs://namenode.example.com:8020/ranger/audit/%app-type%/%time:yyyyMMdd%
+#  XAAUDIT.HDFS.LOCAL_BUFFER_DIRECTORY=/var/log/elasticsearch/audit
+#  XAAUDIT.HDFS.LOCAL_ARCHIVE_DIRECTORY=/var/log/elasticsearch/audit/archive
+#
+XAAUDIT.HDFS.IS_ENABLED=false
+XAAUDIT.HDFS.DESTINATION_DIRECTORY=hdfs://__REPLACE__NAME_NODE_HOST:8020/ranger/audit/%app-type%/%time:yyyyMMdd%
+XAAUDIT.HDFS.LOCAL_BUFFER_DIRECTORY=__REPLACE__LOG_DIR/elasticsearch/audit
+XAAUDIT.HDFS.LOCAL_ARCHIVE_DIRECTORY=__REPLACE__LOG_DIR/elasticsearch/audit/archive
+
+XAAUDIT.HDFS.DESTINTATION_FILE=%hostname%-audit.log
+XAAUDIT.HDFS.DESTINTATION_FLUSH_INTERVAL_SECONDS=900
+XAAUDIT.HDFS.DESTINTATION_ROLLOVER_INTERVAL_SECONDS=86400
+XAAUDIT.HDFS.DESTINTATION_OPEN_RETRY_INTERVAL_SECONDS=60
+XAAUDIT.HDFS.LOCAL_BUFFER_FILE=%time:yyyyMMdd-HHmm.ss%.log
+XAAUDIT.HDFS.LOCAL_BUFFER_FLUSH_INTERVAL_SECONDS=60
+XAAUDIT.HDFS.LOCAL_BUFFER_ROLLOVER_INTERVAL_SECONDS=600
+XAAUDIT.HDFS.LOCAL_ARCHIVE_MAX_FILE_COUNT=10
+
+#Solr Audit Provder
+XAAUDIT.SOLR.IS_ENABLED=false
+XAAUDIT.SOLR.MAX_QUEUE_SIZE=1
+XAAUDIT.SOLR.MAX_FLUSH_INTERVAL_MS=1000
+XAAUDIT.SOLR.SOLR_URL=http://localhost:6083/solr/ranger_audits
+
+#
+# SSL Client Certificate Information
+#
+# Example:
+# SSL_KEYSTORE_FILE_PATH=/etc/hadoop/conf/ranger-plugin-keystore.jks
+# SSL_KEYSTORE_PASSWORD=none
+# SSL_TRUSTSTORE_FILE_PATH=/etc/hadoop/conf/ranger-plugin-truststore.jks
+# SSL_TRUSTSTORE_PASSWORD=none
+#
+# You do not need use SSL between agent and security admin tool, please leave these sample value as it is.
+#
+SSL_KEYSTORE_FILE_PATH=/etc/hadoop/conf/ranger-plugin-keystore.jks
+SSL_KEYSTORE_PASSWORD=myKeyFilePassword
+SSL_TRUSTSTORE_FILE_PATH=/etc/hadoop/conf/ranger-plugin-truststore.jks
+SSL_TRUSTSTORE_PASSWORD=changeit
+
+#
+# Custom component user
+# CUSTOM_COMPONENT_USER=<custom-user>
+# keep blank if component user is default
+CUSTOM_USER=elasticsearch
+
+
+#
+# Custom component group
+# CUSTOM_COMPONENT_GROUP=<custom-group>
+# keep blank if component group is default
+CUSTOM_GROUP=hadoop
diff --git a/plugin-elasticsearch/src/main/java/org/apache/ranger/authorization/elasticsearch/authorizer/RangerElasticsearchAuthorizer.java b/plugin-elasticsearch/src/main/java/org/apache/ranger/authorization/elasticsearch/authorizer/RangerElasticsearchAuthorizer.java
new file mode 100644
index 0000000..a6b024f
--- /dev/null
+++ b/plugin-elasticsearch/src/main/java/org/apache/ranger/authorization/elasticsearch/authorizer/RangerElasticsearchAuthorizer.java
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ranger.authorization.elasticsearch.authorizer;
+
+import java.util.Date;
+import java.util.List;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.logging.log4j.Logger;
+import org.apache.ranger.plugin.audit.RangerDefaultAuditHandler;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequestImpl;
+import org.apache.ranger.plugin.policyengine.RangerAccessResourceImpl;
+import org.apache.ranger.plugin.policyengine.RangerAccessResult;
+import org.apache.ranger.plugin.service.RangerBasePlugin;
+import org.apache.ranger.services.elasticsearch.client.ElasticsearchResourceMgr;
+import org.apache.ranger.services.elasticsearch.privilege.IndexPrivilegeUtils;
+import org.elasticsearch.common.logging.ESLoggerFactory;
+
+import com.google.common.collect.Sets;
+
+public class RangerElasticsearchAuthorizer implements RangerElasticsearchAccessControl {
+
+	private static final Logger LOG = ESLoggerFactory.getLogger(RangerElasticsearchAuthorizer.class);
+
+	private static volatile RangerElasticsearchInnerPlugin elasticsearchPlugin = null;
+
+	public RangerElasticsearchAuthorizer() {
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("==> RangerElasticsearchAuthorizer.RangerElasticsearchAuthorizer()");
+		}
+
+		this.init();
+
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("<== RangerElasticsearchAuthorizer.RangerElasticsearchAuthorizer()");
+		}
+	}
+
+	public void init() {
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("==> RangerElasticsearchAuthorizer.init()");
+		}
+
+		RangerElasticsearchInnerPlugin plugin = elasticsearchPlugin;
+
+		if (plugin == null) {
+			synchronized (RangerElasticsearchAuthorizer.class) {
+				plugin = elasticsearchPlugin;
+
+				if (plugin == null) {
+					plugin = new RangerElasticsearchInnerPlugin();
+					plugin.init();
+					elasticsearchPlugin = plugin;
+				}
+			}
+		}
+
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("<== RangerElasticsearchAuthorizer.init()");
+		}
+	}
+
+	@Override
+	public boolean checkPermission(String user, List<String> groups, String index, String action,
+			String clientIPAddress) {
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("==> RangerElasticsearchAuthorizer.checkPermission( user=" + user + ", groups=" + groups
+					+ ", index=" + index + ", action=" + action + ", clientIPAddress=" + clientIPAddress + ")");
+		}
+
+		boolean ret = false;
+
+		if (elasticsearchPlugin != null) {
+
+			String privilege = IndexPrivilegeUtils.getPrivilegeFromAction(action);
+			String clusterName = elasticsearchPlugin.getClusterName();
+			RangerElasticsearchAccessRequest request = new RangerElasticsearchAccessRequest(user, groups, index,
+					privilege, clusterName, clientIPAddress);
+
+			RangerAccessResult result = elasticsearchPlugin.isAccessAllowed(request);
+			if (result != null && result.getIsAllowed()) {
+				ret = true;
+			}
+		}
+
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("<== RangerElasticsearchAuthorizer.checkPermission(): result=" + ret);
+		}
+
+		return ret;
+	}
+}
+
+class RangerElasticsearchInnerPlugin extends RangerBasePlugin {
+	public RangerElasticsearchInnerPlugin() {
+		super("elasticsearch", "elasticsearch");
+	}
+
+	@Override
+	public void init() {
+		super.init();
+
+		RangerDefaultAuditHandler auditHandler = new RangerDefaultAuditHandler();
+
+		super.setResultProcessor(auditHandler);
+	}
+}
+
+class RangerElasticsearchResource extends RangerAccessResourceImpl {
+	public RangerElasticsearchResource(String index) {
+		if (StringUtils.isEmpty(index)) {
+			index = "*";
+		}
+		setValue(ElasticsearchResourceMgr.INDEX, index);
+	}
+}
+
+class RangerElasticsearchAccessRequest extends RangerAccessRequestImpl {
+	public RangerElasticsearchAccessRequest(String user, List<String> groups, String index, String privilege,
+			String clusterName, String clientIPAddress) {
+		super.setUser(user);
+		if (CollectionUtils.isNotEmpty(groups)) {
+			super.setUserGroups(Sets.newHashSet(groups));
+		}
+		super.setResource(new RangerElasticsearchResource(index));
+		super.setAccessType(privilege);
+		super.setAction(privilege);
+		super.setClusterName(clusterName);
+		super.setClientIPAddress(clientIPAddress);
+		super.setAccessTime(new Date());
+	}
+}
diff --git a/plugin-elasticsearch/src/main/java/org/apache/ranger/services/elasticsearch/RangerServiceElasticsearch.java b/plugin-elasticsearch/src/main/java/org/apache/ranger/services/elasticsearch/RangerServiceElasticsearch.java
new file mode 100644
index 0000000..ed1c98e
--- /dev/null
+++ b/plugin-elasticsearch/src/main/java/org/apache/ranger/services/elasticsearch/RangerServiceElasticsearch.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ranger.services.elasticsearch;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+import org.apache.ranger.plugin.model.RangerService;
+import org.apache.ranger.plugin.model.RangerServiceDef;
+import org.apache.ranger.plugin.service.RangerBaseService;
+import org.apache.ranger.plugin.service.ResourceLookupContext;
+import org.apache.ranger.services.elasticsearch.client.ElasticsearchResourceMgr;
+
+public class RangerServiceElasticsearch extends RangerBaseService {
+
+	private static final Logger LOG = Logger.getLogger(RangerServiceElasticsearch.class);
+
+	public RangerServiceElasticsearch() {
+		super();
+	}
+
+	@Override
+	public void init(RangerServiceDef serviceDef, RangerService service) {
+		super.init(serviceDef, service);
+	}
+
+	@Override
+	public Map<String, Object> validateConfig() throws Exception {
+		Map<String, Object> ret = new HashMap<String, Object>();
+		String serviceName = getServiceName();
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("==> RangerServiceElasticsearch.validateConfig() service: " + serviceName);
+		}
+		if (configs != null) {
+			try {
+				ret = ElasticsearchResourceMgr.validateConfig(serviceName, configs);
+			} catch (Exception e) {
+				LOG.error("<== RangerServiceElasticsearch.validateConfig() error: " + e);
+				throw e;
+			}
+		}
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("<== RangerServiceElasticsearch.validateConfig() result: " + ret);
+		}
+		return ret;
+	}
+
+	@Override
+	public List<String> lookupResource(ResourceLookupContext context) throws Exception {
+
+		List<String> ret = new ArrayList<String>();
+		String serviceName = getServiceName();
+		Map<String, String> configs = getConfigs();
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("==> RangerServiceElasticsearch.lookupResource() context: " + context);
+		}
+		if (context != null) {
+			try {
+				ret = ElasticsearchResourceMgr.getElasticsearchResources(serviceName, configs, context);
+			} catch (Exception e) {
+				LOG.error("<==RangerServiceElasticsearch.lookupResource() error: " + e);
+				throw e;
+			}
+		}
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("<== RangerServiceElasticsearch.lookupResource() result: " + ret);
+		}
+		return ret;
+	}
+}
diff --git a/plugin-elasticsearch/src/main/java/org/apache/ranger/services/elasticsearch/client/ElasticsearchClient.java b/plugin-elasticsearch/src/main/java/org/apache/ranger/services/elasticsearch/client/ElasticsearchClient.java
new file mode 100644
index 0000000..d5c170d
--- /dev/null
+++ b/plugin-elasticsearch/src/main/java/org/apache/ranger/services/elasticsearch/client/ElasticsearchClient.java
@@ -0,0 +1,282 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.ranger.services.elasticsearch.client;
+
+import java.lang.reflect.Type;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.security.auth.Subject;
+import javax.ws.rs.core.MediaType;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.collections.MapUtils;
+import org.apache.commons.lang.ArrayUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.http.HttpStatus;
+import org.apache.log4j.Logger;
+import org.apache.ranger.plugin.client.BaseClient;
+import org.apache.ranger.plugin.client.HadoopException;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.reflect.TypeToken;
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.WebResource;
+import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
+
+public class ElasticsearchClient extends BaseClient {
+
+	private static final Logger LOG = Logger.getLogger(ElasticsearchClient.class);
+
+	private static final String ELASTICSEARCH_INDEX_API_ENDPOINT = "/_all";
+
+	private String elasticsearchUrl;
+
+	private String userName;
+
+	public ElasticsearchClient(String serviceName, Map<String, String> configs) {
+
+		super(serviceName, configs, "elasticsearch-client");
+		this.elasticsearchUrl = configs.get("elasticsearch.url");
+		this.userName = configs.get("username");
+
+		if (StringUtils.isEmpty(this.elasticsearchUrl)) {
+			LOG.error("No value found for configuration 'elasticsearch.url'. Elasticsearch resource lookup will fail.");
+		}
+
+		if (StringUtils.isEmpty(this.userName)) {
+			LOG.error("No value found for configuration 'username'. Elasticsearch resource lookup will fail.");
+		}
+
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("Elasticsearch client is build with url: [" + this.elasticsearchUrl + "], user: [" + this.userName
+					+ "].");
+		}
+	}
+
+	public List<String> getIndexList(final String indexMatching, final List<String> existingIndices) {
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("Get elasticsearch index list for indexMatching: " + indexMatching + ", existingIndices: "
+					+ existingIndices);
+		}
+		Subject subj = getLoginSubject();
+		if (subj == null) {
+			return Collections.emptyList();
+		}
+
+		List<String> ret = Subject.doAs(subj, new PrivilegedAction<List<String>>() {
+
+			@Override
+			public List<String> run() {
+
+				String indexApi = null;
+				if (StringUtils.isNotEmpty(indexMatching)) {
+					indexApi = '/' + indexMatching;
+					if (!indexApi.endsWith("*")) {
+						indexApi += "*";
+					}
+				} else {
+					indexApi = ELASTICSEARCH_INDEX_API_ENDPOINT;
+				}
+				ClientResponse response = getClientResponse(elasticsearchUrl, indexApi, userName);
+
+				Map<String, Object> index2detailMap = getElasticsearchResourceResponse(response,
+						new TypeToken<HashMap<String, Object>>() {
+						}.getType());
+				if (MapUtils.isEmpty(index2detailMap)) {
+					return Collections.emptyList();
+				}
+
+				Set<String> indexResponses = index2detailMap.keySet();
+				if (CollectionUtils.isEmpty(indexResponses)) {
+					return Collections.emptyList();
+				}
+
+				return filterResourceFromResponse(indexMatching, existingIndices, new ArrayList<>(indexResponses));
+			}
+		});
+
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("Get elasticsearch index list result: " + ret);
+		}
+		return ret;
+	}
+
+	private static ClientResponse getClientResponse(String elasticsearchUrl, String elasticsearchApi, String userName) {
+		String[] elasticsearchUrls = elasticsearchUrl.trim().split("[,;]");
+		if (ArrayUtils.isEmpty(elasticsearchUrls)) {
+			return null;
+		}
+
+		ClientResponse response = null;
+		Client client = Client.create();
+		client.addFilter(new HTTPBasicAuthFilter(userName, StringUtils.EMPTY));
+		for (String currentUrl : elasticsearchUrls) {
+			if (StringUtils.isBlank(currentUrl)) {
+				continue;
+			}
+
+			String url = currentUrl.trim() + elasticsearchApi;
+			try {
+				response = getClientResponse(url, client);
+
+				if (response != null) {
+					if (response.getStatus() == HttpStatus.SC_OK) {
+						break;
+					} else {
+						response.close();
+					}
+				}
+			} catch (Throwable t) {
+				String msgDesc = "Exception while getting elasticsearch response, elasticsearchUrl: " + url;
+				LOG.error(msgDesc, t);
+			}
+		}
+		client.destroy();
+
+		return response;
+	}
+
+	private static ClientResponse getClientResponse(String url, Client client) {
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("getClientResponse():calling " + url);
+		}
+
+		WebResource webResource = client.resource(url);
+
+		ClientResponse response = webResource.accept(MediaType.APPLICATION_JSON).get(ClientResponse.class);
+
+		if (response != null) {
+			if (LOG.isDebugEnabled()) {
+				LOG.debug("getClientResponse():response.getStatus()= " + response.getStatus());
+			}
+			if (response.getStatus() != HttpStatus.SC_OK) {
+				LOG.warn("getClientResponse():response.getStatus()= " + response.getStatus() + " for URL " + url
+						+ ", failed to get elasticsearch resource list, response= " + response.getEntity(String.class));
+			}
+		}
+		return response;
+	}
+
+	private <T> T getElasticsearchResourceResponse(ClientResponse response, Type type) {
+		T resource = null;
+		try {
+			if (response != null && response.getStatus() == HttpStatus.SC_OK) {
+				String jsonString = response.getEntity(String.class);
+				Gson gson = new GsonBuilder().setPrettyPrinting().create();
+
+				resource = gson.fromJson(jsonString, type);
+			} else {
+				String msgDesc = "Unable to get a valid response for " + "expected mime type : ["
+						+ MediaType.APPLICATION_JSON + "], elasticsearchUrl: " + elasticsearchUrl
+						+ " - got null response.";
+				LOG.error(msgDesc);
+				HadoopException hdpException = new HadoopException(msgDesc);
+				hdpException.generateResponseDataMap(false, msgDesc, msgDesc + DEFAULT_ERROR_MESSAGE, null, null);
+				throw hdpException;
+			}
+		} catch (HadoopException he) {
+			throw he;
+		} catch (Throwable t) {
+			String msgDesc = "Exception while getting elasticsearch resource response, elasticsearchUrl: "
+					+ elasticsearchUrl;
+			HadoopException hdpException = new HadoopException(msgDesc, t);
+
+			LOG.error(msgDesc, t);
+
+			hdpException.generateResponseDataMap(false, BaseClient.getMessage(t), msgDesc + DEFAULT_ERROR_MESSAGE, null,
+					null);
+			throw hdpException;
+
+		} finally {
+			if (response != null) {
+				response.close();
+			}
+		}
+		return resource;
+	}
+
+	private static List<String> filterResourceFromResponse(String resourceMatching, List<String> existingResources,
+			List<String> resourceResponses) {
+		List<String> resources = new ArrayList<String>();
+		for (String resourceResponse : resourceResponses) {
+			if (CollectionUtils.isNotEmpty(existingResources) && existingResources.contains(resourceResponse)) {
+				continue;
+			}
+			if (StringUtils.isEmpty(resourceMatching) || resourceMatching.startsWith("*")
+					|| resourceResponse.toLowerCase().startsWith(resourceMatching.toLowerCase())) {
+				if (LOG.isDebugEnabled()) {
+					LOG.debug("filterResourceFromResponse(): Adding elasticsearch resource " + resourceResponse);
+				}
+				resources.add(resourceResponse);
+			}
+		}
+		return resources;
+	}
+
+	public static Map<String, Object> connectionTest(String serviceName, Map<String, String> configs) {
+		ElasticsearchClient elasticsearchClient = getElasticsearchClient(serviceName, configs);
+		List<String> indexList = elasticsearchClient.getIndexList(null, null);
+
+		boolean connectivityStatus = false;
+		if (CollectionUtils.isNotEmpty(indexList)) {
+			if (LOG.isDebugEnabled()) {
+				LOG.debug("ConnectionTest list size " + indexList.size() + " elasticsearch indices.");
+			}
+			connectivityStatus = true;
+		}
+
+		Map<String, Object> responseData = new HashMap<String, Object>();
+		if (connectivityStatus) {
+			String successMsg = "ConnectionTest Successful.";
+			BaseClient.generateResponseDataMap(connectivityStatus, successMsg, successMsg, null, null, responseData);
+		} else {
+			String failureMsg = "Unable to retrieve any elasticsearch indices using given parameters.";
+			BaseClient.generateResponseDataMap(connectivityStatus, failureMsg, failureMsg + DEFAULT_ERROR_MESSAGE, null,
+					null, responseData);
+		}
+
+		return responseData;
+	}
+
+	public static ElasticsearchClient getElasticsearchClient(String serviceName, Map<String, String> configs) {
+		ElasticsearchClient elasticsearchClient = null;
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("Getting elasticsearchClient for datasource: " + serviceName);
+		}
+		if (MapUtils.isEmpty(configs)) {
+			String msgDesc = "Could not connect elasticsearch as connection configMap is empty.";
+			LOG.error(msgDesc);
+			HadoopException hdpException = new HadoopException(msgDesc);
+			hdpException.generateResponseDataMap(false, msgDesc, msgDesc + DEFAULT_ERROR_MESSAGE, null, null);
+			throw hdpException;
+		} else {
+			elasticsearchClient = new ElasticsearchClient(serviceName, configs);
+		}
+		return elasticsearchClient;
+	}
+}
diff --git a/plugin-elasticsearch/src/main/java/org/apache/ranger/services/elasticsearch/client/ElasticsearchResourceMgr.java b/plugin-elasticsearch/src/main/java/org/apache/ranger/services/elasticsearch/client/ElasticsearchResourceMgr.java
new file mode 100644
index 0000000..d7980aa
--- /dev/null
+++ b/plugin-elasticsearch/src/main/java/org/apache/ranger/services/elasticsearch/client/ElasticsearchResourceMgr.java
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.ranger.services.elasticsearch.client;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.collections.MapUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+import org.apache.ranger.plugin.service.ResourceLookupContext;
+
+public class ElasticsearchResourceMgr {
+
+	public static final String INDEX = "index";
+
+	private static final Logger LOG = Logger.getLogger(ElasticsearchResourceMgr.class);
+
+	public static Map<String, Object> validateConfig(String serviceName, Map<String, String> configs) throws Exception {
+		Map<String, Object> ret = null;
+
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("==> ElasticsearchResourceMgr.validateConfig() serviceName: " + serviceName + ", configs: "
+					+ configs);
+		}
+
+		try {
+			ret = ElasticsearchClient.connectionTest(serviceName, configs);
+		} catch (Exception e) {
+			LOG.error("<== ElasticsearchResourceMgr.validateConfig() error: " + e);
+			throw e;
+		}
+
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("<== ElasticsearchResourceMgr.validateConfig() result: " + ret);
+		}
+		return ret;
+	}
+
+	public static List<String> getElasticsearchResources(String serviceName, Map<String, String> configs,
+			ResourceLookupContext context) {
+		String userInput = context.getUserInput();
+		String resource = context.getResourceName();
+		Map<String, List<String>> resourceMap = context.getResources();
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("==> ElasticsearchResourceMgr.getElasticsearchResources()  userInput: " + userInput
+					+ ", resource: " + resource + ", resourceMap: " + resourceMap);
+		}
+
+		if (MapUtils.isEmpty(configs)) {
+			LOG.error("Connection config is empty!");
+			return null;
+		}
+
+		if (StringUtils.isEmpty(userInput)) {
+			LOG.warn("User input is empty, set default value : *");
+			userInput = "*";
+		}
+
+		final ElasticsearchClient elasticsearchClient = ElasticsearchClient.getElasticsearchClient(serviceName, configs);
+		if (elasticsearchClient == null) {
+			LOG.error("Failed to getElasticsearchResources!");
+			return null;
+		}
+
+		List<String> resultList = null;
+
+		if (StringUtils.isNotEmpty(resource)) {
+			switch (resource) {
+			case INDEX:
+				List<String> existingConnectors = resourceMap.get(INDEX);
+				resultList = elasticsearchClient.getIndexList(userInput, existingConnectors);
+				break;
+			default:
+				break;
+			}
+		}
+
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("<== ElasticsearchResourceMgr.getElasticsearchResources() result: " + resultList);
+		}
+		return resultList;
+	}
+
+}
diff --git a/plugin-elasticsearch/src/main/java/org/apache/ranger/services/elasticsearch/privilege/IndexPrivilege.java b/plugin-elasticsearch/src/main/java/org/apache/ranger/services/elasticsearch/privilege/IndexPrivilege.java
new file mode 100644
index 0000000..4691a51
--- /dev/null
+++ b/plugin-elasticsearch/src/main/java/org/apache/ranger/services/elasticsearch/privilege/IndexPrivilege.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ranger.services.elasticsearch.privilege;
+
+import java.util.List;
+
+public class IndexPrivilege {
+
+	private String privilege;
+
+	private List<String> actions;
+
+	public IndexPrivilege(String privilege, List<String> actions) {
+		super();
+		this.privilege = privilege;
+		this.actions = actions;
+	}
+
+	public String getPrivilege() {
+		return privilege;
+	}
+
+	public void setPrivilege(String privilege) {
+		this.privilege = privilege;
+	}
+
+	public List<String> getActions() {
+		return actions;
+	}
+
+	public void setActions(List<String> actions) {
+		this.actions = actions;
+	}
+
+	@Override
+	public String toString() {
+		return "IndexPrivilege [privilege=" + privilege + ", actions=" + actions + "]";
+	}
+
+}
\ No newline at end of file
diff --git a/plugin-elasticsearch/src/main/java/org/apache/ranger/services/elasticsearch/privilege/IndexPrivilegeUtils.java b/plugin-elasticsearch/src/main/java/org/apache/ranger/services/elasticsearch/privilege/IndexPrivilegeUtils.java
new file mode 100644
index 0000000..16e666a
--- /dev/null
+++ b/plugin-elasticsearch/src/main/java/org/apache/ranger/services/elasticsearch/privilege/IndexPrivilegeUtils.java
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ranger.services.elasticsearch.privilege;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.commons.lang.StringUtils;
+
+public class IndexPrivilegeUtils {
+	// These privileges have priority, should be matched in order
+	private static final List<IndexPrivilege> privileges = new LinkedList<>();
+
+	// External Privileges for users
+	public static final String ALL = "all";
+	public static final String MONITOR = "monitor";
+	public static final String MANAGE = "manage";
+	public static final String VIEW_INDEX_METADATA = "view_index_metadata";
+	public static final String READ = "read";
+	public static final String READ_CROSS_CLUSTER = "read_cross_cluster";
+	public static final String INDEX = "index";
+	public static final String CREATE = "create";
+	public static final String DELETE = "delete";
+	public static final String WRITE = "write";
+	public static final String DELETE_INDEX = "delete_index";
+	public static final String CREATE_INDEX = "create_index";
+
+	// Internal Privileges for Ranger authentication
+	public static final String INDICES_PUT = "indices_put";
+	public static final String INDICES_SEARCH_SHARDS = "indices_search_shards";
+	public static final String INDICES_BULK = "indices_bulk";
+	public static final String INDICES_INDEX = "indices_index";
+
+	static {
+		// First Priority
+		privileges.add(new IndexPrivilege(VIEW_INDEX_METADATA,
+				Arrays.asList("indices:admin/aliases/get", "indices:admin/aliases/exists", "indices:admin/get",
+						"indices:admin/exists", "indices:admin/mappings/fields/get", "indices:admin/mappings/get",
+						"indices:admin/types/exists", "indices:admin/validate/query", "indices:monitor/settings/get")));
+		privileges.add(new IndexPrivilege(READ, Arrays.asList("indices:data/read/")));
+		privileges.add(
+				new IndexPrivilege(READ_CROSS_CLUSTER, Arrays.asList("internal:transport/proxy/indices:data/read/")));
+		privileges.add(new IndexPrivilege(INDEX, Arrays.asList("indices:data/write/update")));
+
+		privileges.add(new IndexPrivilege(DELETE, Arrays.asList("indices:data/write/delete")));
+		privileges.add(new IndexPrivilege(DELETE_INDEX, Arrays.asList("indices:admin/delete")));
+		privileges.add(new IndexPrivilege(CREATE_INDEX, Arrays.asList("indices:admin/create")));
+
+		privileges.add(new IndexPrivilege(INDICES_PUT, Arrays.asList("indices:admin/mapping/put")));
+		privileges.add(new IndexPrivilege(INDICES_SEARCH_SHARDS, Arrays.asList("indices:admin/shards/search_shards")));
+		privileges.add(new IndexPrivilege(INDICES_BULK, Arrays.asList("indices:data/write/bulk")));
+		privileges.add(new IndexPrivilege(INDICES_INDEX, Arrays.asList("indices:data/write/index")));
+
+		// Second Priority
+		privileges.add(new IndexPrivilege(MONITOR, Arrays.asList("indices:monitor/")));
+		privileges.add(new IndexPrivilege(MANAGE, Arrays.asList("indices:admin/")));
+		privileges.add(new IndexPrivilege(WRITE, Arrays.asList("indices:data/write/")));
+
+		// Last Priority
+		privileges.add(
+				new IndexPrivilege(ALL, Arrays.asList("indices:", "internal:transport/proxy/indices:", "cluster:")));
+
+	}
+
+	/**
+	 * If action is empty or not matched, set default privilege "all".
+	 * @param action
+	 * @return privilege
+	 */
+	public static String getPrivilegeFromAction(String action) {
+		if (StringUtils.isEmpty(action)) {
+			return ALL;
+		}
+
+		for (IndexPrivilege privilege : privileges) {
+			// Get the privilege of matched action rule in order
+			for (String actionRule : privilege.getActions()) {
+				if (action.startsWith(actionRule)) {
+					return privilege.getPrivilege();
+				}
+			}
+		}
+
+		return ALL;
+	}
+}
diff --git a/pom.xml b/pom.xml
index a11cf51..2a2540a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -107,6 +107,7 @@
         <curator.test.version>2.12.0</curator.test.version>
         <derby.version>10.11.1.1</derby.version>
         <eclipse.jpa.version>2.5.2</eclipse.jpa.version>
+        <elasticsearch.version>6.2.2</elasticsearch.version>
         <findbugs.plugin.version>3.0.3</findbugs.plugin.version>
         <google.guava.version>25.1-jre</google.guava.version>
         <googlecode.log4jdbc.version>1.2</googlecode.log4jdbc.version>
@@ -221,6 +222,8 @@
                 <module>ranger-sqoop-plugin-shim</module>
                 <module>plugin-kylin</module>
                 <module>ranger-kylin-plugin-shim</module>
+                <module>plugin-elasticsearch</module>
+                <module>ranger-elasticsearch-plugin-shim</module>
             </modules>
             <build>
                 <plugins>
@@ -247,6 +250,7 @@
                                 <descriptor>src/main/assembly/plugin-atlas.xml</descriptor>
                                 <descriptor>src/main/assembly/plugin-sqoop.xml</descriptor>
                                 <descriptor>src/main/assembly/plugin-kylin.xml</descriptor>
+                                <descriptor>src/main/assembly/plugin-elasticsearch.xml</descriptor>
                             </descriptors>
                         </configuration>
                     </plugin>
@@ -578,6 +582,33 @@
             </build>
         </profile>
         <profile>
+            <id>ranger-elasticsearch-plugin</id>
+            <modules>
+                <module>agents-audit</module>
+                <module>agents-common</module>
+                <module>agents-cred</module>
+                <module>agents-installer</module>
+                <module>credentialbuilder</module>
+                <module>ranger-plugin-classloader</module>
+                <module>ranger-util</module>
+                <module>plugin-elasticsearch</module>
+                <module>ranger-elasticsearch-plugin-shim</module>
+            </modules>
+            <build>
+                <plugins>
+                    <plugin>
+                        <artifactId>maven-assembly-plugin</artifactId>
+                        <version>2.2-beta-5</version>
+                        <configuration>
+                            <descriptors>
+                                <descriptor>src/main/assembly/plugin-elasticsearch.xml</descriptor>
+                            </descriptors>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
             <id>linux</id>
             <activation>
                 <os>
@@ -629,6 +660,8 @@
                 <module>ranger-sqoop-plugin-shim</module>
                 <module>plugin-kylin</module>
                 <module>ranger-kylin-plugin-shim</module>
+                <module>plugin-elasticsearch</module>
+                <module>ranger-elasticsearch-plugin-shim</module>
                 <module>unixauthnative</module>
             </modules>
             <build>
@@ -656,6 +689,7 @@
                                 <descriptor>src/main/assembly/plugin-atlas.xml</descriptor>
                                 <descriptor>src/main/assembly/plugin-sqoop.xml</descriptor>
                                 <descriptor>src/main/assembly/plugin-kylin.xml</descriptor>
+                                <descriptor>src/main/assembly/plugin-elasticsearch.xml</descriptor>
                             </descriptors>
                         </configuration>
                     </plugin>
diff --git a/ranger-elasticsearch-plugin-shim/.gitignore b/ranger-elasticsearch-plugin-shim/.gitignore
new file mode 100644
index 0000000..b83d222
--- /dev/null
+++ b/ranger-elasticsearch-plugin-shim/.gitignore
@@ -0,0 +1 @@
+/target/
diff --git a/ranger-elasticsearch-plugin-shim/conf/plugin-descriptor.properties b/ranger-elasticsearch-plugin-shim/conf/plugin-descriptor.properties
new file mode 100644
index 0000000..95f9604
--- /dev/null
+++ b/ranger-elasticsearch-plugin-shim/conf/plugin-descriptor.properties
@@ -0,0 +1,65 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Elasticsearch plugin descriptor file
+# This file must exist as 'plugin-descriptor.properties' in a folder named `elasticsearch`
+# inside all plugins.
+#
+### example plugin for "foo"
+#
+# foo.zip <-- zip file for the plugin, with this structure:
+#|____elasticsearch/
+#| |____   <arbitrary name1>.jar <-- classes, resources, dependencies
+#| |____   <arbitrary nameN>.jar <-- any number of jars
+#| |____   plugin-descriptor.properties <-- example contents below:
+#
+# classname=foo.bar.BazPlugin
+# description=My cool plugin
+# version=2.0
+# elasticsearch.version=2.0
+# java.version=1.7
+#
+### mandatory elements for all plugins:
+#
+# 'description': simple summary of the plugin
+description=Elasticsearch Security Plugin
+#
+# 'version': plugin's version
+version=${project.version}
+#
+# 'name': the plugin name
+name=ranger-elasticsearch-plugin
+#
+# 'classname': the name of the class to load, fully-qualified.
+classname=org.apache.ranger.authorization.elasticsearch.plugin.RangerElasticsearchPlugin
+#
+# 'java.version': version of java the code is built against
+# use the system property java.specification.version
+# version string must be a sequence of nonnegative decimal integers
+# separated by "."'s and may have leading zeros
+java.version=${javac.target.version}
+#
+# 'elasticsearch.version': version of elasticsearch compiled against
+elasticsearch.version=${elasticsearch.version}
+### optional elements for plugins:
+#
+#  'extended.plugins': other plugins this plugin extends through SPI
+#extended.plugins=${extendedPlugins}
+#
+# 'has.native.controller': whether or not the plugin has a native controller
+has.native.controller=false
+#
+# 'requires.keystore': whether or not the plugin needs the elasticsearch keystore be created
+requires.keystore=false
diff --git a/ranger-elasticsearch-plugin-shim/conf/plugin-security.policy b/ranger-elasticsearch-plugin-shim/conf/plugin-security.policy
new file mode 100644
index 0000000..4f96d87
--- /dev/null
+++ b/ranger-elasticsearch-plugin-shim/conf/plugin-security.policy
@@ -0,0 +1,39 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+grant {
+  permission java.lang.RuntimePermission "createClassLoader";
+  permission java.lang.RuntimePermission "getClassLoader";
+  permission java.lang.RuntimePermission "setContextClassLoader";
+  permission java.lang.RuntimePermission "shutdownHooks";
+  permission java.lang.RuntimePermission "accessDeclaredMembers";
+  permission java.lang.RuntimePermission "accessClassInPackage.sun.misc";
+  permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
+
+  permission javax.security.auth.AuthPermission "getLoginConfiguration";
+  permission javax.security.auth.AuthPermission "setLoginConfiguration";
+
+  permission java.net.NetPermission "getProxySelector";
+  // adapt to connect different IP and Port
+  permission java.net.SocketPermission "*", "connect,resolve";
+
+  permission java.util.PropertyPermission "*", "read,write";
+  // adapt to different directories configured by user
+  permission java.io.FilePermission "<<ALL FILES>>", "read,write";
+};
diff --git a/ranger-elasticsearch-plugin-shim/pom.xml b/ranger-elasticsearch-plugin-shim/pom.xml
new file mode 100644
index 0000000..59a653b
--- /dev/null
+++ b/ranger-elasticsearch-plugin-shim/pom.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<artifactId>ranger-elasticsearch-plugin-shim</artifactId>
+	<name>Elasticsearch Security Plugin Shim</name>
+	<description>Elasticsearch Security Plugin Shim</description>
+	<packaging>jar</packaging>
+	<properties>
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+	</properties>
+	<parent>
+		<groupId>org.apache.ranger</groupId>
+		<artifactId>ranger</artifactId>
+		<version>2.0.0-SNAPSHOT</version>
+		<relativePath>..</relativePath>
+	</parent>
+	<dependencies>
+		<dependency>
+			<groupId>org.elasticsearch</groupId>
+			<artifactId>elasticsearch</artifactId>
+			<version>${elasticsearch.version}</version>
+			<scope>provided</scope>
+		</dependency>
+
+		<dependency>
+			<groupId>org.apache.ranger</groupId>
+			<artifactId>ranger-plugin-classloader</artifactId>
+			<version>${project.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>commons-collections</groupId>
+			<artifactId>commons-collections</artifactId>
+			<version>${commons.collections.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>commons-lang</groupId>
+			<artifactId>commons-lang</artifactId>
+			<version>${commons.lang.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>org.slf4j</groupId>
+			<artifactId>slf4j-log4j12</artifactId>
+			<version>${slf4j-api.version}</version>
+			<scope>runtime</scope>
+		</dependency>
+	</dependencies>
+</project>
\ No newline at end of file
diff --git a/ranger-elasticsearch-plugin-shim/src/main/java/org/apache/ranger/authorization/elasticsearch/authorizer/RangerElasticsearchAccessControl.java b/ranger-elasticsearch-plugin-shim/src/main/java/org/apache/ranger/authorization/elasticsearch/authorizer/RangerElasticsearchAccessControl.java
new file mode 100644
index 0000000..f9996b0
--- /dev/null
+++ b/ranger-elasticsearch-plugin-shim/src/main/java/org/apache/ranger/authorization/elasticsearch/authorizer/RangerElasticsearchAccessControl.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ranger.authorization.elasticsearch.authorizer;
+
+import java.util.List;
+
+public interface RangerElasticsearchAccessControl {
+
+	/**
+	 * Check permission for user do action on the elasticsearch index.
+	 *
+	 * @param user The user do the request.
+	 * @param groups The groups of the user.
+	 * @param index The elasticsearch index.
+	 * @param action The operation type.
+	 * @param clientIPAddress The clent IP address.
+	 * @return Check permission result.
+	 */
+	boolean checkPermission(String user, List<String> groups, String index, String action, String clientIPAddress);
+}
diff --git a/ranger-elasticsearch-plugin-shim/src/main/java/org/apache/ranger/authorization/elasticsearch/authorizer/RangerElasticsearchAuthorizer.java b/ranger-elasticsearch-plugin-shim/src/main/java/org/apache/ranger/authorization/elasticsearch/authorizer/RangerElasticsearchAuthorizer.java
new file mode 100644
index 0000000..8f33cb9
--- /dev/null
+++ b/ranger-elasticsearch-plugin-shim/src/main/java/org/apache/ranger/authorization/elasticsearch/authorizer/RangerElasticsearchAuthorizer.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ranger.authorization.elasticsearch.authorizer;
+
+import java.util.List;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.ranger.plugin.classloader.RangerPluginClassLoader;
+import org.elasticsearch.common.logging.ESLoggerFactory;
+
+public class RangerElasticsearchAuthorizer {
+
+	private static final Logger LOG = ESLoggerFactory.getLogger(RangerElasticsearchAuthorizer.class);
+
+	private static final String RANGER_PLUGIN_TYPE = "elasticsearch";
+
+	private static final String RANGER_ELASTICSEARCH_AUTHORIZER_IMPL_CLASSNAME = "org.apache.ranger.authorization.elasticsearch.authorizer.RangerElasticsearchAuthorizer";
+
+	private static RangerPluginClassLoader rangerPluginClassLoader = null;
+
+	private static ClassLoader esClassLoader = null;
+
+	private RangerElasticsearchAccessControl rangerElasticsearchAccessControl = null;
+
+	public RangerElasticsearchAuthorizer() {
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("==> RangerElasticsearchAuthorizer.RangerElasticsearchAuthorizer()");
+		}
+
+		this.init();
+
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("<== RangerElasticsearchAuthorizer.RangerElasticsearchAuthorizer()");
+		}
+	}
+
+	public void init() {
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("==> RangerElasticsearchAuthorizer.init()");
+		}
+
+		try {
+
+			// In elasticsearch this.getClass().getClassLoader() is FactoryURLClassLoader,
+			// but Thread.currentThread().getContextClassLoader() is AppClassLoader.
+			esClassLoader = Thread.currentThread().getContextClassLoader();
+			Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
+
+			rangerPluginClassLoader = RangerPluginClassLoader.getInstance(RANGER_PLUGIN_TYPE, this.getClass());
+			Thread.currentThread().setContextClassLoader(esClassLoader);
+
+			@SuppressWarnings("unchecked")
+			Class<RangerElasticsearchAccessControl> cls = (Class<RangerElasticsearchAccessControl>) Class
+					.forName(RANGER_ELASTICSEARCH_AUTHORIZER_IMPL_CLASSNAME, true, rangerPluginClassLoader);
+
+			activatePluginClassLoader();
+
+			rangerElasticsearchAccessControl = cls.newInstance();
+		} catch (Exception e) {
+			LOG.error("Error Enabling RangerElasticsearchAuthorizer", e);
+		} finally {
+			deactivatePluginClassLoader();
+		}
+
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("<== RangerElasticsearchAuthorizer.init()");
+		}
+	}
+
+	public boolean checkPermission(String user, List<String> groups, String index, String action,
+			String clientIPAddress) {
+		boolean ret = false;
+
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("==> RangerElasticsearchAuthorizer.checkPermission()");
+		}
+
+		try {
+			activatePluginClassLoader();
+
+			ret = rangerElasticsearchAccessControl.checkPermission(user, groups, index, action, clientIPAddress);
+		} finally {
+			deactivatePluginClassLoader();
+		}
+
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("<== RangerElasticsearchAuthorizer.checkPermission()");
+		}
+
+		return ret;
+	}
+
+	private void activatePluginClassLoader() {
+		if (rangerPluginClassLoader != null) {
+			Thread.currentThread().setContextClassLoader(rangerPluginClassLoader);
+		}
+	}
+
+	private void deactivatePluginClassLoader() {
+		if (esClassLoader != null) {
+			Thread.currentThread().setContextClassLoader(esClassLoader);
+		}
+	}
+}
diff --git a/ranger-elasticsearch-plugin-shim/src/main/java/org/apache/ranger/authorization/elasticsearch/plugin/RangerElasticsearchPlugin.java b/ranger-elasticsearch-plugin-shim/src/main/java/org/apache/ranger/authorization/elasticsearch/plugin/RangerElasticsearchPlugin.java
new file mode 100644
index 0000000..f9a6837
--- /dev/null
+++ b/ranger-elasticsearch-plugin-shim/src/main/java/org/apache/ranger/authorization/elasticsearch/plugin/RangerElasticsearchPlugin.java
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ranger.authorization.elasticsearch.plugin;
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.UnaryOperator;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.ranger.authorization.elasticsearch.plugin.action.filter.RangerSecurityActionFilter;
+import org.apache.ranger.authorization.elasticsearch.plugin.rest.filter.RangerSecurityRestFilter;
+import org.elasticsearch.action.support.ActionFilter;
+import org.elasticsearch.client.Client;
+import org.elasticsearch.cluster.service.ClusterService;
+import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
+import org.elasticsearch.common.logging.ESLoggerFactory;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.common.util.concurrent.ThreadContext;
+import org.elasticsearch.common.xcontent.NamedXContentRegistry;
+import org.elasticsearch.env.Environment;
+import org.elasticsearch.env.NodeEnvironment;
+import org.elasticsearch.plugins.ActionPlugin;
+import org.elasticsearch.plugins.Plugin;
+import org.elasticsearch.rest.RestHandler;
+import org.elasticsearch.script.ScriptService;
+import org.elasticsearch.threadpool.ThreadPool;
+import org.elasticsearch.watcher.ResourceWatcherService;
+
+public class RangerElasticsearchPlugin extends Plugin implements ActionPlugin {
+
+	private static final Logger LOG = ESLoggerFactory.getLogger(RangerElasticsearchPlugin.class);
+
+	private static final String RANGER_ELASTICSEARCH_PLUGIN_CONF_NAME = "ranger-elasticsearch-plugin";
+
+	private final Settings settings;
+
+	private RangerSecurityActionFilter rangerSecurityActionFilter;
+
+	public RangerElasticsearchPlugin(Settings settings) {
+		this.settings = settings;
+	}
+
+	@Override
+	public List<ActionFilter> getActionFilters() {
+		return Collections.singletonList(rangerSecurityActionFilter);
+	}
+
+	@Override
+	public UnaryOperator<RestHandler> getRestHandlerWrapper(ThreadContext threadContext) {
+		return (UnaryOperator<RestHandler>) (handler -> new RangerSecurityRestFilter(this.settings, threadContext,
+				handler));
+	}
+
+	@Override
+	public Collection<Object> createComponents(final Client client, final ClusterService clusterService,
+			final ThreadPool threadPool, final ResourceWatcherService resourceWatcherService,
+			final ScriptService scriptService, final NamedXContentRegistry xContentRegistry,
+			final Environment environment, final NodeEnvironment nodeEnvironment,
+			final NamedWriteableRegistry namedWriteableRegistry) {
+
+		addPluginConfig2Classpath(environment);
+
+		rangerSecurityActionFilter = new RangerSecurityActionFilter(this.settings, threadPool.getThreadContext());
+		return Collections.singletonList(rangerSecurityActionFilter);
+	}
+
+	/**
+	 * Add ranger elasticsearch plugin config directory to classpath,
+	 * then the plugin can load its configuration files from classpath.
+	 */
+	private void addPluginConfig2Classpath(Environment environment) {
+		Path configPath = environment.configFile().resolve(RANGER_ELASTICSEARCH_PLUGIN_CONF_NAME);
+		if (configPath == null) {
+			LOG.error(
+					"Failed to add ranger elasticsearch plugin config directory [ranger-elasticsearch-plugin] to classpath.");
+			return;
+		}
+		File configFile = configPath.toFile();
+
+		try {
+			if (configFile.exists()) {
+				ClassLoader classLoader = this.getClass().getClassLoader();
+				// This classLoader is FactoryURLClassLoader in eleasticsearch
+				if (classLoader instanceof URLClassLoader) {
+					URLClassLoader urlClassLoader = (URLClassLoader) classLoader;
+					Class<? extends URLClassLoader> urlClass = urlClassLoader.getClass();
+					Method method = urlClass.getSuperclass().getDeclaredMethod("addURL", new Class[] { URL.class });
+					method.setAccessible(true);
+					method.invoke(urlClassLoader, new Object[] { configFile.toURI().toURL() });
+					LOG.info("Success to add ranger elasticsearch plugin config directory [{}] to classpath.",
+							configFile.getCanonicalPath());
+				}
+			}
+		} catch (Exception e) {
+			LOG.error(
+					"Failed to add ranger elasticsearch plugin config directory [ranger-elasticsearch-plugin] to classpath.",
+					e);
+			throw new RuntimeException(e);
+		}
+	}
+}
diff --git a/ranger-elasticsearch-plugin-shim/src/main/java/org/apache/ranger/authorization/elasticsearch/plugin/action/filter/RangerSecurityActionFilter.java b/ranger-elasticsearch-plugin-shim/src/main/java/org/apache/ranger/authorization/elasticsearch/plugin/action/filter/RangerSecurityActionFilter.java
new file mode 100644
index 0000000..60baaea
--- /dev/null
+++ b/ranger-elasticsearch-plugin-shim/src/main/java/org/apache/ranger/authorization/elasticsearch/plugin/action/filter/RangerSecurityActionFilter.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ranger.authorization.elasticsearch.plugin.action.filter;
+
+import java.util.List;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.logging.log4j.Logger;
+import org.apache.ranger.authorization.elasticsearch.authorizer.RangerElasticsearchAuthorizer;
+import org.apache.ranger.authorization.elasticsearch.plugin.authc.user.UsernamePasswordToken;
+import org.apache.ranger.authorization.elasticsearch.plugin.utils.RequestUtils;
+import org.elasticsearch.ElasticsearchStatusException;
+import org.elasticsearch.action.ActionListener;
+import org.elasticsearch.action.ActionRequest;
+import org.elasticsearch.action.ActionResponse;
+import org.elasticsearch.action.support.ActionFilter;
+import org.elasticsearch.action.support.ActionFilterChain;
+import org.elasticsearch.common.component.AbstractComponent;
+import org.elasticsearch.common.logging.ESLoggerFactory;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.common.util.concurrent.ThreadContext;
+import org.elasticsearch.rest.RestStatus;
+import org.elasticsearch.tasks.Task;
+
+public class RangerSecurityActionFilter extends AbstractComponent implements ActionFilter {
+
+	private static final Logger LOG = ESLoggerFactory.getLogger(RangerSecurityActionFilter.class);
+
+	private final ThreadContext threadContext;
+
+	private final RangerElasticsearchAuthorizer rangerElasticsearchAuthorizer = new RangerElasticsearchAuthorizer();
+
+	public RangerSecurityActionFilter(Settings settings, ThreadContext threadContext) {
+		super(settings);
+		this.threadContext = threadContext;
+	}
+
+	@Override
+	public int order() {
+		return 0;
+	}
+
+	@Override
+	public <Request extends ActionRequest, Response extends ActionResponse> void apply(Task task, String action,
+			Request request, ActionListener<Response> listener, ActionFilterChain<Request, Response> chain) {
+		String user = threadContext.getTransient(UsernamePasswordToken.USERNAME);
+		// If user is not null, then should check permission of the outside caller.
+		if (StringUtils.isNotEmpty(user)) {
+			List<String> indexs = RequestUtils.getIndexFromRequest(request);
+			String clientIPAddress = threadContext.getTransient(RequestUtils.CLIENT_IP_ADDRESS);
+			for (String index : indexs) {
+				boolean result = rangerElasticsearchAuthorizer.checkPermission(user, null, index, action,
+						clientIPAddress);
+				if (!result) {
+					String errorMsg = "Error: User[{}] could not do action[{}] on index[{}]";
+					throw new ElasticsearchStatusException(errorMsg, RestStatus.FORBIDDEN, user, action, index);
+				}
+			}
+		} else {
+			if (LOG.isDebugEnabled()) {
+				LOG.debug("User is null, no check permission for elasticsearch do action[{}] with request[{}]", action,
+						request);
+			}
+		}
+		chain.proceed(task, action, request, listener);
+	}
+}
diff --git a/ranger-elasticsearch-plugin-shim/src/main/java/org/apache/ranger/authorization/elasticsearch/plugin/authc/user/UsernamePasswordToken.java b/ranger-elasticsearch-plugin-shim/src/main/java/org/apache/ranger/authorization/elasticsearch/plugin/authc/user/UsernamePasswordToken.java
new file mode 100644
index 0000000..c1df938
--- /dev/null
+++ b/ranger-elasticsearch-plugin-shim/src/main/java/org/apache/ranger/authorization/elasticsearch/plugin/authc/user/UsernamePasswordToken.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ranger.authorization.elasticsearch.plugin.authc.user;
+
+import java.util.Base64;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.collections.MapUtils;
+import org.apache.commons.lang.StringUtils;
+import org.elasticsearch.ElasticsearchStatusException;
+import org.elasticsearch.rest.RestRequest;
+import org.elasticsearch.rest.RestStatus;
+
+public class UsernamePasswordToken {
+
+	public static final String USERNAME = "username";
+
+	public static final String BASIC_AUTH_PREFIX = "Basic ";
+
+	public static final String BASIC_AUTH_HEADER = "Authorization";
+
+	private String username;
+
+	private String password;
+
+	public UsernamePasswordToken(String username, String password) {
+		this.username = username;
+		this.password = password;
+	}
+
+	public static UsernamePasswordToken parseToken(RestRequest request) {
+
+		Map<String, List<String>> headers = request.getHeaders();
+		if (MapUtils.isEmpty(headers)) {
+			return null;
+		}
+		List<String> authStrs = headers.get(BASIC_AUTH_HEADER);
+		if (CollectionUtils.isEmpty(authStrs)) {
+			return null;
+		}
+
+		String authStr = authStrs.get(0);
+		if (StringUtils.isEmpty(authStr)) {
+			return null;
+		}
+
+		String userPass = "";
+		try {
+			userPass = new String(Base64.getUrlDecoder().decode(authStr.substring(BASIC_AUTH_PREFIX.length())));
+		} catch (IllegalArgumentException e) {
+			throw new ElasticsearchStatusException("Error: Failed to parse user authentication.",
+					RestStatus.UNAUTHORIZED, e);
+		}
+
+		int i = StringUtils.indexOf(userPass, ':');
+		if (i <= 0) {
+			throw new ElasticsearchStatusException(
+					"Error: Parse user authentication to get the wrong userPass[{}].",
+					RestStatus.UNAUTHORIZED, userPass);
+		}
+		return new UsernamePasswordToken(StringUtils.substring(userPass, 0, i),
+				StringUtils.substring(userPass, i + 1, userPass.length()));
+
+	}
+
+	public String getUsername() {
+		return username;
+	}
+
+	public void setUsername(String username) {
+		this.username = username;
+	}
+
+	public String getPassword() {
+		return password;
+	}
+
+	public void setPassword(String password) {
+		this.password = password;
+	}
+
+	@Override
+	public String toString() {
+		return "UsernamePasswordToken [username=" + username + ", password=" + "******" + "]";
+	}
+}
diff --git a/ranger-elasticsearch-plugin-shim/src/main/java/org/apache/ranger/authorization/elasticsearch/plugin/rest/filter/RangerSecurityRestFilter.java b/ranger-elasticsearch-plugin-shim/src/main/java/org/apache/ranger/authorization/elasticsearch/plugin/rest/filter/RangerSecurityRestFilter.java
new file mode 100644
index 0000000..117356a
--- /dev/null
+++ b/ranger-elasticsearch-plugin-shim/src/main/java/org/apache/ranger/authorization/elasticsearch/plugin/rest/filter/RangerSecurityRestFilter.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ranger.authorization.elasticsearch.plugin.rest.filter;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.logging.log4j.Logger;
+import org.apache.ranger.authorization.elasticsearch.plugin.authc.user.UsernamePasswordToken;
+import org.apache.ranger.authorization.elasticsearch.plugin.utils.RequestUtils;
+import org.elasticsearch.ElasticsearchStatusException;
+import org.elasticsearch.client.node.NodeClient;
+import org.elasticsearch.common.component.AbstractComponent;
+import org.elasticsearch.common.logging.ESLoggerFactory;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.common.util.concurrent.ThreadContext;
+import org.elasticsearch.rest.RestChannel;
+import org.elasticsearch.rest.RestHandler;
+import org.elasticsearch.rest.RestRequest;
+import org.elasticsearch.rest.RestStatus;
+
+public class RangerSecurityRestFilter extends AbstractComponent implements RestHandler {
+
+	private static final Logger LOG = ESLoggerFactory.getLogger(RangerSecurityRestFilter.class);
+
+	private final RestHandler restHandler;
+
+	private final ThreadContext threadContext;
+
+	public RangerSecurityRestFilter(final Settings settings, final ThreadContext threadContext,
+			final RestHandler restHandler) {
+		super(settings);
+		this.restHandler = restHandler;
+		this.threadContext = threadContext;
+	}
+
+	@Override
+	public void handleRequest(final RestRequest request, final RestChannel channel, final NodeClient client)
+			throws Exception {
+		// Now only support to get user from request,
+		// it should work with other elasticsearch identity authentication plugins in fact.
+		UsernamePasswordToken user = UsernamePasswordToken.parseToken(request);
+		if (user == null) {
+			throw new ElasticsearchStatusException("Error: User is null, the request requires user authentication.",
+					RestStatus.UNAUTHORIZED);
+		} else {
+			if (LOG.isDebugEnabled()) {
+				LOG.debug("Success to parse user[{}] from request[{}].", user, request);
+			}
+		}
+		threadContext.putTransient(UsernamePasswordToken.USERNAME, user.getUsername());
+
+		String clientIPAddress = RequestUtils.getClientIPAddress(request);
+		if (StringUtils.isNotEmpty(clientIPAddress)) {
+			threadContext.putTransient(RequestUtils.CLIENT_IP_ADDRESS, clientIPAddress);
+		}
+
+		this.restHandler.handleRequest(request, channel, client);
+	}
+}
diff --git a/ranger-elasticsearch-plugin-shim/src/main/java/org/apache/ranger/authorization/elasticsearch/plugin/utils/RequestUtils.java b/ranger-elasticsearch-plugin-shim/src/main/java/org/apache/ranger/authorization/elasticsearch/plugin/utils/RequestUtils.java
new file mode 100644
index 0000000..8a04b06
--- /dev/null
+++ b/ranger-elasticsearch-plugin-shim/src/main/java/org/apache/ranger/authorization/elasticsearch/plugin/utils/RequestUtils.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ranger.authorization.elasticsearch.plugin.utils;
+
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.elasticsearch.action.ActionRequest;
+import org.elasticsearch.action.DocWriteRequest;
+import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
+import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
+import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
+import org.elasticsearch.action.admin.indices.open.OpenIndexRequest;
+import org.elasticsearch.action.admin.indices.stats.IndicesStatsRequest;
+import org.elasticsearch.action.bulk.BulkRequest;
+import org.elasticsearch.action.get.MultiGetRequest;
+import org.elasticsearch.action.get.MultiGetRequest.Item;
+import org.elasticsearch.action.search.SearchRequest;
+import org.elasticsearch.action.support.replication.ReplicationRequest;
+import org.elasticsearch.action.support.single.instance.InstanceShardOperationRequest;
+import org.elasticsearch.action.support.single.shard.SingleShardRequest;
+import org.elasticsearch.rest.RestRequest;
+
+public class RequestUtils {
+	public static final String CLIENT_IP_ADDRESS = "ClientIPAddress";
+
+	public static String getClientIPAddress(RestRequest request) {
+		SocketAddress socketAddress = request.getRemoteAddress();
+		if (socketAddress instanceof InetSocketAddress) {
+			return ((InetSocketAddress) socketAddress).getAddress().getHostAddress();
+		}
+
+		return null;
+	}
+
+	// To support all kinds of request in elasticsearch
+	public static <Request extends ActionRequest> List<String> getIndexFromRequest(Request request) {
+		List<String> indexs = new ArrayList<>();
+
+		if (request instanceof SingleShardRequest) {
+			indexs.add(((SingleShardRequest<?>) request).index());
+			return indexs;
+		}
+
+		if (request instanceof ReplicationRequest) {
+			indexs.add(((ReplicationRequest<?>) request).index());
+			return indexs;
+		}
+
+		if (request instanceof InstanceShardOperationRequest) {
+			indexs.add(((InstanceShardOperationRequest<?>) request).index());
+			return indexs;
+		}
+
+		if (request instanceof CreateIndexRequest) {
+			indexs.add(((CreateIndexRequest) request).index());
+			return indexs;
+		}
+
+		if (request instanceof PutMappingRequest) {
+			indexs.add(((PutMappingRequest) request).getConcreteIndex().getName());
+			return indexs;
+		}
+
+		if (request instanceof SearchRequest) {
+			return Arrays.asList(((SearchRequest) request).indices());
+		}
+
+		if (request instanceof IndicesStatsRequest) {
+			return Arrays.asList(((IndicesStatsRequest) request).indices());
+		}
+
+		if (request instanceof OpenIndexRequest) {
+			return Arrays.asList(((OpenIndexRequest) request).indices());
+		}
+
+		if (request instanceof DeleteIndexRequest) {
+			return Arrays.asList(((DeleteIndexRequest) request).indices());
+		}
+
+		if (request instanceof BulkRequest) {
+			@SuppressWarnings("rawtypes")
+			List<DocWriteRequest> requests = ((BulkRequest) request).requests();
+
+			if (CollectionUtils.isNotEmpty(requests)) {
+				for (DocWriteRequest<?> docWriteRequest : requests) {
+					indexs.add(docWriteRequest.index());
+				}
+				return indexs;
+			}
+		}
+
+		if (request instanceof MultiGetRequest) {
+			List<Item> items = ((MultiGetRequest) request).getItems();
+			if (CollectionUtils.isNotEmpty(items)) {
+				for (Item item : items) {
+					indexs.add(item.index());
+				}
+				return indexs;
+			}
+		}
+
+		// No matched request type to find specific index , set default value *
+		indexs.add("*");
+		return indexs;
+	}
+}
diff --git a/src/main/assembly/admin-web.xml b/src/main/assembly/admin-web.xml
index b3ec885..8ea728b 100644
--- a/src/main/assembly/admin-web.xml
+++ b/src/main/assembly/admin-web.xml
@@ -376,6 +376,18 @@
           </includes>
       </moduleSet>
 
+      <moduleSet>
+          <binaries>
+              <includeDependencies>true</includeDependencies>
+              <outputDirectory>/ews/webapp/WEB-INF/classes/ranger-plugins/elasticsearch</outputDirectory>
+              <unpack>false</unpack>
+              <directoryMode>755</directoryMode>
+              <fileMode>644</fileMode>
+          </binaries>
+          <includes>
+              <include>org.apache.ranger:ranger-elasticsearch-plugin</include>
+          </includes>
+      </moduleSet>
   </moduleSets>
 
   <fileSets>
diff --git a/src/main/assembly/plugin-elasticsearch.xml b/src/main/assembly/plugin-elasticsearch.xml
new file mode 100644
index 0000000..41f73a3
--- /dev/null
+++ b/src/main/assembly/plugin-elasticsearch.xml
@@ -0,0 +1,197 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<assembly>
+    <id>elasticsearch-plugin</id>
+    <formats>
+        <format>tar.gz</format>
+        <format>zip</format>
+    </formats>
+    <baseDirectory>${project.name}-${project.version}-elasticsearch-plugin</baseDirectory>
+    <includeBaseDirectory>true</includeBaseDirectory>
+  <moduleSets>
+    <moduleSet>
+    <binaries>
+        <includeDependencies>false</includeDependencies>
+        <unpack>false</unpack>
+        <directoryMode>755</directoryMode>
+        <fileMode>644</fileMode>
+        <dependencySets>
+            <dependencySet>
+                <outputDirectory>/lib/ranger-elasticsearch-plugin</outputDirectory>
+                <unpack>false</unpack>
+                <includes>
+                    <include>commons-collections:commons-collections</include>
+                    <include>commons-lang:commons-lang</include>
+                    <include>org.slf4j:slf4j-api</include>
+					<include>org.slf4j:slf4j-log4j12</include>
+                </includes>
+            </dependencySet>
+        </dependencySets>
+        <outputDirectory>/lib/ranger-elasticsearch-plugin</outputDirectory>
+    </binaries>
+    <includes>
+        <include>org.apache.ranger:ranger-elasticsearch-plugin-shim</include>
+        <include>org.apache.ranger:ranger-plugin-classloader</include>
+    </includes>
+    </moduleSet>
+
+    <moduleSet>
+    <binaries>
+        <includeDependencies>false</includeDependencies>
+        <unpack>false</unpack>
+        <directoryMode>755</directoryMode>
+        <fileMode>644</fileMode>
+        <dependencySets>
+            <dependencySet>
+                <outputDirectory>/lib/ranger-elasticsearch-plugin/ranger-elasticsearch-plugin-impl</outputDirectory>
+                <unpack>false</unpack>
+                <includes>
+                    <include>commons-configuration:commons-configuration:jar:${commons.configuration.version}</include>
+                    <include>org.apache.hadoop:hadoop-common:jar:${hadoop.version}</include>
+                    <include>org.apache.hadoop:hadoop-common-plus:jar:${hadoop.version}</include>
+                    <include>org.apache.hadoop:hadoop-auth:jar:${hadoop.version}</include>
+                    <include>org.apache.hadoop:hadoop-hdfs:jar:${hadoop.version}</include>
+                    <include>com.google.code.gson:gson</include>
+                    <include>org.eclipse.persistence:eclipselink</include>
+                    <include>org.eclipse.persistence:javax.persistence</include>
+                    <include>com.sun.jersey:jersey-bundle</include>
+                    <include>commons-logging:commons-logging:jar:${commons.logging.version}</include>
+                    <include>commons-io:commons-io</include>
+                    <include>com.google.guava:guava:jar:${google.guava.version}</include>
+                    <include>org.apache.httpcomponents:httpclient:jar:${httpcomponents.httpclient.version}</include>
+                    <include>org.apache.httpcomponents:httpcore:jar:${httpcomponents.httpcore.version}</include>
+                    <include>org.apache.httpcomponents:httpmime:jar:${httpcomponents.httpmime.version}</include>
+                    <include>org.noggit:noggit:jar:${noggit.version}</include>
+                    <include>org.codehaus.jackson:jackson-core-asl</include>
+                    <include>org.codehaus.jackson:jackson-jaxrs</include>
+                    <include>org.codehaus.jackson:jackson-mapper-asl</include>
+                    <include>org.codehaus.jackson:jackson-xc</include>
+                    <include>org.apache.solr:solr-solrj</include>
+                    <include>commons-codec:commons-codec</include>
+                </includes>
+            </dependencySet>
+            <dependencySet>
+                <outputDirectory>/install/lib</outputDirectory>
+                <unpack>false</unpack>
+                <directoryMode>755</directoryMode>
+                <fileMode>644</fileMode>
+                <includes>
+                    <include>commons-cli:commons-cli</include>
+                    <include>commons-collections:commons-collections</include>
+                    <include>commons-configuration:commons-configuration:jar:${commons.configuration.version}</include>
+                    <include>commons-io:commons-io:jar:${commons.io.version}</include>
+                    <include>commons-lang:commons-lang:jar:${commons.lang.version}</include>
+                    <include>commons-logging:commons-logging:jar:${commons.logging.version}</include>
+                    <include>com.google.guava:guava:jar:${google.guava.version}</include>
+                    <include>org.slf4j:slf4j-api:jar:${slf4j-api.version}</include>
+                    <include>org.apache.hadoop:hadoop-common:jar:${hadoop.version}</include>
+                    <include>org.apache.hadoop:hadoop-auth:jar:${hadoop.version}</include>
+                    <include>org.apache.ranger:ranger-plugins-cred</include>
+                    <include>org.apache.ranger:credentialbuilder</include>
+                </includes>
+            </dependencySet>
+        </dependencySets>
+        <outputDirectory>/lib/ranger-elasticsearch-plugin/ranger-elasticsearch-plugin-impl</outputDirectory>
+    </binaries>
+    <includes>
+        <include>org.apache.ranger:ranger-plugins-audit</include>
+        <include>org.apache.ranger:ranger-plugins-cred</include>
+        <include>org.apache.ranger:ranger-plugins-common</include>
+        <include>org.apache.ranger:ranger-elasticsearch-plugin</include>
+    </includes>
+    </moduleSet>
+    <moduleSet>
+    <binaries>
+        <includeDependencies>true</includeDependencies>
+        <outputDirectory>/install/lib</outputDirectory>
+        <unpack>false</unpack>
+    </binaries>
+    <includes>
+        <include>org.apache.ranger:ranger-plugins-installer</include>
+        <include>org.apache.ranger:credentialbuilder</include>
+    </includes>
+    </moduleSet>
+   </moduleSets>
+   <fileSets>
+   <!-- conf.templates for enable -->
+    <fileSet>
+        <outputDirectory>/install/conf.templates/enable</outputDirectory>
+        <directory>plugin-elasticsearch/conf</directory>
+        <excludes>
+            <exclude>*.sh</exclude>
+        </excludes>
+        <fileMode>700</fileMode>
+    </fileSet>
+    <fileSet>
+        <outputDirectory>/install/conf.templates/disable</outputDirectory>
+        <directory>plugin-elasticsearch/disable-conf</directory>
+        <fileMode>700</fileMode>
+    </fileSet>
+    <fileSet>
+        <outputDirectory>/install/conf.templates/default</outputDirectory>
+        <directory>plugin-elasticsearch/template</directory>
+        <fileMode>700</fileMode>
+    </fileSet>
+    <!-- version file -->
+    <fileSet>
+        <outputDirectory>/</outputDirectory>
+        <directory>${project.build.outputDirectory}</directory>
+        <includes>
+            <include>version</include>
+        </includes>
+        <fileMode>444</fileMode>
+    </fileSet>
+  </fileSets>
+  <!-- enable/disable script for Plugin -->
+  <files>
+    <file>
+        <source>agents-common/scripts/enable-agent.sh</source>
+        <outputDirectory>/</outputDirectory>
+        <destName>enable-elasticsearch-plugin.sh</destName>
+        <fileMode>755</fileMode>
+    </file>
+    <file>
+        <source>agents-common/scripts/enable-agent.sh</source>
+        <outputDirectory>/</outputDirectory>
+        <destName>disable-elasticsearch-plugin.sh</destName>
+        <fileMode>755</fileMode>
+    </file>
+    <file>
+        <source>plugin-elasticsearch/scripts/install.properties</source>
+        <outputDirectory>/</outputDirectory>
+        <destName>install.properties</destName>
+        <fileMode>755</fileMode>
+    </file>
+    <file>
+        <source>security-admin/scripts/ranger_credential_helper.py</source>
+        <outputDirectory>/</outputDirectory>
+        <fileMode>755</fileMode>
+    </file>
+    <file>
+        <source>ranger-elasticsearch-plugin-shim/conf/plugin-descriptor.properties</source>
+        <outputDirectory>/lib/ranger-elasticsearch-plugin</outputDirectory>
+        <fileMode>755</fileMode>
+        <filtered>true</filtered>
+    </file>
+    <file>
+        <source>ranger-elasticsearch-plugin-shim/conf/plugin-security.policy</source>
+        <outputDirectory>/lib/ranger-elasticsearch-plugin</outputDirectory>
+        <fileMode>755</fileMode>
+    </file>
+  </files>
+</assembly>