Skip to content

Commit 2afa7fa

Browse files
authored
Override the JVM DNS cache policy (#36570)
When a security manager is present, the JVM will cache positive hostname lookups indefinitely. This can be problematic, especially in the modern world with cloud services where DNS addresses can change, or environments using Docker containers where IP addresses could be considered ephemeral. This behavior impacts cluster discovery, cross-cluster replication and cross-cluster search, reindex from remote, snapshot repositories, webhooks in Watcher, external authentication mechanisms, and the Elastic Stack Monitoring Service. The experience of watching a DNS lookup change yet not be reflected within Elasticsearch is a poor experience for users. The reason the JVM has this is guard against DNS cache posioning attacks. Yet, there is already a defense in the modern world against such attacks: TLS. With proper certificate validation, even if a resolver falls prey to a DNS cache poisoning attack, using TLS would neuter the attack. Therefore we have a policy with dubious security value that significantly impacts usability. As such we make the usability/security tradeoff towards usability, since the security risks are very low. This commit introduces new system properties that Elasticsearch observes to override the JVM DNS cache policy.
1 parent 7446f75 commit 2afa7fa

File tree

3 files changed

+46
-13
lines changed

3 files changed

+46
-13
lines changed

distribution/src/config/jvm.options

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,15 @@
4545
# 10-:-XX:+UseG1GC
4646
# 10-:-XX:InitiatingHeapOccupancyPercent=75
4747

48+
## DNS cache policy
49+
# cache ttl in seconds for positive DNS lookups noting that this overrides the
50+
# JDK security property networkaddress.cache.ttl; set to -1 to cache forever
51+
-Des.networkaddress.cache.ttl=60
52+
# cache ttl in seconds for negative DNS lookups noting that this overrides the
53+
# JDK security property networkaddress.cache.negative ttl; set to -1 to cache
54+
# forever
55+
-Des.networkaddress.cache.negative.ttl=10
56+
4857
## optimizations
4958

5059
# pre-touch memory pages used by the JVM during initialization

docs/reference/setup/sysconfig/dns-cache.asciidoc

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,18 @@
22
=== DNS cache settings
33

44
Elasticsearch runs with a security manager in place. With a security manager in
5-
place, the JVM defaults to caching positive hostname resolutions
6-
indefinitely. If your Elasticsearch nodes rely on DNS in an environment where
7-
DNS resolutions vary with time (e.g., for node-to-node discovery) then you might
8-
want to modify the default JVM behavior. This can be modified by adding
5+
place, the JVM defaults to caching positive hostname resolutions indefinitely
6+
and defaults to caching negative hostname resolutions for ten
7+
seconds. Elasticsearch overrides this behavior with default values to cache
8+
positive lookups for sixty seconds, and to cache negative lookups for ten
9+
seconds. These values should be suitable for most environments, including
10+
environments where DNS resolutions vary with time. If not, you can edit the
11+
values `es.networkaddress.cache.ttl` and `es.networkaddress.cache.negative.ttl`
12+
in the <<jvm-options,JVM options>>. Note that the values
913
http://docs.oracle.com/javase/8/docs/technotes/guides/net/properties.html[`networkaddress.cache.ttl=<timeout>`]
10-
to your
11-
http://docs.oracle.com/javase/8/docs/technotes/guides/security/PolicyFiles.html[Java
12-
security policy]. Any hosts that fail to resolve will be logged. Note also that
13-
with the Java security manager in place, the JVM defaults to caching negative
14-
hostname resolutions for ten seconds. This can be modified by adding
14+
and
1515
http://docs.oracle.com/javase/8/docs/technotes/guides/net/properties.html[`networkaddress.cache.negative.ttl=<timeout>`]
16-
to your
16+
in the
1717
http://docs.oracle.com/javase/8/docs/technotes/guides/security/PolicyFiles.html[Java
18-
security policy].
18+
security policy] are ignored by Elasticsearch unless you remove the settings for
19+
`es.networkaddress.cache.ttl` and `es.networkaddress.cache.negative.ttl`.

server/src/main/java/org/elasticsearch/bootstrap/Elasticsearch.java

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import java.io.IOException;
3737
import java.nio.file.Path;
3838
import java.security.Permission;
39+
import java.security.Security;
3940
import java.util.Arrays;
4041
import java.util.Locale;
4142

@@ -72,13 +73,19 @@ class Elasticsearch extends EnvironmentAwareCommand {
7273
* Main entry point for starting elasticsearch
7374
*/
7475
public static void main(final String[] args) throws Exception {
75-
// we want the JVM to think there is a security manager installed so that if internal policy decisions that would be based on the
76-
// presence of a security manager or lack thereof act as if there is a security manager present (e.g., DNS cache policy)
76+
overrideDnsCachePolicyProperties();
77+
/*
78+
* We want the JVM to think there is a security manager installed so that if internal policy decisions that would be based on the
79+
* presence of a security manager or lack thereof act as if there is a security manager present (e.g., DNS cache policy). This
80+
* forces such policies to take effect immediately.
81+
*/
7782
System.setSecurityManager(new SecurityManager() {
83+
7884
@Override
7985
public void checkPermission(Permission perm) {
8086
// grant all permissions so that we can later set the security manager to the one that we want
8187
}
88+
8289
});
8390
LogConfigurator.registerErrorListener();
8491
final Elasticsearch elasticsearch = new Elasticsearch();
@@ -88,6 +95,22 @@ public void checkPermission(Permission perm) {
8895
}
8996
}
9097

98+
private static void overrideDnsCachePolicyProperties() {
99+
for (final String property : new String[] {"networkaddress.cache.ttl", "networkaddress.cache.negative.ttl" }) {
100+
final String overrideProperty = "es." + property;
101+
final String overrideValue = System.getProperty(overrideProperty);
102+
if (overrideValue != null) {
103+
try {
104+
// round-trip the property to an integer and back to a string to ensure that it parses properly
105+
Security.setProperty(property, Integer.toString(Integer.valueOf(overrideValue)));
106+
} catch (final NumberFormatException e) {
107+
throw new IllegalArgumentException(
108+
"failed to parse [" + overrideProperty + "] with value [" + overrideValue + "]", e);
109+
}
110+
}
111+
}
112+
}
113+
91114
static int main(final String[] args, final Elasticsearch elasticsearch, final Terminal terminal) throws Exception {
92115
return elasticsearch.main(args, terminal);
93116
}

0 commit comments

Comments
 (0)