diff --git a/src/test/java/com/amazon/opendistroforelasticsearch/security/multitenancy/test/MultitenancyTests.java b/src/test/java/com/amazon/opendistroforelasticsearch/security/multitenancy/test/MultitenancyTests.java index 3e94a2b31..b0aa9a128 100644 --- a/src/test/java/com/amazon/opendistroforelasticsearch/security/multitenancy/test/MultitenancyTests.java +++ b/src/test/java/com/amazon/opendistroforelasticsearch/security/multitenancy/test/MultitenancyTests.java @@ -383,5 +383,4 @@ public void testKibanaAlias65() throws Exception { System.out.println(res.getBody()); Assert.assertTrue(res.getBody().contains(".kibana_-900636979_kibanaro")); } - } diff --git a/src/test/java/com/amazon/opendistroforelasticsearch/security/openshift_logging/CollectorTests.java b/src/test/java/com/amazon/opendistroforelasticsearch/security/openshift_logging/CollectorTests.java new file mode 100644 index 000000000..2b408fcd1 --- /dev/null +++ b/src/test/java/com/amazon/opendistroforelasticsearch/security/openshift_logging/CollectorTests.java @@ -0,0 +1,146 @@ +package com.amazon.opendistroforelasticsearch.security.openshift_logging; + +import com.amazon.opendistroforelasticsearch.security.test.DynamicSecurityConfig; +import com.amazon.opendistroforelasticsearch.security.test.SingleClusterTest; +import com.amazon.opendistroforelasticsearch.security.test.helper.rest.RestHelper; +import org.apache.http.HttpStatus; +import org.apache.http.message.BasicHeader; +import org.elasticsearch.action.admin.indices.alias.Alias; +import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; +import org.elasticsearch.action.index.IndexRequest; +import org.elasticsearch.action.support.WriteRequest; +import org.elasticsearch.client.transport.TransportClient; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.xcontent.XContentType; +import org.junit.Assert; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +public class CollectorTests extends SingleClusterTest { + + @Override + protected String getResourceFolder() { + return "openshift-logging"; + } + + @Test + public void testBulkIndexDocuments() throws Exception { + final Settings settings = Settings.builder() + .put("opendistro_security.restapi.roles_enabled", "kibana_server") + .build(); + + final DynamicSecurityConfig dsc = new DynamicSecurityConfig() + .setConfig("ocp_config.yml") + .setSecurityRoles("ocp_roles.yml") + .setSecurityRolesMapping("ocp_roles_mapping.yml") + .setSecurityInternalUsers("ocp_internal_users.yml") + .setSecurityActionGroups("ocp_action_groups.yml"); + + setup(Settings.EMPTY, dsc, settings); + try (TransportClient tc = getInternalTransportClient()) { + Map indexSettings = new HashMap(); + indexSettings.put("number_of_shards", 1); + indexSettings.put("number_of_replicas", 1); + + for (int i = 1; i < 21; i++) { + String leadingZeros = "00000"; + if (i >= 10) { + leadingZeros = "0000"; + } + + String appIndexName = "app-" + leadingZeros + i; + CreateIndexRequest cir = new CreateIndexRequest(appIndexName) + .alias(new Alias("app")) + .settings(indexSettings); + + if (i == 20) { + cir = cir.alias(new Alias("app-write")); + } + tc.admin().indices().create(cir).actionGet(); + + String doc = "{\"message\": \"This is just a test\", \"namespace\": \"test\", \"kubernetes\": {\"namespace_name\": \"test\"}}"; + tc.index(new IndexRequest(appIndexName) + .type("doc") + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) + .source(doc, XContentType.JSON)).actionGet(); + } + } + final RestHelper rh = nonSslRestHelper(); + RestHelper.HttpResponse res; + + res = rh.executePostRequest( + "_bulk", + "{ \"index\" : { \"_index\" : \"app-write\", \"_type\" : \"_doc\", \"_id\" : \"1\" } }\n" + + "{ \"index\" : { \"_index\" : \"app_write\", \"_type\" : \"_doc\", \"_id\" : \"2\" } }\n" + + "{ \"index\" : { \"_index\" : \"app-write\", \"_type\" : \"_doc\", \"_id\" : \"3\" } }\n" + + "{ \"index\" : { \"_index\" : \"app-write\", \"_type\" : \"_doc\", \"_id\" : \"4\" } }\n", + // Use x-forwarded* headers to allow extended-proxy authentication + new BasicHeader("x-forwarded-for", "127.0.0.1"), + new BasicHeader("x-forwarded-user", "CN=system.logging.fluentd,OU=Logging,O=OpenShift") + ); + + System.out.println(res.getBody()); + Assert.assertEquals(HttpStatus.SC_OK, res.getStatusCode()); + Assert.assertTrue(res.getBody().contains("\"errors\":false,\"items\":[{\"index\":{\"_index\":\"app-000020\",\"_type\":\"_doc\",\"_id\":\"1\",\"_version\":1,\"result\":\"created\",\"_shards\":{\"total\":2,\"successful\":2,\"failed\":0},\"_seq_no\":1,\"_primary_term\":1,\"status\":201}},{\"index\":{\"_index\":\"app-000020\",\"_type\":\"_doc\",\"_id\":\"3\",\"_version\":1,\"result\":\"created\",\"_shards\":{\"total\":2,\"successful\":2,\"failed\":0},\"_seq_no\":2,\"_primary_term\":1,\"status\":201}}]")); + } + + @Test + public void testCreateIndex() throws Exception { + final Settings settings = Settings.builder() + .put("opendistro_security.restapi.roles_enabled", "kibana_server") + .build(); + + final DynamicSecurityConfig dsc = new DynamicSecurityConfig() + .setConfig("ocp_config.yml") + .setSecurityRoles("ocp_roles.yml") + .setSecurityRolesMapping("ocp_roles_mapping.yml") + .setSecurityInternalUsers("ocp_internal_users.yml") + .setSecurityActionGroups("ocp_action_groups.yml"); + + setup(Settings.EMPTY, dsc, settings); + try (TransportClient tc = getInternalTransportClient()) { + Map indexSettings = new HashMap(); + indexSettings.put("number_of_shards", 1); + indexSettings.put("number_of_replicas", 1); + + for (int i = 1; i < 21; i++) { + String leadingZeros = "00000"; + if (i >= 10) { + leadingZeros = "0000"; + } + + String appIndexName = "app-" + leadingZeros + i; + CreateIndexRequest cir = new CreateIndexRequest(appIndexName) + .alias(new Alias("app")) + .settings(indexSettings); + + if (i == 20) { + cir = cir.alias(new Alias("app-write")); + } + tc.admin().indices().create(cir).actionGet(); + + String doc = "{\"message\": \"This is just a test\", \"namespace\": \"test\", \"kubernetes\": {\"namespace_name\": \"test\"}}"; + tc.index(new IndexRequest(appIndexName) + .type("doc") + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) + .source(doc, XContentType.JSON)).actionGet(); + } + } + final RestHelper rh = nonSslRestHelper(); + RestHelper.HttpResponse res; + + res = rh.executePutRequest( + "app-000021", + "", + // Use x-forwarded* headers to allow extended-proxy authentication + new BasicHeader("x-forwarded-for", "127.0.0.1"), + new BasicHeader("x-forwarded-user", "CN=system.logging.fluentd,OU=Logging,O=OpenShift") + ); + + System.out.println(res.getBody()); + Assert.assertEquals(HttpStatus.SC_OK, res.getStatusCode()); + Assert.assertTrue(res.getBody().contains("{\"acknowledged\":true,\"shards_acknowledged\":true,\"index\":\"app-000021\"}")); + } +} diff --git a/src/test/java/com/amazon/opendistroforelasticsearch/security/openshift_logging/ElasticsearchOperatorTests.java b/src/test/java/com/amazon/opendistroforelasticsearch/security/openshift_logging/ElasticsearchOperatorTests.java new file mode 100644 index 000000000..4406c0d74 --- /dev/null +++ b/src/test/java/com/amazon/opendistroforelasticsearch/security/openshift_logging/ElasticsearchOperatorTests.java @@ -0,0 +1,574 @@ +package com.amazon.opendistroforelasticsearch.security.openshift_logging; + +import com.amazon.opendistroforelasticsearch.security.test.DynamicSecurityConfig; +import com.amazon.opendistroforelasticsearch.security.test.SingleClusterTest; +import com.amazon.opendistroforelasticsearch.security.test.helper.rest.RestHelper; +import org.apache.http.HttpStatus; +import org.apache.http.message.BasicHeader; +import org.elasticsearch.action.admin.indices.alias.Alias; +import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; +import org.elasticsearch.action.index.IndexRequest; +import org.elasticsearch.action.support.WriteRequest; +import org.elasticsearch.client.transport.TransportClient; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.xcontent.XContentType; +import org.junit.Assert; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +public class ElasticsearchOperatorTests extends SingleClusterTest { + + @Override + protected String getResourceFolder() { + return "openshift-logging"; + } + + /** + * Cluster Level Tests + **/ + + @Test + public void testDoSynchronizedFlush() throws Exception { + final Settings settings = Settings.builder() + .put("opendistro_security.restapi.roles_enabled", "kibana_server") + .build(); + + final DynamicSecurityConfig dsc = new DynamicSecurityConfig() + .setConfig("ocp_config.yml") + .setSecurityRoles("ocp_roles.yml") + .setSecurityRolesMapping("ocp_roles_mapping.yml") + .setSecurityInternalUsers("ocp_internal_users.yml") + .setSecurityActionGroups("ocp_action_groups.yml"); + + setup(Settings.EMPTY, dsc, settings); + + final RestHelper rh = nonSslRestHelper(); + RestHelper.HttpResponse res; + + res = rh.executeGetRequest( + "_flush/synced", + // Use x-forwarded* headers to allow extended-proxy authentication + new BasicHeader("x-forwarded-for", "127.0.0.1"), + new BasicHeader("x-forwarded-user", "system:serviceaccount:openshift-operators-redhat:elasticsearch-operator"), + new BasicHeader("x-forwarded-roles", "elasticsearch-operator,prometheus"), + new BasicHeader("x-ocp-ns", "openshift-logging") + ); + + System.out.println(res.getBody()); + Assert.assertEquals(HttpStatus.SC_OK, res.getStatusCode()); + } + + @Test + public void testGetClusterHealth() throws Exception { + final Settings settings = Settings.builder() + .put("opendistro_security.restapi.roles_enabled", "kibana_server") + .build(); + + final DynamicSecurityConfig dsc = new DynamicSecurityConfig() + .setConfig("ocp_config.yml") + .setSecurityRoles("ocp_roles.yml") + .setSecurityRolesMapping("ocp_roles_mapping.yml") + .setSecurityInternalUsers("ocp_internal_users.yml") + .setSecurityActionGroups("ocp_action_groups.yml"); + + setup(Settings.EMPTY, dsc, settings); + + final RestHelper rh = nonSslRestHelper(); + RestHelper.HttpResponse res; + + res = rh.executeGetRequest( + "_cluster/health", + // Use x-forwarded* headers to allow extended-proxy authentication + new BasicHeader("x-forwarded-for", "127.0.0.1"), + new BasicHeader("x-forwarded-user", "system:serviceaccount:openshift-operators-redhat:elasticsearch-operator"), + new BasicHeader("x-forwarded-roles", "elasticsearch-operator,prometheus"), + new BasicHeader("x-ocp-ns", "openshift-logging") + ); + + System.out.println(res.getBody()); + Assert.assertEquals(HttpStatus.SC_OK, res.getStatusCode()); + } + + @Test + public void testGetClusterSettings() throws Exception { + final Settings settings = Settings.builder() + .put("opendistro_security.restapi.roles_enabled", "kibana_server") + .build(); + + final DynamicSecurityConfig dsc = new DynamicSecurityConfig() + .setConfig("ocp_config.yml") + .setSecurityRoles("ocp_roles.yml") + .setSecurityRolesMapping("ocp_roles_mapping.yml") + .setSecurityInternalUsers("ocp_internal_users.yml") + .setSecurityActionGroups("ocp_action_groups.yml"); + + setup(Settings.EMPTY, dsc, settings); + + final RestHelper rh = nonSslRestHelper(); + RestHelper.HttpResponse res; + + res = rh.executeGetRequest( + "_cluster/settings", + // Use x-forwarded* headers to allow extended-proxy authentication + new BasicHeader("x-forwarded-for", "127.0.0.1"), + new BasicHeader("x-forwarded-user", "system:serviceaccount:openshift-operators-redhat:elasticsearch-operator"), + new BasicHeader("x-forwarded-roles", "elasticsearch-operator,prometheus"), + new BasicHeader("x-ocp-ns", "openshift-logging") + ); + + System.out.println(res.getBody()); + Assert.assertEquals(HttpStatus.SC_OK, res.getStatusCode()); + } + + @Test + public void testGetClusterStateNodes() throws Exception { + final Settings settings = Settings.builder() + .put("opendistro_security.restapi.roles_enabled", "kibana_server") + .build(); + + final DynamicSecurityConfig dsc = new DynamicSecurityConfig() + .setConfig("ocp_config.yml") + .setSecurityRoles("ocp_roles.yml") + .setSecurityRolesMapping("ocp_roles_mapping.yml") + .setSecurityInternalUsers("ocp_internal_users.yml") + .setSecurityActionGroups("ocp_action_groups.yml"); + + setup(Settings.EMPTY, dsc, settings); + + final RestHelper rh = nonSslRestHelper(); + RestHelper.HttpResponse res; + + res = rh.executeGetRequest( + "_cluster/state/nodes/_all", + // Use x-forwarded* headers to allow extended-proxy authentication + new BasicHeader("x-forwarded-for", "127.0.0.1"), + new BasicHeader("x-forwarded-user", "system:serviceaccount:openshift-operators-redhat:elasticsearch-operator"), + new BasicHeader("x-forwarded-roles", "elasticsearch-operator,prometheus"), + new BasicHeader("x-ocp-ns", "openshift-logging") + ); + + System.out.println(res.getBody()); + Assert.assertEquals(HttpStatus.SC_OK, res.getStatusCode()); + } + + @Test + public void testGetClusterStats() throws Exception { + final Settings settings = Settings.builder() + .put("opendistro_security.restapi.roles_enabled", "kibana_server") + .build(); + + final DynamicSecurityConfig dsc = new DynamicSecurityConfig() + .setConfig("ocp_config.yml") + .setSecurityRoles("ocp_roles.yml") + .setSecurityRolesMapping("ocp_roles_mapping.yml") + .setSecurityInternalUsers("ocp_internal_users.yml") + .setSecurityActionGroups("ocp_action_groups.yml"); + + setup(Settings.EMPTY, dsc, settings); + + final RestHelper rh = nonSslRestHelper(); + RestHelper.HttpResponse res; + + res = rh.executeGetRequest( + "_cluster/stats", + // Use x-forwarded* headers to allow extended-proxy authentication + new BasicHeader("x-forwarded-for", "127.0.0.1"), + new BasicHeader("x-forwarded-user", "system:serviceaccount:openshift-operators-redhat:elasticsearch-operator"), + new BasicHeader("x-forwarded-roles", "elasticsearch-operator,prometheus"), + new BasicHeader("x-ocp-ns", "openshift-logging") + ); + + System.out.println(res.getBody()); + Assert.assertEquals(HttpStatus.SC_OK, res.getStatusCode()); + } + + @Test + public void testGetNodesStatsFS() throws Exception { + final Settings settings = Settings.builder() + .put("opendistro_security.restapi.roles_enabled", "kibana_server") + .build(); + + final DynamicSecurityConfig dsc = new DynamicSecurityConfig() + .setConfig("ocp_config.yml") + .setSecurityRoles("ocp_roles.yml") + .setSecurityRolesMapping("ocp_roles_mapping.yml") + .setSecurityInternalUsers("ocp_internal_users.yml") + .setSecurityActionGroups("ocp_action_groups.yml"); + + setup(Settings.EMPTY, dsc, settings); + + final RestHelper rh = nonSslRestHelper(); + RestHelper.HttpResponse res; + + res = rh.executeGetRequest( + "_nodes/stats/fs", + // Use x-forwarded* headers to allow extended-proxy authentication + new BasicHeader("x-forwarded-for", "127.0.0.1"), + new BasicHeader("x-forwarded-user", "system:serviceaccount:openshift-operators-redhat:elasticsearch-operator"), + new BasicHeader("x-forwarded-roles", "elasticsearch-operator,prometheus"), + new BasicHeader("x-ocp-ns", "openshift-logging") + ); + + System.out.println(res.getBody()); + Assert.assertEquals(HttpStatus.SC_OK, res.getStatusCode()); + } + + /** + * Index Level Tests + **/ + + @Test + public void testGetSingleIndex() throws Exception { + final Settings settings = Settings.builder() + .put("opendistro_security.restapi.roles_enabled", "kibana_server") + .build(); + + final DynamicSecurityConfig dsc = new DynamicSecurityConfig() + .setConfig("ocp_config.yml") + .setSecurityRoles("ocp_roles.yml") + .setSecurityRolesMapping("ocp_roles_mapping.yml") + .setSecurityInternalUsers("ocp_internal_users.yml") + .setSecurityActionGroups("ocp_action_groups.yml"); + + setup(Settings.EMPTY, dsc, settings); + try (TransportClient tc = getInternalTransportClient()) { + Map indexSettings = new HashMap(); + indexSettings.put("number_of_shards", 1); + indexSettings.put("number_of_replicas", 1); + + for (int i = 1; i < 21; i++) { + String leadingZeros = "00000"; + if (i >= 10) { + leadingZeros = "0000"; + } + + String appIndexName = "app-" + leadingZeros + i; + CreateIndexRequest cir = new CreateIndexRequest(appIndexName) + .alias(new Alias("app")) + .settings(indexSettings); + + if (i == 20) { + cir = cir.alias(new Alias("app-write")); + } + tc.admin().indices().create(cir).actionGet(); + + String doc = "{\"message\": \"This is just a test\", \"namespace\": \"test\", \"kubernetes\": {\"namespace_name\": \"test\"}}"; + tc.index(new IndexRequest(appIndexName) + .type("doc") + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) + .source(doc, XContentType.JSON)).actionGet(); + } + } + final RestHelper rh = nonSslRestHelper(); + RestHelper.HttpResponse res; + + res = rh.executeGetRequest( + "app-000010", + // Use x-forwarded* headers to allow extended-proxy authentication + new BasicHeader("x-forwarded-for", "127.0.0.1"), + new BasicHeader("x-forwarded-user", "system:serviceaccount:openshift-operators-redhat:elasticsearch-operator"), + new BasicHeader("x-forwarded-roles", "elasticsearch-operator,prometheus"), + new BasicHeader("x-ocp-ns", "openshift-logging") + ); + + System.out.println(res.getBody()); + Assert.assertEquals(HttpStatus.SC_OK, res.getStatusCode()); + } + + @Test + public void testGetAllIndices() throws Exception { + final Settings settings = Settings.builder() + .put("opendistro_security.restapi.roles_enabled", "kibana_server") + .build(); + + final DynamicSecurityConfig dsc = new DynamicSecurityConfig() + .setConfig("ocp_config.yml") + .setSecurityRoles("ocp_roles.yml") + .setSecurityRolesMapping("ocp_roles_mapping.yml") + .setSecurityInternalUsers("ocp_internal_users.yml") + .setSecurityActionGroups("ocp_action_groups.yml"); + + setup(Settings.EMPTY, dsc, settings); + try (TransportClient tc = getInternalTransportClient()) { + Map indexSettings = new HashMap(); + indexSettings.put("number_of_shards", 1); + indexSettings.put("number_of_replicas", 1); + + for (int i = 1; i < 21; i++) { + String leadingZeros = "00000"; + if (i >= 10) { + leadingZeros = "0000"; + } + + String appIndexName = "app-" + leadingZeros + i; + CreateIndexRequest cir = new CreateIndexRequest(appIndexName) + .alias(new Alias("app")) + .settings(indexSettings); + + if (i == 20) { + cir = cir.alias(new Alias("app-write")); + } + tc.admin().indices().create(cir).actionGet(); + + String doc = "{\"message\": \"This is just a test\", \"namespace\": \"test\", \"kubernetes\": {\"namespace_name\": \"test\"}}"; + tc.index(new IndexRequest(appIndexName) + .type("doc") + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) + .source(doc, XContentType.JSON)).actionGet(); + } + } + final RestHelper rh = nonSslRestHelper(); + RestHelper.HttpResponse res; + + res = rh.executeGetRequest( + "_cat/indices/?format=json", + // Use x-forwarded* headers to allow extended-proxy authentication + new BasicHeader("x-forwarded-for", "127.0.0.1"), + new BasicHeader("x-forwarded-user", "system:serviceaccount:openshift-operators-redhat:elasticsearch-operator"), + new BasicHeader("x-forwarded-roles", "elasticsearch-operator,prometheus"), + new BasicHeader("x-ocp-ns", "openshift-logging") + ); + + System.out.println(res.getBody()); + Assert.assertEquals(HttpStatus.SC_OK, res.getStatusCode()); + } + + @Test + public void testGetAllIndicesForAlias() throws Exception { + final Settings settings = Settings.builder() + .put("opendistro_security.restapi.roles_enabled", "kibana_server") + .build(); + + final DynamicSecurityConfig dsc = new DynamicSecurityConfig() + .setConfig("ocp_config.yml") + .setSecurityRoles("ocp_roles.yml") + .setSecurityRolesMapping("ocp_roles_mapping.yml") + .setSecurityInternalUsers("ocp_internal_users.yml") + .setSecurityActionGroups("ocp_action_groups.yml"); + + setup(Settings.EMPTY, dsc, settings); + try (TransportClient tc = getInternalTransportClient()) { + Map indexSettings = new HashMap(); + indexSettings.put("number_of_shards", 1); + indexSettings.put("number_of_replicas", 1); + + for (int i = 1; i < 21; i++) { + String leadingZeros = "00000"; + if (i >= 10) { + leadingZeros = "0000"; + } + + String appIndexName = "app-" + leadingZeros + i; + CreateIndexRequest cir = new CreateIndexRequest(appIndexName) + .alias(new Alias("app")) + .settings(indexSettings); + + if (i == 20) { + cir = cir.alias(new Alias("app-write")); + } + tc.admin().indices().create(cir).actionGet(); + + String doc = "{\"message\": \"This is just a test\", \"namespace\": \"test\", \"kubernetes\": {\"namespace_name\": \"test\"}}"; + tc.index(new IndexRequest(appIndexName) + .type("doc") + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) + .source(doc, XContentType.JSON)).actionGet(); + } + } + final RestHelper rh = nonSslRestHelper(); + RestHelper.HttpResponse res; + + res = rh.executeGetRequest( + "_alias/app-write", + // Use x-forwarded* headers to allow extended-proxy authentication + new BasicHeader("x-forwarded-for", "127.0.0.1"), + new BasicHeader("x-forwarded-user", "system:serviceaccount:openshift-operators-redhat:elasticsearch-operator"), + new BasicHeader("x-forwarded-roles", "elasticsearch-operator,prometheus"), + new BasicHeader("x-ocp-ns", "openshift-logging") + ); + + System.out.println(res.getBody()); + Assert.assertEquals(HttpStatus.SC_OK, res.getStatusCode()); + Assert.assertTrue(res.getBody().contains("{\"app-000020\":{\"aliases\":{\"app-write\":{}}}}")); + } + + @Test + public void testIndexSettings() throws Exception { + final Settings settings = Settings.builder() + .put("opendistro_security.restapi.roles_enabled", "kibana_server") + .build(); + + final DynamicSecurityConfig dsc = new DynamicSecurityConfig() + .setConfig("ocp_config.yml") + .setSecurityRoles("ocp_roles.yml") + .setSecurityRolesMapping("ocp_roles_mapping.yml") + .setSecurityInternalUsers("ocp_internal_users.yml") + .setSecurityActionGroups("ocp_action_groups.yml"); + + setup(Settings.EMPTY, dsc, settings); + try (TransportClient tc = getInternalTransportClient()) { + Map indexSettings = new HashMap(); + indexSettings.put("number_of_shards", 1); + indexSettings.put("number_of_replicas", 1); + + for (int i = 1; i < 21; i++) { + String leadingZeros = "00000"; + if (i >= 10) { + leadingZeros = "0000"; + } + + String appIndexName = "app-" + leadingZeros + i; + CreateIndexRequest cir = new CreateIndexRequest(appIndexName) + .alias(new Alias("app")) + .settings(indexSettings); + + if (i == 20) { + cir = cir.alias(new Alias("app-write")); + } + tc.admin().indices().create(cir).actionGet(); + + String doc = "{\"message\": \"This is just a test\", \"namespace\": \"test\", \"kubernetes\": {\"namespace_name\": \"test\"}}"; + tc.index(new IndexRequest(appIndexName) + .type("doc") + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) + .source(doc, XContentType.JSON)).actionGet(); + } + } + final RestHelper rh = nonSslRestHelper(); + RestHelper.HttpResponse res; + + res = rh.executeGetRequest( + "app-000010/_settings", + // Use x-forwarded* headers to allow extended-proxy authentication + new BasicHeader("x-forwarded-for", "127.0.0.1"), + new BasicHeader("x-forwarded-user", "system:serviceaccount:openshift-operators-redhat:elasticsearch-operator"), + new BasicHeader("x-forwarded-roles", "elasticsearch-operator,prometheus"), + new BasicHeader("x-ocp-ns", "openshift-logging") + ); + + System.out.println(res.getBody()); + Assert.assertEquals(HttpStatus.SC_OK, res.getStatusCode()); + } + + @Test + public void testCreateIndex() throws Exception { + final Settings settings = Settings.builder() + .put("opendistro_security.restapi.roles_enabled", "kibana_server") + .build(); + + final DynamicSecurityConfig dsc = new DynamicSecurityConfig() + .setConfig("ocp_config.yml") + .setSecurityRoles("ocp_roles.yml") + .setSecurityRolesMapping("ocp_roles_mapping.yml") + .setSecurityInternalUsers("ocp_internal_users.yml") + .setSecurityActionGroups("ocp_action_groups.yml"); + + setup(Settings.EMPTY, dsc, settings); + try (TransportClient tc = getInternalTransportClient()) { + Map indexSettings = new HashMap(); + indexSettings.put("number_of_shards", 1); + indexSettings.put("number_of_replicas", 1); + + for (int i = 1; i < 21; i++) { + String leadingZeros = "00000"; + if (i >= 10) { + leadingZeros = "0000"; + } + + String appIndexName = "app-" + leadingZeros + i; + CreateIndexRequest cir = new CreateIndexRequest(appIndexName) + .alias(new Alias("app")) + .settings(indexSettings); + + if (i == 20) { + cir = cir.alias(new Alias("app-write")); + } + tc.admin().indices().create(cir).actionGet(); + + String doc = "{\"message\": \"This is just a test\", \"namespace\": \"test\", \"kubernetes\": {\"namespace_name\": \"test\"}}"; + tc.index(new IndexRequest(appIndexName) + .type("doc") + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) + .source(doc, XContentType.JSON)).actionGet(); + } + } + final RestHelper rh = nonSslRestHelper(); + RestHelper.HttpResponse res; + + res = rh.executePutRequest( + "app-000021", + "{\"aliases\":{\"app-write\":{\"is_write_index\":true}}}", + // Use x-forwarded* headers to allow extended-proxy authentication + new BasicHeader("x-forwarded-for", "127.0.0.1"), + new BasicHeader("x-forwarded-user", "system:serviceaccount:openshift-operators-redhat:elasticsearch-operator"), + new BasicHeader("x-forwarded-roles", "elasticsearch-operator,prometheus"), + new BasicHeader("x-ocp-ns", "openshift-logging") + ); + + System.out.println(res.getBody()); + Assert.assertEquals(HttpStatus.SC_OK, res.getStatusCode()); + Assert.assertTrue(res.getBody().contains("{\"acknowledged\":true,\"shards_acknowledged\":true,\"index\":\"app-000021\"}")); + } + + @Test + public void testUpdateIndexSettings() throws Exception { + final Settings settings = Settings.builder() + .put("opendistro_security.restapi.roles_enabled", "kibana_server") + .build(); + + final DynamicSecurityConfig dsc = new DynamicSecurityConfig() + .setConfig("ocp_config.yml") + .setSecurityRoles("ocp_roles.yml") + .setSecurityRolesMapping("ocp_roles_mapping.yml") + .setSecurityInternalUsers("ocp_internal_users.yml") + .setSecurityActionGroups("ocp_action_groups.yml"); + + setup(Settings.EMPTY, dsc, settings); + try (TransportClient tc = getInternalTransportClient()) { + Map indexSettings = new HashMap(); + indexSettings.put("number_of_shards", 1); + indexSettings.put("number_of_replicas", 1); + + for (int i = 1; i < 21; i++) { + String leadingZeros = "00000"; + if (i >= 10) { + leadingZeros = "0000"; + } + + String appIndexName = "app-" + leadingZeros + i; + CreateIndexRequest cir = new CreateIndexRequest(appIndexName) + .alias(new Alias("app")) + .settings(indexSettings); + + if (i == 20) { + cir = cir.alias(new Alias("app-write")); + } + tc.admin().indices().create(cir).actionGet(); + + String doc = "{\"message\": \"This is just a test\", \"namespace\": \"test\", \"kubernetes\": {\"namespace_name\": \"test\"}}"; + tc.index(new IndexRequest(appIndexName) + .type("doc") + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) + .source(doc, XContentType.JSON)).actionGet(); + } + } + final RestHelper rh = nonSslRestHelper(); + RestHelper.HttpResponse res; + + res = rh.executePutRequest( + "app-000002/_settings", + "{\"index\":{\"blocks\":{\"read_only_allow_delete\":true}}}", + // Use x-forwarded* headers to allow extended-proxy authentication + new BasicHeader("x-forwarded-for", "127.0.0.1"), + new BasicHeader("x-forwarded-user", "system:serviceaccount:openshift-operators-redhat:elasticsearch-operator"), + new BasicHeader("x-forwarded-roles", "elasticsearch-operator,prometheus"), + new BasicHeader("x-ocp-ns", "openshift-logging") + ); + + System.out.println(res.getBody()); + Assert.assertEquals(HttpStatus.SC_OK, res.getStatusCode()); + Assert.assertTrue(res.getBody().contains("{\"acknowledged\":true}")); + } +} diff --git a/src/test/java/com/amazon/opendistroforelasticsearch/security/openshift_logging/IndexManagementTests.java b/src/test/java/com/amazon/opendistroforelasticsearch/security/openshift_logging/IndexManagementTests.java new file mode 100644 index 000000000..128dbf477 --- /dev/null +++ b/src/test/java/com/amazon/opendistroforelasticsearch/security/openshift_logging/IndexManagementTests.java @@ -0,0 +1,203 @@ +package com.amazon.opendistroforelasticsearch.security.openshift_logging; + +import com.amazon.opendistroforelasticsearch.security.test.DynamicSecurityConfig; +import com.amazon.opendistroforelasticsearch.security.test.SingleClusterTest; +import com.amazon.opendistroforelasticsearch.security.test.helper.rest.RestHelper; +import org.apache.http.HttpStatus; +import org.apache.http.message.BasicHeader; +import org.elasticsearch.action.admin.indices.alias.Alias; +import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; +import org.elasticsearch.action.index.IndexRequest; +import org.elasticsearch.action.support.WriteRequest; +import org.elasticsearch.client.transport.TransportClient; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.xcontent.XContentType; +import org.junit.Assert; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +public class IndexManagementTests extends SingleClusterTest { + + @Override + protected String getResourceFolder() { + return "openshift-logging"; + } + + @Test + public void testDeleteIndex() throws Exception { + final Settings settings = Settings.builder() + .put("opendistro_security.restapi.roles_enabled", "kibana_server") + .build(); + + final DynamicSecurityConfig dsc = new DynamicSecurityConfig() + .setConfig("ocp_config.yml") + .setSecurityRoles("ocp_roles.yml") + .setSecurityRolesMapping("ocp_roles_mapping.yml") + .setSecurityInternalUsers("ocp_internal_users.yml") + .setSecurityActionGroups("ocp_action_groups.yml"); + + setup(Settings.EMPTY, dsc, settings); + try (TransportClient tc = getInternalTransportClient()) { + Map indexSettings = new HashMap(); + indexSettings.put("number_of_shards", 1); + indexSettings.put("number_of_replicas", 1); + + for (int i = 1; i < 21; i++) { + String leadingZeros = "00000"; + if (i >= 10) { + leadingZeros = "0000"; + } + + String appIndexName = "app-" + leadingZeros + i; + CreateIndexRequest cir = new CreateIndexRequest(appIndexName) + .alias(new Alias("app")) + .settings(indexSettings); + + if (i == 20) { + cir = cir.alias(new Alias("app-write")); + } + tc.admin().indices().create(cir).actionGet(); + + String doc = "{\"message\": \"This is just a test\", \"namespace\": \"test\", \"kubernetes\": {\"namespace_name\": \"test\"}}"; + tc.index(new IndexRequest(appIndexName) + .type("doc") + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) + .source(doc, XContentType.JSON)).actionGet(); + } + } + final RestHelper rh = nonSslRestHelper(); + RestHelper.HttpResponse res; + + res = rh.executeDeleteRequest( + "app-000001", + // Use x-forwarded* headers to allow extended-proxy authentication + new BasicHeader("x-forwarded-for", "127.0.0.1"), + new BasicHeader("x-forwarded-user", "system:serviceaccount:openshift-logging:elasticsearch"), + new BasicHeader("x-forwarded-roles", "index-management") + ); + + System.out.println(res.getBody()); + Assert.assertEquals(HttpStatus.SC_OK, res.getStatusCode()); + Assert.assertTrue(res.getBody().contains("{\"acknowledged\":true}")); + } + + @Test + public void testDeleteByQuery() throws Exception { + final Settings settings = Settings.builder() + .put("opendistro_security.restapi.roles_enabled", "kibana_server") + .build(); + + final DynamicSecurityConfig dsc = new DynamicSecurityConfig() + .setConfig("ocp_config.yml") + .setSecurityRoles("ocp_roles.yml") + .setSecurityRolesMapping("ocp_roles_mapping.yml") + .setSecurityInternalUsers("ocp_internal_users.yml") + .setSecurityActionGroups("ocp_action_groups.yml"); + + setup(Settings.EMPTY, dsc, settings); + try (TransportClient tc = getInternalTransportClient()) { + Map indexSettings = new HashMap(); + indexSettings.put("number_of_shards", 1); + indexSettings.put("number_of_replicas", 1); + + for (int i = 1; i < 21; i++) { + String leadingZeros = "00000"; + if (i >= 10) { + leadingZeros = "0000"; + } + + String appIndexName = "app-" + leadingZeros + i; + CreateIndexRequest cir = new CreateIndexRequest(appIndexName) + .alias(new Alias("app")) + .settings(indexSettings); + + if (i == 20) { + cir = cir.alias(new Alias("app-write")); + } + tc.admin().indices().create(cir).actionGet(); + + String doc = "{\"message\": \"This is just a test\", \"namespace\": \"test\", \"kubernetes\": {\"namespace_name\": \"test\"}}"; + tc.index(new IndexRequest(appIndexName) + .type("doc") + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) + .source(doc, XContentType.JSON)).actionGet(); + } + } + final RestHelper rh = nonSslRestHelper(); + RestHelper.HttpResponse res; + + res = rh.executePostRequest( + "app-000001/_doc/_delete_by_query", + "{\"query\":{\"match\":{ \"message\": \"This is just a test\"}}}", + // Use x-forwarded* headers to allow extended-proxy authentication + new BasicHeader("x-forwarded-for", "127.0.0.1"), + new BasicHeader("x-forwarded-user", "system:serviceaccount:openshift-logging:elasticsearch"), + new BasicHeader("x-forwarded-roles", "index-management") + ); + + System.out.println(res.getBody()); + Assert.assertEquals(HttpStatus.SC_OK, res.getStatusCode()); + Assert.assertTrue(res.getBody().contains("{\"acknowledged\":true}")); + } + + @Test + public void testRollover() throws Exception { + final Settings settings = Settings.builder() + .put("opendistro_security.restapi.roles_enabled", "kibana_server") + .build(); + + final DynamicSecurityConfig dsc = new DynamicSecurityConfig() + .setConfig("ocp_config.yml") + .setSecurityRoles("ocp_roles.yml") + .setSecurityRolesMapping("ocp_roles_mapping.yml") + .setSecurityInternalUsers("ocp_internal_users.yml") + .setSecurityActionGroups("ocp_action_groups.yml"); + + setup(Settings.EMPTY, dsc, settings); + try (TransportClient tc = getInternalTransportClient()) { + Map indexSettings = new HashMap(); + indexSettings.put("number_of_shards", 1); + indexSettings.put("number_of_replicas", 1); + + for (int i = 1; i < 21; i++) { + String leadingZeros = "00000"; + if (i >= 10) { + leadingZeros = "0000"; + } + + String appIndexName = "app-" + leadingZeros + i; + CreateIndexRequest cir = new CreateIndexRequest(appIndexName) + .alias(new Alias("app")) + .settings(indexSettings); + + if (i == 20) { + cir = cir.alias(new Alias("app-write")); + } + tc.admin().indices().create(cir).actionGet(); + + String doc = "{\"message\": \"This is just a test\", \"namespace\": \"test\", \"kubernetes\": {\"namespace_name\": \"test\"}}"; + tc.index(new IndexRequest(appIndexName) + .type("doc") + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) + .source(doc, XContentType.JSON)).actionGet(); + } + } + final RestHelper rh = nonSslRestHelper(); + RestHelper.HttpResponse res; + + res = rh.executePostRequest( + "app-write/_rollover", + "", + // Use x-forwarded* headers to allow extended-proxy authentication + new BasicHeader("x-forwarded-for", "127.0.0.1"), + new BasicHeader("x-forwarded-user", "system:serviceaccount:openshift-logging:elasticsearch"), + new BasicHeader("x-forwarded-roles", "index-management") + ); + + System.out.println(res.getBody()); + Assert.assertEquals(HttpStatus.SC_OK, res.getStatusCode()); + Assert.assertTrue(res.getBody().contains("{\"acknowledged\":true,\"shards_acknowledged\":true,\"old_index\":\"app-000020\",\"new_index\":\"app-000021\",\"rolled_over\":true,\"dry_run\":false,\"conditions\":{}}")); + } +} diff --git a/src/test/java/com/amazon/opendistroforelasticsearch/security/openshift_logging/KibanaTests.java b/src/test/java/com/amazon/opendistroforelasticsearch/security/openshift_logging/KibanaTests.java new file mode 100644 index 000000000..ddaeded5a --- /dev/null +++ b/src/test/java/com/amazon/opendistroforelasticsearch/security/openshift_logging/KibanaTests.java @@ -0,0 +1,449 @@ +package com.amazon.opendistroforelasticsearch.security.openshift_logging; + +import com.amazon.opendistroforelasticsearch.security.test.DynamicSecurityConfig; +import com.amazon.opendistroforelasticsearch.security.test.SingleClusterTest; +import com.amazon.opendistroforelasticsearch.security.test.helper.rest.RestHelper; +import org.apache.http.HttpStatus; +import org.apache.http.message.BasicHeader; +import org.elasticsearch.action.admin.indices.alias.Alias; +import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; +import org.elasticsearch.action.index.IndexRequest; +import org.elasticsearch.action.support.WriteRequest; +import org.elasticsearch.client.transport.TransportClient; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.xcontent.XContentType; +import org.junit.Assert; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +public class KibanaTests extends SingleClusterTest { + + @Override + protected String getResourceFolder() { + return "openshift-logging"; + } + + @Test + public void testProjectUser() throws Exception { + final Settings settings = Settings.builder() + .put("opendistro_security.restapi.roles_enabled", "kibana_server") + .build(); + + final DynamicSecurityConfig dsc = new DynamicSecurityConfig() + .setConfig("ocp_config.yml") + .setSecurityRoles("ocp_roles.yml") + .setSecurityRolesMapping("ocp_roles_mapping.yml") + .setSecurityInternalUsers("ocp_internal_users.yml") + .setSecurityActionGroups("ocp_action_groups.yml"); + + setup(Settings.EMPTY, dsc, settings); + + try (TransportClient tc = getInternalTransportClient()) { + Map indexSettings = new HashMap(); + indexSettings.put("number_of_shards", 1); + indexSettings.put("number_of_replicas", 1); + + tc.admin().indices().create(new CreateIndexRequest(".kibana_1") + .alias(new Alias(".kibana")) + .settings(indexSettings)) + .actionGet(); + + tc.admin().indices().create(new CreateIndexRequest(".kibana_-1159834508_testuser1_2") + .settings(indexSettings)) + .actionGet(); + + tc.admin().indices().create(new CreateIndexRequest(".kibana_-1159834508_testuser1_3") + .alias(new Alias(".kibana_-1159834508_testuser1")) + .settings(indexSettings)) + .actionGet(); + + String kibUserBodyJSON = "{\"buildNum\" : 20385,\"defaultIndex\" : \"9f63ccf0-8cb1-11eb-994c-7551a3e70b0d\"}"; + tc.index(new IndexRequest(".kibana_-1159834508_testuser1_2") + .type("doc") + .id("6.8.1") + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) + .source(kibUserBodyJSON, XContentType.JSON)).actionGet(); + tc.index(new IndexRequest(".kibana_-1159834508_testuser1_3") + .type("doc") + .id("6.8.1") + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) + .source(kibUserBodyJSON, XContentType.JSON)).actionGet(); + + for (int i = 1; i < 21; i++) { + String leadingZeros = "00000"; + if (i >= 10) { + leadingZeros = "0000"; + } + + String appIndexName = "app-" + leadingZeros + i; + CreateIndexRequest cir = new CreateIndexRequest(appIndexName) + .alias(new Alias("app")) + .settings(indexSettings); + + if (i == 20) { + cir = cir.alias(new Alias("app-write")); + } + tc.admin().indices().create(cir).actionGet(); + + String doc = "{\"message\": \"This is just a test\", \"namespace\": \"test\", \"kubernetes\": {\"namespace_name\": \"test\"}}"; + tc.index(new IndexRequest(appIndexName) + .type("doc") + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) + .source(doc, XContentType.JSON)).actionGet(); + } + + for (int i = 1; i < 21; i++) { + String leadingZeros = "00000"; + if (i >= 10) { + leadingZeros = "0000"; + } + + String appIndexName = "infra-" + leadingZeros + i; + CreateIndexRequest cir = new CreateIndexRequest(appIndexName) + .alias(new Alias("infra")) + .settings(indexSettings); + + if (i == 20) { + cir = cir.alias(new Alias("infra-write")); + } + tc.admin().indices().create(cir).actionGet(); + + String doc = "{\"message\": \"This is just a test\", \"namespace\": \"openshift-monitoring\", \"kubernetes\": {\"namespace_name\": \"openshift-monitoring\"}}"; + tc.index(new IndexRequest(appIndexName) + .type("doc") + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) + .source(doc, XContentType.JSON)).actionGet(); + } + } + + final RestHelper rh = nonSslRestHelper(); + RestHelper.HttpResponse res; + + res = rh.executeGetRequest( + "app-000001/_search", + + // Use x-forwarded* headers to allow extended-proxy authentication + new BasicHeader("x-forwarded-for", "127.0.0.1"), + new BasicHeader("x-forwarded-user", "testuser1"), + new BasicHeader("x-forwarded-roles", "project_user"), + new BasicHeader("x-ocp-ns", "test"), + + // Fake Cookie storage for selected tenant in Kibana + new BasicHeader("securitytenant", "__user__") + ); + + System.out.println(res.getBody()); + Assert.assertEquals(HttpStatus.SC_OK, res.getStatusCode()); + Assert.assertTrue(res.getBody().contains("This is just a test")); + + res = rh.executeGetRequest( + "infra-000001/_search", + + // Use x-forwarded* headers to allow extended-proxy authentication + new BasicHeader("x-forwarded-for", "127.0.0.1"), + new BasicHeader("x-forwarded-user", "testuser1"), + new BasicHeader("x-forwarded-roles", "project_user"), + new BasicHeader("x-ocp-ns", "test"), + + // Fake Cookie storage for selected tenant in Kibana + new BasicHeader("securitytenant", "__user__") + ); + + System.out.println(res.getBody()); + Assert.assertEquals(HttpStatus.SC_FORBIDDEN, res.getStatusCode()); + } + + @Test + public void testAdminUser() throws Exception { + final Settings settings = Settings.builder() + .put("opendistro_security.restapi.roles_enabled", "kibana_server") + .build(); + + final DynamicSecurityConfig dsc = new DynamicSecurityConfig() + .setConfig("ocp_config.yml") + .setSecurityRoles("ocp_roles.yml") + .setSecurityRolesMapping("ocp_roles_mapping.yml") + .setSecurityInternalUsers("ocp_internal_users.yml") + .setSecurityActionGroups("ocp_action_groups.yml"); + + setup(Settings.EMPTY, dsc, settings); + + try (TransportClient tc = getInternalTransportClient()) { + Map indexSettings = new HashMap(); + indexSettings.put("number_of_shards", 1); + indexSettings.put("number_of_replicas", 1); + + tc.admin().indices().create(new CreateIndexRequest(".kibana_1") + .alias(new Alias(".kibana")) + .settings(indexSettings)) + .actionGet(); + + tc.admin().indices().create(new CreateIndexRequest(".kibana_-1159834508_testuser1_2") + .settings(indexSettings)) + .actionGet(); + + tc.admin().indices().create(new CreateIndexRequest(".kibana_-1159834508_testuser1_3") + .alias(new Alias(".kibana_-1159834508_testuser1")) + .settings(indexSettings)) + .actionGet(); + + String kibUserBodyJSON = "{\"buildNum\" : 20385,\"defaultIndex\" : \"9f63ccf0-8cb1-11eb-994c-7551a3e70b0d\"}"; + tc.index(new IndexRequest(".kibana_-1159834508_testuser1_2") + .type("doc") + .id("6.8.1") + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) + .source(kibUserBodyJSON, XContentType.JSON)).actionGet(); + tc.index(new IndexRequest(".kibana_-1159834508_testuser1_3") + .type("doc") + .id("6.8.1") + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) + .source(kibUserBodyJSON, XContentType.JSON)).actionGet(); + + for (int i = 1; i < 21; i++) { + String leadingZeros = "00000"; + if (i >= 10) { + leadingZeros = "0000"; + } + + String appIndexName = "app-" + leadingZeros + i; + CreateIndexRequest cir = new CreateIndexRequest(appIndexName) + .alias(new Alias("app")) + .settings(indexSettings); + + if (i == 20) { + cir = cir.alias(new Alias("app-write")); + } + tc.admin().indices().create(cir).actionGet(); + + String doc = "{\"message\": \"This is just a test\", \"namespace\": \"test\", \"kubernetes\": {\"namespace_name\": \"test\"}}"; + tc.index(new IndexRequest(appIndexName) + .type("doc") + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) + .source(doc, XContentType.JSON)).actionGet(); + } + + for (int i = 1; i < 21; i++) { + String leadingZeros = "00000"; + if (i >= 10) { + leadingZeros = "0000"; + } + + String appIndexName = "infra-" + leadingZeros + i; + CreateIndexRequest cir = new CreateIndexRequest(appIndexName) + .alias(new Alias("infra")) + .settings(indexSettings); + + if (i == 20) { + cir = cir.alias(new Alias("infra-write")); + } + tc.admin().indices().create(cir).actionGet(); + + String doc = "{\"message\": \"This is just a test\", \"namespace\": \"openshift-monitoring\", \"kubernetes\": {\"namespace_name\": \"openshift-monitoring\"}}"; + tc.index(new IndexRequest(appIndexName) + .type("doc") + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) + .source(doc, XContentType.JSON)).actionGet(); + } + } + + final RestHelper rh = nonSslRestHelper(); + RestHelper.HttpResponse res; + + res = rh.executeGetRequest( + "app-000001/_search", + + // Use x-forwarded* headers to allow extended-proxy authentication + new BasicHeader("x-forwarded-for", "127.0.0.1"), + new BasicHeader("x-forwarded-user", "testuser1"), + new BasicHeader("x-forwarded-roles", "admin_reader"), + new BasicHeader("x-ocp-ns", "test"), + + // Fake Cookie storage for selected tenant in Kibana + new BasicHeader("securitytenant", "__user__") + ); + + System.out.println(res.getBody()); + Assert.assertEquals(HttpStatus.SC_OK, res.getStatusCode()); + Assert.assertTrue(res.getBody().contains("This is just a test")); + + res = rh.executeGetRequest( + "infra-000001/_search", + + // Use x-forwarded* headers to allow extended-proxy authentication + new BasicHeader("x-forwarded-for", "127.0.0.1"), + new BasicHeader("x-forwarded-user", "testuser1"), + new BasicHeader("x-forwarded-roles", "admin_reader"), + new BasicHeader("x-ocp-ns", "test"), + + // Fake Cookie storage for selected tenant in Kibana + new BasicHeader("securitytenant", "__user__") + ); + + System.out.println(res.getBody()); + Assert.assertEquals(HttpStatus.SC_OK, res.getStatusCode()); + } + + @Test + public void testKibanaUserTenantMigration() throws Exception { + final Settings settings = Settings.builder() + .put("opendistro_security.restapi.roles_enabled", "kibana_server") + .build(); + + final DynamicSecurityConfig dsc = new DynamicSecurityConfig() + .setConfig("ocp_config.yml") + .setSecurityRoles("ocp_roles.yml") + .setSecurityRolesMapping("ocp_roles_mapping.yml") + .setSecurityInternalUsers("ocp_internal_users.yml") + .setSecurityActionGroups("ocp_action_groups.yml"); + + setup(Settings.EMPTY, dsc, settings); + + try (TransportClient tc = getInternalTransportClient()) { + Map indexSettings = new HashMap(); + indexSettings.put("number_of_shards", 1); + indexSettings.put("number_of_replicas", 1); + + tc.admin().indices().create(new CreateIndexRequest(".kibana_1") + .alias(new Alias(".kibana")) + .settings(indexSettings)) + .actionGet(); + + tc.admin().indices().create(new CreateIndexRequest(".kibana_-1159834508_testuser1_2") + .settings(indexSettings)) + .actionGet(); + + tc.admin().indices().create(new CreateIndexRequest(".kibana_-1159834508_testuser1_3") + .alias(new Alias(".kibana_-1159834508_testuser1")) + .settings(indexSettings)) + .actionGet(); + + String kibUserBodyJSON = "{\"buildNum\" : 20385,\"defaultIndex\" : \"9f63ccf0-8cb1-11eb-994c-7551a3e70b0d\"}"; + tc.index(new IndexRequest(".kibana_-1159834508_testuser1_2") + .type("doc") + .id("6.8.1") + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) + .source(kibUserBodyJSON, XContentType.JSON)).actionGet(); + tc.index(new IndexRequest(".kibana_-1159834508_testuser1_3") + .type("doc") + .id("6.8.1") + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) + .source(kibUserBodyJSON, XContentType.JSON)).actionGet(); + + for (int i = 1; i < 21; i++) { + String leadingZeros = "00000"; + if (i >= 10) { + leadingZeros = "0000"; + } + + String appIndexName = "app-" + leadingZeros + i; + CreateIndexRequest cir = new CreateIndexRequest(appIndexName) + .alias(new Alias("app")) + .settings(indexSettings); + + if (i == 20) { + cir = cir.alias(new Alias("app-write")); + } + tc.admin().indices().create(cir).actionGet(); + + String doc = "{\"message\": \"This is just a test\", \"namespace\": \"test\", \"kubernetes\": {\"namespace_name\": \"test\"}}"; + tc.index(new IndexRequest(appIndexName) + .type("doc") + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) + .source(doc, XContentType.JSON)).actionGet(); + } + } + + final RestHelper rh = nonSslRestHelper(); + RestHelper.HttpResponse res; + + res = rh.executeDeleteRequest( + // Use .kibana for user testuser1, but this should be replaced by .kibana_-1159834508_testuser1 + // DELETE -> .kibana/doc/6.8.1 -> .kibana_-1159834508_testuser1/doc/6.8.1 -> .kibana_-1159834508_testuser1_3/doc/6.8.1 + ".kibana/doc/6.8.1", + + // Use x-forwarded* headers to allow extended-proxy authentication + new BasicHeader("x-forwarded-for", "127.0.0.1"), + new BasicHeader("x-forwarded-user", "testuser1"), + new BasicHeader("x-forwarded-roles", "project_user"), + new BasicHeader("x-ocp-ns", "test"), + + // Fake Cookie storage for selected tenant in Kibana + new BasicHeader("securitytenant", "__user__") + ); + + System.out.println(res.getBody()); + Assert.assertEquals(HttpStatus.SC_OK, res.getStatusCode()); + Assert.assertTrue(res.getBody().contains(".kibana_-1159834508_testuser1")); + } + + @Test + public void testKibanaServerAccess() throws Exception { + final Settings settings = Settings.builder() + .put("opendistro_security.restapi.roles_enabled", "kibana_server") + .build(); + + final DynamicSecurityConfig dsc = new DynamicSecurityConfig() + .setConfig("ocp_config.yml") + .setSecurityRoles("ocp_roles.yml") + .setSecurityRolesMapping("ocp_roles_mapping.yml") + .setSecurityInternalUsers("ocp_internal_users.yml") + .setSecurityActionGroups("ocp_action_groups.yml"); + + setup(Settings.EMPTY, dsc, settings); + + try (TransportClient tc = getInternalTransportClient()) { + Map indexSettings = new HashMap(); + indexSettings.put("number_of_shards", 1); + indexSettings.put("number_of_replicas", 1); + + tc.admin().indices().create(new CreateIndexRequest(".kibana_1") + .alias(new Alias(".kibana")) + .settings(indexSettings)) + .actionGet(); + + String kibUserBodyJSON = "{\"buildNum\" : 20385,\"defaultIndex\" : \"9f63ccf0-8cb1-11eb-994c-7551a3e70b0d\"}"; + tc.index(new IndexRequest(".kibana") + .type("doc") + .id("6.8.1") + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) + .source(kibUserBodyJSON, XContentType.JSON)).actionGet(); + + for (int i = 1; i < 21; i++) { + String leadingZeros = "00000"; + if (i >= 10) { + leadingZeros = "0000"; + } + + String appIndexName = "app-" + leadingZeros + i; + CreateIndexRequest cir = new CreateIndexRequest(appIndexName) + .alias(new Alias("app")) + .settings(indexSettings); + + if (i == 20) { + cir = cir.alias(new Alias("app-write")); + } + tc.admin().indices().create(cir).actionGet(); + + String doc = "{\"message\": \"This is just a test\", \"namespace\": \"test\", \"kubernetes\": {\"namespace_name\": \"test\"}}"; + tc.index(new IndexRequest(appIndexName) + .type("doc") + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) + .source(doc, XContentType.JSON)).actionGet(); + } + } + + final RestHelper rh = nonSslRestHelper(); + RestHelper.HttpResponse res; + + res = rh.executeDeleteRequest( + ".kibana/doc/6.8.1", + // Use x-forwarded* headers to allow extended-proxy authentication + new BasicHeader("x-forwarded-for", "127.0.0.1"), + new BasicHeader("x-forwarded-user", "CN=system.logging.kibana,OU=Logging,O=OpenShift") + ); + + Assert.assertEquals(HttpStatus.SC_OK, res.getStatusCode()); + } +} diff --git a/src/test/resources/openshift-logging/kirk-keystore.jks b/src/test/resources/openshift-logging/kirk-keystore.jks new file mode 100644 index 000000000..dd7562ef8 Binary files /dev/null and b/src/test/resources/openshift-logging/kirk-keystore.jks differ diff --git a/src/test/resources/openshift-logging/node-0-keystore.jks b/src/test/resources/openshift-logging/node-0-keystore.jks new file mode 100644 index 000000000..5693b7bf8 Binary files /dev/null and b/src/test/resources/openshift-logging/node-0-keystore.jks differ diff --git a/src/test/resources/openshift-logging/ocp_action_groups.yml b/src/test/resources/openshift-logging/ocp_action_groups.yml new file mode 100644 index 000000000..04e49ed45 --- /dev/null +++ b/src/test/resources/openshift-logging/ocp_action_groups.yml @@ -0,0 +1,143 @@ +UNLIMITED: + - "*" + +###### INDEX LEVEL ###### + +INDICES_ALL: + - "indices:*" + +# for backward compatibility +ALL: + - INDICES_ALL + +MANAGE: + - "indices:monitor/*" + - "indices:admin/*" + +CREATE_INDEX: + - "indices:admin/create" + - "indices:admin/mapping/put" + +MANAGE_ALIASES: + - "indices:admin/aliases*" + +# for backward compatibility +MONITOR: + - INDICES_MONITOR + - cluster:monitor/main + +INDICES_MONITOR: + - "indices:monitor/*" + +DATA_ACCESS: + - "indices:data/*" + - CRUD + +WRITE: + - "indices:data/write*" + - "indices:admin/mapping/put" + +READ: + - "indices:data/read*" + - "indices:admin/mappings/fields/get*" + - "indices:admin/mappings/get" + - "indices:data/read/search" + +DELETE: + - "indices:data/write/delete*" + +CRUD: + - READ + - WRITE + +SEARCH: + - "indices:data/read/search*" + - "indices:data/read/msearch*" + - SUGGEST + +SUGGEST: + - "indices:data/read/suggest*" + +INDEX: + - "indices:data/write/index*" + - "indices:data/write/update*" + - "indices:admin/mapping/put" + - "indices:data/write/bulk*" + +GET: + - "indices:data/read/get*" + - "indices:data/read/mget*" + +INDEX_ANY_ADMIN: + - indices:admin/mappings/fields/get* + - indices:admin/mappings/get + - indices:admin/validate/query* + - indices:admin/get* + - "indices:data/read/field_stats" + - "indices:data/read/field_caps" + - READ + +INDEX_KIBANA: + - MANAGE + - INDEX + - READ + - DELETE +INDEX_ANY_KIBANA: + - INDEX_ANY_ADMIN + - MANAGE + - WRITE +INDEX_OPERATIONS: + - INDEX_ANY_ADMIN +INDEX_ANY_OPERATIONS: + - INDEX_ANY_ADMIN + - INDICES_MONITOR +INDEX_PROJECT: + - INDEX_ANY_ADMIN + - INDEX_ALL + +METRICS: + - CLUSTER_MONITOR + - SEARCH +USER_ALL_INDEX_OPS: + - "indices:data/read/field_caps" +USER_CLUSTER_OPERATIONS: + - CLUSTER_COMPOSITE_OPS_RO + - MONITOR + - CLUSTER_COMPOSITE_OPS + +###### CLUSTER LEVEL ###### + +# note indicies permissions here because they are +# 'cluster' level perms +CLUSTER_ALL: + - "cluster:*" + - CLUSTER_COMPOSITE_OPS + +CLUSTER_MONITOR: + - cluster:monitor/* +CLUSTER_MONITOR_KIBANA: + - cluster:monitor/nodes/info + - cluster:monitor/health + - CLUSTER_COMPOSITE_OPS +CLUSTER_OPERATIONS: + - CLUSTER_ALL + +CLUSTER_COMPOSITE_OPS_RO: + - "indices:data/read/coordinate-msearch*" + - "indices:data/read/field_caps" + - "indices:data/read/mget" + - "indices:data/read/search" + - "indices:data/read/msearch" + - "indices:data/read/mtv" + - "indices:data/read/scroll*" + - "indices:admin/aliases/exists*" + - "indices:admin/aliases/get*" + +CLUSTER_COMPOSITE_OPS: + - "indices:data/write/bulk" + - "indices:admin/aliases*" + - CLUSTER_COMPOSITE_OPS_RO + +MANAGE_SNAPSHOTS: + - "cluster:admin/snapshot/*" + - "cluster:admin/repository/*" diff --git a/src/test/resources/openshift-logging/ocp_config.yml b/src/test/resources/openshift-logging/ocp_config.yml new file mode 100644 index 000000000..074541349 --- /dev/null +++ b/src/test/resources/openshift-logging/ocp_config.yml @@ -0,0 +1,32 @@ +opendistro_security: + dynamic: + kibana: + server_username: 'CN=system.logging.kibana,OU=OpenShift,O=Logging' + do_not_fail_on_forbidden: true + http: + xff: + enabled: true + remoteIpHeader: 'x-forwarded-for' + internalProxies: '0:0:0:0:0:0:0:1|127\.0\.0\.1' + trustedProxies: '.*' + authc: + openshift_domain: + enabled: true + order: 0 + http_authenticator: + challenge: false + type: extended-proxy + config: + user_header: 'x-forwarded-user' + roles_header: 'x-forwarded-roles' + attr_header_prefix: 'x-ocp-' + authentication_backend: + type: noop + authentication_domain_basic_internal: + enabled: true + order: 1 + http_authenticator: + type: clientcert + challenge: false + authentication_backend: + type: noop \ No newline at end of file diff --git a/src/test/resources/openshift-logging/ocp_internal_users.yml b/src/test/resources/openshift-logging/ocp_internal_users.yml new file mode 100644 index 000000000..3ca3d3b60 --- /dev/null +++ b/src/test/resources/openshift-logging/ocp_internal_users.yml @@ -0,0 +1,12 @@ +spock: + hash: $2a$12$GI9JXffO3WUjTsU7Yy3E4.LBxC2ILo66Zg/rr79BpikSL2IIRezQa + #password is: spock + roles: + - vulcan + - starfleet +kirk: + hash: $2a$12$xZOcnwYPYQ3zIadnlQIJ0eNhX1ngwMkTN.oMwkKxoGvDVPn4/6XtO + #password is: kirk + roles: + - captains + - starfleet \ No newline at end of file diff --git a/src/test/resources/openshift-logging/ocp_roles.yml b/src/test/resources/openshift-logging/ocp_roles.yml new file mode 100644 index 000000000..26b10e747 --- /dev/null +++ b/src/test/resources/openshift-logging/ocp_roles.yml @@ -0,0 +1,165 @@ +# For the kibana server +kibana_server: + readonly: true + cluster: + - CLUSTER_MONITOR + - CLUSTER_COMPOSITE_OPS + - indices:admin/template* + - indices:data/read/scroll* + - indices:data/write/reindex + indices: + '?kibana': + '*': + - INDICES_ALL + '?kibana-6': + '*': + - INDICES_ALL + '?kibana_*': + '*': + - INDICES_ALL + '?reporting*': + '*': + - INDICES_ALL + '?monitoring*': + '*': + - INDICES_ALL + '?tasks': + '*': + - INDICES_ALL + '*': + '*': + - "indices:admin/aliases*" + '?opendistro': + '?security': + - indices:admin/get + +sg_role_prometheus: + cluster: + - METRICS + indices: + '*': + '*': + - indices:monitor* + - indices:data/read/search + +sg_role_fluentd: + cluster: + - indices:data/write/bulk + - CLUSTER_MONITOR + indices: + '*': + '*': + - CRUD + - CREATE_INDEX + +sg_role_rsyslog: + cluster: + - indices:data/write/bulk + - CLUSTER_MONITOR + indices: + '*': + '*': + - CRUD + - CREATE_INDEX + +sg_role_curator: + cluster: + - CLUSTER_MONITOR + - MANAGE + indices: + '*': + '*': + - READ + - MANAGE + - DELETE + - "indices:data/write/bulk*" + +sg_role_admin: + indices: + '*': + '*': + - ALL + cluster: + - CLUSTER_ALL + - ALL + +sg_role_jaeger: + cluster: + - indices:data/write/bulk + - SEARCH + - CLUSTER_MONITOR + - MANAGE + indices: + '*jaeger-span-*': + '*': + - CRUD + - CREATE_INDEX + - READ + - SEARCH + - MANAGE + '*jaeger-service-*': + '*': + - CRUD + - CREATE_INDEX + - READ + - SEARCH + - MANAGE + '*jaeger-span-archive': + '*': + - CRUD + - CREATE_INDEX + - READ + - SEARCH + - MANAGE + '*jaeger-span-archive-*': + '*': + - CRUD + - CREATE_INDEX + - READ + - SEARCH + - MANAGE + +sg_project_operations: + indices: + '?operations?*': + '*': + - READ + - indices:admin/validate/query* + - indices:admin/get* + '*?*?*': + '*': + - READ + - indices:admin/validate/query* + - indices:admin/get* + +# To support multi-tenancy. User's access to indices is restricted to indices belonging to the user's projects, enforced by DLS. +project_user: + readonly: true + cluster: + - CLUSTER_COMPOSITE_OPS_RO + - MONITOR + - indices:data/write/bulk #required for being able to let index mappings update... is this required still with multitenancy? + indices: + app: + '*': + - READ + _dls_: '{"bool":{"filter":{"terms":{"kubernetes.namespace_name":[${attr.proxy.ns}]}}}}' + '?kibana_*_${user_name}': + '*': + - CRUD + +admin_user: + readonly: true + cluster: + - CLUSTER_MONITOR + - CLUSTER_COMPOSITE_OPS_RO + - indices:data/write/bulk #required for being able to let index mappings update... is this required still with multitenancy? + indices: + '*': + '*': + - INDICES_ALL + '?kibana_*': + '*': + - CRUD + tenants: + admin: RW diff --git a/src/test/resources/openshift-logging/ocp_roles_mapping.yml b/src/test/resources/openshift-logging/ocp_roles_mapping.yml new file mode 100644 index 000000000..7675d2ffc --- /dev/null +++ b/src/test/resources/openshift-logging/ocp_roles_mapping.yml @@ -0,0 +1,48 @@ +kibana_server: + users: + - 'CN=system.logging.kibana,OU=OpenShift,O=Logging' + - 'CN=system.logging.kibana,OU=Logging,O=OpenShift' + +sg_role_fluentd: + users: + - 'CN=system.logging.fluentd,OU=OpenShift,O=Logging' + - 'CN=system.logging.fluentd,OU=Logging,O=OpenShift' + +sg_role_rsyslog: + users: + - 'CN=system.logging.rsyslog,OU=OpenShift,O=Logging' + - 'CN=system.logging.rsyslog,OU=Logging,O=OpenShift' + +sg_role_curator: + users: + - 'CN=system.logging.curator,OU=OpenShift,O=Logging' + - 'CN=system.logging.curator,OU=Logging,O=OpenShift' + backendroles: + - 'index-management' + +sg_role_admin: + users: + - 'CN=system.admin,OU=OpenShift,O=Logging' + - 'CN=system.admin,OU=Logging,O=OpenShift' + backendroles: + - 'elasticsearch-operator' + +sg_role_prometheus: + backendroles: + - 'prometheus' + +sg_role_jaeger: + users: + - 'CN=user.jaeger,OU=OpenShift,O=Logging' + - 'CN=user.jaeger,OU=Logging,O=OpenShift' + backendroles: + - 'jaeger' + +admin_user: + backendroles: + - 'admin_reader' + +project_user: + readonly: true + backendroles: + - 'project_user' diff --git a/src/test/resources/openshift-logging/ocp_tenants.yml b/src/test/resources/openshift-logging/ocp_tenants.yml new file mode 100644 index 000000000..e036519e6 --- /dev/null +++ b/src/test/resources/openshift-logging/ocp_tenants.yml @@ -0,0 +1,3 @@ +admin_tenant: + reserved: false + description: "Admin tenant to be shared by all admins" \ No newline at end of file diff --git a/src/test/resources/openshift-logging/spock-keystore.jks b/src/test/resources/openshift-logging/spock-keystore.jks new file mode 100644 index 000000000..7ceed76f7 Binary files /dev/null and b/src/test/resources/openshift-logging/spock-keystore.jks differ diff --git a/src/test/resources/openshift-logging/truststore.jks b/src/test/resources/openshift-logging/truststore.jks new file mode 100644 index 000000000..7a1b59a8d Binary files /dev/null and b/src/test/resources/openshift-logging/truststore.jks differ