Explorar o código

System indices ignore all user templates (#87260)

When creating an index with a system index descriptor, ignore all
templates. Update tests that check template behavior.

Co-authored-by: Nikola Grcevski <nikola.grcevski@elastic.co>
William Brafford %!s(int64=3) %!d(string=hai) anos
pai
achega
d3f74ca1b6

+ 5 - 0
docs/changelog/87260.yaml

@@ -0,0 +1,5 @@
+pr: 87260
+summary: System indices ignore all user templates
+area: Infra/Core
+type: bug
+issues: [42508,74271]

+ 26 - 18
qa/system-indices/src/javaRestTest/java/org/elasticsearch/system/indices/SystemAliasIT.java

@@ -45,8 +45,8 @@ public class SystemAliasIT extends ESRestTestCase {
             assertThat(response.getStatusLine().getStatusCode(), is(200));
         }
 
-        assertAliasIsHiddenInIndexResponse(".internal-unmanaged-index-8", ".internal-unmanaged-alias");
-        assertAliasIsHiddenInAliasesEndpoint(".internal-unmanaged-index-8", ".internal-unmanaged-alias");
+        assertAliasIsHiddenInIndexResponse(".internal-unmanaged-index-8", ".internal-unmanaged-alias", true);
+        assertAliasIsHiddenInAliasesEndpoint(".internal-unmanaged-index-8", ".internal-unmanaged-alias", true);
     }
 
     public void testCreatingSystemIndexWithLegacyAlias() throws Exception {
@@ -71,8 +71,8 @@ public class SystemAliasIT extends ESRestTestCase {
             assertThat(response.getStatusLine().getStatusCode(), is(200));
         }
 
-        assertAliasIsHiddenInIndexResponse(".internal-unmanaged-index-8", ".internal-unmanaged-alias");
-        assertAliasIsHiddenInAliasesEndpoint(".internal-unmanaged-index-8", ".internal-unmanaged-alias");
+        assertAliasIsHiddenInIndexResponse(".internal-unmanaged-index-8", ".internal-unmanaged-alias", false);
+        assertAliasIsHiddenInAliasesEndpoint(".internal-unmanaged-index-8", ".internal-unmanaged-alias", false);
     }
 
     public void testCreatingSystemIndexWithIndexAliasEndpoint() throws Exception {
@@ -94,8 +94,8 @@ public class SystemAliasIT extends ESRestTestCase {
             assertThat(response.getStatusLine().getStatusCode(), is(200));
         }
 
-        assertAliasIsHiddenInIndexResponse(".internal-unmanaged-index-8", ".internal-unmanaged-alias");
-        assertAliasIsHiddenInAliasesEndpoint(".internal-unmanaged-index-8", ".internal-unmanaged-alias");
+        assertAliasIsHiddenInIndexResponse(".internal-unmanaged-index-8", ".internal-unmanaged-alias", true);
+        assertAliasIsHiddenInAliasesEndpoint(".internal-unmanaged-index-8", ".internal-unmanaged-alias", true);
     }
 
     public void testCreatingSystemIndexWithAliasEndpoint() throws Exception {
@@ -118,8 +118,8 @@ public class SystemAliasIT extends ESRestTestCase {
             assertThat(response.getStatusLine().getStatusCode(), is(200));
         }
 
-        assertAliasIsHiddenInIndexResponse(".internal-unmanaged-index-8", ".internal-unmanaged-alias");
-        assertAliasIsHiddenInAliasesEndpoint(".internal-unmanaged-index-8", ".internal-unmanaged-alias");
+        assertAliasIsHiddenInIndexResponse(".internal-unmanaged-index-8", ".internal-unmanaged-alias", true);
+        assertAliasIsHiddenInAliasesEndpoint(".internal-unmanaged-index-8", ".internal-unmanaged-alias", true);
     }
 
     public void testCreatingSystemIndexWithAliasesEndpoint() throws Exception {
@@ -154,12 +154,12 @@ public class SystemAliasIT extends ESRestTestCase {
             assertThat(response.getStatusLine().getStatusCode(), is(200));
         }
 
-        assertAliasIsHiddenInIndexResponse(".internal-unmanaged-index-8", ".internal-unmanaged-alias");
-        assertAliasIsHiddenInAliasesEndpoint(".internal-unmanaged-index-8", ".internal-unmanaged-alias");
+        assertAliasIsHiddenInIndexResponse(".internal-unmanaged-index-8", ".internal-unmanaged-alias", true);
+        assertAliasIsHiddenInAliasesEndpoint(".internal-unmanaged-index-8", ".internal-unmanaged-alias", true);
     }
 
     @SuppressWarnings("unchecked")
-    private void assertAliasIsHiddenInIndexResponse(String indexName, String aliasName) throws IOException {
+    private void assertAliasIsHiddenInIndexResponse(String indexName, String aliasName, boolean expectMatch) throws IOException {
         Request request = new Request("GET", "/" + indexName);
         request.setOptions(
             expectWarnings(
@@ -177,14 +177,18 @@ public class SystemAliasIT extends ESRestTestCase {
         assertThat(indexSettingsMap.get("hidden"), equalTo("true"));
 
         Map<String, Object> aliasesMap = (Map<String, Object>) indexMap.get("aliases");
-        assertThat(aliasesMap.keySet(), equalTo(Set.of(aliasName)));
-        Map<String, Object> aliasMap = (Map<String, Object>) aliasesMap.get(aliasName);
-        assertThat(aliasMap.get("is_hidden"), notNullValue());
-        assertThat(aliasMap.get("is_hidden"), equalTo(true));
+        if (expectMatch == false) {
+            assertTrue(aliasesMap.keySet().isEmpty());
+        } else {
+            assertThat(aliasesMap.keySet(), equalTo(Set.of(aliasName)));
+            Map<String, Object> aliasMap = (Map<String, Object>) aliasesMap.get(aliasName);
+            assertThat(aliasMap.get("is_hidden"), notNullValue());
+            assertThat(aliasMap.get("is_hidden"), equalTo(true));
+        }
     }
 
     @SuppressWarnings("unchecked")
-    private void assertAliasIsHiddenInAliasesEndpoint(String indexName, String aliasName) throws IOException {
+    private void assertAliasIsHiddenInAliasesEndpoint(String indexName, String aliasName, boolean expectMatch) throws IOException {
         Request request = new Request("GET", "/_aliases");
         request.setOptions(
             expectWarnings(
@@ -199,7 +203,11 @@ public class SystemAliasIT extends ESRestTestCase {
         Map<String, Object> indexAliasMap = (Map<String, Object>) responseMap.get(indexName);
         Map<String, Object> aliasesMap = (Map<String, Object>) indexAliasMap.get("aliases");
         Map<String, Object> aliasMap = (Map<String, Object>) aliasesMap.get(aliasName);
-        assertThat(aliasMap.get("is_hidden"), notNullValue());
-        assertThat(aliasMap.get("is_hidden"), equalTo(true));
+        if (expectMatch == false) {
+            assertNull(aliasMap);
+        } else {
+            assertThat(aliasMap.get("is_hidden"), notNullValue());
+            assertThat(aliasMap.get("is_hidden"), equalTo(true));
+        }
     }
 }

+ 68 - 18
server/src/internalClusterTest/java/org/elasticsearch/action/admin/indices/create/AutoCreateSystemIndexIT.java

@@ -23,6 +23,7 @@ import org.elasticsearch.cluster.metadata.Template;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.common.util.CollectionUtils;
 import org.elasticsearch.indices.SystemIndexDescriptor;
+import org.elasticsearch.indices.TestSystemIndexDescriptorAllowsTemplates;
 import org.elasticsearch.indices.TestSystemIndexPlugin;
 import org.elasticsearch.plugins.Plugin;
 import org.elasticsearch.plugins.SystemIndexPlugin;
@@ -167,40 +168,56 @@ public class AutoCreateSystemIndexIT extends ESIntegTestCase {
         );
     }
 
-    /**
-     * Check that a template applying a system alias creates a hidden alias.
-     */
-    public void testAutoCreateSystemAliasViaV1Template() throws Exception {
+    private String autoCreateSystemAliasViaV1Template(String indexName) throws Exception {
         assertAcked(
             client().admin()
                 .indices()
                 .preparePutTemplate("test-template")
-                .setPatterns(List.of(INDEX_NAME + "*"))
-                .addAlias(new Alias(INDEX_NAME + "-legacy-alias"))
+                .setPatterns(List.of(indexName + "*"))
+                .addAlias(new Alias(indexName + "-legacy-alias"))
                 .get()
         );
 
-        String nonPrimaryIndex = INDEX_NAME + "-2";
+        String nonPrimaryIndex = indexName + "-2";
         CreateIndexRequest request = new CreateIndexRequest(nonPrimaryIndex);
         assertAcked(client().execute(AutoCreateAction.INSTANCE, request).get());
-
         assertTrue(indexExists(nonPrimaryIndex));
 
-        assertAliasesHidden(nonPrimaryIndex, Set.of(".test-index", ".test-index-legacy-alias"));
+        return nonPrimaryIndex;
+    }
 
-        assertAcked(client().admin().indices().prepareDeleteTemplate("*").get());
+    /**
+     * Check that a legacy template does not create an alias for a system index
+     */
+    public void testAutoCreateSystemAliasViaV1Template() throws Exception {
+        var nonPrimaryIndex = autoCreateSystemAliasViaV1Template(INDEX_NAME);
+
+        assertAliasesHidden(nonPrimaryIndex, Set.of(INDEX_NAME), 1);
     }
 
     /**
-     * Check that a composable template applying a system alias creates a hidden alias.
+     * Check that a legacy template does create an alias for a system index, because of allows templates
      */
-    public void testAutoCreateSystemAliasViaComposableTemplate() throws Exception {
+    public void testAutoCreateSystemAliasViaV1TemplateAllowsTemplates() throws Exception {
+        var nonPrimaryIndex = autoCreateSystemAliasViaV1Template(TestSystemIndexDescriptorAllowsTemplates.INDEX_NAME);
+
+        assertAliasesHidden(
+            nonPrimaryIndex,
+            Set.of(
+                TestSystemIndexDescriptorAllowsTemplates.INDEX_NAME,
+                TestSystemIndexDescriptorAllowsTemplates.INDEX_NAME + "-legacy-alias"
+            ),
+            2
+        );
+    }
+
+    private String autoCreateSystemAliasViaComposableTemplate(String indexName) throws Exception {
         ComposableIndexTemplate cit = new ComposableIndexTemplate(
-            Collections.singletonList(INDEX_NAME + "*"),
+            Collections.singletonList(indexName + "*"),
             new Template(
                 null,
                 null,
-                Map.of(INDEX_NAME + "-composable-alias", AliasMetadata.builder(INDEX_NAME + "-composable-alias").build())
+                Map.of(indexName + "-composable-alias", AliasMetadata.builder(indexName + "-composable-alias").build())
             ),
             Collections.emptyList(),
             4L,
@@ -214,13 +231,45 @@ public class AutoCreateSystemIndexIT extends ESIntegTestCase {
             ).get()
         );
 
-        String nonPrimaryIndex = INDEX_NAME + "-2";
+        String nonPrimaryIndex = indexName + "-2";
         CreateIndexRequest request = new CreateIndexRequest(nonPrimaryIndex);
         assertAcked(client().execute(AutoCreateAction.INSTANCE, request).get());
 
         assertTrue(indexExists(nonPrimaryIndex));
 
-        assertAliasesHidden(nonPrimaryIndex, Set.of(".test-index", ".test-index-composable-alias"));
+        return nonPrimaryIndex;
+    }
+
+    /**
+     * Check that a composable template does not create an alias for a system index
+     */
+    public void testAutoCreateSystemAliasViaComposableTemplate() throws Exception {
+        String nonPrimaryIndex = autoCreateSystemAliasViaComposableTemplate(INDEX_NAME);
+
+        assertAliasesHidden(nonPrimaryIndex, Set.of(INDEX_NAME), 1);
+
+        assertAcked(
+            client().execute(
+                DeleteComposableIndexTemplateAction.INSTANCE,
+                new DeleteComposableIndexTemplateAction.Request("test-composable-template")
+            ).get()
+        );
+    }
+
+    /**
+     * Check that a composable template does create an alias for a system index, because of allows templates
+     */
+    public void testAutoCreateSystemAliasViaComposableTemplateAllowsTemplates() throws Exception {
+        String nonPrimaryIndex = autoCreateSystemAliasViaComposableTemplate(TestSystemIndexDescriptorAllowsTemplates.INDEX_NAME);
+
+        assertAliasesHidden(
+            nonPrimaryIndex,
+            Set.of(
+                TestSystemIndexDescriptorAllowsTemplates.INDEX_NAME,
+                TestSystemIndexDescriptorAllowsTemplates.INDEX_NAME + "-composable-alias"
+            ),
+            2
+        );
 
         assertAcked(
             client().execute(
@@ -230,14 +279,15 @@ public class AutoCreateSystemIndexIT extends ESIntegTestCase {
         );
     }
 
-    private void assertAliasesHidden(String nonPrimaryIndex, Set<String> aliasNames) throws InterruptedException, ExecutionException {
+    private void assertAliasesHidden(String nonPrimaryIndex, Set<String> aliasNames, int aliasCount) throws InterruptedException,
+        ExecutionException {
         final GetAliasesResponse getAliasesResponse = client().admin()
             .indices()
             .getAliases(new GetAliasesRequest().indicesOptions(IndicesOptions.strictExpandHidden()))
             .get();
 
         assertThat(getAliasesResponse.getAliases().size(), equalTo(1));
-        assertThat(getAliasesResponse.getAliases().get(nonPrimaryIndex).size(), equalTo(2));
+        assertThat(getAliasesResponse.getAliases().get(nonPrimaryIndex).size(), equalTo(aliasCount));
         assertThat(
             getAliasesResponse.getAliases().get(nonPrimaryIndex).stream().map(AliasMetadata::alias).collect(Collectors.toSet()),
             equalTo(aliasNames)

+ 77 - 22
server/src/internalClusterTest/java/org/elasticsearch/action/admin/indices/create/CreateSystemIndicesIT.java

@@ -30,6 +30,7 @@ import org.elasticsearch.cluster.metadata.Template;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.common.util.CollectionUtils;
 import org.elasticsearch.indices.TestSystemIndexDescriptor;
+import org.elasticsearch.indices.TestSystemIndexDescriptorAllowsTemplates;
 import org.elasticsearch.indices.TestSystemIndexPlugin;
 import org.elasticsearch.plugins.Plugin;
 import org.elasticsearch.test.ESIntegTestCase;
@@ -157,37 +158,56 @@ public class CreateSystemIndicesIT extends ESIntegTestCase {
         doCreateTest(() -> assertAcked(prepareCreate(PRIMARY_INDEX_NAME)), PRIMARY_INDEX_NAME);
     }
 
-    /**
-     * Check that a legacy template applying a system alias creates a hidden alias.
-     */
-    public void testCreateSystemAliasViaV1Template() throws Exception {
+    private void createSystemAliasViaV1Template(String indexName, String primaryIndexName) throws Exception {
         assertAcked(
             client().admin()
                 .indices()
                 .preparePutTemplate("test-template")
-                .setPatterns(List.of(INDEX_NAME + "*"))
-                .addAlias(new Alias(INDEX_NAME + "-legacy-alias"))
+                .setPatterns(List.of(indexName + "*"))
+                .addAlias(new Alias(indexName + "-legacy-alias"))
                 .get()
         );
 
-        assertAcked(prepareCreate(PRIMARY_INDEX_NAME));
-        ensureGreen(PRIMARY_INDEX_NAME);
+        assertAcked(prepareCreate(primaryIndexName));
+        ensureGreen(primaryIndexName);
+    }
 
-        assertHasAliases(Set.of(".test-index", ".test-index-legacy-alias"));
+    /**
+     * Check that a legacy template does not create an alias for a system index
+     */
+    public void testCreateSystemAliasViaV1Template() throws Exception {
+        createSystemAliasViaV1Template(INDEX_NAME, PRIMARY_INDEX_NAME);
 
-        assertAcked(client().admin().indices().prepareDeleteTemplate("*").get());
+        assertHasAliases(Set.of(INDEX_NAME), INDEX_NAME, PRIMARY_INDEX_NAME, 1);
     }
 
     /**
-     * Check that a composable template applying a system alias creates a hidden alias.
+     * Check that a legacy template does create an alias for a system index because of allows templates
      */
-    public void testCreateSystemAliasViaComposableTemplate() throws Exception {
+    public void testCreateSystemAliasViaV1TemplateAllowsTemplates() throws Exception {
+        createSystemAliasViaV1Template(
+            TestSystemIndexDescriptorAllowsTemplates.INDEX_NAME,
+            TestSystemIndexDescriptorAllowsTemplates.PRIMARY_INDEX_NAME
+        );
+
+        assertHasAliases(
+            Set.of(
+                TestSystemIndexDescriptorAllowsTemplates.INDEX_NAME,
+                TestSystemIndexDescriptorAllowsTemplates.INDEX_NAME + "-legacy-alias"
+            ),
+            TestSystemIndexDescriptorAllowsTemplates.INDEX_NAME,
+            TestSystemIndexDescriptorAllowsTemplates.PRIMARY_INDEX_NAME,
+            2
+        );
+    }
+
+    private void createIndexWithComposableTemplates(String indexName, String primaryIndexName) throws Exception {
         ComposableIndexTemplate cit = new ComposableIndexTemplate(
-            Collections.singletonList(INDEX_NAME + "*"),
+            Collections.singletonList(indexName + "*"),
             new Template(
                 null,
                 null,
-                Map.of(INDEX_NAME + "-composable-alias", AliasMetadata.builder(INDEX_NAME + "-composable-alias").build())
+                Map.of(indexName + "-composable-alias", AliasMetadata.builder(indexName + "-composable-alias").build())
             ),
             Collections.emptyList(),
             4L,
@@ -201,10 +221,44 @@ public class CreateSystemIndicesIT extends ESIntegTestCase {
             ).get()
         );
 
-        assertAcked(prepareCreate(PRIMARY_INDEX_NAME));
-        ensureGreen(PRIMARY_INDEX_NAME);
+        assertAcked(prepareCreate(primaryIndexName));
+        ensureGreen(primaryIndexName);
+    }
 
-        assertHasAliases(Set.of(".test-index", ".test-index-composable-alias"));
+    /**
+     * Check that a composable template does not create an alias for a system index
+     */
+    public void testCreateSystemAliasViaComposableTemplate() throws Exception {
+        createIndexWithComposableTemplates(INDEX_NAME, PRIMARY_INDEX_NAME);
+
+        assertHasAliases(Set.of(INDEX_NAME), INDEX_NAME, PRIMARY_INDEX_NAME, 1);
+
+        assertAcked(
+            client().execute(
+                DeleteComposableIndexTemplateAction.INSTANCE,
+                new DeleteComposableIndexTemplateAction.Request("test-composable-template")
+            ).get()
+        );
+    }
+
+    /**
+     * Check that a composable template does create an alias for a system index because of allows templates
+     */
+    public void testCreateSystemAliasViaComposableTemplateWithAllowsTemplates() throws Exception {
+        createIndexWithComposableTemplates(
+            TestSystemIndexDescriptorAllowsTemplates.INDEX_NAME,
+            TestSystemIndexDescriptorAllowsTemplates.PRIMARY_INDEX_NAME
+        );
+
+        assertHasAliases(
+            Set.of(
+                TestSystemIndexDescriptorAllowsTemplates.INDEX_NAME,
+                TestSystemIndexDescriptorAllowsTemplates.INDEX_NAME + "-composable-alias"
+            ),
+            TestSystemIndexDescriptorAllowsTemplates.INDEX_NAME,
+            TestSystemIndexDescriptorAllowsTemplates.PRIMARY_INDEX_NAME,
+            2
+        );
 
         assertAcked(
             client().execute(
@@ -278,21 +332,22 @@ public class CreateSystemIndicesIT extends ESIntegTestCase {
         assertThat(getAliasesResponse.getAliases().get(concreteIndex).get(0).writeIndex(), equalTo(true));
     }
 
-    private void assertHasAliases(Set<String> aliasNames) throws InterruptedException, java.util.concurrent.ExecutionException {
+    private void assertHasAliases(Set<String> aliasNames, String name, String primaryName, int aliasCount) throws InterruptedException,
+        java.util.concurrent.ExecutionException {
         final GetAliasesResponse getAliasesResponse = client().admin()
             .indices()
             .getAliases(new GetAliasesRequest().indicesOptions(IndicesOptions.strictExpandHidden()))
             .get();
 
         assertThat(getAliasesResponse.getAliases().size(), equalTo(1));
-        assertThat(getAliasesResponse.getAliases().get(PRIMARY_INDEX_NAME).size(), equalTo(2));
+        assertThat(getAliasesResponse.getAliases().get(primaryName).size(), equalTo(aliasCount));
         assertThat(
-            getAliasesResponse.getAliases().get(PRIMARY_INDEX_NAME).stream().map(AliasMetadata::alias).collect(Collectors.toSet()),
+            getAliasesResponse.getAliases().get(primaryName).stream().map(AliasMetadata::alias).collect(Collectors.toSet()),
             equalTo(aliasNames)
         );
-        for (AliasMetadata aliasMetadata : getAliasesResponse.getAliases().get(PRIMARY_INDEX_NAME)) {
+        for (AliasMetadata aliasMetadata : getAliasesResponse.getAliases().get(primaryName)) {
             assertThat(aliasMetadata.isHidden(), equalTo(true));
-            if (aliasMetadata.alias().equals(INDEX_NAME)) {
+            if (aliasMetadata.alias().equals(name)) {
                 assertThat(aliasMetadata.writeIndex(), is(true));
             } else {
                 assertThat(aliasMetadata.writeIndex(), is(nullValue()));

+ 21 - 0
server/src/internalClusterTest/java/org/elasticsearch/indices/TestSystemIndexDescriptor.java

@@ -59,6 +59,27 @@ public class TestSystemIndexDescriptor extends SystemIndexDescriptor {
         );
     }
 
+    TestSystemIndexDescriptor(String name, String primaryName, boolean allowsTemplates) {
+        super(
+            name + "*",
+            primaryName,
+            "Test system index",
+            getOldMappings(),
+            SETTINGS,
+            name,
+            0,
+            "version",
+            "stack",
+            Version.CURRENT.minimumCompatibilityVersion(),
+            Type.INTERNAL_MANAGED,
+            List.of(),
+            List.of(),
+            null,
+            false,
+            allowsTemplates
+        );
+    }
+
     @Override
     public boolean isAutomaticallyManaged() {
         return true;

+ 23 - 0
server/src/internalClusterTest/java/org/elasticsearch/indices/TestSystemIndexDescriptorAllowsTemplates.java

@@ -0,0 +1,23 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+package org.elasticsearch.indices;
+
+/**
+ * A special kind of {@link SystemIndexDescriptor} that is exactly like {@link TestSystemIndexDescriptor},
+ * but it allows for user defined templates to apply to it.
+ */
+public class TestSystemIndexDescriptorAllowsTemplates extends TestSystemIndexDescriptor {
+
+    public static final String INDEX_NAME = ".templates-index";
+    public static final String PRIMARY_INDEX_NAME = INDEX_NAME + "-1";
+
+    TestSystemIndexDescriptorAllowsTemplates() {
+        super(INDEX_NAME, PRIMARY_INDEX_NAME, true);
+    }
+}

+ 1 - 1
server/src/internalClusterTest/java/org/elasticsearch/indices/TestSystemIndexPlugin.java

@@ -21,7 +21,7 @@ import java.util.List;
 public class TestSystemIndexPlugin extends Plugin implements SystemIndexPlugin {
     @Override
     public Collection<SystemIndexDescriptor> getSystemIndexDescriptors(Settings settings) {
-        return List.of(new TestSystemIndexDescriptor());
+        return List.of(new TestSystemIndexDescriptor(), new TestSystemIndexDescriptorAllowsTemplates());
     }
 
     @Override

+ 54 - 0
server/src/main/java/org/elasticsearch/cluster/metadata/MetadataCreateIndexService.java

@@ -66,6 +66,7 @@ import org.elasticsearch.indices.IndexCreationException;
 import org.elasticsearch.indices.IndicesService;
 import org.elasticsearch.indices.InvalidIndexNameException;
 import org.elasticsearch.indices.ShardLimitValidator;
+import org.elasticsearch.indices.SystemIndexDescriptor;
 import org.elasticsearch.indices.SystemIndices;
 import org.elasticsearch.threadpool.ThreadPool;
 import org.elasticsearch.xcontent.NamedXContentRegistry;
@@ -352,6 +353,13 @@ public class MetadataCreateIndexService {
                 return applyCreateIndexRequestForSystemDataStream(currentState, request, silent, metadataTransformer);
             }
 
+            SystemIndexDescriptor descriptor = systemIndices.findMatchingDescriptor(request.index());
+            // ignore all templates for all system indices that do not allow templates.
+            // Essentially, all but .kibana indices, see KibanaPlugin.java.
+            if (Objects.nonNull(descriptor) && descriptor.allowsTemplates() == false) {
+                return applyCreateIndexRequestForSystemIndex(currentState, request, silent, descriptor.getIndexPattern());
+            }
+
             // Hidden indices apply templates slightly differently (ignoring wildcard '*'
             // templates), so we need to check to see if the request is creating a hidden index
             // prior to resolving which templates it matches
@@ -632,6 +640,52 @@ public class MetadataCreateIndexService {
         );
     }
 
+    private ClusterState applyCreateIndexRequestForSystemIndex(
+        final ClusterState currentState,
+        final CreateIndexClusterStateUpdateRequest request,
+        final boolean silent,
+        final String indexPattern
+    ) throws Exception {
+        logger.debug("applying create index request for system index [{}] matching pattern [{}]", request.index(), indexPattern);
+
+        final Settings aggregatedIndexSettings = aggregateIndexSettings(
+            currentState,
+            request,
+            Settings.EMPTY,
+            null,
+            null,
+            settings,
+            indexScopedSettings,
+            shardLimitValidator,
+            indexSettingProviders
+        );
+        final int routingNumShards = getIndexNumberOfRoutingShards(aggregatedIndexSettings, null);
+        final IndexMetadata tmpImd = buildAndValidateTemporaryIndexMetadata(aggregatedIndexSettings, request, routingNumShards);
+
+        return applyCreateIndexWithTemporaryService(
+            currentState,
+            request,
+            silent,
+            null,
+            tmpImd,
+            List.of(new CompressedXContent(MapperService.parseMapping(xContentRegistry, request.mappings()))),
+            indexService -> resolveAndValidateAliases(
+                request.index(),
+                request.aliases(),
+                List.of(),
+                currentState.metadata(),
+                // the context is only used for validation so it's fine to pass fake values for the
+                // shard id and the current timestamp
+                xContentRegistry,
+                indexService.newSearchExecutionContext(0, 0, null, () -> 0L, null, emptyMap()),
+                IndexService.dateMathExpressionResolverAt(request.getNameResolvedAt()),
+                systemIndices::isSystemName
+            ),
+            List.of(),
+            null
+        );
+    }
+
     private ClusterState applyCreateIndexRequestForSystemDataStream(
         final ClusterState currentState,
         final CreateIndexClusterStateUpdateRequest request,