Skip to content

Commit 67f9e8f

Browse files
authored
Enforce limitations on ILM policy names (#35104)
Enforces restrictions on ILM policy names to ensure we don't accept policy names the system can't handle, or may reserve for future use.
1 parent ae2af20 commit 67f9e8f

File tree

4 files changed

+67
-0
lines changed

4 files changed

+67
-0
lines changed

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/LifecyclePolicy.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,14 @@
2121
import org.elasticsearch.xpack.core.indexlifecycle.Step.StepKey;
2222

2323
import java.io.IOException;
24+
import java.nio.charset.StandardCharsets;
2425
import java.util.ArrayList;
2526
import java.util.Collections;
2627
import java.util.List;
2728
import java.util.ListIterator;
2829
import java.util.Map;
2930
import java.util.Objects;
31+
import java.util.function.BiFunction;
3032
import java.util.function.Function;
3133
import java.util.stream.Collectors;
3234

@@ -40,6 +42,7 @@
4042
public class LifecyclePolicy extends AbstractDiffable<LifecyclePolicy>
4143
implements ToXContentObject, Diffable<LifecyclePolicy> {
4244
private static final Logger logger = LogManager.getLogger(LifecyclePolicy.class);
45+
private static final int MAX_INDEX_NAME_BYTES = 255;
4346

4447
public static final ParseField PHASES_FIELD = new ParseField("phases");
4548

@@ -241,6 +244,30 @@ public boolean isActionSafe(StepKey stepKey) {
241244
}
242245
}
243246

247+
/**
248+
* Validate the name for an policy against some static rules. Intended to match
249+
* {@link org.elasticsearch.cluster.metadata.MetaDataCreateIndexService#validateIndexOrAliasName(String, BiFunction)}
250+
* @param policy the policy name to validate
251+
* @throws IllegalArgumentException if the name is invalid
252+
*/
253+
public static void validatePolicyName(String policy) {
254+
if (policy.contains(",")) {
255+
throw new IllegalArgumentException("invalid policy name [" + policy + "]: must not contain ','");
256+
}
257+
if (policy.contains(" ")) {
258+
throw new IllegalArgumentException("invalid policy name [" + policy + "]: must not contain spaces");
259+
}
260+
if (policy.charAt(0) == '_') {
261+
throw new IllegalArgumentException("invalid policy name [" + policy + "]: must not start with '_'");
262+
}
263+
int byteCount = 0;
264+
byteCount = policy.getBytes(StandardCharsets.UTF_8).length;
265+
if (byteCount > MAX_INDEX_NAME_BYTES) {
266+
throw new IllegalArgumentException("invalid policy name [" + policy + "]: name is too long, (" + byteCount + " > " +
267+
MAX_INDEX_NAME_BYTES + ")");
268+
}
269+
}
270+
244271
@Override
245272
public int hashCode() {
246273
return Objects.hash(name, phases);

x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/LifecyclePolicyTests.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,4 +316,20 @@ public void testIsActionSafe() {
316316

317317
assertTrue(policy.isActionSafe(new StepKey("new", randomAlphaOfLength(10), randomAlphaOfLength(10))));
318318
}
319+
320+
public void testValidatePolicyName() {
321+
expectThrows(IllegalArgumentException.class, () -> LifecyclePolicy.validatePolicyName(randomAlphaOfLengthBetween(0,10) +
322+
"," + randomAlphaOfLengthBetween(0,10)));
323+
expectThrows(IllegalArgumentException.class, () -> LifecyclePolicy.validatePolicyName(randomAlphaOfLengthBetween(0,10) +
324+
" " + randomAlphaOfLengthBetween(0,10)));
325+
expectThrows(IllegalArgumentException.class, () -> LifecyclePolicy.validatePolicyName("_" + randomAlphaOfLengthBetween(1, 20)));
326+
expectThrows(IllegalArgumentException.class, () -> LifecyclePolicy.validatePolicyName(randomAlphaOfLengthBetween(256, 1000)));
327+
328+
LifecyclePolicy.validatePolicyName(randomAlphaOfLengthBetween(1,10) + "_" + randomAlphaOfLengthBetween(0,10));
329+
330+
LifecyclePolicy.validatePolicyName(randomAlphaOfLengthBetween(0,10) + "-" + randomAlphaOfLengthBetween(0,10));
331+
LifecyclePolicy.validatePolicyName(randomAlphaOfLengthBetween(0,10) + "+" + randomAlphaOfLengthBetween(0,10));
332+
333+
LifecyclePolicy.validatePolicyName(randomAlphaOfLengthBetween(1,255));
334+
}
319335
}

x-pack/plugin/ilm/qa/multi-node/src/test/java/org/elasticsearch/xpack/indexlifecycle/TimeSeriesLifecycleActionsIT.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636

3737
import java.io.IOException;
3838
import java.io.InputStream;
39+
import java.io.UnsupportedEncodingException;
3940
import java.util.Collections;
4041
import java.util.HashMap;
4142
import java.util.List;
@@ -45,6 +46,7 @@
4546

4647
import static java.util.Collections.singletonMap;
4748
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
49+
import static org.hamcrest.Matchers.containsString;
4850
import static org.hamcrest.Matchers.equalTo;
4951
import static org.hamcrest.Matchers.greaterThan;
5052
import static org.hamcrest.Matchers.not;
@@ -399,6 +401,26 @@ public void testNonexistentPolicy() throws Exception {
399401

400402
}
401403

404+
public void testInvalidPolicyNames() throws UnsupportedEncodingException {
405+
ResponseException ex;
406+
407+
policy = randomAlphaOfLengthBetween(0,10) + "," + randomAlphaOfLengthBetween(0,10);
408+
ex = expectThrows(ResponseException.class, () -> createNewSingletonPolicy("delete", new DeleteAction()));
409+
assertThat(ex.getCause().getMessage(), containsString("invalid policy name"));
410+
411+
policy = randomAlphaOfLengthBetween(0,10) + "%20" + randomAlphaOfLengthBetween(0,10);
412+
ex = expectThrows(ResponseException.class, () -> createNewSingletonPolicy("delete", new DeleteAction()));
413+
assertThat(ex.getCause().getMessage(), containsString("invalid policy name"));
414+
415+
policy = "_" + randomAlphaOfLengthBetween(1, 20);
416+
ex = expectThrows(ResponseException.class, () -> createNewSingletonPolicy("delete", new DeleteAction()));
417+
assertThat(ex.getMessage(), containsString("invalid policy name"));
418+
419+
policy = randomAlphaOfLengthBetween(256, 1000);
420+
ex = expectThrows(ResponseException.class, () -> createNewSingletonPolicy("delete", new DeleteAction()));
421+
assertThat(ex.getMessage(), containsString("invalid policy name"));
422+
}
423+
402424
private void createFullPolicy(TimeValue hotTime) throws IOException {
403425
Map<String, LifecycleAction> warmActions = new HashMap<>();
404426
warmActions.put(ForceMergeAction.NAME, new ForceMergeAction(1));

x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/TransportPutLifecycleAction.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.elasticsearch.transport.TransportService;
2222
import org.elasticsearch.xpack.core.ClientHelper;
2323
import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleMetadata;
24+
import org.elasticsearch.xpack.core.indexlifecycle.LifecyclePolicy;
2425
import org.elasticsearch.xpack.core.indexlifecycle.LifecyclePolicyMetadata;
2526
import org.elasticsearch.xpack.core.indexlifecycle.OperationMode;
2627
import org.elasticsearch.xpack.core.indexlifecycle.action.PutLifecycleAction;
@@ -65,6 +66,7 @@ protected void masterOperation(Request request, ClusterState state, ActionListen
6566
Map<String, String> filteredHeaders = threadPool.getThreadContext().getHeaders().entrySet().stream()
6667
.filter(e -> ClientHelper.SECURITY_HEADER_FILTERS.contains(e.getKey()))
6768
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
69+
LifecyclePolicy.validatePolicyName(request.getPolicy().getName());
6870
clusterService.submitStateUpdateTask("put-lifecycle-" + request.getPolicy().getName(),
6971
new AckedClusterStateUpdateTask<Response>(request, listener) {
7072
@Override

0 commit comments

Comments
 (0)