Browse Source

Account for INADDR_ANY in enrollment tokens (#78576)

In certain cases (i.e. docker by default) elasticsearch is bound
to 0.0.0.0, which should not make its way into the enrollment
token, as its consumer will have no way of using this in any
meaningful way. In such cases, publish_address contains an IP
address that is reachable in that network.

This change makes it so we filter out 0.0.0.0 and ::0 when we
create enrollment tokens and we use publish_address as well as
bound_address.
Ioannis Kakavas 4 years ago
parent
commit
b3cb7f7513

+ 14 - 3
x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/enrollment/BaseEnrollmentTokenGenerator.java

@@ -50,14 +50,18 @@ public class BaseEnrollmentTokenGenerator {
 
     static List<String> getFilteredAddresses(List<String> addresses) throws Exception {
         List<String> filteredAddresses = new ArrayList<>();
+        final List<String> localAddresses = new ArrayList<>();
         for (String boundAddress : addresses){
             InetAddress inetAddress = getInetAddressFromString(boundAddress);
-            if (inetAddress.isLoopbackAddress() != true) {
+            if (inetAddress.isLoopbackAddress()) {
+                localAddresses.add(boundAddress);
+            } else if (inetAddress.isAnyLocalAddress() == false) {
                 filteredAddresses.add(boundAddress);
             }
         }
+        // If there are no non-local addresses, add local addresses to the token
         if (filteredAddresses.isEmpty()) {
-            filteredAddresses = addresses;
+            filteredAddresses = localAddresses;
         }
         // Sort the list prioritizing IPv4 addresses when possible, as it is more probable to be reachable when token consumer iterates
         // addresses for the initial node and it is less surprising for users to see in the UI or config
@@ -76,7 +80,14 @@ public class BaseEnrollmentTokenGenerator {
                 return 0;
             }
         });
-        return filteredAddresses;
+        return filteredAddresses.stream().distinct().collect(Collectors.toList());
+    }
+
+    static String getIpFromPublishAddress(String publishAddress) {
+        if (publishAddress.contains("/")) {
+            return publishAddress.split("/")[1];
+        }
+        return publishAddress;
     }
 
     private static InetAddress getInetAddressFromString(String address) throws Exception {

+ 5 - 1
x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/enrollment/ExternalEnrollmentTokenGenerator.java

@@ -33,6 +33,7 @@ import java.net.MalformedURLException;
 import java.net.URISyntaxException;
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -101,7 +102,10 @@ public class ExternalEnrollmentTokenGenerator extends BaseEnrollmentTokenGenerat
         nodesInfo = (Map<?, ?>) nodesInfo.get("nodes");
         Map<?, ?> nodeInfo = (Map<?, ?>) nodesInfo.values().iterator().next();
         Map<?, ?> http = (Map<?, ?>) nodeInfo.get("http");
-        return (ArrayList<String>) http.get("bound_address");
+        final List<String> addresses = new ArrayList<>();
+        addresses.addAll((Collection<? extends String>) http.get("bound_address"));
+        addresses.add(getIpFromPublishAddress((String) http.get("publish_address")));
+        return addresses;
     }
 
     static String getVersion(Map<?, ?> nodesInfo) {

+ 3 - 1
x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/enrollment/InternalEnrollmentTokenGenerator.java

@@ -98,6 +98,8 @@ public class InternalEnrollmentTokenGenerator extends BaseEnrollmentTokenGenerat
             final List<String> httpAddressesList = new ArrayList<>();
             client.execute(NodesInfoAction.INSTANCE, nodesInfoRequest, ActionListener.wrap(response -> {
                 for (NodeInfo nodeInfo : response.getNodes()) {
+                    httpAddressesList.add(
+                        getIpFromPublishAddress(nodeInfo.getInfo(HttpInfo.class).getAddress().publishAddress().toString()));
                     httpAddressesList.addAll(
                         Arrays.stream(nodeInfo.getInfo(HttpInfo.class).getAddress().boundAddresses())
                             .map(TransportAddress::toString)
@@ -108,7 +110,7 @@ public class InternalEnrollmentTokenGenerator extends BaseEnrollmentTokenGenerat
                     apiKey,
                     fingerprint,
                     Version.CURRENT.toString(),
-                    httpAddressesList
+                    getFilteredAddresses(httpAddressesList)
                 );
                 listener.onResponse(enrollmentToken);
             }, e -> {

+ 17 - 0
x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/enrollment/ExternalEnrollmentTokenGeneratorTests.java

@@ -369,12 +369,29 @@ public class ExternalEnrollmentTokenGeneratorTests extends ESTestCase {
             "[2001:db8:0:1234:0:567:8:1]:9203"));
         assertThat(filteredAddresses.get(2), equalTo("[2001:db8:0:1234:0:567:8:1]:9203"));
 
+        addresses = Arrays.asList("0.0.0.0:9200", "172.17.0.2:9200");
+        filteredAddresses = getFilteredAddresses(addresses);
+        assertThat(filteredAddresses, hasSize(1));
+        assertThat(filteredAddresses.get(0), equalTo("172.17.0.2:9200"));
+
+        addresses = Arrays.asList("0.0.0.0:9200", "[::1]:9200", "127.0.0.1:9200");
+        filteredAddresses = getFilteredAddresses(addresses);
+        assertThat(filteredAddresses, hasSize(2));
+        assertThat(filteredAddresses.get(0), equalTo("127.0.0.1:9200"));
+        assertThat(filteredAddresses.get(1), equalTo("[::1]:9200"));
+
         addresses = Arrays.asList("[::1]:9200", "127.0.0.1:9200");
         filteredAddresses = getFilteredAddresses(addresses);
         assertThat(filteredAddresses, hasSize(2));
         assertThat(filteredAddresses.get(0), equalTo("127.0.0.1:9200"));
         assertThat(filteredAddresses.get(1), equalTo("[::1]:9200"));
 
+        addresses = Arrays.asList("[::1]:9200", "127.0.0.1:9200", "[::1]:9200", "127.0.0.1:9200", "[::1]:9200", "127.0.0.1:9200");
+        filteredAddresses = getFilteredAddresses(addresses);
+        assertThat(filteredAddresses, hasSize(2));
+        assertThat(filteredAddresses.get(0), equalTo("127.0.0.1:9200"));
+        assertThat(filteredAddresses.get(1), equalTo("[::1]:9200"));
+
         addresses = Arrays.asList("128.255.255.255", "[::1]:9200", "127.0.0.1:9200");
         filteredAddresses = getFilteredAddresses(addresses);
         assertThat(filteredAddresses, hasSize(1));

+ 1 - 1
x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/enrollment/InternalEnrollmentTokenGeneratorTests.java

@@ -118,7 +118,7 @@ public class InternalEnrollmentTokenGeneratorTests extends ESTestCase {
                             null,
                             new HttpInfo(
                                 new BoundTransportAddress(
-                                    new TransportAddress[] { new TransportAddress(InetAddress.getByName("192.168.1.2"), 9200) },
+                                    new TransportAddress[] { new TransportAddress(InetAddress.getByName("0.0.0.0"), 9200) },
                                     new TransportAddress(InetAddress.getByName("192.168.1.2"), 9200)
                                 ),
                                 0L